| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- /*
- * Copyright (c) 2006-2024, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2024/04/25 flyingcys first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include "board.h"
- #define DBG_TAG "drv.eth"
- #define DBG_LEVEL DBG_INFO
- #include <rtdbg.h>
- #include <lwip/sys.h>
- #include <netif/ethernetif.h>
- #include "drv_eth.h"
- // #define ETH_TX_DUMP
- // #define ETH_RX_DUMP
- #define MAX_ADDR_LEN 6
- #define DETECT_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 2
- #define DETECT_THREAD_STACK_SIZE 4096
- struct _dw_eth
- {
- rt_ubase_t base;
- rt_uint32_t irq;
- struct eth_device parent; /* inherit from ethernet device */
- rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* interface address info, hw address */
- struct rt_semaphore rx_sem;
- };
- static struct _dw_eth dw_eth_device = {0};
- #define GMAC_BUF_LEN (1500 + 20)
- static uint8_t g_mac_addr[6] = {0xf2, 0x42, 0x9f, 0xa5, 0x0a, 0x72};
- static uint8_t g_mac_phy_init_finish = 0;
- static eth_mac_handle_t g_mac_handle;
- static eth_phy_handle_t g_phy_handle;
- static uint8_t SendDataBuf[GMAC_BUF_LEN];
- static uint8_t RecvDataBuf[GMAC_BUF_LEN];
- static void cvi_ephy_id_init(void)
- {
- // set rg_ephy_apb_rw_sel 0x0804@[0]=1/APB by using APB interface
- mmio_write_32(ETH_PHY_BASE + 0x804, 0x0001);
- // Release 0x0800[0]=0/shutdown
- mmio_write_32(ETH_PHY_BASE + 0x800, 0x0900);
- // Release 0x0800[2]=1/dig_rst_n, Let mii_reg can be accessabile
- mmio_write_32(ETH_PHY_BASE + 0x800, 0x0904);
- // PHY_ID
- mmio_write_32(ETH_PHY_BASE + 0x008, 0x0043);
- mmio_write_32(ETH_PHY_BASE + 0x00c, 0x5649);
- // switch to MDIO control by ETH_MAC
- mmio_write_32(ETH_PHY_BASE + 0x804, 0x0000);
- }
- static int cvi_eth_mac_phy_enable(uint32_t enable)
- {
- eth_mac_addr_t addr;
- int32_t ret;
- if ((g_mac_phy_init_finish == 0) && enable)
- {
- /* startup mac */
- ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONFIGURE, 1);
- if (ret != 0)
- {
- LOG_E("Failed to control mac");
- return -1;
- }
- /* Start up the PHY */
- ret = cvi_eth_phy_power_control(g_phy_handle, CSI_ETH_POWER_FULL);
- if (ret != 0)
- {
- LOG_E("Failed to control phy, ret:0x%d", ret);
- return -1;
- }
- }
- /* enable mac TX/RX */
- ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONTROL_TX, enable ? 1 : 0);
- if (ret != 0)
- {
- LOG_E("Failed to enable mac TX");
- return ret;
- }
- ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONTROL_RX, enable ? 1 : 0);
- if (ret != 0)
- {
- LOG_E("Failed to enable mac RX");
- return ret;
- }
- /* set mac address */
- rt_memcpy(addr.b, g_mac_addr, sizeof(g_mac_addr));
- ret = cvi_eth_mac_set_macaddr(g_mac_handle, &addr);
- if (ret != 0)
- {
- LOG_E("Failed to set mac address");
- return -1;
- }
- /* adjust mac link parameter */
- ret = cvi_eth_mac_control(g_mac_handle, DRV_ETH_MAC_ADJUST_LINK, 1);
- if (ret != 0)
- {
- LOG_E("Failed to adjust link");
- return -1;
- }
- return 0;
- }
- static int32_t fn_phy_read(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
- {
- return dw_eth_mac_phy_read(g_mac_handle, phy_addr, reg_addr, data);
- }
- static int32_t fn_phy_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
- {
- return dw_eth_mac_phy_write(g_mac_handle, phy_addr, reg_addr, data);
- }
- static void dw_gmac_handler_irq(int vector, void *param)
- {
- gmac_dev_t *mac_dev = (gmac_dev_t *)param;
- struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
- uint32_t dma_status;
- uint32_t event = 0;
- /* no ephy or ephy link down */
- if (!mac_dev->phy_dev || !mac_dev->phy_dev->link_state)
- return;
- /* read and clear dma interrupt */
- dma_status = dma_reg->status;
- /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
- dma_reg->status = dma_status & 0x1ffff;
- if (dma_status & CVI_DMA_STATUS_RI)
- {
- LOG_D("CVI_DMA_STATUS_RI");
- /* a frame has been received */
- eth_device_ready(&(dw_eth_device.parent));
- }
- if (dma_status & CVI_DMA_STATUS_TI)
- {
- LOG_D("CVI_DMA_STATUS_TI");
- }
- if (dma_status & CVI_DMA_STATUS_ERI)
- {
- LOG_D("CVI_DMA_STATUS_TI");
- }
- }
- static void phy_link_detect(void *param)
- {
- int link_status = -1;
- int link_status_old = -1;
- int ret = -1;
- while (1)
- {
- link_status = eth_phy_update_link(g_phy_handle);
- LOG_D("eth link status: %d", link_status);
- if (link_status_old != link_status)
- {
- if (link_status == 0)
- {
- LOG_I("eth link up");
- eth_device_linkchange(&(dw_eth_device.parent), RT_TRUE);
- }
- else
- {
- LOG_I("eth link down");
- eth_device_linkchange(&(dw_eth_device.parent), RT_FALSE);
- }
- link_status_old = link_status;
- }
- rt_thread_delay(RT_TICK_PER_SECOND);
- }
- }
- static rt_err_t rt_dw_eth_init(rt_device_t dev)
- {
- struct _dw_eth *dw_eth;
- struct eth_device *eth_dev;
- RT_ASSERT(dev != RT_NULL);
- eth_dev = rt_container_of(dev, struct eth_device, parent);
- if (eth_dev == RT_NULL)
- return -RT_ERROR;
- dw_eth = rt_container_of(eth_dev, struct _dw_eth, parent);
- if (dw_eth == RT_NULL)
- return -RT_ERROR;
- /* init phy id */
- cvi_ephy_id_init();
- /* initialize MAC & PHY */
- g_mac_handle = cvi_eth_mac_init(dw_eth->base);
- if (g_mac_handle == NULL)
- return -RT_ERROR;
- g_phy_handle = cvi_eth_phy_init(fn_phy_read, fn_phy_write);
- dw_eth_mac_connect_phy(g_mac_handle, g_phy_handle);
- if (cvi_eth_mac_phy_enable(1))
- {
- LOG_E("PHY MAC init fail");
- return -RT_ERROR;
- }
- rt_hw_interrupt_install(dw_eth->irq, dw_gmac_handler_irq, g_mac_handle, "e0");
- rt_hw_interrupt_umask(dw_eth->irq);
- LOG_D("PHY MAC init success");
- rt_thread_t link_detect;
- link_detect = rt_thread_create("link_detect",
- phy_link_detect,
- (void *)&dw_eth_device,
- DETECT_THREAD_STACK_SIZE,
- DETECT_THREAD_PRIORITY,
- 2);
- if (link_detect != RT_NULL)
- {
- rt_thread_startup(link_detect);
- }
- else
- {
- return -RT_ERROR;
- }
- return RT_EOK;
- }
- static rt_err_t rt_dw_eth_control(rt_device_t dev, int cmd, void *args)
- {
- switch (cmd)
- {
- case NIOCTL_GADDR:
- if (args)
- rt_memcpy(args, g_mac_addr, MAX_ADDR_LEN);
- break;
- default:
- break;
- }
- return RT_EOK;
- }
- #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");
- }
- #endif
- struct pbuf* rt_dw_eth_rx(rt_device_t dev)
- {
- struct pbuf *p = NULL;
- struct pbuf *q = NULL;
- uint32_t i = 0;
- int32_t len = cvi_eth_mac_read_frame(g_mac_handle, RecvDataBuf, GMAC_BUF_LEN);
- if ((len <= 0) || (len > GMAC_BUF_LEN))
- {
- return NULL;
- }
- #if RT_LWIP_ETH_PAD_SIZE
- len += RT_LWIP_ETH_PAD_SIZE; /* allow room for Ethernet padding */
- #endif
- p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
- if (p == NULL)
- {
- LOG_E("eth_rx: pbuf_alloc failed");
- len = 0;
- return NULL;
- }
- #if RT_LWIP_ETH_PAD_SIZE
- pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
- #endif
- /* We iterate over the pbuf chain until we have read the entire
- * packet into the pbuf. */
- for (q = p; q != NULL; q = q->next)
- {
- /* Read enough bytes to fill this pbuf in the chain. The
- * available data in the pbuf is given by the q->len
- * variable.
- * This does not necessarily have to be a memcpy, you can also preallocate
- * pbufs for a DMA-enabled MAC and after receiving truncate it to the
- * actually received size. In this case, ensure the tot_len member of the
- * pbuf is the sum of the chained pbuf len members.
- */
- rt_memcpy((u8_t*)q->payload, (u8_t*)&RecvDataBuf[i], q->len);
- i = i + q->len;
- }
- if ((i != p->tot_len) || (i > len))
- {
- return NULL;
- }
- #ifdef ETH_RX_DUMP
- packet_dump("RX dump", p);
- #endif /* ETH_RX_DUMP */
- return p;
- }
- rt_err_t rt_dw_eth_tx(rt_device_t dev, struct pbuf* p)
- {
- rt_err_t ret = RT_EOK;
- #ifdef ETH_TX_DUMP
- packet_dump("send", p);
- #endif
- struct pbuf *q;
- uint32_t len = 0;
- #if RT_LWIP_ETH_PAD_SIZE
- pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
- #endif
- for (q = p; q != NULL; q = q->next)
- {
- /* Send the data from the pbuf to the interface, one pbuf at a
- time. The size of the data in each pbuf is kept in the ->len
- variable. */
- MEMCPY((uint8_t *)&SendDataBuf[len], (uint8_t *)q->payload, q->len);
- len = len + q->len;
- if ((len > GMAC_BUF_LEN) || (len > p->tot_len))
- {
- LOG_E("rt_dw_eth_tx: error, len=%d, tot_len=%d", len, p->tot_len);
- return -RT_ERROR;
- }
- }
- if (len == p->tot_len)
- {
- if (cvi_eth_mac_send_frame(g_mac_handle, SendDataBuf, len) < 0)
- ret = -RT_ERROR;
- }
- else
- ret = -RT_ERROR;
- #if RT_LWIP_ETH_PAD_SIZE
- pbuf_header(p, RT_LWIP_ETH_PAD_SIZE); /* reclaim the padding word */
- #endif
- return ret;
- }
- const static struct rt_device_ops dw_eth_ops =
- {
- rt_dw_eth_init,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- rt_dw_eth_control
- };
- static int rthw_eth_init(void)
- {
- rt_err_t ret = RT_EOK;
- dw_eth_device.base = (rt_ubase_t)DW_MAC_BASE;
- dw_eth_device.irq = DW_MAC_IRQ;
- dw_eth_device.parent.parent.ops = &dw_eth_ops;
- dw_eth_device.parent.eth_rx = rt_dw_eth_rx;
- dw_eth_device.parent.eth_tx = rt_dw_eth_tx;
- ret = rt_sem_init(&dw_eth_device.rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
- if (ret != RT_EOK)
- {
- LOG_E("rt_sem_init failed: %d", ret);
- return ret;
- }
- ret = eth_device_init(&dw_eth_device.parent, "e0");
- if (ret != RT_EOK)
- {
- LOG_E("eth_device_init failed: %d", ret);
- return ret;
- }
- return RT_EOK;
- }
- INIT_DEVICE_EXPORT(rthw_eth_init);
|