/* * File: bcm5222.c * Purpose: Driver for the Micrel BCM5222 10/100 Ethernet PHY * * Notes: This driver was written specifically for the M5475EVB * and M5485EVB. These boards use the MII signals from * FEC0 to control the PHY. Therefore the fec_ch parameter * is ignored when doing MII reads and writes. */ #include "net.h" #include "fec.h" #include "bcm5222.h" #include "bas_printf.h" #if defined(MACHINE_FIREBEE) #include "firebee.h" #elif defined(MACHINE_M5484LITE) #include "m5484l.h" #elif defined(MACHINE_M54455) #include "m54455.h" #else #error "Unknown machine!" #endif #define DBG_BCM #ifdef DBG_BCM #define dbg(format, arg...) do { xprintf("DEBUG: " format, ##arg); } while (0) #else #define dbg(format, arg...) do { ; } while (0) #endif /* DBG_BCM */ /* * Initialize the BCM5222 PHY * * This function sets up the Auto-Negotiate Advertisement register * within the PHY and then forces the PHY to auto-negotiate for * it's settings. * * Params: * fec_ch FEC channel * phy_addr Address of the PHY. * speed Desired speed (10BaseT or 100BaseTX) * duplex Desired duplex (Full or Half) * * Return Value: * 0 if MII commands fail * 1 otherwise */ int bcm5222_init(uint8_t fec_ch, uint8_t phy_addr, uint8_t speed, uint8_t duplex) { int timeout; uint16_t settings; /* Initialize the MII interface */ fec_mii_init(fec_ch, SYSCLK / 1000); dbg("%s: PHY reset\r\n", __FUNCTION__); /* Reset the PHY */ if (!fec_mii_write(fec_ch, phy_addr, BCM5222_CTRL, BCM5222_CTRL_RESET | BCM5222_CTRL_ANE)) return 0; /* Wait for the PHY to reset */ for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++) { fec_mii_read(fec_ch, phy_addr, BCM5222_CTRL, &settings); if (!(settings & BCM5222_CTRL_RESET)) break; } if(timeout >= FEC_MII_TIMEOUT) return 0; dbg("%s: PHY reset OK\r\n", __FUNCTION__); settings = (BCM5222_AN_ADV_NEXT_PAGE | BCM5222_AN_ADV_PAUSE); if (speed == FEC_MII_10BASE_T) settings |= (uint16_t)((duplex == FEC_MII_FULL_DUPLEX) ? (BCM5222_AN_ADV_10BT_FDX | BCM5222_AN_ADV_10BT) : BCM5222_AN_ADV_10BT); else /* (speed == FEC_MII_100BASE_TX) */ settings = (uint16_t)((duplex == FEC_MII_FULL_DUPLEX) ? (BCM5222_AN_ADV_100BTX_FDX | BCM5222_AN_ADV_100BTX | BCM5222_AN_ADV_10BT_FDX | BCM5222_AN_ADV_10BT) : (BCM5222_AN_ADV_100BTX | BCM5222_AN_ADV_10BT)); /* Set the Auto-Negotiation Advertisement Register */ if (!fec_mii_write(fec_ch, phy_addr, BCM5222_AN_ADV, settings)) return 0; dbg("%s: PHY Enable Auto-Negotiation\r\n", __FUNCTION__); /* Enable Auto-Negotiation */ if (!fec_mii_write(fec_ch, phy_addr, BCM5222_CTRL, (BCM5222_CTRL_ANE | BCM5222_CTRL_RESTART_AN))) return 0; dbg("%s: PHY Wait for auto-negotiation to complete\r\n", __FUNCTION__); /* Wait for auto-negotiation to complete */ for (timeout = 0; timeout < FEC_MII_TIMEOUT; timeout++) { if (!fec_mii_read(fec_ch, phy_addr, BCM5222_STAT, &settings)) return 0; if (settings & BCM5222_STAT_AN_COMPLETE) break; } if (timeout < FEC_MII_TIMEOUT) { dbg("%s: PHY auto-negociation complete\r\n", __FUNCTION__); /* Read Auxiliary Control/Status Register */ if (!fec_mii_read(fec_ch, phy_addr, BCM5222_ACSR, &settings)) return 0; } else { dbg("%s: auto negotiation failed, PHY Set the default mode\r\n", __FUNCTION__); /* Set the default mode (Full duplex, 100 Mbps) */ if (!fec_mii_write(fec_ch, phy_addr, BCM5222_ACSR, settings = (BCM5222_ACSR_100BTX | BCM5222_ACSR_FDX))) return 0; } /* Set the proper duplex in the FEC now that we have auto-negotiated */ if (settings & BCM5222_ACSR_FDX) fec_duplex(fec_ch, FEC_MII_FULL_DUPLEX); else fec_duplex(fec_ch, FEC_MII_HALF_DUPLEX); dbg("%s: PHY Mode: ", __FUNCTION__); if (settings & BCM5222_ACSR_100BTX) dbg("%s: 100Mbps\r\n", __FUNCTION__); else dbg("%s: 10Mbps\r\n", __FUNCTION__); if (settings & BCM5222_ACSR_FDX) dbg("%s: Full-duplex\r\n", __FUNCTION__); else dbg("%s: Half-duplex\r\n", __FUNCTION__); return 1; } void bcm5222_get_reg(uint16_t* status0, uint16_t* status1) { fec_mii_read(0, 0x00, 0x00000000, &status0[0]); fec_mii_read(0, 0x00, 0x00000001, &status0[1]); fec_mii_read(0, 0x00, 0x00000004, &status0[4]); fec_mii_read(0, 0x00, 0x00000005, &status0[5]); fec_mii_read(0, 0x00, 0x00000006, &status0[6]); fec_mii_read(0, 0x00, 0x00000007, &status0[7]); fec_mii_read(0, 0x00, 0x00000008, &status0[8]); fec_mii_read(0, 0x00, 0x00000010, &status0[16]); fec_mii_read(0, 0x00, 0x00000011, &status0[17]); fec_mii_read(0, 0x00, 0x00000012, &status0[18]); fec_mii_read(0, 0x00, 0x00000013, &status0[19]); fec_mii_read(0, 0x00, 0x00000018, &status0[24]); fec_mii_read(0, 0x00, 0x00000019, &status0[25]); fec_mii_read(0, 0x00, 0x0000001B, &status0[27]); fec_mii_read(0, 0x00, 0x0000001C, &status0[28]); fec_mii_read(0, 0x00, 0x0000001E, &status0[30]); fec_mii_read(0, 0x01, 0x00000000, &status1[0]); fec_mii_read(0, 0x01, 0x00000001, &status1[1]); fec_mii_read(0, 0x01, 0x00000004, &status1[4]); fec_mii_read(0, 0x01, 0x00000005, &status1[5]); fec_mii_read(0, 0x01, 0x00000006, &status1[6]); fec_mii_read(0, 0x01, 0x00000007, &status1[7]); fec_mii_read(0, 0x01, 0x00000008, &status1[8]); fec_mii_read(0, 0x01, 0x00000010, &status1[16]); fec_mii_read(0, 0x01, 0x00000011, &status1[17]); fec_mii_read(0, 0x01, 0x00000012, &status1[18]); fec_mii_read(0, 0x01, 0x00000013, &status1[19]); fec_mii_read(0, 0x01, 0x00000018, &status1[24]); fec_mii_read(0, 0x01, 0x00000019, &status1[25]); fec_mii_read(0, 0x01, 0x0000001B, &status1[27]); fec_mii_read(0, 0x01, 0x0000001C, &status1[28]); fec_mii_read(0, 0x01, 0x0000001E, &status1[30]); }