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(Ð_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(Ð_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