[bsp] update emac driver

- fix 10 or hard duplex not work
- rewrite tx/rx function
- update emac init function
This commit is contained in:
tanek liang 2017-11-24 15:26:53 +08:00
parent aa0747f64e
commit e2b5f7a722
1 changed files with 532 additions and 398 deletions

View File

@ -22,6 +22,7 @@
*/ */
#include <rtthread.h> #include <rtthread.h>
#include "lwipopts.h" #include "lwipopts.h"
#include <netif/ethernetif.h> #include <netif/ethernetif.h>
#include <board.h> #include <board.h>
@ -32,6 +33,16 @@
#include "fsl_sctimer.h" #include "fsl_sctimer.h"
#include "fsl_phy.h" #include "fsl_phy.h"
#define DEBUG
//#define ETH_RX_DUMP
//#define ETH_TX_DUMP
#define ETH_STATISTICS
#ifdef DEBUG
#define ETH_PRINTF rt_kprintf
#else
#define ETH_PRINTF(...)
#endif
#define IOCON_PIO_DIGITAL_EN 0x0100u /*!< Enables digital function */ #define IOCON_PIO_DIGITAL_EN 0x0100u /*!< Enables digital function */
#define IOCON_PIO_FUNC0 0x00u /*!< Selects pin function 0 */ #define IOCON_PIO_FUNC0 0x00u /*!< Selects pin function 0 */
@ -60,245 +71,115 @@
#define PORT2_IDX 2u /*!< Port index */ #define PORT2_IDX 2u /*!< Port index */
#define PORT4_IDX 4u /*!< Port index */ #define PORT4_IDX 4u /*!< Port index */
#define MAX_ADDR_LEN 6u
#define ENET_RXBD_NUM 4u
#define ENET_TXBD_NUM 4u
#define EMAC_PHY_AUTO 0 #define ENET_ALIGN(x) \
#define EMAC_PHY_10MBIT 1 ((unsigned int)((x) + ((ENET_BUFF_ALIGNMENT)-1)) & (unsigned int)(~(unsigned int)((ENET_BUFF_ALIGNMENT)-1)))
#define EMAC_PHY_100MBIT 2
#define MAX_ADDR_LEN 6 #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
#define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
/* EMAC_RAM_BASE is defined in board.h and the size is 16KB */
#define RX_DESC_BASE ETH_RAM_BASE
#define RX_STAT_BASE (RX_DESC_BASE + NUM_RX_FRAG*8)
#define TX_DESC_BASE (RX_STAT_BASE + NUM_RX_FRAG*8)
#define TX_STAT_BASE (TX_DESC_BASE + NUM_TX_FRAG*8)
#define RX_BUF_BASE (TX_STAT_BASE + NUM_TX_FRAG*4)
#define TX_BUF_BASE (RX_BUF_BASE + NUM_RX_FRAG*ETH_FRAG_SIZE)
/* RX and TX descriptor and status definitions. */
#define RX_DESC_PACKET(i) (*(unsigned int *)(RX_DESC_BASE + 8*i))
#define RX_DESC_CTRL(i) (*(unsigned int *)(RX_DESC_BASE+4 + 8*i))
#define RX_STAT_INFO(i) (*(unsigned int *)(RX_STAT_BASE + 8*i))
#define RX_STAT_HASHCRC(i) (*(unsigned int *)(RX_STAT_BASE+4 + 8*i))
#define TX_DESC_PACKET(i) (*(unsigned int *)(TX_DESC_BASE + 8*i))
#define TX_DESC_CTRL(i) (*(unsigned int *)(TX_DESC_BASE+4 + 8*i))
#define TX_STAT_INFO(i) (*(unsigned int *)(TX_STAT_BASE + 4*i))
#define RX_BUF(i) (RX_BUF_BASE + ETH_FRAG_SIZE*i)
#define TX_BUF(i) (TX_BUF_BASE + ETH_FRAG_SIZE*i)
struct lpc_emac struct lpc_emac
{ {
/* inherit from ethernet device */ /* inherit from ethernet device */
struct eth_device parent; struct eth_device parent;
struct rt_semaphore tx_wait;
rt_uint8_t phy_mode; ENET_Type *base;
enet_handle_t handle;
/* interface address info. */ /* interface address info. */
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */
uint32_t phyAddr;
uint8_t RxBuffDescrip[ENET_RXBD_NUM * sizeof(enet_rx_bd_struct_t) + ENET_BUFF_ALIGNMENT];
uint8_t TxBuffDescrip[ENET_TXBD_NUM * sizeof(enet_tx_bd_struct_t) + ENET_BUFF_ALIGNMENT];
uint8_t RxDataBuff[ENET_RXBD_NUM * ENET_ALIGN(ENET_RXBUFF_SIZE) + ENET_BUFF_ALIGNMENT];
uint8_t TxDataBuff[ENET_TXBD_NUM * ENET_ALIGN(ENET_TXBUFF_SIZE) + ENET_BUFF_ALIGNMENT];
uint8_t txIdx;
}; };
static struct lpc_emac lpc_emac_device; static struct lpc_emac lpc_emac_device;
static struct rt_semaphore sem_lock;
static struct rt_event tx_event;
#if defined(__GNUC__) #ifdef ETH_STATISTICS
#ifndef __ALIGN_END static uint32_t isr_rx_counter = 0;
#define __ALIGN_END __attribute__((aligned(ENET_BUFF_ALIGNMENT))) static uint32_t isr_tx_counter = 0;
#endif
#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif #endif
static inline enet_rx_bd_struct_t *get_rx_desc(uint32_t index)
{
return (enet_rx_bd_struct_t *)ENET_ALIGN(&lpc_emac_device.RxBuffDescrip[index * sizeof(enet_rx_bd_struct_t)]);
}
static inline enet_tx_bd_struct_t *get_tx_desc(uint32_t index)
{
return (enet_tx_bd_struct_t *)ENET_ALIGN(&lpc_emac_device.TxBuffDescrip[index * sizeof(enet_tx_bd_struct_t)]);
}
#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
static void packet_dump(const char * msg, const struct pbuf* p)
{
const struct pbuf* q;
rt_uint32_t i,j;
rt_uint8_t *ptr;
rt_kprintf("%s %d byte\n", msg, p->tot_len);
i=0;
for(q=p; q != RT_NULL; q= q->next)
{
ptr = q->payload;
for(j=0; j<q->len; j++)
{
if( (i%8) == 0 )
{
rt_kprintf(" ");
}
if( (i%16) == 0 )
{
rt_kprintf("\r\n");
}
rt_kprintf("%02x ",*ptr);
i++;
ptr++;
}
}
rt_kprintf("\n\n");
}
#else #else
#ifndef __ALIGN_END #define packet_dump(...)
#define __ALIGN_END #endif /* dump */
static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, uint8_t channel, void *param)
{
switch (event)
{
case kENET_RxIntEvent:
#ifdef ETH_STATISTICS
isr_rx_counter++;
#endif #endif
#ifndef __ALIGN_BEGIN
#if defined(__CC_ARM)
#define __ALIGN_BEGIN __align(ENET_BUFF_ALIGNMENT)
#elif defined(__ICCARM__)
#define __ALIGN_BEGIN
#endif
#endif
#endif
#define ENET_RXBD_NUM (4)
#define ENET_TXBD_NUM (4)
#define PHY_ADDR (0x00U)
#define ENET_LOOP_COUNT (20U)
#define ENET_ALIGN(x, align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)-1)))
#define ENET_BuffSizeAlign(n) ENET_ALIGN(n, ENET_BUFF_ALIGNMENT)
__ALIGN_BEGIN enet_rx_bd_struct_t g_rxBuffDescrip[ENET_RXBD_NUM] __ALIGN_END;
__ALIGN_BEGIN enet_tx_bd_struct_t g_txBuffDescrip[ENET_TXBD_NUM] __ALIGN_END;
uint8_t multicastAddr[6] = {0x01, 0x00, 0x5e, 0x00, 0x01, 0x81};
uint8_t *g_txbuff[ENET_TXBD_NUM];
uint32_t g_txIdx = 0;
uint8_t g_txbuffIdx = 0;
uint8_t g_txGenIdx = 0;
uint8_t g_txCosumIdx = 0;
uint8_t g_txUsed = 0;
uint8_t g_rxGenIdx = 0;
uint32_t g_rxCosumIdx = 0;
uint32_t g_rxbuffer[ENET_RXBD_NUM];
static uint8_t *ENET_RXRead(int32_t *length)
{
uint32_t control;
uint8_t *data;
*length = 0;
/* Get the Frame size */
control = ENET_GetRxDescriptor(&g_rxBuffDescrip[g_rxGenIdx]);
if (!(control & ENET_RXDESCRIP_RD_OWN_MASK))
{
if (control & ENET_RXDESCRIP_WR_LD_MASK)
{
/* if no error */
if (control & ENET_RXDESCRIP_WR_ERRSUM_MASK)
{
*length = -1;
}
else
{
*length = control & ENET_RXDESCRIP_WR_PACKETLEN_MASK;
data = (uint8_t *)g_rxbuffer[g_rxGenIdx];
}
g_rxGenIdx = (g_rxGenIdx + 1) % ENET_RXBD_NUM;
}
}
return data;
}
static void ENET_RXClaim(uint8_t* buffer)
{
if (ENET_GetDmaInterruptStatus(ENET, 0) & kENET_DmaRxBuffUnavail)
{
ENET_UpdateRxDescriptor(&g_rxBuffDescrip[g_rxCosumIdx], buffer, NULL, true, false);
/* Command for rx poll when the dma suspend. */
ENET_UpdateRxDescriptorTail(ENET, 0, (uint32_t)&g_rxBuffDescrip[ENET_RXBD_NUM]);
}
else
{
ENET_UpdateRxDescriptor(&g_rxBuffDescrip[g_rxCosumIdx], buffer, NULL, true, false);
}
if (buffer)
{
g_rxbuffer[g_rxCosumIdx] = (uint32_t)buffer;
}
g_rxCosumIdx = (g_rxCosumIdx + 1) % ENET_RXBD_NUM;
}
static status_t ENET_TXQueue(uint8_t *data, uint16_t length)
{
uint32_t txdescTailAddr;
/* Fill the descriptor. */
if (ENET_IsTxDescriptorDmaOwn(&g_txBuffDescrip[g_txGenIdx]))
{
return kStatus_Fail;
}
ENET_SetupTxDescriptor(&g_txBuffDescrip[g_txGenIdx], data, length, NULL, 0, length, true, false, kENET_FirstLastFlag, 0);
/* Increase the index. */
g_txGenIdx = (g_txGenIdx + 1) % ENET_TXBD_NUM;
g_txUsed++;
/* Update the transmit tail address. */
txdescTailAddr = (uint32_t)&g_txBuffDescrip[g_txGenIdx];
if (!g_txGenIdx)
{
txdescTailAddr = (uint32_t)&g_txBuffDescrip[ENET_TXBD_NUM];
}
ENET_UpdateTxDescriptorTail(ENET, 0, txdescTailAddr);
return kStatus_Success;
}
static void ENET_TXReclaim()
{
if (!ENET_IsTxDescriptorDmaOwn(&g_txBuffDescrip[g_txCosumIdx]) && (g_txUsed > 0))
{
/* Free tx buffers. */
free(g_txbuff[g_txCosumIdx]);
g_txUsed--;
g_txCosumIdx = (g_txCosumIdx + 1) % ENET_TXBD_NUM;
}
}
void ETHERNET_IRQHandler(void)
{
/* Check for the interrupt source type. */
/* DMA CHANNEL 0. */
uint32_t status;
/* enter interrupt */
rt_interrupt_enter();
status = ENET_GetDmaInterruptStatus(ENET, 0);
if (status)
{
if (status & kENET_DmaRx)
{
/* a frame has been received */ /* a frame has been received */
eth_device_ready(&(lpc_emac_device.parent)); eth_device_ready(&(lpc_emac_device.parent));
} break;
if (status & kENET_DmaTx) case kENET_TxIntEvent:
{ #ifdef ETH_STATISTICS
isr_tx_counter++;
#endif
/* set event */ /* set event */
rt_event_send(&tx_event, 0x01); rt_sem_release(&lpc_emac_device.tx_wait);
break;
default:
break;
} }
/* Clear the interrupt. */
ENET_ClearDmaInterruptStatus(ENET, 0, status);
}
/* leave interrupt */
rt_interrupt_leave();
} }
static rt_err_t lpc_emac_init(rt_device_t dev) static void lcp_emac_io_init(void)
{ {
int32_t status, index;
void *buff;
phy_speed_t speed;
phy_duplex_t duplex;
enet_config_t config;
bool link = false;
uint32_t timedelay;
uint32_t refClock = 50000000; /* 50MHZ for rmii reference clock. */
for (index = 0; index < ENET_RXBD_NUM; index++)
{
/* This is for rx buffers, static alloc and dynamic alloc both ok. use as your wish. */
buff = rt_malloc(ENET_FRAME_MAX_FRAMELEN);
if (buff)
{
g_rxbuffer[index] = (uint32_t)buff;
}
else
{
rt_kprintf("Mem Alloc fail\r\n");
}
}
/* prepare the buffer configuration. */
enet_buffer_config_t buffConfig =
{
ENET_RXBD_NUM,
ENET_TXBD_NUM,
&g_txBuffDescrip[0],
&g_txBuffDescrip[0],
&g_rxBuffDescrip[0],
&g_rxBuffDescrip[4],
&g_rxbuffer[0],
ENET_BuffSizeAlign(ENET_FRAME_MAX_FRAMELEN),
};
{
const uint32_t port0_pin17_config = ( const uint32_t port0_pin17_config = (
IOCON_PIO_FUNC7 | /* Pin is configured as ENET_TXD1 */ IOCON_PIO_FUNC7 | /* Pin is configured as ENET_TXD1 */
IOCON_PIO_MODE_INACT | /* No addition pin function */ IOCON_PIO_MODE_INACT | /* No addition pin function */
@ -399,49 +280,104 @@ static rt_err_t lpc_emac_init(rt_device_t dev)
IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */
); );
IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN8_IDX, port4_pin8_config); /* PORT4 PIN8 (coords: B14) is configured as ENET_TXD0 */ IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN8_IDX, port4_pin8_config); /* PORT4 PIN8 (coords: B14) is configured as ENET_TXD0 */
} }
status = PHY_Init(ENET, PHY_ADDR, 0); static rt_err_t lpc_emac_phy_init(phy_speed_t * speed, phy_duplex_t * duplex)
if (status == kStatus_Success) {
bool link = false;
int32_t status;
status = PHY_Init(lpc_emac_device.base, lpc_emac_device.phyAddr, 0);
if (status != kStatus_Success)
{ {
PHY_GetLinkSpeedDuplex(ENET, PHY_ADDR, &speed, &duplex); ETH_PRINTF("PHY_Init failed!\n");
/* Use the actual speed and duplex when phy success to finish the autonegotiation. */
config.miiSpeed = (enet_mii_speed_t)speed;
config.miiDuplex = (enet_mii_duplex_t)duplex;
}
else
{
rt_kprintf("PHY_Init failed!\n");
return RT_ERROR; return RT_ERROR;
} }
/* Wait for link up and get the actual PHY link speed. */ /* Wait for link up and get the actual PHY link speed. */
PHY_GetLinkStatus(ENET, PHY_ADDR, &link); PHY_GetLinkStatus(lpc_emac_device.base, lpc_emac_device.phyAddr, &link);
while (!link) while (!link)
{ {
rt_kprintf("PHY Wait for link up!\n"); uint32_t timedelay;
ETH_PRINTF("PHY Wait for link up!\n");
for (timedelay = 0; timedelay < 0xFFFFFU; timedelay++) for (timedelay = 0; timedelay < 0xFFFFFU; timedelay++)
{ {
__ASM("nop"); __ASM("nop");
} }
PHY_GetLinkStatus(ENET, PHY_ADDR, &link); PHY_GetLinkStatus(lpc_emac_device.base, lpc_emac_device.phyAddr, &link);
} }
RT_ASSERT(speed != NULL);
RT_ASSERT(duplex != NULL);
PHY_GetLinkSpeedDuplex(lpc_emac_device.base, lpc_emac_device.phyAddr, speed, duplex);
return RT_EOK;
}
static rt_err_t lpc_emac_init(rt_device_t dev)
{
int i;
phy_speed_t speed;
phy_duplex_t duplex;
enet_config_t config;
enet_buffer_config_t buffCfg;
uint32_t rxBufferStartAddr[ENET_RXBD_NUM];
lcp_emac_io_init();
if (lpc_emac_phy_init(&speed, &duplex) != RT_EOK)
{
return RT_ERROR;
}
/* calculate start addresses of all rx buffers */
for (i = 0; i < ENET_RXBD_NUM; i++)
{
rxBufferStartAddr[i] = ENET_ALIGN(&lpc_emac_device.RxDataBuff[i * ENET_ALIGN(ENET_RXBUFF_SIZE)]);
}
buffCfg.rxRingLen = ENET_RXBD_NUM;
buffCfg.txRingLen = ENET_TXBD_NUM;
buffCfg.txDescStartAddrAlign = get_tx_desc(0U);
buffCfg.txDescTailAddrAlign = get_tx_desc(0U);
buffCfg.rxDescStartAddrAlign = get_rx_desc(0U);
buffCfg.rxDescTailAddrAlign = get_rx_desc(ENET_RXBD_NUM);
buffCfg.rxBufferStartAddr = rxBufferStartAddr;
buffCfg.rxBuffSizeAlign = ENET_ALIGN(ENET_RXBUFF_SIZE);
/* Get default configuration 100M RMII. */ /* Get default configuration 100M RMII. */
ENET_GetDefaultConfig(&config); ENET_GetDefaultConfig(&config);
/* Use the actual speed and duplex when phy success to finish the autonegotiation. */
config.miiSpeed = (enet_mii_speed_t)speed;
config.miiDuplex = (enet_mii_duplex_t)duplex;
/* Initialize ENET. */ ETH_PRINTF("Auto negotiation, Speed: ");
ENET_Init(ENET, &config, &lpc_emac_device.dev_addr[0], refClock); if (config.miiSpeed == kENET_MiiSpeed100M)
ETH_PRINTF("100M");
else
ETH_PRINTF("10M");
ETH_PRINTF(", Duplex: ");
if (config.miiSpeed == kENET_MiiSpeed100M)
ETH_PRINTF("Full\n");
else
ETH_PRINTF("Half\n");
/* Initialize lpc_emac_device.base. */
ENET_Init(lpc_emac_device.base, &config, &lpc_emac_device.dev_addr[0], CLOCK_GetFreq(kCLOCK_CoreSysClk));
/* Enable the tx/rx interrupt. */ /* Enable the tx/rx interrupt. */
ENET_EnableInterrupts(ENET, (kENET_DmaTx | kENET_DmaRx)); ENET_EnableInterrupts(lpc_emac_device.base, (kENET_DmaTx | kENET_DmaRx));
EnableIRQ(ETHERNET_IRQn); ENET_CreateHandler(lpc_emac_device.base, &lpc_emac_device.handle, &config, &buffCfg, ethernet_callback, NULL);
/* Initialize Descriptor. */ /* Initialize Descriptor. */
ENET_DescriptorInit(ENET, &config, &buffConfig); ENET_DescriptorInit(lpc_emac_device.base, &config, &buffCfg);
/* Active TX/RX. */ /* Active TX/RX. */
ENET_StartRxTx(ENET, 1, 1); ENET_StartRxTx(lpc_emac_device.base, 1, 1);
eth_device_linkchange(&lpc_emac_device.parent, RT_TRUE);
return RT_EOK; return RT_EOK;
} }
@ -489,39 +425,47 @@ static rt_err_t lpc_emac_control(rt_device_t dev, int cmd, void *args)
/* transmit packet. */ /* transmit packet. */
rt_err_t lpc_emac_tx(rt_device_t dev, struct pbuf *p) rt_err_t lpc_emac_tx(rt_device_t dev, struct pbuf *p)
{ {
rt_uint8_t *buffer; rt_err_t result = RT_EOK;
enet_handle_t * enet_handle = &lpc_emac_device.handle;
ENET_Type *enet_base = lpc_emac_device.base;
uint8_t * data;
RT_ASSERT(p != NULL);
RT_ASSERT(enet_handle != RT_NULL);
if (p->tot_len > ENET_TXBUFF_SIZE)
{
return RT_ERROR;
}
packet_dump("TX dump", p);
/* get free tx buffer */
{
rt_err_t result; rt_err_t result;
rt_uint32_t recved; result = rt_sem_take(&lpc_emac_device.tx_wait, RT_TICK_PER_SECOND/10);
if (result != RT_EOK)
/* lock EMAC device */
rt_sem_take(&sem_lock, RT_WAITING_FOREVER);
/* there is no block yet, wait a flag */
result = rt_event_recv(&tx_event, 0x01, RT_EVENT_FLAG_AND | RT_EVENT_FLAG_CLEAR, RT_WAITING_NO, &recved);
if (result == RT_EOK)
ENET_TXReclaim();
/* Create the buffer for zero-copy transmit. */
buffer = (uint8_t *)malloc(p->tot_len);
if (buffer)
{ {
/* copy data to tx buffer */ return RT_ERROR;
pbuf_copy_partial(p, buffer, p->tot_len, 0); }
while ((g_txbuffIdx + 1) % ENET_TXBD_NUM == g_txCosumIdx)
{
rt_thread_delay(RT_TICK_PER_SECOND / 20); // 50 ms
} }
/* Store the buffer for mem free. */ data = (uint8_t *)ENET_ALIGN(&lpc_emac_device.RxDataBuff[lpc_emac_device.txIdx * ENET_ALIGN(ENET_RXBUFF_SIZE)]);
g_txbuff[g_txbuffIdx] = buffer; pbuf_copy_partial(p, data, p->tot_len, 0);
g_txbuffIdx = (g_txbuffIdx + 1) % ENET_TXBD_NUM; lpc_emac_device.txIdx = (lpc_emac_device.txIdx + 1) / ENET_TXBD_NUM;
/* Send the frame out (wait unitl the descriptor ready). */
while (ENET_TXQueue(buffer, p->tot_len) != kStatus_Success);
}
/* unlock EMAC device */ result = ENET_SendFrame(enet_base, enet_handle, data, p->len);
rt_sem_release(&sem_lock);
RT_ASSERT(result != kStatus_ENET_TxFrameBusy);
if ((result == kStatus_ENET_TxFrameFail) || (result == kStatus_ENET_TxFrameOverLen))
{
return RT_ERROR;
}
else if (result == kStatus_ENET_TxFrameBusy)
{
RT_ASSERT(NULL);
}
return RT_EOK; return RT_EOK;
} }
@ -529,60 +473,58 @@ rt_err_t lpc_emac_tx(rt_device_t dev, struct pbuf *p)
/* reception packet. */ /* reception packet. */
struct pbuf *lpc_emac_rx(rt_device_t dev) struct pbuf *lpc_emac_rx(rt_device_t dev)
{ {
struct pbuf *p; uint32_t length = 0;
uint8_t *data; status_t status;
int length;
/* init p pointer */ struct pbuf* p = RT_NULL;
p = RT_NULL; enet_handle_t * enet_handle = &lpc_emac_device.handle;
ENET_Type *enet_base = lpc_emac_device.base;
/* lock EMAC device */ /* Get the Frame size */
rt_sem_take(&sem_lock, RT_WAITING_FOREVER); status = ENET_GetRxFrameSize(enet_base, enet_handle, &length, 0);
length = 0; /* Call ENET_ReadFrame when there is a received frame. */
data = ENET_RXRead(&length); if (length != 0)
if (length > 0)
{ {
void *buffer; /* Received valid frame. Deliver the rx buffer with the size equal to length. */
/* Update the buffers and then we can delivery the previous buffer diectly to p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
the application without memcpy. */
buffer = rt_malloc(ENET_FRAME_MAX_FRAMELEN); if (p != NULL)
if (buffer)
{ {
ENET_RXClaim(buffer); status = ENET_ReadFrame(enet_base, enet_handle, p->payload, length, 0);
if (status == kStatus_Success)
{
packet_dump("RX dump", p);
return p;
} }
else else
{ {
ENET_RXClaim(NULL); ETH_PRINTF(" A frame read failed\n");
pbuf_free(p);
} }
}
/* Do what you want to do with the data and then free the used one. */ else
p = pbuf_alloc(PBUF_LINK, length, PBUF_RAM);
if (p != RT_NULL)
{ {
rt_memcpy(p->payload, data, length); ETH_PRINTF(" pbuf_alloc faild\n");
p->tot_len = length;
} }
rt_free(data);
} }
else if (length < 0) else if (status == kStatus_ENET_RxFrameError)
{ {
ENET_RXClaim(NULL); ETH_PRINTF("ENET_GetRxFrameSize: kStatus_ENET_RxFrameError\n");
ENET_ReadFrame(enet_base, enet_handle, NULL, 0, 0);
} }
/* unlock EMAC device */ return NULL;
rt_sem_release(&sem_lock);
return p;
} }
int lpc_emac_hw_init(void) int lpc_emac_hw_init(void)
{ {
rt_event_init(&tx_event, "tx_event", RT_IPC_FLAG_FIFO); /* init tx semaphore */
rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO); rt_sem_init(&lpc_emac_device.tx_wait, "tx_wait", ENET_TXBD_NUM, RT_IPC_FLAG_FIFO);
/* set autonegotiation mode */ lpc_emac_device.phyAddr = 0;
lpc_emac_device.phy_mode = EMAC_PHY_AUTO; lpc_emac_device.txIdx = 0;
lpc_emac_device.base = ENET;
// OUI 00-60-37 NXP Semiconductors // OUI 00-60-37 NXP Semiconductors
lpc_emac_device.dev_addr[0] = 0x00; lpc_emac_device.dev_addr[0] = 0x00;
@ -605,6 +547,198 @@ int lpc_emac_hw_init(void)
lpc_emac_device.parent.eth_tx = lpc_emac_tx; lpc_emac_device.parent.eth_tx = lpc_emac_tx;
eth_device_init(&(lpc_emac_device.parent), "e0"); eth_device_init(&(lpc_emac_device.parent), "e0");
return 0; return 0;
} }
INIT_DEVICE_EXPORT(lpc_emac_hw_init); INIT_DEVICE_EXPORT(lpc_emac_hw_init);
#ifdef ETH_STATISTICS
int emac_stat(void)
{
rt_kprintf("enter rx isr coutner : %d\n", isr_rx_counter);
rt_kprintf("enter tx isr coutner : %d\n", isr_tx_counter);
return 0;
}
#endif
void phy_dump(void)
{
status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr);
int i;
for (i = 0; i < 31; i++)
{
status_t result = kStatus_Success;
uint32_t reg;
result = PHY_Read(lpc_emac_device.base, lpc_emac_device.phyAddr, i, &reg);
if (result == kStatus_Success)
{
rt_kprintf("%02d: %08d\n", i, reg);
}
else
{
rt_kprintf("read register %d faild\n", i);
}
}
}
void emac_dump(void)
{
#define DUMP_REG(__NAME) \
rt_kprintf("%-40s, %08x: %08x\n", #__NAME, (uint32_t)&(lpc_emac_device.base->__NAME), lpc_emac_device.base->__NAME)
DUMP_REG(MAC_CONFIG);
DUMP_REG(MAC_EXT_CONFIG);
DUMP_REG(MAC_FRAME_FILTER);
DUMP_REG(MAC_WD_TIMEROUT);
DUMP_REG(MAC_VLAN_TAG);
DUMP_REG(MAC_TX_FLOW_CTRL_Q[0]);
DUMP_REG(MAC_TX_FLOW_CTRL_Q[1]);
DUMP_REG(MAC_RX_FLOW_CTRL);
DUMP_REG(MAC_TXQ_PRIO_MAP);
DUMP_REG(MAC_RXQ_CTRL[0]);
DUMP_REG(MAC_RXQ_CTRL[1]);
DUMP_REG(MAC_RXQ_CTRL[2]);
DUMP_REG(MAC_INTR_STAT);
DUMP_REG(MAC_INTR_EN);
DUMP_REG(MAC_RXTX_STAT);
DUMP_REG(MAC_PMT_CRTL_STAT);
DUMP_REG(MAC_RWAKE_FRFLT);
DUMP_REG(MAC_LPI_CTRL_STAT);
DUMP_REG(MAC_LPI_TIMER_CTRL);
DUMP_REG(MAC_LPI_ENTR_TIMR);
DUMP_REG(MAC_1US_TIC_COUNTR);
DUMP_REG(MAC_VERSION);
DUMP_REG(MAC_DBG);
DUMP_REG(MAC_HW_FEAT[0]);
DUMP_REG(MAC_HW_FEAT[1]);
DUMP_REG(MAC_HW_FEAT[2]);
DUMP_REG(MAC_MDIO_ADDR);
DUMP_REG(MAC_MDIO_DATA);
DUMP_REG(MAC_ADDR_HIGH);
DUMP_REG(MAC_ADDR_LOW);
DUMP_REG(MAC_TIMESTAMP_CTRL);
DUMP_REG(MAC_SUB_SCND_INCR);
DUMP_REG(MAC_SYS_TIME_SCND);
DUMP_REG(MAC_SYS_TIME_NSCND);
DUMP_REG(MAC_SYS_TIME_SCND_UPD);
DUMP_REG(MAC_SYS_TIME_NSCND_UPD);
DUMP_REG(MAC_SYS_TIMESTMP_ADDEND);
DUMP_REG(MAC_SYS_TIME_HWORD_SCND);
DUMP_REG(MAC_SYS_TIMESTMP_STAT);
DUMP_REG(MAC_TX_TIMESTAMP_STATUS_NANOSECONDS);
DUMP_REG(MAC_TX_TIMESTAMP_STATUS_SECONDS);
DUMP_REG(MAC_TIMESTAMP_INGRESS_CORR_NANOSECOND);
DUMP_REG(MAC_TIMESTAMP_EGRESS_CORR_NANOSECOND);
DUMP_REG(MTL_OP_MODE);
DUMP_REG(MTL_INTR_STAT);
DUMP_REG(MTL_RXQ_DMA_MAP);
DUMP_REG(DMA_MODE);
DUMP_REG(DMA_SYSBUS_MODE);
DUMP_REG(DMA_INTR_STAT);
DUMP_REG(DMA_DBG_STAT);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_OP_MODE);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_UNDRFLW);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_DBG);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_ETS_CTRL);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_ETS_STAT);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_QNTM_WGHT);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_SNDSLP_CRDT);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_HI_CRDT);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_LO_CRDT);
DUMP_REG(MTL_QUEUE[0].MTL_TXQX_INTCTRL_STAT);
DUMP_REG(MTL_QUEUE[0].MTL_RXQX_OP_MODE);
DUMP_REG(MTL_QUEUE[0].MTL_RXQX_MISSPKT_OVRFLW_CNT);
DUMP_REG(MTL_QUEUE[0].MTL_RXQX_DBG);
DUMP_REG(MTL_QUEUE[0].MTL_RXQX_CTRL);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_OP_MODE);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_UNDRFLW);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_DBG);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_ETS_CTRL);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_ETS_STAT);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_QNTM_WGHT);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_SNDSLP_CRDT);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_HI_CRDT);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_LO_CRDT);
DUMP_REG(MTL_QUEUE[1].MTL_TXQX_INTCTRL_STAT);
DUMP_REG(MTL_QUEUE[1].MTL_RXQX_OP_MODE);
DUMP_REG(MTL_QUEUE[1].MTL_RXQX_MISSPKT_OVRFLW_CNT);
DUMP_REG(MTL_QUEUE[1].MTL_RXQX_DBG);
DUMP_REG(MTL_QUEUE[1].MTL_RXQX_CTRL);
DUMP_REG(DMA_CH[0].DMA_CHX_CTRL);
DUMP_REG(DMA_CH[0].DMA_CHX_TX_CTRL);
DUMP_REG(DMA_CH[0].DMA_CHX_RX_CTRL);
DUMP_REG(DMA_CH[0].DMA_CHX_TXDESC_LIST_ADDR);
DUMP_REG(DMA_CH[0].DMA_CHX_RXDESC_LIST_ADDR);
DUMP_REG(DMA_CH[0].DMA_CHX_TXDESC_TAIL_PTR);
DUMP_REG(DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR);
DUMP_REG(DMA_CH[0].DMA_CHX_TXDESC_RING_LENGTH);
DUMP_REG(DMA_CH[0].DMA_CHX_RXDESC_RING_LENGTH);
DUMP_REG(DMA_CH[0].DMA_CHX_INT_EN);
DUMP_REG(DMA_CH[0].DMA_CHX_RX_INT_WDTIMER);
DUMP_REG(DMA_CH[0].DMA_CHX_SLOT_FUNC_CTRL_STAT);
DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_TXDESC);
DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_RXDESC);
DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_TXBUF);
DUMP_REG(DMA_CH[0].DMA_CHX_CUR_HST_RXBUF);
DUMP_REG(DMA_CH[0].DMA_CHX_STAT);
DUMP_REG(DMA_CH[1].DMA_CHX_CTRL);
DUMP_REG(DMA_CH[1].DMA_CHX_TX_CTRL);
DUMP_REG(DMA_CH[1].DMA_CHX_RX_CTRL);
DUMP_REG(DMA_CH[1].DMA_CHX_TXDESC_LIST_ADDR);
DUMP_REG(DMA_CH[1].DMA_CHX_RXDESC_LIST_ADDR);
DUMP_REG(DMA_CH[1].DMA_CHX_TXDESC_TAIL_PTR);
DUMP_REG(DMA_CH[1].DMA_CHX_RXDESC_TAIL_PTR);
DUMP_REG(DMA_CH[1].DMA_CHX_TXDESC_RING_LENGTH);
DUMP_REG(DMA_CH[1].DMA_CHX_RXDESC_RING_LENGTH);
DUMP_REG(DMA_CH[1].DMA_CHX_INT_EN);
DUMP_REG(DMA_CH[1].DMA_CHX_RX_INT_WDTIMER);
DUMP_REG(DMA_CH[1].DMA_CHX_SLOT_FUNC_CTRL_STAT);
DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_TXDESC);
DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_RXDESC);
DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_TXBUF);
DUMP_REG(DMA_CH[1].DMA_CHX_CUR_HST_RXBUF);
DUMP_REG(DMA_CH[1].DMA_CHX_STAT);
}
void emac_bd_dump(void)
{
int i;
rt_kprintf("rx bd dump: \n");
for (i = 0; i < ENET_RXBD_NUM; i++)
{
enet_rx_bd_struct_t * rx_bd = get_rx_desc(i);
rt_kprintf("buf1: %p, buf2: %p, ctrl: %08x\n",
rx_bd->buff1Addr,
rx_bd->buff2Addr,
rx_bd->control);
}
rt_kprintf("tx bd dump: \n");
for (i = 0; i < ENET_TXBD_NUM; i++)
{
enet_tx_bd_struct_t * tx_bd = get_tx_desc(i);
rt_kprintf("buf1: %p, buf2: %p, len: %08x, ctrl: %08x\n",
tx_bd->buff1Addr,
tx_bd->buff2Addr,
tx_bd->buffLen,
tx_bd->controlStat);
}
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(emac_stat, dump emac stat data);
FINSH_FUNCTION_EXPORT(phy_dump, dump phy registers);
FINSH_FUNCTION_EXPORT(emac_dump, dump emac registers);
FINSH_FUNCTION_EXPORT(emac_bd_dump, dump emac tx and rx descriptor);
#endif