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