mcxe31b_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file mcxe31b_eth_driver.c
3  * @brief NXP MCX E31B Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "fsl_device_registers.h"
36 #include "fsl_clock.h"
37 #include "fsl_memory.h"
38 #include "fsl_siul2.h"
39 #include "core/net.h"
41 #include "debug.h"
42 
43 //Underlying network interface
44 static NetInterface *nicDriverInterface;
45 
46 //IAR EWARM compiler?
47 #if defined(__ICCARM__)
48 
49 //Transmit buffer
50 #pragma data_alignment = 4
51 #pragma location = MCXE31B_ETH_RAM_SECTION
53 //Receive buffer
54 #pragma data_alignment = 4
55 #pragma location = MCXE31B_ETH_RAM_SECTION
57 //Transmit DMA descriptors
58 #pragma data_alignment = 4
59 #pragma location = MCXE31B_ETH_RAM_SECTION
61 //Receive DMA descriptors
62 #pragma data_alignment = 4
63 #pragma location = MCXE31B_ETH_RAM_SECTION
65 
66 //Keil MDK-ARM or GCC compiler?
67 #else
68 
69 //Transmit buffer
71  __attribute__((aligned(4), __section__(MCXE31B_ETH_RAM_SECTION)));
72 //Receive buffer
74  __attribute__((aligned(4), __section__(MCXE31B_ETH_RAM_SECTION)));
75 //Transmit DMA descriptors
77  __attribute__((aligned(4), __section__(MCXE31B_ETH_RAM_SECTION)));
78 //Receive DMA descriptors
80  __attribute__((aligned(4), __section__(MCXE31B_ETH_RAM_SECTION)));
81 
82 #endif
83 
84 //Current transmit descriptor
85 static uint_t txIndex;
86 //Current receive descriptor
87 static uint_t rxIndex;
88 
89 
90 /**
91  * @brief MCX E31B Ethernet MAC driver
92  **/
93 
95 {
97  ETH_MTU,
108  TRUE,
109  TRUE,
110  TRUE,
111  FALSE
112 };
113 
114 
115 /**
116  * @brief MCX E31B Ethernet MAC initialization
117  * @param[in] interface Underlying network interface
118  * @return Error code
119  **/
120 
122 {
123  error_t error;
124  uint32_t temp;
125 
126  //Debug message
127  TRACE_INFO("Initializing MCX E31B Ethernet MAC...\r\n");
128 
129  //Save underlying network interface
130  nicDriverInterface = interface;
131 
132  //GPIO configuration
133  mcxe31bEthInitGpio(interface);
134 
135  //Enable EMAC peripheral clock
136  CLOCK_EnableClock(kCLOCK_Emac);
137 
138  //Perform a software reset
139  EMAC->DMA_MODE |= EMAC_DMA_MODE_SWR_MASK;
140  //Wait for the reset to complete
141  while((EMAC->DMA_MODE & EMAC_DMA_MODE_SWR_MASK) != 0)
142  {
143  }
144 
145  //Adjust MDC clock range depending on CSR frequency
146  EMAC->MAC_MDIO_ADDRESS = EMAC_MAC_MDIO_ADDRESS_CR(4);
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  EMAC->MAC_CONFIGURATION = EMAC_MAC_CONFIGURATION_GPSLCE_MASK |
173  EMAC_MAC_CONFIGURATION_PS_MASK | EMAC_MAC_CONFIGURATION_DO_MASK;
174 
175  //Set the maximum packet size that can be accepted
176  temp = EMAC->MAC_EXT_CONFIGURATION & ~EMAC_MAC_EXT_CONFIGURATION_GPSL_MASK;
177  EMAC->MAC_EXT_CONFIGURATION = temp | MCXE31B_ETH_RX_BUFFER_SIZE;
178 
179  //Configure MAC address filtering
181 
182  //Disable flow control
183  EMAC->MAC_TX_FLOW_CTRL_Q[0] = 0;
184  EMAC->MAC_RX_FLOW_CTRL = 0;
185 
186  //Enable the first RX queue
187  EMAC->MAC_RXQ_CTRL[0] = EMAC_MAC_RXQ_CTRL_RXQ0EN(2);
188 
189  //Configure DMA operating mode
190  EMAC->DMA_MODE = EMAC_DMA_MODE_PR(0);
191  //Configure system bus mode
192  EMAC->DMA_SYSBUS_MODE |= EMAC_DMA_SYSBUS_MODE_AAL_MASK;
193 
194  //The DMA takes the descriptor table as contiguous
195  EMAC->DMA_CH[0].DMA_CHX_CTRL = EMAC_DMA_CHX_CTRL_DSL(0);
196  //Configure TX features
197  EMAC->DMA_CH[0].DMA_CHX_TX_CTRL = EMAC_DMA_CHX_TX_CTRL_TxPBL(32);
198 
199  //Configure RX features
200  EMAC->DMA_CH[0].DMA_CHX_RX_CTRL = EMAC_DMA_CHX_RX_CTRL_RxPBL(32) |
201  EMAC_DMA_CHX_RX_CTRL_RBSZ_13_y(MCXE31B_ETH_RX_BUFFER_SIZE / 4);
202 
203  //Enable store and forward mode for transmission
204  EMAC->MTL_QUEUE[0].MTL_TXQX_OP_MODE |= EMAC_MTL_TXQX_OP_MODE_TQS(7) |
205  EMAC_MTL_TXQX_OP_MODE_TXQEN(2) | EMAC_MTL_TXQX_OP_MODE_TSF_MASK;
206 
207  //Enable store and forward mode for reception
208  EMAC->MTL_QUEUE[0].MTL_RXQX_OP_MODE |= EMAC_MTL_RXQX_OP_MODE_RQS(7) |
209  EMAC_MTL_RXQX_OP_MODE_RSF_MASK;
210 
211  //Initialize DMA descriptor lists
212  mcxe31bEthInitDmaDesc(interface);
213 
214  //Prevent interrupts from being generated when statistic counters reach
215  //half their maximum value
216  EMAC->MMC_TX_INTERRUPT_MASK = 0xFFFFFFFF;
217  EMAC->MMC_RX_INTERRUPT_MASK = 0xFFFFFFFF;
218  EMAC->MMC_FPE_TX_INTERRUPT_MASK = 0xFFFFFFFF;
219  EMAC->MMC_FPE_RX_INTERRUPT_MASK = 0xFFFFFFFF;
220 
221  //Disable MAC interrupts
222  EMAC->MAC_INTERRUPT_ENABLE = 0;
223 
224  //Enable the desired DMA interrupts
225  EMAC->DMA_CH[0].DMA_CHX_INT_EN = EMAC_DMA_CHX_INT_EN_NIE_MASK |
226  EMAC_DMA_CHX_INT_EN_RIE_MASK | EMAC_DMA_CHX_INT_EN_TIE_MASK;
227 
228  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
229  NVIC_SetPriorityGrouping(MCXE31B_ETH_IRQ_PRIORITY_GROUPING);
230 
231  //Configure Ethernet interrupt priority
232  NVIC_SetPriority(EMAC_0_IRQn, NVIC_EncodePriority(MCXE31B_ETH_IRQ_PRIORITY_GROUPING,
234 
235  //Enable MAC transmission and reception
236  EMAC->MAC_CONFIGURATION |= EMAC_MAC_CONFIGURATION_TE_MASK |
237  EMAC_MAC_CONFIGURATION_RE_MASK;
238 
239  //Enable DMA transmission and reception
240  EMAC->DMA_CH[0].DMA_CHX_TX_CTRL |= EMAC_DMA_CHX_TX_CTRL_ST_MASK;
241  EMAC->DMA_CH[0].DMA_CHX_RX_CTRL |= EMAC_DMA_CHX_RX_CTRL_SR_MASK;
242 
243  //Accept any packets from the upper layer
244  osSetEvent(&interface->nicTxEvent);
245 
246  //Successful initialization
247  return NO_ERROR;
248 }
249 
250 
251 /**
252  * @brief GPIO configuration
253  * @param[in] interface Underlying network interface
254  **/
255 
256 __weak_func void mcxe31bEthInitGpio(NetInterface *interface)
257 {
258 //FRDM-MCXE31B evaluation board?
259 #if defined(USE_FRDM_MCXE31B)
260  //Select RMII interface mode
261  DCM_GPR->DCMRWF1 |= DCM_GPR_DCMRWF1_RMII_MII_SEL_MASK;
262 
263  //Configure MII_RMII_TX_CLK (PTD11)
264  SIUL2_SetPinInputBuffer(SIUL2, 107, true, 296, kPORT_INPUT_MUX_ALT1);
265 
266  //Configure MII_RMII_TX_EN (PTD12)
267  SIUL2_SetPinOutputBuffer(SIUL2, 108, true, kPORT_MUX_ALT5);
268  //Configure MII_RMII_TXD0 (PTC2)
269  SIUL2_SetPinOutputBuffer(SIUL2, 66, true, kPORT_MUX_ALT5);
270  //Configure MII_RMII_TXD1 (PTD7)
271  SIUL2_SetPinOutputBuffer(SIUL2, 103, true, kPORT_MUX_ALT5);
272 
273  //Configure MII_RMII_RX_DV (PTC17)
274  SIUL2_SetPinInputBuffer(SIUL2, 81, true, 292, kPORT_INPUT_MUX_ALT1);
275  //Configure MII_RMII_RXD0 (PTC1)
276  SIUL2_SetPinInputBuffer(SIUL2, 65, true, 294, kPORT_INPUT_MUX_ALT1);
277  //Configure MII_RMII_RXD1 (PTC0)
278  SIUL2_SetPinInputBuffer(SIUL2, 64, true, 295, kPORT_INPUT_MUX_ALT1);
279 
280  //Configure MII_RMII_MDC (PTB5)
281  SIUL2_SetPinOutputBuffer(SIUL2, 37, true, kPORT_MUX_ALT7);
282 
283  //Configure MII_RMII_MDIO (PTB4)
284  SIUL2_SetPinOutputBuffer(SIUL2, 36, true, kPORT_MUX_ALT5);
285  SIUL2_SetPinInputBuffer(SIUL2, 36, true, 291, kPORT_INPUT_MUX_ALT1);
286 
287  //Configure ENET_PHY_RST (PTC3) as an output
288  SIUL2_SetPinOutputBuffer(SIUL2, 67, true, kPORT_MUX_AS_GPIO);
289 
290  //Reset PHY transceiver (hard reset)
291  SIUL2_PortPinWrite(SIUL2, kSIUL2_PTC, 3, 0);
292  sleep(10);
293  SIUL2_PortPinWrite(SIUL2, kSIUL2_PTC, 3, 1);
294  sleep(10);
295 
296  //Configure RMII clocks
297  CLOCK_SetEmacRmiiTxClkFreq(50000000);
298  CLOCK_AttachClk(kEMAC_RMII_TX_CLK_to_EMAC_TX);
299  CLOCK_AttachClk(kEMAC_RMII_TX_CLK_to_EMAC_RX);
300  CLOCK_AttachClk(kEMAC_RMII_TX_CLK_to_EMAC_TS);
301  CLOCK_SetClkDiv(kCLOCK_DivEmacRxClk, 2);
302  CLOCK_SetClkDiv(kCLOCK_DivEmacTxClk, 2);
303  CLOCK_SetClkDiv(kCLOCK_DivEmacTsClk, 1);
304 #endif
305 }
306 
307 
308 /**
309  * @brief Initialize DMA descriptor lists
310  * @param[in] interface Underlying network interface
311  **/
312 
314 {
315  uint_t i;
316 
317  //Initialize TX DMA descriptor list
318  for(i = 0; i < MCXE31B_ETH_TX_BUFFER_COUNT; i++)
319  {
320  //The descriptor is initially owned by the application
321  txDmaDesc[i].tdes0 = 0;
322  txDmaDesc[i].tdes1 = 0;
323  txDmaDesc[i].tdes2 = 0;
324  txDmaDesc[i].tdes3 = 0;
325  }
326 
327  //Initialize TX descriptor index
328  txIndex = 0;
329 
330  //Initialize RX DMA descriptor list
331  for(i = 0; i < MCXE31B_ETH_RX_BUFFER_COUNT; i++)
332  {
333  //The descriptor is initially owned by the DMA
334  rxDmaDesc[i].rdes0 = MEMORY_ConvertMemoryMapAddress(
335  (uint32_t) rxBuffer[i], kMEMORY_Local2DMA);
336 
337  rxDmaDesc[i].rdes1 = 0;
338  rxDmaDesc[i].rdes2 = 0;
340  }
341 
342  //Initialize RX descriptor index
343  rxIndex = 0;
344 
345  //Start location of the TX descriptor list
346  EMAC->DMA_CH[0].DMA_CHX_TXDESC_LIST_ADDR = MEMORY_ConvertMemoryMapAddress(
347  (uint32_t) &txDmaDesc[0], kMEMORY_Local2DMA);
348 
349  //Length of the transmit descriptor ring
350  EMAC->DMA_CH[0].DMA_CHX_TXDESC_RING_LENGTH = MCXE31B_ETH_TX_BUFFER_COUNT - 1;
351 
352  //Start location of the RX descriptor list
353  EMAC->DMA_CH[0].DMA_CHX_RXDESC_LIST_ADDR = MEMORY_ConvertMemoryMapAddress(
354  (uint32_t) &rxDmaDesc[0], kMEMORY_Local2DMA);
355 
356  //Length of the receive descriptor ring
357  EMAC->DMA_CH[0].DMA_CHX_RXDESC_RING_LENGTH = MCXE31B_ETH_RX_BUFFER_COUNT - 1;
358 }
359 
360 
361 /**
362  * @brief MCX E31B Ethernet MAC timer handler
363  *
364  * This routine is periodically called by the TCP/IP stack to handle periodic
365  * operations such as polling the link state
366  *
367  * @param[in] interface Underlying network interface
368  **/
369 
370 void mcxe31bEthTick(NetInterface *interface)
371 {
372  //Valid Ethernet PHY or switch driver?
373  if(interface->phyDriver != NULL)
374  {
375  //Handle periodic operations
376  interface->phyDriver->tick(interface);
377  }
378  else if(interface->switchDriver != NULL)
379  {
380  //Handle periodic operations
381  interface->switchDriver->tick(interface);
382  }
383  else
384  {
385  //Just for sanity
386  }
387 }
388 
389 
390 /**
391  * @brief Enable interrupts
392  * @param[in] interface Underlying network interface
393  **/
394 
396 {
397  //Enable Ethernet MAC interrupts
398  NVIC_EnableIRQ(EMAC_0_IRQn);
399 
400  //Valid Ethernet PHY or switch driver?
401  if(interface->phyDriver != NULL)
402  {
403  //Enable Ethernet PHY interrupts
404  interface->phyDriver->enableIrq(interface);
405  }
406  else if(interface->switchDriver != NULL)
407  {
408  //Enable Ethernet switch interrupts
409  interface->switchDriver->enableIrq(interface);
410  }
411  else
412  {
413  //Just for sanity
414  }
415 }
416 
417 
418 /**
419  * @brief Disable interrupts
420  * @param[in] interface Underlying network interface
421  **/
422 
424 {
425  //Disable Ethernet MAC interrupts
426  NVIC_DisableIRQ(EMAC_0_IRQn);
427 
428  //Valid Ethernet PHY or switch driver?
429  if(interface->phyDriver != NULL)
430  {
431  //Disable Ethernet PHY interrupts
432  interface->phyDriver->disableIrq(interface);
433  }
434  else if(interface->switchDriver != NULL)
435  {
436  //Disable Ethernet switch interrupts
437  interface->switchDriver->disableIrq(interface);
438  }
439  else
440  {
441  //Just for sanity
442  }
443 }
444 
445 
446 /**
447  * @brief MCX E31B Ethernet MAC interrupt service routine
448  **/
449 
451 {
452  bool_t flag;
453  uint32_t status;
454 
455  //Interrupt service routine prologue
456  osEnterIsr();
457 
458  //This flag will be set if a higher priority task must be woken
459  flag = FALSE;
460 
461  //Read DMA status register
462  status = EMAC->DMA_CH[0].DMA_CHX_STAT;
463 
464  //Packet transmitted?
465  if((status & EMAC_DMA_CHX_STAT_TI_MASK) != 0)
466  {
467  //Clear TI interrupt flag
468  EMAC->DMA_CH[0].DMA_CHX_STAT = EMAC_DMA_CHX_STAT_TI_MASK;
469 
470  //Check whether the TX buffer is available for writing
471  if((txDmaDesc[txIndex].tdes3 & EMAC_TDES3_OWN) == 0)
472  {
473  //Notify the TCP/IP stack that the transmitter is ready to send
474  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
475  }
476  }
477 
478  //Packet received?
479  if((status & EMAC_DMA_CHX_STAT_RI_MASK) != 0)
480  {
481  //Clear RI interrupt flag
482  EMAC->DMA_CH[0].DMA_CHX_STAT = EMAC_DMA_CHX_STAT_RI_MASK;
483 
484  //Set event flag
485  nicDriverInterface->nicEvent = TRUE;
486  //Notify the TCP/IP stack of the event
487  flag |= osSetEventFromIsr(&nicDriverInterface->netContext->event);
488  }
489 
490  //Clear NIS interrupt flag
491  EMAC->DMA_CH[0].DMA_CHX_STAT = EMAC_DMA_CHX_STAT_NIS_MASK;
492 
493  //Interrupt service routine epilogue
494  osExitIsr(flag);
495 }
496 
497 
498 /**
499  * @brief MCX E31B Ethernet MAC event handler
500  * @param[in] interface Underlying network interface
501  **/
502 
504 {
505  error_t error;
506 
507  //Process all pending packets
508  do
509  {
510  //Read incoming packet
511  error = mcxe31bEthReceivePacket(interface);
512 
513  //No more data in the receive buffer?
514  } while(error != ERROR_BUFFER_EMPTY);
515 }
516 
517 
518 /**
519  * @brief Send a packet
520  * @param[in] interface Underlying network interface
521  * @param[in] buffer Multi-part buffer containing the data to send
522  * @param[in] offset Offset to the first data byte
523  * @param[in] ancillary Additional options passed to the stack along with
524  * the packet
525  * @return Error code
526  **/
527 
529  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
530 {
531  size_t length;
532 
533  //Retrieve the length of the packet
534  length = netBufferGetLength(buffer) - offset;
535 
536  //Check the frame length
538  {
539  //The transmitter can accept another packet
540  osSetEvent(&interface->nicTxEvent);
541  //Report an error
542  return ERROR_INVALID_LENGTH;
543  }
544 
545  //Make sure the current buffer is available for writing
546  if((txDmaDesc[txIndex].tdes3 & EMAC_TDES3_OWN) != 0)
547  {
548  return ERROR_FAILURE;
549  }
550 
551  //Copy user data to the transmit buffer
552  netBufferRead(txBuffer[txIndex], buffer, offset, length);
553 
554  //Set the start address of the buffer
555  txDmaDesc[txIndex].tdes0 = MEMORY_ConvertMemoryMapAddress(
556  (uint32_t) txBuffer[txIndex], kMEMORY_Local2DMA);
557 
558  //Write the number of bytes to send
559  txDmaDesc[txIndex].tdes2 = EMAC_TDES2_IOC | (length & EMAC_TDES2_B1L);
560  //Give the ownership of the descriptor to the DMA
562 
563  //Data synchronization barrier
564  __DSB();
565 
566  //Clear TBU flag to resume processing
567  EMAC->DMA_CH[0].DMA_CHX_STAT = EMAC_DMA_CHX_STAT_TBU_MASK;
568  //Instruct the DMA to poll the transmit descriptor list
569  EMAC->DMA_CH[0].DMA_CHX_TXDESC_TAIL_PTR = 0;
570 
571  //Increment index and wrap around if necessary
572  if(++txIndex >= MCXE31B_ETH_TX_BUFFER_COUNT)
573  {
574  txIndex = 0;
575  }
576 
577  //Check whether the next buffer is available for writing
578  if((txDmaDesc[txIndex].tdes3 & EMAC_TDES3_OWN) == 0)
579  {
580  //The transmitter can accept another packet
581  osSetEvent(&interface->nicTxEvent);
582  }
583 
584  //Data successfully written
585  return NO_ERROR;
586 }
587 
588 
589 /**
590  * @brief Receive a packet
591  * @param[in] interface Underlying network interface
592  * @return Error code
593  **/
594 
596 {
597  error_t error;
598  size_t n;
599  NetRxAncillary ancillary;
600 
601  //Current buffer available for reading?
602  if((rxDmaDesc[rxIndex].rdes3 & EMAC_RDES3_OWN) == 0)
603  {
604  //FD and LD flags should be set
605  if((rxDmaDesc[rxIndex].rdes3 & EMAC_RDES3_FD) != 0 &&
606  (rxDmaDesc[rxIndex].rdes3 & EMAC_RDES3_LD) != 0)
607  {
608  //Make sure no error occurred
609  if((rxDmaDesc[rxIndex].rdes3 & EMAC_RDES3_ES) == 0)
610  {
611  //Retrieve the length of the frame
612  n = rxDmaDesc[rxIndex].rdes3 & EMAC_RDES3_PL;
613  //Limit the number of data to read
615 
616  //Additional options can be passed to the stack along with the packet
617  ancillary = NET_DEFAULT_RX_ANCILLARY;
618 
619  //Pass the packet to the upper layer
620  nicProcessPacket(interface, rxBuffer[rxIndex], n, &ancillary);
621 
622  //Valid packet received
623  error = NO_ERROR;
624  }
625  else
626  {
627  //The received packet contains an error
628  error = ERROR_INVALID_PACKET;
629  }
630  }
631  else
632  {
633  //The packet is not valid
634  error = ERROR_INVALID_PACKET;
635  }
636 
637  //Set the start address of the buffer
638  rxDmaDesc[rxIndex].rdes0 = MEMORY_ConvertMemoryMapAddress(
639  (uint32_t) rxBuffer[rxIndex], kMEMORY_Local2DMA);
640 
641  //Give the ownership of the descriptor back to the DMA
643 
644  //Increment index and wrap around if necessary
645  if(++rxIndex >= MCXE31B_ETH_RX_BUFFER_COUNT)
646  {
647  rxIndex = 0;
648  }
649  }
650  else
651  {
652  //No more data in the receive buffer
653  error = ERROR_BUFFER_EMPTY;
654  }
655 
656  //Clear RBU flag to resume processing
657  EMAC->DMA_CH[0].DMA_CHX_STAT = EMAC_DMA_CHX_STAT_RBU_MASK;
658  //Instruct the DMA to poll the receive descriptor list
659  EMAC->DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR = 0;
660 
661  //Return status code
662  return error;
663 }
664 
665 
666 /**
667  * @brief Configure MAC address filtering
668  * @param[in] interface Underlying network interface
669  * @return Error code
670  **/
671 
673 {
674  uint_t i;
675  uint_t j;
676  uint_t k;
677  uint32_t crc;
678  uint32_t hashTable[2];
679  MacAddr unicastMacAddr[2];
680  MacFilterEntry *entry;
681 
682  //Debug message
683  TRACE_DEBUG("Updating MAC filter...\r\n");
684 
685  //Promiscuous mode?
686  if(interface->promiscuous)
687  {
688  //Pass all incoming frames regardless of their destination address
689  EMAC->MAC_PACKET_FILTER = EMAC_MAC_PACKET_FILTER_PR_MASK;
690  }
691  else
692  {
693  //Set the MAC address of the station
694  EMAC->MAC_ADDRESS[0].LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
695  EMAC->MAC_ADDRESS[0].HIGH = interface->macAddr.w[2];
696 
697  //The MAC supports 2 additional addresses for unicast perfect filtering
698  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
699  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
700 
701  //The hash table is used for multicast address filtering
702  hashTable[0] = 0;
703  hashTable[1] = 0;
704 
705  //The MAC address filter contains the list of MAC addresses to accept
706  //when receiving an Ethernet frame
707  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
708  {
709  //Point to the current entry
710  entry = &interface->macAddrFilter[i];
711 
712  //Valid entry?
713  if(entry->refCount > 0)
714  {
715  //Multicast address?
716  if(macIsMulticastAddr(&entry->addr))
717  {
718  //Compute CRC over the current MAC address
719  crc = mcxe31bEthCalcCrc(&entry->addr, sizeof(MacAddr));
720 
721  //The upper 6 bits in the CRC register are used to index the
722  //contents of the hash table
723  k = (crc >> 26) & 0x3F;
724 
725  //Update hash table contents
726  hashTable[k / 32] |= (1 << (k % 32));
727  }
728  else
729  {
730  //Up to 2 additional MAC addresses can be specified
731  if(j < 2)
732  {
733  //Save the unicast address
734  unicastMacAddr[j++] = entry->addr;
735  }
736  }
737  }
738  }
739 
740  //Configure the first unicast address filter
741  if(j >= 1)
742  {
743  //When the AE bit is set, the entry is used for perfect filtering
744  EMAC->MAC_ADDRESS[1].LOW = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
745  EMAC->MAC_ADDRESS[1].HIGH = unicastMacAddr[0].w[2] | EMAC_HIGH_AE_MASK;
746  }
747  else
748  {
749  //When the AE bit is cleared, the entry is ignored
750  EMAC->MAC_ADDRESS[1].LOW = 0;
751  EMAC->MAC_ADDRESS[1].HIGH = 0;
752  }
753 
754  //Configure the second unicast address filter
755  if(j >= 2)
756  {
757  //When the AE bit is set, the entry is used for perfect filtering
758  EMAC->MAC_ADDRESS[2].LOW = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
759  EMAC->MAC_ADDRESS[2].HIGH = unicastMacAddr[1].w[2] | EMAC_HIGH_AE_MASK;
760  }
761  else
762  {
763  //When the AE bit is cleared, the entry is ignored
764  EMAC->MAC_ADDRESS[2].LOW = 0;
765  EMAC->MAC_ADDRESS[2].HIGH = 0;
766  }
767 
768  //Check whether frames with a multicast destination address should be
769  //accepted
770  if(interface->acceptAllMulticast)
771  {
772  //Configure the receive filter
773  EMAC->MAC_PACKET_FILTER = EMAC_MAC_PACKET_FILTER_HPF_MASK |
774  EMAC_MAC_PACKET_FILTER_PM_MASK;
775  }
776  else
777  {
778  //Configure the receive filter
779  EMAC->MAC_PACKET_FILTER = EMAC_MAC_PACKET_FILTER_HPF_MASK |
780  EMAC_MAC_PACKET_FILTER_HMC_MASK;
781 
782  //Configure the multicast hash table
783  EMAC->MAC_HASH_TABLE_REG0 = hashTable[0];
784  EMAC->MAC_HASH_TABLE_REG1 = hashTable[1];
785 
786  //Debug message
787  TRACE_DEBUG(" MAC_HASH_TABLE_REG0 = 0x%08" PRIX32 "\r\n", EMAC->MAC_HASH_TABLE_REG0);
788  TRACE_DEBUG(" MAC_HASH_TABLE_REG1 = 0x%08" PRIX32 "\r\n", EMAC->MAC_HASH_TABLE_REG1);
789  }
790  }
791 
792  //Successful processing
793  return NO_ERROR;
794 }
795 
796 
797 /**
798  * @brief Adjust MAC configuration parameters for proper operation
799  * @param[in] interface Underlying network interface
800  * @return Error code
801  **/
802 
804 {
805  uint32_t config;
806 
807  //Read current MAC configuration
808  config = EMAC->MAC_CONFIGURATION;
809 
810  //10BASE-T or 100BASE-TX operation mode?
811  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
812  {
813  config |= EMAC_MAC_CONFIGURATION_FES_MASK;
814  }
815  else
816  {
817  config &= ~EMAC_MAC_CONFIGURATION_FES_MASK;
818  }
819 
820  //Half-duplex or full-duplex mode?
821  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
822  {
823  config |= EMAC_MAC_CONFIGURATION_DM_MASK;
824  }
825  else
826  {
827  config &= ~EMAC_MAC_CONFIGURATION_DM_MASK;
828  }
829 
830  //Update MAC configuration register
831  EMAC->MAC_CONFIGURATION = config;
832 
833  //Successful processing
834  return NO_ERROR;
835 }
836 
837 
838 /**
839  * @brief Write PHY register
840  * @param[in] opcode Access type (2 bits)
841  * @param[in] phyAddr PHY address (5 bits)
842  * @param[in] regAddr Register address (5 bits)
843  * @param[in] data Register value
844  **/
845 
846 void mcxe31bEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
847  uint8_t regAddr, uint16_t data)
848 {
849  uint32_t temp;
850 
851  //Valid opcode?
852  if(opcode == SMI_OPCODE_WRITE)
853  {
854  //Take care not to alter MDC clock configuration
855  temp = EMAC->MAC_MDIO_ADDRESS & EMAC_MAC_MDIO_ADDRESS_CR_MASK;
856  //Set up a write operation
857  temp |= EMAC_MAC_MDIO_ADDRESS_GOC_0_MASK | EMAC_MAC_MDIO_ADDRESS_GB_MASK;
858 
859  //PHY address
860  temp |= EMAC_MAC_MDIO_ADDRESS_PA(phyAddr);
861  //Register address
862  temp |= EMAC_MAC_MDIO_ADDRESS_RDA(regAddr);
863 
864  //Data to be written in the PHY register
865  EMAC->MAC_MDIO_DATA = data & EMAC_MAC_MDIO_DATA_GD_MASK;
866 
867  //Start a write operation
868  EMAC->MAC_MDIO_ADDRESS = temp;
869  //Wait for the write to complete
870  while((EMAC->MAC_MDIO_ADDRESS & EMAC_MAC_MDIO_ADDRESS_GB_MASK) != 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 mcxe31bEthReadPhyReg(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 = EMAC->MAC_MDIO_ADDRESS & EMAC_MAC_MDIO_ADDRESS_CR_MASK;
900 
901  //Set up a read operation
902  temp |= EMAC_MAC_MDIO_ADDRESS_GOC_1_MASK |
903  EMAC_MAC_MDIO_ADDRESS_GOC_0_MASK | EMAC_MAC_MDIO_ADDRESS_GB_MASK;
904 
905  //PHY address
906  temp |= EMAC_MAC_MDIO_ADDRESS_PA(phyAddr);
907  //Register address
908  temp |= EMAC_MAC_MDIO_ADDRESS_RDA(regAddr);
909 
910  //Start a read operation
911  EMAC->MAC_MDIO_ADDRESS = temp;
912  //Wait for the read to complete
913  while((EMAC->MAC_MDIO_ADDRESS & EMAC_MAC_MDIO_ADDRESS_GB_MASK) != 0)
914  {
915  }
916 
917  //Get register value
918  data = EMAC->MAC_MDIO_DATA & EMAC_MAC_MDIO_DATA_GD_MASK;
919  }
920  else
921  {
922  //The MAC peripheral only supports standard Clause 22 opcodes
923  data = 0;
924  }
925 
926  //Return the value of the PHY register
927  return data;
928 }
929 
930 
931 /**
932  * @brief CRC calculation
933  * @param[in] data Pointer to the data over which to calculate the CRC
934  * @param[in] length Number of bytes to process
935  * @return Resulting CRC value
936  **/
937 
938 uint32_t mcxe31bEthCalcCrc(const void *data, size_t length)
939 {
940  uint_t i;
941  uint_t j;
942  uint32_t crc;
943  const uint8_t *p;
944 
945  //Point to the data over which to calculate the CRC
946  p = (uint8_t *) data;
947  //CRC preset value
948  crc = 0xFFFFFFFF;
949 
950  //Loop through data
951  for(i = 0; i < length; i++)
952  {
953  //The message is processed bit by bit
954  for(j = 0; j < 8; j++)
955  {
956  //Update CRC value
957  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
958  {
959  crc = (crc << 1) ^ 0x04C11DB7;
960  }
961  else
962  {
963  crc = crc << 1;
964  }
965  }
966  }
967 
968  //Return CRC value
969  return ~crc;
970 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void mcxe31bEthEventHandler(NetInterface *interface)
MCX E31B Ethernet MAC event handler.
#define EMAC_TDES3_OWN
uint8_t opcode
Definition: dns_common.h:191
int bool_t
Definition: compiler_port.h:63
#define EMAC_RDES3_PL
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
error_t mcxe31bEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:690
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define EMAC_RDES3_BUF1V
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
#define EMAC_RDES3_ES
uint8_t data[]
Definition: ethernet.h:224
#define sleep(delay)
Definition: os_port.h:310
void mcxe31bEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
error_t mcxe31bEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
Receive descriptor.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define osExitIsr(flag)
#define EMAC_TDES3_FD
void mcxe31bEthEnableIrq(NetInterface *interface)
Enable interrupts.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define MCXE31B_ETH_TX_BUFFER_SIZE
#define MCXE31B_ETH_RX_BUFFER_SIZE
#define FALSE
Definition: os_port.h:46
error_t
Error codes.
Definition: error.h:43
Transmit descriptor.
#define EMAC_TDES3_LD
const NicDriver mcxe31bEthDriver
MCX E31B Ethernet MAC driver.
error_t mcxe31bEthReceivePacket(NetInterface *interface)
Receive a packet.
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
uint16_t mcxe31bEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define txBuffer
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
MacAddr addr
MAC address.
Definition: ethernet.h:265
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
uint32_t mcxe31bEthCalcCrc(const void *data, size_t length)
CRC calculation.
void mcxe31bEthDisableIrq(NetInterface *interface)
Disable interrupts.
#define NetTxAncillary
Definition: net_misc.h:36
#define SMI_OPCODE_READ
Definition: nic.h:67
void mcxe31bEthTick(NetInterface *interface)
MCX E31B Ethernet MAC timer handler.
#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 MCXE31B_ETH_IRQ_PRIORITY_GROUPING
#define MIN(a, b)
Definition: os_port.h:63
#define rxBuffer
MacAddr
Definition: ethernet.h:197
#define MCXE31B_ETH_IRQ_GROUP_PRIORITY
#define EMAC_RDES3_FD
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define MCXE31B_ETH_IRQ_SUB_PRIORITY
#define EMAC_TDES2_IOC
void mcxe31bEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
void EMAC_0_IRQHandler(void)
MCX E31B Ethernet MAC interrupt service routine.
#define MCXE31B_ETH_RX_BUFFER_COUNT
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
MAC filter table entry.
Definition: ethernet.h:264
#define osEnterIsr()
error_t mcxe31bEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define EMAC_RDES3_LD
#define EMAC_RDES3_IOC
#define EMAC_RDES3_OWN
#define rxDmaDesc
error_t mcxe31bEthInit(NetInterface *interface)
MCX E31B Ethernet MAC initialization.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define EMAC_TDES2_B1L
#define txDmaDesc
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
NIC driver.
Definition: nic.h:286
__weak_func void mcxe31bEthInitGpio(NetInterface *interface)
GPIO configuration.
NXP MCX E31B Ethernet MAC driver.
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
@ NO_ERROR
Success.
Definition: error.h:44
#define MCXE31B_ETH_RAM_SECTION
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
#define MCXE31B_ETH_TX_BUFFER_COUNT
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83