stm32mp1xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file stm32mp1xx_eth_driver.c
3  * @brief STM32MP1 Gigabit 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 "stm32mp1xx.h"
36 #include "stm32mp1xx_hal.h"
37 #include "core/net.h"
39 #include "debug.h"
40 
41 //Underlying network interface
42 static NetInterface *nicDriverInterface;
43 
44 //IAR EWARM compiler?
45 #if defined(__ICCARM__)
46 
47 //Transmit buffer
48 #pragma data_alignment = 4
50 //Receive buffer
51 #pragma data_alignment = 4
53 //Transmit DMA descriptors
54 #pragma data_alignment = 8
56 //Receive DMA descriptors
57 #pragma data_alignment = 8
59 
60 //Keil MDK-ARM or GCC compiler?
61 #else
62 
63 //Transmit buffer
65  __attribute__((aligned(4)));
66 //Receive buffer
68  __attribute__((aligned(4)));
69 //Transmit DMA descriptors
71  __attribute__((aligned(8)));
72 //Receive DMA descriptors
74  __attribute__((aligned(8)));
75 
76 #endif
77 
78 //Current transmit descriptor
79 static uint_t txIndex;
80 //Current receive descriptor
81 static uint_t rxIndex;
82 
83 
84 /**
85  * @brief STM32MP1 Ethernet MAC driver
86  **/
87 
89 {
91  ETH_MTU,
102  TRUE,
103  TRUE,
104  TRUE,
105  FALSE
106 };
107 
108 
109 /**
110  * @brief STM32MP1 Ethernet MAC initialization
111  * @param[in] interface Underlying network interface
112  * @return Error code
113  **/
114 
116 {
117  error_t error;
118  uint32_t temp;
119 
120  //Debug message
121  TRACE_INFO("Initializing STM32MP1 Ethernet MAC...\r\n");
122 
123  //Save underlying network interface
124  nicDriverInterface = interface;
125 
126  //GPIO configuration
127  stm32mp1xxEthInitGpio(interface);
128 
129  //Enable Ethernet MAC clock
130  __HAL_RCC_ETH1MAC_CLK_ENABLE();
131  __HAL_RCC_ETH1TX_CLK_ENABLE();
132  __HAL_RCC_ETH1RX_CLK_ENABLE();
133 
134  //Reset Ethernet MAC peripheral
135  __HAL_RCC_ETH1MAC_FORCE_RESET();
136  __HAL_RCC_ETH1MAC_RELEASE_RESET();
137 
138  //Perform a software reset
139  ETH->DMAMR |= ETH_DMAMR_SWR;
140  //Wait for the reset to complete
141  while((ETH->DMAMR & ETH_DMAMR_SWR) != 0)
142  {
143  }
144 
145  //Adjust MDC clock range depending on HCLK frequency
146  ETH->MACMDIOAR = ETH_MACMDIOAR_CR_Val(5);
147 
148  //Valid Ethernet PHY or switch driver?
149  if(interface->phyDriver != NULL)
150  {
151  //Ethernet PHY initialization
152  error = interface->phyDriver->init(interface);
153  }
154  else if(interface->switchDriver != NULL)
155  {
156  //Ethernet switch initialization
157  error = interface->switchDriver->init(interface);
158  }
159  else
160  {
161  //The interface is not properly configured
162  error = ERROR_FAILURE;
163  }
164 
165  //Any error to report?
166  if(error)
167  {
168  return error;
169  }
170 
171  //Use default MAC configuration
172  ETH->MACCR = ETH_MACCR_GPSLCE | ETH_MACCR_DO;
173 
174  //Set the maximum packet size that can be accepted
175  temp = ETH->MACECR & ~ETH_MACECR_GPSL;
176  ETH->MACECR = temp | STM32MP1XX_ETH_RX_BUFFER_SIZE;
177 
178  //Configure MAC address filtering
180 
181  //Disable flow control
182  ETH->MACQ0TXFCR = 0;
183  ETH->MACRXFCR = 0;
184 
185  //Enable the first RX queue
186  ETH->MACRXQC0R = ETH_MACRXQC0R_RXQ0EN_Val(2);
187 
188  //Configure DMA operating mode
189  ETH->DMAMR = ETH_DMAMR_INTM_Val(0) | ETH_DMAMR_PR_Val(0);
190  //Configure system bus mode
191  ETH->DMASBMR |= ETH_DMASBMR_AAL;
192 
193  //The DMA takes the descriptor table as contiguous
194  ETH->DMAC0CR = ETH_DMAC0CR_DSL_Val(0);
195  //Configure TX features
196  ETH->DMAC0TXCR = ETH_DMAC0TXCR_TXPBL_Val(32);
197 
198  //Configure RX features
199  ETH->DMAC0RXCR = ETH_DMAC0RXCR_RXPBL_Val(32) |
201 
202  //Enable store and forward mode for transmission
203  ETH->MTLTXQ0OMR = ETH_MTLTXQ0OMR_TQS_Val(7) | ETH_MTLTXQ0OMR_TXQEN_Val(2) |
204  ETH_MTLTXQ0OMR_TSF;
205 
206  //Enable store and forward mode for reception
207  ETH->MTLRXQ0OMR = ETH_MTLRXQ0OMR_RQS_Val(7) | ETH_MTLRXQ0OMR_RSF;
208 
209  //Initialize DMA descriptor lists
210  stm32mp1xxEthInitDmaDesc(interface);
211 
212  //Prevent interrupts from being generated when the transmit statistic
213  //counters reach half their maximum value
214  ETH->MMCTXIMR = ETH_MMCTXIMR_TXLPITRCIM | ETH_MMCTXIMR_TXLPIUSCIM |
215  ETH_MMCTXIMR_TXGPKTIM | ETH_MMCTXIMR_TXMCOLGPIM | ETH_MMCTXIMR_TXSCOLGPIM;
216 
217  //Prevent interrupts from being generated when the receive statistic
218  //counters reach half their maximum value
219  ETH->MMCRXIMR = ETH_MMCRXIMR_RXLPITRCIM | ETH_MMCRXIMR_RXLPIUSCIM |
220  ETH_MMCRXIMR_RXUCGPIM | ETH_MMCRXIMR_RXALGNERPIM | ETH_MMCRXIMR_RXCRCERPIM;
221 
222  //Disable MAC interrupts
223  ETH->MACIER = 0;
224  //Enable the desired DMA interrupts
225  ETH->DMAC0IER = ETH_DMAC0IER_NIE | ETH_DMAC0IER_RIE | ETH_DMAC0IER_TIE;
226 
227  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
228  NVIC_SetPriorityGrouping(STM32MP1XX_ETH_IRQ_PRIORITY_GROUPING);
229 
230  //Configure Ethernet interrupt priority
231  NVIC_SetPriority(ETH1_IRQn, NVIC_EncodePriority(STM32MP1XX_ETH_IRQ_PRIORITY_GROUPING,
233 
234  //Enable MAC transmission and reception
235  ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;
236 
237  //Enable DMA transmission and reception
238  ETH->DMAC0TXCR |= ETH_DMAC0TXCR_ST;
239  ETH->DMAC0RXCR |= ETH_DMAC0RXCR_SR;
240 
241  //Accept any packets from the upper layer
242  osSetEvent(&interface->nicTxEvent);
243 
244  //Successful initialization
245  return NO_ERROR;
246 }
247 
248 
249 /**
250  * @brief GPIO configuration
251  * @param[in] interface Underlying network interface
252  **/
253 
254 __weak_func void stm32mp1xxEthInitGpio(NetInterface *interface)
255 {
256 //STM32MP157A-EV1 evaluation board?
257 #if defined(USE_STM32MP15XX_EVAL)
258  GPIO_InitTypeDef GPIO_InitStructure;
259 
260  //Enable SYSCFG clock
261  __HAL_RCC_SYSCFG_CLK_ENABLE();
262 
263  //Enable GPIO clocks
264  __HAL_RCC_GPIOA_CLK_ENABLE();
265  __HAL_RCC_GPIOB_CLK_ENABLE();
266  __HAL_RCC_GPIOC_CLK_ENABLE();
267  //__HAL_RCC_GPIOD_CLK_ENABLE();
268  __HAL_RCC_GPIOE_CLK_ENABLE();
269  __HAL_RCC_GPIOG_CLK_ENABLE();
270 
271  //Select RGMII interface mode
272  HAL_SYSCFG_ETHInterfaceSelect(SYSCFG_ETH_RGMII);
273 
274  //Configure RGMII pins
275  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
276  GPIO_InitStructure.Pull = GPIO_NOPULL;
277  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
278  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
279 
280  //Configure ETH1_RGMII_RX_CLK (PA1), ETH1_MDIO (PA2) and
281  //ETH1_RGMII_RX_CTL (PA7)
282  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
283  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
284 
285  //Configure ETH1_RGMII_RXD2 (PB0), ETH1_RGMII_RXD3 (PB1) and
286  //ETH1_RGMII_TX_CTL (PB11)
287  GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_11;
288  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
289 
290  //Configure ETH1_MDC (PC1), ETH1_RGMII_TXD2 (PC2), ETH1_RGMII_RXD0 (PC4) and
291  //ETH1_RGMII_RXD1 (PC5)
292  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5;
293  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
294 
295  //Configure ETH1_RGMII_TXD3 (PE2)
296  GPIO_InitStructure.Pin = GPIO_PIN_2;
297  HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
298 
299  //Configure ETH1_RGMII_GTX_CLK (PG4), ETH1_RGMII_CLK125 (PG5),
300  //ETH1_RGMII_TXD0 (PG13) and ETH1_RMII_TXD1 (PG14)
301  GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_13 | GPIO_PIN_14;
302  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
303 
304  //Configure PHY_RST (PD10)
305  //GPIO_InitStructure.Pin = GPIO_PIN_10;
306  //GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
307  //GPIO_InitStructure.Pull = GPIO_NOPULL;
308  //GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
309  //HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
310 
311  //Reset PHY transceiver
312  //HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10, GPIO_PIN_RESET);
313  //sleep(10);
314  //HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10, GPIO_PIN_SET);
315  //sleep(10);
316 
317 //STM32MP157C-DK2 evaluation board?
318 #elif defined(USE_STM32MP15XX_DISCO)
319  GPIO_InitTypeDef GPIO_InitStructure;
320 
321  //Enable SYSCFG clock
322  __HAL_RCC_SYSCFG_CLK_ENABLE();
323 
324  //Enable GPIO clocks
325  __HAL_RCC_GPIOA_CLK_ENABLE();
326  __HAL_RCC_GPIOB_CLK_ENABLE();
327  __HAL_RCC_GPIOC_CLK_ENABLE();
328  __HAL_RCC_GPIOE_CLK_ENABLE();
329  __HAL_RCC_GPIOG_CLK_ENABLE();
330 
331  //Select RGMII interface mode
332  HAL_SYSCFG_ETHInterfaceSelect(SYSCFG_ETH_RGMII);
333 
334  //Configure RGMII pins
335  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
336  GPIO_InitStructure.Pull = GPIO_NOPULL;
337  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
338  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
339 
340  //Configure ETH1_RGMII_RX_CLK (PA1), ETH1_MDIO (PA2) and
341  //ETH1_RGMII_RX_CTL (PA7)
342  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
343  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
344 
345  //Configure ETH1_RGMII_RXD2 (PB0), ETH1_RGMII_RXD3 (PB1) and
346  //ETH1_RGMII_TX_CTL (PB11)
347  GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_11;
348  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
349 
350  //Configure ETH1_MDC (PC1), ETH1_RGMII_TXD2 (PC2), ETH1_RGMII_RXD0 (PC4) and
351  //ETH1_RGMII_RXD1 (PC5)
352  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5;
353  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
354 
355  //Configure ETH1_RGMII_TXD3 (PE2)
356  GPIO_InitStructure.Pin = GPIO_PIN_2;
357  HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
358 
359  //Configure ETH1_RGMII_GTX_CLK (PG4), ETH1_RGMII_CLK125 (PG5),
360  //ETH1_RGMII_TXD0 (PG13) and ETH1_RMII_TXD1 (PG14)
361  GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_13 | GPIO_PIN_14;
362  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
363 
364  //Configure PHY_RST (PG0)
365  GPIO_InitStructure.Pin = GPIO_PIN_0;
366  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
367  GPIO_InitStructure.Pull = GPIO_NOPULL;
368  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
369  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
370 
371  //Reset PHY transceiver
372  HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_RESET);
373  sleep(10);
374  HAL_GPIO_WritePin(GPIOG, GPIO_PIN_0, GPIO_PIN_SET);
375  sleep(10);
376 #endif
377 }
378 
379 
380 /**
381  * @brief Initialize DMA descriptor lists
382  * @param[in] interface Underlying network interface
383  **/
384 
386 {
387  uint_t i;
388 
389  //Initialize TX DMA descriptor list
390  for(i = 0; i < STM32MP1XX_ETH_TX_BUFFER_COUNT; i++)
391  {
392  //The descriptor is initially owned by the application
393  txDmaDesc[i].tdes0 = 0;
394  txDmaDesc[i].tdes1 = 0;
395  txDmaDesc[i].tdes2 = 0;
396  txDmaDesc[i].tdes3 = 0;
397  }
398 
399  //Initialize TX descriptor index
400  txIndex = 0;
401 
402  //Initialize RX DMA descriptor list
403  for(i = 0; i < STM32MP1XX_ETH_RX_BUFFER_COUNT; i++)
404  {
405  //The descriptor is initially owned by the DMA
406  rxDmaDesc[i].rdes0 = (uint32_t) rxBuffer[i];
407  rxDmaDesc[i].rdes1 = 0;
408  rxDmaDesc[i].rdes2 = 0;
410  }
411 
412  //Initialize RX descriptor index
413  rxIndex = 0;
414 
415  //Start location of the TX descriptor list
416  ETH->DMAC0TXDLAR = (uint32_t) &txDmaDesc[0];
417  //Length of the transmit descriptor ring
418  ETH->DMAC0TXRLR = STM32MP1XX_ETH_TX_BUFFER_COUNT - 1;
419 
420  //Start location of the RX descriptor list
421  ETH->DMAC0RXDLAR = (uint32_t) &rxDmaDesc[0];
422  //Length of the receive descriptor ring
423  ETH->DMAC0RXRLR = STM32MP1XX_ETH_RX_BUFFER_COUNT - 1;
424 }
425 
426 
427 /**
428  * @brief STM32MP1 Ethernet MAC timer handler
429  *
430  * This routine is periodically called by the TCP/IP stack to handle periodic
431  * operations such as polling the link state
432  *
433  * @param[in] interface Underlying network interface
434  **/
435 
437 {
438  //Valid Ethernet PHY or switch driver?
439  if(interface->phyDriver != NULL)
440  {
441  //Handle periodic operations
442  interface->phyDriver->tick(interface);
443  }
444  else if(interface->switchDriver != NULL)
445  {
446  //Handle periodic operations
447  interface->switchDriver->tick(interface);
448  }
449  else
450  {
451  //Just for sanity
452  }
453 }
454 
455 
456 /**
457  * @brief Enable interrupts
458  * @param[in] interface Underlying network interface
459  **/
460 
462 {
463  //Enable Ethernet MAC interrupts
464  NVIC_EnableIRQ(ETH1_IRQn);
465 
466  //Valid Ethernet PHY or switch driver?
467  if(interface->phyDriver != NULL)
468  {
469  //Enable Ethernet PHY interrupts
470  interface->phyDriver->enableIrq(interface);
471  }
472  else if(interface->switchDriver != NULL)
473  {
474  //Enable Ethernet switch interrupts
475  interface->switchDriver->enableIrq(interface);
476  }
477  else
478  {
479  //Just for sanity
480  }
481 }
482 
483 
484 /**
485  * @brief Disable interrupts
486  * @param[in] interface Underlying network interface
487  **/
488 
490 {
491  //Disable Ethernet MAC interrupts
492  NVIC_DisableIRQ(ETH1_IRQn);
493 
494  //Valid Ethernet PHY or switch driver?
495  if(interface->phyDriver != NULL)
496  {
497  //Disable Ethernet PHY interrupts
498  interface->phyDriver->disableIrq(interface);
499  }
500  else if(interface->switchDriver != NULL)
501  {
502  //Disable Ethernet switch interrupts
503  interface->switchDriver->disableIrq(interface);
504  }
505  else
506  {
507  //Just for sanity
508  }
509 }
510 
511 
512 /**
513  * @brief STM32MP1 Ethernet MAC interrupt service routine
514  **/
515 
516 void ETH1_IRQHandler(void)
517 {
518  bool_t flag;
519  uint32_t status;
520 
521  //Interrupt service routine prologue
522  osEnterIsr();
523 
524  //This flag will be set if a higher priority task must be woken
525  flag = FALSE;
526 
527  //Read DMA status register
528  status = ETH->DMAC0SR;
529 
530  //Packet transmitted?
531  if((status & ETH_DMAC0SR_TI) != 0)
532  {
533  //Clear TI interrupt flag
534  ETH->DMAC0SR = ETH_DMAC0SR_TI;
535 
536  //Check whether the TX buffer is available for writing
537  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
538  {
539  //Notify the TCP/IP stack that the transmitter is ready to send
540  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
541  }
542  }
543 
544  //Packet received?
545  if((status & ETH_DMAC0SR_RI) != 0)
546  {
547  //Clear RI interrupt flag
548  ETH->DMAC0SR = ETH_DMAC0SR_RI;
549 
550  //Set event flag
551  nicDriverInterface->nicEvent = TRUE;
552  //Notify the TCP/IP stack of the event
553  flag |= osSetEventFromIsr(&netEvent);
554  }
555 
556  //Clear NIS interrupt flag
557  ETH->DMAC0SR = ETH_DMAC0SR_NIS;
558 
559  //Interrupt service routine epilogue
560  osExitIsr(flag);
561 }
562 
563 
564 /**
565  * @brief STM32MP1 Ethernet MAC event handler
566  * @param[in] interface Underlying network interface
567  **/
568 
570 {
571  error_t error;
572 
573  //Process all pending packets
574  do
575  {
576  //Read incoming packet
577  error = stm32mp1xxEthReceivePacket(interface);
578 
579  //No more data in the receive buffer?
580  } while(error != ERROR_BUFFER_EMPTY);
581 }
582 
583 
584 /**
585  * @brief Send a packet
586  * @param[in] interface Underlying network interface
587  * @param[in] buffer Multi-part buffer containing the data to send
588  * @param[in] offset Offset to the first data byte
589  * @param[in] ancillary Additional options passed to the stack along with
590  * the packet
591  * @return Error code
592  **/
593 
595  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
596 {
597  size_t length;
598 
599  //Retrieve the length of the packet
600  length = netBufferGetLength(buffer) - offset;
601 
602  //Check the frame length
604  {
605  //The transmitter can accept another packet
606  osSetEvent(&interface->nicTxEvent);
607  //Report an error
608  return ERROR_INVALID_LENGTH;
609  }
610 
611  //Make sure the current buffer is available for writing
612  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) != 0)
613  {
614  return ERROR_FAILURE;
615  }
616 
617  //Copy user data to the transmit buffer
618  netBufferRead(txBuffer[txIndex], buffer, offset, length);
619 
620  //Set the start address of the buffer
621  txDmaDesc[txIndex].tdes0 = (uint32_t) txBuffer[txIndex];
622  //Write the number of bytes to send
623  txDmaDesc[txIndex].tdes2 = ETH_TDES2_IOC | (length & ETH_TDES2_B1L);
624  //Give the ownership of the descriptor to the DMA
625  txDmaDesc[txIndex].tdes3 = ETH_TDES3_OWN | ETH_TDES3_FD | ETH_TDES3_LD;
626 
627  //Data synchronization barrier
628  __DSB();
629 
630  //Clear TBU flag to resume processing
631  ETH->DMAC0SR = ETH_DMAC0SR_TBU;
632  //Instruct the DMA to poll the transmit descriptor list
633  ETH->DMAC0TXDTPR = 0;
634 
635  //Increment index and wrap around if necessary
636  if(++txIndex >= STM32MP1XX_ETH_TX_BUFFER_COUNT)
637  {
638  txIndex = 0;
639  }
640 
641  //Check whether the next buffer is available for writing
642  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
643  {
644  //The transmitter can accept another packet
645  osSetEvent(&interface->nicTxEvent);
646  }
647 
648  //Data successfully written
649  return NO_ERROR;
650 }
651 
652 
653 /**
654  * @brief Receive a packet
655  * @param[in] interface Underlying network interface
656  * @return Error code
657  **/
658 
660 {
661  error_t error;
662  size_t n;
663  NetRxAncillary ancillary;
664 
665  //Current buffer available for reading?
666  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_OWN) == 0)
667  {
668  //FD and LD flags should be set
669  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_FD) != 0 &&
670  (rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_LD) != 0)
671  {
672  //Make sure no error occurred
673  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_ES) == 0)
674  {
675  //Retrieve the length of the frame
676  n = rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_PL;
677  //Limit the number of data to read
679 
680  //Additional options can be passed to the stack along with the packet
681  ancillary = NET_DEFAULT_RX_ANCILLARY;
682 
683  //Pass the packet to the upper layer
684  nicProcessPacket(interface, rxBuffer[rxIndex], n, &ancillary);
685 
686  //Valid packet received
687  error = NO_ERROR;
688  }
689  else
690  {
691  //The received packet contains an error
692  error = ERROR_INVALID_PACKET;
693  }
694  }
695  else
696  {
697  //The packet is not valid
698  error = ERROR_INVALID_PACKET;
699  }
700 
701  //Set the start address of the buffer
702  rxDmaDesc[rxIndex].rdes0 = (uint32_t) rxBuffer[rxIndex];
703  //Give the ownership of the descriptor back to the DMA
705 
706  //Increment index and wrap around if necessary
707  if(++rxIndex >= STM32MP1XX_ETH_RX_BUFFER_COUNT)
708  {
709  rxIndex = 0;
710  }
711  }
712  else
713  {
714  //No more data in the receive buffer
715  error = ERROR_BUFFER_EMPTY;
716  }
717 
718  //Clear RBU flag to resume processing
719  ETH->DMAC0SR = ETH_DMAC0SR_RBU;
720  //Instruct the DMA to poll the receive descriptor list
721  ETH->DMAC0RXDTPR = 0;
722 
723  //Return status code
724  return error;
725 }
726 
727 
728 /**
729  * @brief Configure MAC address filtering
730  * @param[in] interface Underlying network interface
731  * @return Error code
732  **/
733 
735 {
736  uint_t i;
737  uint_t j;
738  uint_t k;
739  uint32_t crc;
740  uint32_t hashTable[2];
741  MacAddr unicastMacAddr[3];
742  MacFilterEntry *entry;
743 
744  //Debug message
745  TRACE_DEBUG("Updating MAC filter...\r\n");
746 
747  //Promiscuous mode?
748  if(interface->promiscuous)
749  {
750  //Pass all incoming frames regardless of their destination address
751  ETH->MACPFR = ETH_MACPFR_PR;
752  }
753  else
754  {
755  //Set the MAC address of the station
756  ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
757  ETH->MACA0HR = interface->macAddr.w[2];
758 
759  //The MAC supports 3 additional addresses for unicast perfect filtering
760  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
761  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
762  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
763 
764  //The hash table is used for multicast address filtering
765  hashTable[0] = 0;
766  hashTable[1] = 0;
767 
768  //The MAC address filter contains the list of MAC addresses to accept
769  //when receiving an Ethernet frame
770  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
771  {
772  //Point to the current entry
773  entry = &interface->macAddrFilter[i];
774 
775  //Valid entry?
776  if(entry->refCount > 0)
777  {
778  //Multicast address?
779  if(macIsMulticastAddr(&entry->addr))
780  {
781  //Compute CRC over the current MAC address
782  crc = stm32mp1xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
783 
784  //The upper 6 bits in the CRC register are used to index the
785  //contents of the hash table
786  k = (crc >> 26) & 0x3F;
787 
788  //Update hash table contents
789  hashTable[k / 32] |= (1 << (k % 32));
790  }
791  else
792  {
793  //Up to 3 additional MAC addresses can be specified
794  if(j < 3)
795  {
796  //Save the unicast address
797  unicastMacAddr[j++] = entry->addr;
798  }
799  }
800  }
801  }
802 
803  //Configure the first unicast address filter
804  if(j >= 1)
805  {
806  //When the AE bit is set, the entry is used for perfect filtering
807  ETH->MACA1LR = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
808  ETH->MACA1HR = unicastMacAddr[0].w[2] | ETH_MACA1HR_AE;
809  }
810  else
811  {
812  //When the AE bit is cleared, the entry is ignored
813  ETH->MACA1LR = 0;
814  ETH->MACA1HR = 0;
815  }
816 
817  //Configure the second unicast address filter
818  if(j >= 2)
819  {
820  //When the AE bit is set, the entry is used for perfect filtering
821  ETH->MACA2LR = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
822  ETH->MACA2HR = unicastMacAddr[1].w[2] | ETH_MACA2HR_AE;
823  }
824  else
825  {
826  //When the AE bit is cleared, the entry is ignored
827  ETH->MACA2LR = 0;
828  ETH->MACA2HR = 0;
829  }
830 
831  //Configure the third unicast address filter
832  if(j >= 3)
833  {
834  //When the AE bit is set, the entry is used for perfect filtering
835  ETH->MACA3LR = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
836  ETH->MACA3HR = unicastMacAddr[2].w[2] | ETH_MACA3HR_AE;
837  }
838  else
839  {
840  //When the AE bit is cleared, the entry is ignored
841  ETH->MACA3LR = 0;
842  ETH->MACA3HR = 0;
843  }
844 
845  //Check whether frames with a multicast destination address should be
846  //accepted
847  if(interface->acceptAllMulticast)
848  {
849  //Configure the receive filter
850  ETH->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_PM;
851  }
852  else
853  {
854  //Configure the receive filter
855  ETH->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_HMC;
856 
857  //Configure the multicast hash table
858  ETH->MACHT0R = hashTable[0];
859  ETH->MACHT1R = hashTable[1];
860 
861  //Debug message
862  TRACE_DEBUG(" MACHT0R = %08" PRIX32 "\r\n", ETH->MACHT0R);
863  TRACE_DEBUG(" MACHT1R = %08" PRIX32 "\r\n", ETH->MACHT1R);
864  }
865  }
866 
867  //Successful processing
868  return NO_ERROR;
869 }
870 
871 
872 /**
873  * @brief Adjust MAC configuration parameters for proper operation
874  * @param[in] interface Underlying network interface
875  * @return Error code
876  **/
877 
879 {
880  uint32_t config;
881 
882  //Read current MAC configuration
883  config = ETH->MACCR;
884 
885  //1000BASE-T operation mode?
886  if(interface->linkSpeed == NIC_LINK_SPEED_1GBPS)
887  {
888  config &= ~ETH_MACCR_PS;
889  config &= ~ETH_MACCR_FES;
890  }
891  //100BASE-TX operation mode?
892  else if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
893  {
894  config |= ETH_MACCR_PS;
895  config |= ETH_MACCR_FES;
896  }
897  //10BASE-T operation mode?
898  else
899  {
900  config |= ETH_MACCR_PS;
901  config &= ~ETH_MACCR_FES;
902  }
903 
904  //Half-duplex or full-duplex mode?
905  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
906  {
907  config |= ETH_MACCR_DM;
908  }
909  else
910  {
911  config &= ~ETH_MACCR_DM;
912  }
913 
914  //Update MAC configuration register
915  ETH->MACCR = config;
916 
917  //Successful processing
918  return NO_ERROR;
919 }
920 
921 
922 /**
923  * @brief Write PHY register
924  * @param[in] opcode Access type (2 bits)
925  * @param[in] phyAddr PHY address (5 bits)
926  * @param[in] regAddr Register address (5 bits)
927  * @param[in] data Register value
928  **/
929 
930 void stm32mp1xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
931  uint8_t regAddr, uint16_t data)
932 {
933  uint32_t temp;
934 
935  //Valid opcode?
936  if(opcode == SMI_OPCODE_WRITE)
937  {
938  //Take care not to alter MDC clock configuration
939  temp = ETH->MACMDIOAR & ETH_MACMDIOAR_CR;
940  //Set up a write operation
941  temp |= ETH_MACMDIOAR_GOC_Val(1) | ETH_MACMDIOAR_GB;
942  //PHY address
943  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
944  //Register address
945  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
946 
947  //Data to be written in the PHY register
948  ETH->MACMDIODR = data & ETH_MACMDIODR_GD;
949 
950  //Start a write operation
951  ETH->MACMDIOAR = temp;
952  //Wait for the write to complete
953  while((ETH->MACMDIOAR & ETH_MACMDIOAR_GB) != 0)
954  {
955  }
956  }
957  else
958  {
959  //The MAC peripheral only supports standard Clause 22 opcodes
960  }
961 }
962 
963 
964 /**
965  * @brief Read PHY register
966  * @param[in] opcode Access type (2 bits)
967  * @param[in] phyAddr PHY address (5 bits)
968  * @param[in] regAddr Register address (5 bits)
969  * @return Register value
970  **/
971 
972 uint16_t stm32mp1xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
973  uint8_t regAddr)
974 {
975  uint16_t data;
976  uint32_t temp;
977 
978  //Valid opcode?
979  if(opcode == SMI_OPCODE_READ)
980  {
981  //Take care not to alter MDC clock configuration
982  temp = ETH->MACMDIOAR & ETH_MACMDIOAR_CR;
983  //Set up a read operation
984  temp |= ETH_MACMDIOAR_GOC_Val(3) | ETH_MACMDIOAR_GB;
985  //PHY address
986  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
987  //Register address
988  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
989 
990  //Start a read operation
991  ETH->MACMDIOAR = temp;
992  //Wait for the read to complete
993  while((ETH->MACMDIOAR & ETH_MACMDIOAR_GB) != 0)
994  {
995  }
996 
997  //Get register value
998  data = ETH->MACMDIODR & ETH_MACMDIODR_GD;
999  }
1000  else
1001  {
1002  //The MAC peripheral only supports standard Clause 22 opcodes
1003  data = 0;
1004  }
1005 
1006  //Return the value of the PHY register
1007  return data;
1008 }
1009 
1010 
1011 /**
1012  * @brief CRC calculation
1013  * @param[in] data Pointer to the data over which to calculate the CRC
1014  * @param[in] length Number of bytes to process
1015  * @return Resulting CRC value
1016  **/
1017 
1018 uint32_t stm32mp1xxEthCalcCrc(const void *data, size_t length)
1019 {
1020  uint_t i;
1021  uint_t j;
1022  uint32_t crc;
1023  const uint8_t *p;
1024 
1025  //Point to the data over which to calculate the CRC
1026  p = (uint8_t *) data;
1027  //CRC preset value
1028  crc = 0xFFFFFFFF;
1029 
1030  //Loop through data
1031  for(i = 0; i < length; i++)
1032  {
1033  //The message is processed bit by bit
1034  for(j = 0; j < 8; j++)
1035  {
1036  //Update CRC value
1037  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1038  {
1039  crc = (crc << 1) ^ 0x04C11DB7;
1040  }
1041  else
1042  {
1043  crc = crc << 1;
1044  }
1045  }
1046  }
1047 
1048  //Return CRC value
1049  return ~crc;
1050 }
#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 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
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define sleep(delay)
Definition: os_port.h:301
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)
#define ETH_TDES3_LD
#define ETH_RDES3_OWN
#define ETH_RDES3_FD
#define ETH_RDES3_IOC
#define ETH_RDES3_BUF1V
#define ETH_TDES2_B1L
#define ETH_TDES3_FD
#define ETH_RDES3_PL
#define ETH_RDES3_ES
#define ETH_TDES3_OWN
#define ETH_RDES3_LD
#define ETH_TDES2_IOC
#define ETH_MTLTXQ0OMR_TQS_Val(n)
#define ETH_DMAC0TXCR_TXPBL_Val(n)
#define ETH_DMAC0RXCR_RBSZ_Val(n)
#define ETH_DMAC0CR_DSL_Val(n)
#define ETH_MTLTXQ0OMR_TXQEN_Val(n)
#define ETH_MTLRXQ0OMR_RQS_Val(n)
#define ETH_DMAC0RXCR_RXPBL_Val(n)
#define ETH_DMAMR_INTM_Val(n)
#define ETH_MACMDIOAR_CR_Val(n)
#define ETH_MACRXQC0R_RXQ0EN_Val(n)
#define ETH_MACMDIOAR_GOC_Val(n)
__weak_func void stm32mp1xxEthInitGpio(NetInterface *interface)
GPIO configuration.
void stm32mp1xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
error_t stm32mp1xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
error_t stm32mp1xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
error_t stm32mp1xxEthInit(NetInterface *interface)
STM32MP1 Ethernet MAC initialization.
uint32_t stm32mp1xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
const NicDriver stm32mp1xxEthDriver
STM32MP1 Ethernet MAC driver.
void stm32mp1xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
error_t stm32mp1xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void stm32mp1xxEthTick(NetInterface *interface)
STM32MP1 Ethernet MAC timer handler.
void stm32mp1xxEthEventHandler(NetInterface *interface)
STM32MP1 Ethernet MAC event handler.
uint16_t stm32mp1xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void ETH1_IRQHandler(void)
STM32MP1 Ethernet MAC interrupt service routine.
void stm32mp1xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
void stm32mp1xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
error_t stm32mp1xxEthReceivePacket(NetInterface *interface)
Receive a packet.
STM32MP1 Gigabit Ethernet MAC driver.
#define STM32MP1XX_ETH_IRQ_GROUP_PRIORITY
#define STM32MP1XX_ETH_TX_BUFFER_COUNT
#define STM32MP1XX_ETH_TX_BUFFER_SIZE
#define ETH_DMAMR_PR_Val(n)
#define STM32MP1XX_ETH_IRQ_PRIORITY_GROUPING
#define STM32MP1XX_ETH_RX_BUFFER_SIZE
#define STM32MP1XX_ETH_RX_BUFFER_COUNT
#define STM32MP1XX_ETH_IRQ_SUB_PRIORITY
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
Receive descriptor.
Transmit descriptor.
uint8_t length
Definition: tcp.h:368