xmc4400_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file xmc4400_eth_driver.c
3  * @brief Infineon XMC4400 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 "xmc4400.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 = XMC4400_ETH_RAM_SECTION
50 //Receive buffer
51 #pragma data_alignment = 4
52 #pragma location = XMC4400_ETH_RAM_SECTION
54 //Transmit DMA descriptors
55 #pragma data_alignment = 4
56 #pragma location = XMC4400_ETH_RAM_SECTION
58 //Receive DMA descriptors
59 #pragma data_alignment = 4
60 #pragma location = XMC4400_ETH_RAM_SECTION
62 
63 //Keil MDK-ARM or GCC compiler?
64 #else
65 
66 //Transmit buffer
68  __attribute__((aligned(4), __section__(XMC4400_ETH_RAM_SECTION)));
69 //Receive buffer
71  __attribute__((aligned(4), __section__(XMC4400_ETH_RAM_SECTION)));
72 //Transmit DMA descriptors
74  __attribute__((aligned(4), __section__(XMC4400_ETH_RAM_SECTION)));
75 //Receive DMA descriptors
77  __attribute__((aligned(4), __section__(XMC4400_ETH_RAM_SECTION)));
78 
79 #endif
80 
81 //Pointer to the current TX DMA descriptor
82 static Xmc4400TxDmaDesc *txCurDmaDesc;
83 //Pointer to the current RX DMA descriptor
84 static Xmc4400RxDmaDesc *rxCurDmaDesc;
85 
86 
87 /**
88  * @brief XMC4400 Ethernet MAC driver
89  **/
90 
92 {
94  ETH_MTU,
105  TRUE,
106  TRUE,
107  TRUE,
108  FALSE
109 };
110 
111 
112 /**
113  * @brief XMC4400 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 XMC4400 Ethernet MAC...\r\n");
124 
125  //Save underlying network interface
126  nicDriverInterface = interface;
127 
128  //Disable parity error trap
129  SCU_PARITY->PETE = 0;
130  //Disable unaligned access trap
131  PPB->CCR &= ~PPB_CCR_UNALIGN_TRP_Msk;
132 
133  //Enable ETH0 peripheral clock
134  SCU_CLK->CLKSET = SCU_CLK_CLKSET_ETH0CEN_Msk;
135 
136  //GPIO configuration
137  xmc4400EthInitGpio(interface);
138 
139  //Reset ETH0 peripheral
140  SCU_RESET->PRSET2 = SCU_RESET_PRSET2_ETH0RS_Msk;
141  SCU_RESET->PRCLR2 = SCU_RESET_PRCLR2_ETH0RS_Msk;
142 
143  //Reset DMA controller
144  ETH0->BUS_MODE |= ETH_BUS_MODE_SWR_Msk;
145  //Wait for the reset to complete
146  while((ETH0->BUS_MODE & ETH_BUS_MODE_SWR_Msk) != 0)
147  {
148  }
149 
150  //Adjust MDC clock range depending on ETH clock frequency
151  ETH0->GMII_ADDRESS = ETH_GMII_ADDRESS_CR_DIV62;
152 
153  //Valid Ethernet PHY or switch driver?
154  if(interface->phyDriver != NULL)
155  {
156  //Ethernet PHY initialization
157  error = interface->phyDriver->init(interface);
158  }
159  else if(interface->switchDriver != NULL)
160  {
161  //Ethernet switch initialization
162  error = interface->switchDriver->init(interface);
163  }
164  else
165  {
166  //The interface is not properly configured
167  error = ERROR_FAILURE;
168  }
169 
170  //Any error to report?
171  if(error)
172  {
173  return error;
174  }
175 
176  //Use default MAC configuration
177  ETH0->MAC_CONFIGURATION = ETH_MAC_CONFIGURATION_RESERVED15_Msk |
178  ETH_MAC_CONFIGURATION_DO_Msk;
179 
180  //Set the MAC address of the station
181  ETH0->MAC_ADDRESS0_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
182  ETH0->MAC_ADDRESS0_HIGH = interface->macAddr.w[2];
183 
184  //The MAC supports 3 additional addresses for unicast perfect filtering
185  ETH0->MAC_ADDRESS1_LOW = 0;
186  ETH0->MAC_ADDRESS1_HIGH = 0;
187  ETH0->MAC_ADDRESS2_LOW = 0;
188  ETH0->MAC_ADDRESS2_HIGH = 0;
189  ETH0->MAC_ADDRESS3_LOW = 0;
190  ETH0->MAC_ADDRESS3_HIGH = 0;
191 
192  //Initialize hash table
193  ETH0->HASH_TABLE_LOW = 0;
194  ETH0->HASH_TABLE_HIGH = 0;
195 
196  //Configure the receive filter
197  ETH0->MAC_FRAME_FILTER = ETH_MAC_FRAME_FILTER_HPF_Msk | ETH_MAC_FRAME_FILTER_HMC_Msk;
198  //Disable flow control
199  ETH0->FLOW_CONTROL = 0;
200  //Enable store and forward mode
201  ETH0->OPERATION_MODE = ETH_OPERATION_MODE_RSF_Msk | ETH_OPERATION_MODE_TSF_Msk;
202 
203  //Configure DMA bus mode
204  ETH0->BUS_MODE = ETH_BUS_MODE_AAL_Msk | ETH_BUS_MODE_USP_Msk |
206 
207  //Initialize DMA descriptor lists
208  xmc4400EthInitDmaDesc(interface);
209 
210  //Prevent interrupts from being generated when statistic counters reach
211  //half their maximum value
212  ETH0->MMC_TRANSMIT_INTERRUPT_MASK = 0xFFFFFFFF;
213  ETH0->MMC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF;
214  ETH0->MMC_IPC_RECEIVE_INTERRUPT_MASK = 0xFFFFFFFF;
215 
216  //Disable MAC interrupts
217  ETH0->INTERRUPT_MASK = ETH_INTERRUPT_MASK_TSIM_Msk | ETH_INTERRUPT_MASK_PMTIM_Msk;
218 
219  //Enable the desired DMA interrupts
220  ETH0->INTERRUPT_ENABLE = ETH_INTERRUPT_ENABLE_NIE_Msk |
221  ETH_INTERRUPT_ENABLE_RIE_Msk | ETH_INTERRUPT_ENABLE_TIE_Msk;
222 
223  //Set priority grouping (6 bits for pre-emption priority, no bits for subpriority)
224  NVIC_SetPriorityGrouping(XMC4400_ETH_IRQ_PRIORITY_GROUPING);
225 
226  //Configure Ethernet interrupt priority
227  NVIC_SetPriority(ETH0_0_IRQn, NVIC_EncodePriority(XMC4400_ETH_IRQ_PRIORITY_GROUPING,
229 
230  //Enable MAC transmission and reception
231  ETH0->MAC_CONFIGURATION |= ETH_MAC_CONFIGURATION_TE_Msk | ETH_MAC_CONFIGURATION_RE_Msk;
232  //Enable DMA transmission and reception
233  ETH0->OPERATION_MODE |= ETH_OPERATION_MODE_ST_Msk | ETH_OPERATION_MODE_SR_Msk;
234 
235  //Accept any packets from the upper layer
236  osSetEvent(&interface->nicTxEvent);
237 
238  //Successful initialization
239  return NO_ERROR;
240 }
241 
242 
243 /**
244  * @brief GPIO configuration
245  * @param[in] interface Underlying network interface
246  **/
247 
248 __weak_func void xmc4400EthInitGpio(NetInterface *interface)
249 {
250 //XMC4400 Platform2GO Kit?
251 #if defined(USE_KIT_XMC4400_PLT2GO)
252  uint32_t temp;
253 
254  //Configure ETH0.TX_EN (P0.4)
255  temp = PORT0->IOCR4;
256  temp &= ~PORT0_IOCR4_PC4_Msk;
257  temp |= (17UL << PORT0_IOCR4_PC4_Pos);
258  PORT0->IOCR4 = temp;
259 
260  //Configure ETH0.MDIO (P2.0), ETH0.RXD0A (P2.2) and ETH0.RXD1A (P2.3)
261  temp = PORT2->IOCR0;
262  temp &= ~(PORT2_IOCR0_PC0_Msk | PORT2_IOCR0_PC2_Msk | PORT2_IOCR0_PC3_Msk);
263  temp |= (0UL << PORT2_IOCR0_PC0_Pos) | (0UL << PORT2_IOCR0_PC2_Pos) | (0UL << PORT2_IOCR0_PC3_Pos);
264  PORT2->IOCR0 = temp;
265 
266  //Configure ETH0.RXERA (P2.4)and ETH0.MDC (P2.7)
267  temp = PORT2->IOCR4;
268  temp &= ~(PORT2_IOCR4_PC4_Msk | PORT2_IOCR4_PC7_Msk);
269  temp |= (0UL << PORT2_IOCR4_PC4_Pos) | (17UL << PORT2_IOCR4_PC7_Pos);
270  PORT2->IOCR4 = temp;
271 
272  //Configure ETH0.TXD0 (P2.8) and ETH0.TXD1 (P2.9)
273  temp = PORT2->IOCR8;
274  temp &= ~(PORT2_IOCR8_PC8_Msk | PORT2_IOCR8_PC9_Msk);
275  temp |= (17UL << PORT2_IOCR8_PC8_Pos) | (17UL << PORT2_IOCR8_PC9_Pos);
276  PORT2->IOCR8 = temp;
277 
278  //Configure ETH0.CLK_RMIIC (P15.8) and ETH0.CRS_DVC (P15.9)
279  temp = PORT15->IOCR8;
280  temp &= ~(PORT15_IOCR8_PC8_Msk | PORT15_IOCR8_PC9_Msk);
281  temp |= (0UL << PORT15_IOCR8_PC8_Pos) | (0UL << PORT15_IOCR8_PC9_Pos);
282  PORT15->IOCR8 = temp;
283 
284  //Assign ETH_MDIO (P2.0) to HW0
285  temp = PORT2->HWSEL & ~PORT2_HWSEL_HW0_Msk;
286  PORT2->HWSEL = temp | (1UL << PORT2_HWSEL_HW0_Pos);
287 
288  //Select output driver strength for ETH0.TX_EN (P2.5)
289  temp = PORT2->PDR0;
290  temp &= ~PORT2_PDR0_PD5_Msk;
291  temp |= (0UL << PORT2_PDR0_PD5_Pos);
292  PORT2->PDR0 = temp;
293 
294  //Select output driver strength for ETH0.TXD0 (P2.8) and ETH0.TXD1 (P2.9)
295  temp = PORT2->PDR1;
296  temp &= ~(PORT2_PDR1_PD8_Msk | PORT2_PDR1_PD9_Msk);
297  temp |= (0UL << PORT2_PDR1_PD8_Pos) | (0UL << PORT2_PDR1_PD9_Pos);
298  PORT2->PDR1 = temp;
299 
300  //Use ETH0.CLK_RMIIC (P15.8) and ETH0.CRS_DVC (P15.9) as digital inputs
301  PORT15->PDISC &= ~(PORT15_PDISC_PDIS8_Msk | PORT15_PDISC_PDIS9_Msk);
302 
303  //Select RMII operation mode
304  ETH0_CON->CON = ETH_CON_INFSEL_Msk | ETH_CON_MDIO_B | ETH_CON_RXER_A |
306 #endif
307 }
308 
309 
310 /**
311  * @brief Initialize DMA descriptor lists
312  * @param[in] interface Underlying network interface
313  **/
314 
316 {
317  uint_t i;
318 
319  //Initialize TX DMA descriptor list
320  for(i = 0; i < XMC4400_ETH_TX_BUFFER_COUNT; i++)
321  {
322  //Use chain structure rather than ring structure
323  txDmaDesc[i].tdes0 = ETH_TDES0_IC | ETH_TDES0_TCH;
324  //Initialize transmit buffer size
325  txDmaDesc[i].tdes1 = 0;
326  //Transmit buffer address
327  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
328  //Next descriptor address
329  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
330  }
331 
332  //The last descriptor is chained to the first entry
333  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
334  //Point to the very first descriptor
335  txCurDmaDesc = &txDmaDesc[0];
336 
337  //Initialize RX DMA descriptor list
338  for(i = 0; i < XMC4400_ETH_RX_BUFFER_COUNT; i++)
339  {
340  //The descriptor is initially owned by the DMA
341  rxDmaDesc[i].rdes0 = ETH_RDES0_OWN;
342  //Use chain structure rather than ring structure
344  //Receive buffer address
345  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
346  //Next descriptor address
347  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
348  }
349 
350  //The last descriptor is chained to the first entry
351  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
352  //Point to the very first descriptor
353  rxCurDmaDesc = &rxDmaDesc[0];
354 
355  //Start location of the TX descriptor list
356  ETH0->TRANSMIT_DESCRIPTOR_LIST_ADDRESS = (uint32_t) txDmaDesc;
357  //Start location of the RX descriptor list
358  ETH0->RECEIVE_DESCRIPTOR_LIST_ADDRESS = (uint32_t) rxDmaDesc;
359 }
360 
361 
362 /**
363  * @brief XMC4400 Ethernet MAC timer handler
364  *
365  * This routine is periodically called by the TCP/IP stack to handle periodic
366  * operations such as polling the link state
367  *
368  * @param[in] interface Underlying network interface
369  **/
370 
371 void xmc4400EthTick(NetInterface *interface)
372 {
373  //Valid Ethernet PHY or switch driver?
374  if(interface->phyDriver != NULL)
375  {
376  //Handle periodic operations
377  interface->phyDriver->tick(interface);
378  }
379  else if(interface->switchDriver != NULL)
380  {
381  //Handle periodic operations
382  interface->switchDriver->tick(interface);
383  }
384  else
385  {
386  //Just for sanity
387  }
388 }
389 
390 
391 /**
392  * @brief Enable interrupts
393  * @param[in] interface Underlying network interface
394  **/
395 
397 {
398  //Enable Ethernet MAC interrupts
399  NVIC_EnableIRQ(ETH0_0_IRQn);
400 
401  //Valid Ethernet PHY or switch driver?
402  if(interface->phyDriver != NULL)
403  {
404  //Enable Ethernet PHY interrupts
405  interface->phyDriver->enableIrq(interface);
406  }
407  else if(interface->switchDriver != NULL)
408  {
409  //Enable Ethernet switch interrupts
410  interface->switchDriver->enableIrq(interface);
411  }
412  else
413  {
414  //Just for sanity
415  }
416 }
417 
418 
419 /**
420  * @brief Disable interrupts
421  * @param[in] interface Underlying network interface
422  **/
423 
425 {
426  //Disable Ethernet MAC interrupts
427  NVIC_DisableIRQ(ETH0_0_IRQn);
428 
429  //Valid Ethernet PHY or switch driver?
430  if(interface->phyDriver != NULL)
431  {
432  //Disable Ethernet PHY interrupts
433  interface->phyDriver->disableIrq(interface);
434  }
435  else if(interface->switchDriver != NULL)
436  {
437  //Disable Ethernet switch interrupts
438  interface->switchDriver->disableIrq(interface);
439  }
440  else
441  {
442  //Just for sanity
443  }
444 }
445 
446 
447 /**
448  * @brief XMC4400 Ethernet MAC interrupt service routine
449  **/
450 
452 {
453  bool_t flag;
454  uint32_t status;
455 
456  //Interrupt service routine prologue
457  osEnterIsr();
458 
459  //This flag will be set if a higher priority task must be woken
460  flag = FALSE;
461 
462  //Read DMA status register
463  status = ETH0->STATUS;
464 
465  //Packet transmitted?
466  if((status & ETH_STATUS_TI_Msk) != 0)
467  {
468  //Clear TI interrupt flag
469  ETH0->STATUS = ETH_STATUS_TI_Msk;
470 
471  //Check whether the TX buffer is available for writing
472  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
473  {
474  //Notify the TCP/IP stack that the transmitter is ready to send
475  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
476  }
477  }
478 
479  //Packet received?
480  if((status & ETH_STATUS_RI_Msk) != 0)
481  {
482  //Clear RI interrupt flag
483  ETH0->STATUS = ETH_STATUS_RI_Msk;
484 
485  //Set event flag
486  nicDriverInterface->nicEvent = TRUE;
487  //Notify the TCP/IP stack of the event
488  flag |= osSetEventFromIsr(&netEvent);
489  }
490 
491  //Clear NIS interrupt flag
492  ETH0->STATUS = ETH_STATUS_NIS_Msk;
493 
494  //Interrupt service routine epilogue
495  osExitIsr(flag);
496 }
497 
498 
499 /**
500  * @brief XMC4400 Ethernet MAC event handler
501  * @param[in] interface Underlying network interface
502  **/
503 
505 {
506  error_t error;
507 
508  //Process all pending packets
509  do
510  {
511  //Read incoming packet
512  error = xmc4400EthReceivePacket(interface);
513 
514  //No more data in the receive buffer?
515  } while(error != ERROR_BUFFER_EMPTY);
516 }
517 
518 
519 /**
520  * @brief Send a packet
521  * @param[in] interface Underlying network interface
522  * @param[in] buffer Multi-part buffer containing the data to send
523  * @param[in] offset Offset to the first data byte
524  * @param[in] ancillary Additional options passed to the stack along with
525  * the packet
526  * @return Error code
527  **/
528 
530  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
531 {
532  size_t length;
533 
534  //Retrieve the length of the packet
535  length = netBufferGetLength(buffer) - offset;
536 
537  //Check the frame length
539  {
540  //The transmitter can accept another packet
541  osSetEvent(&interface->nicTxEvent);
542  //Report an error
543  return ERROR_INVALID_LENGTH;
544  }
545 
546  //Make sure the current buffer is available for writing
547  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) != 0)
548  {
549  return ERROR_FAILURE;
550  }
551 
552  //Copy user data to the transmit buffer
553  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
554 
555  //Write the number of bytes to send
556  txCurDmaDesc->tdes1 = length & ETH_TDES1_TBS1;
557  //Set LS and FS flags as the data fits in a single buffer
558  txCurDmaDesc->tdes0 |= ETH_TDES0_LS | ETH_TDES0_FS;
559  //Give the ownership of the descriptor to the DMA
560  txCurDmaDesc->tdes0 |= ETH_TDES0_OWN;
561 
562  //Clear TU flag to resume processing
563  ETH0->STATUS = ETH_STATUS_TU_Msk;
564  //Instruct the DMA to poll the transmit descriptor list
565  ETH0->TRANSMIT_POLL_DEMAND = 0;
566 
567  //Point to the next descriptor in the list
568  txCurDmaDesc = (Xmc4400TxDmaDesc *) txCurDmaDesc->tdes3;
569 
570  //Check whether the next buffer is available for writing
571  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
572  {
573  //The transmitter can accept another packet
574  osSetEvent(&interface->nicTxEvent);
575  }
576 
577  //Data successfully written
578  return NO_ERROR;
579 }
580 
581 
582 /**
583  * @brief Receive a packet
584  * @param[in] interface Underlying network interface
585  * @return Error code
586  **/
587 
589 {
590  error_t error;
591  size_t n;
592  NetRxAncillary ancillary;
593 
594  //Current buffer available for reading?
595  if((rxCurDmaDesc->rdes0 & ETH_RDES0_OWN) == 0)
596  {
597  //FS and LS flags should be set
598  if((rxCurDmaDesc->rdes0 & ETH_RDES0_FS) != 0 &&
599  (rxCurDmaDesc->rdes0 & ETH_RDES0_LS) != 0)
600  {
601  //Make sure no error occurred
602  if((rxCurDmaDesc->rdes0 & ETH_RDES0_ES) == 0)
603  {
604  //Retrieve the length of the frame
605  n = (rxCurDmaDesc->rdes0 & ETH_RDES0_FL) >> 16;
606  //Limit the number of data to read
608 
609  //Additional options can be passed to the stack along with the packet
610  ancillary = NET_DEFAULT_RX_ANCILLARY;
611 
612  //Pass the packet to the upper layer
613  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
614  &ancillary);
615 
616  //Valid packet received
617  error = NO_ERROR;
618  }
619  else
620  {
621  //The received packet contains an error
622  error = ERROR_INVALID_PACKET;
623  }
624  }
625  else
626  {
627  //The packet is not valid
628  error = ERROR_INVALID_PACKET;
629  }
630 
631  //Give the ownership of the descriptor back to the DMA
632  rxCurDmaDesc->rdes0 = ETH_RDES0_OWN;
633  //Point to the next descriptor in the list
634  rxCurDmaDesc = (Xmc4400RxDmaDesc *) rxCurDmaDesc->rdes3;
635  }
636  else
637  {
638  //No more data in the receive buffer
639  error = ERROR_BUFFER_EMPTY;
640  }
641 
642  //Clear RU flag to resume processing
643  ETH0->STATUS = ETH_STATUS_RU_Msk;
644  //Instruct the DMA to poll the receive descriptor list
645  ETH0->RECEIVE_POLL_DEMAND = 0;
646 
647  //Return status code
648  return error;
649 }
650 
651 
652 /**
653  * @brief Configure MAC address filtering
654  * @param[in] interface Underlying network interface
655  * @return Error code
656  **/
657 
659 {
660  uint_t i;
661  uint_t j;
662  uint_t k;
663  uint32_t crc;
664  uint32_t hashTable[2];
665  MacAddr unicastMacAddr[3];
666  MacFilterEntry *entry;
667 
668  //Debug message
669  TRACE_DEBUG("Updating MAC filter...\r\n");
670 
671  //Set the MAC address of the station
672  ETH0->MAC_ADDRESS0_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
673  ETH0->MAC_ADDRESS0_HIGH = interface->macAddr.w[2];
674 
675  //The MAC supports 3 additional addresses for unicast perfect filtering
676  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
677  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
678  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
679 
680  //The hash table is used for multicast address filtering
681  hashTable[0] = 0;
682  hashTable[1] = 0;
683 
684  //The MAC address filter contains the list of MAC addresses to accept
685  //when receiving an Ethernet frame
686  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
687  {
688  //Point to the current entry
689  entry = &interface->macAddrFilter[i];
690 
691  //Valid entry?
692  if(entry->refCount > 0)
693  {
694  //Multicast address?
695  if(macIsMulticastAddr(&entry->addr))
696  {
697  //Compute CRC over the current MAC address
698  crc = xmc4400EthCalcCrc(&entry->addr, sizeof(MacAddr));
699 
700  //The upper 6 bits in the CRC register are used to index the
701  //contents of the hash table
702  k = (crc >> 26) & 0x3F;
703 
704  //Update hash table contents
705  hashTable[k / 32] |= (1 << (k % 32));
706  }
707  else
708  {
709  //Up to 3 additional MAC addresses can be specified
710  if(j < 3)
711  {
712  //Save the unicast address
713  unicastMacAddr[j++] = entry->addr;
714  }
715  }
716  }
717  }
718 
719  //Configure the first unicast address filter
720  if(j >= 1)
721  {
722  //When the AE bit is set, the entry is used for perfect filtering
723  ETH0->MAC_ADDRESS1_LOW = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
724  ETH0->MAC_ADDRESS1_HIGH = unicastMacAddr[0].w[2] | ETH_MAC_ADDRESS1_HIGH_AE_Msk;
725  }
726  else
727  {
728  //When the AE bit is cleared, the entry is ignored
729  ETH0->MAC_ADDRESS1_LOW = 0;
730  ETH0->MAC_ADDRESS1_HIGH = 0;
731  }
732 
733  //Configure the second unicast address filter
734  if(j >= 2)
735  {
736  //When the AE bit is set, the entry is used for perfect filtering
737  ETH0->MAC_ADDRESS2_LOW = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
738  ETH0->MAC_ADDRESS2_HIGH = unicastMacAddr[1].w[2] | ETH_MAC_ADDRESS2_HIGH_AE_Msk;
739  }
740  else
741  {
742  //When the AE bit is cleared, the entry is ignored
743  ETH0->MAC_ADDRESS2_LOW = 0;
744  ETH0->MAC_ADDRESS2_HIGH = 0;
745  }
746 
747  //Configure the third unicast address filter
748  if(j >= 3)
749  {
750  //When the AE bit is set, the entry is used for perfect filtering
751  ETH0->MAC_ADDRESS3_LOW = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
752  ETH0->MAC_ADDRESS3_HIGH = unicastMacAddr[2].w[2] | ETH_MAC_ADDRESS3_HIGH_AE_Msk;
753  }
754  else
755  {
756  //When the AE bit is cleared, the entry is ignored
757  ETH0->MAC_ADDRESS3_LOW = 0;
758  ETH0->MAC_ADDRESS3_HIGH = 0;
759  }
760 
761  //Configure the multicast hash table
762  ETH0->HASH_TABLE_LOW = hashTable[0];
763  ETH0->HASH_TABLE_HIGH = hashTable[1];
764 
765  //Debug message
766  TRACE_DEBUG(" HASH_TABLE_LOW = %08" PRIX32 "\r\n", ETH0->HASH_TABLE_LOW);
767  TRACE_DEBUG(" HASH_TABLE_HIGH = %08" PRIX32 "\r\n", ETH0->HASH_TABLE_HIGH);
768 
769  //Successful processing
770  return NO_ERROR;
771 }
772 
773 
774 /**
775  * @brief Adjust MAC configuration parameters for proper operation
776  * @param[in] interface Underlying network interface
777  * @return Error code
778  **/
779 
781 {
782  uint32_t config;
783 
784  //Read current MAC configuration
785  config = ETH0->MAC_CONFIGURATION;
786 
787  //10BASE-T or 100BASE-TX operation mode?
788  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
789  {
790  config |= ETH_MAC_CONFIGURATION_FES_Msk;
791  }
792  else
793  {
794  config &= ~ETH_MAC_CONFIGURATION_FES_Msk;
795  }
796 
797  //Half-duplex or full-duplex mode?
798  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
799  {
800  config |= ETH_MAC_CONFIGURATION_DM_Msk;
801  }
802  else
803  {
804  config &= ~ETH_MAC_CONFIGURATION_DM_Msk;
805  }
806 
807  //Update MAC configuration register
808  ETH0->MAC_CONFIGURATION = config;
809 
810  //Successful processing
811  return NO_ERROR;
812 }
813 
814 
815 /**
816  * @brief Write PHY register
817  * @param[in] opcode Access type (2 bits)
818  * @param[in] phyAddr PHY address (5 bits)
819  * @param[in] regAddr Register address (5 bits)
820  * @param[in] data Register value
821  **/
822 
823 void xmc4400EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
824  uint8_t regAddr, uint16_t data)
825 {
826  uint32_t temp;
827 
828  //Valid opcode?
829  if(opcode == SMI_OPCODE_WRITE)
830  {
831  //Take care not to alter MDC clock configuration
832  temp = ETH0->GMII_ADDRESS & ETH_GMII_ADDRESS_CR_Msk;
833  //Set up a write operation
834  temp |= ETH_GMII_ADDRESS_MW_Msk | ETH_GMII_ADDRESS_MB_Msk;
835  //PHY address
836  temp |= (phyAddr << ETH_GMII_ADDRESS_PA_Pos) & ETH_GMII_ADDRESS_PA_Msk;
837  //Register address
838  temp |= (regAddr << ETH_GMII_ADDRESS_MR_Pos) & ETH_GMII_ADDRESS_MR_Msk;
839 
840  //Data to be written in the PHY register
841  ETH0->GMII_DATA = data & ETH_GMII_DATA_MD_Msk;
842 
843  //Start a write operation
844  ETH0->GMII_ADDRESS = temp;
845  //Wait for the write to complete
846  while((ETH0->GMII_ADDRESS & ETH_GMII_ADDRESS_MB_Msk) != 0)
847  {
848  }
849  }
850  else
851  {
852  //The MAC peripheral only supports standard Clause 22 opcodes
853  }
854 }
855 
856 
857 /**
858  * @brief Read PHY register
859  * @param[in] opcode Access type (2 bits)
860  * @param[in] phyAddr PHY address (5 bits)
861  * @param[in] regAddr Register address (5 bits)
862  * @return Register value
863  **/
864 
865 uint16_t xmc4400EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
866  uint8_t regAddr)
867 {
868  uint16_t data;
869  uint32_t temp;
870 
871  //Valid opcode?
872  if(opcode == SMI_OPCODE_READ)
873  {
874  //Take care not to alter MDC clock configuration
875  temp = ETH0->GMII_ADDRESS & ETH_GMII_ADDRESS_CR_Msk;
876  //Set up a read operation
877  temp |= ETH_GMII_ADDRESS_MB_Msk;
878  //PHY address
879  temp |= (phyAddr << ETH_GMII_ADDRESS_PA_Pos) & ETH_GMII_ADDRESS_PA_Msk;
880  //Register address
881  temp |= (regAddr << ETH_GMII_ADDRESS_MR_Pos) & ETH_GMII_ADDRESS_MR_Msk;
882 
883  //Start a read operation
884  ETH0->GMII_ADDRESS = temp;
885  //Wait for the read to complete
886  while((ETH0->GMII_ADDRESS & ETH_GMII_ADDRESS_MB_Msk) != 0)
887  {
888  }
889 
890  //Get register value
891  data = ETH0->GMII_DATA & ETH_GMII_DATA_MD_Msk;
892  }
893  else
894  {
895  //The MAC peripheral only supports standard Clause 22 opcodes
896  data = 0;
897  }
898 
899  //Return the value of the PHY register
900  return data;
901 }
902 
903 
904 /**
905  * @brief CRC calculation
906  * @param[in] data Pointer to the data over which to calculate the CRC
907  * @param[in] length Number of bytes to process
908  * @return Resulting CRC value
909  **/
910 
911 uint32_t xmc4400EthCalcCrc(const void *data, size_t length)
912 {
913  uint_t i;
914  uint_t j;
915  uint32_t crc;
916  const uint8_t *p;
917 
918  //Point to the data over which to calculate the CRC
919  p = (uint8_t *) data;
920  //CRC preset value
921  crc = 0xFFFFFFFF;
922 
923  //Loop through data
924  for(i = 0; i < length; i++)
925  {
926  //The message is processed bit by bit
927  for(j = 0; j < 8; j++)
928  {
929  //Update CRC value
930  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
931  {
932  crc = (crc << 1) ^ 0x04C11DB7;
933  }
934  else
935  {
936  crc = crc << 1;
937  }
938  }
939  }
940 
941  //Return CRC value
942  return ~crc;
943 }
#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
#define ETH_TDES0_OWN
#define ETH_RDES0_FS
#define ETH_TDES0_IC
#define ETH_RDES1_RCH
#define ETH_RDES0_OWN
#define ETH_RDES0_LS
#define ETH_RDES0_FL
#define ETH_RDES0_ES
#define ETH_TDES0_LS
#define ETH_RDES1_RBS1
#define ETH_TDES0_TCH
#define ETH_TDES0_FS
#define ETH_TDES1_TBS1
uint16_t regAddr
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
#define SMI_OPCODE_WRITE
Definition: nic.h:66
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define SMI_OPCODE_READ
Definition: nic.h:67
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osEnterIsr()
#define osExitIsr(flag)
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 DMA descriptor.
Transmit DMA descriptor.
uint8_t length
Definition: tcp.h:368
void xmc4400EthTick(NetInterface *interface)
XMC4400 Ethernet MAC timer handler.
void xmc4400EthDisableIrq(NetInterface *interface)
Disable interrupts.
uint32_t xmc4400EthCalcCrc(const void *data, size_t length)
CRC calculation.
error_t xmc4400EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
error_t xmc4400EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void xmc4400EthEnableIrq(NetInterface *interface)
Enable interrupts.
void ETH0_0_IRQHandler(void)
XMC4400 Ethernet MAC interrupt service routine.
void xmc4400EthEventHandler(NetInterface *interface)
XMC4400 Ethernet MAC event handler.
void xmc4400EthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
error_t xmc4400EthInit(NetInterface *interface)
XMC4400 Ethernet MAC initialization.
uint16_t xmc4400EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
error_t xmc4400EthReceivePacket(NetInterface *interface)
Receive a packet.
const NicDriver xmc4400EthDriver
XMC4400 Ethernet MAC driver.
error_t xmc4400EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void xmc4400EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
__weak_func void xmc4400EthInitGpio(NetInterface *interface)
GPIO configuration.
Infineon XMC4400 Ethernet MAC driver.
#define XMC4400_ETH_RAM_SECTION
#define ETH_GMII_ADDRESS_CR_DIV62
#define ETH_BUS_MODE_PR_1_1
#define XMC4400_ETH_IRQ_SUB_PRIORITY
#define ETH_BUS_MODE_PBL_32
#define XMC4400_ETH_RX_BUFFER_SIZE
#define XMC4400_ETH_IRQ_PRIORITY_GROUPING
#define ETH_MAC_CONFIGURATION_RESERVED15_Msk
#define ETH_CON_MDIO_B
#define XMC4400_ETH_IRQ_GROUP_PRIORITY
#define XMC4400_ETH_TX_BUFFER_SIZE
#define ETH_CON_RXD0_A
#define XMC4400_ETH_RX_BUFFER_COUNT
#define ETH_CON_CLK_RMII_C
#define XMC4400_ETH_TX_BUFFER_COUNT
#define ETH_CON_RXER_A
#define ETH_BUS_MODE_RPBL_32
#define ETH_CON_RXD1_A
#define ETH_CON_CRS_DV_C