📄 lan9118.c
字号:
LanWritePhy(PHY_BCR,(WORD)0x0100);
//enable MAC Tx/Rx, FD
LanWriteMac(MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);
// Phy_TransmitTestPacket(privateData);
//set Phy to loopback mode
LanWritePhy(PHY_BCR,(WORD)0x4100);
#endif
for(tryCount=0UL;tryCount<10UL;tryCount++) {
if(Phy_CheckLoopBackPacket(pLan9118Data) == TRUE)
{
result=(BOOLEAN)TRUE;
goto DONE;
}
#if 0
DumpSIMRegs(pLan9118Data);
DumpPHYRegs(pLan9118Data);
#endif
pLan9118Data->dwResetCount++;
#if 1
//disable MAC rx
LanWriteMac(MAC_CR,0UL);
result = Phy_Reset(pLan9118Data);
//Set Phy to 10/FD, no ANEG, and Loopbackmode
LanWritePhy(PHY_BCR,(WORD)0x4100);
//enable MAC Tx/Rx, FD
LanWriteMac(MAC_CR,MAC_CR_FDPX_|MAC_CR_TXEN_|MAC_CR_RXEN_);
#endif
}
DONE:
//disable MAC
LanWriteMac(MAC_CR,0UL);
//Cancel Phy loopback mode
LanWritePhy(PHY_BCR,(WORD)0U);
}
SetRegDW(pLan9118Data->dwLanBase,TX_CFG,0UL);
SetRegDW(pLan9118Data->dwLanBase,RX_CFG,0UL);
return result;
}
#endif //USE_PHY_WORK_AROUND
/*
FUNCTION: Lan_InitializePhy
This function should be called after Lan_InitializeInterrupts.
Continues to initialize the LAN9118_DATA structure.
It reads some phy ID values from the phy
It resets the phy.
It initializes phy interrupts
RETURN VALUE:
returns TRUE on Success,
returns FALSE on Failure
*/
BOOL Lan_InitializePhy(PLAN9118_DATA pLan9118Data, BYTE bPhyAddress)
{
BOOL result = FALSE;
BOOL ExtPhy = FALSE;
DWORD dwTemp = 0UL;
DWORD dwLoopCount = 0UL;
DWORD dwPhyId = 0UL;
BYTE bPhyModel = (BYTE)0;
BYTE bPhyRev = (BYTE)0;
WORD wPhyID1, wPhyID2;
SMSC_TRACE2(DBG_INIT, "+Lan_InitializePhy(pLan9118Data=0x%08lX, bPhyAddress=%d)\r\n", (DWORD)pLan9118Data,bPhyAddress);
SMSC_ASSERT(pLan9118Data);
if (pLan9118Data == NULL)
{
return FALSE;
}
SMSC_ASSERT(pLan9118Data->dwLanBase != 0UL);
SMSC_ASSERT(pLan9118Data->dwIdRev != 0UL);
SMSC_ASSERT(pLan9118Data->LanInitialized == (BOOLEAN)TRUE);
SMSC_ASSERT(pLan9118Data->InterruptsInitialized == (BOOLEAN)TRUE);
if (bPhyAddress == 0xFF)
{
/* Use Internal Phy */
SMSC_TRACE0(DBG_PHY, "Use IntPhy\r\n");
RETAILMSG(1, (TEXT("Use IntPhy\r\n")));
/* verify phy ID */
bPhyAddress = (BYTE)1; // internal address
ExtPhy = FALSE;
}
else
{
/* Using External Phy */
/* Check ID */
switch (pLan9118Data->dwIdRev & 0xFFFF0000UL)
{
case 0x01150000UL:
case 0x01170000UL:
if (pLan9118Data->dwIdRev & 0x0000FFFFUL)
{
dwTemp = GetRegDW(pLan9118Data->dwLanBase, HW_CFG);
if (dwTemp & HW_CFG_EXT_PHY_DET_)
{
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp |= HW_CFG_EXT_PHY_EN_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp |= HW_CFG_SMI_SEL_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
if (bPhyAddress < 32)
{
// Use specified PhyAddress
SMSC_TRACE1(DBG_PHY, "Use 0x%x ExtPhy\r\n", bPhyAddress);
wPhyID1 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_ID_1);
wPhyID2 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_ID_2);
ExtPhy = TRUE;
}
else
{
DWORD dwAddr;
for (dwAddr = 0UL;dwAddr < 32UL;dwAddr++)
{
wPhyID1 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, dwAddr, PHY_ID_1);
wPhyID2 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, dwAddr, PHY_ID_2);
if ((wPhyID1 != (WORD)0xFFFFU) ||
(wPhyID2 != (WORD)0xFFFFU))
{
SMSC_TRACE1(DBG_PHY, "Detect Phy at Address 0x%x\r\n", dwAddr);
RETAILMSG(1, (TEXT("Detect Phy at Address 0x%x\r\n"), dwAddr));
bPhyAddress = (BYTE)dwAddr;
ExtPhy = TRUE;
break;
}
}
if (dwAddr == 32UL)
{
SMSC_WARNING0("Error! Failed to detect External Phy\r\n");
ExtPhy = FALSE;
}
}
if ((wPhyID1 == (WORD)0xFFFF) &&
(wPhyID2 == (WORD)0xFFFF))
{
SMSC_WARNING0("Error! External Phy is not accessible. Switch to Internal Phy\r\n");
// revert back to Internal Phy
bPhyAddress = (BYTE)1; // internal address
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp &= ~HW_CFG_EXT_PHY_EN_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp &= ~HW_CFG_SMI_SEL_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
ExtPhy = FALSE;
}
}
else
{
/* Use Internal Phy */
SMSC_WARNING0("ExtPhy is not detected. Switch to Internal Phy\r\n");
ExtPhy = FALSE;
bPhyAddress = (BYTE)1; // internal address
}
}
else
{
SMSC_WARNING2("Error! Chip Id = 0x%x and Rev = 0x%x doesn't seem to be right combination.\r\n", (pLan9118Data->dwIdRev >> 16) & 0xFFFFUL, pLan9118Data->dwIdRev & 0xFFFFUL);
}
break;
case 0x115A0000UL:
case 0x117A0000UL:
dwTemp = GetRegDW(pLan9118Data->dwLanBase, HW_CFG);
if (dwTemp & HW_CFG_EXT_PHY_DET_)
{
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp |= HW_CFG_EXT_PHY_EN_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp |= HW_CFG_SMI_SEL_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
if (bPhyAddress < 32)
{
// Use specified PhyAddress
SMSC_TRACE1(DBG_PHY, "Use 0x%x ExtPhy\r\n", bPhyAddress);
RETAILMSG(1, (TEXT("Use 0x%x ExtPhy\r\n"), bPhyAddress));
wPhyID1 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_ID_1);
wPhyID2 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_ID_2);
}
else
{
DWORD dwAddr;
for (dwAddr = 0UL;dwAddr < 32UL;dwAddr++)
{
wPhyID1 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, dwAddr, PHY_ID_1);
wPhyID2 = Lan_GetPhyRegW(pLan9118Data->dwLanBase, dwAddr, PHY_ID_2);
if ((wPhyID1 != (WORD)0xFFFFU) ||
(wPhyID2 != (WORD)0xFFFFU))
{
SMSC_TRACE1(DBG_PHY, "Detect Phy at Address 0x%x\r\n", dwAddr);
RETAILMSG(1, (TEXT("Detect Phy at Address 0x%x\r\n"), dwAddr));
bPhyAddress = (BYTE)dwAddr;
break;
}
}
if (dwAddr == 32UL)
{
SMSC_WARNING0("Error! Failed to detect External Phy\r\n");
}
}
if ((wPhyID1 == (WORD)0xFFFF) &&
(wPhyID2 == (WORD)0xFFFF))
{
SMSC_WARNING0("Error! External Phy is not accessible. Switch to Internal Phy\r\n");
// revert back to Internal Phy
bPhyAddress = (BYTE)1; // internal address
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp &= ~HW_CFG_EXT_PHY_EN_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
dwTemp &= ~HW_CFG_PHY_CLK_SEL_;
dwTemp |= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
SMSC_MICRO_DELAY(10U);
dwTemp &= ~HW_CFG_SMI_SEL_;
SetRegDW(pLan9118Data->dwLanBase, HW_CFG, dwTemp);
}
}
else
{
/* Use Internal Phy */
SMSC_WARNING0("ExtPhy is not detected. Switch to Internal Phy\r\n");
bPhyAddress = (BYTE)1; // internal address
}
break;
default:
/* Use Internal Phy */
SMSC_TRACE0(DBG_PHY, "Use IntPhy\r\n");
RETAILMSG(1, (TEXT("Use IntPhy\r\n")));
bPhyAddress = (BYTE)1; // internal address
break;
}
}
dwTemp = (DWORD)Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_ID_2);
bPhyRev = ((BYTE)(dwTemp & (0x0FUL)));
bPhyModel = ((BYTE)((dwTemp>>4) & (0x3FUL)));
dwPhyId = dwTemp << 16;
dwTemp = (DWORD)Lan_GetPhyRegW(pLan9118Data->dwLanBase, (DWORD)bPhyAddress, PHY_ID_1);
dwPhyId |= ((dwTemp & (0x0000FFFFUL))<<2);
pLan9118Data->bPhyAddress = bPhyAddress;
pLan9118Data->dwPhyId = dwPhyId;
pLan9118Data->bPhyModel = bPhyModel;
pLan9118Data->bPhyRev = bPhyRev;
pLan9118Data->dwLinkMode = LINK_NO_LINK;
/* 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/112 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
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -