123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- /*
- * Copyright (c) 2021, WangHuachen
- *
- * SPDX-License-Identifier: MIT
- *
- * Change Logs:
- * Date Author Notes
- * 2021-5-10 WangHuachen the first version
- */
- #include "board.h"
- #include <netif/ethernetif.h>
- #include "lwipopts.h"
- #include "lwip/opt.h"
- #include "drv_eth.h"
- #include "lwip/netif.h"
- #include "netif/xadapter.h"
- #include "netif/xemacpsif.h"
- #include "xparameters.h"
- #include "xemacps.h"
- #define DBG_TAG "drv.emac"
- #define DBG_LEVEL DBG_INFO
- #include <rtdbg.h>
- #define MAC_BASE_ADDR XPAR_PSU_ETHERNET_3_BASEADDR
- #define MAX_ADDR_LEN 6
- struct rt_zynqmp_eth
- {
- /* inherit from ethernet device */
- struct eth_device parent;
- /* interface address info, hw address */
- rt_uint8_t dev_addr[MAX_ADDR_LEN];
- struct xemac_s *xemac;
- };
- static struct rt_zynqmp_eth zynqmp_eth_device;
- extern XEmacPs_Config *mac_config;
- extern struct netif *NetIf;
- static void rt_hw_eth_isr(int irqno, void *param)
- {
- struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)param;
- xemacpsif_s *xemacpsif = (xemacpsif_s *)eth_dev->xemac->state;
- XEmacPs_IntrHandler(&xemacpsif->emacps);
- }
- extern enum ethernet_link_status eth_link_status;
- extern u32_t phy_link_detect(XEmacPs *xemacp, u32_t phy_addr);
- extern u32_t phy_autoneg_status(XEmacPs *xemacp, u32_t phy_addr);
- extern u32_t phyaddrforemac;
- void rt_zynqmp_eth_link_detect(struct rt_zynqmp_eth *eth_dev)
- {
- u32_t link_speed, phy_link_status;
- struct xemac_s *xemac = eth_dev->xemac;
- xemacpsif_s *xemacs = (xemacpsif_s *)(xemac->state);
- XEmacPs *xemacp = &xemacs->emacps;
- if ((xemacp->IsReady != (u32)XIL_COMPONENT_IS_READY) ||
- (eth_link_status == ETH_LINK_UNDEFINED))
- return;
- phy_link_status = phy_link_detect(xemacp, phyaddrforemac);
- if ((eth_link_status == ETH_LINK_UP) && (!phy_link_status))
- eth_link_status = ETH_LINK_DOWN;
- switch (eth_link_status) {
- case ETH_LINK_UNDEFINED:
- case ETH_LINK_UP:
- return;
- case ETH_LINK_DOWN:
- eth_device_linkchange(&zynqmp_eth_device.parent, RT_FALSE);
- eth_link_status = ETH_LINK_NEGOTIATING;
- LOG_D("Ethernet Link down");
- break;
- case ETH_LINK_NEGOTIATING:
- if (phy_link_status &&
- phy_autoneg_status(xemacp, phyaddrforemac)) {
- /* Initiate Phy setup to get link speed */
- link_speed = phy_setup_emacps(xemacp,
- phyaddrforemac);
- XEmacPs_SetOperatingSpeed(xemacp, link_speed);
- eth_device_linkchange(&zynqmp_eth_device.parent, RT_TRUE);
- eth_link_status = ETH_LINK_UP;
- LOG_D("Ethernet Link up");
- }
- break;
- }
- }
- static void phy_monitor_thread(void *parameter)
- {
- struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)parameter;
- while (1)
- {
- rt_zynqmp_eth_link_detect(eth_dev);
- rt_thread_delay(RT_TICK_PER_SECOND);
- }
- }
- static rt_err_t rt_zynqmp_eth_init(rt_device_t dev)
- {
- struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
- struct netif *netif = eth_dev->parent.netif;
- struct xemac_s *xemac;
- xemacpsif_s *xemacpsif;
- u32 dmacrreg;
- s32_t status = XST_SUCCESS;
- struct xtopology_t *xtopologyp;
- if (eth_dev->xemac != RT_NULL)
- {
- LOG_W("rt_zynqmp_eth_init: device has been initialized");
- return -RT_ERROR;
- }
- NetIf = netif;
- xemacpsif = rt_malloc(sizeof *xemacpsif);
- if (xemacpsif == NULL)
- {
- LOG_E("rt_zynqmp_eth_init: out of memory");
- return -RT_ENOMEM;
- }
- xemac = rt_malloc(sizeof *xemac);
- if (xemac == NULL)
- {
- LOG_E("rt_zynqmp_eth_init: out of memory");
- return -RT_ENOMEM;
- }
- xemac->state = (void *)xemacpsif;
- xemac->topology_index = xtopology_find_index(MAC_BASE_ADDR);
- xemac->type = xemac_type_emacps;
- xemac->rt_eth_device = ð_dev->parent;
- xemacpsif->send_q = NULL;
- xemacpsif->recv_q = pq_create_queue();
- if (!xemacpsif->recv_q)
- return -RT_ENOMEM;
- eth_dev->xemac = xemac;
- /* obtain config of this emac */
- mac_config = (XEmacPs_Config *)xemacps_lookup_config(MAC_BASE_ADDR);
- status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
- mac_config->BaseAddress);
- if (status != XST_SUCCESS)
- {
- LOG_W("In %s:EmacPs Configuration Failed....", __func__);
- return -RT_ERROR;
- }
- /* initialize the mac */
- init_emacps(xemacpsif, netif);
- dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
- XEMACPS_DMACR_OFFSET);
- dmacrreg = dmacrreg | (0x00000010);
- XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
- XEMACPS_DMACR_OFFSET, dmacrreg);
- setup_isr(xemac);
- init_dma(xemac);
- xtopologyp = &xtopology[xemac->topology_index];
- /*
- * Connect the device driver handler that will be called when an
- * interrupt for the device occurs, the handler defined above performs
- * the specific interrupt processing for the device.
- */
- rt_hw_interrupt_install(xtopologyp->scugic_emac_intr, rt_hw_eth_isr, (void *)eth_dev, "eth");
- /*
- * Enable the interrupt for emacps.
- */
- rt_hw_interrupt_umask(xtopologyp->scugic_emac_intr);
- start_emacps(xemacpsif);
- if (eth_link_status == ETH_LINK_UP)
- eth_device_linkchange(ð_dev->parent, RT_TRUE);
- rt_thread_t tid;
- tid = rt_thread_create("phylnk",
- phy_monitor_thread,
- eth_dev,
- 1024,
- RT_THREAD_PRIORITY_MAX - 2,
- 2);
- if (tid != RT_NULL)
- rt_thread_startup(tid);
- else
- return -RT_ERROR;
- return RT_EOK;
- }
- static rt_err_t rt_zynqmp_eth_open(rt_device_t dev, rt_uint16_t oflag)
- {
- LOG_D("emac open");
- return RT_EOK;
- }
- static rt_err_t rt_zynqmp_eth_close(rt_device_t dev)
- {
- LOG_D("emac close");
- return RT_EOK;
- }
- static rt_size_t rt_zynqmp_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
- {
- LOG_D("emac read");
- rt_set_errno(-RT_ENOSYS);
- return 0;
- }
- static rt_size_t rt_zynqmp_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
- {
- LOG_D("emac write");
- rt_set_errno(-RT_ENOSYS);
- return 0;
- }
- static rt_err_t rt_zynqmp_eth_control(rt_device_t dev, int cmd, void *args)
- {
- struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
- switch (cmd)
- {
- case NIOCTL_GADDR:
- /* get mac address */
- if (args) rt_memcpy(args, eth_dev->dev_addr, 6);
- else return -RT_ERROR;
- break;
- default :
- break;
- }
- return RT_EOK;
- }
- extern err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif, struct pbuf *p);
- rt_err_t rt_zynqmp_eth_tx(rt_device_t dev, struct pbuf *p)
- {
- rt_base_t lev;
- rt_err_t err;
- XEmacPs_BdRing *txring;
- struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
- struct xemac_s *xemac = eth_dev->xemac;
- xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
- lev = rt_hw_interrupt_disable();
- txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
- process_sent_bds(xemacpsif, txring);
- if (is_tx_space_available(xemacpsif))
- {
- _unbuffered_low_level_output(xemacpsif, p);
- err = RT_EOK;
- }
- else
- {
- #if LINK_STATS
- lwip_stats.link.drop++;
- #endif
- LOG_D("pack dropped, no space");
- err = -RT_ENOMEM;
- }
- rt_hw_interrupt_enable(lev);
- return err;
- }
- struct pbuf *rt_zynqmp_eth_rx(rt_device_t dev)
- {
- rt_base_t lev;
- struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
- struct xemac_s *xemac = eth_dev->xemac;
- xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
- struct pbuf *p;
- lev = rt_hw_interrupt_disable();
- /* see if there is data to process */
- if (pq_qlength(xemacpsif->recv_q) == 0)
- return NULL;
- /* return one packet from receive q */
- p = (struct pbuf *)pq_dequeue(xemacpsif->recv_q);
- rt_hw_interrupt_enable(lev);
- return p;
- }
- static int rt_hw_zynqmp_eth_init(void)
- {
- rt_err_t state = RT_EOK;
- zynqmp_eth_device.xemac = RT_NULL;
- zynqmp_eth_device.dev_addr[0] = 0x00;
- zynqmp_eth_device.dev_addr[1] = 0x0A;
- zynqmp_eth_device.dev_addr[2] = 0x35;
- zynqmp_eth_device.dev_addr[3] = 0x00;
- zynqmp_eth_device.dev_addr[4] = 0x01;
- zynqmp_eth_device.dev_addr[5] = 0x02;
- zynqmp_eth_device.parent.parent.init = rt_zynqmp_eth_init;
- zynqmp_eth_device.parent.parent.open = rt_zynqmp_eth_open;
- zynqmp_eth_device.parent.parent.close = rt_zynqmp_eth_close;
- zynqmp_eth_device.parent.parent.read = rt_zynqmp_eth_read;
- zynqmp_eth_device.parent.parent.write = rt_zynqmp_eth_write;
- zynqmp_eth_device.parent.parent.control = rt_zynqmp_eth_control;
- zynqmp_eth_device.parent.parent.user_data = &zynqmp_eth_device;
- zynqmp_eth_device.parent.eth_rx = rt_zynqmp_eth_rx;
- zynqmp_eth_device.parent.eth_tx = rt_zynqmp_eth_tx;
- /* register eth device */
- state = eth_device_init(&(zynqmp_eth_device.parent), "e0");
- if (RT_EOK == state)
- {
- LOG_D("emac device init success");
- }
- else
- {
- LOG_E("emac device init faild: %d", state);
- state = -RT_ERROR;
- return state;
- }
- return state;
- }
- INIT_DEVICE_EXPORT(rt_hw_zynqmp_eth_init);
|