📄 csl_mdio.c
字号:
switch( pd->phyState )
{
case PHYSTATE_MDIOINIT:
CheckTimeout:
/* Here we just check timeout and try to find a PHY */
if( pd->phyStateTicks >= PhyStateTimeout[pd->phyState] )
{
// Try the next PHY if anything but a MDIOINIT condition
if( pd->phyState != PHYSTATE_MDIOINIT )
if( ++pd->phyAddr == 32 )
pd->phyAddr = 0;
ltmp1 = MDIO_RGET( ALIVE );
for( tmp1=0; tmp1<32; tmp1++ )
{
if( ltmp1 & (1<<pd->phyAddr) )
{
if( MDIO_initPHY( pd, pd->phyAddr ) )
break;
}
if( ++pd->phyAddr == 32 )
pd->phyAddr = 0;
}
// If we didn't find a PHY, try again
if( tmp1 == 32 )
{
pd->phyAddr = 0;
pd->phyState = PHYSTATE_MDIOINIT;
pd->phyStateTicks = 0;
RetVal = MDIO_EVENT_PHYERROR;
}
}
break;
case PHYSTATE_NWAYSTART:
/*
// Here we started NWAY. We check to see if NWAY is done.
// If not done and timeout occured, we find another PHY.
*/
/* Read the CONTROL reg to verify "restart" isn't set */
PHYREG_read( PHYREG_CONTROL, pd->phyAddr );
PHYREG_waitResultsAck( tmp1, ack );
if( !ack )
{
mdioInitStateMachine();
break;
}
if( tmp1 & PHYREG_CONTROL_AUTORESTART )
goto CheckTimeout;
/* Flush latched "link status" from the STATUS reg */
PHYREG_read( PHYREG_STATUS, pd->phyAddr );
PHYREG_wait();
pd->phyState = PHYSTATE_NWAYWAIT;
/* Fallthrough */
case PHYSTATE_NWAYWAIT:
/*
// Here we are waiting for NWAY to complete.
*/
/* Read the STATUS reg to check for "complete" */
PHYREG_read( PHYREG_STATUS, pd->phyAddr );
PHYREG_waitResultsAck( tmp1, ack );
if( !ack )
{
mdioInitStateMachine();
break;
}
if( !(tmp1 & PHYREG_STATUS_AUTOCOMPLETE) )
goto CheckTimeout;
/* We can now check the negotiation results */
PHYREG_read( PHYREG_ADVERTISE, pd->phyAddr );
PHYREG_waitResults( tmp1 );
PHYREG_read( PHYREG_PARTNER, pd->phyAddr );
PHYREG_waitResults( tmp2 );
/* Use the "best" results */
tmp2 &= tmp1;
if( tmp2 & PHYREG_ADVERTISE_FD100 )
pd->PendingStatus = MDIO_LINKSTATUS_FD100;
else if( tmp2 & PHYREG_ADVERTISE_HD100 )
pd->PendingStatus = MDIO_LINKSTATUS_HD100;
else if( tmp2 & PHYREG_ADVERTISE_FD10 )
pd->PendingStatus = MDIO_LINKSTATUS_FD10;
else if( tmp2 & PHYREG_ADVERTISE_HD10 )
pd->PendingStatus = MDIO_LINKSTATUS_HD10;
/*
// If we get here the negotiation failed
// We just use HD 100 or 10 - the best we think we can do
*/
else if( tmp1 & PHYREG_ADVERTISE_HD100 )
pd->PendingStatus = MDIO_LINKSTATUS_HD100;
else
pd->PendingStatus = MDIO_LINKSTATUS_HD10;
pd->phyState = PHYSTATE_LINKWAIT;
/* Fallthrough */
case PHYSTATE_LINKWAIT:
/*
// Here we are waiting for LINK
*/
/* Read the STATUS reg to check for "link" */
PHYREG_read( PHYREG_STATUS, pd->phyAddr );
PHYREG_waitResultsAck( tmp1, ack );
if( !ack )
{
mdioInitStateMachine();
break;
}
if( !(tmp1 & PHYREG_STATUS_LINKSTATUS) )
goto CheckTimeout;
/* Make sure we're linked in the MDIO module as well */
ltmp1 = MDIO_RGET( LINK );
if( !(ltmp1&(1<<pd->phyAddr)) )
goto CheckTimeout;
/* Start monitoring this PHY */
MDIO_RSET( USERPHYSEL0, pd->phyAddr );
/* Clear the link change flag so we can detect a "re-link" later */
MDIO_RSET( LINKINTRAW, 1 );
/* Setup our linked state */
pd->phyState = PHYSTATE_LINKED;
pd->LinkStatus = pd->PendingStatus;
RetVal = MDIO_EVENT_LINKUP;
break;
}
}
return( RetVal );
}
/*-----------------------------------------------------------------------*\
* MDIO_initPHY()
*
* Force a switch to the specified PHY, and start the negotiation process.
*
* Returns 1 if the PHY selection completed OK, else 0
\*-----------------------------------------------------------------------*/
uint MDIO_initPHY( Handle hMDIO, volatile uint phyAddr )
{
MDIO_Device *pd = (MDIO_Device *)hMDIO;
Uint16 tmp1,tmp2;
Uint32 ltmp1;
uint i;
/* Switch the PHY */
pd->phyAddr = phyAddr;
/* There will be no link when we're done with this PHY */
pd->LinkStatus = MDIO_LINKSTATUS_NOLINK;
/* Shutdown all other PHYs */
ltmp1 = MDIO_RGET( ALIVE );
for( i=0; ltmp1; i++,ltmp1>>=1 )
{
if( (ltmp1 & 1) && (i != phyAddr) )
{
PHYREG_write( PHYREG_CONTROL, i, PHYREG_CONTROL_ISOLATE |
PHYREG_CONTROL_POWERDOWN );
PHYREG_wait();
}
}
/* Reset the PHY we plan to use */
PHYREG_write( PHYREG_CONTROL, phyAddr, PHYREG_CONTROL_RESET );
PHYREG_wait();
/* Wait for reset to go low (but not forever) */
for( i=0; i<5000; i++ )
{
PHYREG_read( PHYREG_CONTROL, phyAddr );
PHYREG_waitResults( tmp1 );
if( !(tmp1 & PHYREG_CONTROL_RESET) )
break;
}
if( i == 5000 )
return(0);
/* Read the STATUS reg to check autonegotiation capability */
PHYREG_read( PHYREG_STATUS, phyAddr );
PHYREG_waitResults( tmp1 );
/* See if we auto-neg or not */
if( (pd->ModeFlags & MDIO_MODEFLG_AUTONEG) &&
(tmp1 & PHYREG_STATUS_AUTOCAPABLE) )
{
/* We will use NWAY */
/* Shift down the capability bits */
tmp1 >>= 6;
/* Mask with the capabilities */
tmp1 &= ( PHYREG_ADVERTISE_FD100 | PHYREG_ADVERTISE_HD100 |
PHYREG_ADVERTISE_FD10 | PHYREG_ADVERTISE_HD10 );
/* Set Ethernet message bit */
tmp1 |= PHYREG_ADVERTISE_MSG;
/* Write out advertisement */
PHYREG_write( PHYREG_ADVERTISE, phyAddr, tmp1 );
PHYREG_wait();
/* Start NWAY */
PHYREG_write( PHYREG_CONTROL, phyAddr, PHYREG_CONTROL_AUTONEGEN );
PHYREG_wait();
PHYREG_write( PHYREG_CONTROL, phyAddr,
PHYREG_CONTROL_AUTONEGEN|PHYREG_CONTROL_AUTORESTART );
PHYREG_wait();
/* Setup current state */
pd->ModeFlags |= MDIO_MODEFLG_NWAYACTIVE;
pd->phyState = PHYSTATE_NWAYSTART;
pd->phyStateTicks = 0; /* Reset timeout */
}
else
{
/* We will use a fixed configuration */
/* Shift down the capability bits */
tmp1 >>= 10;
/* Mask with possible modes */
tmp1 &= ( MDIO_MODEFLG_HD10 | MDIO_MODEFLG_FD10 |
MDIO_MODEFLG_HD100 | MDIO_MODEFLG_FD100 );
/* Mask with what the User wants to allow */
tmp1 &= pd->ModeFlags;
/* If nothing if left, move on */
if( !tmp1 )
return(0);
/* Setup Control word and pending status */
if( tmp1 & MDIO_MODEFLG_FD100 )
{
tmp2 = PHYREG_CONTROL_SPEED100 | PHYREG_CONTROL_DUPLEXFULL;
pd->PendingStatus = MDIO_LINKSTATUS_FD100;
}
else if( tmp1 & MDIO_MODEFLG_HD100 )
{
tmp2 = PHYREG_CONTROL_SPEED100;
pd->PendingStatus = MDIO_LINKSTATUS_HD100;
}
else if( tmp1 & MDIO_MODEFLG_FD10 )
{
tmp2 = PHYREG_CONTROL_DUPLEXFULL;
pd->PendingStatus = MDIO_LINKSTATUS_FD10;
}
else
{
tmp2 = 0;
pd->PendingStatus = MDIO_LINKSTATUS_HD10;
}
/* Add in loopback if user wanted it */
if( pd->ModeFlags & MDIO_MODEFLG_LOOPBACK )
tmp2 |= PHYREG_CONTROL_LOOPBACK;
/* Configure PHY */
PHYREG_write( PHYREG_CONTROL, phyAddr, tmp2 );
PHYREG_wait();
/* Setup current state */
pd->ModeFlags &= ~MDIO_MODEFLG_NWAYACTIVE;
pd->phyState = PHYSTATE_LINKWAIT;
pd->phyStateTicks = 0; /* Reset timeout */
}
return(1);
}
/*-----------------------------------------------------------------------*\
* MDIO_phyRegRead()
*
* Raw data read of a PHY register.
*
* Returns 1 if the PHY ACK'd the read, else 0
\*-----------------------------------------------------------------------*/
uint MDIO_phyRegRead( volatile uint phyIdx, volatile uint phyReg, Uint16 *pData )
{
uint data,ack;
PHYREG_read( phyReg, phyIdx );
PHYREG_waitResultsAck( data, ack );
if( !ack )
return(0);
if( pData )
*pData = data;
return(1);
}
/*-----------------------------------------------------------------------*\
* MDIO_phyRegWrite()
*
* Raw data write of a PHY register.
*
* Returns 1 if the PHY ACK'd the write, else 0
\*-----------------------------------------------------------------------*/
uint MDIO_phyRegWrite( volatile uint phyIdx, volatile uint phyReg, Uint16 data )
{
uint ack;
PHYREG_write( phyReg, phyIdx, data );
PHYREG_waitResultsAck( data, ack );
if( !ack )
return(0);
return(1);
}
#endif /* MDIO_SUPPORT */
/******************************************************************************\
* End of mdio.c
\******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -