[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, ®)) {
- 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, ®)) {
- 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, ®)) {
- 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, ®)) {
- 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, ®)) {
- 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, ®)) {
- 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