From 107c5aea262b0e2e849638e56fd34e41efb5f2c4 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Wed, 13 Mar 2013 16:40:05 +0100 Subject: GRETH: changed the PHY initialization sequence 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/net/greth.c | 80 ++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 13 deletions(-) (limited to 'c/src/lib/libbsp/sparc/shared/net') diff --git a/c/src/lib/libbsp/sparc/shared/net/greth.c b/c/src/lib/libbsp/sparc/shared/net/greth.c index 769de59016..ac4ec7792d 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. -- cgit v1.2.3