[U-Boot-Users] [PATCH 2/2] PPC4xx: Add Ethernet 1000BASE-X support for PPC4xx

Larry Johnson lrj at arlinx.com
Tue Oct 30 15:31:13 CET 2007


This patch adds a new switch: "CONFIG_PHY_DYNAMIC_ANEG".  When this symbol
is defined, the PHY will advertise it's capabilities for autonegotiation
based on the capabilities shown in the PHY's status registers, including
1000BASE-X.  When "CONFIG_PHY_DYNAMIC_ANEG" is not defined, the PHY will
advertise hard-coded capabilities, as before.

Signed-off-by: Larry Johnson <lrj at acm.org>
---

 common/miiphyutil.c |  157 +++++++++++++++++++++++++++++++++------------------
 cpu/ppc4xx/miiphy.c |   85 ++++++++++++++++++++++++++--
 include/miiphy.h    |   21 +++++++
 3 files changed, 203 insertions(+), 60 deletions(-)

diff --git a/common/miiphyutil.c b/common/miiphyutil.c
index 58ebc5e..65c3960 100644
--- a/common/miiphyutil.c
+++ b/common/miiphyutil.c
@@ -344,101 +344,148 @@ int miiphy_reset (char *devname, unsigned char addr)

 /*****************************************************************************
  *
- * Determine the ethernet speed (10/100).
+ * Determine the ethernet speed (10/100/1000).  Return 10 on error.
  */
 int miiphy_speed (char *devname, unsigned char addr)
 {
-	unsigned short reg;
+	u16 bmcr;

 #if defined(CONFIG_PHY_GIGE)
-	if (miiphy_read (devname, addr, PHY_1000BTSR, &reg)) {
-		printf ("PHY 1000BT Status read failed\n");
-	} else {
-		if (reg != 0xFFFF) {
-			if ((reg & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))
-			    != 0) {
-				return (_1000BASET);
-			}
+	u16 btsr;
+
+#if defined(CONFIG_PHY_DYNAMIC_ANEG)
+	u16 bmsr;
+
+	/* Check for 1000BASE-X. */
+	if (miiphy_read (devname, addr, PHY_BMSR, &bmsr)) {
+		printf ("PHY status");
+		goto miiphy_read_failed;
+	}
+	if (bmsr & PHY_BMSR_EXT_STAT) {
+		u16 exsr;
+
+		if (miiphy_read (devname, addr, PHY_EXSR, &exsr)) {
+			printf ("PHY extended status");
+			goto miiphy_read_failed;
+		}
+		if (exsr & (PHY_EXSR_1000XF | PHY_EXSR_1000XH)) {
+			/* 1000BASE-X */
+			return _1000BASET;
 		}
 	}
+#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+
+	/* Check for 1000BASE-T. */
+	if (miiphy_read (devname, addr, PHY_1000BTSR, &btsr)) {
+		printf ("PHY 1000BT status");
+		goto miiphy_read_failed;
+	}
+	if (btsr != 0xFFFF &&
+	    (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) {
+		return _1000BASET;
+	}
 #endif /* CONFIG_PHY_GIGE */

 	/* Check Basic Management Control Register first. */
-	if (miiphy_read (devname, addr, PHY_BMCR, &reg)) {
-		puts ("PHY speed read failed, assuming 10bT\n");
-		return (_10BASET);
+	if (miiphy_read (devname, addr, PHY_BMCR, &bmcr)) {
+		printf ("PHY speed");
+		goto miiphy_read_failed;
 	}
 	/* Check if auto-negotiation is on. */
-	if ((reg & PHY_BMCR_AUTON) != 0) {
+	if (bmcr & PHY_BMCR_AUTON) {
 		/* Get auto-negotiation results. */
-		if (miiphy_read (devname, addr, PHY_ANLPAR, &reg)) {
-			puts ("PHY AN speed read failed, assuming 10bT\n");
-			return (_10BASET);
-		}
-		if ((reg & PHY_ANLPAR_100) != 0) {
-			return (_100BASET);
-		} else {
-			return (_10BASET);
+		u16 anlpar;
+
+		if (miiphy_read (devname, addr, PHY_ANLPAR, &anlpar)) {
+			printf ("PHY AN speed");
+			goto miiphy_read_failed;
 		}
+		return (anlpar & PHY_ANLPAR_100) ? _100BASET : _10BASET;
 	}
 	/* Get speed from basic control settings. */
-	else if (reg & PHY_BMCR_100MB) {
-		return (_100BASET);
-	} else {
-		return (_10BASET);
-	}
+	return (bmcr & PHY_BMCR_100MB) ? _100BASET : _10BASET;

+      miiphy_read_failed:
+	printf (" read failed, assuming 10BASE-T\n");
+	return _10BASET;
 }

 /*****************************************************************************
  *
- * Determine full/half duplex.
+ * Determine full/half duplex.  Return half on error.
  */
 int miiphy_duplex (char *devname, unsigned char addr)
 {
-	unsigned short reg;
+	u16 bmcr;

 #if defined(CONFIG_PHY_GIGE)
-	if (miiphy_read (devname, addr, PHY_1000BTSR, &reg)) {
-		printf ("PHY 1000BT Status read failed\n");
-	} else {
-		if ((reg != 0xFFFF) &&
-		    (reg & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) {
-			if ((reg & PHY_1000BTSR_1000FD) != 0) {
-				return (FULL);
-			} else {
-				return (HALF);
+	u16 btsr;
+
+#if defined(CONFIG_PHY_DYNAMIC_ANEG)
+	u16 bmsr;
+
+	/* Check for 1000BASE-X. */
+	if (miiphy_read (devname, addr, PHY_BMSR, &bmsr)) {
+		printf ("PHY status");
+		goto miiphy_read_failed;
+	}
+	if (bmsr & PHY_BMSR_EXT_STAT) {
+		u16 exsr;
+
+		if (miiphy_read (devname, addr, PHY_EXSR, &exsr)) {
+			printf ("PHY extended status");
+			goto miiphy_read_failed;
+		}
+		if (exsr & (PHY_EXSR_1000XF | PHY_EXSR_1000XH)) {
+			/* 1000BASE-X */
+			u16 anlpar;
+
+			if (miiphy_read (devname, addr, PHY_ANLPAR, &anlpar)) {
+				printf ("1000BASE-X PHY AN duplex");
+				goto miiphy_read_failed;
 			}
+			return (anlpar & PHY_X_ANLPAR_FD) ? FULL : HALF;
+		}
+	}
+#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+
+	/* Check for 1000BASE-T. */
+	if (miiphy_read (devname, addr, PHY_1000BTSR, &btsr)) {
+		printf ("PHY 1000BT status");
+		goto miiphy_read_failed;
+	}
+	if (btsr != 0xFFFF) {
+		if (btsr & PHY_1000BTSR_1000FD) {
+			return FULL;
+		} else if (btsr & PHY_1000BTSR_1000HD) {
+			return HALF;
 		}
 	}
 #endif /* CONFIG_PHY_GIGE */

 	/* Check Basic Management Control Register first. */
-	if (miiphy_read (devname, addr, PHY_BMCR, &reg)) {
-		puts ("PHY duplex read failed, assuming half duplex\n");
-		return (HALF);
+	if (miiphy_read (devname, addr, PHY_BMCR, &bmcr)) {
+		puts ("PHY duplex");
+		goto miiphy_read_failed;
 	}
 	/* Check if auto-negotiation is on. */
-	if ((reg & PHY_BMCR_AUTON) != 0) {
+	if (bmcr & PHY_BMCR_AUTON) {
 		/* Get auto-negotiation results. */
-		if (miiphy_read (devname, addr, PHY_ANLPAR, &reg)) {
-			puts ("PHY AN duplex read failed, assuming half duplex\n");
-			return (HALF);
-		}
+		u16 anlpar;

-		if ((reg & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) != 0) {
-			return (FULL);
-		} else {
-			return (HALF);
+		if (miiphy_read (devname, addr, PHY_ANLPAR, &anlpar)) {
+			puts ("PHY AN duplex");
+			goto miiphy_read_failed;
 		}
+		return (anlpar & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) ?
+		    FULL : HALF;
 	}
 	/* Get speed from basic control settings. */
-	else if (reg & PHY_BMCR_DPLX) {
-		return (FULL);
-	} else {
-		return (HALF);
-	}
+	return (bmcr & PHY_BMCR_DPLX) ? FULL : HALF;

+      miiphy_read_failed:
+	printf (" read failed, assuming half duplex\n");
+	return HALF;
 }

 #ifdef CFG_FAULT_ECHO_LINK_DOWN
diff --git a/cpu/ppc4xx/miiphy.c b/cpu/ppc4xx/miiphy.c
index 2fa1b57..4056ca8 100644
--- a/cpu/ppc4xx/miiphy.c
+++ b/cpu/ppc4xx/miiphy.c
@@ -66,9 +66,82 @@ void miiphy_dump (char *devname, unsigned char addr)
 /***********************************************************/
 int phy_setup_aneg (char *devname, unsigned char addr)
 {
-	unsigned short ctl, adv;
+	u16 bmcr;
+
+#if defined(CONFIG_PHY_DYNAMIC_ANEG)
+	/*
+	 * Set up advertisement based on capablilities reported by the PHY.
+	 * This should work for both copper and fiber.
+	 */
+	u16 bmsr;
+#if defined(CONFIG_PHY_GIGE)
+	u16 exsr = 0x0000;
+#endif
+
+	miiphy_read (devname, addr, PHY_BMSR, &bmsr);
+
+#if defined(CONFIG_PHY_GIGE)
+	if (bmsr & PHY_BMSR_EXT_STAT) {
+		miiphy_read (devname, addr, PHY_EXSR, &exsr);
+	}
+
+	if (exsr & (PHY_EXSR_1000XF | PHY_EXSR_1000XH)) {
+		/* 1000BASE-X */
+		u16 anar = 0x0000;
+
+		if (exsr & PHY_EXSR_1000XF) {
+			anar |= PHY_X_ANLPAR_FD;
+		}
+		if (exsr & PHY_EXSR_1000XH) {
+			anar |= PHY_X_ANLPAR_HD;
+		}
+		miiphy_write (devname, addr, PHY_ANAR, anar);
+	} else
+#endif
+	{
+		u16 anar, btcr;
+
+		miiphy_read (devname, addr, PHY_ANAR, &anar);
+		anar &= ~(0x5000 | PHY_ANLPAR_T4 | PHY_ANLPAR_TXFD |
+			  PHY_ANLPAR_TX | PHY_ANLPAR_10FD | PHY_ANLPAR_10);
+
+		miiphy_read (devname, addr, PHY_1000BTCR, &btcr);
+		btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
+
+		if (bmsr & PHY_BMSR_100T4) {
+			anar |= PHY_ANLPAR_T4;
+		}
+		if (bmsr & PHY_BMSR_100TXF) {
+			anar |= PHY_ANLPAR_TXFD;
+		}
+		if (bmsr & PHY_BMSR_100TXH) {
+			anar |= PHY_ANLPAR_TX;
+		}
+		if (bmsr & PHY_BMSR_10TF) {
+			anar |= PHY_ANLPAR_10FD;
+		}
+		if (bmsr & PHY_BMSR_10TH) {
+			anar |= PHY_ANLPAR_10;
+		}
+		miiphy_write (devname, addr, PHY_ANAR, anar);
+
+#if defined(CONFIG_PHY_GIGE)
+		if (exsr & PHY_EXSR_1000TF) {
+			btcr |= PHY_1000BTCR_1000FD;
+		}
+		if (exsr & PHY_EXSR_1000TH) {
+			btcr |= PHY_1000BTCR_1000HD;
+		}
+		miiphy_write (devname, addr, PHY_1000BTCR, btcr);
+#endif
+	}
+
+#else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+	/*
+	 * Set up standard advertisement
+	 */
+	u16 adv;

-	/* Setup standard advertise */
 	miiphy_read (devname, addr, PHY_ANAR, &adv);
 	adv |= (PHY_ANLPAR_ACK | PHY_ANLPAR_RF | PHY_ANLPAR_T4 |
 		PHY_ANLPAR_TXFD | PHY_ANLPAR_TX | PHY_ANLPAR_10FD |
@@ -79,10 +152,12 @@ int phy_setup_aneg (char *devname, unsigned char addr)
 	adv |= (0x0300);
 	miiphy_write (devname, addr, PHY_1000BTCR, adv);

+#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
+
 	/* Start/Restart aneg */
-	miiphy_read (devname, addr, PHY_BMCR, &ctl);
-	ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
-	miiphy_write (devname, addr, PHY_BMCR, ctl);
+	miiphy_read (devname, addr, PHY_BMCR, &bmcr);
+	bmcr |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
+	miiphy_write (devname, addr, PHY_BMCR, bmcr);

 	return 0;
 }
diff --git a/include/miiphy.h b/include/miiphy.h
index 42f2ad0..83234b9 100644
--- a/include/miiphy.h
+++ b/include/miiphy.h
@@ -85,6 +85,7 @@ int bb_miiphy_write (char *devname, unsigned char addr,
 #define PHY_ANLPNP		0x08
 #define PHY_1000BTCR		0x09
 #define PHY_1000BTSR		0x0A
+#define PHY_EXSR		0x0F
 #define PHY_PHYSTS		0x10
 #define PHY_MIPSCR		0x11
 #define PHY_MIPGSR		0x12
@@ -118,6 +119,7 @@ int bb_miiphy_write (char *devname, unsigned char addr,
 #define PHY_BMSR_100TXH		0x2000
 #define PHY_BMSR_10TF		0x1000
 #define PHY_BMSR_10TH		0x0800
+#define PHY_BMSR_EXT_STAT	0x0100
 #define PHY_BMSR_PRE_SUP	0x0040
 #define PHY_BMSR_AUTN_COMP	0x0020
 #define PHY_BMSR_RF		0x0010
@@ -130,17 +132,30 @@ int bb_miiphy_write (char *devname, unsigned char addr,
 #define PHY_ANLPAR_NP		0x8000
 #define PHY_ANLPAR_ACK		0x4000
 #define PHY_ANLPAR_RF		0x2000
+#define PHY_ANLPAR_ASYMP	0x0800
+#define PHY_ANLPAR_PAUSE	0x0400
 #define PHY_ANLPAR_T4		0x0200
 #define PHY_ANLPAR_TXFD		0x0100
 #define PHY_ANLPAR_TX		0x0080
 #define PHY_ANLPAR_10FD		0x0040
 #define PHY_ANLPAR_10		0x0020
 #define PHY_ANLPAR_100		0x0380	/* we can run at 100 */
+/* phy ANLPAR 1000BASE-X */
+#define PHY_X_ANLPAR_NP		0x8000
+#define PHY_X_ANLPAR_ACK	0x4000
+#define PHY_X_ANLPAR_RF_MASK	0x3000
+#define PHY_X_ANLPAR_PAUSE_MASK	0x0180
+#define PHY_X_ANLPAR_HD		0x0040
+#define PHY_X_ANLPAR_FD		0x0020

 #define PHY_ANLPAR_PSB_MASK	0x001f
 #define PHY_ANLPAR_PSB_802_3	0x0001
 #define PHY_ANLPAR_PSB_802_9	0x0002

+/* phy 1000BTCR */
+#define PHY_1000BTCR_1000FD	0x0200
+#define PHY_1000BTCR_1000HD	0x0100
+
 /* phy 1000BTSR */
 #define PHY_1000BTSR_MSCF	0x8000
 #define PHY_1000BTSR_MSCR	0x4000
@@ -149,4 +164,10 @@ int bb_miiphy_write (char *devname, unsigned char addr,
 #define PHY_1000BTSR_1000FD	0x0800
 #define PHY_1000BTSR_1000HD	0x0400

+/* phy EXSR */
+#define PHY_EXSR_1000XF		0x8000
+#define PHY_EXSR_1000XH		0x4000
+#define PHY_EXSR_1000TF		0x2000
+#define PHY_EXSR_1000TH		0x1000
+
 #endif




More information about the U-Boot mailing list