mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: "Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>
To: barebox@lists.infradead.org
Subject: [PATCH v1 7/7] net/phy: marvell: add support for 88e1510 to marvell phy driver
Date: Wed, 11 Jan 2017 16:59:20 +0100	[thread overview]
Message-ID: <20170111155920.13179-8-u.kleine-koenig@pengutronix.de> (raw)
In-Reply-To: <20170111155920.13179-1-u.kleine-koenig@pengutronix.de>

This is mostly copied verbatim from the Linux driver.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/net/phy/marvell.c | 204 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 201 insertions(+), 3 deletions(-)

diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 6bb50a3a1f4c..38b2ad31f893 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -31,6 +31,9 @@
 #define MII_M1011_PHY_STATUS_RESOLVED	BIT(11)
 #define MII_M1011_PHY_STATUS_LINK	BIT(10)
 
+#define MII_M1111_COPPER		0
+#define MII_M1111_FIBER			1
+
 #define MII_88E1121_PHY_MSCR_PAGE	2
 #define MII_88E1121_PHY_MSCR_REG	21
 #define MII_88E1121_PHY_MSCR_TX_DELAY	BIT(4)
@@ -45,6 +48,20 @@
 #define MII_88E1540_QSGMII_CONTROL	0x0
 #define MII_88E1540_QSGMII_AUTONEG_EN	BIT(12)
 
+#define MII_88E1510_GEN_CTRL_REG_1              0x14
+#define MII_88E1510_GEN_CTRL_REG_1_MODE_MASK    0x7
+#define MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII   0x1     /* SGMII to copper */
+#define MII_88E1510_GEN_CTRL_REG_1_RESET        0x8000  /* Soft reset */
+
+#define LPA_PAUSE_FIBER	0x180
+#define LPA_PAUSE_ASYM_FIBER	0x100
+
+#define ADVERTISE_FIBER_1000HALF	0x40
+#define ADVERTISE_FIBER_1000FULL	0x20
+
+#define ADVERTISE_PAUSE_FIBER		0x180
+#define ADVERTISE_PAUSE_ASYM_FIBER	0x100
+
 /*
  * marvell_read_status
  *
@@ -133,12 +150,24 @@ static int marvell_read_status(struct phy_device *phydev)
 	return 0;
 }
 
+#define MII_88E1510_GEN_CTRL_REG_1              0x14
+
 static inline bool phy_interface_is_rgmii(struct phy_device *phydev)
 {
 	return phydev->interface >= PHY_INTERFACE_MODE_RGMII &&
 		phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID;
 };
 
+/*
+ * This same function in the Linux kernel parses the marvell,reg-init dt
+ * property and does the necessary register writes. It's kept as an exercise for
+ * a future user to implement this. :-)
+ */
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+	return 0;
+}
+
 static int m88e1121_config_aneg(struct phy_device *phydev)
 {
 	int err, oldpage, mscr;
@@ -207,6 +236,130 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
 	return m88e1121_config_aneg(phydev);
 }
 
+/**
+ * ethtool_adv_to_fiber_adv_t
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_ADV register for fiber link.
+ */
+static inline u32 ethtool_adv_to_fiber_adv_t(u32 ethadv)
+{
+	u32 result = 0;
+
+	if (ethadv & ADVERTISED_1000baseT_Half)
+		result |= ADVERTISE_FIBER_1000HALF;
+	if (ethadv & ADVERTISED_1000baseT_Full)
+		result |= ADVERTISE_FIBER_1000FULL;
+
+	if ((ethadv & ADVERTISE_PAUSE_ASYM) && (ethadv & ADVERTISE_PAUSE_CAP))
+		result |= LPA_PAUSE_ASYM_FIBER;
+	else if (ethadv & ADVERTISE_PAUSE_CAP)
+		result |= (ADVERTISE_PAUSE_FIBER
+			   & (~ADVERTISE_PAUSE_ASYM_FIBER));
+
+	return result;
+}
+
+/**
+ * marvell_config_aneg_fiber - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ *   advertising, and then restart auto-negotiation.  If it is not
+ *   enabled, then we write the BMCR. Adapted for fiber link in
+ *   some Marvell's devices.
+ */
+static int marvell_config_aneg_fiber(struct phy_device *phydev)
+{
+	int changed = 0;
+	int err;
+	int adv, oldadv;
+	u32 advertise;
+
+	if (phydev->autoneg != AUTONEG_ENABLE)
+		return genphy_setup_forced(phydev);
+
+	/* Only allow advertising what this PHY supports */
+	phydev->advertising &= phydev->supported;
+	advertise = phydev->advertising;
+
+	/* Setup fiber advertisement */
+	adv = phy_read(phydev, MII_ADVERTISE);
+	if (adv < 0)
+		return adv;
+
+	oldadv = adv;
+	adv &= ~(ADVERTISE_FIBER_1000HALF | ADVERTISE_FIBER_1000FULL
+		| LPA_PAUSE_FIBER);
+	adv |= ethtool_adv_to_fiber_adv_t(advertise);
+
+	if (adv != oldadv) {
+		err = phy_write(phydev, MII_ADVERTISE, adv);
+		if (err < 0)
+			return err;
+
+		changed = 1;
+	}
+
+	if (changed == 0) {
+		/* Advertisement hasn't changed, but maybe aneg was never on to
+		 * begin with?  Or maybe phy was isolated?
+		 */
+		int ctl = phy_read(phydev, MII_BMCR);
+
+		if (ctl < 0)
+			return ctl;
+
+		if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
+			changed = 1; /* do restart aneg */
+	}
+
+	/* Only restart aneg if we are advertising something different
+	 * than we were before.
+	 */
+	if (changed > 0)
+		changed = genphy_restart_aneg(phydev);
+
+	return changed;
+}
+
+static int m88e1510_config_aneg(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
+	if (err < 0)
+		goto error;
+
+	/* Configure the copper link first */
+	err = m88e1318_config_aneg(phydev);
+	if (err < 0)
+		goto error;
+
+	/* Then the fiber link */
+	err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
+	if (err < 0)
+		goto error;
+
+	err = marvell_config_aneg_fiber(phydev);
+	if (err < 0)
+		goto error;
+
+	return phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
+
+error:
+	phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_COPPER);
+	return err;
+}
+
+static int marvell_config_init(struct phy_device *phydev)
+{
+	/* Set registers from marvell,reg-init DT property */
+	return marvell_of_reg_init(phydev);
+}
+
 static int m88e1540_config_init(struct phy_device *phydev)
 {
 	u16 reg;
@@ -246,7 +399,7 @@ static int m88e1540_config_init(struct phy_device *phydev)
 	if (ret < 0)
 		return ret;
 
-	return 0;
+	return marvell_config_init(phydev);
 }
 
 static int m88e1121_config_init(struct phy_device *phydev)
