1 /*
2  * Copyright (c) 2021, WangHuachen
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-5-10     WangHuachen  the first version
9  */
10 #include "board.h"
11 #include <netif/ethernetif.h>
12 #include "lwipopts.h"
13 #include "lwip/opt.h"
14 #include "drv_eth.h"
15 #include "lwip/netif.h"
16 #include "netif/xadapter.h"
17 #include "netif/xemacpsif.h"
18 #include "xparameters.h"
19 #include "xemacps.h"
20 
21 #define DBG_TAG             "drv.emac"
22 #define DBG_LEVEL           DBG_INFO
23 #include <rtdbg.h>
24 
25 #define MAC_BASE_ADDR       XPAR_PSU_ETHERNET_3_BASEADDR
26 #define MAX_ADDR_LEN        6
27 
28 struct rt_zynqmp_eth
29 {
30     /* inherit from ethernet device */
31     struct eth_device parent;
32 
33     /* interface address info, hw address */
34     rt_uint8_t  dev_addr[MAX_ADDR_LEN];
35 
36     struct xemac_s *xemac;
37 };
38 
39 static struct rt_zynqmp_eth zynqmp_eth_device;
40 extern XEmacPs_Config *mac_config;
41 extern struct netif *NetIf;
42 
rt_hw_eth_isr(int irqno,void * param)43 static void rt_hw_eth_isr(int irqno, void *param)
44 {
45     struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)param;
46     xemacpsif_s *xemacpsif = (xemacpsif_s *)eth_dev->xemac->state;
47     XEmacPs_IntrHandler(&xemacpsif->emacps);
48 }
49 
50 extern enum ethernet_link_status eth_link_status;
51 extern u32_t phy_link_detect(XEmacPs *xemacp, u32_t phy_addr);
52 extern u32_t phy_autoneg_status(XEmacPs *xemacp, u32_t phy_addr);
53 extern u32_t phyaddrforemac;
54 
rt_zynqmp_eth_link_detect(struct rt_zynqmp_eth * eth_dev)55 void rt_zynqmp_eth_link_detect(struct rt_zynqmp_eth *eth_dev)
56 {
57     u32_t link_speed, phy_link_status;
58     struct xemac_s *xemac = eth_dev->xemac;
59     xemacpsif_s *xemacs = (xemacpsif_s *)(xemac->state);
60     XEmacPs *xemacp = &xemacs->emacps;
61 
62     if ((xemacp->IsReady != (u32)XIL_COMPONENT_IS_READY) ||
63             (eth_link_status == ETH_LINK_UNDEFINED))
64         return;
65 
66     phy_link_status = phy_link_detect(xemacp, phyaddrforemac);
67 
68     if ((eth_link_status == ETH_LINK_UP) && (!phy_link_status))
69         eth_link_status = ETH_LINK_DOWN;
70 
71     switch (eth_link_status) {
72         case ETH_LINK_UNDEFINED:
73         case ETH_LINK_UP:
74             return;
75         case ETH_LINK_DOWN:
76             eth_device_linkchange(&zynqmp_eth_device.parent, RT_FALSE);
77             eth_link_status = ETH_LINK_NEGOTIATING;
78             LOG_D("Ethernet Link down");
79             break;
80         case ETH_LINK_NEGOTIATING:
81             if (phy_link_status &&
82                 phy_autoneg_status(xemacp, phyaddrforemac)) {
83 
84                 /* Initiate Phy setup to get link speed */
85                 link_speed = phy_setup_emacps(xemacp,
86                                 phyaddrforemac);
87                 XEmacPs_SetOperatingSpeed(xemacp, link_speed);
88 
89                 eth_device_linkchange(&zynqmp_eth_device.parent, RT_TRUE);
90                 eth_link_status = ETH_LINK_UP;
91                 LOG_D("Ethernet Link up");
92             }
93             break;
94     }
95 }
96 
phy_monitor_thread(void * parameter)97 static void phy_monitor_thread(void *parameter)
98 {
99     struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)parameter;
100 
101     while (1)
102     {
103         rt_zynqmp_eth_link_detect(eth_dev);
104         rt_thread_delay(RT_TICK_PER_SECOND);
105     }
106 }
107 
rt_zynqmp_eth_init(rt_device_t dev)108 static rt_err_t rt_zynqmp_eth_init(rt_device_t dev)
109 {
110     struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
111     struct netif *netif = eth_dev->parent.netif;
112     struct xemac_s *xemac;
113     xemacpsif_s *xemacpsif;
114     u32 dmacrreg;
115     s32_t status = XST_SUCCESS;
116     struct xtopology_t *xtopologyp;
117 
118     if (eth_dev->xemac != RT_NULL)
119     {
120         LOG_W("rt_zynqmp_eth_init: device has been initialized");
121         return -RT_ERROR;
122     }
123 
124     NetIf = netif;
125 
126     xemacpsif = rt_malloc(sizeof *xemacpsif);
127     if (xemacpsif == NULL)
128     {
129         LOG_E("rt_zynqmp_eth_init: out of memory");
130         return -RT_ENOMEM;
131     }
132 
133     xemac = rt_malloc(sizeof *xemac);
134     if (xemac == NULL)
135     {
136         LOG_E("rt_zynqmp_eth_init: out of memory");
137         return -RT_ENOMEM;
138     }
139 
140     xemac->state = (void *)xemacpsif;
141     xemac->topology_index = xtopology_find_index(MAC_BASE_ADDR);
142     xemac->type = xemac_type_emacps;
143     xemac->rt_eth_device = &eth_dev->parent;
144 
145     xemacpsif->send_q = NULL;
146     xemacpsif->recv_q = pq_create_queue();
147     if (!xemacpsif->recv_q)
148         return -RT_ENOMEM;
149 
150     eth_dev->xemac = xemac;
151 
152     /* obtain config of this emac */
153     mac_config = (XEmacPs_Config *)xemacps_lookup_config(MAC_BASE_ADDR);
154 
155     status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
156                                    mac_config->BaseAddress);
157     if (status != XST_SUCCESS)
158     {
159         LOG_W("In %s:EmacPs Configuration Failed....", __func__);
160         return -RT_ERROR;
161     }
162 
163     /* initialize the mac */
164     init_emacps(xemacpsif, netif);
165 
166     dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
167                                XEMACPS_DMACR_OFFSET);
168     dmacrreg = dmacrreg | (0x00000010);
169     XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
170                      XEMACPS_DMACR_OFFSET, dmacrreg);
171 
172     setup_isr(xemac);
173     init_dma(xemac);
174 
175     xtopologyp = &xtopology[xemac->topology_index];
176     /*
177     * Connect the device driver handler that will be called when an
178     * interrupt for the device occurs, the handler defined above performs
179     * the specific interrupt processing for the device.
180     */
181     rt_hw_interrupt_install(xtopologyp->scugic_emac_intr, rt_hw_eth_isr, (void *)eth_dev, "eth");
182     /*
183     * Enable the interrupt for emacps.
184     */
185     rt_hw_interrupt_umask(xtopologyp->scugic_emac_intr);
186 
187     start_emacps(xemacpsif);
188 
189     if (eth_link_status == ETH_LINK_UP)
190         eth_device_linkchange(&eth_dev->parent, RT_TRUE);
191 
192     rt_thread_t tid;
193     tid = rt_thread_create("phylnk",
194                            phy_monitor_thread,
195                            eth_dev,
196                            1024,
197                            RT_THREAD_PRIORITY_MAX - 2,
198                            2);
199     if (tid != RT_NULL)
200         rt_thread_startup(tid);
201     else
202         return -RT_ERROR;
203 
204     return RT_EOK;
205 }
206 
rt_zynqmp_eth_open(rt_device_t dev,rt_uint16_t oflag)207 static rt_err_t rt_zynqmp_eth_open(rt_device_t dev, rt_uint16_t oflag)
208 {
209     LOG_D("emac open");
210     return RT_EOK;
211 }
212 
rt_zynqmp_eth_close(rt_device_t dev)213 static rt_err_t rt_zynqmp_eth_close(rt_device_t dev)
214 {
215     LOG_D("emac close");
216     return RT_EOK;
217 }
218 
rt_zynqmp_eth_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)219 static rt_ssize_t rt_zynqmp_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
220 {
221     LOG_D("emac read");
222     rt_set_errno(-RT_ENOSYS);
223     return 0;
224 }
225 
rt_zynqmp_eth_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)226 static rt_ssize_t rt_zynqmp_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
227 {
228     LOG_D("emac write");
229     rt_set_errno(-RT_ENOSYS);
230     return 0;
231 }
232 
rt_zynqmp_eth_control(rt_device_t dev,int cmd,void * args)233 static rt_err_t rt_zynqmp_eth_control(rt_device_t dev, int cmd, void *args)
234 {
235     struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
236     switch (cmd)
237     {
238     case NIOCTL_GADDR:
239         /* get mac address */
240         if (args) rt_memcpy(args, eth_dev->dev_addr, 6);
241         else return -RT_ERROR;
242         break;
243 
244     default :
245         break;
246     }
247 
248     return RT_EOK;
249 }
250 
251 extern err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif, struct pbuf *p);
rt_zynqmp_eth_tx(rt_device_t dev,struct pbuf * p)252 rt_err_t rt_zynqmp_eth_tx(rt_device_t dev, struct pbuf *p)
253 {
254     rt_base_t lev;
255     rt_err_t err;
256     XEmacPs_BdRing *txring;
257 
258     struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
259     struct xemac_s *xemac = eth_dev->xemac;
260     xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
261 
262     lev = rt_hw_interrupt_disable();
263 
264     txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
265     process_sent_bds(xemacpsif, txring);
266 
267     if (is_tx_space_available(xemacpsif))
268     {
269         _unbuffered_low_level_output(xemacpsif, p);
270         err = RT_EOK;
271     }
272     else
273     {
274 #if LINK_STATS
275         lwip_stats.link.drop++;
276 #endif
277         LOG_D("pack dropped, no space");
278         err = -RT_ENOMEM;
279     }
280 
281     rt_hw_interrupt_enable(lev);
282 
283     return err;
284 }
285 
rt_zynqmp_eth_rx(rt_device_t dev)286 struct pbuf *rt_zynqmp_eth_rx(rt_device_t dev)
287 {
288     rt_base_t lev;
289     struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
290     struct xemac_s *xemac = eth_dev->xemac;
291     xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
292     struct pbuf *p;
293 
294     lev = rt_hw_interrupt_disable();
295 
296     /* see if there is data to process */
297     if (pq_qlength(xemacpsif->recv_q) == 0)
298         return NULL;
299 
300     /* return one packet from receive q */
301     p = (struct pbuf *)pq_dequeue(xemacpsif->recv_q);
302 
303     rt_hw_interrupt_enable(lev);
304 
305     return p;
306 }
307 
rt_hw_zynqmp_eth_init(void)308 static int rt_hw_zynqmp_eth_init(void)
309 {
310     rt_err_t state = RT_EOK;
311 
312     zynqmp_eth_device.xemac = RT_NULL;
313 
314     zynqmp_eth_device.dev_addr[0] = 0x00;
315     zynqmp_eth_device.dev_addr[1] = 0x0A;
316     zynqmp_eth_device.dev_addr[2] = 0x35;
317     zynqmp_eth_device.dev_addr[3] = 0x00;
318     zynqmp_eth_device.dev_addr[4] = 0x01;
319     zynqmp_eth_device.dev_addr[5] = 0x02;
320 
321     zynqmp_eth_device.parent.parent.init       = rt_zynqmp_eth_init;
322     zynqmp_eth_device.parent.parent.open       = rt_zynqmp_eth_open;
323     zynqmp_eth_device.parent.parent.close      = rt_zynqmp_eth_close;
324     zynqmp_eth_device.parent.parent.read       = rt_zynqmp_eth_read;
325     zynqmp_eth_device.parent.parent.write      = rt_zynqmp_eth_write;
326     zynqmp_eth_device.parent.parent.control    = rt_zynqmp_eth_control;
327     zynqmp_eth_device.parent.parent.user_data  = &zynqmp_eth_device;
328 
329     zynqmp_eth_device.parent.eth_rx     = rt_zynqmp_eth_rx;
330     zynqmp_eth_device.parent.eth_tx     = rt_zynqmp_eth_tx;
331 
332     /* register eth device */
333     state = eth_device_init(&(zynqmp_eth_device.parent), "e0");
334     if (RT_EOK == state)
335     {
336         LOG_D("emac device init success");
337     }
338     else
339     {
340         LOG_E("emac device init faild: %d", state);
341         state = -RT_ERROR;
342         return state;
343     }
344 
345     return state;
346 }
347 INIT_DEVICE_EXPORT(rt_hw_zynqmp_eth_init);
348