/*! | |
* \file mii.c | |
* \brief Media Independent Interface (MII) driver | |
* \version $Revision: 1.2 $ | |
* \author Michael Norman | |
* | |
* \warning This driver assumes that FEC0 is used for all MII management | |
* communications. For dual PHYs, etc. Insure that FEC0_MDC and | |
* FEC0_MDIO are connected to the PHY's MDC and MDIO. | |
*/ | |
#include "common.h" | |
#include "mii.h" | |
/********************************************************************/ | |
/* | |
* \brief Initialize the MII interface controller | |
* \param System Clock Frequency (in MHz) | |
* \warning The system clock in this case is the clock that drives | |
* the FEC logic. This may be different from the speed at which | |
* the CPU is operating. | |
* | |
* Initialize the MII clock (EMDC) frequency. The desired MII clock is 2.5MHz: | |
* | |
* MII Speed Setting = System_Clock / (2.5MHz * 2) | |
* (plus 1 to round up) | |
*/ | |
void | |
mii_init(int ch, int sys_clk_mhz) | |
{ | |
ENET_MSCR/*(ch)*/ = 0 | |
#ifdef TSIEVB/*TSI EVB requires a longer hold time than default 10 ns*/ | |
| ENET_MSCR_HOLDTIME(2) | |
#endif | |
| ENET_MSCR_MII_SPEED((2*sys_clk_mhz/5)+1) | |
; | |
} | |
/********************************************************************/ | |
/*! | |
* \brief Write a value to a PHY's MII register. | |
* | |
* \param phy_addr Address of the PHY | |
* \param reg_addr Address of the register in the PHY | |
* \param data Data to be written to the PHY register | |
* \return 0 if write is successful; 1 if write times out | |
* | |
* mii_write() polls for the FEC's MII interrupt event (which should | |
* be masked from the interrupt handler) and clears it. If after a | |
* suitable amount of time the event isn't triggered, a non-zero value | |
* is returned. | |
*/ | |
int | |
mii_write(int ch, int phy_addr, int reg_addr, int data) | |
{ | |
int timeout; | |
/* Clear the MII interrupt bit */ | |
ENET_EIR/*(ch)*/ = ENET_EIR_MII_MASK; | |
/* Initiatate the MII Management write */ | |
ENET_MMFR/*(ch)*/ = 0 | |
| ENET_MMFR_ST(0x01) | |
| ENET_MMFR_OP(0x01) | |
| ENET_MMFR_PA(phy_addr) | |
| ENET_MMFR_RA(reg_addr) | |
| ENET_MMFR_TA(0x02) | |
| ENET_MMFR_DATA(data); | |
/* Poll for the MII interrupt (interrupt should be masked) */ | |
for (timeout = 0; timeout < MII_TIMEOUT; timeout++) | |
{ | |
if (ENET_EIR/*(ch)*/ & ENET_EIR_MII_MASK) | |
break; | |
} | |
if(timeout == MII_TIMEOUT) | |
return 1; | |
/* Clear the MII interrupt bit */ | |
ENET_EIR/*(ch)*/ = ENET_EIR_MII_MASK; | |
return 0; | |
} | |
/********************************************************************/ | |
/*! | |
* \brief Read a value from a PHY's MII register. | |
* \param phy_addr Address of the PHY | |
* \param reg_addr Address of the register in the PHY | |
* \param data Pointer to location were read data will be stored | |
* \return 0 if write is successful; 1 if write times out | |
* | |
* mii_read() polls for the FEC's MII interrupt event (which should | |
* be masked from the interrupt handler) and clears it. If after a | |
* suitable amount of time the event isn't triggered, a non-zero value | |
* is returned. | |
*/ | |
int | |
mii_read(int ch, int phy_addr, int reg_addr, int *data) | |
{ | |
int timeout; | |
/* Clear the MII interrupt bit */ | |
ENET_EIR/*(ch)*/ = ENET_EIR_MII_MASK; | |
/* Initiatate the MII Management read */ | |
ENET_MMFR/*(ch)*/ = 0 | |
| ENET_MMFR_ST(0x01) | |
| ENET_MMFR_OP(0x2) | |
| ENET_MMFR_PA(phy_addr) | |
| ENET_MMFR_RA(reg_addr) | |
| ENET_MMFR_TA(0x02); | |
/* Poll for the MII interrupt (interrupt should be masked) */ | |
for (timeout = 0; timeout < MII_TIMEOUT; timeout++) | |
{ | |
if (ENET_EIR/*(ch)*/ & ENET_EIR_MII_MASK) | |
break; | |
} | |
if(timeout == MII_TIMEOUT) | |
return 1; | |
/* Clear the MII interrupt bit */ | |
ENET_EIR/*(ch)*/ = ENET_EIR_MII_MASK; | |
*data = ENET_MMFR/*(ch)*/ & 0x0000FFFF; | |
return 0; | |
} | |
/********************************************************************/ |