blob: 8de8dae21c87ee641b61781c8218916522bf1bcd [file] [log] [blame]
/*!
* \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;
}
/********************************************************************/