📄 at91emacend.c
字号:
pDrvCtrl->txHdrs = (volatile TXBUF_HDR *) malloc(pDrvCtrl->txNum * sizeof(TXBUF_HDR));
if (pDrvCtrl->txHdrs == NULL)
{
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndMemInit: Could not allocate TX descriptors\n", 1, 2, 3, 4, 5, 6);
return (ERROR);
}
for (i = 0; i < pDrvCtrl->txNum; i++)
{
pDrvCtrl->txHdrs[i].pAdrs = (char *) cacheDmaMalloc(EMAC_END_MAX_CL_LEN);
if (pDrvCtrl->txHdrs[i].pAdrs == NULL)
{
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndMemInit: Could not allocate TX buffer %i\n", i, 2, 3, 4, 5, 6);
return (ERROR);
}
}
/* Allocate a TX buffer for polling mode */
pDrvCtrl->pTxPollBuf = (char *) cacheDmaMalloc(EMAC_END_MAX_CL_LEN);
if (pDrvCtrl->pTxPollBuf == NULL)
{
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndMemInit: Could not allocate TX poll buffer\n", 1, 2, 3, 4, 5, 6);
return (ERROR);
}
/*
* Rx buffer and descriptors (EMAC use the descriptor for receiving data)
*/
#ifdef EMAC_RX_BUFFER_IN_SRAM
/*
* use internal SRAM for RX buffers and descriptors
* ensures that the receive descriptors start on a 64byte boundary
* (errata #11)
* NOTE: Start at offset 0x200 because the area below is used
* by vxWorks for the vectors and exceptions pointer.
*/
pDrvCtrl->rxHdrs = (volatile RXBUF_HDR *) (AT91C_ISRAM + 0x200);
pDrvCtrl->rxBuff = (volatile UCHAR *) (AT91C_ISRAM + 0x300);
for (i = 0; i < pDrvCtrl->rxNum; i++)
{
pDrvCtrl->rxHdrs[i].adrs = (UINT32)(&pDrvCtrl->rxBuff[i * RX_BUFFER_SIZE]);
pDrvCtrl->rxHdrs[i].status = 0;
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndMemInit: RX Buffer %i at 0x%08x.\n", i, (int) pDrvCtrl->rxHdrs[i].adrs,0,0,0,0);
}
#else
/*
* This variant lets the descriptor in SRAM (not cached)
* but allows to create more RX buffers.
* NOTE: Start at offset 0x200 because the area below is used
* by vxWorks for the vectors and exceptions pointer.
*/
pDrvCtrl->rxHdrs = (volatile RXBUF_HDR *) (AT91C_ISRAM + 0x200);
pDrvCtrl->rxBuff = NULL;
pDrvCtrl->rxCluster = (UINT32 *) malloc(pDrvCtrl->rxNum * sizeof(UINT32));
if (pDrvCtrl->rxCluster == NULL)
{
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndMemInit: Could not allocate RX Clusters pointer\n", 1, 2, 3, 4, 5, 6);
return (ERROR);
}
for (i = 0; i < pDrvCtrl->rxNum; i++)
{
char * pBuf = NULL; /* a rx data pointer */
char * pData = NULL;
/* allocate aligned buffer */
if ((pBuf = cacheDmaMalloc(EMAC_END_MAX_CL_LEN)) == NULL)
{
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndMemInit: Could not allocate RX buffer %i\n", i, 2, 3, 4, 5, 6);
return (ERROR);
}
pData = (char *) NET_TO_EMAC_END_BUF(pBuf); /* align buffer according to errata #11 */
pDrvCtrl->rxHdrs[i].adrs = (UINT32) pData;
pDrvCtrl->rxCluster[i] = (UINT32) pBuf; /* save pointer for releasing in unload() routine */
pDrvCtrl->rxHdrs[i].status = 0;
}
#endif /* EMAC_RX_BUFFER_IN_SRAM */
EMAC_END_LOG (EMAC_END_DBG_LOAD, "Memory setup complete\n", 1, 2, 3, 4, 5, 6);
return OK;
}
/*******************************************************************************
*
* at91EmacEndPhyRead - Read from MII register
*
* 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 <retVal>.
*
* SEE ALSO: at91EmacEndPhyWrite()
*
* RETURNS: value read
*/
UINT32 at91EmacEndPhyRead
(
UINT8 phyReg
)
{
UINT32 phyVal; /* value written/read to/from the MII register */
phyVal = ((0x01 << 30) /* Start of Frame Delimiter */
|(0x02 << 28) /* Operation, 0x01 = Write, 0x02 = Read */
|(0x00 << 23) /* Phy Number, 0 as we only have one */
|(phyReg << 18) /* Phy Register */
|(0x02 << 16)); /* must be 0x02 for turn around field */
EMAC_REG(EMAC_MAN) = phyVal;
/* wait for phy read to complete */
sysDelay();
phyVal = EMAC_REG(EMAC_MAN) & 0xFFFF;
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndPhyRead: Phy 0, Reg %i, Read 0x%x.\n", phyReg, phyVal, 0,0,0,0);
return (phyVal);
}
/**************************************************************************
*
* at91EmacEndPhyWrite - 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 <data>.
*
* SEE ALSO: at91EmacEndPhyRead()
*
* RETURNS: N/A.
*/
void at91EmacEndPhyWrite
(
UINT8 phyReg,
UINT16 data
)
{
UINT32 phyVal; /* value written/read to/from the MII register */
phyVal = ((0x01 << 30) /* Start of Frame Delimiter */
|(0x01 << 28) /* Operation, 0x01 = Write, 0x02 = Read */
|(0x00 << 23) /* Phy Number, 0 as we only have one */
|(phyReg << 18) /* Phy Register */
|(0x02 << 16) /* must be 0x02 for turn around field */
| data);
EMAC_REG(EMAC_MAN) = phyVal;
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndStart: Phy 0, Reg %i, Write 0x%x.\n", phyReg, data, 0,0,0,0);
/* wait for phy write to complete */
sysDelay();
}
/*******************************************************************************
*
* at91EmacEndStart - start the device
*
* This function calls BSP functions to connect interrupts and start the
* device running in interrupt mode.
*
* RETURNS: OK or ERROR
*
*/
LOCAL STATUS at91EmacEndStart
(
EMAC_END_DEVICE * pDrvCtrl /* device ID */
)
{
STATUS result;
int i;
int timeout;
UINT32 emacLinkStatus = 0;
/*
* RX buffers and descriptors initialisation
*/
/* initialize the receive buffer descriptors */
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndStart: RX Buffer Header at 0x%08x.\n", (int) pDrvCtrl->rxHdrs, 2, 3, 4, 5, 6);
for (i = 0; i < pDrvCtrl->rxNum; i++)
{
pDrvCtrl->rxHdrs[i].adrs &= ~RXBUF_ADD_OWNED; /* ensure that buffer is owned by the DMA engine */
pDrvCtrl->rxHdrs[i].status = 0;
}
/* set the wrap bit on the last buffer */
pDrvCtrl->rxHdrs[pDrvCtrl->rxNum-1].adrs |= RXBUF_ADD_WRAP;
/* point to the receive buffer queue */
EMAC_REG(EMAC_RBQP) = (UINT32) pDrvCtrl->rxHdrs;
pDrvCtrl->rxIndex = 0;
/* clear Rx status bits */
EMAC_REG(EMAC_RSR) &= ~(EMAC_RSR_OVR | EMAC_RSR_REC | EMAC_RSR_BNA);
/*
* TX buffers and descriptors initialisation
*/
for (i = 0; i < pDrvCtrl->txNum; i++)
{
pDrvCtrl->txHdrs[i].inUse = FALSE; /* buffer not used to transmit */
}
pDrvCtrl->txIndexRd = 0;
pDrvCtrl->txIndexWr = 0;
/* initialize the transmit control register */
EMAC_REG(EMAC_TCR) = 0;
EMAC_REG(EMAC_TAR) = 0;
/* clear Tx status bits */
EMAC_REG(EMAC_TSR) &= ~(EMAC_TSR_UND | EMAC_TSR_COMP | EMAC_TSR_BNQ
| EMAC_TSR_TXIDLE | EMAC_TSR_RLE | EMAC_TSR_COL | EMAC_TSR_OVR);
/*
* PHY configuration
*/
/* set the MII clock divider to MCK/64 */
EMAC_REG(EMAC_CFG) = (EMAC_CFG_CLK_64 | EMAC_CFG_BIG | EMAC_CFG_FD);
/* enable the MII interface */
EMAC_REG(EMAC_CTL) = EMAC_CTL_MPE;
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndStart: Getting Link Status.\n", 0,0,0,0,0,0);
/* Get the link status - wait for done with a timeout */
timeout = 1000;
while (timeout > 0)
{
emacLinkStatus = at91EmacEndPhyRead(MII_STAT_REG);
if (!(emacLinkStatus & MII_SR_AUTO_SEL))
{
EMAC_END_PRINT(EMAC_END_DBG_ERR, ("at91EmacEndStart: PHY is unable to Auto-Negotiate!\n"));
timeout = 0;
break;
}
if (emacLinkStatus & MII_SR_AUTO_NEG)
{
EMAC_END_PRINT(EMAC_END_DBG_LOAD, ("at91EmacEndStart: Auto-Negotiate Complete, Link = "));
break;
}
timeout-- ;
}
if (!(timeout))
{
EMAC_END_PRINT(EMAC_END_DBG_ERR, ("at91EmacEndStart: Auto-Negotatiate Failed, Status = 0x%x!\n", emacLinkStatus));
return ERROR;
}
/* Set SPD and FD based on the return link status */
if (emacLinkStatus & (MII_SR_TX_HALF_DPX | MII_SR_TX_FULL_DPX))
{
EMAC_REG(EMAC_CFG) |= EMAC_CFG_SPD;
EMAC_END_PRINT(EMAC_END_DBG_LOAD, ("100MBIT, "));
}
else
{
EMAC_REG(EMAC_CFG) &= ~EMAC_CFG_SPD;
EMAC_END_PRINT(EMAC_END_DBG_LOAD, ("10MBIT, "));
}
if (emacLinkStatus & (MII_SR_TX_FULL_DPX | MII_SR_10T_FULL_DPX))
{
EMAC_REG(EMAC_CFG) |= EMAC_CFG_FD;
EMAC_END_PRINT(EMAC_END_DBG_LOAD, ("Full Duplex.\n"));
}
else
{
EMAC_REG(EMAC_CFG) &= ~EMAC_CFG_FD;
EMAC_END_PRINT(EMAC_END_DBG_LOAD, ("Half Duplex.\n"));
}
#ifdef TARGET_CSB337
/* Set PHY LED1 to Speed, PHY LED2 to combined Link/Activity and enable pulse stretching */
at91EmacEndPhyWrite(0x14, (LXT971_LED1(LXT971_LED_SPEED)
| LXT971_LED2(LXT971_LED_LINK_RX_TX)
| LXT971_LED_STRETCH_30MS
| LXT971_LED_STRETCH_ON));
#endif /* TARGET_CSB337 */
/* disable the MII interface */
EMAC_REG(EMAC_CTL) &= ~EMAC_CTL_MPE;
SYS_INT_CONNECT (pDrvCtrl, at91EmacEndInt, (int)pDrvCtrl, &result);
if (result == ERROR)
{
return ERROR;
}
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndStart: Interrupt connected.\n", 1, 2, 3, 4, 5, 6);
SYS_INT_ENABLE (pDrvCtrl);
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndStart: interrupt enabled.\n", 1, 2, 3, 4, 5, 6);
END_FLAGS_SET (&pDrvCtrl->end, IFF_UP | IFF_RUNNING);
EMAC_END_LOG (EMAC_END_DBG_LOAD, "at91EmacEndStart: Enable TX and RX.\n", 0,0,0,0,0,0);
/* Enable interrupts */
EMAC_REG(EMAC_IER) = EMAC_INT_RCOM | EMAC_INT_RBNA
| EMAC_INT_TUND | EMAC_INT_RTRY | EMAC_INT_TCOM
| EMAC_INT_ROVR | EMAC_INT_ABT;
/* Enable TX/RX and clear the statistics counters */
EMAC_REG(EMAC_CTL) = (EMAC_CTL_TE | EMAC_CTL_RE | EMAC_CTL_CSR);
return (OK);
}
/*******************************************************************************
*
* at91EmacEndNextSend - send next packet
*
* This routine send the nex packet through the EMAC.
*
* RETURNS: current TX index.
*/
int at91EmacEndNextSend
(
EMAC_END_DEVICE *pDrvCtrl /* interrupting device */
)
{
UINT32 stat;
volatile TXBUF_HDR * pBufHdr;
stat = EMAC_REG(EMAC_TSR);
if ((stat & EMAC_TSR_BNQ) == EMAC_TSR_BNQ)
{
/* release packet from queue (should be the current index pointed) */
if (EMAC_REG(EMAC_TAR) != 0)
{
pBufHdr = (volatile TXBUF_HDR *) &pDrvCtrl->txHdrs[pDrvCtrl->txIndexRd];
pBufHdr->inUse = FALSE;
/* next index to enqueue */
if (pDrvCtrl->txIndexRd == (pDrvCtrl->txNum-1))
{
pDrvCtrl->txIndexRd = 0;
}
else
{
pDrvCtrl->txIndexRd++;
}
}
/* enqueue packet */
pBufHdr = (volatile TXBUF_HDR *) &pDrvCtrl->txHdrs[pDrvCtrl->txIndexRd];
if (pBufHdr->inUse)
{
EMAC_REG(EMAC_TAR) = (UINT32) pBufHdr->pAdrs;
EMAC_REG(EMAC_TCR) = EMAC_TCR_LEN((UINT32) pBufHdr->length);
at91EmacEndNumSend++;
EMAC_END_LOG (EMAC_END_DBG_TX, "at91EmacEndNextSend: send adrs=0x%x, length=%i (%i).\n",
(int) pBufHdr->pAdrs, pBufHdr->length, pDrvCtrl->txIndexRd,0,0,0);
}
else
{
EMAC_REG(EMAC_TCR) = 0;
EMAC_REG(EMAC_TAR) = 0;
EMAC_END_LOG (EMAC_END_DBG_TX, "at91EmacEndNextSend: Nothing more to send (%i).\n",
pDrvCtrl->txIndexRd, 0,0,0,0,0);
}
}
return(pDrvCtrl->txIndexRd);
}
/*******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -