/**
* @file icss_miimdio.c
*
* @brief Contains the MDIO Interface
*
* \par
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
* \par
*/
/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include <ti/ndk/inc/stkmain.h>
#include "icss_common.h"
#include "icss_miimdio.h"
#include "icss_miimdio_regs.h"
#include "mdio.h"
#include "phy.h"
#include "osdrv_mdio.h"
#include "osdrv_ndkdeviceconfig.h"


/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
/**
* @def COMMON_RANDOM_MAX
*      R A N D O M  N U M B E R  S U P P O R T
*/
#define COMMON_RANDOM_MAX        0xFFFFu
/**
* @def mdioPrintf
*      MDIO printf
*/
#define mdioPrintf printf
/**
* @def  _icssIsGigPhy(PhyDev)
*      Defines whether ports have gigabit mode support
*/
#define   _icssIsGigPhy(PhyDev) 	(TRUE)
/**
* @def PHY_NOT_FOUND
*      Used in Phy Detection
*/
#define PHY_NOT_FOUND  0xFFFFu
/**
* @def PHY_DEV_OFFSET
*      CHECK:: PhyState field breakup
*/
#define PHY_DEV_OFFSET      (0u)
/**
* @def PHY_DEV_SIZE
*      PHY device size
*/
#define PHY_DEV_SIZE        (5u)
/**
* @def PHY_DEV_MASK
*      PHY device mask
*/
#define PHY_DEV_MASK        (0x1f<<PHY_DEV_OFFSET)
/**
* @def PHY_STATE_OFFSET
*      PHY state offset
*/
#define PHY_STATE_OFFSET    (PHY_DEV_SIZE+PHY_DEV_OFFSET)
/**
* @def PHY_STATE_SIZE
*      PHY state reg size(in bits)
*/
#define PHY_STATE_SIZE      (5u)
/**
* @def PHY_STATE_MASK
*      Mask to extract PHY state information
*/
#define PHY_STATE_MASK      (0x1fu<<PHY_STATE_OFFSET)
/**
* @def INIT
*      Init bit mask within PHY state
*/
#define INIT       			(1u<<PHY_STATE_OFFSET)
/**
* @def FINDING
*      finding bit mask within PHY state
*/
#define FINDING    			(2u<<PHY_STATE_OFFSET)
/**
* @def FOUND
*      Found bit mask within PHY state
*/
#define FOUND      			(3u<<PHY_STATE_OFFSET)
/**
* @def NWAY_START
*      nway start bit mask within PHY state
*/
#define NWAY_START 			(4u<<PHY_STATE_OFFSET)
/**
* @def NWAY_WAIT
*      nway wait bit mask within PHY state
*/
#define NWAY_WAIT  			(5u<<PHY_STATE_OFFSET)
/**
* @def LINK_WAIT
*      link wait bit mask within PHY state
*/
#define LINK_WAIT  			(6u<<PHY_STATE_OFFSET)
/**
* @def LINKED
*      linked wait bit mask within PHY state
*/
#define LINKED     			(7u<<PHY_STATE_OFFSET)
/**
* @def LOOPBACK
*      loopback bit mask within PHY state
*/
#define LOOPBACK   			(8u<<PHY_STATE_OFFSET)
/**
* @def PHY_SPEED_OFFSET
*      PHY speed reg offset
*/
#define PHY_SPEED_OFFSET    (PHY_STATE_OFFSET+PHY_STATE_SIZE)
/**
 * @def PHY_SPEED_SIZE
 *      PHY speed reg size (in bits)
 */
#define PHY_SPEED_SIZE      (1u)
/**
* @def PHY_SPEED_MASK_ICSS
*      PHY speed reg mask
*/
#define PHY_SPEED_MASK_ICSS      (1u<<PHY_SPEED_OFFSET)
/**
* @def PHY_DUPLEX_OFFSET
*      PHY Duplex reg offset
*/
#define PHY_DUPLEX_OFFSET   (PHY_SPEED_OFFSET+PHY_SPEED_SIZE)
/**
* @def PHY_DUPLEX_SIZE
*      PHY Duplex reg size(in bits)
*/
#define PHY_DUPLEX_SIZE     (1u)
/**
* @def PHY_DUPLEX_MASK
*      PHY Duplex register mask
*/
#define PHY_DUPLEX_MASK     (1u<<PHY_DUPLEX_OFFSET)
/**
* @def PHY_TIM_OFFSET
*      PHY TIM reg offset
*/
#define PHY_TIM_OFFSET      (PHY_DUPLEX_OFFSET+PHY_DUPLEX_SIZE)
/**
* @def PHY_TIM_SIZE
*      PHY TIM reg size(in bits)
*/
#define PHY_TIM_SIZE        (10u)
/**
* @def PHY_TIM_MASK
*      PHY TIM reg bit mask
*/
#define PHY_TIM_MASK        (0x3ffu<<PHY_TIM_OFFSET)
/**
* @def PHY_FIND_TO
*     100ms interval
*/

#define PHY_FIND_TO (  1u<<PHY_TIM_OFFSET)
/**
* @def PHY_RECK_TO
*      2 Second interval
*/
#define PHY_RECK_TO (20u<<PHY_TIM_OFFSET)
/**
* @def PHY_LINK_TO
*      5 second interval
*/
#define PHY_LINK_TO (50u<<PHY_TIM_OFFSET)
/**
* @def PHY_NWST_TO
*      5 second interval
*/
#define PHY_NWST_TO (50u<<PHY_TIM_OFFSET)
/**
* @def PHY_NWDN_TO
*     8 second interval
*/
#define PHY_NWDN_TO (80u<<PHY_TIM_OFFSET)
/**
* @def PHY_MDIX_TO
*      2.74 Seconds <--Spec and empirical
*/
#define PHY_MDIX_TO (27u<<PHY_TIM_OFFSET)
/**
* @def PHY_SMODE_OFFSET
*      PHY S Mode Reg offset
*/
#define PHY_SMODE_OFFSET    (PHY_TIM_OFFSET+PHY_TIM_SIZE)
/**
* @def PHY_SMODE_SIZE
*      PHY S Mode size (in bits)
*/
#define PHY_SMODE_SIZE      (7u)
/**
* @def PHY_SMODE_MASK
*      PHY S Mode bit mask
*/
#define PHY_SMODE_MASK      (0x7fu<<PHY_SMODE_OFFSET)
/**
* @def SMODE_LPBK
*      PHY S Mode link break bit mask
*/
#define SMODE_LPBK   (0x40u<<PHY_SMODE_OFFSET)
/**
* @def SMODE_AUTO
*      PHY S Mode auto bit mask
*/
#define SMODE_AUTO   (0x20u<<PHY_SMODE_OFFSET)

#ifdef GIGABIT_MODE_SUPPORT
#define SMODE_FD1000 (0x10u<<PHY_SMODE_OFFSET)
#endif
/**
* @def SMODE_FD100
*      PHY Full Duplex 100 Mbps reg offset
*/
#define SMODE_FD100  (0x08u<<PHY_SMODE_OFFSET)
/**
* @def SMODE_HD100
*      PHY Half Duplex 100 Mbps reg offset
*/
#define SMODE_HD100  (0x04u<<PHY_SMODE_OFFSET)
/**
* @def SMODE_FD10
*      PHY Full Duplex 10 Mbps reg offset
*/
#define SMODE_FD10   (0x02u<<PHY_SMODE_OFFSET)
/**
* @def SMODE_HD10
*      PHY Half Duplex 10 Mbps reg offset
*/
#define SMODE_HD10   (0x01u<<PHY_SMODE_OFFSET)
/**
* @def SMODE_ALL
*      PHY reg offset for FD/HD 10/100
*/
#define SMODE_ALL    (0x1fu<<PHY_SMODE_OFFSET)
/**
* @def PHY_CHNG_OFFSET
*      PHY Change reg offset
*/
#define PHY_CHNG_OFFSET    (PHY_SMODE_OFFSET+PHY_SMODE_SIZE)
/**
* @def PHY_CHNG_SIZE
*      PHY change reg size (in bits)
*/
#define PHY_CHNG_SIZE      (1u)
/**
* @def PHY_CHNG_MASK
*      PHY change reg mask
*/
#define PHY_CHNG_MASK      (1u<<PHY_CHNG_OFFSET)
/**
* @def PHY_CHANGE
*      PHY change reg mask
*/
#define PHY_CHANGE 		   (1u<<PHY_CHNG_OFFSET)
/**
* @def PHY_TIMEDOUT_OFFSET
*      PHY Timedout reg offset
*/
#define PHY_TIMEDOUT_OFFSET    (PHY_CHNG_OFFSET+PHY_CHNG_SIZE)
/**
* @def PHY_TIMEDOUT_SIZE
*      PHY Timedout reg size (in bits). 30 Bits used
*/
#define PHY_TIMEDOUT_SIZE      (1u)
/**
* @def PHY_TIMEDOUT_MASK
*      PHY Timedout bit mask
*/
#define PHY_TIMEDOUT_MASK      ((Uint32)(1u<<PHY_TIMEDOUT_OFFSET))
/**
* @def PHY_MDIX_SWITCH
*      PHY MDIX Switch Mask
*/
#define PHY_MDIX_SWITCH        ((Uint32)(1u<<PHY_TIMEDOUT_OFFSET))
/**
* @def PHY_MDIX_OFFSET
*      PHY MDIX reg offset
*/
#define PHY_MDIX_OFFSET    (PHY_TIMEDOUT_OFFSET+PHY_TIMEDOUT_SIZE)
/**
* @def PHY_MDIX_SIZE
*      PHY MDIX Size. 31 Bits used
*/
#define PHY_MDIX_SIZE      (1u)
/**
* @def PHY_MDIX_MASK
*      PHY MDIX Mask
*/
#define PHY_MDIX_MASK      ((Uint32)(1u<<PHY_MDIX_OFFSET))
/**
* @def PHY_MDIX
*     PHY MDIX Mask
*/
#define PHY_MDIX           ((Uint32)(1u<<PHY_MDIX_OFFSET))


#ifndef USE_STARTERWARE_MDIO_APIS
/*  Local MDIO Register Macros    */
#define myMDIO_ALIVE           MDIO_ALIVE(PhyDev->miibase)
#define myMDIO_CONTROL         MDIO_CONTROL(PhyDev->miibase)
#define myMDIO_LINK            MDIO_LINK(PhyDev->miibase)
#define myMDIO_LINKINT         MDIO_LINKINT(PhyDev->miibase)
#define myMDIO_USERACCESS      MDIO_USERACCESS(PhyDev->miibase, PhyDev->inst)
#define myMDIO_USERPHYSEL      MDIO_USERPHYSEL(PhyDev->miibase, PhyDev->inst)
#define myMDIO_VER             MDIO_VER(PhyDev->miibase)
#endif


#ifndef VOLATILE32
#define VOLATILE32(addr) (*((volatile Uint32 *)(addr)))
#endif

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
/**Speed set flag*/
Int32 g_speed_set = 0;
/**Soft reset status*/
Int32 g_soft_reset_status = 0;
/**Random seed*/
static Uint32 RandomSeed = 1u;

#ifndef USE_STARTERWARE_MDIO_APIS
/* Local Helper Function Prototypes */
static void   _icss_MDIO_WaitForAccessComplete(PHY_DEVICE *PhyDev);
static void   _icss_MDIO_UserAccess(PHY_DEVICE *PhyDev, Uint32 method, Uint32 regadr, Uint32 phyadr, Uint32 data);
#endif

/* Debug Print infrastructure */
#ifdef __ICSS_MDIO_DEBUG
static char *lstate[]={"NULL","INIT","FINDING","FOUND","NWAY_START","NWAY_WAIT","LINK_WAIT","LINKED","LOOPBACK"};

static void _icss_MDIO_DumpPhy(PHY_DEVICE *PhyDev, Uint32 p);
static void _icss_MDIO_DumpState(PHY_DEVICE *PhyDev);
static void _icss_MDIO_DumpPhyDetailed(PHY_DEVICE *PhyDev);
#endif

static void ICSSMDIOPhyTimeOut(PHY_DEVICE *PhyDev);
static void ICSSMDIOResetPhy(PHY_DEVICE *PhyDev,Uint32 PhyNum);
static void ICSSMDIODefaultState  (PHY_DEVICE *PhyDev);
static void ICSSMDIOFindingState  (PHY_DEVICE *PhyDev);
static void ICSSMDIOFoundState    (PHY_DEVICE *PhyDev);
static void ICSSMDIOInitState     (PHY_DEVICE *PhyDev);
static void ICSSMDIOLinkedState   (PHY_DEVICE *PhyDev);
static void ICSSMDIOLoopbackState (PHY_DEVICE *PhyDev);
static void ICSSMDIONwayStartState(PHY_DEVICE *PhyDev);
static void ICSSMDIONwayWaitState (PHY_DEVICE *PhyDev);
static void ICSSMDIOLinkWaitState(PHY_DEVICE *PhyDev);

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

/**
* @internal
* @brief Generates a random seed value
*
* @param none
*
* @retval 32 bit random seed value
*/
static Uint32 IcssRandom(void)
{
  RandomSeed = (RandomSeed * (1103515245u)) + (12345u);
  return ((Uint32) (RandomSeed/(65536u)) % (COMMON_RANDOM_MAX + 1u));
}

/**
* @internal
* @brief Given a max and min generates a random number in between
*
* @param min minimum value for the random range
* @param max maximum value for the random range
*
* @retval 32 bit random seed value
*/
static Uint32 IcssRandomRange(Uint32 min, Uint32 max)
{
  Uint32 iTmp;

  iTmp =  IcssRandom();
  iTmp %= ((max - min) + 1u);
  iTmp += min;
  return(iTmp);
}


/**
* @internal
* @brief Updates book-keeping with info provided, programs ControlReg with clkdiv,enable bits
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param miibase  32 bit offset to the MII Base address in the subsystem
* @param inst
* @param PhyMask
* @param MLinkMask
* @param MdixMask
* @param PhyNUM	     Phy Number
* @param ResetBit
* @param MdioBusFreq   Bus frequency in KHz
* @param MdioClockFreq Clock frequency in KHz
* @param verbose
*
* @retval success or failure
*/
int ICSSMDIOInit(PHY_DEVICE *PhyDev, Uint32 miibase, Uint32 inst, Uint32 PhyMask, Uint32 MLinkMask, Uint32 MdixMask, Uint32 PhyNUM, Uint32 ResetBit, Uint32 MdioBusFreq, Uint32 MdioClockFreq,int verbose)
{

  Uint32 *PhyState = &PhyDev->PhyState;
  Int32  ret =0 ;

#ifndef USE_STARTERWARE_MDIO_APIS
  Uint32 HighestChannel;
  Uint32 ControlState;
  Uint32 clkdiv;
  Uint16 reg = 0;
#endif

  PhyDev->miibase   = miibase;
  PhyDev->inst      = inst;
  PhyDev->PhyMask   = PhyMask;
  PhyDev->MLinkMask = MLinkMask;
  PhyDev->MdixMask  = MdixMask;


  (void)verbose;/* remove if not required */
  
  *PhyState &= ~PHY_MDIX_MASK;   /* Set initial State to MDI */
 


#ifdef USE_STARTERWARE_MDIO_APIS
  	MDIOInit(PhyDev->miibase, MdioClockFreq, MdioBusFreq);



	 *PhyState=INIT;

	 ret = 0;
#else

  /* Check that the channel supplied is within range */
  /* GSG 1/18/05 - Applied fix identified by Denis.  The definition of the
     Control register changed between versions of MDIO. */

  	HighestChannel = myMDIO_CONTROL >> 8;
  	 if ((myMDIO_VER & 0x0ffff) > 0x0102)
  	 {
  	 	HighestChannel = myMDIO_CONTROL >> 24;
  	 }
  	 HighestChannel &= 0x1f;

  	 if(inst > HighestChannel)
  	 {
  	 	     ret =(Int32)HighestChannel;
  	 }
  	 else
  	 {

  		/*Setup MII MDIO access regs*/

  		// FW todo: still need to check the clock calculation

  		/* Calculate the correct value for the mclkdiv */
  	 	  	if (0u != MdioClockFreq)                                              /*MJH+030402*/
  	 		{
	  		//clkdiv = (MdioBusFreq / MdioClockFreq) - 1;                  /*MJH+030402*/
  	 	  		clkdiv = (MdioClockFreq / MdioBusFreq) - 1;                  /*MJH+030402*/
  	 		}
  	 	  	else                                                            /*MJH+030402*/
  	 	  	{
  	 	  		clkdiv = MDIO_CONTROL_CLKDIV;                                  /*MJH+030402*/
  	 		}

  	 	 	ControlState  = MDIO_CONTROL_ENABLE ;
  	   	ControlState |= ((clkdiv) & MDIO_CONTROL_CLKDIV);

  	   	myMDIO_CONTROL = ControlState;  /* Enable MDIO   */
  
	  	(void)ResetReg; /* suppress warning */
	  	(void)ResetBit; /* suppress warning */

	  	*PhyState=INIT;
  	
	  	ret = 0;
	  }
	#endif //

  	return ret;
}/* end of function icss_MDIO_Init*/

/**
* @internal
* @brief Sets the PHY mode (Manual or Auto Negotiate)
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param PhyMode  32 bit offset to the MII Base address in the subsystem
*
* @retval none
*/
void ICSSMDIOSetPhyMode(PHY_DEVICE *PhyDev,Uint32 PhyMode)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32 CurrentState;

  PhyDev->PhyMode = PhyMode;   /* used for AUTOMIDX, planned to replace PhyState fields */
  *PhyState &= (~PHY_SMODE_MASK);

  if (0u != (PhyMode & NWAY_LPBK))
    {
    *PhyState |= SMODE_LPBK;
    }
  if (0u != (PhyMode & NWAY_AUTO))
    {
     *PhyState |= SMODE_AUTO;
    }

#ifdef GIGABIT_MODE_SUPPORT
  if (0u != (PhyMode & NWAY_FD1000) )
    {
    *PhyState |= SMODE_FD1000;
    }
#endif

  if (0u!= (PhyMode & NWAY_FD100))
    {
    *PhyState |= SMODE_FD100;
    }
  if (0u != (PhyMode & NWAY_HD100))
    {
    *PhyState |= SMODE_HD100;
    }
  if (0u != (PhyMode & NWAY_FD10))
    {
    *PhyState |= SMODE_FD10;
    }
  if (0u != (PhyMode & NWAY_HD10))
    {
    *PhyState |= SMODE_HD10;
    }

  CurrentState = (*PhyState) & PHY_STATE_MASK;
  if ( ((CurrentState == NWAY_START)|| (CurrentState == NWAY_WAIT)) ||
       ( ((CurrentState == LINK_WAIT) || (CurrentState == LINKED) ) || (CurrentState == LOOPBACK)) )
    {
    *PhyState = ( (*PhyState)&(~PHY_STATE_MASK)) | (FOUND | PHY_CHANGE);
    }
	 
	//_icss_MDIO_DumpState(PhyDev);
  }

/**
* @internal
* @brief Sets the PHY mode (Manual or Auto Negotiate)
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval PhyMode unsigned 32 bit value indicating the phy mode
*/
Uint32 ICSSMDIOGetPhyMode(PHY_DEVICE *PhyDev)
{
    Uint32  PhyMode =0;
    Uint32  control_reg = 0,advertize_reg;
    Uint32  PhyNum,j;
    Uint32  PhyMask   = PhyDev->PhyMask;

    PhyNum = 0; 
    for(j = 1;PhyNum < 32;PhyNum++)
    {
      if( 0u != ( j & PhyMask))
	{
	break;
	}
      j = j<<1;
    }

#ifdef GIGABIT_MODE_SUPPORT
    if(0u != _icssIsGigPhy(PhyDev))
    {
       /* read gig status */
       control_reg =ICSSMDIOUserAccessRead(PhyDev, NWAY_1000BT_ADVERTISE_REG, PhyNum);
       /* read gig status */
       status_reg =ICSSMDIOUserAccessRead(PhyDev, NWAY_1000BT_REMADVERTISE_REG, PhyNum);
    }
    /* figure out if gig connected at FD 1000 or not first */
    if ((0u != (control_reg & MII_NWAY_MY_FD1000)) && (0u != (status_reg & MII_NWAY_REM_FD1000)) )
    {
        PhyMode |= NWAY_FD1000;
    }
#endif
    
    control_reg = ICSSMDIOUserAccessRead(PhyDev, PHY_BCR, PhyNum);
    if(0u != (control_reg & MII_AUTO_NEGOTIATE_EN)  )
    {
       PhyMode |= NWAY_AUTO;
    }
    ICSSMDIOUserAccessRead(PhyDev, PHY_BSR, PhyNum);
    advertize_reg = ICSSMDIOUserAccessRead(PhyDev, PHY_AUTONEG_ADV, PhyNum);

    /* Check for 10/100 capabilities of PHYs */
    if((0u != (control_reg & MII_PHY_100))|| (0u != (PhyMode & NWAY_AUTO)) )
    {
       if(0u != (advertize_reg & MII_NWAY_FD100))
	    {
	    PhyMode |= NWAY_FD100;
	    }
       if(0u != (advertize_reg & MII_NWAY_HD100))
	    {
	    PhyMode |= NWAY_HD100;
	    }
       
    }
   
    if(((control_reg & MII_PHY_100) == 0) || (0u != (PhyMode & NWAY_AUTO)) )
    {
       if(0u != (advertize_reg & MII_NWAY_FD10))
	    {
	    PhyMode |= NWAY_FD10;
	    }
       if(0u != (advertize_reg & MII_NWAY_HD10))
	    {
	    PhyMode |= NWAY_HD10;
	    }
       
    }
	//_icss_MDIO_DumpState(PhyDev);
    return PhyMode;
}

/**
* @internal
* @brief icss_MDIO_Tic is called every 10 mili seconds to process Phy states
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param mdioStatus pointer to the mdio status, this is updated with the current mdio status value
*
* @retval status unsigned word indicating whether the polling was successful or not
*/
int ICSSMDIOTic(PHY_DEVICE *PhyDev,Uint32* mdioStatus)
{
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  CurrentState;
  Int32   ret = 0;

  *mdioStatus = MDIO_EVENT_NOCHANGE;
  
  /*Act on current state of the Phy */
  CurrentState=*PhyState;
  switch(CurrentState&PHY_STATE_MASK)
    {
    case INIT:         ICSSMDIOInitState(PhyDev);      break;
    case FINDING:      ICSSMDIOFindingState(PhyDev);   break;
    case FOUND:        ICSSMDIOFoundState(PhyDev);     break;
    case NWAY_START:   ICSSMDIONwayStartState(PhyDev); break;
    case NWAY_WAIT:    ICSSMDIONwayWaitState(PhyDev);  break;
    case LINK_WAIT:    ICSSMDIOLinkWaitState(PhyDev);  break;
    case LINKED:       ICSSMDIOLinkedState(PhyDev);    break;
    case LOOPBACK:     ICSSMDIOLoopbackState(PhyDev);  break;
    default:           ICSSMDIODefaultState(PhyDev);   break;
    }

  /*Dump state info if a change has been detected                            */
#ifdef __ICSS_MDIO_DEBUG
  if ((CurrentState & (~PHY_TIM_MASK))!=( (*PhyState)&(~PHY_TIM_MASK) ))
    {
    _icss_MDIO_DumpState(PhyDev);
    }
#endif

  /*  Check is MDI/MDIX mode switch is needed */
  if(0u != ((*PhyState) & PHY_MDIX_SWITCH) )
    {
    Uint32 Mdix;

    *PhyState &= (~PHY_MDIX_SWITCH);  /* Clear Mdix Flip indicator */

    if(0u != ((*PhyState) & PHY_MDIX))
	{
      Mdix = 1;
	}
    else
	{
      Mdix = 0;
    }
    ret = (Int32)(_MIIMDIO_MDIXFLIP | Mdix);
    }
  else
    {

  /*Return state change to user */
  /** CHECK : report MDIO_LINKEVENTS as MDIO_EVENT_NOCHANGE, MDIO_EVENT_LINKDOWN,
   * MDIO_EVENT_PHYERROR,MDIO_EVENT_LINKUP
   * Currently PHY_CHNG_MASK set for any state transition*/
   
    if (0u != ((*PhyState) & PHY_CHNG_MASK))
   {
   	if(  ( ((*PhyState) & PHY_STATE_MASK) == LINKED) && ((CurrentState & PHY_STATE_MASK) != LINKED) )
   		{
   		/* we have just entered LInked state */
   		*mdioStatus = MDIO_EVENT_LINKUP;
   		}
   	if(  ((CurrentState & PHY_STATE_MASK) == LINKED) && ( ( (*PhyState) & PHY_STATE_MASK) != LINKED))
   		{
   		/* we started in Linked state and we have a state change */
   		*mdioStatus = MDIO_EVENT_LINKDOWN;
   		}
    	*PhyState &= (~PHY_CHNG_MASK);
    	ret = (Int32)(TRUE);
    }
   else
   {
    	ret = (Int32)(FALSE);
	}
    }
   	
  return ret;

}

/**
* @internal
* @brief Change the MDIO link status
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOLinkChange(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  PhyNum,PhyStatus;

  PhyNum = ( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;


  if (0u != (ICSSMDIOGetLinked(PhyDev)) )
    {
    PhyStatus=ICSSMDIOUserAccessRead(PhyDev, PHY_BSR, PhyNum);

    if ((PhyStatus & MII_PHY_LINKED) == 0u)
      {
      *PhyState &= (~(PHY_TIM_MASK | PHY_STATE_MASK));
      if (0u!=((*PhyState) & SMODE_AUTO))
        {
        ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE);
        *PhyState |= ((PHY_CHANGE | PHY_NWST_TO) | NWAY_START);
        }
       else
        {
        *PhyState|= ((PHY_CHANGE | PHY_LINK_TO) | LINK_WAIT);
        }
      }
    }
  }

/**
* @internal
* @brief Find out if the current Phy has auto negotiate mode
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval 0 if current Phy has AutoMdix support, otherwise 1
*/
static int ICSSMDIOMdixSupported(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32 PhyNum;
  Int32 ret;

  if((PhyDev->PhyMode & NWAY_AUTOMDIX) == 0)
  {
    ret = (0);  /* AutoMdix not turned on */
  }
  else
  {
    PhyNum = ((*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;
  if( ((1<<PhyNum) & PhyDev->MdixMask) == 0)
    {
	ret = 0;  /*  Phy does not support AutoMdix*/
    }

    ret = 1;
  }
  return ret;
  }

/**
* @internal
* @brief If current Phy has AutoMdix support add Mdix Delay to the Timer State Value
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
static void ICSSMDIOMdixDelay(PHY_DEVICE *PhyDev)
  {
  Uint32 Delay;
  Uint32 *PhyState = &PhyDev->PhyState;


  if(ICSSMDIOMdixSupported(PhyDev) != 0)
    {
  /* Get the Delay value in milli-seconds and convert to ten-milli second value */
  Delay = IcssRandomRange(_AUTOMDIX_DELAY_MIN, _AUTOMDIX_DELAY_MAX);
  Delay /= 10;

  /*  Add AutoMidx Random Switch Delay to AutoMdix Link Delay */

  Delay += (PHY_MDIX_TO>>PHY_TIM_OFFSET);

  /* Change Timeout value to AutoMdix standard */
    *PhyState &= (~(PHY_TIM_MASK));  /* Clear current Time out value */
  *PhyState |=  (Delay<<PHY_TIM_OFFSET);     /* Set new value */
    }
  return;

  }
/**
* @internal
* @brief Disable they Phy device
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param PhyNum Phy number 0 or 1
*
* @retval none
*/
void ICSSMDIODisablePhy(PHY_DEVICE *PhyDev,Uint32 PhyNum)
  {
#ifdef USE_STARTERWARE_MDIO_APIS
	MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_BCR, (MII_PHY_ISOLATE | MII_PHY_PDOWN) );
#else
     ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG,PhyNum, (MII_PHY_ISOLATE | MII_PHY_PDOWN));
#endif

  }

/**
* @internal
* @brief Initialize the MDIO
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOInitState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32 CurrentState;

  CurrentState=*PhyState;
  CurrentState = (CurrentState & (~PHY_TIM_MASK)) | (PHY_FIND_TO);
  CurrentState=(CurrentState & (~PHY_STATE_MASK)) | (FINDING);
  CurrentState=(CurrentState & (~PHY_SPEED_MASK_ICSS));
  CurrentState=(CurrentState & (~PHY_DUPLEX_MASK));
  CurrentState|=PHY_CHANGE;

  *PhyState=CurrentState;

  }

/**
* @internal
* @brief ICSSMDIOFindingState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOFindingState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  PhyMask  = PhyDev->PhyMask;
  Uint32  PhyNum,i,j,PhyAcks;
 
  PhyNum=PHY_NOT_FOUND;

  if (0u!= ((*PhyState) & PHY_TIM_MASK))
    {
    *PhyState=( (*PhyState) & (~PHY_TIM_MASK) ) | (( (*PhyState) & PHY_TIM_MASK) - (1 << PHY_TIM_OFFSET));
    }
   else
    {

#ifdef USE_STARTERWARE_MDIO_APIS
	PhyAcks = MDIOPhyAliveStatusGet(PhyDev->miibase);
#else
	PhyAcks=myMDIO_ALIVE;
#endif

    PhyAcks&=PhyMask;   /* Only interested in 'our' Phys */
   
    j =1;
    for(i=0; i<32; i++)
    {
	if( 0u != (j & PhyAcks))
	{
	    break;
	}
	j = j << 1;
    }
	
    if ((0u != PhyAcks) && (i < 32)) 
	{
	PhyNum=i;
	}
    
    if (PhyNum!=PHY_NOT_FOUND)
      {
      /*  Phy Found! */
      *PhyState = ((*PhyState) & (~PHY_DEV_MASK) ) | ((PhyNum & PHY_DEV_MASK) << PHY_DEV_OFFSET);
      *PhyState = ( (*PhyState) & (~PHY_STATE_MASK) ) | (FOUND);
      *PhyState|=PHY_CHANGE;

      }
     else
      {

      *PhyState|=PHY_RECK_TO;  /* Set Timer */
      }
    }
  }

/**
* @internal
* @brief ICSSMDIOFoundState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOFoundState(PHY_DEVICE *PhyDev)
 {
  Uint32 *PhyState  = &PhyDev->PhyState;
  Uint32  PhyMask   = PhyDev->PhyMask;
  Uint32  MLinkMask = PhyDev->MLinkMask;
  Uint32  PhyNum,PhyStatus,NWAYadvertise,NWAY1000advertise=0,m,phynum,i,j,PhyAcks;
  Uint32  PhySel;
//  Uint16 reg = 0;
  static  Uint32 auto_neg1 = 0xFFFFFFFF,auto_neg2= 0xFFFFFFFF;


  if (( (*PhyState) & PHY_SMODE_MASK) == 0)
    {
    return;
    }

  PhyNum = ((*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;

#ifdef USE_STARTERWARE_MDIO_APIS
  PhyAcks = MDIOPhyAliveStatusGet(PhyDev->miibase);
#else
  PhyAcks=myMDIO_ALIVE;
#endif

  PhyAcks&=PhyMask;   /* Only interested in 'our' Phys */
  
  /* Will now isolate all our Phys, except the one we have decided to use */
  j = 1;
  for(phynum = 0;phynum < 32;phynum++)
    {
    if (0u!= (PhyAcks & j))
    {
        if (phynum != PhyNum)
      {
	    /* Do not disabled Found Phy */
        	ICSSMDIODisablePhy(PhyDev,phynum);
      }
  }
    j = j<<1;
    }
  /* If Aries SWR2 reset then don't reset phy*/ 
  /*  Reset the Phy and proceed with auto-negotiation */
  if(( 0u != g_speed_set) || ((0u ==g_soft_reset_status) || ((auto_neg1 & (1 << PhyNum)) == 0) )  )
  {
	  ICSSMDIOResetPhy(PhyDev,PhyNum);
  }

  /* Now setup the MDIOUserPhySel register */
  PhySel=PhyNum;  /* Set the phy address */
  
  /*  Set the way Link will be Monitored */
  /* Check the Link Selection Method */
  if (0u != ((1 << PhyNum) & MLinkMask) )
    {
    PhySel |= MDIO_USERPHYSEL_LINKSEL;
    }

#ifdef USE_STARTERWARE_MDIO_APIS
	  //Enable mdio link interrupt
	  PhySel = (PhySel | 0x40);

  	  MDIOPhyUserPhySel(PhyDev->miibase,PhyDev->inst, PhySel);
#else
  	  myMDIO_USERPHYSEL = PhySel;  /* update PHYSEL */
#endif



  /* Get the Phy Status */
  PhyStatus = ICSSMDIOUserAccessRead(PhyDev, PHY_BSR, PhyNum);
  

 /*  For Phy Internal loopback test, need to wait until Phy
      found, then set Loopback */
  if (0u != ((*PhyState) & SMODE_LPBK))
    {
    /* Set Phy in Loopback */
#ifdef USE_STARTERWARE_MDIO_APIS
	 MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_BCR, MII_PHY_LOOP|MII_PHY_FD);
#else
    ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, MII_PHY_LOOP|MII_PHY_FD);
#endif

    /* Do a read to ensure PHY_LOOP has completed */
    ICSSMDIOUserAccessRead(PhyDev, PHY_BSR, PhyNum);
    *PhyState = ( (*PhyState) & (~PHY_STATE_MASK) ) | (LOOPBACK);
    *PhyState|=PHY_CHANGE;
    return;
    }

  NWAYadvertise=MII_NWAY_SEL;
  if (0u != ((*PhyState) & SMODE_FD100))
  {
    NWAYadvertise |= MII_NWAY_FD100;
    }
  if (0u != ((*PhyState) & SMODE_HD100))
    {
    NWAYadvertise |= MII_NWAY_HD100;
    }
  if (0u != ((*PhyState) & SMODE_FD10))
    {
    NWAYadvertise |= MII_NWAY_FD10;
    }
  if (0u != ((*PhyState) & SMODE_HD10))
    {
    NWAYadvertise |= MII_NWAY_HD10;
    }
#ifdef GIGABIT_MODE_SUPPORT
  if (0u != ((*PhyState) & SMODE_FD1000))
    {
    NWAY1000advertise |= MII_NWAY_MY_FD1000;
    }
#endif

  *PhyState &= ( ~(PHY_TIM_MASK | PHY_STATE_MASK));
  if ((0u != (PhyStatus & MII_NWAY_CAPABLE)) && (0u != ( (*PhyState) & SMODE_AUTO)) )   /*NWAY Phy Detected*/
  {
    if(( 0u != g_speed_set) || ((0u ==g_soft_reset_status) || ((auto_neg1 & (1 << PhyNum)) == 0) )  )
    {
       /*For NWAY compliant Phys                                                */
		#ifdef USE_STARTERWARE_MDIO_APIS
			 MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_AUTONEG_ADV, NWAYadvertise);
		#else
			ICSSMDIOUserAccessWrite(PhyDev, NWAY_ADVERTIZE_REG, PhyNum, NWAYadvertise);
		#endif

       /* for gig negotiation */
      if(0u != _icssIsGigPhy(PhyDev))
      {
#ifdef USE_STARTERWARE_MDIO_APIS
       MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_1000BT_CONTROL, NWAY1000advertise);
#else
       ICSSMDIOUserAccessWrite(PhyDev, NWAY_1000BT_ADVERTISE_REG, PhyNum, NWAY1000advertise);
#endif
      }


#ifdef USE_STARTERWARE_MDIO_APIS
      MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_BCR, MII_AUTO_NEGOTIATE_EN);
      MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_BCR, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE);
#else
      ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, MII_AUTO_NEGOTIATE_EN);
      ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, MII_AUTO_NEGOTIATE_EN|MII_RENEGOTIATE);
#endif
     *PhyState|= ( (PHY_CHANGE | PHY_NWST_TO) | NWAY_START);
    }
    else
    {
      *PhyState |= ( (PHY_CHANGE | PHY_NWST_TO) | NWAY_START);
      auto_neg1 = auto_neg1 & (~(1 << PhyNum));
    }  
  }
  else
  {
    *PhyState &= (~SMODE_AUTO);   /*The Phy is not capable of auto negotiation!  */
    m=NWAYadvertise;
    j = 0x8000u;
    
    for(i=0;(i<16);i++)
    {
	if(0u != (j & m))
	{
	    break;
	}
	j = j >> 1 ;

    }
    m=j;
    j=0;

    /* figure out if gig connected at FD 1000 or not first */
    if ((NWAY1000advertise & MII_NWAY_MY_FD1000)== MII_NWAY_MY_FD1000)
    {
         j = MII_PHY_1000;
         j |= MII_PHY_FD;
    }
    else
    {
        if (0u != (m & (MII_NWAY_FD100 | MII_NWAY_HD100)) )
        {
           j=MII_PHY_100;
           m&=(MII_NWAY_FD100|MII_NWAY_HD100);
        }
        if (0u != (m & (MII_NWAY_FD100 | MII_NWAY_FD10)) )
	    {
           j |= MII_PHY_FD;
    }  
    }  
    if((0u != g_speed_set) || ( (0u == g_soft_reset_status) || ((auto_neg2 & (1 << PhyNum)) == 0) )) 
    {  
       if(0u != (j & MII_PHY_1000))
       { 
#ifdef USE_STARTERWARE_MDIO_APIS
    	   MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_1000BT_CONTROL, j);
#else
          ICSSMDIOUserAccessWrite(PhyDev,NWAY_1000BT_ADVERTISE_REG, PhyNum, j);
#endif
       }
       else
       {
#ifdef USE_STARTERWARE_MDIO_APIS
           MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_BCR, j);
           MDIOPhyRegWrite(PhyDev->miibase, PhyNum, PHY_AUTONEG_ADV, NWAYadvertise);
#else
           ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, j);
           ICSSMDIOUserAccessWrite(PhyDev, NWAY_ADVERTIZE_REG, PhyNum, NWAYadvertise);
#endif
       }
       g_speed_set = 0;    
    }
    else
    {
       auto_neg2 = auto_neg2 & (~(1 << PhyNum));
    } 
    *PhyState &= (~PHY_SPEED_MASK_ICSS);

#ifdef GIGABIT_MODE_SUPPORT
    if(0u != (j & MII_PHY_1000) )
    {
        *PhyState|=(1<<PHY_DUPLEX_OFFSET);
        PhyDev->SPEED_1000 = 1;
    }
    else
    {
        PhyDev->SPEED_1000 = 0;
    }
#endif
    if (0u != (j & MII_PHY_100) )
    {
       *PhyState|=(1<<PHY_SPEED_OFFSET);
    }  
    *PhyState &= (~PHY_DUPLEX_MASK);
    if (0u != (j & MII_PHY_FD) )
    {
       *PhyState|=(1<<PHY_DUPLEX_OFFSET);
    }
    *PhyState |= ((PHY_CHANGE | PHY_LINK_TO) | LINK_WAIT);
  }
  ICSSMDIOMdixDelay(PhyDev);  /* If AutoMdix add delay */
  }

/**
* @internal
* @brief API to reset PHY
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param PhyNum	Phy number
*
* @retval none
*/
void ICSSMDIOResetPhy(PHY_DEVICE *PhyDev,Uint32 PhyNum)
  {

#ifdef USE_STARTERWARE_MDIO_APIS
	PhyReset(PhyDev->miibase, PhyNum);
#else
	Uint16 PhyControlReg;

	ICSSMDIOUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, MII_PHY_RESET);

		/* Read control register until Phy Reset is complete */
	do
	{
		PhyControlReg = ICSSMDIOUserAccessRead(PhyDev, PHY_CONTROL_REG, PhyNum);
	}
	while (0u != (PhyControlReg & MII_PHY_RESET)); /* Wait for Reset to clear */
#endif

  	}

/**
* @internal
* @brief ICSSMDIONwayStartState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIONwayStartState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32 PhyNum,PhyMode;

  PhyNum = ( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;

  /*Wait for Negotiation to start                                            */

  PhyMode=ICSSMDIOUserAccessRead(PhyDev, PHY_BCR, PhyNum);

  if((PhyMode&MII_RENEGOTIATE)==0)
    {
	  ICSSMDIOUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum); /*Flush pending latch bits*/
    *PhyState &= (~(PHY_STATE_MASK|PHY_TIM_MASK));
    *PhyState |= ((PHY_CHANGE | NWAY_WAIT) |PHY_NWDN_TO);
    ICSSMDIOMdixDelay(PhyDev);  /* If AutoMdix add delay */
    }
   else
    {
    if (0u != ((*PhyState) & PHY_TIM_MASK) )
	{
	*PhyState=( (*PhyState) & (~PHY_TIM_MASK)) | ( ( (*PhyState) & PHY_TIM_MASK)-(1 << PHY_TIM_OFFSET));
	}
     else
	{
    	 ICSSMDIOPhyTimeOut(PhyDev);
    }
  }
  }

/**
* @internal
* @brief ICSSMDIONwayWaitState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIONwayWaitState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  PhyNum,PhyStatus,NWAYadvertise = 0,NWAYREadvertise = 0,NegMode,i,j;
  Uint32 NWAY1000advertise = 0, NWAY1000REMadvertise = 0;

  PhyNum=( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;
  PhyStatus=ICSSMDIOUserAccessRead(PhyDev, PHY_BSR, PhyNum);

  if (0u != (PhyStatus & MII_NWAY_COMPLETE))
    {
    *PhyState|=PHY_CHANGE;
    *PhyState &= (~PHY_SPEED_MASK_ICSS);
    *PhyState &= (~PHY_DUPLEX_MASK);

    NWAYadvertise   =ICSSMDIOUserAccessRead(PhyDev, PHY_AUTONEG_ADV, PhyNum);
    NWAYREadvertise =ICSSMDIOUserAccessRead(PhyDev, PHY_LINK_PARTNER_ABLTY, PhyNum);

    /* read gig status */
    if(0u != _icssIsGigPhy(PhyDev))
    {
       NWAY1000advertise   =ICSSMDIOUserAccessRead(PhyDev, PHY_1000BT_CONTROL, PhyNum);
       NWAY1000REMadvertise =ICSSMDIOUserAccessRead(PhyDev, PHY_1000BT_STATUS, PhyNum);
    }

    /* figure out if gig connected at FD 1000 or not first */
    if ((0u !=(NWAY1000advertise & MII_NWAY_MY_FD1000)) && (0u!=(NWAY1000REMadvertise & MII_NWAY_REM_FD1000)) )
	{
      NegMode = MII_NWAY_MY_FD1000;
	}
    else
	{
	NegMode = 0u;
	}

    if (NegMode == 0u)
      {
	/* continue checking for 100 and 10 connection */

	/* Negotiated mode is we and the remote have in common */
	NegMode = NWAYadvertise & NWAYREadvertise;

	/* Limit negotiation to fields below */
	NegMode &= ( (MII_NWAY_FD100|MII_NWAY_HD100) | (MII_NWAY_FD10|MII_NWAY_HD10));
	
	if (NegMode == 0u)
	  {
	    NegMode=(MII_NWAY_HD100|MII_NWAY_HD10)&NWAYadvertise; /*or 10 ?? who knows, Phy is not MII compliant*/
	    
	  }

	j = 0x8000u;
	for(i = 0; i <16 ; i++)
	{
	    if (0u != (j & NegMode))
	    {
		break;
	    }
	    j = j >> 1;
	}

	NegMode=j;



#ifdef GIGABIT_MODE_SUPPORT
	PhyDev->SPEED_1000 = 0u;
      }
   else
      {
	/* found 1000 negotiated connection! */
	mdioPrintf("Negotiated connection: ");
	mdioPrintf("FullDuplex 1000 Mbs\n");

	PhyDev->SPEED_1000 = 1u;
      }
