123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- /*
- * COPYRIGHT (C) 2018, Real-Thread Information Technology Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2015-07-15 Bernard The first version
- */
- #include <board.h>
- #include <rtthread.h>
- #include "drv_emac.h"
- #if defined(RT_USING_LWIP)
- #include <finsh.h>
- #include <stdint.h>
- #include <netif/ethernetif.h>
- #include <lwip/opt.h>
- #include "MK64F12.h"
- #include "fsl_port.h"
- #include "fsl_enet.h"
- #include "fsl_phy.h"
- //#define DRV_EMAC_DEBUG
- //#define DRV_EMAC_RX_DUMP
- //#define DRV_EMAC_TX_DUMP
- #ifdef DRV_EMAC_DEBUG
- #define DEBUG_PRINTF(...) rt_kprintf(__VA_ARGS__)
- #else
- #define DEBUG_PRINTF(...)
- #endif
- #define MAX_ADDR_LEN 6
- #define ENET_RX_RING_LEN (16)
- #define ENET_TX_RING_LEN (8)
- #define K64_EMAC_DEVICE(eth) (struct emac_device*)(eth)
- #define ENET_ALIGN(x) \
- ((unsigned int)((x) + ((ENET_BUFF_ALIGNMENT)-1)) & (unsigned int)(~(unsigned int)((ENET_BUFF_ALIGNMENT)-1)))
- #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
- #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
- #define ENET_ETH_MAX_FLEN (1522) // recommended size for a VLAN frame
- struct emac_device
- {
- /* inherit from Ethernet device */
- struct eth_device parent;
- rt_align(64) enet_rx_bd_struct_t RxBuffDescrip[ENET_RX_RING_LEN];
- rt_align(64) enet_tx_bd_struct_t TxBuffDescrip[ENET_TX_RING_LEN];
- rt_align(64) uint8_t RxDataBuff[ENET_RX_RING_LEN * ENET_ALIGN(ENET_RXBUFF_SIZE)];
- rt_align(64) uint8_t TxDataBuff[ENET_TX_RING_LEN * ENET_ALIGN(ENET_TXBUFF_SIZE)];
- enet_handle_t enet_handle;
- rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* MAC address */
- struct rt_semaphore tx_wait;
- };
- static struct emac_device _emac;
- static void setup_k64_io_enet(void)
- {
- port_pin_config_t configENET = {0};
- #ifndef FEATURE_UVISOR
- /* Disable MPU only when uVisor is not around. */
- SYSMPU->CESR &= ~SYSMPU_CESR_VLD_MASK;
- #endif/*FEATURE_UVISOR*/
- /* Affects PORTC_PCR16 register */
- PORT_SetPinMux(PORTC, 16u, kPORT_MuxAlt4);
- /* Affects PORTC_PCR17 register */
- PORT_SetPinMux(PORTC, 17u, kPORT_MuxAlt4);
- /* Affects PORTC_PCR18 register */
- PORT_SetPinMux(PORTC, 18u, kPORT_MuxAlt4);
- /* Affects PORTC_PCR19 register */
- PORT_SetPinMux(PORTC, 19u, kPORT_MuxAlt4);
- /* Affects PORTB_PCR1 register */
- PORT_SetPinMux(PORTB, 1u, kPORT_MuxAlt4);
- configENET.openDrainEnable = kPORT_OpenDrainEnable;
- configENET.mux = kPORT_MuxAlt4;
- configENET.pullSelect = kPORT_PullUp;
- /* Ungate the port clock */
- CLOCK_EnableClock(kCLOCK_PortA);
- /* Affects PORTB_PCR0 register */
- PORT_SetPinConfig(PORTB, 0u, &configENET);
- /* Affects PORTA_PCR13 register */
- PORT_SetPinMux(PORTA, 13u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR12 register */
- PORT_SetPinMux(PORTA, 12u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR14 register */
- PORT_SetPinMux(PORTA, 14u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR5 register */
- PORT_SetPinMux(PORTA, 5u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR16 register */
- PORT_SetPinMux(PORTA, 16u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR17 register */
- PORT_SetPinMux(PORTA, 17u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR15 register */
- PORT_SetPinMux(PORTA, 15u, kPORT_MuxAlt4);
- /* Affects PORTA_PCR28 register */
- PORT_SetPinMux(PORTA, 28u, kPORT_MuxAlt4);
- }
- static void setup_enet_clock_init(void)
- {
- CLOCK_EnableClock(kCLOCK_PortC);
- CLOCK_EnableClock(kCLOCK_PortB);
- /* Select the Ethernet timestamp clock source */
- CLOCK_SetEnetTime0Clock(0x2);
- }
- static void enet_mac_rx_isr(struct emac_device* emac)
- {
- rt_err_t result;
- result = eth_device_ready(&(_emac.parent));
- if( result != RT_EOK )
- {
- DEBUG_PRINTF("RX err =%d\n", result );
- }
- }
- static void enet_mac_tx_isr(struct emac_device* emac)
- {
- rt_sem_release(&emac->tx_wait);
- }
- static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param)
- {
- struct emac_device* emac = param;
- switch (event)
- {
- case kENET_RxEvent:
- enet_mac_rx_isr(emac);
- break;
- case kENET_TxEvent:
- enet_mac_tx_isr(emac);
- break;
- default:
- break;
- }
- }
- static rt_err_t k64_emac_init(rt_device_t dev)
- {
- struct emac_device* emac = K64_EMAC_DEVICE(dev);
- enet_handle_t * enet_handle = &emac->enet_handle;
- bool link = false;
- uint32_t phyAddr = 0;
- phy_speed_t phy_speed;
- phy_duplex_t phy_duplex;
- uint32_t sysClock;
- enet_buffer_config_t buffCfg;
- enet_config_t config;
- /* initialize config according to emac device */
- setup_enet_clock_init();
- /* enable iomux and clock */
- setup_k64_io_enet();
- /* prepare the buffer configuration. */
- buffCfg.rxBdNumber = ENET_RX_RING_LEN; /* Receive buffer descriptor number. */
- buffCfg.txBdNumber = ENET_TX_RING_LEN; /* Transmit buffer descriptor number. */
- buffCfg.rxBuffSizeAlign = ENET_ALIGN(ENET_RXBUFF_SIZE); /* Aligned receive data buffer size. */
- buffCfg.txBuffSizeAlign = ENET_ALIGN(ENET_TXBUFF_SIZE); /* Aligned transmit data buffer size. */
- buffCfg.rxBdStartAddrAlign = emac->RxBuffDescrip; /* Aligned receive buffer descriptor start address. */
- buffCfg.txBdStartAddrAlign = emac->TxBuffDescrip; /* Aligned transmit buffer descriptor start address. */
- buffCfg.rxBufferAlign = emac->RxDataBuff; /* Receive data buffer start address. */
- buffCfg.txBufferAlign = emac->TxDataBuff; /* Transmit data buffer start address. */
- sysClock = CLOCK_GetFreq(kCLOCK_CoreSysClk);
- DEBUG_PRINTF("sysClock: %d\n", sysClock);
- ENET_GetDefaultConfig(&config);
- PHY_Init(ENET, 0, CLOCK_GetFreq(kCLOCK_CoreSysClk));
- if (PHY_GetLinkStatus(ENET, phyAddr, &link) == kStatus_Success)
- {
- if (link)
- {
- DEBUG_PRINTF("phy link up\n");
- /* Get link information from PHY */
- PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
- /* Change the MII speed and duplex for actual link status. */
- config.miiSpeed = (enet_mii_speed_t)phy_speed;
- config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
- config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
- }
- else
- {
- DEBUG_PRINTF("phy link down\n");
- }
- config.rxMaxFrameLen = ENET_ETH_MAX_FLEN;
- config.macSpecialConfig = kENET_ControlFlowControlEnable;
- config.txAccelerConfig = 0;
- config.rxAccelerConfig = kENET_RxAccelMacCheckEnabled;
- ENET_Init(ENET, enet_handle, &config, &buffCfg, emac->dev_addr, sysClock);
- ENET_SetCallback(enet_handle, ethernet_callback, emac);
- ENET_ActiveRead(ENET);
- }
- else
- {
- DEBUG_PRINTF("read phy failed\n");
- }
- return RT_EOK;
- }
- static rt_err_t k64_emac_open(rt_device_t dev, rt_uint16_t oflag)
- {
- return RT_EOK;
- }
- static rt_err_t k64_emac_close(rt_device_t dev)
- {
- return RT_EOK;
- }
- static rt_size_t k64_emac_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
- {
- rt_set_errno(-RT_ENOSYS);
- return 0;
- }
- static rt_size_t k64_emac_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
- {
- rt_set_errno(-RT_ENOSYS);
- return 0;
- }
- static rt_err_t k64_emac_control(rt_device_t dev, int cmd, void *args)
- {
- struct emac_device *emac;
- DEBUG_PRINTF("k64_emac_control\n");
- emac = K64_EMAC_DEVICE(dev);
- RT_ASSERT(emac != RT_NULL);
- switch(cmd)
- {
- case NIOCTL_GADDR:
- /* get MAC address */
- if(args) rt_memcpy(args, emac->dev_addr, 6);
- else return -RT_ERROR;
- break;
- default :
- break;
- }
- return RT_EOK;
- }
- static rt_err_t k64_emac_tx(rt_device_t dev, struct pbuf* p)
- {
- rt_err_t result = RT_EOK;
- struct emac_device *emac = K64_EMAC_DEVICE(dev);
- enet_handle_t * enet_handle = &emac->enet_handle;
- RT_ASSERT(p != NULL);
- DEBUG_PRINTF("k64_emac_tx: %d\n", p->len);
- emac = K64_EMAC_DEVICE(dev);
- RT_ASSERT(emac != RT_NULL);
- #ifdef DRV_EMAC_RX_DUMP
- {
- int i;
- uint8_t * buf;
- buf = (uint8_t *)p->payload;
- for (i = 0; i < p->len; i++)
- {
- DEBUG_PRINTF("%02X ", buf[i]);
- if (i % 16 == 15)
- DEBUG_PRINTF("\n");
- }
- DEBUG_PRINTF("\n");
- }
- #endif
- do
- {
- result = ENET_SendFrame(ENET, enet_handle, p->payload, p->len);
- if (result == kStatus_ENET_TxFrameBusy)
- {
- rt_sem_take(&emac->tx_wait, RT_WAITING_FOREVER);
- }
- } while (result == kStatus_ENET_TxFrameBusy);
- return RT_EOK;
- }
- struct pbuf *k64_emac_rx(rt_device_t dev)
- {
- uint32_t length = 0;
- status_t status;
- enet_data_error_stats_t eErrStatic;
- struct pbuf* p = RT_NULL;
- struct emac_device *emac = K64_EMAC_DEVICE(dev);
- enet_handle_t * enet_handle = &emac->enet_handle;
- RT_ASSERT(emac != RT_NULL);
- DEBUG_PRINTF("k64_emac_rx\n");
- /* Get the Frame size */
- status = ENET_GetRxFrameSize(enet_handle, &length);
- if (status == kStatus_ENET_RxFrameError)
- {
- /* Update the received buffer when error happened. */
- /* Get the error information of the received g_frame. */
- ENET_GetRxErrBeforeReadFrame(enet_handle, &eErrStatic);
- /* update the receive buffer. */
- ENET_ReadFrame(ENET, enet_handle, NULL, 0);
- DEBUG_PRINTF("receive frame faild\n");
- return p;
- }
- /* 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)
- {
- status = ENET_ReadFrame(ENET, enet_handle, p->payload, length);
- if (status == kStatus_Success)
- {
- #ifdef DRV_EMAC_RX_DUMP
- uint8_t *buf;
- int i;
- DEBUG_PRINTF(" A frame received. the length:%d\n", p->len);
- buf = (uint8_t *)p->payload;
- for (i = 0; i < p->len; i++)
- {
- DEBUG_PRINTF("%02X ", buf[i]);
- if (i % 16 == 15)
- DEBUG_PRINTF("\n");
- }
- DEBUG_PRINTF("\n");
- #endif
- }
- else
- {
- DEBUG_PRINTF(" A frame read failed\n");
- pbuf_free(p);
- }
- }
- return p;
- }
- int drv_emac_hw_init(void)
- {
- /* use the test MAC address */
- _emac.dev_addr[0] = 0x00;
- _emac.dev_addr[1] = 0x04;
- _emac.dev_addr[2] = 0x9f;
- _emac.dev_addr[3] = 0xc4;
- _emac.dev_addr[4] = 0x44;
- _emac.dev_addr[5] = 0x22;
- _emac.parent.parent.init = k64_emac_init;
- _emac.parent.parent.open = k64_emac_open;
- _emac.parent.parent.close = k64_emac_close;
- _emac.parent.parent.read = k64_emac_read;
- _emac.parent.parent.write = k64_emac_write;
- _emac.parent.parent.control = k64_emac_control;
- _emac.parent.parent.user_data = RT_NULL;
- _emac.parent.eth_rx = k64_emac_rx;
- _emac.parent.eth_tx = k64_emac_tx;
- /* init tx semaphore */
- rt_sem_init(&_emac.tx_wait, "tx_wait", ENET_TX_RING_LEN - 1, RT_IPC_FLAG_FIFO);
- /* register ETH device */
- eth_device_init(&(_emac.parent), "e0");
- return 0;
- }
- INIT_DEVICE_EXPORT(drv_emac_hw_init);
- #ifdef DRV_EMAC_DEBUG
- long k64_dump_tx_bd(void)
- {
- int i;
- enet_tx_bd_struct_t *txbd = _emac.TxBuffDescrip;
- for (i = 0; i < ENET_RX_RING_LEN; i++)
- {
- DEBUG_PRINTF("status: %04X, length: %04X, data: %08X\n", txbd[i].control, txbd[i].length, (uint32_t)txbd[i].buffer);
- }
- return 0;
- }
- FINSH_FUNCTION_EXPORT(k64_dump_tx_bd, dump all receive buffer descriptor);
- MSH_CMD_EXPORT(k64_dump_tx_bd, dump all receive buffer descriptor);
- long k64_dump_rx_bd(void)
- {
- int i;
- enet_rx_bd_struct_t *rxbd = _emac.RxBuffDescrip;
- for (i = 0; i < ENET_RX_RING_LEN; i++)
- {
- DEBUG_PRINTF("bd:%08X, ", (void *)&rxbd[i]);
- //rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, (void *)&rxbd[i], sizeof(enet_rx_bd_struct_t));
- DEBUG_PRINTF("status:%04X, length:%04X, data:%08X ", rxbd[i].control, rxbd[i].length, (uint32_t)rxbd[i].buffer);
- #ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
- DEBUG_PRINTF("ce:%04X/%04X/%04X ", rxbd[i].controlExtend0, rxbd[i].controlExtend1, rxbd[i].controlExtend2);
- DEBUG_PRINTF("crc:%04X, len:%04X, type:%04X, ts:%04X", rxbd[i].payloadCheckSum, rxbd[i].headerLength, rxbd[i].protocolTyte, rxbd[i].timestamp);
- #endif
- DEBUG_PRINTF("\n");
- }
- return 0;
- }
- FINSH_FUNCTION_EXPORT(k64_dump_rx_bd, dump all receive buffer descriptor);
- MSH_CMD_EXPORT(k64_dump_rx_bd, dump all receive buffer descriptor);
- #endif
- #endif
|