[PATCH 038/111] GRETH: changed the PHY initialization sequence

Daniel Hellstrom daniel at gaisler.com
Thu Feb 26 16:38:40 UTC 2015


1. read_mii() now returns 0xffff on failure. It is more robust when it
   comes to reading the reset bit in the control register, that is the
   first access.

2. write_mii() now has error printout like read_mii().

3. Additional (optional) PHY access debugging is now available by
   enabling GRETH_DEBUG_MII. Even successful accesses are printed.

4. Let PHY do power-down (not only reset) to get in a good state,
   this is just in case the PHY input pin settings are sampled only
   on PHY power-up on some PHYs.

5. PHY GBit advertisement is disabled if Gbit is not supported by MAC.
   Or forced if supported.

6. Auto-nego is started if supported by PHY, before it was started only
   if default set by PHY.

7. Reset Sequence updated:
     * one must wait until reset bit is self-cleared.
     * the DD (Disable Duplex Detection) bit is set, only affects
       EDCL capable devices. This lets RTEMS handle PHY initialization
---
 c/src/lib/libbsp/sparc/shared/include/greth.h |    1 +
 c/src/lib/libbsp/sparc/shared/net/greth.c     |   80 +++++++++++++++++++++----
 2 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/include/greth.h b/c/src/lib/libbsp/sparc/shared/include/greth.h
index c0c3b9a..8c88172 100644
--- a/c/src/lib/libbsp/sparc/shared/include/greth.h
+++ b/c/src/lib/libbsp/sparc/shared/include/greth.h
@@ -81,6 +81,7 @@ typedef struct _greth_regs {
 #define GRETH_CTRL_FULLD        0x00000010 /* Full Duplex */
 #define GRETH_CTRL_PRO          0x00000020 /* Promiscuous (receive all) */
 #define GRETH_CTRL_RST          0x00000040 /* Reset MAC */
+#define GRETH_CTRL_DD           0x00001000 /* Disable EDCL Duplex Detection */
 
 /* Status Register */
 #define GRETH_STATUS_RXERR      0x00000001 /* Receive Error */
diff --git a/c/src/lib/libbsp/sparc/shared/net/greth.c b/c/src/lib/libbsp/sparc/shared/net/greth.c
index 769de59..ac4ec77 100644
--- a/c/src/lib/libbsp/sparc/shared/net/greth.c
+++ b/c/src/lib/libbsp/sparc/shared/net/greth.c
@@ -63,6 +63,14 @@ extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
 #define DBG(args...)
 #endif
 
+/* #define GRETH_DEBUG_MII */
+
+#ifdef GRETH_DEBUG_MII
+#define MIIDBG(args...) printk(args)
+#else
+#define MIIDBG(args...)
+#endif
+
 #ifdef CPU_U32_FIX
 extern void ipalign(struct mbuf *m);
 #endif
@@ -162,6 +170,8 @@ struct greth_softc
    
    /*Status*/
    struct phy_device_info phydev;
+   int phy_read_access;
+   int phy_write_access;
    int fd;
    int sp;
    int gb;
@@ -241,23 +251,40 @@ void greth_interrupt (void *arg)
 
 static uint32_t read_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr)
 {
+    sc->phy_read_access++;
     while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
     sc->regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
     while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
-    if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
+    if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) {
+	MIIDBG("greth%d: mii read[%d] OK to %x.%x (0x%08x,0x%08x)\n",
+                sc->minor, sc->phy_read_access, phy_addr, reg_addr,
+                sc->regs->ctrl, sc->regs->mdio_ctrl);
+
         return((sc->regs->mdio_ctrl >> 16) & 0xFFFF);
-    else {
-	printf("greth: failed to read mii\n");
-	return (0);
+    } else {
+	printf("greth%d: mii read[%d] failed to %x.%x (0x%08x,0x%08x)\n",
+                sc->minor, sc->phy_read_access, phy_addr, reg_addr,
+                sc->regs->ctrl, sc->regs->mdio_ctrl);
+	return (0xffff);
     }
 }
 
 static void write_mii(struct greth_softc *sc, uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
 {
+    sc->phy_write_access++;
     while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
     sc->regs->mdio_ctrl =
      ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
     while (sc->regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
+    if (!(sc->regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) {
+	MIIDBG("greth%d: mii write[%d] OK to %x.%x (0x%08x,0x%08x)\n",
+                sc->minor, sc->phy_write_access, phy_addr, reg_addr,
+                sc->regs->ctrl, sc->regs->mdio_ctrl);
+    } else {
+	printf("greth%d: mii write[%d] failed to %x.%x (0x%08x,0x%08x)\n",
+                sc->minor, sc->phy_write_access, phy_addr, reg_addr,
+                sc->regs->ctrl, sc->regs->mdio_ctrl);
+    }
 }
 
 static void print_init_info(struct greth_softc *sc) 
@@ -313,13 +340,14 @@ greth_initialize_hardware (struct greth_softc *sc)
     sc->rxInterrupts = 0;
     sc->rxPackets = 0;
 
-    regs->ctrl = 0;
     regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
-    regs->ctrl = 0;			/* Reset OFF */
-    
+    for (i = 0; i<100 && (regs->ctrl & GRETH_CTRL_RST); i++)
+        ;
+    regs->ctrl = GRETH_CTRL_DD; 	/* Reset OFF. SW do PHY Init */
+
     /* Check if mac is gbit capable*/
     sc->gbit_mac = (regs->ctrl >> 27) & 1;
-    
+
     /* Get the phy address which assumed to have been set
        correctly with the reset value in hardware*/
     if ( sc->phyaddr == -1 ) {
@@ -327,15 +355,40 @@ greth_initialize_hardware (struct greth_softc *sc)
     } else {
         phyaddr = sc->phyaddr;
     }
+    sc->phy_read_access = 0;
+    sc->phy_write_access = 0;
+
+    /* As I understand the PHY comes back to a good default state after
+     * Power-down or Reset, so we do both just in case. Power-down bit should
+     * be cleared.
+     * Wait for old reset (if asserted by boot loader) to complete, otherwise
+     * power-down instruction might not have any effect.
+     */
+    while (read_mii(sc, phyaddr, 0) & 0x8000) {}
+    write_mii(sc, phyaddr, 0, 0x0800); /* Power-down */
+    write_mii(sc, phyaddr, 0, 0x0000); /* Power-Up */
+    write_mii(sc, phyaddr, 0, 0x8000); /* Reset */
 
-    /* reset PHY */
-    write_mii(sc, phyaddr, 0, 0x8000);
+    /* We wait about 30ms */
+    rtems_task_wake_after(rtems_clock_get_ticks_per_second()/32);
 
     /* Wait for reset to complete and get default values */
     while ((phyctrl = read_mii(sc, phyaddr, 0)) & 0x8000) {}
 
-    /* If autonegotiation implemented we start it */
+    /* Enable/Disable GBit auto-neg advetisement so that the link partner
+     * know that we have/haven't GBit capability. The MAC may not support
+     * Gbit even though PHY does...
+     */
     phystatus = read_mii(sc, phyaddr, 1);
+    if (phystatus & 0x0100) {
+        tmp1 = read_mii(sc, phyaddr, 9);
+        if (sc->gbit_mac)
+            write_mii(sc, phyaddr, 9, tmp1 | 0x300);
+        else
+            write_mii(sc, phyaddr, 9, tmp1 & ~(0x300));
+    }
+
+    /* If autonegotiation implemented we start it */
     if (phystatus & 0x0008) {
         write_mii(sc, phyaddr, 0, phyctrl | 0x1200);
         phyctrl = read_mii(sc, phyaddr, 0);
@@ -437,9 +490,10 @@ auto_neg_done:
     }
     while ((read_mii(sc, phyaddr, 0)) & 0x8000) {}
 
-    regs->ctrl = 0;
     regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
-    regs->ctrl = 0;
+    for (i = 0; i < 100 && (regs->ctrl & GRETH_CTRL_RST); i++)
+        ;
+    regs->ctrl = GRETH_CTRL_DD;
 
     /* Initialize rx/tx descriptor table pointers. Due to alignment we 
      * always allocate maximum table size.
-- 
1.7.0.4




More information about the devel mailing list