#else
    }
#endif
    if (NegMode != 0u)
      {
      if (0u != (PhyStatus & MII_PHY_LINKED))
	{
        *PhyState=( (*PhyState) & (~PHY_STATE_MASK)) | LINKED;
	}
       else
	{
        *PhyState=( (*PhyState) & (~PHY_STATE_MASK)) | LINK_WAIT;
	}
      if (0u != (NegMode & (MII_NWAY_FD100 | MII_NWAY_HD100)) )
	{
        *PhyState=( (*PhyState) & (~PHY_SPEED_MASK_ICSS)) | (1 << PHY_SPEED_OFFSET);
	}
      if (0u != (NegMode & (MII_NWAY_FD100 | MII_NWAY_FD10 | MII_NWAY_MY_FD1000)))
	{
        *PhyState=( (*PhyState) & (~PHY_DUPLEX_MASK)) | (1 << PHY_DUPLEX_OFFSET);
	}
      }
    }
   else
    {
    if ( 0u != ( (*PhyState) & PHY_TIM_MASK) )
	{
	*PhyState=( (*PhyState) & (~PHY_TIM_MASK)) | (( (*PhyState) & PHY_TIM_MASK)-(1 << PHY_TIM_OFFSET));
	}
     else
	{
    	 ICSSMDIOPhyTimeOut(PhyDev);
    }
  }
  }

/**
* @internal
* @brief ICSSMDIOLinkWaitState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOLinkWaitState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  PhyStatus;
  Uint32  PhyNum;

  PhyNum=( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;

  PhyStatus=ICSSMDIOUserAccessRead(PhyDev, PHY_BSR, PhyNum);

  if (0u != (PhyStatus & MII_PHY_LINKED) )
    {
    *PhyState=( (*PhyState) & (~PHY_STATE_MASK) ) | LINKED;
    *PhyState|=PHY_CHANGE;
    }
   else
    {
    if (0u != ( (*PhyState) & PHY_TIM_MASK)  )
	{
      *PhyState=(*PhyState&~PHY_TIM_MASK)|((*PhyState&PHY_TIM_MASK)-(1<<PHY_TIM_OFFSET));
	}
     else
	{
    	 ICSSMDIOPhyTimeOut(PhyDev);
    }
  }
  }

/**
* @internal
* @brief ICSSMDIOPhyTimeOut
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOPhyTimeOut(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState;

  if(ICSSMDIOMdixSupported(PhyDev) == 0)
    {
    return;  /* AutoMdix not supported */
    }

  PhyState = &PhyDev->PhyState;

  /*  Indicate MDI/MDIX mode switch is needed */
  *PhyState|=PHY_MDIX_SWITCH;

  /* Toggle the MDIX mode indicatir */
  if(0u != ( (*PhyState) & PHY_MDIX) )
    {
    *PhyState &= (~PHY_MDIX_MASK);       /* Current State is MDIX, set to MDI */
    }
  else
    {
    *PhyState |=  PHY_MDIX_MASK;      /* Current State is MDI, set to MDIX */
    }

  /* Reset state machine to FOUND */
  *PhyState = ( (*PhyState) & (~PHY_STATE_MASK)) | (FOUND);
  }

/**
* @internal
* @brief ICSSMDIOLoopbackState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOLoopbackState(PHY_DEVICE *PhyDev)
{
    (void)PhyDev; /* remove if not needed, to avoid warning */
  return;
}

/**
* @internal
* @brief ICSSMDIOLinkedState
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIOLinkedState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  PhyNum   = ( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;
  
  if (0u != (MDIOPhyLinkStatusGet(PhyDev->miibase) & (1 << PhyNum)))
    {
     return;  /* if still Linked, exit*/
    }

  /* Not Linked */
  *PhyState &= (~(PHY_STATE_MASK | PHY_TIM_MASK));
  if (0u != ( (*PhyState) & SMODE_AUTO) )
  {
    *PhyState |= ( (PHY_CHANGE | NWAY_WAIT) | PHY_NWDN_TO);
  }
   else
    {
    *PhyState |= ( (PHY_CHANGE | PHY_LINK_TO) | LINK_WAIT);
    }

  ICSSMDIOMdixDelay(PhyDev);  /* If AutoMdix add delay */
  }

/**
* @internal
* @brief Calls init to reset MDIO to default state
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval none
*/
void ICSSMDIODefaultState(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  /*Awaiting a icss_MDIO_Init call                                             */
  *PhyState|=PHY_CHANGE;
  }

/**
* @internal
* @brief Simple Query Functions for reporting speed,duplex
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval returns the duplex status information
*/
int ICSSMDIOGetDuplex(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  return(( (*PhyState) & PHY_DUPLEX_MASK) ? 1:0);  /* return 0 or a 1  */
  }

/**
* @internal
* @brief ICSSMDIOGetSpeed is called to retrieve the Speed info
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval  returns the speed of PHY. Speed can be set to 10 or 100 Mbps
*/
int ICSSMDIOGetSpeed(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  Int32 ret = 0 ;

#ifdef GIGABIT_MODE_SUPPORT
  if (PhyDev->SPEED_1000 == 1)
    {
    ret = 2; /* if we are linked at 1000, we return a value of 2 */
    }
  else
    {
    ret = ( (*PhyState) & PHY_SPEED_MASK_ICSS);
    }
#else
    ret = ( (*PhyState) & PHY_SPEED_MASK_ICSS);
#endif
  return ret;
  }


