📄 lan9118.c
字号:
/* reset the PHY */
Lan_SetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_BCR, PHY_BCR_RESET_);
dwLoopCount = 100000UL;
do {
SMSC_MICRO_DELAY(10U);
dwTemp = (DWORD)Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_BCR);
dwLoopCount--;
} while ((dwLoopCount>0UL) && (dwTemp & (DWORD)PHY_BCR_RESET_));
if (dwTemp & (DWORD)PHY_BCR_RESET_) {
SMSC_WARNING0("PHY reset failed to complete.\r\n");
goto DONE;
}
#ifdef USE_PHY_WORK_AROUND // on internal PHY use only
if (ExtPhy == FALSE) // 031305 WH
{
// workaround for 118/117/116/115 family
if (((pLan9118Data->dwIdRev & 0xFFF0FFFFUL) == 0x01100001UL) ||
((pLan9118Data->dwIdRev & 0xFFF0FFFFUL) == 0x01100002UL))
{
if(!Phy_LoopBackTest(pLan9118Data) && (pLan9118Data->bPhyAddress==(BYTE)1)) {
SMSC_WARNING1("Failed Loop Back Test, reset %d times\n\r",
pLan9118Data->dwResetCount);
goto DONE;
} else {
SMSC_WARNING1("Passed Loop Back Test, reset %d times\n\r",
pLan9118Data->dwResetCount);
}
}
}
#endif //USE_PHY_WORK_AROUND // on internal PHY use only
if (ExtPhy == FALSE)
{
if (((pLan9118Data->dwIdRev & 0x000F0000UL) == 0x000A0000UL) |
((pLan9118Data->dwIdRev & 0xFFF00000UL) == 0x92100000UL))
{
Lan_SetAutoMdixSts(pLan9118Data);
}
else
{
RETAILMSG(1, (TEXT("This chip doesn't support Auto Mdix!!!\r\n")));
}
}
pLan9118Data->PhyInitialized = (BOOLEAN)TRUE;
result = TRUE;
DONE:
SMSC_TRACE1(DBG_INIT,"-Lan_InitializePhy, result=%s\r\n",result?TEXT("TRUE"):TEXT("FALSE"));
return result;
}
/*
FUNCTION: Lan_AutoNegotiate
RETURN VALUE:
returns TRUE on success.
returns FALSE on failure.
*/
BOOLEAN Lan_AutoNegotiate(const LAN9118_DATA * const pLan9118Data)
{
DWORD dwTimeout=0UL;
WORD wTemp, wBreaknow=(WORD)0;
SMSC_TRACE0(DBG_INIT, "+Lan_AutoNegotiate(...)\n");
wTemp = (WORD)(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_);
LanWritePhy(PHY_BCR, wTemp);
Restart_AutoNegotiation:
wBreaknow++;
dwTimeout = 100000UL;
// Check for the completion and the remote fault
do {
wTemp = LanReadPhy(PHY_BSR);
} while((dwTimeout-- > 0UL) &&
!((wTemp & (WORD)PHY_BSR_REMOTE_FAULT_) ||
(wTemp & (WORD)PHY_BSR_AUTO_NEG_COMP_)));
if(wTemp & (WORD)PHY_BSR_REMOTE_FAULT_) {
SMSC_TRACE0(DBG_INIT,"Autonegotiation Remote Fault\n");
if(wBreaknow < 10)
{
goto Restart_AutoNegotiation;
}
}
SMSC_TRACE0(DBG_INIT, "-Lan_AutoNegotiate(...)\n");
return (BOOLEAN)FALSE;
}
/*
FUNCTION: Lan_EstablishLink
This function similar to Lan_RequestLink except that it is
not interrupt driven. This function will not return until
either the link is established or link can not be established.
RETURN VALUE:
returns TRUE on success.
returns FALSE on failure.
*/
BOOL Lan_EstablishLink(PLAN9118_DATA pLan9118Data, const DWORD dwLinkRequest)
{
WORD wTemp, wRegVal = (WORD)0;
DWORD dwRegVal = 0UL;
BOOL result = TRUE;
SMSC_TRACE2(DBG_INIT, "+Lan_EstablishLink(pLan9118Data==0x%08lX,dwLinkRequest==%ld)\r\n", (DWORD)pLan9118Data,dwLinkRequest);
if (dwLinkRequest & LINKMODE_ANEG) {
// Enable ANEG
wTemp = LanReadPhy(PHY_BCR);
wTemp = (WORD)(wTemp | PHY_BCR_AUTO_NEG_ENABLE_);
LanWritePhy(PHY_BCR, wTemp);
// Set ANEG Advertise
wTemp = LanReadPhy(PHY_ANEG_ADV);
wTemp = (WORD)(wTemp & ~(PHY_ANEG_ADV_PAUSE_OP_ | PHY_ANEG_ADV_SPEED_));
if (dwLinkRequest & LINKMODE_ASYM_PAUSE)
{
wTemp = (WORD)(wTemp | PHY_ANEG_ADV_ASYM_PAUSE_);
}
if (dwLinkRequest & LINKMODE_SYM_PAUSE)
{
wTemp = (WORD)(wTemp | PHY_ANEG_ADV_SYM_PAUSE_);
}
if (dwLinkRequest & LINKMODE_100_FD)
{
wTemp = (WORD)(wTemp | PHY_ANEG_ADV_100F_);
}
if (dwLinkRequest & LINKMODE_100_HD)
{
wTemp = (WORD)(wTemp | PHY_ANEG_ADV_100H_);
}
if (dwLinkRequest & LINKMODE_10_FD)
{
wTemp = (WORD)(wTemp | PHY_ANEG_ADV_10F_);
}
if (dwLinkRequest & LINKMODE_10_HD)
{
wTemp = (WORD)(wTemp | PHY_ANEG_ADV_10H_);
}
LanWritePhy(PHY_ANEG_ADV, wTemp);
if(!Lan_AutoNegotiate(pLan9118Data))
{
pLan9118Data->dwLinkMode = LINK_NO_LINK;
SMSC_TRACE0(DBG_INIT,"Auto Negotiation Failed !\r\n");
result = FALSE;
}
else
{
SMSC_TRACE0(DBG_INIT,"Auto Negotiation Complete\r\n");
}
//Clear any pending interrupts
wRegVal = LanReadPhy(PHY_INT_SRC);
// avoid lint error
wRegVal = wRegVal;
//CheckForLink
pLan9118Data->dwLinkMode = Lan_GetLinkMode(pLan9118Data);
dwRegVal = Lan_GetMacRegDW(pLan9118Data->dwLanBase, MAC_CR);
dwRegVal &= ~(MAC_CR_FDPX_|MAC_CR_RCVOWN_);
switch(pLan9118Data->dwLinkMode)
{
case LINK_NO_LINK:
SMSC_TRACE0(DBG_INIT,"There is no Link\r\n");
//TODO: consider auto linking to a specified link state.
break;
case LINK_10MPS_HALF:
SMSC_TRACE0(DBG_INIT,"Link is 10Mbps Half Duplex\r\n");
dwRegVal|=MAC_CR_RCVOWN_;
break;
case LINK_10MPS_FULL:
SMSC_TRACE0(DBG_INIT,"Link is 10Mbps Full Duplex\r\n");
dwRegVal|=MAC_CR_FDPX_;
break;
case LINK_100MPS_HALF:
SMSC_TRACE0(DBG_INIT,"Link is 100Mbps Half Duplex\r\n");
dwRegVal|=MAC_CR_RCVOWN_;
break;
case LINK_100MPS_FULL:
SMSC_TRACE0(DBG_INIT,"Link is 100Mbps Full Duplex\r\n");
dwRegVal|=MAC_CR_FDPX_;
break;
default:
SMSC_TRACE0(DBG_INIT,"Unknown LinkMode\r\n");
break;
}
Lan_SetMacRegDW(pLan9118Data->dwLanBase, MAC_CR, dwRegVal);
}
else {
// Non-ANEG
// If multiple mode bits were set, it uses following priority,
// 100FD->100HD->10FD->10HD
wTemp = LanReadPhy(PHY_BCR);
if (dwLinkRequest & LINKMODE_100_FD) {
wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
wTemp = (WORD)(wTemp | (PHY_BCR_SPEED_SELECT_ | PHY_BCR_DUPLEX_MODE_));
}
else if (dwLinkRequest & LINKMODE_100_HD) {
wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
wTemp = (WORD)(wTemp | PHY_BCR_SPEED_SELECT_);
wTemp = (WORD)(wTemp & ~PHY_BCR_DUPLEX_MODE_);
}
else if (dwLinkRequest & LINKMODE_10_FD) {
wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
wTemp = (WORD)(wTemp & ~PHY_BCR_SPEED_SELECT_);
wTemp = (WORD)(wTemp | PHY_BCR_DUPLEX_MODE_);
}
else if (dwLinkRequest & LINKMODE_10_HD) {
wTemp = (WORD)(wTemp & ~(PHY_BCR_AUTO_NEG_ENABLE_ | PHY_BCR_RESTART_AUTO_NEG_));
wTemp = (WORD)(wTemp & ~(PHY_BCR_SPEED_SELECT_ | PHY_BCR_DUPLEX_MODE_));
}
else {
RETAILMSG(1, (TEXT("Error! No Link Mode was Set.\r\n")));
return FALSE;
}
LanWritePhy(PHY_BCR, wTemp);
//Clear any pending interrupts
wRegVal = LanReadPhy(PHY_INT_SRC);
// avoid lint error
wRegVal = wRegVal;
//CheckForLink
dwRegVal = Lan_GetMacRegDW(pLan9118Data->dwLanBase, MAC_CR);
dwRegVal &= ~(MAC_CR_FDPX_|MAC_CR_RCVOWN_);
if (dwLinkRequest & LINKMODE_100_FD) {
dwRegVal|=MAC_CR_FDPX_;
}
else if (dwLinkRequest & LINKMODE_100_HD) {
dwRegVal|=MAC_CR_RCVOWN_;
}
else if (dwLinkRequest & LINKMODE_10_FD) {
dwRegVal|=MAC_CR_FDPX_;
}
else if (dwLinkRequest & LINKMODE_10_HD) {
dwRegVal|=MAC_CR_RCVOWN_;
}
else
{
// do nothing except making lint happy
}
Lan_SetMacRegDW(pLan9118Data->dwLanBase, MAC_CR, dwRegVal);
}
SMSC_TRACE1(DBG_INIT,"-Lan_EstablishLink, result=%s\r\n",result?TEXT("TRUE"):TEXT("FALSE"));
return result;
}
/*
FUNCTION: Lan_GetLinkMode
Gets the link mode from the PHY,
Stores it in LAN9118_DATA and also returns it.
RETURN VALUE:
one of the following link modes
LINK_NO_LINK
LINK_10MPS_HALF
LINK_10MPS_FULL
LINK_100MPS_HALF
LINK_100MPS_FULL
*/
DWORD Lan_GetLinkMode(const LAN9118_DATA * const pLan9118Data)
{
DWORD result = LINK_NO_LINK;
WORD wRegVal;
const WORD wRegBSR = LanReadPhy(PHY_BSR);
wRegVal = LanReadPhy(PHY_BCR);
if (wRegVal & PHY_BCR_AUTO_NEG_ENABLE_)
{
if(wRegBSR & PHY_BSR_LINK_STATUS_)
{
WORD wTemp;
const WORD wRegADV = LanReadPhy(PHY_ANEG_ADV);
const WORD wRegLPA = LanReadPhy(PHY_ANEG_LPA);
wTemp = (WORD)(wRegLPA & wRegADV);
if(wTemp & PHY_ANEG_LPA_100FDX_)
{
result = LINK_100MPS_FULL;
}
else if(wTemp & PHY_ANEG_LPA_100HDX_)
{
result = LINK_100MPS_HALF;
}
else if(wTemp & PHY_ANEG_LPA_10FDX_)
{
result = LINK_10MPS_FULL;
}
else if(wTemp & PHY_ANEG_LPA_10HDX_)
{
result = LINK_10MPS_HALF;
}
else
{
// do nothing except making lint happy
}
// check Flow Control
if (wTemp & (WORD) (PHY_ANEG_LPA_100FDX_ | PHY_ANEG_LPA_10FDX_)) {
DWORD dwTemp;
if (wTemp & (WORD)0x0400U) {
// both support Symmetric Flow Control
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp | FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp | AFC_CFG_FCANY_);
}
else if (((wRegADV & 0x0C00) == 0x0C00) &&
((wRegLPA & 0x0C00) == 0x0800)) {
// Partner is Asymmetric Flow Control
// Enable Rx Only (Enable FC on MAC, Disable at AFC_CFG)
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp | FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp & ~AFC_CFG_FCANY_);
}
else {
// Disable Flow Control
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp & ~FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp & ~AFC_CFG_FCANY_);
}
}
else {
// Half-Duplex
// Disable Flow Control
DWORD dwTemp;
dwTemp = LanReadMac(FLOW);
LanWriteMac(FLOW, dwTemp & ~FLOW_FCEN_);
dwTemp = GetRegDW(pLan9118Data->dwLanBase, AFC_CFG);
SetRegDW(pLan9118Data->dwLanBase, AFC_CFG, dwTemp & ~AFC_CFG_FCANY_);
}
}
}
else
{
if (wRegBSR & PHY_BSR_LINK_STATUS_)
{
if (wRegVal & PHY_BCR_SPEED_SELECT_)
{
if (wRegVal & PHY_BCR_DUPLEX_MODE_)
{
result = LINK_100MPS_FULL;
}
else
{
result = LINK_100MPS_HALF;
}
}
else
{
if (wRegVal & PHY_BCR_DUPLEX_MODE_)
{
result = LINK_10MPS_FULL;
}
else
{
result = LINK_10MPS_HALF;
}
}
}
}
return result;
}
void Lan_SetAutoMdixSts(PLAN9118_DATA pLan9118Data)
{
WORD wAutoMdixSts = pLan9118Data->wAutoMdix;
WORD SpecialCtrlSts=0U;
if (wAutoMdixSts > 2)
{
SpecialCtrlSts=LanReadPhy(SPECIAL_CTRL_STS);
SpecialCtrlSts = (SpecialCtrlSts&0x1FFF);
LanWritePhy(SPECIAL_CTRL_STS,SpecialCtrlSts);
if (GetRegDW(pLan9118Data->dwLanBase, HW_CFG) & HW_CFG_AMDIX_EN_STRAP_STS_)
{
RETAILMSG(1, (TEXT("Auto-MDIX Enable by default!!!\r\n")));
}
else {
RETAILMSG(1, (TEXT("Auto-MDIX Disable by default!!!\r\n")));
}
pLan9118Data->wAutoMdix=3;
}
else
{
SpecialCtrlSts=LanReadPhy(SPECIAL_CTRL_STS);
SpecialCtrlSts = (((wAutoMdixSts+4) << 13) | (SpecialCtrlSts&0x1FFF));
LanWritePhy(SPECIAL_CTRL_STS,SpecialCtrlSts);
if (wAutoMdixSts & AMDIX_ENABLE) {
RETAILMSG(1, (TEXT("Override Strap, Enable Auto-MDIX\r\n")));
} else if (wAutoMdixSts & AMDIX_DISABLE_CROSSOVER) {
RETAILMSG(1, (TEXT("Override Strap, Disable Auto-MDIX, CrossOver Cable\r\n")));
} else {
RETAILMSG(1, (TEXT("Override Strap, Disable Auto-MDIX, Straight Cable\r\n")));
}
pLan9118Data->wAutoMdix=wAutoMdixSts;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -