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 * 2020-07-17 wanghaijing support h7
13 * 2020-11-30 wanghaijing add phy reset
14 */
15
16 #include<rtthread.h>
17 #include<rtdevice.h>
18 #include "board.h"
19 #include "drv_config.h"
20
21 #ifdef BSP_USING_ETH_H750
22
23 #include <netif/ethernetif.h>
24 #include "lwipopts.h"
25 #include "drv_eth.h"
26
27 /*
28 * Emac driver uses CubeMX tool to generate emac and phy's configuration,
29 * the configuration files can be found in CubeMX_Config folder.
30 */
31
32 /* debug option */
33 #define LOG_TAG "drv.emac"
34 #include <drv_log.h>
35
36 #define MAX_ADDR_LEN 6
37
38 struct rt_stm32_eth
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 /* interface address info, hw address */
47 rt_uint8_t dev_addr[MAX_ADDR_LEN];
48 /* ETH_Speed */
49 uint32_t ETH_Speed;
50 /* ETH_Duplex_Mode */
51 uint32_t ETH_Mode;
52 };
53
54 static ETH_HandleTypeDef EthHandle;
55 static ETH_TxPacketConfig TxConfig;
56 static struct rt_stm32_eth stm32_eth_device;
57 static uint8_t PHY_ADDR = 0x1F;
58 static rt_uint32_t reset_pin = 0;
59
60 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
61 #pragma location=0x30040000
62 ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
63 #pragma location=0x30040060
64 ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
65 #pragma location=0x30040200
66 uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; /* Ethernet Receive Buffers */
67
68 #elif defined ( __CC_ARM ) /* MDK ARM Compiler */
69 __attribute__((at(0x30040000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
70 __attribute__((at(0x30040060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
71 __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; /* Ethernet Receive Buffer */
72
73 #elif defined ( __GNUC__ ) /* GNU Compiler */
74 ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
75 ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection"))); /* Ethernet Tx DMA Descriptors */
76 uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffers */
77 #endif
78
79 #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
80 #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
dump_hex(const rt_uint8_t * ptr,rt_size_t buflen)81 static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
82 {
83 unsigned char *buf = (unsigned char *)ptr;
84 int i, j;
85
86 for (i = 0; i < buflen; i += 16)
87 {
88 rt_kprintf("%08X: ", i);
89
90 for (j = 0; j < 16; j++)
91 if (i + j < buflen)
92 rt_kprintf("%02X ", buf[i + j]);
93 else
94 rt_kprintf(" ");
95
96 rt_kprintf(" ");
97
98 for (j = 0; j < 16; j++)
99 if (i + j < buflen)
100 rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
101
102 rt_kprintf("\n");
103 }
104 }
105 #endif
106
phy_reset(void)107 static void phy_reset(void)
108 {
109 rt_pin_write(reset_pin, PIN_LOW);
110 rt_thread_mdelay(50);
111 rt_pin_write(reset_pin, PIN_HIGH);
112 }
113
114
115 /* EMAC initialization function */
rt_stm32_eth_init(rt_device_t dev)116 static rt_err_t rt_stm32_eth_init(rt_device_t dev)
117 {
118 ETH_MACConfigTypeDef MACConf;
119 uint32_t regvalue = 0;
120 rt_err_t status = RT_EOK;
121
122 __HAL_RCC_D2SRAM3_CLK_ENABLE();
123
124 phy_reset();
125
126 /* ETHERNET Configuration */
127 EthHandle.Instance = ETH;
128 EthHandle.Init.MACAddr = (rt_uint8_t *)&stm32_eth_device.dev_addr[0];
129 EthHandle.Init.MediaInterface = HAL_ETH_RMII_MODE;
130 EthHandle.Init.TxDesc = DMATxDscrTab;
131 EthHandle.Init.RxDesc = DMARxDscrTab;
132 EthHandle.Init.RxBuffLen = ETH_MAX_PACKET_SIZE;
133
134 SCB_InvalidateDCache();
135
136 HAL_ETH_DeInit(&EthHandle);
137
138 /* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
139 if (HAL_ETH_Init(&EthHandle) != HAL_OK)
140 {
141 LOG_E("eth hardware init failed");
142 }
143 else
144 {
145 LOG_D("eth hardware init success");
146 }
147
148 rt_memset(&TxConfig, 0, sizeof(ETH_TxPacketConfig));
149 TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
150 TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
151 TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
152
153 for (int idx = 0; idx < ETH_RX_DESC_CNT; idx++)
154 {
155 HAL_ETH_DescAssignMemory(&EthHandle, idx, &Rx_Buff[idx][0], NULL);
156 }
157
158 HAL_ETH_SetMDIOClockRange(&EthHandle);
159
160 for(int i = 0; i <= PHY_ADDR; i ++)
161 {
162 if(HAL_ETH_ReadPHYRegister(&EthHandle, i, PHY_SPECIAL_MODES_REG, ®value) != HAL_OK)
163 {
164 status = -RT_ERROR;
165 /* Can't read from this device address continue with next address */
166 continue;
167 }
168
169 if((regvalue & PHY_BASIC_STATUS_REG) == i)
170 {
171 PHY_ADDR = i;
172 status = RT_EOK;
173 LOG_D("Found a phy, address:0x%02X", PHY_ADDR);
174 break;
175 }
176 }
177
178 if(HAL_ETH_WritePHYRegister(&EthHandle, PHY_ADDR, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK) == HAL_OK)
179 {
180 HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ADDR, PHY_SPECIAL_MODES_REG, ®value);
181
182 uint32_t tickstart = rt_tick_get();
183
184 /* wait until software reset is done or timeout occured */
185 while(regvalue & PHY_RESET_MASK)
186 {
187 if((rt_tick_get() - tickstart) <= 500)
188 {
189 if(HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ADDR, PHY_BASIC_CONTROL_REG, ®value) != HAL_OK)
190 {
191 status = -RT_ERROR;
192 break;
193 }
194 }
195 else
196 {
197 status = -RT_ETIMEOUT;
198 }
199 }
200 }
201
202 rt_thread_delay(2000);
203
204 if(HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ADDR, PHY_BASIC_CONTROL_REG, ®value) == HAL_OK)
205 {
206 regvalue |= PHY_AUTO_NEGOTIATION_MASK;
207 HAL_ETH_WritePHYRegister(&EthHandle, PHY_ADDR, PHY_BASIC_CONTROL_REG, regvalue);
208
209 eth_device_linkchange(&stm32_eth_device.parent, RT_TRUE);
210 HAL_ETH_GetMACConfig(&EthHandle, &MACConf);
211 MACConf.DuplexMode = ETH_FULLDUPLEX_MODE;
212 MACConf.Speed = ETH_SPEED_100M;
213 HAL_ETH_SetMACConfig(&EthHandle, &MACConf);
214
215 HAL_ETH_Start_IT(&EthHandle);
216 }
217 else
218 {
219 status = -RT_ERROR;
220 }
221
222 return status;
223 }
224
rt_stm32_eth_open(rt_device_t dev,rt_uint16_t oflag)225 static rt_err_t rt_stm32_eth_open(rt_device_t dev, rt_uint16_t oflag)
226 {
227 LOG_D("emac open");
228 return RT_EOK;
229 }
230
rt_stm32_eth_close(rt_device_t dev)231 static rt_err_t rt_stm32_eth_close(rt_device_t dev)
232 {
233 LOG_D("emac close");
234 return RT_EOK;
235 }
236
rt_stm32_eth_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)237 static rt_ssize_t rt_stm32_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
238 {
239 LOG_D("emac read");
240 rt_set_errno(-RT_ENOSYS);
241 return 0;
242 }
243
rt_stm32_eth_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)244 static rt_ssize_t rt_stm32_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
245 {
246 LOG_D("emac write");
247 rt_set_errno(-RT_ENOSYS);
248 return 0;
249 }
250
rt_stm32_eth_control(rt_device_t dev,int cmd,void * args)251 static rt_err_t rt_stm32_eth_control(rt_device_t dev, int cmd, void *args)
252 {
253 switch (cmd)
254 {
255 case NIOCTL_GADDR:
256
257 /* get mac address */
258 if (args) rt_memcpy(args, stm32_eth_device.dev_addr, 6);
259 else return -RT_ERROR;
260
261 break;
262
263 default :
264 break;
265 }
266
267 return RT_EOK;
268 }
269
270 /* ethernet device interface */
271 /* transmit data*/
rt_stm32_eth_tx(rt_device_t dev,struct pbuf * p)272 rt_err_t rt_stm32_eth_tx(rt_device_t dev, struct pbuf *p)
273 {
274 rt_err_t ret = -RT_ERROR;
275 HAL_StatusTypeDef state;
276 uint32_t i = 0, framelen = 0;
277 struct pbuf *q;
278 ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT];
279
280 rt_memset(Txbuffer, 0, ETH_TX_DESC_CNT * sizeof(ETH_BufferTypeDef));
281
282 for (q = p; q != NULL; q = q->next)
283 {
284 if (i >= ETH_TX_DESC_CNT)
285 return ERR_IF;
286
287 Txbuffer[i].buffer = q->payload;
288 Txbuffer[i].len = q->len;
289 framelen += q->len;
290
291 if (i > 0)
292 {
293 Txbuffer[i - 1].next = &Txbuffer[i];
294 }
295
296 if (q->next == NULL)
297 {
298 Txbuffer[i].next = NULL;
299 }
300
301 i++;
302 }
303
304 TxConfig.Length = framelen;
305 TxConfig.TxBuffer = Txbuffer;
306
307 #ifdef ETH_TX_DUMP
308 rt_kprintf("Tx dump, len= %d\r\n", framelen);
309 dump_hex(&Txbuffer[0]);
310 #endif
311
312 if (stm32_eth_device.parent.link_status)
313 {
314 SCB_CleanInvalidateDCache();
315 state = HAL_ETH_Transmit(&EthHandle, &TxConfig, 1000);
316
317 if (state != HAL_OK)
318 {
319 LOG_W("eth transmit frame faild: %d", EthHandle.ErrorCode);
320 EthHandle.ErrorCode = HAL_ETH_STATE_READY;
321 EthHandle.gState = HAL_ETH_STATE_READY;
322 }
323 }
324 else
325 {
326 LOG_E("eth transmit frame faild, netif not up");
327 }
328
329 ret = ERR_OK;
330
331 return ret;
332 }
333
334 /* receive data*/
rt_stm32_eth_rx(rt_device_t dev)335 struct pbuf *rt_stm32_eth_rx(rt_device_t dev)
336 {
337 uint32_t framelength = 0;
338 rt_uint16_t l;
339 struct pbuf *p = RT_NULL, *q;
340 ETH_BufferTypeDef RxBuff;
341 uint32_t alignedAddr;
342
343 if(HAL_ETH_GetRxDataBuffer(&EthHandle, &RxBuff) == HAL_OK)
344 {
345 HAL_ETH_GetRxDataLength(&EthHandle, &framelength);
346
347 /* Build Rx descriptor to be ready for next data reception */
348 HAL_ETH_BuildRxDescriptors(&EthHandle);
349
350 /* Invalidate data cache for ETH Rx Buffers */
351 alignedAddr = (uint32_t)RxBuff.buffer & ~0x1F;
352 SCB_InvalidateDCache_by_Addr((uint32_t *)alignedAddr, (uint32_t)RxBuff.buffer - alignedAddr + framelength);
353
354 p = pbuf_alloc(PBUF_RAW, framelength, PBUF_RAM);
355
356 if (p != NULL)
357 {
358 for (q = p, l = 0; q != NULL; q = q->next)
359 {
360 rt_memcpy((rt_uint8_t *)q->payload, (rt_uint8_t *)&RxBuff.buffer[l], q->len);
361 l = l + q->len;
362 }
363 }
364 }
365
366 return p;
367 }
368
369 /* interrupt service routine */
ETH_IRQHandler(void)370 void ETH_IRQHandler(void)
371 {
372 /* enter interrupt */
373 rt_interrupt_enter();
374
375 HAL_ETH_IRQHandler(&EthHandle);
376
377 /* leave interrupt */
378 rt_interrupt_leave();
379 }
380
HAL_ETH_RxCpltCallback(ETH_HandleTypeDef * heth)381 void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)
382 {
383 rt_err_t result;
384 result = eth_device_ready(&(stm32_eth_device.parent));
385
386 if (result != RT_EOK)
387 LOG_I("RxCpltCallback err = %d", result);
388 }
389
HAL_ETH_ErrorCallback(ETH_HandleTypeDef * heth)390 void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth)
391 {
392 LOG_E("eth err");
393 }
394
395 enum
396 {
397 PHY_LINK = (1 << 0),
398 PHY_100M = (1 << 1),
399 PHY_FULL_DUPLEX = (1 << 2),
400 };
401
phy_linkchange()402 static void phy_linkchange()
403 {
404 static rt_uint8_t phy_speed = 0;
405 rt_uint8_t phy_speed_new = 0;
406 rt_uint32_t status;
407
408 HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ADDR, PHY_BASIC_STATUS_REG, (uint32_t *)&status);
409 LOG_D("phy basic status reg is 0x%X", status);
410
411 if (status & (PHY_AUTONEGO_COMPLETE_MASK | PHY_LINKED_STATUS_MASK))
412 {
413 rt_uint32_t SR = 0;
414
415 phy_speed_new |= PHY_LINK;
416
417 HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ADDR, PHY_Status_REG, (uint32_t *)&SR);
418 LOG_D("phy control status reg is 0x%X", SR);
419
420 if (PHY_Status_SPEED_100M(SR))
421 {
422 phy_speed_new |= PHY_100M;
423 }
424
425 if (PHY_Status_FULL_DUPLEX(SR))
426 {
427 phy_speed_new |= PHY_FULL_DUPLEX;
428 }
429 }
430
431 if (phy_speed != phy_speed_new)
432 {
433 phy_speed = phy_speed_new;
434
435 if (phy_speed & PHY_LINK)
436 {
437 LOG_D("link up");
438
439 if (phy_speed & PHY_100M)
440 {
441 LOG_D("100Mbps");
442 stm32_eth_device.ETH_Speed = ETH_SPEED_100M;
443 }
444 else
445 {
446 stm32_eth_device.ETH_Speed = ETH_SPEED_10M;
447 LOG_D("10Mbps");
448 }
449
450 if (phy_speed & PHY_FULL_DUPLEX)
451 {
452 LOG_D("full-duplex");
453 stm32_eth_device.ETH_Mode = ETH_FULLDUPLEX_MODE;
454 }
455 else
456 {
457 LOG_D("half-duplex");
458 stm32_eth_device.ETH_Mode = ETH_HALFDUPLEX_MODE;
459 }
460
461 /* send link up. */
462 eth_device_linkchange(&stm32_eth_device.parent, RT_TRUE);
463 }
464 else
465 {
466 LOG_I("link down");
467 eth_device_linkchange(&stm32_eth_device.parent, RT_FALSE);
468 }
469 }
470 }
471
472 #ifdef PHY_USING_INTERRUPT_MODE
eth_phy_isr(void * args)473 static void eth_phy_isr(void *args)
474 {
475 rt_uint32_t status = 0;
476
477 HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ADDR, PHY_INTERRUPT_FLAG_REG, (uint32_t *)&status);
478 LOG_D("phy interrupt status reg is 0x%X", status);
479
480 phy_linkchange();
481 }
482 #endif /* PHY_USING_INTERRUPT_MODE */
483
phy_monitor_thread_entry(void * parameter)484 static void phy_monitor_thread_entry(void *parameter)
485 {
486 phy_linkchange();
487 #ifdef PHY_USING_INTERRUPT_MODE
488 /* configuration intterrupt pin */
489 rt_pin_mode(PHY_INT_PIN, PIN_MODE_INPUT_PULLUP);
490 rt_pin_attach_irq(PHY_INT_PIN, PIN_IRQ_MODE_FALLING, eth_phy_isr, (void *)"callbackargs");
491 rt_pin_irq_enable(PHY_INT_PIN, PIN_IRQ_ENABLE);
492
493 /* enable phy interrupt */
494 HAL_ETH_WritePHYRegister(&EthHandle, PHY_ADDR, PHY_INTERRUPT_MASK_REG, PHY_INT_MASK);
495 #if defined(PHY_INTERRUPT_CTRL_REG)
496 HAL_ETH_WritePHYRegister(&EthHandle, PHY_ADDR, PHY_INTERRUPT_CTRL_REG, PHY_INTERRUPT_EN);
497 #endif
498 #else /* PHY_USING_INTERRUPT_MODE */
499 stm32_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
500 NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
501
502 if (!stm32_eth_device.poll_link_timer || rt_timer_start(stm32_eth_device.poll_link_timer) != RT_EOK)
503 {
504 LOG_E("Start link change detection timer failed");
505 }
506
507 #endif /* PHY_USING_INTERRUPT_MODE */
508 }
509
510 /* Register the EMAC device */
rt_hw_stm32_eth_init(void)511 static int rt_hw_stm32_eth_init(void)
512 {
513 rt_err_t state = RT_EOK;
514 reset_pin = rt_pin_get(ETH_RESET_PIN);
515
516 rt_pin_mode(reset_pin, PIN_MODE_OUTPUT);
517 rt_pin_write(reset_pin, PIN_HIGH);
518
519 stm32_eth_device.ETH_Speed = ETH_SPEED_100M;
520 stm32_eth_device.ETH_Mode = ETH_FULLDUPLEX_MODE;
521
522 /* OUI 00-80-E1 STMICROELECTRONICS. */
523 stm32_eth_device.dev_addr[0] = 0x00;
524 stm32_eth_device.dev_addr[1] = 0x80;
525 stm32_eth_device.dev_addr[2] = 0xE1;
526 /* generate MAC addr from 96bit unique ID (only for test). */
527 stm32_eth_device.dev_addr[3] = *(rt_uint8_t *)(UID_BASE + 4);
528 stm32_eth_device.dev_addr[4] = *(rt_uint8_t *)(UID_BASE + 2);
529 stm32_eth_device.dev_addr[5] = *(rt_uint8_t *)(UID_BASE + 0);
530
531 stm32_eth_device.parent.parent.init = rt_stm32_eth_init;
532 stm32_eth_device.parent.parent.open = rt_stm32_eth_open;
533 stm32_eth_device.parent.parent.close = rt_stm32_eth_close;
534 stm32_eth_device.parent.parent.read = rt_stm32_eth_read;
535 stm32_eth_device.parent.parent.write = rt_stm32_eth_write;
536 stm32_eth_device.parent.parent.control = rt_stm32_eth_control;
537 stm32_eth_device.parent.parent.user_data = RT_NULL;
538
539 stm32_eth_device.parent.eth_rx = rt_stm32_eth_rx;
540 stm32_eth_device.parent.eth_tx = rt_stm32_eth_tx;
541
542 /* register eth device */
543 state = eth_device_init(&(stm32_eth_device.parent), "e0");
544
545 if (RT_EOK == state)
546 {
547 LOG_D("emac device init success");
548 }
549 else
550 {
551 LOG_E("emac device init faild: %d", state);
552 state = -RT_ERROR;
553 }
554
555 /* start phy monitor */
556 rt_thread_t tid;
557 tid = rt_thread_create("phy",
558 phy_monitor_thread_entry,
559 RT_NULL,
560 1024,
561 RT_THREAD_PRIORITY_MAX - 2,
562 2);
563
564 if (tid != RT_NULL)
565 {
566 rt_thread_startup(tid);
567 }
568 else
569 {
570 state = -RT_ERROR;
571 }
572
573 return state;
574 }
575 INIT_DEVICE_EXPORT(rt_hw_stm32_eth_init);
576
577 #endif /* BSP_USING_ETH_ARTPI */
578