@@ -289,9 +442,10 @@ static int m88e1121_config_init(struct phy_device *phydev)
 	if (ret < 0)
 		return ret;
 
-	return 0;
+	return marvell_config_init(phydev);
 }
 
+
 static int m88e1318s_config_init(struct phy_device *phydev)
 {
 	u16 reg;
@@ -311,6 +465,41 @@ static int m88e1318s_config_init(struct phy_device *phydev)
 	return m88e1121_config_init(phydev);
 }
 
+static int m88e1510_config_init(struct phy_device *phydev)
+{
+	int err;
+	int temp;
+
+	/* SGMII-to-Copper mode initialization */
+	if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+		/* Select page 18 */
+		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 18);
+		if (err < 0)
+			return err;
+
+		/* In reg 20, write MODE[2:0] = 0x1 (SGMII to Copper) */
+		temp = phy_read(phydev, MII_88E1510_GEN_CTRL_REG_1);
+		temp &= ~MII_88E1510_GEN_CTRL_REG_1_MODE_MASK;
+		temp |= MII_88E1510_GEN_CTRL_REG_1_MODE_SGMII;
+		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
+		if (err < 0)
+			return err;
+
+		/* PHY reset is necessary after changing MODE[2:0] */
+		temp |= MII_88E1510_GEN_CTRL_REG_1_RESET;
+		err = phy_write(phydev, MII_88E1510_GEN_CTRL_REG_1, temp);
+		if (err < 0)
+			return err;
+
+		/* Reset page selection */
+		err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
+		if (err < 0)
+			return err;
+	}
+
+	return m88e1121_config_init(phydev);
+}
+
 static struct phy_driver marvell_drivers[] = {
 	{
 		.phy_id = MARVELL_PHY_ID_88E1121R,
@@ -340,12 +529,21 @@ static struct phy_driver marvell_drivers[] = {
 		.read_status = &marvell_read_status,
 	},
 	{
+		.phy_id = MARVELL_PHY_ID_88E1510,
+		.phy_id_mask = MARVELL_PHY_ID_MASK,
+		.drv.name = "Marvell 88E1510",
+		.features = PHY_GBIT_FEATURES | SUPPORTED_FIBRE,
+		.config_init = &m88e1510_config_init,
+		.config_aneg = &m88e1510_config_aneg,
+		.read_status = &marvell_read_status,
+	},
+	{
 		.phy_id = MARVELL_PHY_ID_88E1540,
 		.phy_id_mask = MARVELL_PHY_ID_MASK,
 		.drv.name = "Marvell 88E1540",
 		.features = PHY_GBIT_FEATURES,
 		.config_init = &m88e1540_config_init,
-		.config_aneg = &genphy_config_aneg,
+		.config_aneg = &m88e1510_config_aneg,
 		.read_status = &marvell_read_status,
 	},
 };
-- 
2.11.0


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2017-01-11 15:59 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-11 15:59 [PATCH v1 0/7] net/phy: marvell: add support for 88e1510 Uwe Kleine-König
2017-01-11 15:59 ` [PATCH v1 1/7] net/phy: marvell: rename 88E1545 to 88E1540 Uwe Kleine-König
2017-01-11 15:59 ` [PATCH v1 2/7] net/phy: marvell: 88E1540 LED registers already exist on 88E1121 Uwe Kleine-König
2017-01-11 15:59 ` [PATCH v1 3/7] net/phy: marvell: rename phy_driver array to match Linux driver Uwe Kleine-König
2017-01-11 15:59 ` [PATCH v1 4/7] net/phy: marvell: change spacing to be more similar to the " Uwe Kleine-König
2017-01-11 15:59 ` [PATCH v1 5/7] net/phy: marvell: align definition of MII_88E1121_PHY_MSCR to " Uwe Kleine-König
2017-01-11 15:59 ` [PATCH v1 6/7] net/phy: marvell: improve config_aneg for 88E1121R and 88E1318S Uwe Kleine-König
2017-01-11 15:59 ` Uwe Kleine-König [this message]
2017-01-13  6:54 ` [PATCH v1 0/7] net/phy: marvell: add support for 88e1510 Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170111155920.13179-8-u.kleine-koenig@pengutronix.de \
    --to=u.kleine-koenig@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox