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, &regvalue) != 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, &regvalue);
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, &regvalue) != 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, &regvalue) == 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