/**
* @internal
* @brief Is called to retreive the Phy Device Address info
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval  PHY number
*/
int ICSSMDIOGetPhyNum(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  return((Int32)(( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET));
  }

/**
* @internal
* @brief ICSSMDIOGetLoopback is called to Determine if the LOOPBACK state has been reached
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval  PHY loop back state
*/
ICSSMDIOGetLoopback(PHY_DEVICE *PhyDev)
  {
  Uint32 *PhyState = &PhyDev->PhyState;
  return(( (*PhyState) & PHY_STATE_MASK) == LOOPBACK);
  }

/**
* @internal
* @brief ICSSMDIOGetLinked is called to determine if the LINKED state has been reached
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
*
* @retval  Linked state
*/
int ICSSMDIOGetLinked(PHY_DEVICE *PhyDev)
  {
    Uint32 *PhyState = &PhyDev->PhyState;
    return (( (*PhyState) & PHY_STATE_MASK) == LINKED);
  }

/**
* @internal
* @brief brief Waits for MDIO_USERACCESS to be ready and reads data
* @details  If 'WaitForData' set, waits for read to complete and returns Data,
*  			otherwise returns 0
*  			Note: 'data' is 16 bits but we use 32 bits to be consistent with rest of the code.
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param regadr 32bit offset to the register address space
* @param phyadr 32bit offset to the phy address
*
* @retval data from teh register
*/
Uint32 ICSSMDIOUserAccessRead(PHY_DEVICE *PhyDev, Uint32 regadr, Uint32 phyadr)
  {
#ifdef USE_STARTERWARE_MDIO_APIS
	 unsigned short retVal;
	 MDIOPhyRegRead(PhyDev->miibase, phyadr, regadr, &retVal);
	 return retVal & MDIO_USERACCESS_DATA; /*return only data */
#else
  _icss_MDIO_WaitForAccessComplete(PhyDev);  /* Wait until UserAccess ready */
  _icss_MDIO_UserAccess(PhyDev, MDIO_USERACCESS_READ, regadr, phyadr, 0);
  _icss_MDIO_WaitForAccessComplete(PhyDev);  /* Wait for Read to complete */

  return(myMDIO_USERACCESS & MDIO_USERACCESS_DATA);
#endif
  }

/**
* @internal
* @brief Function to write to MDIO Register
*
* @param PhyDev	pointer to the structure which represents the PHY and it's attributes
* @param regadr 32bit offset to the register address space
* @param phyadr 32bit offset to the phy address
* @param data data that is to be written
*
* @retval none
*/
void ICSSMDIOUserAccessWrite(PHY_DEVICE *PhyDev, Uint32 regadr, Uint32 phyadr, Uint32 data)
 {
#ifdef USE_STARTERWARE_MDIO_APIS
	MDIOPhyRegWrite(PhyDev->miibase, phyadr, regadr, data);
#else
  _icss_MDIO_WaitForAccessComplete(PhyDev);  /* Wait until UserAccess ready */
  _icss_MDIO_UserAccess(PhyDev, MDIO_USERACCESS_WRITE, regadr, phyadr, data);
#endif
 }


#ifndef USE_STARTERWARE_MDIO_APIS
void _icss_MDIO_WaitForAccessComplete(PHY_DEVICE *PhyDev)
  {
  while((myMDIO_USERACCESS & MDIO_USERACCESS_GO)!=0u)
    {
    }
  }

void _icss_MDIO_UserAccess(PHY_DEVICE *PhyDev, Uint32 method, Uint32 regadr, Uint32 phyadr, Uint32 data)
  {
  Uint32  control;

  control =  MDIO_USERACCESS_GO |
             (method) |
             (((regadr) << 21u) & MDIO_USERACCESS_REGADR) |
             (((phyadr) << 16u) & MDIO_USERACCESS_PHYADR) |
             ((data) & MDIO_USERACCESS_DATA);

  myMDIO_USERACCESS = control;
  }
#endif



#ifdef __ICSS_MDIO_DEBUG
/** Debug print functions , exported for Apps */
void _icss_MDIO_DumpState(PHY_DEVICE *PhyDev)
  {
  Uint32 state    = PhyDev->PhyState;

  mdioPrintf("Phy: %d, ",(state&PHY_DEV_MASK)>>PHY_DEV_OFFSET);
  mdioPrintf("State: %d/%s, ",(state & PHY_STATE_MASK) >> PHY_STATE_OFFSET,
		  lstate[(state & PHY_STATE_MASK) >> PHY_STATE_OFFSET]);
  mdioPrintf("Speed: %d, ",(state&PHY_SPEED_MASK_ICSS)>>PHY_SPEED_OFFSET);
  mdioPrintf("Dup: %d, ",(state&PHY_DUPLEX_MASK)>>PHY_DUPLEX_OFFSET);
  mdioPrintf("Tim: %d, ",(state&PHY_TIM_MASK)>>PHY_TIM_OFFSET);
  mdioPrintf("SMode: %d, ",(state&PHY_SMODE_MASK)>>PHY_SMODE_OFFSET);
  mdioPrintf("Chng: %d",(state&PHY_CHNG_MASK)>>PHY_CHNG_OFFSET);
  mdioPrintf("\n");

  if (((state & PHY_STATE_MASK) != FINDING) && 
	((state & PHY_STATE_MASK) != INIT))
    {
    _icss_MDIO_DumpPhy(PhyDev, (state&PHY_DEV_MASK)>>PHY_DEV_OFFSET);
  }
  }

void _icss_MDIO_DumpPhy(PHY_DEVICE *PhyDev, Uint32 p)
  {
  Uint32 j,n,PhyAcks;
  Uint32 PhyRegAddr;
  Uint32 phy_num;
  Uint32 PhyMask  = PhyDev->PhyMask;

  PhyAcks=myMDIO_ALIVE;
  PhyAcks&=PhyMask;   /* Only interested in 'our' Phys */

  phy_num = 0;
  for(j=1;phy_num<32;phy_num++)
    {
    if (0u != (PhyAcks & j))
      {
      mdioPrintf("%2d%s:",phy_num,(phy_num==p)?">":" ");
      for(PhyRegAddr=0;PhyRegAddr<6;PhyRegAddr++)
        {
        n = ICSSMDIOUserAccessRead(PhyDev, PhyRegAddr, phy_num);
        mdioPrintf(" %04x",( n & 0x0ffffu));
        }/* end of for loop */
      mdioPrintf("\n");
      }/* end of if conditional loop */
    j <<= 1;
    }/* end of for phy_num loop */
  _icss_MDIO_DumpPhyDetailed(PhyDev);
  }

void _icss_MDIO_DumpPhyDetailed(PHY_DEVICE *PhyDev)
{
  Uint32 *PhyState = &PhyDev->PhyState;
  Uint32  PhyNum;
  int     RegData, RegData2;

  PhyNum=( (*PhyState) & PHY_DEV_MASK) >> PHY_DEV_OFFSET;

  RegData = ICSSMDIOUserAccessRead(PhyDev, 0, PhyNum);
  mdioPrintf("PhyControl: %04X, Lookback=%s, Speed=%s, Duplex=%s\n",
    RegData,
    (RegData & MII_PHY_LOOP) ? "On":"Off",
    (RegData & MII_PHY_1000) ? "1000" : (RegData & MII_PHY_100 ? "100":"10"),
    (RegData & MII_PHY_FD ) ? "Full":"Half");
  RegData = ICSSMDIOUserAccessRead(PhyDev, 1, PhyNum);
  mdioPrintf("PhyStatus: %04X, AutoNeg=%s, Link=%s\n",
    RegData,
    (RegData & MII_NWAY_COMPLETE) ? "Complete":"NotComplete",
    (RegData & MII_PHY_LINKED) ? "Up":"Down");
  RegData = ICSSMDIOUserAccessRead(PhyDev, 4, PhyNum);
  RegData2 = ICSSMDIOUserAccessRead(PhyDev, 9, PhyNum);
  mdioPrintf("PhyMyCapability: %04X, 1000FD=%s, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
    RegData,
    (RegData2 & MII_NWAY_MY_FD1000) ? "Yes":"No",
    (RegData & MII_NWAY_FD100) ? "Yes":"No",
    (RegData & MII_NWAY_HD100) ? "Yes":"No",
    (RegData & MII_NWAY_FD10) ? "Yes":"No",
    (RegData & MII_NWAY_HD10) ? "Yes":"No");

  RegData = ICSSMDIOUserAccessRead(PhyDev, 5, PhyNum);
  RegData2 = ICSSMDIOUserAccessRead(PhyDev, 10, PhyNum);
  mdioPrintf("PhyPartnerCapability: %04X, 1000FD=%s, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
    RegData,
    (RegData2 & MII_NWAY_REM_FD1000 ) ? "Yes":"No",
    (RegData & MII_NWAY_FD100) ? "Yes":"No",
    (RegData & MII_NWAY_HD100) ? "Yes":"No",
    (RegData & MII_NWAY_FD10) ? "Yes":"No",
    (RegData & MII_NWAY_HD10) ? "Yes":"No");
}

#endif
