⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lan9118.c

📁 Lan9118以太网芯片linux驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
			} 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.
*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -