gd32e5xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file gd32e5xx_eth_driver.c
3  * @brief GigaDevice GD32E5 Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "gd32e50x.h"
36 #include "core/net.h"
38 #include "debug.h"
39 
40 //Underlying network interface
41 static NetInterface *nicDriverInterface;
42 
43 //IAR EWARM compiler?
44 #if defined(__ICCARM__)
45 
46 //Transmit buffer
47 #pragma data_alignment = 4
49 //Receive buffer
50 #pragma data_alignment = 4
52 //Transmit DMA descriptors
53 #pragma data_alignment = 4
55 //Receive DMA descriptors
56 #pragma data_alignment = 4
58 
59 //Keil MDK-ARM or GCC compiler?
60 #else
61 
62 //Transmit buffer
64  __attribute__((aligned(4)));
65 //Receive buffer
67  __attribute__((aligned(4)));
68 //Transmit DMA descriptors
70  __attribute__((aligned(4)));
71 //Receive DMA descriptors
73  __attribute__((aligned(4)));
74 
75 #endif
76 
77 //Pointer to the current TX DMA descriptor
78 static Gd32e5xxTxDmaDesc *txCurDmaDesc;
79 //Pointer to the current RX DMA descriptor
80 static Gd32e5xxRxDmaDesc *rxCurDmaDesc;
81 
82 
83 /**
84  * @brief GD32E5XX Ethernet MAC driver
85  **/
86 
88 {
90  ETH_MTU,
101  TRUE,
102  TRUE,
103  TRUE,
104  FALSE
105 };
106 
107 
108 /**
109  * @brief GD32E5XX Ethernet MAC initialization
110  * @param[in] interface Underlying network interface
111  * @return Error code
112  **/
113 
115 {
116  error_t error;
117 
118  //Debug message
119  TRACE_INFO("Initializing GD32E5XX Ethernet MAC...\r\n");
120 
121  //Save underlying network interface
122  nicDriverInterface = interface;
123 
124  //GPIO configuration
125  gd32e5xxEthInitGpio(interface);
126 
127  //Enable Ethernet MAC clock
128  rcu_periph_clock_enable(RCU_ENET);
129  rcu_periph_clock_enable(RCU_ENETTX);
130  rcu_periph_clock_enable(RCU_ENETRX);
131 
132  //Reset Ethernet MAC peripheral
133  rcu_periph_reset_enable(RCU_ENETRST);
134  rcu_periph_reset_disable(RCU_ENETRST);
135 
136  //Perform a software reset
137  ENET_DMA_BCTL |= ENET_DMA_BCTL_SWR;
138  //Wait for the reset to complete
139  while((ENET_DMA_BCTL & ENET_DMA_BCTL_SWR) != 0)
140  {
141  }
142 
143  //Adjust MDC clock range depending on HCLK frequency
144  ENET_MAC_PHY_CTL = ENET_MDC_HCLK_DIV62;
145 
146  //Valid Ethernet PHY or switch driver?
147  if(interface->phyDriver != NULL)
148  {
149  //Ethernet PHY initialization
150  error = interface->phyDriver->init(interface);
151  }
152  else if(interface->switchDriver != NULL)
153  {
154  //Ethernet switch initialization
155  error = interface->switchDriver->init(interface);
156  }
157  else
158  {
159  //The interface is not properly configured
160  error = ERROR_FAILURE;
161  }
162 
163  //Any error to report?
164  if(error)
165  {
166  return error;
167  }
168 
169  //Use default MAC configuration
170  ENET_MAC_CFG = ENET_MAC_CFG_ROD;
171 
172  //Set the MAC address of the station
173  ENET_MAC_ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
174  ENET_MAC_ADDR0H = interface->macAddr.w[2] | ENET_MAC_ADDR0H_MO;
175 
176  //The MAC supports 3 additional addresses for unicast perfect filtering
177  ENET_MAC_ADDR1L = 0;
178  ENET_MAC_ADDR1H = 0;
179  ENET_MAC_ADDR2L = 0;
180  ENET_MAC_ADDT2H = 0;
181  ENET_MAC_ADDR3L = 0;
182  ENET_MAC_ADDR3H = 0;
183 
184  //Initialize hash table
185  ENET_MAC_HLL = 0;
186  ENET_MAC_HLH = 0;
187 
188  //Configure the receive filter
189  ENET_MAC_FRMF = ENET_MAC_FRMF_HPFLT | ENET_MAC_FRMF_HMF;
190  //Disable flow control
191  ENET_MAC_FCTL = 0;
192  //Enable store and forward mode
193  ENET_DMA_CTL = ENET_DMA_CTL_RSFD | ENET_DMA_CTL_TSFD;
194 
195  //Configure DMA bus mode
196  ENET_DMA_BCTL = ENET_DMA_BCTL_AA | ENET_DMA_BCTL_UIP | ENET_RXDP_32BEAT |
197  ENET_ARBITRATION_RXTX_1_1 | ENET_PGBL_32BEAT | ENET_DMA_BCTL_DFM;
198 
199  //Initialize DMA descriptor lists
200  gd32e5xxEthInitDmaDesc(interface);
201 
202  //Prevent interrupts from being generated when the transmit statistic
203  //counters reach half their maximum value
204  ENET_MSC_TINTMSK = ENET_MSC_TINTMSK_TGFIM | ENET_MSC_TINTMSK_TGFMSCIM |
205  ENET_MSC_TINTMSK_TGFSCIM;
206 
207  //Prevent interrupts from being generated when the receive statistic
208  //counters reach half their maximum value
209  ENET_MSC_RINTMSK = ENET_MSC_RINTMSK_RGUFIM | ENET_MSC_RINTMSK_RFAEIM |
210  ENET_MSC_RINTMSK_RFCEIM;
211 
212  //Disable MAC interrupts
213  ENET_MAC_INTMSK = ENET_MAC_INTMSK_TMSTIM | ENET_MAC_INTMSK_WUMIM;
214  //Enable the desired DMA interrupts
215  ENET_DMA_INTEN = ENET_DMA_INTEN_NIE | ENET_DMA_INTEN_RIE | ENET_DMA_INTEN_TIE;
216 
217  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
218  NVIC_SetPriorityGrouping(GD32E5XX_ETH_IRQ_PRIORITY_GROUPING);
219 
220  //Configure Ethernet interrupt priority
221  NVIC_SetPriority(ENET_IRQn, NVIC_EncodePriority(GD32E5XX_ETH_IRQ_PRIORITY_GROUPING,
223 
224  //Enable MAC transmission and reception
225  ENET_MAC_CFG |= ENET_MAC_CFG_TEN | ENET_MAC_CFG_REN;
226  //Enable DMA transmission and reception
227  ENET_DMA_CTL |= ENET_DMA_CTL_STE | ENET_DMA_CTL_SRE;
228 
229  //Accept any packets from the upper layer
230  osSetEvent(&interface->nicTxEvent);
231 
232  //Successful initialization
233  return NO_ERROR;
234 }
235 
236 
237 /**
238  * @brief GPIO configuration
239  * @param[in] interface Underlying network interface
240  **/
241 
242 __weak_func void gd32e5xxEthInitGpio(NetInterface *interface)
243 {
244 //GD32E507Z-EVAL evaluation board?
245 #if defined(USE_GD32E507Z_EVAL)
246  //Enable SYSCFG clock
247  rcu_periph_clock_enable(RCU_AF);
248 
249  //Enable GPIO clocks
250  rcu_periph_clock_enable(RCU_GPIOA);
251  rcu_periph_clock_enable(RCU_GPIOB);
252  rcu_periph_clock_enable(RCU_GPIOC);
253 
254  //Configure CKOUT0 (PA8) as an output
255  gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);
256 
257  //Configure CKOUT0 pin to output the 50MHz reference clock
258  rcu_pll2_config(RCU_PLL2_MUL10);
259  rcu_osci_on(RCU_PLL2_CK);
260  rcu_osci_stab_wait(RCU_PLL2_CK);
261  rcu_ckout0_config(RCU_CKOUT0SRC_CKPLL2);
262 
263  //Select RMII interface mode
264  gpio_ethernet_phy_select(GPIO_ENET_PHY_RMII);
265 
266  //Configure ETH_RMII_REF_CLK (PA1)
267  gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
268  //Configure ETH_MDIO (PA2)
269  gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
270  //Configure ETH_RMII_CRS_DV (PA7)
271  gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
272 
273  //Configure ETH_RMII_TX_EN (PB11)
274  gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
275  //Configure ETH_RMII_TXD0 (PB12)
276  gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
277  //Configure ETH_RMII_TXD1 (PB13)
278  gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
279 
280  //Configure ETH_MDC (PC1)
281  gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
282  //Configure ETH_RMII_RXD0 (PC4)
283  gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
284  //Configure ETH_RMII_RXD1 (PC5)
285  gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
286 #endif
287 }
288 
289 
290 /**
291  * @brief Initialize DMA descriptor lists
292  * @param[in] interface Underlying network interface
293  **/
294 
296 {
297  uint_t i;
298 
299  //Initialize TX DMA descriptor list
300  for(i = 0; i < GD32E5XX_ETH_TX_BUFFER_COUNT; i++)
301  {
302  //Use chain structure rather than ring structure
303  txDmaDesc[i].tdes0 = ENET_TDES0_INTC | ENET_TDES0_TCHM;
304  //Initialize transmit buffer size
305  txDmaDesc[i].tdes1 = 0;
306  //Transmit buffer address
307  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
308  //Next descriptor address
309  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
310  //Reserved fields
311  txDmaDesc[i].tdes4 = 0;
312  txDmaDesc[i].tdes5 = 0;
313  //Transmit frame time stamp
314  txDmaDesc[i].tdes6 = 0;
315  txDmaDesc[i].tdes7 = 0;
316  }
317 
318  //The last descriptor is chained to the first entry
319  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
320  //Point to the very first descriptor
321  txCurDmaDesc = &txDmaDesc[0];
322 
323  //Initialize RX DMA descriptor list
324  for(i = 0; i < GD32E5XX_ETH_RX_BUFFER_COUNT; i++)
325  {
326  //The descriptor is initially owned by the DMA
327  rxDmaDesc[i].rdes0 = ENET_RDES0_DAV;
328  //Use chain structure rather than ring structure
329  rxDmaDesc[i].rdes1 = ENET_RDES1_RCHM | (GD32E5XX_ETH_RX_BUFFER_SIZE & ENET_RDES1_RB1S);
330  //Receive buffer address
331  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
332  //Next descriptor address
333  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
334  //Extended status
335  rxDmaDesc[i].rdes4 = 0;
336  //Reserved field
337  rxDmaDesc[i].rdes5 = 0;
338  //Receive frame time stamp
339  rxDmaDesc[i].rdes6 = 0;
340  rxDmaDesc[i].rdes7 = 0;
341  }
342 
343  //The last descriptor is chained to the first entry
344  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
345  //Point to the very first descriptor
346  rxCurDmaDesc = &rxDmaDesc[0];
347 
348  //Start location of the TX descriptor list
349  ENET_DMA_TDTADDR = (uint32_t) txDmaDesc;
350  //Start location of the RX descriptor list
351  ENET_DMA_RDTADDR = (uint32_t) rxDmaDesc;
352 }
353 
354 
355 /**
356  * @brief GD32E5XX Ethernet MAC timer handler
357  *
358  * This routine is periodically called by the TCP/IP stack to handle periodic
359  * operations such as polling the link state
360  *
361  * @param[in] interface Underlying network interface
362  **/
363 
365 {
366  //Valid Ethernet PHY or switch driver?
367  if(interface->phyDriver != NULL)
368  {
369  //Handle periodic operations
370  interface->phyDriver->tick(interface);
371  }
372  else if(interface->switchDriver != NULL)
373  {
374  //Handle periodic operations
375  interface->switchDriver->tick(interface);
376  }
377  else
378  {
379  //Just for sanity
380  }
381 }
382 
383 
384 /**
385  * @brief Enable interrupts
386  * @param[in] interface Underlying network interface
387  **/
388 
390 {
391  //Enable Ethernet MAC interrupts
392  NVIC_EnableIRQ(ENET_IRQn);
393 
394  //Valid Ethernet PHY or switch driver?
395  if(interface->phyDriver != NULL)
396  {
397  //Enable Ethernet PHY interrupts
398  interface->phyDriver->enableIrq(interface);
399  }
400  else if(interface->switchDriver != NULL)
401  {
402  //Enable Ethernet switch interrupts
403  interface->switchDriver->enableIrq(interface);
404  }
405  else
406  {
407  //Just for sanity
408  }
409 }
410 
411 
412 /**
413  * @brief Disable interrupts
414  * @param[in] interface Underlying network interface
415  **/
416 
418 {
419  //Disable Ethernet MAC interrupts
420  NVIC_DisableIRQ(ENET_IRQn);
421 
422  //Valid Ethernet PHY or switch driver?
423  if(interface->phyDriver != NULL)
424  {
425  //Disable Ethernet PHY interrupts
426  interface->phyDriver->disableIrq(interface);
427  }
428  else if(interface->switchDriver != NULL)
429  {
430  //Disable Ethernet switch interrupts
431  interface->switchDriver->disableIrq(interface);
432  }
433  else
434  {
435  //Just for sanity
436  }
437 }
438 
439 
440 /**
441  * @brief GD32E5XX Ethernet MAC interrupt service routine
442  **/
443 
444 void ENET_IRQHandler(void)
445 {
446  bool_t flag;
447  uint32_t status;
448 
449  //Interrupt service routine prologue
450  osEnterIsr();
451 
452  //This flag will be set if a higher priority task must be woken
453  flag = FALSE;
454 
455  //Read DMA status register
456  status = ENET_DMA_STAT;
457 
458  //Packet transmitted?
459  if((status & ENET_DMA_STAT_TS) != 0)
460  {
461  //Clear TS interrupt flag
462  ENET_DMA_STAT = ENET_DMA_STAT_TS;
463 
464  //Check whether the TX buffer is available for writing
465  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) == 0)
466  {
467  //Notify the TCP/IP stack that the transmitter is ready to send
468  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
469  }
470  }
471 
472  //Packet received?
473  if((status & ENET_DMA_STAT_RS) != 0)
474  {
475  //Clear RS interrupt flag
476  ENET_DMA_STAT = ENET_DMA_STAT_RS;
477 
478  //Set event flag
479  nicDriverInterface->nicEvent = TRUE;
480  //Notify the TCP/IP stack of the event
481  flag |= osSetEventFromIsr(&netEvent);
482  }
483 
484  //Clear NIS interrupt flag
485  ENET_DMA_STAT = ENET_DMA_STAT_NI;
486 
487  //Interrupt service routine epilogue
488  osExitIsr(flag);
489 }
490 
491 
492 /**
493  * @brief GD32E5XX Ethernet MAC event handler
494  * @param[in] interface Underlying network interface
495  **/
496 
498 {
499  error_t error;
500 
501  //Process all pending packets
502  do
503  {
504  //Read incoming packet
505  error = gd32e5xxEthReceivePacket(interface);
506 
507  //No more data in the receive buffer?
508  } while(error != ERROR_BUFFER_EMPTY);
509 }
510 
511 
512 /**
513  * @brief Send a packet
514  * @param[in] interface Underlying network interface
515  * @param[in] buffer Multi-part buffer containing the data to send
516  * @param[in] offset Offset to the first data byte
517  * @param[in] ancillary Additional options passed to the stack along with
518  * the packet
519  * @return Error code
520  **/
521 
523  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
524 {
525  size_t length;
526 
527  //Retrieve the length of the packet
528  length = netBufferGetLength(buffer) - offset;
529 
530  //Check the frame length
532  {
533  //The transmitter can accept another packet
534  osSetEvent(&interface->nicTxEvent);
535  //Report an error
536  return ERROR_INVALID_LENGTH;
537  }
538 
539  //Make sure the current buffer is available for writing
540  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) != 0)
541  {
542  return ERROR_FAILURE;
543  }
544 
545  //Copy user data to the transmit buffer
546  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
547 
548  //Write the number of bytes to send
549  txCurDmaDesc->tdes1 = length & ENET_TDES1_TB1S;
550  //Set LS and FS flags as the data fits in a single buffer
551  txCurDmaDesc->tdes0 |= ENET_TDES0_LSG | ENET_TDES0_FSG;
552  //Give the ownership of the descriptor to the DMA
553  txCurDmaDesc->tdes0 |= ENET_TDES0_DAV;
554 
555  //Data synchronization barrier
556  __DSB();
557 
558  //Clear TBU flag to resume processing
559  ENET_DMA_STAT = ENET_DMA_STAT_TBU;
560  //Instruct the DMA to poll the transmit descriptor list
561  ENET_DMA_TPEN = 0;
562 
563  //Point to the next descriptor in the list
564  txCurDmaDesc = (Gd32e5xxTxDmaDesc *) txCurDmaDesc->tdes3;
565 
566  //Check whether the next buffer is available for writing
567  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) == 0)
568  {
569  //The transmitter can accept another packet
570  osSetEvent(&interface->nicTxEvent);
571  }
572 
573  //Data successfully written
574  return NO_ERROR;
575 }
576 
577 
578 /**
579  * @brief Receive a packet
580  * @param[in] interface Underlying network interface
581  * @return Error code
582  **/
583 
585 {
586  error_t error;
587  size_t n;
588  NetRxAncillary ancillary;
589 
590  //Current buffer available for reading?
591  if((rxCurDmaDesc->rdes0 & ENET_RDES0_DAV) == 0)
592  {
593  //FS and LS flags should be set
594  if((rxCurDmaDesc->rdes0 & ENET_RDES0_FDES) != 0 &&
595  (rxCurDmaDesc->rdes0 & ENET_RDES0_LDES) != 0)
596  {
597  //Make sure no error occurred
598  if((rxCurDmaDesc->rdes0 & ENET_RDES0_ERRS) == 0)
599  {
600  //Retrieve the length of the frame
601  n = (rxCurDmaDesc->rdes0 & ENET_RDES0_FRML) >> 16;
602  //Limit the number of data to read
604 
605  //Additional options can be passed to the stack along with the packet
606  ancillary = NET_DEFAULT_RX_ANCILLARY;
607 
608  //Pass the packet to the upper layer
609  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
610  &ancillary);
611 
612  //Valid packet received
613  error = NO_ERROR;
614  }
615  else
616  {
617  //The received packet contains an error
618  error = ERROR_INVALID_PACKET;
619  }
620  }
621  else
622  {
623  //The packet is not valid
624  error = ERROR_INVALID_PACKET;
625  }
626 
627  //Give the ownership of the descriptor back to the DMA
628  rxCurDmaDesc->rdes0 = ENET_RDES0_DAV;
629  //Point to the next descriptor in the list
630  rxCurDmaDesc = (Gd32e5xxRxDmaDesc *) rxCurDmaDesc->rdes3;
631  }
632  else
633  {
634  //No more data in the receive buffer
635  error = ERROR_BUFFER_EMPTY;
636  }
637 
638  //Clear RBU flag to resume processing
639  ENET_DMA_STAT = ENET_DMA_STAT_RBU;
640  //Instruct the DMA to poll the receive descriptor list
641  ENET_DMA_RPEN = 0;
642 
643  //Return status code
644  return error;
645 }
646 
647 
648 /**
649  * @brief Configure MAC address filtering
650  * @param[in] interface Underlying network interface
651  * @return Error code
652  **/
653 
655 {
656  uint_t i;
657  uint_t j;
658  uint_t k;
659  uint32_t crc;
660  uint32_t hashTable[2];
661  MacAddr unicastMacAddr[3];
662  MacFilterEntry *entry;
663 
664  //Debug message
665  TRACE_DEBUG("Updating MAC filter...\r\n");
666 
667  //Set the MAC address of the station
668  ENET_MAC_ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
669  ENET_MAC_ADDR0H = interface->macAddr.w[2] | ENET_MAC_ADDR0H_MO;
670 
671  //The MAC supports 3 additional addresses for unicast perfect filtering
672  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
673  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
674  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
675 
676  //The hash table is used for multicast address filtering
677  hashTable[0] = 0;
678  hashTable[1] = 0;
679 
680  //The MAC address filter contains the list of MAC addresses to accept
681  //when receiving an Ethernet frame
682  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
683  {
684  //Point to the current entry
685  entry = &interface->macAddrFilter[i];
686 
687  //Valid entry?
688  if(entry->refCount > 0)
689  {
690  //Multicast address?
691  if(macIsMulticastAddr(&entry->addr))
692  {
693  //Compute CRC over the current MAC address
694  crc = gd32e5xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
695 
696  //The upper 6 bits in the CRC register are used to index the
697  //contents of the hash table
698  k = (crc >> 26) & 0x3F;
699 
700  //Update hash table contents
701  hashTable[k / 32] |= (1 << (k % 32));
702  }
703  else
704  {
705  //Up to 3 additional MAC addresses can be specified
706  if(j < 3)
707  {
708  //Save the unicast address
709  unicastMacAddr[j++] = entry->addr;
710  }
711  }
712  }
713  }
714 
715  //Configure the first unicast address filter
716  if(j >= 1)
717  {
718  //When the AE bit is set, the entry is used for perfect filtering
719  ENET_MAC_ADDR1L = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
720  ENET_MAC_ADDR1H = unicastMacAddr[0].w[2] | ENET_MAC_ADDR1H_AFE;
721  }
722  else
723  {
724  //When the AE bit is cleared, the entry is ignored
725  ENET_MAC_ADDR1L = 0;
726  ENET_MAC_ADDR1H = 0;
727  }
728 
729  //Configure the second unicast address filter
730  if(j >= 2)
731  {
732  //When the AE bit is set, the entry is used for perfect filtering
733  ENET_MAC_ADDR2L = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
734  ENET_MAC_ADDT2H = unicastMacAddr[1].w[2] | ENET_MAC_ADDR2H_AFE;
735  }
736  else
737  {
738  //When the AE bit is cleared, the entry is ignored
739  ENET_MAC_ADDR2L = 0;
740  ENET_MAC_ADDT2H = 0;
741  }
742 
743  //Configure the third unicast address filter
744  if(j >= 3)
745  {
746  //When the AE bit is set, the entry is used for perfect filtering
747  ENET_MAC_ADDR3L = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
748  ENET_MAC_ADDR3H = unicastMacAddr[2].w[2] | ENET_MAC_ADDR3H_AFE;
749  }
750  else
751  {
752  //When the AE bit is cleared, the entry is ignored
753  ENET_MAC_ADDR3L = 0;
754  ENET_MAC_ADDR3H = 0;
755  }
756 
757  //Configure the multicast hash table
758  ENET_MAC_HLL = hashTable[0];
759  ENET_MAC_HLH = hashTable[1];
760 
761  //Debug message
762  TRACE_DEBUG(" ENET_MAC_HLL = %08" PRIX32 "\r\n", ENET_MAC_HLL);
763  TRACE_DEBUG(" ENET_MAC_HLH = %08" PRIX32 "\r\n", ENET_MAC_HLH);
764 
765  //Successful processing
766  return NO_ERROR;
767 }
768 
769 
770 /**
771  * @brief Adjust MAC configuration parameters for proper operation
772  * @param[in] interface Underlying network interface
773  * @return Error code
774  **/
775 
777 {
778  uint32_t config;
779 
780  //Read current MAC configuration
781  config = ENET_MAC_CFG;
782 
783  //10BASE-T or 100BASE-TX operation mode?
784  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
785  {
786  config |= ENET_MAC_CFG_SPD;
787  }
788  else
789  {
790  config &= ~ENET_MAC_CFG_SPD;
791  }
792 
793  //Half-duplex or full-duplex mode?
794  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
795  {
796  config |= ENET_MAC_CFG_DPM;
797  }
798  else
799  {
800  config &= ~ENET_MAC_CFG_DPM;
801  }
802 
803  //Update MAC configuration register
804  ENET_MAC_CFG = config;
805 
806  //Successful processing
807  return NO_ERROR;
808 }
809 
810 
811 /**
812  * @brief Write PHY register
813  * @param[in] opcode Access type (2 bits)
814  * @param[in] phyAddr PHY address (5 bits)
815  * @param[in] regAddr Register address (5 bits)
816  * @param[in] data Register value
817  **/
818 
819 void gd32e5xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
820  uint8_t regAddr, uint16_t data)
821 {
822  uint32_t temp;
823 
824  //Valid opcode?
825  if(opcode == SMI_OPCODE_WRITE)
826  {
827  //Take care not to alter MDC clock configuration
828  temp = ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_CLR;
829  //Set up a write operation
830  temp |= ENET_MAC_PHY_CTL_PW | ENET_MAC_PHY_CTL_PB;
831  //PHY address
832  temp |= MAC_PHY_CTL_PA(phyAddr);
833  //Register address
834  temp |= MAC_PHY_CTL_PR(regAddr);
835 
836  //Data to be written in the PHY register
837  ENET_MAC_PHY_DATA = data & ENET_MAC_PHY_DATA_PD;
838 
839  //Start a write operation
840  ENET_MAC_PHY_CTL = temp;
841  //Wait for the write to complete
842  while((ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_PB) != 0)
843  {
844  }
845  }
846  else
847  {
848  //The MAC peripheral only supports standard Clause 22 opcodes
849  }
850 }
851 
852 
853 /**
854  * @brief Read PHY register
855  * @param[in] opcode Access type (2 bits)
856  * @param[in] phyAddr PHY address (5 bits)
857  * @param[in] regAddr Register address (5 bits)
858  * @return Register value
859  **/
860 
861 uint16_t gd32e5xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
862  uint8_t regAddr)
863 {
864  uint16_t data;
865  uint32_t temp;
866 
867  //Valid opcode?
868  if(opcode == SMI_OPCODE_READ)
869  {
870  //Take care not to alter MDC clock configuration
871  temp = ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_CLR;
872  //Set up a read operation
873  temp |= ENET_MAC_PHY_CTL_PB;
874  //PHY address
875  temp |= MAC_PHY_CTL_PA(phyAddr);
876  //Register address
877  temp |= MAC_PHY_CTL_PR(regAddr);
878 
879  //Start a read operation
880  ENET_MAC_PHY_CTL = temp;
881  //Wait for the read to complete
882  while((ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_PB) != 0)
883  {
884  }
885 
886  //Get register value
887  data = ENET_MAC_PHY_DATA & ENET_MAC_PHY_DATA_PD;
888  }
889  else
890  {
891  //The MAC peripheral only supports standard Clause 22 opcodes
892  data = 0;
893  }
894 
895  //Return the value of the PHY register
896  return data;
897 }
898 
899 
900 /**
901  * @brief CRC calculation
902  * @param[in] data Pointer to the data over which to calculate the CRC
903  * @param[in] length Number of bytes to process
904  * @return Resulting CRC value
905  **/
906 
907 uint32_t gd32e5xxEthCalcCrc(const void *data, size_t length)
908 {
909  uint_t i;
910  uint_t j;
911  uint32_t crc;
912  const uint8_t *p;
913 
914  //Point to the data over which to calculate the CRC
915  p = (uint8_t *) data;
916  //CRC preset value
917  crc = 0xFFFFFFFF;
918 
919  //Loop through data
920  for(i = 0; i < length; i++)
921  {
922  //The message is processed bit by bit
923  for(j = 0; j < 8; j++)
924  {
925  //Update CRC value
926  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
927  {
928  crc = (crc << 1) ^ 0x04C11DB7;
929  }
930  else
931  {
932  crc = crc << 1;
933  }
934  }
935  }
936 
937  //Return CRC value
938  return ~crc;
939 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
Enhanced TX DMA descriptor.
#define GD32E5XX_ETH_RX_BUFFER_COUNT
uint8_t opcode
Definition: dns_common.h:188
#define GD32E5XX_ETH_IRQ_SUB_PRIORITY
int bool_t
Definition: compiler_port.h:53
#define netEvent
Definition: net_legacy.h:196
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:690
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define GD32E5XX_ETH_RX_BUFFER_SIZE
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
GigaDevice GD32E5 Ethernet MAC driver.
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
void gd32e5xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:392
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define osExitIsr(flag)
void ENET_IRQHandler(void)
GD32E5XX Ethernet MAC interrupt service routine.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
error_t gd32e5xxEthInit(NetInterface *interface)
GD32E5XX Ethernet MAC initialization.
#define FALSE
Definition: os_port.h:46
error_t gd32e5xxEthReceivePacket(NetInterface *interface)
Receive a packet.
error_t
Error codes.
Definition: error.h:43
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:104
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define txBuffer
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:140
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:263
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
error_t gd32e5xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void gd32e5xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
__weak_func void gd32e5xxEthInitGpio(NetInterface *interface)
GPIO configuration.
#define NetTxAncillary
Definition: net_misc.h:36
#define GD32E5XX_ETH_TX_BUFFER_SIZE
#define SMI_OPCODE_READ
Definition: nic.h:67
error_t gd32e5xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
const NicDriver gd32e5xxEthDriver
GD32E5XX Ethernet MAC driver.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MIN(a, b)
Definition: os_port.h:63
#define rxBuffer
MacAddr
Definition: ethernet.h:195
void gd32e5xxEthTick(NetInterface *interface)
GD32E5XX Ethernet MAC timer handler.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define GD32E5XX_ETH_TX_BUFFER_COUNT
#define GD32E5XX_ETH_IRQ_GROUP_PRIORITY
uint32_t gd32e5xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
uint16_t regAddr
void gd32e5xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
MAC filter table entry.
Definition: ethernet.h:262
#define osEnterIsr()
void gd32e5xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
#define rxDmaDesc
Enhanced RX DMA descriptor.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define txDmaDesc
void gd32e5xxEthEventHandler(NetInterface *interface)
GD32E5XX Ethernet MAC event handler.
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
NIC driver.
Definition: nic.h:286
uint16_t gd32e5xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
error_t gd32e5xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
#define GD32E5XX_ETH_IRQ_PRIORITY_GROUPING
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83