gd32f4xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file gd32f4xx_eth_driver.c
3  * @brief GigaDevice GD32F4 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.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "gd32f4xx.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 Gd32f4xxTxDmaDesc *txCurDmaDesc;
79 //Pointer to the current RX DMA descriptor
80 static Gd32f4xxRxDmaDesc *rxCurDmaDesc;
81 
82 
83 /**
84  * @brief GD32F4XX Ethernet MAC driver
85  **/
86 
88 {
90  ETH_MTU,
101  TRUE,
102  TRUE,
103  TRUE,
104  FALSE
105 };
106 
107 
108 /**
109  * @brief GD32F4XX 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 GD32F4XX Ethernet MAC...\r\n");
120 
121  //Save underlying network interface
122  nicDriverInterface = interface;
123 
124  //GPIO configuration
125  gd32f4xxEthInitGpio(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  gd32f4xxEthInitDmaDesc(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(GD32F4XX_ETH_IRQ_PRIORITY_GROUPING);
219 
220  //Configure Ethernet interrupt priority
221  NVIC_SetPriority(ENET_IRQn, NVIC_EncodePriority(GD32F4XX_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 gd32f4xxEthInitGpio(NetInterface *interface)
243 {
244 //GD32F470I-EVAL or GD32F470Z-EVAL evaluation board?
245 #if defined(USE_GD32F470I_EVAL) || defined(USE_GD32F470Z_EVAL)
246  //Enable SYSCFG clock
247  rcu_periph_clock_enable(RCU_SYSCFG);
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_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
256  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_8);
257  gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_8);
258 
259  //Configure CKOUT0 pin to output the 50MHz reference clock
260  rcu_ckout0_config(RCU_CKOUT0SRC_PLLP, RCU_CKOUT0_DIV4);
261 
262  //Select RMII interface mode
263  syscfg_enet_phy_interface_config(SYSCFG_ENET_PHY_RMII);
264 
265  //Configure ETH_RMII_REF_CLK (PA1)
266  gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
267  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_1);
268  gpio_af_set(GPIOA, GPIO_AF_11, GPIO_PIN_1);
269 
270  //Configure ETH_MDIO (PA2)
271  gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
272  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_2);
273  gpio_af_set(GPIOA, GPIO_AF_11, GPIO_PIN_2);
274 
275  //Configure ETH_RMII_CRS_DV (PA7)
276  gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
277  gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_7);
278  gpio_af_set(GPIOA, GPIO_AF_11, GPIO_PIN_7);
279 
280  //Configure ETH_RMII_TX_EN (PB11)
281  gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
282  gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_11);
283  gpio_af_set(GPIOB, GPIO_AF_11, GPIO_PIN_11);
284 
285  //Configure ETH_RMII_TXD0 (PB12)
286  gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
287  gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_12);
288  gpio_af_set(GPIOB, GPIO_AF_11, GPIO_PIN_12);
289 
290  //Configure ETH_RMII_TXD1 (PB13)
291  gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
292  gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_13);
293  gpio_af_set(GPIOB, GPIO_AF_11, GPIO_PIN_13);
294 
295  //Configure ETH_MDC (PC1)
296  gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
297  gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_1);
298  gpio_af_set(GPIOC, GPIO_AF_11, GPIO_PIN_1);
299 
300  //Configure ETH_RMII_RXD0 (PC4)
301  gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4);
302  gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);
303  gpio_af_set(GPIOC, GPIO_AF_11, GPIO_PIN_4);
304 
305  //Configure ETH_RMII_RXD1 (PC5)
306  gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
307  gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);
308  gpio_af_set(GPIOC, GPIO_AF_11, GPIO_PIN_5);
309 #endif
310 }
311 
312 
313 /**
314  * @brief Initialize DMA descriptor lists
315  * @param[in] interface Underlying network interface
316  **/
317 
319 {
320  uint_t i;
321 
322  //Initialize TX DMA descriptor list
323  for(i = 0; i < GD32F4XX_ETH_TX_BUFFER_COUNT; i++)
324  {
325  //Use chain structure rather than ring structure
326  txDmaDesc[i].tdes0 = ENET_TDES0_INTC | ENET_TDES0_TCHM;
327  //Initialize transmit buffer size
328  txDmaDesc[i].tdes1 = 0;
329  //Transmit buffer address
330  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
331  //Next descriptor address
332  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
333  //Reserved fields
334  txDmaDesc[i].tdes4 = 0;
335  txDmaDesc[i].tdes5 = 0;
336  //Transmit frame time stamp
337  txDmaDesc[i].tdes6 = 0;
338  txDmaDesc[i].tdes7 = 0;
339  }
340 
341  //The last descriptor is chained to the first entry
342  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
343  //Point to the very first descriptor
344  txCurDmaDesc = &txDmaDesc[0];
345 
346  //Initialize RX DMA descriptor list
347  for(i = 0; i < GD32F4XX_ETH_RX_BUFFER_COUNT; i++)
348  {
349  //The descriptor is initially owned by the DMA
350  rxDmaDesc[i].rdes0 = ENET_RDES0_DAV;
351  //Use chain structure rather than ring structure
352  rxDmaDesc[i].rdes1 = ENET_RDES1_RCHM | (GD32F4XX_ETH_RX_BUFFER_SIZE & ENET_RDES1_RB1S);
353  //Receive buffer address
354  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
355  //Next descriptor address
356  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
357  //Extended status
358  rxDmaDesc[i].rdes4 = 0;
359  //Reserved field
360  rxDmaDesc[i].rdes5 = 0;
361  //Receive frame time stamp
362  rxDmaDesc[i].rdes6 = 0;
363  rxDmaDesc[i].rdes7 = 0;
364  }
365 
366  //The last descriptor is chained to the first entry
367  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
368  //Point to the very first descriptor
369  rxCurDmaDesc = &rxDmaDesc[0];
370 
371  //Start location of the TX descriptor list
372  ENET_DMA_TDTADDR = (uint32_t) txDmaDesc;
373  //Start location of the RX descriptor list
374  ENET_DMA_RDTADDR = (uint32_t) rxDmaDesc;
375 }
376 
377 
378 /**
379  * @brief GD32F4XX Ethernet MAC timer handler
380  *
381  * This routine is periodically called by the TCP/IP stack to handle periodic
382  * operations such as polling the link state
383  *
384  * @param[in] interface Underlying network interface
385  **/
386 
388 {
389  //Valid Ethernet PHY or switch driver?
390  if(interface->phyDriver != NULL)
391  {
392  //Handle periodic operations
393  interface->phyDriver->tick(interface);
394  }
395  else if(interface->switchDriver != NULL)
396  {
397  //Handle periodic operations
398  interface->switchDriver->tick(interface);
399  }
400  else
401  {
402  //Just for sanity
403  }
404 }
405 
406 
407 /**
408  * @brief Enable interrupts
409  * @param[in] interface Underlying network interface
410  **/
411 
413 {
414  //Enable Ethernet MAC interrupts
415  NVIC_EnableIRQ(ENET_IRQn);
416 
417  //Valid Ethernet PHY or switch driver?
418  if(interface->phyDriver != NULL)
419  {
420  //Enable Ethernet PHY interrupts
421  interface->phyDriver->enableIrq(interface);
422  }
423  else if(interface->switchDriver != NULL)
424  {
425  //Enable Ethernet switch interrupts
426  interface->switchDriver->enableIrq(interface);
427  }
428  else
429  {
430  //Just for sanity
431  }
432 }
433 
434 
435 /**
436  * @brief Disable interrupts
437  * @param[in] interface Underlying network interface
438  **/
439 
441 {
442  //Disable Ethernet MAC interrupts
443  NVIC_DisableIRQ(ENET_IRQn);
444 
445  //Valid Ethernet PHY or switch driver?
446  if(interface->phyDriver != NULL)
447  {
448  //Disable Ethernet PHY interrupts
449  interface->phyDriver->disableIrq(interface);
450  }
451  else if(interface->switchDriver != NULL)
452  {
453  //Disable Ethernet switch interrupts
454  interface->switchDriver->disableIrq(interface);
455  }
456  else
457  {
458  //Just for sanity
459  }
460 }
461 
462 
463 /**
464  * @brief GD32F4XX Ethernet MAC interrupt service routine
465  **/
466 
467 void ENET_IRQHandler(void)
468 {
469  bool_t flag;
470  uint32_t status;
471 
472  //Interrupt service routine prologue
473  osEnterIsr();
474 
475  //This flag will be set if a higher priority task must be woken
476  flag = FALSE;
477 
478  //Read DMA status register
479  status = ENET_DMA_STAT;
480 
481  //Packet transmitted?
482  if((status & ENET_DMA_STAT_TS) != 0)
483  {
484  //Clear TS interrupt flag
485  ENET_DMA_STAT = ENET_DMA_STAT_TS;
486 
487  //Check whether the TX buffer is available for writing
488  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) == 0)
489  {
490  //Notify the TCP/IP stack that the transmitter is ready to send
491  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
492  }
493  }
494 
495  //Packet received?
496  if((status & ENET_DMA_STAT_RS) != 0)
497  {
498  //Clear RS interrupt flag
499  ENET_DMA_STAT = ENET_DMA_STAT_RS;
500 
501  //Set event flag
502  nicDriverInterface->nicEvent = TRUE;
503  //Notify the TCP/IP stack of the event
504  flag |= osSetEventFromIsr(&netEvent);
505  }
506 
507  //Clear NIS interrupt flag
508  ENET_DMA_STAT = ENET_DMA_STAT_NI;
509 
510  //Interrupt service routine epilogue
511  osExitIsr(flag);
512 }
513 
514 
515 /**
516  * @brief GD32F4XX Ethernet MAC event handler
517  * @param[in] interface Underlying network interface
518  **/
519 
521 {
522  error_t error;
523 
524  //Process all pending packets
525  do
526  {
527  //Read incoming packet
528  error = gd32f4xxEthReceivePacket(interface);
529 
530  //No more data in the receive buffer?
531  } while(error != ERROR_BUFFER_EMPTY);
532 }
533 
534 
535 /**
536  * @brief Send a packet
537  * @param[in] interface Underlying network interface
538  * @param[in] buffer Multi-part buffer containing the data to send
539  * @param[in] offset Offset to the first data byte
540  * @param[in] ancillary Additional options passed to the stack along with
541  * the packet
542  * @return Error code
543  **/
544 
546  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
547 {
548  size_t length;
549 
550  //Retrieve the length of the packet
551  length = netBufferGetLength(buffer) - offset;
552 
553  //Check the frame length
555  {
556  //The transmitter can accept another packet
557  osSetEvent(&interface->nicTxEvent);
558  //Report an error
559  return ERROR_INVALID_LENGTH;
560  }
561 
562  //Make sure the current buffer is available for writing
563  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) != 0)
564  {
565  return ERROR_FAILURE;
566  }
567 
568  //Copy user data to the transmit buffer
569  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
570 
571  //Write the number of bytes to send
572  txCurDmaDesc->tdes1 = length & ENET_TDES1_TB1S;
573  //Set LS and FS flags as the data fits in a single buffer
574  txCurDmaDesc->tdes0 |= ENET_TDES0_LSG | ENET_TDES0_FSG;
575  //Give the ownership of the descriptor to the DMA
576  txCurDmaDesc->tdes0 |= ENET_TDES0_DAV;
577 
578  //Clear TBU flag to resume processing
579  ENET_DMA_STAT = ENET_DMA_STAT_TBU;
580  //Instruct the DMA to poll the transmit descriptor list
581  ENET_DMA_TPEN = 0;
582 
583  //Point to the next descriptor in the list
584  txCurDmaDesc = (Gd32f4xxTxDmaDesc *) txCurDmaDesc->tdes3;
585 
586  //Check whether the next buffer is available for writing
587  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) == 0)
588  {
589  //The transmitter can accept another packet
590  osSetEvent(&interface->nicTxEvent);
591  }
592 
593  //Data successfully written
594  return NO_ERROR;
595 }
596 
597 
598 /**
599  * @brief Receive a packet
600  * @param[in] interface Underlying network interface
601  * @return Error code
602  **/
603 
605 {
606  error_t error;
607  size_t n;
608  NetRxAncillary ancillary;
609 
610  //Current buffer available for reading?
611  if((rxCurDmaDesc->rdes0 & ENET_RDES0_DAV) == 0)
612  {
613  //FS and LS flags should be set
614  if((rxCurDmaDesc->rdes0 & ENET_RDES0_FDES) != 0 &&
615  (rxCurDmaDesc->rdes0 & ENET_RDES0_LDES) != 0)
616  {
617  //Make sure no error occurred
618  if((rxCurDmaDesc->rdes0 & ENET_RDES0_ERRS) == 0)
619  {
620  //Retrieve the length of the frame
621  n = (rxCurDmaDesc->rdes0 & ENET_RDES0_FRML) >> 16;
622  //Limit the number of data to read
624 
625  //Additional options can be passed to the stack along with the packet
626  ancillary = NET_DEFAULT_RX_ANCILLARY;
627 
628  //Pass the packet to the upper layer
629  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
630  &ancillary);
631 
632  //Valid packet received
633  error = NO_ERROR;
634  }
635  else
636  {
637  //The received packet contains an error
638  error = ERROR_INVALID_PACKET;
639  }
640  }
641  else
642  {
643  //The packet is not valid
644  error = ERROR_INVALID_PACKET;
645  }
646 
647  //Give the ownership of the descriptor back to the DMA
648  rxCurDmaDesc->rdes0 = ENET_RDES0_DAV;
649  //Point to the next descriptor in the list
650  rxCurDmaDesc = (Gd32f4xxRxDmaDesc *) rxCurDmaDesc->rdes3;
651  }
652  else
653  {
654  //No more data in the receive buffer
655  error = ERROR_BUFFER_EMPTY;
656  }
657 
658  //Clear RBU flag to resume processing
659  ENET_DMA_STAT = ENET_DMA_STAT_RBU;
660  //Instruct the DMA to poll the receive descriptor list
661  ENET_DMA_RPEN = 0;
662 
663  //Return status code
664  return error;
665 }
666 
667 
668 /**
669  * @brief Configure MAC address filtering
670  * @param[in] interface Underlying network interface
671  * @return Error code
672  **/
673 
675 {
676  uint_t i;
677  uint_t j;
678  uint_t k;
679  uint32_t crc;
680  uint32_t hashTable[2];
681  MacAddr unicastMacAddr[3];
682  MacFilterEntry *entry;
683 
684  //Debug message
685  TRACE_DEBUG("Updating MAC filter...\r\n");
686 
687  //Set the MAC address of the station
688  ENET_MAC_ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
689  ENET_MAC_ADDR0H = interface->macAddr.w[2] | ENET_MAC_ADDR0H_MO;
690 
691  //The MAC supports 3 additional addresses for unicast perfect filtering
692  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
693  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
694  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
695 
696  //The hash table is used for multicast address filtering
697  hashTable[0] = 0;
698  hashTable[1] = 0;
699 
700  //The MAC address filter contains the list of MAC addresses to accept
701  //when receiving an Ethernet frame
702  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
703  {
704  //Point to the current entry
705  entry = &interface->macAddrFilter[i];
706 
707  //Valid entry?
708  if(entry->refCount > 0)
709  {
710  //Multicast address?
711  if(macIsMulticastAddr(&entry->addr))
712  {
713  //Compute CRC over the current MAC address
714  crc = gd32f4xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
715 
716  //The upper 6 bits in the CRC register are used to index the
717  //contents of the hash table
718  k = (crc >> 26) & 0x3F;
719 
720  //Update hash table contents
721  hashTable[k / 32] |= (1 << (k % 32));
722  }
723  else
724  {
725  //Up to 3 additional MAC addresses can be specified
726  if(j < 3)
727  {
728  //Save the unicast address
729  unicastMacAddr[j++] = entry->addr;
730  }
731  }
732  }
733  }
734 
735  //Configure the first unicast address filter
736  if(j >= 1)
737  {
738  //When the AE bit is set, the entry is used for perfect filtering
739  ENET_MAC_ADDR1L = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
740  ENET_MAC_ADDR1H = unicastMacAddr[0].w[2] | ENET_MAC_ADDR1H_AFE;
741  }
742  else
743  {
744  //When the AE bit is cleared, the entry is ignored
745  ENET_MAC_ADDR1L = 0;
746  ENET_MAC_ADDR1H = 0;
747  }
748 
749  //Configure the second unicast address filter
750  if(j >= 2)
751  {
752  //When the AE bit is set, the entry is used for perfect filtering
753  ENET_MAC_ADDR2L = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
754  ENET_MAC_ADDT2H = unicastMacAddr[1].w[2] | ENET_MAC_ADDR2H_AFE;
755  }
756  else
757  {
758  //When the AE bit is cleared, the entry is ignored
759  ENET_MAC_ADDR2L = 0;
760  ENET_MAC_ADDT2H = 0;
761  }
762 
763  //Configure the third unicast address filter
764  if(j >= 3)
765  {
766  //When the AE bit is set, the entry is used for perfect filtering
767  ENET_MAC_ADDR3L = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
768  ENET_MAC_ADDR3H = unicastMacAddr[2].w[2] | ENET_MAC_ADDR3H_AFE;
769  }
770  else
771  {
772  //When the AE bit is cleared, the entry is ignored
773  ENET_MAC_ADDR3L = 0;
774  ENET_MAC_ADDR3H = 0;
775  }
776 
777  //Configure the multicast hash table
778  ENET_MAC_HLL = hashTable[0];
779  ENET_MAC_HLH = hashTable[1];
780 
781  //Debug message
782  TRACE_DEBUG(" ENET_MAC_HLL = %08" PRIX32 "\r\n", ENET_MAC_HLL);
783  TRACE_DEBUG(" ENET_MAC_HLH = %08" PRIX32 "\r\n", ENET_MAC_HLH);
784 
785  //Successful processing
786  return NO_ERROR;
787 }
788 
789 
790 /**
791  * @brief Adjust MAC configuration parameters for proper operation
792  * @param[in] interface Underlying network interface
793  * @return Error code
794  **/
795 
797 {
798  uint32_t config;
799 
800  //Read current MAC configuration
801  config = ENET_MAC_CFG;
802 
803  //10BASE-T or 100BASE-TX operation mode?
804  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
805  {
806  config |= ENET_MAC_CFG_SPD;
807  }
808  else
809  {
810  config &= ~ENET_MAC_CFG_SPD;
811  }
812 
813  //Half-duplex or full-duplex mode?
814  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
815  {
816  config |= ENET_MAC_CFG_DPM;
817  }
818  else
819  {
820  config &= ~ENET_MAC_CFG_DPM;
821  }
822 
823  //Update MAC configuration register
824  ENET_MAC_CFG = config;
825 
826  //Successful processing
827  return NO_ERROR;
828 }
829 
830 
831 /**
832  * @brief Write PHY register
833  * @param[in] opcode Access type (2 bits)
834  * @param[in] phyAddr PHY address (5 bits)
835  * @param[in] regAddr Register address (5 bits)
836  * @param[in] data Register value
837  **/
838 
839 void gd32f4xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
840  uint8_t regAddr, uint16_t data)
841 {
842  uint32_t temp;
843 
844  //Valid opcode?
845  if(opcode == SMI_OPCODE_WRITE)
846  {
847  //Take care not to alter MDC clock configuration
848  temp = ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_CLR;
849  //Set up a write operation
850  temp |= ENET_MAC_PHY_CTL_PW | ENET_MAC_PHY_CTL_PB;
851  //PHY address
852  temp |= MAC_PHY_CTL_PA(phyAddr);
853  //Register address
854  temp |= MAC_PHY_CTL_PR(regAddr);
855 
856  //Data to be written in the PHY register
857  ENET_MAC_PHY_DATA = data & ENET_MAC_PHY_DATA_PD;
858 
859  //Start a write operation
860  ENET_MAC_PHY_CTL = temp;
861  //Wait for the write to complete
862  while((ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_PB) != 0)
863  {
864  }
865  }
866  else
867  {
868  //The MAC peripheral only supports standard Clause 22 opcodes
869  }
870 }
871 
872 
873 /**
874  * @brief Read PHY register
875  * @param[in] opcode Access type (2 bits)
876  * @param[in] phyAddr PHY address (5 bits)
877  * @param[in] regAddr Register address (5 bits)
878  * @return Register value
879  **/
880 
881 uint16_t gd32f4xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
882  uint8_t regAddr)
883 {
884  uint16_t data;
885  uint32_t temp;
886 
887  //Valid opcode?
888  if(opcode == SMI_OPCODE_READ)
889  {
890  //Take care not to alter MDC clock configuration
891  temp = ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_CLR;
892  //Set up a read operation
893  temp |= ENET_MAC_PHY_CTL_PB;
894  //PHY address
895  temp |= MAC_PHY_CTL_PA(phyAddr);
896  //Register address
897  temp |= MAC_PHY_CTL_PR(regAddr);
898 
899  //Start a read operation
900  ENET_MAC_PHY_CTL = temp;
901  //Wait for the read to complete
902  while((ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_PB) != 0)
903  {
904  }
905 
906  //Get register value
907  data = ENET_MAC_PHY_DATA & ENET_MAC_PHY_DATA_PD;
908  }
909  else
910  {
911  //The MAC peripheral only supports standard Clause 22 opcodes
912  data = 0;
913  }
914 
915  //Return the value of the PHY register
916  return data;
917 }
918 
919 
920 /**
921  * @brief CRC calculation
922  * @param[in] data Pointer to the data over which to calculate the CRC
923  * @param[in] length Number of bytes to process
924  * @return Resulting CRC value
925  **/
926 
927 uint32_t gd32f4xxEthCalcCrc(const void *data, size_t length)
928 {
929  uint_t i;
930  uint_t j;
931  uint32_t crc;
932  const uint8_t *p;
933 
934  //Point to the data over which to calculate the CRC
935  p = (uint8_t *) data;
936  //CRC preset value
937  crc = 0xFFFFFFFF;
938 
939  //Loop through data
940  for(i = 0; i < length; i++)
941  {
942  //The message is processed bit by bit
943  for(j = 0; j < 8; j++)
944  {
945  //Update CRC value
946  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
947  {
948  crc = (crc << 1) ^ 0x04C11DB7;
949  }
950  else
951  {
952  crc = crc << 1;
953  }
954  }
955  }
956 
957  //Return CRC value
958  return ~crc;
959 }
#define txDmaDesc
#define rxBuffer
#define txBuffer
#define rxDmaDesc
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint8_t opcode
Definition: dns_common.h:188
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
uint16_t gd32f4xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void gd32f4xxEthTick(NetInterface *interface)
GD32F4XX Ethernet MAC timer handler.
uint32_t gd32f4xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
const NicDriver gd32f4xxEthDriver
GD32F4XX Ethernet MAC driver.
error_t gd32f4xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void ENET_IRQHandler(void)
GD32F4XX Ethernet MAC interrupt service routine.
void gd32f4xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
void gd32f4xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
void gd32f4xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
__weak_func void gd32f4xxEthInitGpio(NetInterface *interface)
GPIO configuration.
error_t gd32f4xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
error_t gd32f4xxEthInit(NetInterface *interface)
GD32F4XX Ethernet MAC initialization.
error_t gd32f4xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
error_t gd32f4xxEthReceivePacket(NetInterface *interface)
Receive a packet.
void gd32f4xxEthEventHandler(NetInterface *interface)
GD32F4XX Ethernet MAC event handler.
void gd32f4xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
GigaDevice GD32F4 Ethernet MAC driver.
#define GD32F4XX_ETH_IRQ_PRIORITY_GROUPING
#define GD32F4XX_ETH_RX_BUFFER_COUNT
#define GD32F4XX_ETH_IRQ_GROUP_PRIORITY
#define GD32F4XX_ETH_IRQ_SUB_PRIORITY
#define GD32F4XX_ETH_RX_BUFFER_SIZE
#define GD32F4XX_ETH_TX_BUFFER_SIZE
#define GD32F4XX_ETH_TX_BUFFER_COUNT
uint16_t regAddr
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
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:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
#define SMI_OPCODE_WRITE
Definition: nic.h:66
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define SMI_OPCODE_READ
Definition: nic.h:67
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osEnterIsr()
#define osExitIsr(flag)
Enhanced RX DMA descriptor.
Enhanced TX DMA descriptor.
MAC filter table entry.
Definition: ethernet.h:262
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368