📄 mplphy.c
字号:
if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
{
// Apply fix for ATAN switch link-up issue
atanPatchUp(pMplCtx);
}
#endif //MPL_EXTERNAL_PHY
// Cancel any PHY link timer
OaiCancelTimer(pMplCtx->phyTimer);
EXIT(MplPhyGetLinkStatus);
return MPL_LINK_STATUS_DOWN;
}
//*****************************************************************************
// MplPhyGetLinkSpeed
// Returns current link speed.
// NOTE: SHOULD be called only after determing that the link is UP -
// i.e MplPhyGetLinkStatus has returned MPL_LINK_STATUS_UP
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// MPL_LINK_SPEED_TENMBPS
// The current link speed is 10Mbps
// MPL_LINK_SPEED_HUNDREDMBPS
// The current link speed is 100Mbps
//
//*****************************************************************************
MPL_LINK_SPEED
MplPhyGetLinkSpeed(
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 regVal;
ENTER(MplPhyGetLinkSpeed);
#ifndef MPL_EXTERNAL_PHY
{
// Read the PhySts register to get the current link speed
regVal = MPL_READ32(pMplCtx, PHYSTS);
// Check the link state
if (regVal & SPEED_10_STS)
{
PRINT(("Phy Link SPEED 10Mbps\n"));
EXIT(MplPhyGetLinkSpeed);
return MPL_LINK_SPEED_TENMBPS;
}
else
{
PRINT(("Phy Link SPEED 100Mbps\n"));
EXIT(MplPhyGetLinkSpeed);
return MPL_LINK_SPEED_HUNDREDMBPS;
}
}
#else
// Use internal PHY registers to return current link SPEED
// EXTERNAL_PHY_HOOK Modify this to suit your specific device needs
{
pMplCtx = pMplCtx; regVal = regVal; //To supress warnings
return DEFINE_CURRENT_SPEED; //One of MPL_LINK_SPEED_XXX
}
#endif // MPL_EXTERNAL_PHY
}
//*****************************************************************************
// MplPhyGetLinkDuplex
// Returns current link duplex mode.
// NOTE: SHOULD be called only after determing that the link is UP -
// i.e MplPhyGetLinkStatus has returned MPL_LINK_STATUS_UP
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// MPL_LINK_DUPLEX_HALF
// The current duplex mode is half
// MPL_LINK_DUPLEX_FULL
// The current duplex mode is full
//
//*****************************************************************************
MPL_LINK_DUPLEX
MplPhyGetLinkDuplex(
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 regVal;
ENTER(MplPhyGetLinkDuplex);
#ifndef MPL_EXTERNAL_PHY
{
// Read the PhySts register to get the current link mode
regVal = MPL_READ32(pMplCtx, PHYSTS);
// Check the link state
if (regVal & DUPLEX_FULL_STS)
{
PRINT(("Phy Link Duplex FULL \n"));
EXIT(MplPhyGetLinkDuplex);
return MPL_LINK_DUPLEX_FULL;
}
else
{
PRINT(("Phy Link Duplex HALF \n"));
EXIT(MplPhyGetLinkDuplex);
return MPL_LINK_DUPLEX_HALF;
}
}
#else
// Use internal PHY regs to return current DUPLEX mode
// EXTERNAL_PHY_HOOK Modify this to suit your specific device needs
{
pMplCtx = pMplCtx; regVal = regVal; //To supress warnings
return DEFINE_CURRENT_DUPLEX; //One of MPL_LINK_DUPLEX_XXX
}
#endif // MPL_EXTERNAL_PHY
}
//*****************************************************************************
// MplPhyAutoNegDone
// Returns if Auto Neg process is completed.
// NOTE: SHOULD be called only after determing that the link is UP -
// i.e MplPhyGetLinkStatus has returned MPL_LINK_STATUS_UP
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// NS_TRUE
// The link was setup following a Auto-Neg process
// NS_FALSE
// The link was setup in forced mode
//
//*****************************************************************************
NS_BOOLEAN
MplPhyAutoNegDone(
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 regVal;
ENTER(MplPhyAutoNegDone);
// Read the PhySts register to get the current mode
regVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMSR);
// Check the link state
if (regVal & AUTONEG_COMP)
{
PRINT(("Phy Link Auto DONE \n"));
EXIT(MplPhyAutoNegDone);
return NS_TRUE;
}
else
{
PRINT(("Phy Link Auto NOT DONE \n"));
EXIT(MplPhyAutoNegDone);
return NS_FALSE;
}
}
//*****************************************************************************
// MplPhyLinkSetupComplete
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// NS_TRUE
// The link was sucessfully setup
// NS_FALSE
// The link is not up (Assert - should not happen)
//
//
//*****************************************************************************
NS_BOOLEAN
MplPhyLinkSetupComplete(
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 anar, anlPar;
ENTER(MplPhyLinkSetupComplete);
// Make sure we have a valid link before proceeding
if (MplPhyGetLinkStatus(pMplHandle) != MPL_LINK_STATUS_UP)
{
// FM: Assert - We should never come here!!
EXIT(MplPhyLinkSetupComplete);
return NS_FALSE;
}
// Get the Duplex Status
if (MplPhyGetLinkDuplex(pMplCtx) == MPL_LINK_DUPLEX_FULL)
{
// We are in Full duplex mode
pMplCtx->linkCfg.duplex = MPL_LINK_DUPLEX_FULL;
// Set Pause - Only in AutoNeg'ed Full Duplex mode
if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
{
// Read our adv values and that of our partner
anar = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR);
anlPar = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANLPAR);
/*
* Look at the PAUSE and ASM_DIR bits between us and link partner
* to determine the pause setting.
* The following table, taken out of the IEEE 802.3ab/D6.0 spec
* describes final PAUSE resolution
* NOTE: DC = Don't Care
*
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | PAUSE Resolution
*-------|---------|-------|---------|--------------------
* 0 | 0 | DC | DC | MPL_LINK_PAUSE_NONE
* 0 | 1 | 0 | DC | MPL_LINK_PAUSE_NONE
* 0 | 1 | 1 | 0 | MPL_LINK_PAUSE_NONE
* 0 | 1 | 1 | 1 | MPL_LINK_PAUSE_TRANSMIT
* 1 | 0 | 0 | DC | MPL_LINK_PAUSE_NONE
* 1 | DC | 1 | DC | MPL_LINK_PAUSE_SYMMETRICAL
* 1 | 1 | 0 | 0 | MPL_LINK_PAUSE_NONE
* 1 | 1 | 0 | 1 | MPL_LINK_PAUSE_RECEIVE
*
*/
// Test for SYMMETRICAL pause mode
if ((anar & ADV_PAUSE) && (anlPar & ADV_PAUSE))
{
if (pMplCtx->linkCfg.pauseType == MPL_LINK_PAUSE_SYMMETRICAL)
{
pMplCtx->pauseType = MPL_LINK_PAUSE_SYMMETRICAL;
}
else
{
// Since we had earlier advertised Sym pause for rx-only mode too
pMplCtx->pauseType = MPL_LINK_PAUSE_RECEIVE;
}
}
else if (!(anar & ADV_PAUSE) && (anar & ADV_ASM_DIR) &&
(anlPar & ADV_PAUSE) && (anlPar & ADV_ASM_DIR))
{
// TRANSMIT only pause mode
pMplCtx->pauseType = MPL_LINK_PAUSE_TRANSMIT;
}
else if ((anar & ADV_PAUSE) && (anar & ADV_ASM_DIR) &&
!(anlPar & ADV_PAUSE) && (anlPar & ADV_ASM_DIR))
{
// RECEIVE only pause mode
pMplCtx->pauseType = MPL_LINK_PAUSE_RECEIVE;
}
// At this point the IEEE spec says no pause generation
// However unless the NSM has specifically asked for
// No-Pause or only Tx-Pause, we can enable Rx-Pause safely
// since we are only receiveing pause requests and
// not generating our own pause requests
else if ((pMplCtx->linkCfg.pauseType ==
MPL_LINK_PAUSE_TRANSMIT) ||
(pMplCtx->linkCfg.pauseType == MPL_LINK_PAUSE_NONE))
{
pMplCtx->pauseType = MPL_LINK_PAUSE_NONE;
}
else
{
pMplCtx->pauseType = MPL_LINK_PAUSE_RECEIVE;
}
}
}
else
{
// We are in half duplex mode
pMplCtx->linkCfg.duplex = MPL_LINK_DUPLEX_HALF;
// Disable Pause
pMplCtx->pauseType = MPL_LINK_PAUSE_NONE;
}
// Get the Speed Status
if (MplPhyGetLinkSpeed(pMplCtx) == MPL_LINK_SPEED_HUNDREDMBPS)
{
// We are in 100Mbps
pMplCtx->linkCfg.speed = MPL_LINK_SPEED_HUNDREDMBPS;
}
else
{
// We are in 10Mbps
pMplCtx->linkCfg.speed = MPL_LINK_SPEED_TENMBPS;
}
// Postlink Patch Works - Only for Internal PHYs
#ifndef MPL_EXTERNAL_PHY
{
if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
{
// Since we are linked up remove ATAN patch and go to
// full attenuation level
atanPatchDown(pMplCtx);
}
// Start timer to watch coeff 100msec from now - Short Cable patch
if ((pMplCtx->linkCfg.speed == MPL_LINK_SPEED_HUNDREDMBPS) &&
(((pMplCtx->srr & 0xFF00) == 0x0300) ||
((pMplCtx->srr & 0xFF00) == 0x0400) ||
(pMplCtx->srr == 0x0504)))
{
OaiStartTimer(pMplCtx->phyTimer, 100);
}
}
#endif // MPL_EXTERNAL_PHY
EXIT(MplPhyLinkSetupComplete);
return NS_TRUE;
}
//*****************************************************************************
// MplPhyRequiresPatch
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// NS_TRUE
// The PHY requires patches to be applied
// NS_FALSE
// No Patch work required
//
//*****************************************************************************
NS_BOOLEAN
MplPhyRequiresPatch(
IN NS_VOID *pMplHandle
)
{
NS_BOOLEAN retVal = NS_TRUE;
ENTER(MplPhyRequiresPatch);
#ifndef MPL_EXTERNAL_PHY
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
switch (pMplCtx->phySiliconRev)
{
case MP_PHY_REV : retVal = NS_TRUE; break;
case ASPEN_PHY_REV : retVal = NS_FALSE; break; //FM: TBD
}
}
#endif // MPL_EXTERNAL_PHY
EXIT(MplPhyRequiresPatch);
return retVal;
}
//*****************************************************************************
// MplPhyGetDeviceAddr
// Return the Phy device address
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// Phy device addr
//
//*****************************************************************************
NS_UINT
MplPhyGetDeviceAddr (
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
ENTER(MplPhyGetDeviceAddr);
EXIT(MplPhyGetDeviceAddr);
return pMplCtx->phyDeviceAddr;
}
//*****************************************************************************
// MplPhyMdioRead
// Read Phy register
//
// Parameters
// pMplHandle
// MPL device handle
// phyDevAddr
// Device addr of the Phy
// regIndex
// Register to read (in terms of MII offset e.g. BMCR = 0x0, BMSR = 0x1)
//
// Return Value
// Reg data
//
//*****************************************************************************
NS_UINT32
MplPhyMdioRead(
IN NS_VOID *pMplHandle,
IN NS_UINT phyDevAddr,
IN NS_UINT regIndex
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 regData = 0x0;
// If we are using the internal PHY then go thru the simple register
// API to access the PHY registers, if not do bit-banging on MDIO
#ifndef MPL_EXTERNAL_PHY
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -