1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-10-20     luobeihai    first version
9  * 2023-01-10     luobeihai    fix Eanble HARDWARE_CHECKSUM bug
10  */
11 
12 #include <board.h>
13 
14 #ifdef BSP_USING_ETH
15 
16 #include <netif/ethernetif.h>
17 #include <netif/etharp.h>
18 #include <lwip/icmp.h>
19 #include "lwipopts.h"
20 #include "lwip/ip.h"
21 #include "drv_eth.h"
22 
23 /* debug option */
24 //#define DRV_DEBUG
25 //#define ETH_RX_DUMP
26 //#define ETH_TX_DUMP
27 #define LOG_TAG             "drv.emac"
28 #include <drv_log.h>
29 
30 /* Global pointers on Tx and Rx descriptor used to transmit and receive descriptors */
31 extern ETH_DMADescConfig_T  *DMATxDescToSet, *DMARxDescToGet;
32 
33 /* Ethernet Rx & Tx DMA Descriptors */
34 extern ETH_DMADescConfig_T  DMARxDscrTab[ETH_RXBUFNB];
35 extern ETH_DMADescConfig_T  DMATxDscrTab[ETH_TXBUFNB];
36 
37 /* Ethernet Receive and Transmit buffers */
38 extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
39 extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];
40 
41 /* phy address */
42 static uint8_t phy_addr = 0xFF;
43 
44 #define MAX_ADDR_LEN 6
45 struct rt_apm32_eth
46 {
47     /* inherit from ethernet device */
48     struct eth_device parent;
49 
50     rt_timer_t poll_link_timer;
51 
52     /* interface address info. */
53     rt_uint8_t  dev_addr[MAX_ADDR_LEN];         /* hw address   */
54 
55     uint32_t    ETH_Speed; /*!< @ref ETH_Speed */
56     uint32_t    ETH_Mode;  /*!< @ref ETH_Duplex_Mode */
57 
58     uint32_t ETH_HashTableHigh;
59     uint32_t ETH_HashTableLow;
60 };
61 static struct rt_apm32_eth apm32_eth_device;
62 static struct rt_semaphore tx_wait;
63 static rt_bool_t tx_is_waiting = RT_FALSE;
64 
65 #if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
66 #define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
dump_hex(const rt_uint8_t * ptr,rt_size_t buflen)67 static void dump_hex(const rt_uint8_t *ptr, rt_size_t buflen)
68 {
69     unsigned char *buf = (unsigned char *)ptr;
70     int i, j;
71 
72     for (i = 0; i < buflen; i += 16)
73     {
74         rt_kprintf("%08X: ", i);
75 
76         for (j = 0; j < 16; j++)
77             if (i + j < buflen)
78                 rt_kprintf("%02X ", buf[i + j]);
79             else
80                 rt_kprintf("   ");
81         rt_kprintf(" ");
82 
83         for (j = 0; j < 16; j++)
84             if (i + j < buflen)
85                 rt_kprintf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
86         rt_kprintf("\n");
87     }
88 }
89 #endif
90 
91 /* interrupt service routine */
ETH_IRQHandler(void)92 void ETH_IRQHandler(void)
93 {
94     rt_uint32_t status, ier;
95 
96     /* enter interrupt */
97     rt_interrupt_enter();
98 
99     /* ETH DMA status registor */
100     status = ETH->DMASTS;
101     /* ETH DMA interrupt resgitor */
102     ier = ETH->DMAINTEN;
103 
104     if(status & ETH_DMA_INT_MMC)
105     {
106         ETH_ClearDMAIntFlag(ETH_DMA_INT_MMC);
107     }
108 
109     if(status & ETH_DMA_INT_NIS)
110     {
111         rt_uint32_t nis_clear = ETH_DMA_INT_NIS;
112 
113         /* [0]:Transmit Interrupt. */
114         if((status & ier) & ETH_DMA_INT_TX) /* packet transmission */
115         {
116             if (tx_is_waiting == RT_TRUE)
117             {
118                 tx_is_waiting = RT_FALSE;
119                 rt_sem_release(&tx_wait);
120             }
121 
122             nis_clear |= ETH_DMA_INT_TX;
123         }
124 
125         /* [2]:Transmit Buffer Unavailable. */
126 
127         /* [6]:Receive Interrupt. */
128         if((status & ier) & ETH_DMA_INT_RX) /* packet reception */
129         {
130             /* a frame has been received */
131             eth_device_ready(&(apm32_eth_device.parent));
132 
133             nis_clear |= ETH_DMA_INT_RX;
134         }
135 
136         /* [14]:Early Receive Interrupt. */
137 
138         ETH_ClearDMAIntFlag(nis_clear);
139     }
140 
141     if(status & ETH_DMA_INT_AIS)
142     {
143         rt_uint32_t ais_clear = ETH_DMA_INT_AIS;
144 
145         /* [1]:Transmit Process Stopped. */
146         if(status & ETH_DMA_INT_TPS)
147         {
148             ais_clear |= ETH_DMA_INT_TPS;
149         }
150 
151         /* [3]:Transmit Jabber Timeout. */
152         if(status & ETH_DMA_INT_TJT)
153         {
154             ais_clear |= ETH_DMA_INT_TJT;
155         }
156 
157         /* [4]: Receive FIFO Overflow. */
158         if(status & ETH_DMA_INT_RO)
159         {
160             ais_clear |= ETH_DMA_INT_RO;
161         }
162 
163         /* [5]: Transmit Underflow. */
164         if(status & ETH_DMA_INT_TU)
165         {
166             ais_clear |= ETH_DMA_INT_TU;
167         }
168 
169         /* [7]: Receive Buffer Unavailable. */
170         if(status & ETH_DMA_INT_RBU)
171         {
172             ais_clear |= ETH_DMA_INT_RBU;
173         }
174 
175         /* [8]: Receive Process Stopped. */
176         if(status & ETH_DMA_INT_RPS)
177         {
178             ais_clear |= ETH_DMA_INT_RPS;
179         }
180 
181         /* [9]: Receive Watchdog Timeout. */
182         if(status & ETH_DMA_INT_RWT)
183         {
184             ais_clear |= ETH_DMA_INT_RWT;
185         }
186 
187         /* [10]: Early Transmit Interrupt. */
188 
189         /* [13]: Fatal Bus Error. */
190         if(status & ETH_DMA_INT_FBE)
191         {
192             ais_clear |= ETH_DMA_INT_FBE;
193         }
194 
195         ETH_ClearDMAIntFlag(ais_clear);
196     }
197 
198     /* leave interrupt */
199     rt_interrupt_leave();
200 }
201 
202 #if (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD)
203 /* polynomial: 0x04C11DB7 */
ethcrc(const uint8_t * data,size_t length)204 static uint32_t ethcrc(const uint8_t *data, size_t length)
205 {
206     uint32_t crc = 0xffffffff;
207     size_t i;
208     int j;
209 
210     for (i = 0; i < length; i++)
211     {
212         for (j = 0; j < 8; j++)
213         {
214             if (((crc >> 31) ^ (data[i] >> j)) & 0x01)
215             {
216                 /* x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 */
217                 crc = (crc << 1) ^ 0x04C11DB7;
218             }
219             else
220             {
221                 crc = crc << 1;
222             }
223         }
224     }
225 
226     return ~crc;
227 }
228 
229 #define HASH_BITS   6       /* #bits in hash */
register_multicast_address(struct rt_apm32_eth * apm32_eth,const uint8_t * mac)230 static void register_multicast_address(struct rt_apm32_eth *apm32_eth, const uint8_t *mac)
231 {
232     uint32_t crc;
233     uint8_t hash;
234 
235     /* calculate crc32 value of mac address */
236     crc = ethcrc(mac, 6);
237 
238     /* only upper 6 bits (HASH_BITS) are used
239     * which point to specific bit in he hash registers
240     */
241     hash = (crc >> 26) & 0x3F;
242     //rt_kprintf("register_multicast_address crc: %08X hash: %02X\n", crc, hash);
243 
244     if (hash > 31)
245     {
246         apm32_eth->ETH_HashTableHigh |= 1 << (hash - 32);
247         ETH->HTH = apm32_eth->ETH_HashTableHigh;
248     }
249     else
250     {
251         apm32_eth->ETH_HashTableLow |= 1 << hash;
252         ETH->HTL = apm32_eth->ETH_HashTableLow;
253     }
254 }
255 #endif /* (LWIP_IPV4 && LWIP_IGMP) || (LWIP_IPV6 && LWIP_IPV6_MLD) */
256 
257 #if LWIP_IPV4 && LWIP_IGMP
igmp_mac_filter(struct netif * netif,const ip4_addr_t * ip4_addr,enum netif_mac_filter_action action)258 static err_t igmp_mac_filter( struct netif *netif, const ip4_addr_t *ip4_addr, enum netif_mac_filter_action action )
259 {
260     uint8_t mac[6];
261     const uint8_t *p = (const uint8_t *)ip4_addr;
262     struct rt_apm32_eth *apm32_eth = (struct rt_apm32_eth *)netif->state;
263 
264     mac[0] = 0x01;
265     mac[1] = 0x00;
266     mac[2] = 0x5E;
267     mac[3] = *(p+1) & 0x7F;
268     mac[4] = *(p+2);
269     mac[5] = *(p+3);
270 
271     register_multicast_address(apm32_eth, mac);
272 
273     if(1)
274     {
275         rt_kprintf("%s %s %s ", __FUNCTION__, (action==NETIF_ADD_MAC_FILTER)?"add":"del", ip4addr_ntoa(ip4_addr));
276         rt_kprintf("%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
277     }
278 
279     return 0;
280 }
281 #endif /* LWIP_IPV4 && LWIP_IGMP */
282 
283 #if LWIP_IPV6 && LWIP_IPV6_MLD
mld_mac_filter(struct netif * netif,const ip6_addr_t * ip6_addr,enum netif_mac_filter_action action)284 static err_t mld_mac_filter( struct netif *netif, const ip6_addr_t *ip6_addr, enum netif_mac_filter_action action )
285 {
286     uint8_t mac[6];
287     const uint8_t *p = (const uint8_t *)&ip6_addr->addr[3];
288     struct rt_apm32_eth *apm32_eth = (struct rt_apm32_eth *)netif->state;
289 
290     mac[0] = 0x33;
291     mac[1] = 0x33;
292     mac[2] = *(p+0);
293     mac[3] = *(p+1);
294     mac[4] = *(p+2);
295     mac[5] = *(p+3);
296 
297     register_multicast_address(apm32_eth, mac);
298 
299     if(1)
300     {
301         rt_kprintf("%s %s %s ", __FUNCTION__, (action==NETIF_ADD_MAC_FILTER)?"add":"del", ip6addr_ntoa(ip6_addr));
302         rt_kprintf("%02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
303     }
304 
305     return 0;
306 }
307 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
308 
309 /* initialize the interface */
rt_apm32_eth_init(rt_device_t dev)310 static rt_err_t rt_apm32_eth_init(rt_device_t dev)
311 {
312     struct rt_apm32_eth * apm32_eth = (struct rt_apm32_eth *)dev;
313     ETH_Config_T ETH_InitStructure;
314 
315     /* Enable ETHERNET clock  */
316 #if defined(SOC_SERIES_APM32F1)
317     RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_ETH_MAC | RCM_AHB_PERIPH_ETH_MAC_TX |
318                              RCM_AHB_PERIPH_ETH_MAC_RX);
319 #elif defined(SOC_SERIES_APM32F4)
320     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_ETH_MAC | RCM_AHB1_PERIPH_ETH_MAC_Tx |
321                               RCM_AHB1_PERIPH_ETH_MAC_Rx);
322 #endif
323 
324     /* Reset ETHERNET on AHB Bus */
325     ETH_Reset();
326 
327     /* Software reset */
328     ETH_SoftwareReset();
329 
330     /* Wait for software reset */
331     while(ETH_ReadSoftwareReset() == SET);
332 
333     /* ETHERNET Configuration --------------------------------------------------*/
334     /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */
335     ETH_ConfigStructInit(&ETH_InitStructure);
336 
337     /* Fill ETH_InitStructure parametrs */
338     /*------------------------   MAC   -----------------------------------*/
339     ETH_InitStructure.autoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
340     ETH_InitStructure.speed = (ETH_SPEED_T)apm32_eth->ETH_Speed;
341     ETH_InitStructure.mode  = (ETH_MODE_T)apm32_eth->ETH_Mode;
342 
343     ETH_InitStructure.loopbackMode = ETH_LOOPBACKMODE_DISABLE;
344     ETH_InitStructure.retryTransmission = ETH_RETRYTRANSMISSION_DISABLE;
345     ETH_InitStructure.automaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE;
346     ETH_InitStructure.receiveAll = ETH_RECEIVEAll_DISABLE;
347     ETH_InitStructure.broadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE;
348     ETH_InitStructure.promiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE;
349     ETH_InitStructure.multicastFramesFilter = ETH_MULTICASTFRAMESFILTER_HASHTABLE;
350     ETH_InitStructure.hashTableHigh = apm32_eth->ETH_HashTableHigh;
351     ETH_InitStructure.hashTableLow  = apm32_eth->ETH_HashTableLow;
352     ETH_InitStructure.unicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT;
353 #ifdef RT_LWIP_USING_HW_CHECKSUM
354     ETH_InitStructure.checksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE;
355 #endif
356 
357     /*------------------------   DMA   -----------------------------------*/
358 
359     /* When we use the Checksum offload feature, we need to enable the Store and Forward mode:
360     the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum,
361     if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
362     ETH_InitStructure.dropTCPIPChecksumErrorFrame = ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE;
363     ETH_InitStructure.receiveStoreForward = ETH_RECEIVESTOREFORWARD_ENABLE;
364     ETH_InitStructure.flushReceivedFrame = ETH_FLUSHRECEIVEDFRAME_DISABLE;
365     ETH_InitStructure.transmitStoreForward = ETH_TRANSMITSTOREFORWARD_ENABLE;
366 
367     ETH_InitStructure.forwardErrorFrames = ETH_FORWARDERRORFRAMES_DISABLE;
368     ETH_InitStructure.forwardUndersizedGoodFrames = ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE;
369     ETH_InitStructure.secondFrameOperate = ETH_SECONDFRAMEOPERARTE_ENABLE;
370     ETH_InitStructure.addressAlignedBeats = ETH_ADDRESSALIGNEDBEATS_ENABLE;
371     ETH_InitStructure.fixedBurst = ETH_FIXEDBURST_ENABLE;
372     ETH_InitStructure.rxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT;
373     ETH_InitStructure.txDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT;
374     ETH_InitStructure.DMAArbitration = ETH_DMAARBITRATION_ROUNDROBIN_RXTX_2_1;
375 
376     /* configure Ethernet */
377     ETH_Config(&ETH_InitStructure, phy_addr);
378 
379     /* Enable DMA Receive interrupt (need to enable in this case Normal interrupt) */
380     ETH_EnableDMAInterrupt(ETH_DMA_INT_NIS | ETH_DMA_INT_RX | ETH_DMA_INT_TX);
381     NVIC_EnableIRQ(ETH_IRQn);
382 
383     /* Initialize Tx Descriptors list: Chain Mode */
384     ETH_ConfigDMATxDescChain(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
385     /* Initialize Rx Descriptors list: Chain Mode  */
386     ETH_ConfigDMARxDescChain(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
387 
388     /* MAC address configuration */
389     ETH_ConfigMACAddress(ETH_MAC_ADDRESS0, (u8*)&apm32_eth_device.dev_addr[0]);
390 
391     /* Enable MAC and DMA transmission and reception */
392     ETH_Start();
393 
394 #if LWIP_IPV4 && LWIP_IGMP
395     netif_set_igmp_mac_filter(apm32_eth->parent.netif, igmp_mac_filter);
396 #endif /* LWIP_IPV4 && LWIP_IGMP */
397 
398 #if LWIP_IPV6 && LWIP_IPV6_MLD
399     netif_set_mld_mac_filter(apm32_eth->parent.netif, mld_mac_filter);
400 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
401 
402     return RT_EOK;
403 }
404 
rt_apm32_eth_open(rt_device_t dev,rt_uint16_t oflag)405 static rt_err_t rt_apm32_eth_open(rt_device_t dev, rt_uint16_t oflag)
406 {
407     return RT_EOK;
408 }
409 
rt_apm32_eth_close(rt_device_t dev)410 static rt_err_t rt_apm32_eth_close(rt_device_t dev)
411 {
412     return RT_EOK;
413 }
414 
rt_apm32_eth_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)415 static rt_ssize_t rt_apm32_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
416 {
417     rt_set_errno(-RT_ENOSYS);
418     return 0;
419 }
420 
rt_apm32_eth_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)421 static rt_ssize_t rt_apm32_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
422 {
423     rt_set_errno(-RT_ENOSYS);
424     return 0;
425 }
426 
rt_apm32_eth_control(rt_device_t dev,int cmd,void * args)427 static rt_err_t rt_apm32_eth_control(rt_device_t dev, int cmd, void *args)
428 {
429     switch(cmd)
430     {
431     case NIOCTL_GADDR:
432         /* get mac address */
433         if(args) rt_memcpy(args, apm32_eth_device.dev_addr, 6);
434         else return -RT_ERROR;
435         break;
436 
437     default :
438         break;
439     }
440 
441     return RT_EOK;
442 }
443 
444 /* ethernet device interface */
445 /* transmit packet. */
rt_apm32_eth_tx(rt_device_t dev,struct pbuf * p)446 rt_err_t rt_apm32_eth_tx( rt_device_t dev, struct pbuf* p)
447 {
448     struct pbuf* q;
449     rt_uint32_t offset;
450 
451     /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
452     while ((DMATxDescToSet->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)
453     {
454         rt_err_t result;
455         rt_uint32_t level;
456 
457         level = rt_hw_interrupt_disable();
458         tx_is_waiting = RT_TRUE;
459         rt_hw_interrupt_enable(level);
460 
461         /* it's own bit set, wait it */
462         result = rt_sem_take(&tx_wait, RT_WAITING_FOREVER);
463         if (result == RT_EOK) break;
464         if (result == -RT_ERROR) return -RT_ERROR;
465     }
466 
467     offset = 0;
468     for (q = p; q != NULL; q = q->next)
469     {
470         uint8_t *to;
471 
472         /* Copy the frame to be sent into memory pointed by the current ETHERNET DMA Tx descriptor */
473         to = (uint8_t*)((DMATxDescToSet->Buffer1Addr) + offset);
474         SMEMCPY(to, q->payload, q->len);
475         offset += q->len;
476     }
477 #ifdef ETH_TX_DUMP
478     rt_kprintf("tx_dump, len:%d\r\n", p->tot_len);
479     dump_hex((rt_uint8_t*)(DMATxDescToSet->Buffer1Addr), p->tot_len);
480 #endif
481 
482     /* Setting the Frame Length: bits[12:0] */
483     DMATxDescToSet->ControlBufferSize = (p->tot_len & ETH_DMATXDESC_TXBS1);
484     /* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */
485     DMATxDescToSet->Status |= ETH_DMATXDESC_LS | ETH_DMATXDESC_FS;
486     /* Enable TX Completion Interrupt */
487     DMATxDescToSet->Status |= ETH_DMATXDESC_INTC;
488 #ifdef RT_LWIP_USING_HW_CHECKSUM
489     DMATxDescToSet->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL;
490     /* clean ICMP checksum APM32F need */
491     {
492         struct eth_hdr *ethhdr = (struct eth_hdr *)(DMATxDescToSet->Buffer1Addr);
493         /* is IP ? */
494         if( ethhdr->type == htons(ETHTYPE_IP) )
495         {
496             struct ip_hdr *iphdr = (struct ip_hdr *)(DMATxDescToSet->Buffer1Addr + SIZEOF_ETH_HDR);
497             /* is ICMP ? */
498             if( IPH_PROTO(iphdr) == IP_PROTO_ICMP )
499             {
500                 struct icmp_echo_hdr *iecho = (struct icmp_echo_hdr *)(DMATxDescToSet->Buffer1Addr + SIZEOF_ETH_HDR + sizeof(struct ip_hdr) );
501                 iecho->chksum = 0;
502             }
503         }
504     }
505 #endif
506     /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
507     DMATxDescToSet->Status |= ETH_DMATXDESC_OWN;
508     /* When Tx Buffer unavailable flag is set: clear it and resume transmission */
509     if ((ETH->DMASTS & BIT2) != (u32)RESET)
510     {
511         /** Clear TBUS ETHERNET DMA flag */
512         ETH->DMASTS = BIT2;
513         /** Resume DMA transmission*/
514         ETH->DMATXPD = 0;
515     }
516 
517     /* Update the ETHERNET DMA global Tx descriptor with next Tx decriptor */
518     /* Chained Mode */
519     /* Selects the next DMA Tx descriptor list for next buffer to send */
520     DMATxDescToSet = (ETH_DMADescConfig_T*) (DMATxDescToSet->Buffer2NextDescAddr);
521 
522     /* Return SUCCESS */
523     return RT_EOK;
524 }
525 
526 /* reception packet. */
rt_apm32_eth_rx(rt_device_t dev)527 struct pbuf *rt_apm32_eth_rx(rt_device_t dev)
528 {
529     struct pbuf* p;
530     rt_uint32_t offset = 0, framelength = 0;
531 
532     /* init p pointer */
533     p = RT_NULL;
534 
535     /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */
536     if(((DMARxDescToGet->Status & ETH_DMARXDESC_OWN) != (uint32_t)RESET))
537         return p;
538 
539     if (((DMARxDescToGet->Status & ETH_DMARXDESC_ERRS) == (uint32_t)RESET) &&
540             ((DMARxDescToGet->Status & ETH_DMARXDESC_LDES) != (uint32_t)RESET) &&
541             ((DMARxDescToGet->Status & ETH_DMARXDESC_FDES) != (uint32_t)RESET))
542     {
543         /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
544         framelength = ((DMARxDescToGet->Status & ETH_DMARXDESC_FL) >> ETH_DMARXDESC_FRAME_LENGTHSHIFT) - 4;
545 
546         /* allocate buffer */
547         p = pbuf_alloc(PBUF_LINK, framelength, PBUF_RAM);
548         if (p != RT_NULL)
549         {
550             struct pbuf* q;
551 
552             for (q = p; q != RT_NULL; q= q->next)
553             {
554                 /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
555                 SMEMCPY(q->payload, (uint8_t *)((DMARxDescToGet->Buffer1Addr) + offset), q->len);
556                 offset += q->len;
557             }
558 #ifdef ETH_RX_DUMP
559             rt_kprintf("rx_dump, len:%d\r\n", p->tot_len);
560             dump_hex((rt_uint8_t*)(DMARxDescToGet->Buffer1Addr), p->tot_len);
561 #endif
562         }
563     }
564 
565     /* Set Own bit of the Rx descriptor Status: gives the buffer back to ETHERNET DMA */
566     DMARxDescToGet->Status = ETH_DMARXDESC_OWN;
567 
568     /* When Rx Buffer unavailable flag is set: clear it and resume reception */
569     if ((ETH->DMASTS & BIT7) != (u32)RESET)
570     {
571         /* Clear RBUS ETHERNET DMA flag */
572         ETH->DMASTS = BIT7;
573         /* Resume DMA reception */
574         ETH->DMARXPD = 0;
575     }
576 
577     /* Update the ETHERNET DMA global Rx descriptor with next Rx decriptor */
578     /* Chained Mode */
579     if((DMARxDescToGet->ControlBufferSize & ETH_DMARXDESC_RXCH) != (uint32_t)RESET)
580     {
581         /* Selects the next DMA Rx descriptor list for next buffer to read */
582         DMARxDescToGet = (ETH_DMADescConfig_T*) (DMARxDescToGet->Buffer2NextDescAddr);
583     }
584     else /* Ring Mode */
585     {
586         if((DMARxDescToGet->ControlBufferSize & ETH_DMARXDESC_RXER) != (uint32_t)RESET)
587         {
588             /* Selects the first DMA Rx descriptor for next buffer to read: last Rx descriptor was used */
589             DMARxDescToGet = (ETH_DMADescConfig_T*) (ETH->DMARXDLADDR);
590         }
591         else
592         {
593             /* Selects the next DMA Rx descriptor list for next buffer to read */
594             DMARxDescToGet = (ETH_DMADescConfig_T*) ((uint32_t)DMARxDescToGet + 0x10 + ((ETH->DMABMOD & 0x0000007C) >> 2));
595         }
596     }
597 
598     return p;
599 }
600 
601 enum {
602     PHY_LINK        = (1 << 0),
603     PHY_100M        = (1 << 1),
604     PHY_FULL_DUPLEX = (1 << 2),
605 };
606 
phy_linkchange(void)607 static void phy_linkchange(void)
608 {
609     uint8_t phy_speed_new = 0;
610     static uint8_t phy_speed = 0;
611     uint16_t status  = ETH_ReadPHYRegister(phy_addr, PHY_BSR);
612 
613     LOG_D("phy basic status reg is 0x%X", status);
614 
615     if(status & (PHY_AUTONEGO_COMPLETE | PHY_LINKED_STATUS))
616     {
617         uint16_t SR;
618 
619         phy_speed_new |= PHY_LINK;
620 
621         SR = ETH_ReadPHYRegister(phy_addr, PHY_Status_REG);
622         LOG_D("phy control status reg is 0x%X", SR);
623 
624         if (PHY_Status_SPEED_100M(SR))
625         {
626             phy_speed_new |= PHY_100M;
627         }
628 
629         if (PHY_Status_FULL_DUPLEX(SR))
630         {
631             phy_speed_new |= PHY_FULL_DUPLEX;
632         }
633     }
634 
635     /* linkchange */
636     if(phy_speed_new != phy_speed)
637     {
638         if(phy_speed_new & PHY_LINK)
639         {
640             LOG_D("link up ");
641 
642             if(phy_speed_new & PHY_100M)
643             {
644                 LOG_D("100Mbps");
645                 apm32_eth_device.ETH_Speed = ETH_SPEED_100M;
646             }
647             else
648             {
649                 apm32_eth_device.ETH_Speed = ETH_SPEED_10M;
650                 LOG_D("10Mbps");
651             }
652 
653             if(phy_speed_new & PHY_FULL_DUPLEX)
654             {
655                 LOG_D("full-duplex\r\n");
656                 apm32_eth_device.ETH_Mode = ETH_MODE_FULLDUPLEX;
657             }
658             else
659             {
660                 LOG_D("half-duplex\r\n");
661                 apm32_eth_device.ETH_Mode = ETH_MODE_HALFDUPLEX;
662             }
663             rt_apm32_eth_init((rt_device_t)&apm32_eth_device);
664 
665             /* send link up. */
666             eth_device_linkchange(&apm32_eth_device.parent, RT_TRUE);
667         } /* link up. */
668         else
669         {
670             LOG_I("link down\r\n");
671             /* send link down. */
672             eth_device_linkchange(&apm32_eth_device.parent, RT_FALSE);
673         } /* link down. */
674 
675         phy_speed = phy_speed_new;
676     } /* linkchange */
677 }
678 
phy_monitor_thread_entry(void * parameter)679 static void phy_monitor_thread_entry(void *parameter)
680 {
681     uint8_t detected_count = 0;
682 
683     while(phy_addr == 0xFF)
684     {
685         /* phy search */
686         rt_uint32_t i, temp;
687         for (i = 0; i <= 0x1F; i++)
688         {
689             temp = ETH_ReadPHYRegister(i, PHY_ID1_REG);
690 
691             if (temp != 0xFFFF && temp != 0x00)
692             {
693                 phy_addr = i;
694                 break;
695             }
696         }
697 
698         detected_count++;
699         rt_thread_mdelay(1000);
700 
701         if (detected_count > 10)
702         {
703             LOG_E("No PHY device was detected, please check hardware!");
704         }
705     }
706 
707     LOG_D("Found a phy, address:0x%02X", phy_addr);
708 
709     /* RESET PHY */
710     LOG_D("RESET PHY!\r\n");
711     ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_RESET);
712     rt_thread_delay(RT_TICK_PER_SECOND * 2);
713     ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_AUTONEGOTIATION);
714 
715     phy_linkchange();
716 
717     apm32_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
718                                         NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
719     if (!apm32_eth_device.poll_link_timer || rt_timer_start(apm32_eth_device.poll_link_timer) != RT_EOK)
720     {
721         LOG_E("Start link change detection timer failed");
722     }
723 }
724 
rt_hw_apm32_eth_init(void)725 static int rt_hw_apm32_eth_init(void)
726 {
727     /* reset phy */
728     extern void phy_reset(void);
729     phy_reset();
730 
731     /* apm32 eth gpio init */
732     extern void apm32_msp_eth_init(void *instance);
733     apm32_msp_eth_init(RT_NULL);
734 
735     apm32_eth_device.ETH_Speed = ETH_SPEED_100M;
736     apm32_eth_device.ETH_Mode  = ETH_MODE_FULLDUPLEX;
737 
738     /* set mac address. */
739     apm32_eth_device.dev_addr[0] = 0x00;
740     apm32_eth_device.dev_addr[1] = 0x00;
741     apm32_eth_device.dev_addr[2] = 0x00;
742     apm32_eth_device.dev_addr[3] = 0x00;
743     apm32_eth_device.dev_addr[4] = 0x00;
744     apm32_eth_device.dev_addr[5] = 0x08;
745 
746     apm32_eth_device.parent.parent.init       = rt_apm32_eth_init;
747     apm32_eth_device.parent.parent.open       = rt_apm32_eth_open;
748     apm32_eth_device.parent.parent.close      = rt_apm32_eth_close;
749     apm32_eth_device.parent.parent.read       = rt_apm32_eth_read;
750     apm32_eth_device.parent.parent.write      = rt_apm32_eth_write;
751     apm32_eth_device.parent.parent.control    = rt_apm32_eth_control;
752     apm32_eth_device.parent.parent.user_data  = RT_NULL;
753 
754     apm32_eth_device.parent.eth_rx     = rt_apm32_eth_rx;
755     apm32_eth_device.parent.eth_tx     = rt_apm32_eth_tx;
756 
757     /* init tx semaphore */
758     rt_sem_init(&tx_wait, "tx_wait", 0, RT_IPC_FLAG_FIFO);
759 
760     /* register eth device */
761     eth_device_init(&(apm32_eth_device.parent), "e0");
762 
763     /* start phy monitor */
764     {
765         rt_thread_t tid;
766         tid = rt_thread_create("phy",
767                                phy_monitor_thread_entry,
768                                RT_NULL,
769                                512,
770                                RT_THREAD_PRIORITY_MAX - 2,
771                                2);
772         if (tid != RT_NULL)
773             rt_thread_startup(tid);
774     }
775 
776     return RT_EOK;
777 }
778 INIT_DEVICE_EXPORT(rt_hw_apm32_eth_init);
779 
780 #endif /* BSP_USING_ETH */
781