181 lines
5.8 KiB
C
181 lines
5.8 KiB
C
/*
|
|
* 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_M5475EVB)
|
|
#include "m5475e.h"
|
|
#elif defined(MACHINE_M54455)
|
|
#include "m54455.h"
|
|
#else
|
|
#error "Unknown machine!"
|
|
#endif
|
|
|
|
// #define DEBUG
|
|
#include "debug.h"
|
|
|
|
/*
|
|
* 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("PHY reset\r\n");
|
|
|
|
/* 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("PHY reset OK\r\n");
|
|
|
|
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("PHY Enable Auto-Negotiation\r\n");
|
|
|
|
/* Enable Auto-Negotiation */
|
|
if (!fec_mii_write(fec_ch, phy_addr, BCM5222_CTRL, (BCM5222_CTRL_ANE | BCM5222_CTRL_RESTART_AN)))
|
|
return 0;
|
|
|
|
dbg("PHY Wait for auto-negotiation to complete\r\n");
|
|
|
|
/* 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("PHY auto-negociation complete\r\n");
|
|
|
|
/* Read Auxiliary Control/Status Register */
|
|
if (!fec_mii_read(fec_ch, phy_addr, BCM5222_ACSR, &settings))
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
dbg("auto negotiation failed, PHY Set the default mode\r\n");
|
|
|
|
/* 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("PHY Mode: ");
|
|
|
|
if (settings & BCM5222_ACSR_100BTX)
|
|
dbg("100Mbps\r\n");
|
|
else
|
|
dbg("10Mbps\r\n");
|
|
|
|
if (settings & BCM5222_ACSR_FDX)
|
|
dbg("Full-duplex\r\n");
|
|
else
|
|
dbg("Half-duplex\r\n");
|
|
|
|
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]);
|
|
}
|
|
|