?? lan9118.c
字號(hào):
} else {
switch(bNewLink) {
case NG_ETHIF_LINK_10BASET:
case NG_ETHIF_LINK_100BASETX:
Lan_SetMacRegDW(dwLanBase,FLOW,0x0UL);
dwTemp = GetRegDW(dwLanBase,AFC_CFG);
dwTemp|=0x0000000FUL;
SetRegDW(dwLanBase,AFC_CFG,dwTemp);
break;
default:
Lan_SetMacRegDW(dwLanBase,FLOW,0x0UL);
dwTemp = GetRegDW(dwLanBase,AFC_CFG);
dwTemp&=0xFFFFFFF0UL;
SetRegDW(dwLanBase,AFC_CFG,dwTemp);
break;
}
}
} else {
#ifdef SMC_DEBUG
OS_TEXT_OUT ("Link is now DOWN\n");
#endif
Lan_SetMacRegDW(dwLanBase,FLOW,0UL);
dwTemp = GetRegDW(dwLanBase,AFC_CFG);
dwTemp&=0xFFFFFFF0UL;
SetRegDW(dwLanBase,AFC_CFG,dwTemp);
}
}
}
/* Phy_CheckLink(netp) is called periodically at every 100 msec
* to check and update current link status.
*/
void Phy_CheckLink (const NGifnet * const netp)
{
/* must call this twice */
Phy_UpdateLinkMode(netp);
Phy_UpdateLinkMode(netp);
SetRegDW((DWORD) NG_ETHIF_DATA(((void *) netp), eif_base),GPT_CFG,10000UL | GPT_CFG_TIMER_EN_);
}
/*
FUNCTION: Phy_Initialize
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.
RETURN VALUE:
returns TRUE on Success,
returns FALSE on Failure,
*/
BOOLEAN Phy_Initialize(const NGifnet * const netp, const DWORD dwPhyAddr)
{
#ifdef SMC_DEBUG
char buffer [128];
NGubyte bPhyRev;
NGubyte bPhyModel;
DWORD dwPhyId;
#endif
PLAN9118_DATA pLan9118Data;
DWORD dwLanBase;
BOOLEAN result=FALSE;
DWORD dwTemp=0UL;
DWORD dwLoopCount=0UL;
dwLanBase = (DWORD) NG_ETHIF_DATA(((void *) netp), eif_base);
pLan9118Data = (PLAN9118_DATA) netp->if_devptr1;
if(dwPhyAddr!=0xFFFFFFFFUL) { /* not using internal phy */
switch(pLan9118Data->dwIdRev&0xFFFF0000UL) {
case 0x01170000UL:
case 0x01150000UL:
{
DWORD dwHwCfg=GetRegDW(dwLanBase,HW_CFG);
if(dwHwCfg&HW_CFG_EXT_PHY_DET_) {
/* External phy is requested, supported, and detected
Attempt to switch
NOTE: Assuming Rx and Tx are stopped
because Phy_Initialize is called before
Rx_Initialize and Tx_Initialize
*/
NGushort wPhyId1=(NGushort) 0;
NGushort wPhyId2=(NGushort) 0;
/* Disable phy clocks to the mac */
dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
LanDelayUS(dwLanBase,10UL);/* wait for clocks to actually stop */
dwHwCfg|=HW_CFG_EXT_PHY_EN_;
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|= HW_CFG_PHY_CLK_SEL_EXT_PHY_;
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
LanDelayUS(dwLanBase,10UL);/* wait for clocks to actually start */
dwHwCfg|=HW_CFG_SMI_SEL_;
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
if(dwPhyAddr<=31UL) {
/* only check the phy address specified */
pLan9118Data->dwPhyAddress=dwPhyAddr;
wPhyId1=Phy_GetRegW(netp,PHY_ID_1);
wPhyId2=Phy_GetRegW(netp,PHY_ID_2);
} else {
/* auto detect phy */
DWORD address=0UL;
for(address=0UL;address<=31UL;address++) {
pLan9118Data->dwPhyAddress=address;
wPhyId1=Phy_GetRegW(netp,PHY_ID_1);
wPhyId2=Phy_GetRegW(netp,PHY_ID_2);
if((wPhyId1!=(NGushort) 0xFFFF)||(wPhyId2!=(NGushort) 0xFFFF)) {
#ifdef SMC_DEBUG
sprintf (buffer, "Detected Phy at address = 0x%02lX = %ld\n", address, address);
OS_TEXT_OUT (buffer);
#endif
break;
}
}
if(address>=32UL) {
#ifdef SMC_DEBUG
OS_TEXT_OUT("Failed to auto detect external phy\n");
#endif
}
}
if((wPhyId1==(NGushort) 0xFFFF)&&(wPhyId2==(NGushort) 0xFFFF)) {
#ifdef SMC_DEBUG
OS_TEXT_OUT("External Phy is not accessable\n");
OS_TEXT_OUT(" using internal phy instead\n");
#endif
/* revert back to interal phy settings. */
/* Disable phy clocks to the mac */
dwHwCfg&= (~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|= HW_CFG_PHY_CLK_SEL_CLK_DIS_;
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
LanDelayUS(dwLanBase,10UL);/* wait for clocks to actually stop*/
dwHwCfg&=(~HW_CFG_EXT_PHY_EN_);
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
dwHwCfg&=(~HW_CFG_PHY_CLK_SEL_);
dwHwCfg|=HW_CFG_PHY_CLK_SEL_INT_PHY_;
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
LanDelayUS(dwLanBase,10UL);/*wait for clocks to actually start*/
dwHwCfg&=(~HW_CFG_SMI_SEL_);
SetRegDW(dwLanBase,HW_CFG,dwHwCfg);
goto USE_INTERNAL_PHY;
} else {
#ifdef SMC_DEBUG
OS_TEXT_OUT("Successfully switched to external phy\n");
#endif
}
} else {
#ifdef SMC_DEBUG
OS_TEXT_OUT("No External Phy Detected\n");
OS_TEXT_OUT(" using internal phy instead\n");
#endif
goto USE_INTERNAL_PHY;
}
};
break;
default:
#ifdef SMC_DEBUG
OS_TEXT_OUT("External Phy is not supported\n");
OS_TEXT_OUT(" using internal phy instead\n");
#endif
goto USE_INTERNAL_PHY;
}
} else {
USE_INTERNAL_PHY:
pLan9118Data->dwPhyAddress=1UL;
}
#ifdef SMC_DEBUG
dwTemp=(DWORD)Phy_GetRegW(netp,PHY_ID_2);
dwPhyId=((dwTemp&(0xFC00UL))<<8);
dwTemp=(DWORD)Phy_GetRegW(netp,PHY_ID_1);
dwPhyId|=((dwTemp&(0x0000FFFFUL))<<2);
bPhyRev=((NGubyte)(dwTemp&(0x0FUL)));
bPhyModel=((NGubyte)((dwTemp>>4)&(0x3FUL)));
sprintf (buffer, "dwPhyId==0x%08lX,bPhyModel==0x%02X,bPhyRev==0x%02X\n",
dwPhyId, bPhyModel, bPhyRev);
OS_TEXT_OUT (buffer);
#endif
/* reset the PHY */
dwTemp = GetRegDW(dwLanBase,PMT_CTRL);
dwTemp |= PMT_CTRL_PHY_RST_;
SetRegDW(dwLanBase,PMT_CTRL,dwTemp);
dwLoopCount=20UL;
do {
LanDelayUS(dwLanBase,10UL);
dwTemp = GetRegDW(dwLanBase,PMT_CTRL);
dwLoopCount--;
} while((dwLoopCount>0UL) && (dwTemp&PMT_CTRL_PHY_RST_));
if(dwTemp&PMT_CTRL_PHY_RST_) {
#ifdef SMC_DEBUG
OS_TEXT_OUT("PHY reset failed to complete.\n");
#endif
goto DONE;
}
Phy_SetLink(netp);
/* schedule Phy_CheckLink() to run every second */
SetRegDW(dwLanBase,GPT_CFG,10000UL | GPT_CFG_TIMER_EN_);
Lan_EnableInterrupt(dwLanBase,INT_EN_GPT_INT_EN_);
result=TRUE;
DONE:
#ifdef SMC_DEBUG
sprintf (buffer, "<--Phy_Initialize, result=%s\n",result?"TRUE":"FALSE");
OS_TEXT_OUT (buffer);
#endif
return result;
}
/*
* Lan_StopGptTimer() disable Lan9118 Gpt Timer
*/
void Lan_StopGptTimer (const DWORD dwLanBase)
{
SetRegDW(dwLanBase,GPT_CFG,0UL);
}
/*
FUNCTION: Lan_EnableInterrupt
Enables bits in INT_EN according to the set bits in dwMask
WARNING this has thread synchronization issues. Use with caution.
*/
void Lan_EnableInterrupt(const DWORD dwLanBase,const DWORD dwMask)
{
DWORD dwTemp;
dwTemp=GetRegDW(dwLanBase, INT_EN);
dwTemp|=dwMask;
SetRegDW(dwLanBase,INT_EN,dwTemp);
}
/*
FUNCTION: Lan_GetInterruptStatus
Reads and returns the value in the INT_STS register.
*/
DWORD Lan_GetInterruptStatus(const DWORD dwLanBase)
{
return GetRegDW(dwLanBase,INT_STS);
}
/*
FUNCTION: Lan_ClearInterruptStatus
Clears the bits in INT_STS according to the bits set in dwMask
*/
void Lan_ClearInterruptStatus(const DWORD dwLanBase,const DWORD dwMask)
{
SetRegDW(dwLanBase,INT_STS,dwMask);
}
/*
FUNCTION: Lan_InitializeInterrupts
Should be called after Lan_Initialize
Should be called before the ISR is registered.
*/
void Lan_InitializeInterrupts(const DWORD dwLanBase,DWORD dwIntCfg)
{
SetRegDW(dwLanBase,INT_EN,0UL);
SetRegDW(dwLanBase,INT_STS,0xFFFFFFFFUL);
dwIntCfg|=INT_CFG_IRQ_EN_;
SetRegDW(dwLanBase,INT_CFG,dwIntCfg);
}
/*
FUNCTION: Lan_EnableSoftwareInterrupt
Clears a flag in the LAN9118_DATA structure
Sets the SW_INT_EN bit of the INT_EN register
WARNING this has thread sychronization issues. Use with caution.
*/
void Lan_EnableSoftwareInterrupt(const DWORD dwLanBase)
{
DWORD dwTemp=0UL;
dwTemp=GetRegDW(dwLanBase,INT_EN);
dwTemp|=INT_EN_SW_INT_EN_;
SetRegDW(dwLanBase,INT_EN,dwTemp);
}
/*
FUNCTION: Lan_HandleSoftwareInterrupt
Disables the SW_INT_EN bit of the INT_EN register,
Clears the SW_INT in the INT_STS,
Sets a flag in the LAN9118_DATA structure
*/
void Lan_HandleSoftwareInterrupt(const DWORD dwLanBase)
{
DWORD dwTemp=0UL;
dwTemp=GetRegDW(dwLanBase,INT_EN);
dwTemp&=~(INT_EN_SW_INT_EN_);
SetRegDW(dwLanBase,INT_EN,dwTemp);
SetRegDW(dwLanBase,INT_STS,INT_STS_SW_INT_);
}
/*
FUNCTION: Lan_SetMacAddress sets the Mac Address
*/
void Lan_SetMacAddress(const DWORD dwLanBase,DWORD dwHigh16,DWORD dwLow32)
{
Lan_SetMacRegDW(dwLanBase,ADDRH,dwHigh16);
Lan_SetMacRegDW(dwLanBase,ADDRL,dwLow32);
}
/*
FUNCTION: Lan_GetMacAddress gets the Mac Address
*/
void Lan_GetMacAddress(const DWORD dwLanBase,DWORD *dwHigh16,DWORD *dwLow32)
{
(*dwHigh16)=Lan_GetMacRegDW(dwLanBase,ADDRH);
(*dwLow32)=Lan_GetMacRegDW(dwLanBase,ADDRL);
}
/*
FUNCTION: Lan_InitializeTx
Prepares the LAN9118 for transmission of packets
must be called before
Lan_SendPacketPIO
Lan_CompleteTx
*/
void Lan_InitializeTx(const DWORD dwLanBase)
{
DWORD dwRegVal=0UL;
/* setup MAC for TX */
dwRegVal=Lan_GetMacRegDW(dwLanBase,MAC_CR);
dwRegVal|=(MAC_CR_TXEN_ | MAC_CR_HBDIS_);
Lan_SetMacRegDW(dwLanBase,MAC_CR,dwRegVal);
/*setup TLI store-and-forward, and preserve TxFifo size */
dwRegVal=GetRegDW(dwLanBase,HW_CFG);
dwRegVal&=(HW_CFG_TX_FIF_SZ_|0x00000FFFUL);
dwRegVal|=HW_CFG_SF_;
SetRegDW(dwLanBase,HW_CFG,dwRegVal);
SetRegDW(dwLanBase,TX_CFG,TX_CFG_TX_ON_);
SetRegDW(dwLanBase,FIFO_INT,0xFF000000UL);
Lan_EnableInterrupt(dwLanBase,INT_EN_TDFA_EN_);
}
/*
FUNCTION: Lan_SendPacketPIO
Sends a specified packet out on the ethernet line.
Must first call Lan_InitializeTx
WARNING: wPacketTag must not be 0. Zero is reserved.
*/
void Lan_SendPacketPIO(
const DWORD dwLanBase,
const NGushort wPacketTag,
const NGushort wPacketLength,
NGubyte *pbPacketData)
{
DWORD dwTxCmdA;
DWORD dwTxCmdB;
#ifdef SMC_DEBUG
if(wPacketTag==0) {
OS_TEXT_OUT ("Lan_SendPacketPIO(wPacketTag==0) Zero is reserved\n");
}
#endif
dwTxCmdA=(
((((DWORD)pbPacketData)&0x03UL)<<16) | /*DWORD alignment adjustment */
TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_ |
((DWORD)wPacketLength));
dwTxCmdB=
(((DWORD)wPacketTag)<<16) |
((DWORD)wPacketLength);
SetRegDW(dwLanBase,TX_DATA_FIFO_PORT,dwTxCmdA);
SetRegDW(dwLanBase,TX_DATA_FIFO_PORT,dwTxCmdB);
Lan_WriteTxFifo(
dwLanBase,
(DWORD *)(((DWORD)pbPacketData)&0xFFFFFFFCUL),
((DWORD)wPacketLength+3UL+
(((DWORD)pbPacketData)&0x03UL))>>2);
}
/*
FUNCTION: Lan_CompleteTx
Gets the Status DWORD of a previous transmission from the TX status FIFO
If the TX Status FIFO is empty as indicated by TX_FIFO_INF then this
function will return 0
*/
DWORD Lan_CompleteTx(const DWORD dwLanBase)
{
DWORD result;
result=GetRegDW(dwLanBase,TX_FIFO_INF);
result&=TX_FIFO_INF_TSUSED_;
if(result!=0x00000000UL) {
result=GetRegDW(dwLanBase,TX_STATUS_FIFO_PORT);
} else {
result=0UL;
}
return result;
}
/*
FUNCTION: Lan_GetTxStatusCount
Gets the number of TX completion status' available on the TX_STATUS_FIFO
These can be read from Lan_CompleteTx
*/
DWORD Lan_GetTxStatusCount(const DWORD dwLanBase)
{
DWORD result;
result=GetRegDW(dwLanBase,TX_FIFO_INF);
result&=TX_FIFO_INF_TSUSED_;
result>>=16;
return result;
}
/*
FUNCTION: Lan_GetTxDataFreeSpace
Gets the free space available in the TX fifo
*/
DWORD Lan_GetTxDataFreeSpace(const DWORD dwLanBase)
{
DWORD result;
result=GetRegDW(dwLanBase,TX_FIFO_INF);
result&=TX_FIFO_INF_TDFREE_;
return result;
}
/*
FUNCTION: Lan_InitializeRx
Prepares the LAN9118 for reception of packets
Must be called After Lan_InitializeInterrupts
*/
void Lan_InitializeRx(const DWORD dwLanBase,const DWORD dwRxCfg)
{
DWORD dwRegVal=0UL;
/*set receive configuration */
SetRegDW(dwLanBase,RX_CFG,dwRxCfg);
/*enable receiver */
dwRegVal=Lan_GetMacRegDW(dwLanBase,MAC_CR);
dwRegVal|=MAC_CR_RXEN_;
Lan_SetMacRegDW(dwLanBase,MAC_CR,dwRegVal);
/*set the interrupt levels to zero */
dwRegVal=GetRegDW(dwLanBase,FIFO_INT);
dwRegVal&=0xFFFF0000UL;
SetRegDW(dwLanBase,FIFO_INT,dwRegVal);
/*enable interrupt */
Lan_EnableInterrupt(dwLanBase,INT_EN_RSFL_EN_);
}
/*
FUNCTION: Lan_PopRxStatus
If an Rx Status DWORD is available it will return it.
*/
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -