?? s3c2510eth.c
字號:
/* s3c2510Eth.c - SAMSUNG S3C2510 Ethernet controller driver */
/* Copyright 2002 SAMSUNG ELECTRONICS */
/*
modification history
--------------------
01a,08feb02,jmLee created.
*/
#include "vxWorks.h"
#include "intLib.h"
#include "netLib.h"
#include "end.h"
#include "endLib.h"
#include "cacheLib.h"
#include "miiLib.h"
#include "errno.h"
#include "stdio.h"
#include "logLib.h"
#include "taskLib.h"
#include "drv/multi/s3c2510.h"
#include "config.h"
#include "drv/intrCtl/s3c2510Intr.h"
#include "s3c2510Eth.h"
#include "s3c2510Des.h"
#undef DEBUG_TRACE
#define DEBUG_LOG(x, p1, p2, p3, p4, p5, p6) \
logMsg(x, (int)(UINT32)(p1), (int)(UINT32)(p2), (int)(UINT32)(p3), (int)(UINT32)(p4), (int)(UINT32)(p5), (int)(UINT32)(p6))
#define RX_WAIT_MAX (CPLL_FREQ * 1000) /* Rx completion timeout */
#define TX_WAIT_MAX (CPLL_FREQ * 1000) /* Tx completion timeout */
#define MII_WAIT_MAX (CPLL_FREQ * 1000) /* max delay for the MII operation */
#ifndef NSDELAY
#define NSDELAY(nsec) \
{ \
volatile int nx; \
volatile int loop = (int)(((CPLL_FREQ * nsec) / 1000) + 1); \
\
for (nx=0; nx<loop; nx++); \
}
#endif /* NSDELAY */
/* External */
IMPORT STATUS sysSecEnetAddrGet(int unit, UCHAR* address);
/* Forward Function Declarations */
LOCAL STATUS s3c2510EthInitPhy(ETH_DRV_CTRL *pDrvCtrl);
LOCAL STATUS s3c2510EthAnRestart(ETH_DRV_CTRL *pDrvCtrl);
LOCAL STATUS s3c2510EthMiiRead(ETH_DRV_CTRL *pDrvCtrl, UINT8 phyAddr, UINT8 regAddr, UINT16 *miiData);
LOCAL STATUS s3c2510EthMiiWrite(ETH_DRV_CTRL *pDrvCtrl, UINT8 phyAddr, UINT8 regAddr, UINT16 miiData);
LOCAL void s3c2510EthInitBD(ETH_DRV_CTRL *pDrvCtrl);
LOCAL void s3c2510EthIntRx(ETH_DRV_CTRL *pDrvCtrl);
LOCAL void s3c2510EthIntTx(ETH_DRV_CTRL *pDrvCtrl);
LOCAL void s3c2510EthRxHandler(ETH_DRV_CTRL *pDrvCtrl);
LOCAL void s3c2510EthTxHandler(ETH_DRV_CTRL *pDrvCtrl);
#ifdef DEBUG_TRACE
LOCAL void s3c2510EthHexDump(UCHAR *p, ULONG l);
#endif /* DEBUG_TRACE */
/*******************************************************************************
*
* s3c2510EthInit - initialize S3C2510 Ethernet controller
*
* RETURNS: OK, or ERROR.
*/
STATUS s3c2510EthInit(
ETH_DRV_CTRL *pDrvCtrl /* pointer to driver structure */
)
{
int unit = pDrvCtrl->unit;
#ifdef DEBUG_TRACE
printf("s3c2510Eth%d Init\n", unit);
#endif /* DEBUG_TRACE */
if (unit == 0)
{
pDrvCtrl->intLvlRx = INT_LVL_ETH0RX;
pDrvCtrl->intLvlTx = INT_LVL_ETH0TX;
pDrvCtrl->intVecRx = INT_VEC_ETH0RX;
pDrvCtrl->intVecTx = INT_VEC_ETH0TX;
}
else if (unit == 1)
{
pDrvCtrl->intLvlRx = INT_LVL_ETH1RX;
pDrvCtrl->intLvlTx = INT_LVL_ETH1TX;
pDrvCtrl->intVecRx = INT_VEC_ETH1RX;
pDrvCtrl->intVecTx = INT_VEC_ETH1TX;
}
else
{
printf("s3c2510Eth%d Error: Invalid unit number\n", unit);
return ERROR;
}
/* Disable BDMA/MAC. */
s3c2510EthStop(pDrvCtrl);
/* Enable peripheral clock. */
*S3C2510_PCLKDIS &= ~(S3C2510_PCLKDIS_ETH0 << unit);
/* Initialize PHY. */
s3c2510EthInitPhy(pDrvCtrl);
/* Reset BDMA. */
*S3C2510_BRXCON(unit) = S3C2510_BRXCON_RESET;
*S3C2510_BTXCON(unit) = S3C2510_BTXCON_RESET;
/* Reset MAC. */
*S3C2510_MACCON(unit) = S3C2510_MACCON_RESET;
/* Initlalize Buffer Descriptor. */
s3c2510EthInitBD(pDrvCtrl);
/* Initlalize BDMA Receive Frame Size Register. */
*S3C2510_BRXLEN(unit) = (SIZE_ETH_MDMA << S3C2510_BRXLEN_MFS_SHIFT) |
(SIZE_ETH_MDMA << S3C2510_BRXLEN_BS_SHIFT);
/* Initialize BDMA RBD/TBD Start Address Register. */
*S3C2510_BRXBDPTR(unit) = pDrvCtrl->rbdBase;
*S3C2510_BTXBDPTR(unit) = pDrvCtrl->tbdBase;
/* Initialize BDMA Rx/Tx Control Register. */
*S3C2510_BRXCON(unit) = NBD_RBD_ETH | /* defined in smdk2510.h */
(SIZE_ETH_WA << S3C2510_BRXCON_WA_SHIFT);
*S3C2510_BTXCON(unit) = NBD_TBD_ETH | /* defined in smdk2510.h */
S3C2510_BTXCON_SL_6; /* Wait to Fill 6/8 of BDMA Tx Buffer */
/* Initialize MAC Rx/Tx Control Register. */
*S3C2510_MRXCON(unit) =
#if (SIZE_ETH_CRC == 0)
S3C2510_MRXCON_STRIPCRC | /* Strip CRC Value */
#endif /* (SIZE_ETH_CRC > 0) */
0;
*S3C2510_MTXCON(unit) = 0;
/* Initialize BDMA-MAC Rx/Tx Interrupt Enable Register. */
*S3C2510_BMRXINTEN(unit) = S3C2510_BMRXINTEN_BNOIE | /* BDMA Rx Not Owner Interrupt Enable */
S3C2510_BMRXINTEN_BDONEIE; /* BDMA Rx Done Interrupt Enable */
*S3C2510_BMTXINTEN(unit) = S3C2510_BMTXINTEN_MCOMPIE; /* MAC Tx Completion Interrupt Enable */
/* Initialize MAC Control Register. */
if (pDrvCtrl->l80225Status & L80225_STAT_FDX)
{
*S3C2510_MACCON(unit) = S3C2510_MACCON_FULLDUPLEX; /* Full-Duplex Enable */
}
else
{
*S3C2510_MACCON(unit) = 0;
}
/* Get hardware address. */
sysSecEnetAddrGet(unit, pDrvCtrl->IFADDR.phyAddress);
/* Set hardware address. */
s3c2510EthAddrSet(pDrvCtrl);
/* Initialize CAM. First entry is reserved for our MAC address. */
*S3C2510_CAMEN(unit) = 0x00000001;
*S3C2510_CAMCON(unit) = S3C2510_CAMCON_COMPEN | /* Compare Enable */
S3C2510_CAMCON_BROAD | /* Broadcast Accept */
S3C2510_CAMCON_GROUP | /* Group Accept */
S3C2510_CAMCON_STATION; /* Station Accept */
/* Initialize flags. */
pDrvCtrl->bPolling = FALSE;
pDrvCtrl->bTxBlocked = FALSE;
pDrvCtrl->bRxHandler = FALSE;
pDrvCtrl->bTxHandler = FALSE;
/* Clear status. */
/* should be clear value one, jwchoi
*S3C2510_BMRXSTAT(unit) = 0;
*S3C2510_BMTXSTAT(unit) = 0;
*/
/* Connect interrupt. */
intConnect(pDrvCtrl->intVecRx, (VOIDFUNCPTR)s3c2510EthIntRx, (int)pDrvCtrl);
intConnect(pDrvCtrl->intVecTx, (VOIDFUNCPTR)s3c2510EthIntTx, (int)pDrvCtrl);
return OK;
}
/*******************************************************************************
*
* s3c2510EthInitPhy - initialize S3C2510 Ethernet PHY
*
* RETURNS: OK, or ERROR.
*/
STATUS s3c2510EthInitPhy(
ETH_DRV_CTRL *pDrvCtrl /* pointer to driver structure */
)
{
int unit = pDrvCtrl->unit;
UINT8 phyAddr = (UINT8)(unit + 1);
#ifdef DEBUG_TRACE
printf("s3c2510Eth%d InitPhy\n", unit);
#endif /* DEBUG_TRACE */
/* Save PHY address. */
pDrvCtrl->phyInfo.phyAddr = phyAddr;
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_CTRL_REG, &pDrvCtrl->PHYREGS.phyCtrl);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_STAT_REG, &pDrvCtrl->PHYREGS.phyStatus);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_PHY_ID1_REG, &pDrvCtrl->PHYREGS.phyId1);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_PHY_ID2_REG, &pDrvCtrl->PHYREGS.phyId2);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_AN_ADS_REG, &pDrvCtrl->PHYREGS.phyAds);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_AN_PRTN_REG, &pDrvCtrl->PHYREGS.phyPrtn);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_AN_EXP_REG, &pDrvCtrl->PHYREGS.phyExp);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_AN_NEXT_REG, &pDrvCtrl->PHYREGS.phyNext);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, L80225_STAT_REG, &pDrvCtrl->l80225Status);
#ifdef ETH_AUTO_NEGOTIATION
/* If link is down, abort auto negotiation. */
if (pDrvCtrl->PHYREGS.phyPrtn)
{
s3c2510EthAnRestart(pDrvCtrl);
}
#else /* ETH_AUTO_NEGOTIATION */
/* Initialize MII Control Register. */
pDrvCtrl->PHYREGS.phyCtrl =
#ifndef ETH_10BT
MII_CR_100 | /* 100T */
#endif /* ETH_10BT */
#ifdef ETH_FULL_DUPLEX
MII_CR_FDX | /* Full-Duplex */
#endif /* ETH_FULL_DUPLEX */
0;
s3c2510EthMiiWrite(pDrvCtrl, phyAddr, MII_CTRL_REG, pDrvCtrl->PHYREGS.phyCtrl);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_STAT_REG, &pDrvCtrl->PHYREGS.phyStatus);
#endif /* ETH_AUTO_NEGOTIATION */
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_CTRL_REG, &pDrvCtrl->PHYREGS.phyCtrl);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_AN_ADS_REG, &pDrvCtrl->PHYREGS.phyAds);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_AN_PRTN_REG, &pDrvCtrl->PHYREGS.phyPrtn);
s3c2510EthMiiRead(pDrvCtrl, phyAddr, L80225_STAT_REG, &pDrvCtrl->l80225Status);
/* Connection speed. */
if (pDrvCtrl->l80225Status & L80225_STAT_100)
{
pDrvCtrl->phyInfo.phySpeed = MII_100MBS;
}
else
{
pDrvCtrl->phyInfo.phySpeed = MII_10MBS;
}
#ifdef DEBUG_TRACE
printf(" MII_CTRL_REG: 0x%04X\n", pDrvCtrl->PHYREGS.phyCtrl);
printf(" MII_STAT_REG: 0x%04X\n", pDrvCtrl->PHYREGS.phyStatus);
printf(" MII_AN_ADS_REG: 0x%04X\n", pDrvCtrl->PHYREGS.phyAds);
printf(" MII_AN_PRTN_REG: 0x%04X\n", pDrvCtrl->PHYREGS.phyPrtn);
printf(" L80225_STAT_REG: 0x%04X\n", pDrvCtrl->l80225Status);
#endif /* DEBUG_TRACE */
return OK;
}
/*******************************************************************************
*
* s3c2510EthAnRestart - restart auto negotiation
*
* RETURNS: OK, or ERROR.
*/
STATUS s3c2510EthAnRestart(
ETH_DRV_CTRL *pDrvCtrl /* pointer to driver structure */
)
{
UINT16 phyAddr = pDrvCtrl->phyInfo.phyAddr;
int timeout = MII_WAIT_MAX;
/* Perserve selector. */
pDrvCtrl->PHYREGS.phyAds &= MII_ADS_SEL_MASK;
/* Set appropriate options. */
pDrvCtrl->PHYREGS.phyAds |=
#ifdef ETH_10BT
MII_TECH_10BASE_T | /* 10T half-duplex capable */
#endif /* ETH_10BT */
#ifdef ETH_FULL_DUPLEX
MII_TECH_100BASE_TX_FD | /* 100TX-FX full-duplex capable */
#ifdef ETH_10BT
MII_TECH_10BASE_FD | /* 10T full-duplex capable */
#endif /* ETH_10BT */
#endif /* ETH_FULL_DUPLEX */
MII_TECH_100BASE_TX; /* 100TX-FX half-duplex capable */
/* Initialize Auto Negotiation Advertisement Register. */
s3c2510EthMiiWrite(pDrvCtrl, phyAddr, MII_AN_ADS_REG, pDrvCtrl->PHYREGS.phyAds);
/* Enable and Start Auto Negotiation. */
pDrvCtrl->PHYREGS.phyCtrl |= MII_CR_AUTO_EN | /* Auto-Negotiation Enable */
MII_CR_RESTART; /* Restart Auto Negotiation */
/* Start auto negotiation. */
s3c2510EthMiiWrite(pDrvCtrl, phyAddr, MII_CTRL_REG, pDrvCtrl->PHYREGS.phyCtrl);
/* Wait until start auto negotiation. */
while (1)
{
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_CTRL_REG, &pDrvCtrl->PHYREGS.phyCtrl);
if (!(pDrvCtrl->PHYREGS.phyCtrl & MII_CR_RESTART))
{
break;
}
}
/* Wait until complete auto negotiation. */
while (1)
{
s3c2510EthMiiRead(pDrvCtrl, phyAddr, MII_STAT_REG, &pDrvCtrl->PHYREGS.phyStatus);
if (pDrvCtrl->PHYREGS.phyStatus & MII_SR_AUTO_NEG)
{
break;
}
if (--timeout == 0)
{
printf("s3c2510Eth%d Error: MII auto negotiation timeout\n", pDrvCtrl->unit);
return ERROR;
}
}
return OK;
}
/**************************************************************************
*
* s3c2510EthMiiRead - read the MII interface
*
* This routine reads the register specified by <phyReg> in the PHY device whose
* address is <phyAddr>. The value read is returned in the location pointed to by
* <miiData>.
*
* RETURNS: OK, or ERROR.
*/
STATUS s3c2510EthMiiRead(
ETH_DRV_CTRL *pDrvCtrl, /* pointer to driver structure */
UINT8 phyAddr, /* the PHY being read */
UINT8 regAddr, /* the PHY's register being read */
UINT16 *miiData /* value read from the MII interface */
)
{
int unit = pDrvCtrl->unit;
UINT16 val;
int timeout = MII_WAIT_MAX;
#ifdef DEBUG_TRACE
printf("s3c2510Eth%d MiiRead, PHY%u, REG%u\n", unit, phyAddr, regAddr);
#endif /* DEBUG_TRACE */
val = (3 << S3C2510_STACON_MDCCLKRATE_SHIFT) | /* MDC Clock Rate */
(phyAddr << S3C2510_STACON_PHYADDR_SHIFT) | /* PHY Address */
(regAddr << S3C2510_STACON_PHYREGADDR_SHIFT) | /* PHY Register Address */
S3C2510_STACON_PHYREAD | /* Read */
S3C2510_STACON_PHYBUSY; /* Start Operation */
*S3C2510_STACON(unit) = val;
/* Wait until complete operation. */
while (1)
{
val = *S3C2510_STACON(unit);
if (!(val & S3C2510_STACON_PHYBUSY)) /* End Operation */
{
break;
}
if (--timeout == 0)
{
printf("s3c2510Eth%d Error: MII read timeout\n", unit);
return ERROR;
}
}
*miiData = *S3C2510_STADATA(unit);
return OK;
}
/**************************************************************************
*
* s3c2510EthMiiWrite - write to the MII register
*
* This routine writes the register specified by <phyReg> in the PHY device whose
* address is <phyAddr>, with the 16-bit value included in <miiData>.
*
* RETURNS: OK, or ERROR.
*/
STATUS s3c2510EthMiiWrite(
ETH_DRV_CTRL *pDrvCtrl, /* pointer to driver structure */
UINT8 phyAddr, /* the PHY being written */
UINT8 regAddr, /* the PHY's register being written */
UINT16 miiData /* value written to the MII interface */
)
{
int unit = pDrvCtrl->unit;
UINT16 val;
int timeout = MII_WAIT_MAX;
#ifdef DEBUG_TRACE
printf("s3c2510Eth%d MiiWrite, PHY%u, REG%u\n", unit, phyAddr, regAddr);
#endif /* DEBUG_TRACE */
*S3C2510_STADATA(unit) = miiData;
val = (3 << S3C2510_STACON_MDCCLKRATE_SHIFT) | /* MDC Clock Rate */
(phyAddr << S3C2510_STACON_PHYADDR_SHIFT) | /* PHY Address */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -