1 /*
2 * Copyright (c) 2006-2025, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-11-19 SummerGift first version
9 * 2018-12-25 zylx fix some bugs
10 * 2019-06-10 SummerGift optimize PHY state detection process
11 * 2019-09-03 xiaofan optimize link change detection process
12 * 2025-02-11 kurisaW adaptation for RZ Ethernet driver
13 */
14
15 #include "drv_config.h"
16 #include "drv_eth.h"
17 #include <hal_data.h>
18 #include <netif/ethernetif.h>
19 #include <lwipopts.h>
20
21 /* debug option */
22 // #define ETH_RX_DUMP
23 // #define ETH_TX_DUMP
24 #define MINIMUM_ETHERNET_FRAME_SIZE (60U)
25 #define ETH_MAX_PACKET_SIZE (2048U)
26 #define ETHER_GMAC_INTERRUPT_FACTOR_RECEPTION (0x000000C0)
27 #define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE
28 #define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE
29 // #define DRV_DEBUG
30 #define LOG_TAG "drv.eth"
31 #ifdef DRV_DEBUG
32 #define DBG_LVL DBG_LOG
33 #else
34 #define DBG_LVL DBG_INFO
35 #endif /* DRV_DEBUG */
36 #include <rtdbg.h>
37
38 struct rt_eth_dev
39 {
40 /* inherit from ethernet device */
41 struct eth_device parent;
42 #ifndef PHY_USING_INTERRUPT_MODE
43 rt_timer_t poll_link_timer;
44 #endif
45 };
46
47 static rt_uint8_t *Rx_Buff, *Tx_Buff;
48 // static ETH_HandleTypeDef EthHandle;
49 static struct rt_eth_dev ra_eth_device;
50
51 static uint8_t g_link_change = 0; ///< Link change (bit0:port0, bit1:port1, bit2:port2)
52 static uint8_t g_link_status = 0; ///< Link status (bit0:port0, bit1:port1, bit2:port2)
53 static uint8_t previous_link_status = 0;
54
55 #if defined(SOC_SERIES_R9A07G0)
56
57 #define status_ecsr status_link
58 #define ETHER_EVENT_INTERRUPT ETHER_EVENT_SBD_INTERRUPT
59
60 #define R_ETHER_Open R_GMAC_Open
61 #define R_ETHER_Write R_GMAC_Write
62 #define R_ETHER_Read R_GMAC_Read
63 #define R_ETHER_LinkProcess R_GMAC_LinkProcess
64
65 #endif
66
67 #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
68 #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
dump_hex(const rt_uint8_t * ptr,rt_size_t buflen)69 static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
70 {
71 unsigned char *buf = (unsigned char *)ptr;
72 int i, j;
73
74 for (i = 0; i < buflen; i += 16)
75 {
76 rt_kprintf("%08X: ", i);
77
78 for (j = 0; j < 16; j++)
79 if (i + j < buflen)
80 rt_kprintf("%02X ", buf[i + j]);
81 else
82 rt_kprintf(" ");
83 rt_kprintf(" ");
84
85 for (j = 0; j < 16; j++)
86 if (i + j < buflen)
87 rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
88 rt_kprintf("\n");
89 }
90 }
91 #endif
92
93 extern void phy_reset(void);
94 /* EMAC initialization function */
rt_ra_eth_init(void)95 static rt_err_t rt_ra_eth_init(void)
96 {
97 fsp_err_t res;
98
99 res = R_ETHER_Open(&g_ether0_ctrl, &g_ether0_cfg);
100 if (res != FSP_SUCCESS)
101 LOG_W("R_ETHER_Open failed!, res = %d", res);
102
103 return RT_EOK;
104 }
105
rt_ra_eth_open(rt_device_t dev,rt_uint16_t oflag)106 static rt_err_t rt_ra_eth_open(rt_device_t dev, rt_uint16_t oflag)
107 {
108 LOG_D("emac open");
109 return RT_EOK;
110 }
111
rt_ra_eth_close(rt_device_t dev)112 static rt_err_t rt_ra_eth_close(rt_device_t dev)
113 {
114 LOG_D("emac close");
115 return RT_EOK;
116 }
117
rt_ra_eth_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)118 static rt_ssize_t rt_ra_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
119 {
120 LOG_D("emac read");
121 rt_set_errno(-RT_ENOSYS);
122 return 0;
123 }
124
rt_ra_eth_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)125 static rt_ssize_t rt_ra_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
126 {
127 LOG_D("emac write");
128 rt_set_errno(-RT_ENOSYS);
129 return 0;
130 }
131
rt_ra_eth_control(rt_device_t dev,int cmd,void * args)132 static rt_err_t rt_ra_eth_control(rt_device_t dev, int cmd, void *args)
133 {
134 switch (cmd)
135 {
136 case NIOCTL_GADDR:
137 /* get mac address */
138 if (args)
139 {
140 #if defined(SOC_SERIES_R9A07G0)
141 SMEMCPY(args, g_ether0_ctrl.p_gmac_cfg->p_mac_address, 6);
142 #else
143 SMEMCPY(args, g_ether0_ctrl.p_ether_cfg->p_mac_address, 6);
144 #endif
145 }
146 else
147 {
148 return -RT_ERROR;
149 }
150 break;
151
152 default:
153 break;
154 }
155
156 return RT_EOK;
157 }
158
159 /* ethernet device interface */
160 /* transmit data*/
rt_ra_eth_tx(rt_device_t dev,struct pbuf * p)161 rt_err_t rt_ra_eth_tx(rt_device_t dev, struct pbuf *p)
162 {
163 fsp_err_t res;
164 struct pbuf *q;
165 uint8_t *buffer = Tx_Buff;
166 uint32_t framelength = 0;
167 uint32_t bufferoffset = 0;
168 uint32_t byteslefttocopy = 0;
169 uint32_t payloadoffset = 0;
170 bufferoffset = 0;
171
172 LOG_D("send frame len : %d", p->tot_len);
173
174 /* copy frame from pbufs to driver buffers */
175 for (q = p; q != NULL; q = q->next)
176 {
177 /* Get bytes in current lwIP buffer */
178 byteslefttocopy = q->len;
179 payloadoffset = 0;
180
181 /* Check if the length of data to copy is bigger than Tx buffer size*/
182 while ((byteslefttocopy + bufferoffset) > ETH_TX_BUF_SIZE)
183 {
184 /* Copy data to Tx buffer*/
185 SMEMCPY((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), (ETH_TX_BUF_SIZE - bufferoffset));
186
187 byteslefttocopy = byteslefttocopy - (ETH_TX_BUF_SIZE - bufferoffset);
188 payloadoffset = payloadoffset + (ETH_TX_BUF_SIZE - bufferoffset);
189 framelength = framelength + (ETH_TX_BUF_SIZE - bufferoffset);
190 bufferoffset = 0;
191 }
192
193 /* Copy the remaining bytes */
194 SMEMCPY((uint8_t *)((uint8_t *)buffer + bufferoffset), (uint8_t *)((uint8_t *)q->payload + payloadoffset), byteslefttocopy);
195 bufferoffset = bufferoffset + byteslefttocopy;
196 framelength = framelength + byteslefttocopy;
197 }
198
199 #ifdef ETH_TX_DUMP
200 dump_hex(buffer, p->tot_len);
201 #endif
202 #ifdef ETH_RX_DUMP
203 if (p)
204 {
205 LOG_E("******p buf frame *********");
206 for (q = p; q != NULL; q = q->next)
207 {
208 dump_hex(q->payload, q->len);
209 }
210 }
211 #endif
212 res = R_ETHER_Write(&g_ether0_ctrl, buffer, p->tot_len);//>MINIMUM_ETHERNET_FRAME_SIZE?p->tot_len:MINIMUM_ETHERNET_FRAME_SIZE);
213 if (res != FSP_SUCCESS)
214 LOG_W("R_ETHER_Write failed!, res = %d", res);
215 return RT_EOK;
216 }
217
218 /* receive data*/
rt_ra_eth_rx(rt_device_t dev)219 struct pbuf *rt_ra_eth_rx(rt_device_t dev)
220 {
221 struct pbuf *p = NULL;
222 struct pbuf *q = NULL;
223 uint32_t len = 0;
224 uint8_t *buffer = Rx_Buff;
225 fsp_err_t res;
226
227 res = R_ETHER_Read(&g_ether0_ctrl, buffer, &len);
228 if (res != FSP_SUCCESS)
229 LOG_D("R_ETHER_Read failed!, res = %d", res);
230
231 uint32_t bufferoffset = 0;
232 uint32_t payloadoffset = 0;
233 uint32_t byteslefttocopy = 0;
234
235 LOG_D("receive frame len : %d", len);
236
237 if (len > 0)
238 {
239 /* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
240 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
241 }
242
243 #ifdef ETH_RX_DUMP
244 if (p)
245 {
246 dump_hex(buffer, p->tot_len);
247 }
248 #endif
249
250 if (p != NULL)
251 {
252 bufferoffset = 0;
253 for (q = p; q != NULL; q = q->next)
254 {
255 byteslefttocopy = q->len;
256 payloadoffset = 0;
257
258 /* Check if the length of bytes to copy in current pbuf is bigger than Rx buffer size*/
259 while ((byteslefttocopy + bufferoffset) > ETH_RX_BUF_SIZE)
260 {
261 /* Copy data to pbuf */
262 SMEMCPY((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), (ETH_RX_BUF_SIZE - bufferoffset));
263
264 byteslefttocopy = byteslefttocopy - (ETH_RX_BUF_SIZE - bufferoffset);
265 payloadoffset = payloadoffset + (ETH_RX_BUF_SIZE - bufferoffset);
266 bufferoffset = 0;
267 }
268 /* Copy remaining data in pbuf */
269 SMEMCPY((uint8_t *)((uint8_t *)q->payload + payloadoffset), (uint8_t *)((uint8_t *)buffer + bufferoffset), byteslefttocopy);
270 bufferoffset = bufferoffset + byteslefttocopy;
271 }
272 }
273
274 #ifdef ETH_RX_DUMP
275 if (p)
276 {
277 LOG_E("******p buf frame *********");
278 for (q = p; q != NULL; q = q->next)
279 {
280 dump_hex(q->payload, q->len);
281 }
282 }
283 #endif
284
285 return p;
286 }
287
phy_linkchange()288 static void phy_linkchange()
289 {
290 fsp_err_t res;
291 uint8_t port = 0;
292 uint8_t port_bit = 0;
293
294 #if defined(SOC_SERIES_R9A07G0)
295 gmac_link_status_t port_status;
296 #endif
297
298 res = R_ETHER_LinkProcess(&g_ether0_ctrl);
299 if (res != FSP_SUCCESS)
300 LOG_D("R_ETHER_LinkProcess failed!, res = %d", res);
301
302 if (0 == g_ether0.p_cfg->p_callback)
303 {
304 for (port = 0; port < PING_PORT_COUNT; port++)
305 {
306 #if defined(SOC_SERIES_R9A07G0)
307 res = R_GMAC_GetLinkStatus(&g_ether0_ctrl, port, &port_status);
308 #else
309 res = R_ETHER_PHY_LinkStatusGet(&g_ether_phy0_ctrl);
310 #endif
311 if (FSP_SUCCESS != res)
312 {
313 /* An error has occurred */
314 LOG_E("PHY_LinkStatus get failed!, res = %d", res);
315 break;
316 }
317
318 /* Set link up */
319 g_link_status |= (uint8_t)(1U << port);
320 }
321 if (FSP_SUCCESS == res)
322 {
323 /* Set changed link status */
324 g_link_change = previous_link_status ^ g_link_status;
325 }
326 }
327
328 for (port = 0; port < PING_PORT_COUNT; port++)
329 {
330 port_bit = (uint8_t)(1U << port);
331
332 if (g_link_change & port_bit)
333 {
334 /* Link status changed */
335 g_link_change &= (uint8_t)(~port_bit); // change bit clear
336
337 if (g_link_status & port_bit)
338 {
339 /* Changed to Link-up */
340 eth_device_linkchange(&ra_eth_device.parent, RT_TRUE);
341 LOG_I("link up");
342 }
343 else
344 {
345 /* Changed to Link-down */
346 eth_device_linkchange(&ra_eth_device.parent, RT_FALSE);
347 LOG_I("link down");
348 }
349 }
350 }
351
352 previous_link_status = g_link_status;
353 }
354
user_ether0_callback(ether_callback_args_t * p_args)355 void user_ether0_callback(ether_callback_args_t *p_args)
356 {
357 rt_interrupt_enter();
358
359 switch (p_args->event)
360 {
361 case ETHER_EVENT_LINK_ON: ///< Link up detection event/
362 g_link_status |= (uint8_t)p_args->status_ecsr; ///< status up
363 g_link_change |= (uint8_t)p_args->status_ecsr; ///< change bit set
364 break;
365
366 case ETHER_EVENT_LINK_OFF: ///< Link down detection event
367 g_link_status &= (uint8_t)(~p_args->status_ecsr); ///< status down
368 g_link_change |= (uint8_t)p_args->status_ecsr; ///< change bit set
369 break;
370
371 case ETHER_EVENT_WAKEON_LAN: ///< Magic packet detection event
372 /* If EDMAC FR (Frame Receive Event) or FDE (Receive Descriptor Empty Event)
373 * interrupt occurs, send rx mailbox. */
374 case ETHER_EVENT_INTERRUPT: ///< BSD Interrupt event
375 {
376 rt_err_t result;
377 result = eth_device_ready(&(ra_eth_device.parent));
378 if (result != RT_EOK)
379 rt_kprintf("RX err =%d\n", result);
380 break;
381 }
382
383 default:
384 break;
385 }
386
387 rt_interrupt_leave();
388 }
389
390 /* Register the EMAC device */
rt_hw_ra_eth_init(void)391 static int rt_hw_ra_eth_init(void)
392 {
393 rt_err_t state = RT_EOK;
394
395 /* Prepare receive and send buffers */
396 Rx_Buff = (rt_uint8_t *)rt_calloc(1, ETH_MAX_PACKET_SIZE);
397 if (Rx_Buff == RT_NULL)
398 {
399 LOG_E("No memory");
400 state = -RT_ENOMEM;
401 goto __exit;
402 }
403
404 Tx_Buff = (rt_uint8_t *)rt_calloc(1, ETH_MAX_PACKET_SIZE);
405 if (Tx_Buff == RT_NULL)
406 {
407 LOG_E("No memory");
408 state = -RT_ENOMEM;
409 goto __exit;
410 }
411
412 ra_eth_device.parent.parent.init = NULL;
413 ra_eth_device.parent.parent.open = rt_ra_eth_open;
414 ra_eth_device.parent.parent.close = rt_ra_eth_close;
415 ra_eth_device.parent.parent.read = rt_ra_eth_read;
416 ra_eth_device.parent.parent.write = rt_ra_eth_write;
417 ra_eth_device.parent.parent.control = rt_ra_eth_control;
418 ra_eth_device.parent.parent.user_data = RT_NULL;
419
420 ra_eth_device.parent.eth_rx = rt_ra_eth_rx;
421 ra_eth_device.parent.eth_tx = rt_ra_eth_tx;
422
423 rt_ra_eth_init();
424
425 /* register eth device */
426 state = eth_device_init(&(ra_eth_device.parent), "e0");
427 if (RT_EOK == state)
428 {
429 LOG_D("emac device init success");
430 }
431 else
432 {
433 LOG_E("emac device init faild: %d", state);
434 state = -RT_ERROR;
435 goto __exit;
436 }
437
438 ra_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void *))phy_linkchange,
439 NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
440 if (!ra_eth_device.poll_link_timer || rt_timer_start(ra_eth_device.poll_link_timer) != RT_EOK)
441 {
442 LOG_E("Start link change detection timer failed");
443 }
444 __exit:
445 if (state != RT_EOK)
446 {
447 if (Rx_Buff)
448 {
449 rt_free(Rx_Buff);
450 }
451
452 if (Tx_Buff)
453 {
454 rt_free(Tx_Buff);
455 }
456 }
457
458 return state;
459 }
460 INIT_DEVICE_EXPORT(rt_hw_ra_eth_init);
461