/*!
 * \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;
}
/********************************************************************/
