📄 smsc9118.c
字号:
//--------------------------------------------------------------------------
//
// File name: smsc9118.c
//
// Abstract: Driver for SMSC LAN9118 ethernet controller.
//
// Start Automated RH
// *** Do not edit between "Start Automated RH" and "End Automated RH" ***
//
// Copyright 2005, Seagate Technology LLC
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Revision History
//
// *** Do not edit between "Start Automated RH" and "End Automated RH" ***
// End Automated RH
//
//--------------------------------------------------------------------------
/*---------------------------------------------------------------------------
* Copyright(c) 2005-2006 SMSC
*
* Use of this source code is subject to the terms of the SMSC Software
* License Agreement (SLA) under which you licensed this software product.
* If you did not accept the terms of the SLA, you are not authorized to use
* this source code.
*
* This code and information is provided as is without warranty of any kind,
* either expressed or implied, including but not limited to the implied
* warranties of merchantability and/or fitness for a particular purpose.
*
* File name : smsc9118.c
* Description : smsc9118 polled driver (non-interrupt driven)
*
* History :
* 09-27-06 MDG v1.0 (First Release)
* modified for ARM platform
*----------------------------------------------------------------------------*/
#include <common.h>
#include <command.h>
#include <config.h>
#include "smsc9118.h"
#include <net.h>
#ifdef CONFIG_DRIVER_SMSC9118
//*************************************************************************
// FUNCTION PROTOTYPES
//*************************************************************************
int eth_init(bd_t *bd);
void eth_halt(void);
int eth_rx(void);
int eth_send(volatile void *packet, int length);
extern void *malloc( unsigned ); // <stdlib.h>
extern void free( void * ); // <stdlib.h>
//*************************************************************************
// LOCAL DEFINITIONS AND MACROS
//*************************************************************************
//#define DEBUG
#define GPIO_OUT(val) (*GPIO_CFG = ((*GPIO_CFG & ~GPIO_CFG_GPIOD_MSK) | (val & GPIO_CFG_GPIOD_MSK)))
#define ENET_MAX_MTU PKTSIZE
#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN
#define NUM_RX_BUFF PKTBUFSRX
#define ENET_ADDR_LENGTH 6
#define TX_TIMEOUT_COUNT 30 // waiting for TX_FIFO to drain
//*************************************************************************
// GLOBAL DATA
//*************************************************************************
static const char date_code[] = BUILD_NUMBER;
static char * txbp; // TX buffer pointer (only 1 buffer)
static volatile char * rxbp[PKTBUFSRX]; // Receiver buffer queue (IP layers)
static struct rxQue rxAvlQue[PKTBUFSRX]; // Receive buffer available queue
static int rxNdx = 0; // Current receive buffer index
static int rxNdxIn = 0; // Used for input
static int rxNdxOut = 0; // Used for output to protocol layer
static ushort lastTxTag = 0x0;
static unsigned char macAddr[ENET_ADDR_LENGTH];
// Temp variables
//#ifdef DEBUG
ulong MaxRxFifoSz;
ulong TotalInts = 0;
ulong TotalRXE = 0;
ulong TotalRxPackets = 0;
ulong TotalBytes = 0;
ulong EmptyReads = 0;
ulong RxPacketBuf[400];
ulong SWIntTriggered = FALSE;
ulong TotalRxDrop = 0;
ulong TotalPackets = 0;
ulong TotalWords = 0;
ulong TBLower1, TBLower2;
//#endif
// Temp variables
//*************************************************************************
// EXTERNS
//*************************************************************************
#ifdef DEBUG
extern int use_smsc9118;
#endif
static void lan9118_udelay(unsigned long delta) // Arg is really microseconds
{
const unsigned long start = *FREE_RUN, // Start timing
usec = delta * (25000000/1000000);
// usec adjusted for 25MHz on-chip clock, 1 microsecond (1/1000000) scaling
do {
delta = *FREE_RUN;
if (delta >= start)
delta = (delta - start);
else
delta = (delta - start) + 1; // use 0x100000000, not 0xffffffff
} while (delta < usec);
}
static int MacBusy(int ReqTO)
{
int timeout = ReqTO;
int RetVal = FALSE; // No timeout
while (timeout--) {
if (!(*MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY)) {
goto done;
}
}
RetVal = TRUE; // Timeout
done:
return (RetVal);
}
static ulong
GetMacReg(int Reg)
{
ulong RegVal = 0xffffffff;
if (*MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
LAN9118_WARN("GetMacReg: previous command not complete\n");
goto done;
}
*MAC_CSR_CMD = MAC_RD_CMD(Reg);
DELAY(1);
if (MacBusy(MAC_TIMEOUT) == TRUE) {
LAN9118_WARN("GetMacReg: timeout waiting for response "
"from MAC\n");
goto done;
}
RegVal = *MAC_CSR_DATA;
done:
return (RegVal);
}
static int
PhyBusy(int ReqTO)
{
int timeout = ReqTO;
int RetVal = FALSE; // No timeout
while (timeout--) {
if (!(GetMacReg(MAC_MIIACC) & MAC_MIIACC_MII_BUSY)) {
goto done;
}
}
RetVal = TRUE; // Timeout
done:
return (RetVal);
}
static int
SetMacReg(int Reg, ulong Value)
{
int RetVal = FALSE;
if (*MAC_CSR_CMD & MAC_CSR_CMD_CSR_BUSY) {
LAN9118_WARN("SetMacReg: previous command not complete\n");
goto done;
}
*MAC_CSR_DATA = Value;
DELAY(1);
*MAC_CSR_CMD = MAC_WR_CMD(Reg);
DELAY(1);
if (MacBusy(MAC_TIMEOUT) == TRUE) {
LAN9118_WARN("SetMacReg: timeout waiting for response "
"from MAC\n");
goto done;
}
RetVal = TRUE;
done:
return (RetVal);
}
static ushort
GetPhyReg(unchar Reg)
{
ushort RegVal = 0xffff;
if (GetMacReg(MAC_MIIACC) & MAC_MIIACC_MII_BUSY) {
LAN9118_WARN("GetPhyReg: MII busy\n");
RegVal = 0;
goto done;
}
SetMacReg(MAC_MIIACC, MAC_MII_RD_CMD((unchar)PHY_ADDR, Reg));
DELAY(1);
if (PhyBusy(PHY_TIMEOUT) == TRUE) {
LAN9118_WARN("GetPhyReg: timeout waiting for MII command\n");
goto done;
}
RegVal = (ushort)GetMacReg(MAC_MIIDATA);
done:
return (RegVal);
}
static int
SetPhyReg(unchar Reg, ushort Value)
{
int RetVal = FALSE;
if (GetMacReg(MAC_MIIACC) & MAC_MIIACC_MII_BUSY) {
LAN9118_WARN("SetPhyReg: MII busy\n");
goto done;
}
SetMacReg(MAC_MIIDATA, Value);
DELAY(1);
SetMacReg(MAC_MIIACC, MAC_MII_WR_CMD((unchar)PHY_ADDR, Reg));
DELAY(1);
if (PhyBusy(PHY_TIMEOUT) == TRUE) {
LAN9118_WARN("SetPhyReg: timeout waiting for MII command\n");
goto done;
}
RetVal = TRUE;
done:
return (RetVal);
}
// Display directly accessed, Control/Status Registers
static int
DumpCsrRegs(void)
{
printf("ID_REV:\t\t0x%0.8x\n", *ID_REV);
printf("IRQ_CFG:\t0x%0.8x\n", *IRQ_CFG);
printf("INT_STS:\t0x%0.8x\n", *INT_STS);
printf("INT_EN:\t\t0x%0.8x\n", *INT_EN);
printf("BYTE_TEST:\t0x%0.8x\n", *BYTE_TEST);
printf("FIFO_INT:\t0x%0.8x\n", *FIFO_INT);
printf("RX_CFG:\t\t0x%0.8x\n", *RX_CFG);
printf("TX_CFG:\t\t0x%0.8x\n", *TX_CFG);
printf("HW_CFG:\t\t0x%0.8x\n", *HW_CFG);
printf("RX_DP_CTL:\t0x%0.8x\n", *RX_DP_CTL);
printf("RX_FIFO_INF:\t0x%0.8x\n", *RX_FIFO_INF);
printf("TX_FIFO_INF:\t0x%0.8x\n", *TX_FIFO_INF);
printf("PWR_MGMT:\t0x%0.8x\n", *PWR_MGMT);
printf("GPIO_CFG:\t0x%0.8x\n", *GPIO_CFG);
printf("GPT_CFG:\t0x%0.8x\n", *GPT_CFG);
printf("GPT_CNT:\t0x%0.8x\n", *GPT_CNT);
printf("FPGA_REV:\t0x%0.8x\n", *FPGA_REV);
printf("ENDIAN:\t\t0x%0.8x\n", *ENDIAN);
printf("FREE_RUN\t0x%0.8x\n", *FREE_RUN);
printf("RX_DROP\t\t0x%0.8x\n", *RX_DROP);
printf("MAC_CSR_CMD\t0x%0.8x\n", *MAC_CSR_CMD);
printf("MAC_CSR_DATA\t0x%0.8x\n", *MAC_CSR_DATA);
printf("AFC_CFG\t\t0x%0.8x\n", *AFC_CFG);
return (0);
}
// Display Media Access Controller Registers
static int
DumpMacRegs(void)
{
printf("MAC_CR\t\t0x%0.8x\n", GetMacReg(MAC_CR));
printf("MAC_ADDRH\t0x%0.8x\n", GetMacReg(MAC_ADDRH));
printf("MAC_ADDRL\t0x%0.8x\n", GetMacReg(MAC_ADDRL));
printf("MAC_HASHH\t0x%0.8x\n", GetMacReg(MAC_HASHH));
printf("MAC_HASHL\t0x%0.8x\n", GetMacReg(MAC_HASHL));
printf("MAC_MIIACC\t0x%0.8x\n", GetMacReg(MAC_MIIACC));
printf("MAC_MIIDATA\t0x%0.8x\n", GetMacReg(MAC_MIIDATA));
printf("MAC_FLOW\t0x%0.8x\n", GetMacReg(MAC_FLOW));
printf("MAC_VLAN1\t0x%0.8x\n", GetMacReg(MAC_VLAN1));
printf("MAC_VLAN2\t0x%0.8x\n", GetMacReg(MAC_VLAN2));
printf("MAC_WUFF\t0x%0.8x\n", GetMacReg(MAC_WUFF));
printf("MAC_WUCSR\t0x%0.8x\n", GetMacReg(MAC_WUCSR));
return (0);
}
// Display PHYsical media interface registers
static int
DumpPhyRegs(void)
{
printf("PHY_BCR\t\t0x%0.4x\n", GetPhyReg(PHY_BCR));
printf("PHY_BSR\t\t0x%0.4x\n", GetPhyReg(PHY_BSR));
printf("PHY_ID1\t\t0x%0.4x\n", GetPhyReg(PHY_ID1));
printf("PHY_ID2\t\t0x%0.4x\n", GetPhyReg(PHY_ID2));
printf("PHY_ANAR\t0x%0.4x\n", GetPhyReg(PHY_ANAR));
printf("PHY_ANLPAR\t0x%0.4x\n", GetPhyReg(PHY_ANLPAR));
printf("PHY_ANEXPR\t0x%0.4x\n", GetPhyReg(PHY_ANEXPR));
printf("PHY_SILREV\t0x%0.4x\n", GetPhyReg(PHY_SILREV));
printf("PHY_MCSR\t0x%0.4x\n", GetPhyReg(PHY_MCSR));
printf("PHY_SPMODES\t0x%0.4x\n", GetPhyReg(PHY_SPMODES));
printf("PHY_CSIR\t0x%0.4x\n", GetPhyReg(PHY_CSIR));
printf("PHY_ISR\t\t0x%0.4x\n", GetPhyReg(PHY_ISR));
printf("PHY_IMR\t\t0x%0.4x\n", GetPhyReg(PHY_IMR));
printf("PHY_PHYSCSR\t0x%0.4x\n", GetPhyReg(PHY_PHYSCSR));
return (0);
}
static int
lan9118_open(bd_t *bis)
{
int RetVal = TRUE;
int timeout;
int i;
printf("DRIVER_VERSION : %X, ", DRIVER_VERSION);
printf("DATECODE : %s\r\n", BUILD_NUMBER);
#ifdef DEBUG
TotalInts = 0;
TotalRXE = 0;
TotalBytes = 0;
if (bis->bi_bootflags & 0x40000000) {
use_smsc9118 = 1;
}
#endif //DEBUG
// Because we just came out of h/w reset we can't be sure that
// the chip has completed reset and may have to implement the
// workaround for Errata 5, stepping A0. Therefore we need to
// check the ID_REV in little endian, the reset default.
if (((*ID_REV & ID_REV_ID_MASK) == ID_REV_CHIP_118) ||
((*ID_REV & ID_REV_ID_MASK) == ID_REV_CHIP_218) ||
((*ID_REV & ID_REV_ID_MASK) == ID_REV_CHIP_115) ||
((*ID_REV & ID_REV_ID_MASK) == ID_REV_CHIP_215) ||
)
{
printf("LAN9x18 (0x%08x) detected.\n", *ID_REV);
}
else
{
printf("Failed to detect LAN9118. ID_REV = 0x%08x\n", *ID_REV);
RetVal = FALSE;
goto done;
}
// Does SoftReset to 118
*HW_CFG = HW_CFG_SRST;
DELAY(10);
// Is the internal PHY running?
if ((*PWR_MGMT & PWR_MGMT_PM_MODE_MSK) != 0) {
// Apparently not...
*BYTE_TEST = 0x0; // Wake it up
DELAY(1);
timeout = PHY_TIMEOUT;
while (timeout-- && ((*PWR_MGMT & PWR_MGMT_PME_READY) == 0)) {
lan9118_udelay(1);
}
if ((*PWR_MGMT & PWR_MGMT_PME_READY) == 0) {
LAN9118_WARN("LAN9118: PHY not ready");
LAN9118_WARN(" - aborting\n");
RetVal = FALSE;
goto done;
}
}
// Setup TX and RX resources.
// There is one TX buffer.
if ((txbp = (char *)malloc(ENET_MAX_MTU_ALIGNED)) == NULL) {
LAN9118_WARN("lan9118_open: can't get TX buffer\n");
goto cleanup;
}
// The receive buffers are allocated and aligned by upper layer
// software.
for (i = 0; i < PKTBUFSRX; i++) {
rxbp[i] = NetRxPackets[i];
rxAvlQue[i].index = -1;
}
rxNdx = 0;
rxNdxIn = 0;
rxNdxOut = 0;
lastTxTag = 0x0;
// Set TX Fifo Size
*HW_CFG = 0x00040000; // 4K for TX
// This value is dependent on TX Fifo Size since there's a limited
// amount of Fifo space.
MaxRxFifoSz = 13440; // Decimal
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -