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 = ð_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(ð_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