📄 mplphy.c
字号:
//******************************************************************************
//
// MPLPHY.C
//
// Copyright (c) 2004 National Semiconductor Corporation.
// All Rights Reserved
//
// MPL Phy Interface Module.
//
// This file contains the API implementations for
// o Detection of PHY
// o Configuring the PHY
// o Reporting PHY status
//
//******************************************************************************
#include <mplinternal.h>
// Local helful debug macros
#undef ENTER
#undef EXIT
#undef ASSERT
#undef PRINT
#undef PRINTI
#undef PRINTS
#undef TBREAK
#define ENTER(fn) MPL_CENTER(DZONE_MPL_LINK, fn)
#define EXIT(fn) MPL_CEXIT(DZONE_MPL_LINK, fn)
#define ASSERT(le) MPL_CASSERT(DZONE_MPL_LINK, le)
#define PRINT(fmt) MPL_CTRACE(DZONE_MPL_LINK, fmt)
#define PRINTI(v) MPL_CTRACE(DZONE_MPL_LINK, (" "#v": %x \n",(NS_UINT)(v)))
#define PRINTS(v) MPL_CTRACE(DZONE_MPL_LINK, (" "#v": %s \n", v))
#define TBREAK(fmt) MPL_CTRACEBREAK(DZONE_MPL_LINK, fmt)
// Local functions
static NS_VOID mdioIdle(MPL_CONTEXT *pMplCtx);
static NS_VOID mdioSync(MPL_CONTEXT *pMplCtx);
#ifndef MPL_EXTERNAL_PHY
static NS_VOID phyAdjust(MPL_CONTEXT *pMplCtx);
static NS_VOID atanPatchUp(MPL_CONTEXT *pMplCtx);
static NS_VOID atanPatchDown(MPL_CONTEXT *pMplCtx);
#else
static NS_VOID mdioWriteReg(MPL_CONTEXT *pMplCtx, NS_UINT phyDevAddr,
NS_UINT regIndex,NS_UINT16 regData);
static NS_UINT16 mdioReadReg(MPL_CONTEXT *pMplCtx, NS_UINT phyDevAddr,
NS_UINT regIndex);
#endif // MPL_EXTERNAL_PHY
//*****************************************************************************
// MplPhyDetect
// Detect the presence of a MacPhyter device on the system.
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// NS_STATUS_SUCCESS
// A MacPhyter device was successfully probed
// NS_STATUS_HARDWARE_FAILURE
// Could not find a MacPhyter device
//
//*****************************************************************************
MPL_STATUS
MplPhyDetect(
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 phyIdr1, phyIdr2;
ENTER(MplPhyDetect);
// Sync up the MII bus
mdioSync(pMplCtx);
// Scan for a matching OUI.
for (pMplCtx->phyDeviceAddr = 31; pMplCtx->phyDeviceAddr != 0;
pMplCtx->phyDeviceAddr--)
{
// Check bits 3 - 18 of the OUI
phyIdr1 = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_PHYIDR1);
switch (phyIdr1)
{
case MP_PHY_ID1 : // NSC PHY Ids
phyIdr2 = MplPhyMdioRead(pMplCtx,
pMplCtx->phyDeviceAddr, MII_PHYIDR2);
switch (phyIdr2 & 0xfff0)
{
case MP_PHY_REV :
case ASPEN_PHY_REV :
pMplCtx->phySiliconRev = phyIdr2 & 0xfff0;
EXIT(MplPhyDetect);
return NS_STATUS_SUCCESS;
default : break;
}
break;
#ifdef MPL_EXTERNAL_PHY
// Add a case here to match your PHY Ids
// EXTERNAL_PHY_HOOK Modify this to suit your specific device needs
case DEFINE_PHY_ID :
break;
#endif
}
}
EXIT(MplPhyDetect);
return NS_STATUS_HARDWARE_FAILURE;
}
//*****************************************************************************
// MplPhyReset
// Reset the PHY device
//
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// NS_STATUS_SUCCESS
// A MacPhyter device was successfully probed
// NS_STATUS_HARDWARE_FAILURE
// Could not find a MacPhyter device
//
//*****************************************************************************
MPL_STATUS
MplPhyReset(
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT i;
ENTER(MplPhyReset);
// Hit the reset bit
MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, PHY_RESET);
// Wait (total 10 msec) for the PHY to come out of reset
for (i = 0x0; i < 10; i ++)
{
OaiSleep(RESETINTERVAL_PHY);
if ((MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR) &
PHY_RESET) == 0x0)
{
// Reset done
#ifndef MPL_EXTERNAL_PHY
// For NSC internal PHYs some more work remains to be done
{
NS_UINT32 regVal;
// Apply Optimization patch
phyAdjust(pMplCtx);
// Enable Phy Interrupts, after clearing pending ones
regVal = MPL_READ32(pMplCtx, MISR);
MPL_WRITE32(pMplCtx, MISR, regVal & ~(MSK_LINK | MSK_ANC));
MPL_WRITE32(pMplCtx, MICR, PHY_INT);
}
#else
// Set Interrupts and other init time operations
// EXTERNAL_PHY_HOOK Modify this to suit your specific device needs
{
DEFINE_PHY_INTERRUPTS;
}
#endif // MPL_EXTERNAL_PHY
EXIT(MplPhyReset);
return NS_STATUS_SUCCESS;
}
}
EXIT(MplPhyReset);
return NS_STATUS_HARDWARE_FAILURE;
}
//*****************************************************************************
// MplPhyLinkSetup
// Setup the link on the PHY with the requested settings
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// NS_STATUS_SUCCESS
// The link was set on the PHY device
// NS_STATUS_INVALID_PARAM
// An invalid link configuration was detected
// NS_STATUS_HARDWARE_FAILURE
// Unexpected hardware error
//
//*****************************************************************************
MPL_STATUS
MplPhyLinkSetup (
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 bmcrVal, anarVal, bmcrValTmp;
ENTER(MplPhyLinkSetup);
// Reset the PHY to apply patches before link being set
if (MplPhyReset(pMplCtx) != NS_STATUS_SUCCESS)
{
return NS_STATUS_HARDWARE_FAILURE;
}
// Setup AutoNeg advertisements
if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
{
#ifndef MPL_EXTERNAL_PHY
// Prelink Patch Works - Only for Internal PHYs
{
// Apply fix for ATAN switch link-up issue
atanPatchUp(pMplCtx);
}
#endif // MPL_EXTERNAL_PHY
// Defaults
bmcrVal = AUTONEG_ENABLE | AUTONEG_RESTART;
anarVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR);
anarVal &= ~(ADV_100BASET_FD | ADV_100BASET_HD | ADV_10BASET_FD
| ADV_10BASET_HD | ADV_PAUSE | ADV_ASM_DIR);
// Using a fall though switch case statement since
// in AUTONEG mode the modes must be backwards compatible
// When the user selects Half Duplex then he is backwards
// compatible only in Half duplex modes and does not enter
// any Full Duplex modes, but when in Full Duplex mode he
// can get into any backward compatible mode.
switch (pMplCtx->linkCfg.speed)
{
default:
case MPL_LINK_SPEED_HUNDREDMBPS:
if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
{
anarVal |= ADV_100BASET_FD;
}
// Half duplex and backward compatible
anarVal |= ADV_100BASET_HD;
case MPL_LINK_SPEED_TENMBPS:
if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
{
anarVal |= ADV_10BASET_FD;
}
// Half duplex and backward compatible
anarVal |= ADV_10BASET_HD;
break;
}
// Setup advertisement of Flow control (Pause)
switch (pMplCtx->linkCfg.pauseType)
{
case MPL_LINK_PAUSE_TRANSMIT:
// Transmit of pause requests only
anarVal |= ADV_ASM_DIR;
break;
case MPL_LINK_PAUSE_RECEIVE:
// The Auto-Neg spec does not specify a way to adv receive
// only of pause requests. So we will adv both asym and
// sym pause support - Later after link is setup we can
// disable the transmission of pause requests
anarVal |= ADV_ASM_DIR | ADV_PAUSE;
break;
case MPL_LINK_PAUSE_SYMMETRICAL: // Tx and Rx
// Both Transmit and Reception of pause requests
anarVal |= ADV_ASM_DIR | ADV_PAUSE;
break;
default:
// No pause advertisement
break;
}
// If we need to do/restart AutoNegtiation then we
// first check if we are in forced mode, if we are in forced
// mode then we clear bit 12 of the BMCR (AUTO_NEG_ENABLE) and
// then reset the bit to 1 and then write to register to restart
// Auto Negotiation if required.
bmcrValTmp = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR);
if (!(bmcrValTmp & AUTONEG_ENABLE))
{
// We clear the AUTONEGENABLE bit and then reset the bit
// before we start a AutoNegotiate process.
bmcrValTmp &= ~AUTONEG_ENABLE;
MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, bmcrValTmp);
bmcrValTmp |= AUTONEG_ENABLE;
MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, bmcrValTmp);
}
}
else
{
// Setup for Forced mode operation
// Defaults
bmcrVal = 0x0;
anarVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR);
anarVal &= ~(ADV_100BASET_FD | ADV_100BASET_HD | ADV_10BASET_FD |
ADV_10BASET_HD | ADV_PAUSE | ADV_ASM_DIR);
// Set the speed on the card individually
// based on the user selection and force selection
switch (pMplCtx->linkCfg.speed)
{
default:
case MPL_LINK_SPEED_HUNDREDMBPS:
if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
{
bmcrVal |= FORCE_MODE_FD;
}
bmcrVal |= FORCE_SPEED_100;
break;
case MPL_LINK_SPEED_TENMBPS:
if (pMplCtx->linkCfg.duplex == MPL_LINK_DUPLEX_FULL)
{
bmcrVal |= FORCE_MODE_FD;
}
break;
}
}
// Enable advertized values
MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_ANAR, anarVal);
// Write the new configuration
MplPhyMdioWrite(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMCR, bmcrVal);
EXIT(MplPhyLinkSetup);
return NS_STATUS_SUCCESS;
}
//*****************************************************************************
// MplPhyGetLinkStatus
// Returns the status of the link
//
// Parameters
// pMplHandle
// MPL device handle
//
// Return Value
// MPL_LINK_STATUS_NONE
// An unexpected hardware error occurred while processing this request
// and the link state was not retrieved.
// MPL_LINK_STATUS_DOWN
// The link is down.
// MPL_LINK_STATUS_ACTIVE
// The link is currently being configured or negotiated.
// MPL_LINK_STATUS_UP
// The link is up
//
//*****************************************************************************
MPL_LINK_STATUS
MplPhyGetLinkStatus (
IN NS_VOID *pMplHandle
)
{
MPL_CONTEXT *pMplCtx = (MPL_CONTEXT *)pMplHandle;
NS_UINT32 regVal;
ENTER(MplPhyGetLinkStatus);
// Read the PhySts register to get the current link state
// MacPhy requires the read of BMSR twice to correctly note
// the link change event
regVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMSR);
regVal = MplPhyMdioRead(pMplCtx, pMplCtx->phyDeviceAddr, MII_BMSR);
// Check the link state
if (regVal & LINK_STATUS)
{
// Link Up
// If we are in Auto-Neg mode, make sure that we are completely
// ready
if (pMplCtx->linkCfg.mode == MPL_LINK_MODE_AUTO)
{
if (regVal & AUTONEG_COMP)
{
EXIT(MplPhyGetLinkStatus);
return MPL_LINK_STATUS_UP;
}
// We are in the process of setting up link
EXIT(MplPhyGetLinkStatus);
return MPL_LINK_STATUS_ACTIVE;
}
EXIT(MplPhyGetLinkStatus);
return MPL_LINK_STATUS_UP;
}
// All other cases no Link
// This is a good time to apply linkup related patches
// (to link correctly with (potentially) a new partner)
#ifndef MPL_EXTERNAL_PHY
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -