[U-Boot] [PATCH 4/5] tsec: Add support for using the BCM5482 PHY in fiber mode

Peter Tyser ptyser at xes-inc.com
Mon Nov 9 20:09:47 CET 2009


The BCM5482 PHY supports both copper and fiber as an ethernet medium.
By enabling its copper/fiber mode auto-detection feature it can
dynamically determine if it should be configured for copper or fiber.

Signed-off-by: Peter Tyser <ptyser at xes-inc.com>
---
 drivers/net/tsec.c |  110 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 include/tsec.h     |   13 ++++++
 2 files changed, 119 insertions(+), 4 deletions(-)

diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index a2a1aea..2f41024 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -529,8 +529,105 @@ static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv)
 	}
 
 	return 0;
+}
 
+/*
+ * Find out if PHY is in copper or serdes mode by looking at Expansion Reg
+ * 0x42 - "Operating Mode Status Register"
+ */
+static int BCM8482_is_serdes(struct tsec_private *priv)
+{
+	u16 val;
+	int serdes = 0;
+
+	write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42);
+	val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
+
+	switch (val & 0x1f) {
+	case 0x0d:	/* RGMII-to-100Base-FX */
+	case 0x0e:	/* RGMII-to-SGMII */
+	case 0x0f:	/* RGMII-to-SerDes */
+	case 0x12:	/* SGMII-to-SerDes */
+	case 0x13:	/* SGMII-to-100Base-FX */
+	case 0x16:	/* SerDes-to-Serdes */
+		serdes = 1;
+		break;
+	case 0x6:	/* RGMII-to-Copper */
+	case 0x14:	/* SGMII-to-Copper */
+	case 0x17:	/* SerDes-to-Copper */
+		break;
+	default:
+		printf("ERROR, invalid PHY mode (0x%x\n)", val);
+		break;
+	}
+
+	return serdes;
 }
+
+/*
+ * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating
+ * Mode Status Register"
+ */
+uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv)
+{
+	u16 val;
+	int i = 0;
+
+	/* Wait 1s for link - Clause 37 autonegotiation happens very fast */
+	while (1) {
+		write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL,
+				MIIM_BCM54XX_EXP_SEL_ER | 0x42);
+		val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA);
+
+		if (val & 0x8000)
+			break;
+
+		if (i++ > 1000) {
+			priv->link = 0;
+			return 1;
+		}
+
+		udelay(1000);	/* 1 ms */
+	}
+
+	priv->link = 1;
+	switch ((val >> 13) & 0x3) {
+	case (0x00):
+		priv->speed = 10;
+		break;
+	case (0x01):
+		priv->speed = 100;
+		break;
+	case (0x02):
+		priv->speed = 1000;
+		break;
+	}
+
+	priv->duplexity = (val & 0x1000) == 0x1000;
+
+	return 0;
+}
+
+/*
+ * Figure out if BCM5482 is in serdes or copper mode and determine link
+ * configuration accordingly
+ */
+static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv)
+{
+	if (BCM8482_is_serdes(priv)) {
+		mii_parse_BCM5482_serdes_sr(priv);
+	} else {
+		/* Wait for auto-negotiation to complete or fail */
+		mii_parse_sr(mii_reg, priv);
+
+		/* Parse BCM54xx copper aux status register */
+		mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS);
+		mii_parse_BCM54xx_sr(mii_reg, priv);
+	}
+
+	return 0;
+}
+
 /* Parse the 88E1011's status register for speed and duplex
  * information
  */
@@ -1090,15 +1187,20 @@ static struct phy_info phy_info_BCM5482S =  {
 		/* Read Misc Control register and or in Ethernet at Wirespeed */
 		{MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed},
 		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init},
+		/* Initial config/enable of secondary SerDes interface */
+		{MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL},
+		/* Write intial value to secondary SerDes Contol */
+		{MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL},
+		{MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL},
+		/* Enable copper/fiber auto-detect */
+		{MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)},
 		{miim_end,}
 	},
 	(struct phy_cmd[]) { /* startup */
 		/* Status is read once to clear old link state */
 		{MIIM_STATUS, miim_read, NULL},
-		/* Auto-negotiate */
-		{MIIM_STATUS, miim_read, &mii_parse_sr},
-		/* Read the status */
-		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
+		/* Determine copper/fiber, auto-negotiate, and read the result */
+		{MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr},
 		{miim_end,}
 	},
 	(struct phy_cmd[]) { /* shutdown */
diff --git a/include/tsec.h b/include/tsec.h
index 29e4c56..b2e37d4 100644
--- a/include/tsec.h
+++ b/include/tsec.h
@@ -153,6 +153,19 @@
 #define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK	0x0700
 #define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT	8
 
+#define MIIM_BCM54XX_SHD	0x1c	/* 0x1c shadow registers */
+#define MIIM_BCM54XX_SHD_WRITE	0x8000
+#define MIIM_BCM54XX_SHD_VAL(x)	((x & 0x1f) << 10)
+#define MIIM_BCM54XX_SHD_DATA(x)	((x & 0x3ff) << 0)
+#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data)	\
+	(MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \
+	 MIIM_BCM54XX_SHD_DATA(data))
+
+#define MIIM_BCM54XX_EXP_DATA	0x15	/* Expansion register data */
+#define MIIM_BCM54XX_EXP_SEL	0x17	/* Expansion register select */
+#define MIIM_BCM54XX_EXP_SEL_SSD	0x0e00	/* Secondary SerDes select */
+#define MIIM_BCM54XX_EXP_SEL_ER	0x0f00	/* Expansion register select */
+
 /* Cicada Auxiliary Control/Status Register */
 #define MIIM_CIS8201_AUX_CONSTAT	0x1c
 #define MIIM_CIS8201_AUXCONSTAT_INIT	0x0004
-- 
1.6.2.1



More information about the U-Boot mailing list