diff --git a/bsp/lpc54608-LPCXpresso/drivers/drv_emac.c b/bsp/lpc54608-LPCXpresso/drivers/drv_emac.c index ffa4dafa12dea8b11787f814d80799a954c58c34..639a59f2e5534666496a50fcdf1b61609177ad78 100644 --- a/bsp/lpc54608-LPCXpresso/drivers/drv_emac.c +++ b/bsp/lpc54608-LPCXpresso/drivers/drv_emac.c @@ -22,6 +22,7 @@ */ #include + #include "lwipopts.h" #include #include @@ -32,6 +33,16 @@ #include "fsl_sctimer.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_FUNC0 0x00u /*!< Selects pin function 0 */ @@ -60,388 +71,313 @@ #define PORT2_IDX 2u /*!< 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 EMAC_PHY_10MBIT 1 -#define EMAC_PHY_100MBIT 2 - -#define MAX_ADDR_LEN 6 +#define ENET_ALIGN(x) \ + ((unsigned int)((x) + ((ENET_BUFF_ALIGNMENT)-1)) & (unsigned int)(~(unsigned int)((ENET_BUFF_ALIGNMENT)-1))) -/* 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) +#define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN) +#define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN) struct lpc_emac { /* inherit from ethernet device */ struct eth_device parent; - - rt_uint8_t phy_mode; - + struct rt_semaphore tx_wait; + + ENET_Type *base; + enet_handle_t handle; + /* interface address info. */ 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 rt_semaphore sem_lock; -static struct rt_event tx_event; -#if defined(__GNUC__) -#ifndef __ALIGN_END -#define __ALIGN_END __attribute__((aligned(ENET_BUFF_ALIGNMENT))) -#endif -#ifndef __ALIGN_BEGIN -#define __ALIGN_BEGIN -#endif -#else -#ifndef __ALIGN_END -#define __ALIGN_END -#endif -#ifndef __ALIGN_BEGIN -#if defined(__CC_ARM) -#define __ALIGN_BEGIN __align(ENET_BUFF_ALIGNMENT) -#elif defined(__ICCARM__) -#define __ALIGN_BEGIN -#endif -#endif +#ifdef ETH_STATISTICS +static uint32_t isr_rx_counter = 0; +static uint32_t isr_tx_counter = 0; #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 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)]); +} -static uint8_t *ENET_RXRead(int32_t *length) +#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP) +static void packet_dump(const char * msg, const struct pbuf* p) { - uint32_t control; - uint8_t *data; - *length = 0; + const struct pbuf* q; + rt_uint32_t i,j; + rt_uint8_t *ptr; + + rt_kprintf("%s %d byte\n", msg, p->tot_len); - /* Get the Frame size */ - control = ENET_GetRxDescriptor(&g_rxBuffDescrip[g_rxGenIdx]); - if (!(control & ENET_RXDESCRIP_RD_OWN_MASK)) + i=0; + for(q=p; q != RT_NULL; q= q->next) { - if (control & ENET_RXDESCRIP_WR_LD_MASK) + ptr = q->payload; + + for(j=0; jlen; j++) { - /* if no error */ - if (control & ENET_RXDESCRIP_WR_ERRSUM_MASK) + if( (i%8) == 0 ) { - *length = -1; + rt_kprintf(" "); } - else + if( (i%16) == 0 ) { - *length = control & ENET_RXDESCRIP_WR_PACKETLEN_MASK; - data = (uint8_t *)g_rxbuffer[g_rxGenIdx]; + rt_kprintf("\r\n"); } - g_rxGenIdx = (g_rxGenIdx + 1) % ENET_RXBD_NUM; - } - } - return data; -} + rt_kprintf("%02x ",*ptr); -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; + i++; + ptr++; + } } - g_rxCosumIdx = (g_rxCosumIdx + 1) % ENET_RXBD_NUM; + rt_kprintf("\n\n"); } +#else +#define packet_dump(...) +#endif /* dump */ - -static status_t ENET_TXQueue(uint8_t *data, uint16_t length) +static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, uint8_t channel, void *param) { - 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) + switch (event) { - txdescTailAddr = (uint32_t)&g_txBuffDescrip[ENET_TXBD_NUM]; + case kENET_RxIntEvent: +#ifdef ETH_STATISTICS + isr_rx_counter++; +#endif + /* a frame has been received */ + eth_device_ready(&(lpc_emac_device.parent)); + break; + case kENET_TxIntEvent: +#ifdef ETH_STATISTICS + isr_tx_counter++; +#endif + /* set event */ + rt_sem_release(&lpc_emac_device.tx_wait); + break; + default: + break; } - ENET_UpdateTxDescriptorTail(ENET, 0, txdescTailAddr); - return kStatus_Success; } -static void ENET_TXReclaim() +static void lcp_emac_io_init(void) { - 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; - } + const uint32_t port0_pin17_config = ( + IOCON_PIO_FUNC7 | /* Pin is configured as ENET_TXD1 */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT0_IDX, PIN17_IDX, port0_pin17_config); /* PORT0 PIN17 (coords: E14) is configured as ENET_TXD1 */ + const uint32_t port2_pin26_config = ( + IOCON_PIO_FUNC0 | /* Pin is configured as PIO2_26 */ + IOCON_PIO_MODE_PULLUP | /* Selects pull-up function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN26_IDX, port2_pin26_config); /* PORT2 PIN26 (coords: H11) is configured as PIO2_26 */ + const uint32_t port4_pin10_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RX_DV */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN10_IDX, port4_pin10_config); /* PORT4 PIN10 (coords: B9) is configured as ENET_RX_DV */ + const uint32_t port4_pin11_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RXD0 */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN11_IDX, port4_pin11_config); /* PORT4 PIN11 (coords: A9) is configured as ENET_RXD0 */ + const uint32_t port4_pin12_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RXD1 */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN12_IDX, port4_pin12_config); /* PORT4 PIN12 (coords: A6) is configured as ENET_RXD1 */ + const uint32_t port4_pin13_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_TX_EN */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN13_IDX, port4_pin13_config); /* PORT4 PIN13 (coords: B6) is configured as ENET_TX_EN */ + const uint32_t port4_pin14_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RX_CLK */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN14_IDX, port4_pin14_config); /* PORT4 PIN14 (coords: B5) is configured as ENET_RX_CLK */ + const uint32_t port4_pin15_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_MDC */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN15_IDX, port4_pin15_config); /* PORT4 PIN15 (coords: A4) is configured as ENET_MDC */ + const uint32_t port4_pin16_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_MDIO */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ + ); + IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN16_IDX, port4_pin16_config); /* PORT4 PIN16 (coords: C4) is configured as ENET_MDIO */ + const uint32_t port4_pin8_config = ( + IOCON_PIO_FUNC1 | /* Pin is configured as ENET_TXD0 */ + IOCON_PIO_MODE_INACT | /* No addition pin function */ + IOCON_PIO_INV_DI | /* Input function is not inverted */ + IOCON_PIO_DIGITAL_EN | /* Enables digital function */ + IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ + IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ + 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 */ } -void ETHERNET_IRQHandler(void) +static rt_err_t lpc_emac_phy_init(phy_speed_t * speed, phy_duplex_t * duplex) { - /* Check for the interrupt source type. */ - /* DMA CHANNEL 0. */ - uint32_t status; + bool link = false; + int32_t status; - /* enter interrupt */ - rt_interrupt_enter(); + status = PHY_Init(lpc_emac_device.base, lpc_emac_device.phyAddr, 0); + if (status != kStatus_Success) + { + ETH_PRINTF("PHY_Init failed!\n"); + return RT_ERROR; + } - status = ENET_GetDmaInterruptStatus(ENET, 0); - if (status) + /* Wait for link up and get the actual PHY link speed. */ + PHY_GetLinkStatus(lpc_emac_device.base, lpc_emac_device.phyAddr, &link); + while (!link) { - if (status & kENET_DmaRx) - { - /* a frame has been received */ - eth_device_ready(&(lpc_emac_device.parent)); - } - if (status & kENET_DmaTx) + uint32_t timedelay; + ETH_PRINTF("PHY Wait for link up!\n"); + for (timedelay = 0; timedelay < 0xFFFFFU; timedelay++) { - /* set event */ - rt_event_send(&tx_event, 0x01); + __ASM("nop"); } - - /* Clear the interrupt. */ - ENET_ClearDmaInterruptStatus(ENET, 0, status); + PHY_GetLinkStatus(lpc_emac_device.base, lpc_emac_device.phyAddr, &link); } - - /* leave interrupt */ - rt_interrupt_leave(); + + 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) { - int32_t status, index; - void *buff; + int i; 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_buffer_config_t buffCfg; + uint32_t rxBufferStartAddr[ENET_RXBD_NUM]; + + lcp_emac_io_init(); + + if (lpc_emac_phy_init(&speed, &duplex) != RT_EOK) { - 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 = ( - IOCON_PIO_FUNC7 | /* Pin is configured as ENET_TXD1 */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT0_IDX, PIN17_IDX, port0_pin17_config); /* PORT0 PIN17 (coords: E14) is configured as ENET_TXD1 */ - const uint32_t port2_pin26_config = ( - IOCON_PIO_FUNC0 | /* Pin is configured as PIO2_26 */ - IOCON_PIO_MODE_PULLUP | /* Selects pull-up function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT2_IDX, PIN26_IDX, port2_pin26_config); /* PORT2 PIN26 (coords: H11) is configured as PIO2_26 */ - const uint32_t port4_pin10_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RX_DV */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN10_IDX, port4_pin10_config); /* PORT4 PIN10 (coords: B9) is configured as ENET_RX_DV */ - const uint32_t port4_pin11_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RXD0 */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN11_IDX, port4_pin11_config); /* PORT4 PIN11 (coords: A9) is configured as ENET_RXD0 */ - const uint32_t port4_pin12_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RXD1 */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN12_IDX, port4_pin12_config); /* PORT4 PIN12 (coords: A6) is configured as ENET_RXD1 */ - const uint32_t port4_pin13_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_TX_EN */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN13_IDX, port4_pin13_config); /* PORT4 PIN13 (coords: B6) is configured as ENET_TX_EN */ - const uint32_t port4_pin14_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_RX_CLK */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN14_IDX, port4_pin14_config); /* PORT4 PIN14 (coords: B5) is configured as ENET_RX_CLK */ - const uint32_t port4_pin15_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_MDC */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN15_IDX, port4_pin15_config); /* PORT4 PIN15 (coords: A4) is configured as ENET_MDC */ - const uint32_t port4_pin16_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_MDIO */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - IOCON_PIO_OPENDRAIN_DI /* Open drain is disabled */ - ); - IOCON_PinMuxSet(IOCON, PORT4_IDX, PIN16_IDX, port4_pin16_config); /* PORT4 PIN16 (coords: C4) is configured as ENET_MDIO */ - const uint32_t port4_pin8_config = ( - IOCON_PIO_FUNC1 | /* Pin is configured as ENET_TXD0 */ - IOCON_PIO_MODE_INACT | /* No addition pin function */ - IOCON_PIO_INV_DI | /* Input function is not inverted */ - IOCON_PIO_DIGITAL_EN | /* Enables digital function */ - IOCON_PIO_INPFILT_OFF | /* Input filter disabled */ - IOCON_PIO_SLEW_STANDARD | /* Standard mode, output slew rate control is enabled */ - 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 */ - } - - status = PHY_Init(ENET, PHY_ADDR, 0); - if (status == kStatus_Success) - { - PHY_GetLinkSpeedDuplex(ENET, PHY_ADDR, &speed, &duplex); - /* 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; } - /* Wait for link up and get the actual PHY link speed. */ - PHY_GetLinkStatus(ENET, PHY_ADDR, &link); - while (!link) + /* calculate start addresses of all rx buffers */ + for (i = 0; i < ENET_RXBD_NUM; i++) { - rt_kprintf("PHY Wait for link up!\n"); - for (timedelay = 0; timedelay < 0xFFFFFU; timedelay++) - { - __ASM("nop"); - } - PHY_GetLinkStatus(ENET, PHY_ADDR, &link); + 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. */ 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; + + ETH_PRINTF("Auto negotiation, Speed: "); + 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 ENET. */ - ENET_Init(ENET, &config, &lpc_emac_device.dev_addr[0], refClock); + /* 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. */ - ENET_EnableInterrupts(ENET, (kENET_DmaTx | kENET_DmaRx)); - EnableIRQ(ETHERNET_IRQn); - + ENET_EnableInterrupts(lpc_emac_device.base, (kENET_DmaTx | kENET_DmaRx)); + ENET_CreateHandler(lpc_emac_device.base, &lpc_emac_device.handle, &config, &buffCfg, ethernet_callback, NULL); + /* Initialize Descriptor. */ - ENET_DescriptorInit(ENET, &config, &buffConfig); - + ENET_DescriptorInit(lpc_emac_device.base, &config, &buffCfg); + /* 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; } @@ -489,39 +425,47 @@ static rt_err_t lpc_emac_control(rt_device_t dev, int cmd, void *args) /* transmit packet. */ rt_err_t lpc_emac_tx(rt_device_t dev, struct pbuf *p) { - rt_uint8_t *buffer; - rt_err_t result; - rt_uint32_t recved; - - /* lock EMAC device */ - rt_sem_take(&sem_lock, RT_WAITING_FOREVER); + 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; - /* 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(); + RT_ASSERT(p != NULL); + RT_ASSERT(enet_handle != RT_NULL); - /* Create the buffer for zero-copy transmit. */ - buffer = (uint8_t *)malloc(p->tot_len); - if (buffer) + if (p->tot_len > ENET_TXBUFF_SIZE) { - /* copy data to tx buffer */ - pbuf_copy_partial(p, buffer, p->tot_len, 0); - - while ((g_txbuffIdx + 1) % ENET_TXBD_NUM == g_txCosumIdx) + return RT_ERROR; + } + + packet_dump("TX dump", p); + + /* get free tx buffer */ + { + rt_err_t result; + result = rt_sem_take(&lpc_emac_device.tx_wait, RT_TICK_PER_SECOND/10); + if (result != RT_EOK) { - rt_thread_delay(RT_TICK_PER_SECOND / 20); // 50 ms + return RT_ERROR; } - - /* Store the buffer for mem free. */ - g_txbuff[g_txbuffIdx] = buffer; - g_txbuffIdx = (g_txbuffIdx + 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 */ - rt_sem_release(&sem_lock); + + data = (uint8_t *)ENET_ALIGN(&lpc_emac_device.RxDataBuff[lpc_emac_device.txIdx * ENET_ALIGN(ENET_RXBUFF_SIZE)]); + pbuf_copy_partial(p, data, p->tot_len, 0); + lpc_emac_device.txIdx = (lpc_emac_device.txIdx + 1) / ENET_TXBD_NUM; + + result = ENET_SendFrame(enet_base, enet_handle, data, p->len); + + 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; } @@ -529,61 +473,59 @@ rt_err_t lpc_emac_tx(rt_device_t dev, struct pbuf *p) /* reception packet. */ struct pbuf *lpc_emac_rx(rt_device_t dev) { - struct pbuf *p; - uint8_t *data; - int length; - - /* init p pointer */ - p = RT_NULL; - - /* lock EMAC device */ - rt_sem_take(&sem_lock, RT_WAITING_FOREVER); - - length = 0; - data = ENET_RXRead(&length); - if (length > 0) - { - void *buffer; - /* Update the buffers and then we can delivery the previous buffer diectly to - the application without memcpy. */ - buffer = rt_malloc(ENET_FRAME_MAX_FRAMELEN); - if (buffer) + uint32_t length = 0; + status_t status; + + struct pbuf* p = RT_NULL; + enet_handle_t * enet_handle = &lpc_emac_device.handle; + ENET_Type *enet_base = lpc_emac_device.base; + + /* Get the Frame size */ + status = ENET_GetRxFrameSize(enet_base, enet_handle, &length, 0); + + /* Call ENET_ReadFrame when there is a received frame. */ + if (length != 0) + { + /* Received valid frame. Deliver the rx buffer with the size equal to length. */ + p = pbuf_alloc(PBUF_RAW, length, PBUF_POOL); + + if (p != NULL) { - 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 + { + ETH_PRINTF(" A frame read failed\n"); + pbuf_free(p); + } } else { - ENET_RXClaim(NULL); + ETH_PRINTF(" pbuf_alloc faild\n"); } - - /* Do what you want to do with the data and then free the used one. */ - p = pbuf_alloc(PBUF_LINK, length, PBUF_RAM); - if (p != RT_NULL) - { - rt_memcpy(p->payload, data, length); - p->tot_len = length; - } - rt_free(data); - } - else if (length < 0) - { - ENET_RXClaim(NULL); - } - - /* unlock EMAC device */ - rt_sem_release(&sem_lock); - - return p; + } + else if (status == kStatus_ENET_RxFrameError) + { + ETH_PRINTF("ENET_GetRxFrameSize: kStatus_ENET_RxFrameError\n"); + ENET_ReadFrame(enet_base, enet_handle, NULL, 0, 0); + } + + return NULL; } int lpc_emac_hw_init(void) { - rt_event_init(&tx_event, "tx_event", RT_IPC_FLAG_FIFO); - rt_sem_init(&sem_lock, "eth_lock", 1, RT_IPC_FLAG_FIFO); - - /* set autonegotiation mode */ - lpc_emac_device.phy_mode = EMAC_PHY_AUTO; - + /* init tx semaphore */ + rt_sem_init(&lpc_emac_device.tx_wait, "tx_wait", ENET_TXBD_NUM, RT_IPC_FLAG_FIFO); + + lpc_emac_device.phyAddr = 0; + lpc_emac_device.txIdx = 0; + lpc_emac_device.base = ENET; + // OUI 00-60-37 NXP Semiconductors lpc_emac_device.dev_addr[0] = 0x00; lpc_emac_device.dev_addr[1] = 0x60; @@ -605,6 +547,198 @@ int lpc_emac_hw_init(void) lpc_emac_device.parent.eth_tx = lpc_emac_tx; eth_device_init(&(lpc_emac_device.parent), "e0"); + return 0; } 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, ®); + + 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_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