lpc43xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file lpc43xx_eth_driver.c
3  * @brief LPC4300 Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "lpc43xx.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 = LPC43XX_ETH_RAM_SECTION
50 //Receive buffer
51 #pragma data_alignment = 4
52 #pragma location = LPC43XX_ETH_RAM_SECTION
54 //Transmit DMA descriptors
55 #pragma data_alignment = 4
56 #pragma location = LPC43XX_ETH_RAM_SECTION
58 //Receive DMA descriptors
59 #pragma data_alignment = 4
60 #pragma location = LPC43XX_ETH_RAM_SECTION
62 
63 //ARM or GCC compiler?
64 #else
65 
66 //Transmit buffer
68  __attribute__((aligned(4), __section__(LPC43XX_ETH_RAM_SECTION)));
69 //Receive buffer
71  __attribute__((aligned(4), __section__(LPC43XX_ETH_RAM_SECTION)));
72 //Transmit DMA descriptors
74  __attribute__((aligned(4), __section__(LPC43XX_ETH_RAM_SECTION)));
75 //Receive DMA descriptors
77  __attribute__((aligned(4), __section__(LPC43XX_ETH_RAM_SECTION)));
78 
79 #endif
80 
81 //Pointer to the current TX DMA descriptor
82 static Lpc43xxTxDmaDesc *txCurDmaDesc;
83 //Pointer to the current RX DMA descriptor
84 static Lpc43xxRxDmaDesc *rxCurDmaDesc;
85 
86 
87 /**
88  * @brief LPC43xx Ethernet MAC driver
89  **/
90 
92 {
94  ETH_MTU,
105  TRUE,
106  TRUE,
107  TRUE,
108  FALSE
109 };
110 
111 
112 /**
113  * @brief LPC43xx 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 LPC43xx Ethernet MAC...\r\n");
124 
125  //Save underlying network interface
126  nicDriverInterface = interface;
127 
128  //Enable Ethernet peripheral clock
129  LPC_CCU1->CLK_M4_ETHERNET_CFG |= CCU1_CLK_M4_ETHERNET_CFG_RUN_Msk;
130  //Wait for completion
131  while((LPC_CCU1->CLK_M4_ETHERNET_STAT & CCU1_CLK_M4_ETHERNET_STAT_RUN_Msk) == 0)
132  {
133  }
134 
135  //Reset DMA
136  LPC_RGU->RESET_EXT_STAT19 |= RGU_RESET_EXT_STAT19_MASTER_RESET_Msk;
137  LPC_RGU->RESET_EXT_STAT19 &= ~RGU_RESET_EXT_STAT19_MASTER_RESET_Msk;
138 
139  //Reset Ethernet peripheral
140  LPC_RGU->RESET_EXT_STAT22 |= RGU_RESET_EXT_STAT22_MASTER_RESET_Msk;
141  LPC_RGU->RESET_EXT_STAT22 &= ~RGU_RESET_EXT_STAT22_MASTER_RESET_Msk;
142 
143  //GPIO configuration
144  lpc43xxEthInitGpio(interface);
145 
146  //Reset Ethernet peripheral
147  LPC_RGU->RESET_CTRL0 = RGU_RESET_CTRL0_ETHERNET_RST_Msk;
148  //Wait for the reset to complete
149  while((LPC_RGU->RESET_ACTIVE_STATUS0 & RGU_RESET_ACTIVE_STATUS0_ETHERNET_RST_Msk) == 0)
150  {
151  }
152 
153  //Perform a software reset
154  LPC_ETHERNET->DMA_BUS_MODE |= ETHERNET_DMA_BUS_MODE_SWR_Msk;
155  //Wait for the reset to complete
156  while((LPC_ETHERNET->DMA_BUS_MODE & ETHERNET_DMA_BUS_MODE_SWR_Msk) != 0)
157  {
158  }
159 
160  //Adjust MDC clock range
161  LPC_ETHERNET->MAC_MII_ADDR = ETHERNET_MAC_MII_ADDR_CR_DIV62;
162 
163  //Valid Ethernet PHY or switch driver?
164  if(interface->phyDriver != NULL)
165  {
166  //Ethernet PHY initialization
167  error = interface->phyDriver->init(interface);
168  }
169  else if(interface->switchDriver != NULL)
170  {
171  //Ethernet switch initialization
172  error = interface->switchDriver->init(interface);
173  }
174  else
175  {
176  //The interface is not properly configured
177  error = ERROR_FAILURE;
178  }
179 
180  //Any error to report?
181  if(error)
182  {
183  return error;
184  }
185 
186  //Use default MAC configuration
187  LPC_ETHERNET->MAC_CONFIG = ETHERNET_MAC_CONFIG_DO_Msk;
188 
189  //Set the MAC address of the station
190  LPC_ETHERNET->MAC_ADDR0_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
191  LPC_ETHERNET->MAC_ADDR0_HIGH = interface->macAddr.w[2];
192 
193  //Initialize hash table
194  LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;
195  LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;
196 
197  //Configure the receive filter
198  LPC_ETHERNET->MAC_FRAME_FILTER = ETHERNET_MAC_FRAME_FILTER_HPF_Msk |
199  ETHERNET_MAC_FRAME_FILTER_HMC_Msk;
200 
201  //Disable flow control
202  LPC_ETHERNET->MAC_FLOW_CTRL = 0;
203  //Set the threshold level of the transmit and receive FIFOs
204  LPC_ETHERNET->DMA_OP_MODE = ETHERNET_DMA_OP_MODE_TTC_64 | ETHERNET_DMA_OP_MODE_RTC_32;
205 
206  //Configure DMA bus mode
207  LPC_ETHERNET->DMA_BUS_MODE = ETHERNET_DMA_BUS_MODE_AAL_Msk | ETHERNET_DMA_BUS_MODE_USP_Msk |
209  ETHERNET_DMA_BUS_MODE_PBL_1 | ETHERNET_DMA_BUS_MODE_ATDS_Msk;
210 
211  //Initialize DMA descriptor lists
212  lpc43xxEthInitDmaDesc(interface);
213 
214  //Disable MAC interrupts
215  LPC_ETHERNET->MAC_INTR_MASK = ETHERNET_MAC_INTR_MASK_TSIM_Msk |
216  ETHERNET_MAC_INTR_MASK_PMTIM_Msk;
217 
218  //Enable the desired DMA interrupts
219  LPC_ETHERNET->DMA_INT_EN = ETHERNET_DMA_INT_EN_NIE_Msk |
220  ETHERNET_DMA_INT_EN_AIE_Msk | ETHERNET_DMA_INT_EN_RIE_Msk |
221  ETHERNET_DMA_INT_EN_OVE_Msk | ETHERNET_DMA_INT_EN_TIE_Msk |
222  ETHERNET_DMA_INT_EN_UNE_Msk;
223 
224  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
225  NVIC_SetPriorityGrouping(LPC43XX_ETH_IRQ_PRIORITY_GROUPING);
226 
227  //Configure Ethernet interrupt priority
228  NVIC_SetPriority(ETHERNET_IRQn, NVIC_EncodePriority(LPC43XX_ETH_IRQ_PRIORITY_GROUPING,
230 
231  //Enable MAC transmission and reception
232  LPC_ETHERNET->MAC_CONFIG |= ETHERNET_MAC_CONFIG_TE_Msk | ETHERNET_MAC_CONFIG_RE_Msk;
233  //Enable DMA transmission and reception
234  LPC_ETHERNET->DMA_OP_MODE |= ETHERNET_DMA_OP_MODE_ST_Msk | ETHERNET_DMA_OP_MODE_SR_Msk;
235 
236  //Accept any packets from the upper layer
237  osSetEvent(&interface->nicTxEvent);
238 
239  //Successful initialization
240  return NO_ERROR;
241 }
242 
243 
244 /**
245  * @brief GPIO configuration
246  * @param[in] interface Underlying network interface
247  **/
248 
249 __weak_func void lpc43xxEthInitGpio(NetInterface *interface)
250 {
251 //LPC4330-Xplorer or LPCXpresso4337 evaluation board?
252 #if defined(USE_LPC4330_XPLORER) || defined(USE_LPCXPRESSO_4337)
253  //Enable GPIO peripheral clock
254  LPC_CCU1->CLK_M4_GPIO_CFG |= CCU1_CLK_M4_GPIO_CFG_RUN_Msk;
255  //Wait for completion
256  while((LPC_CCU1->CLK_M4_GPIO_STAT & CCU1_CLK_M4_GPIO_STAT_RUN_Msk) == 0)
257  {
258  }
259 
260  //Select RMII operation mode
261  LPC_CREG->CREG6 &= ~CREG_CREG6_ETHMODE_Msk;
262  LPC_CREG->CREG6 |= CREG6_ETHMODE_RMII;
263 
264  //Configure P0.0 (ENET_RXD1)
265  LPC_SCU->SFSP0_0 = SCU_SFSP0_0_EZI_Msk | SCU_SFSP0_0_EHS_Msk | (2 & SCU_SFSP0_0_MODE_Msk);
266  //Configure P0.1 (ENET_TX_EN)
267  LPC_SCU->SFSP0_1 = SCU_SFSP0_1_EHS_Msk | (6 & SCU_SFSP0_1_MODE_Msk);
268 
269  //Configure P1.15 (ENET_RXD0)
270  LPC_SCU->SFSP1_15 = SCU_SFSP1_15_EZI_Msk | SCU_SFSP1_15_EHS_Msk | (3 & SCU_SFSP1_15_MODE_Msk);
271  //Configure P1.16 (ENET_RX_DV)
272  LPC_SCU->SFSP1_16 = SCU_SFSP1_16_EZI_Msk | SCU_SFSP1_16_EHS_Msk | (7 & SCU_SFSP1_16_MODE_Msk);
273  //Configure P1.17 (ENET_MDIO)
274  LPC_SCU->SFSP1_17 = SCU_SFSP1_17_EZI_Msk | (3 & SCU_SFSP1_17_MODE_Msk);
275  //Configure P1.18 (ENET_TXD0)
276  LPC_SCU->SFSP1_18 = SCU_SFSP1_18_EHS_Msk | (3 & SCU_SFSP1_18_MODE_Msk);
277  //Configure P1.19 (ENET_REF_CLK)
278  LPC_SCU->SFSP1_19 = SCU_SFSP1_19_EZI_Msk | SCU_SFSP1_19_EHS_Msk | (0 & SCU_SFSP1_19_MODE_Msk);
279  //Configure P1.20 (ENET_TXD1)
280  LPC_SCU->SFSP1_20 = SCU_SFSP1_20_EHS_Msk | (3 & SCU_SFSP1_20_MODE_Msk);
281 
282  //Configure P2.0 (ENET_MDC)
283  LPC_SCU->SFSP2_0 = (7 & SCU_SFSP2_0_MODE_Msk);
284 #endif
285 }
286 
287 
288 /**
289  * @brief Initialize DMA descriptor lists
290  * @param[in] interface Underlying network interface
291  **/
292 
294 {
295  uint_t i;
296 
297  //Initialize TX DMA descriptor list
298  for(i = 0; i < LPC43XX_ETH_TX_BUFFER_COUNT; i++)
299  {
300  //Use chain structure rather than ring structure
301  txDmaDesc[i].tdes0 = ETH_TDES0_IC | ETH_TDES0_TCH;
302  //Initialize transmit buffer size
303  txDmaDesc[i].tdes1 = 0;
304  //Transmit buffer address
305  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
306  //Next descriptor address
307  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
308  //Reserved fields
309  txDmaDesc[i].tdes4 = 0;
310  txDmaDesc[i].tdes5 = 0;
311  //Transmit frame time stamp
312  txDmaDesc[i].tdes6 = 0;
313  txDmaDesc[i].tdes7 = 0;
314  }
315 
316  //The last descriptor is chained to the first entry
317  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
318  //Point to the very first descriptor
319  txCurDmaDesc = &txDmaDesc[0];
320 
321  //Initialize RX DMA descriptor list
322  for(i = 0; i < LPC43XX_ETH_RX_BUFFER_COUNT; i++)
323  {
324  //The descriptor is initially owned by the DMA
325  rxDmaDesc[i].rdes0 = ETH_RDES0_OWN;
326  //Use chain structure rather than ring structure
328  //Receive buffer address
329  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
330  //Next descriptor address
331  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
332  //Extended status
333  rxDmaDesc[i].rdes4 = 0;
334  //Reserved field
335  rxDmaDesc[i].rdes5 = 0;
336  //Receive frame time stamp
337  rxDmaDesc[i].rdes6 = 0;
338  rxDmaDesc[i].rdes7 = 0;
339  }
340 
341  //The last descriptor is chained to the first entry
342  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
343  //Point to the very first descriptor
344  rxCurDmaDesc = &rxDmaDesc[0];
345 
346  //Start location of the TX descriptor list
347  LPC_ETHERNET->DMA_TRANS_DES_ADDR = (uint32_t) txDmaDesc;
348  //Start location of the RX descriptor list
349  LPC_ETHERNET->DMA_REC_DES_ADDR = (uint32_t) rxDmaDesc;
350 }
351 
352 
353 /**
354  * @brief LPC43xx Ethernet MAC timer handler
355  *
356  * This routine is periodically called by the TCP/IP stack to handle periodic
357  * operations such as polling the link state
358  *
359  * @param[in] interface Underlying network interface
360  **/
361 
362 void lpc43xxEthTick(NetInterface *interface)
363 {
364  //Valid Ethernet PHY or switch driver?
365  if(interface->phyDriver != NULL)
366  {
367  //Handle periodic operations
368  interface->phyDriver->tick(interface);
369  }
370  else if(interface->switchDriver != NULL)
371  {
372  //Handle periodic operations
373  interface->switchDriver->tick(interface);
374  }
375  else
376  {
377  //Just for sanity
378  }
379 }
380 
381 
382 /**
383  * @brief Enable interrupts
384  * @param[in] interface Underlying network interface
385  **/
386 
388 {
389  //Enable Ethernet MAC interrupts
390  NVIC_EnableIRQ(ETHERNET_IRQn);
391 
392  //Valid Ethernet PHY or switch driver?
393  if(interface->phyDriver != NULL)
394  {
395  //Enable Ethernet PHY interrupts
396  interface->phyDriver->enableIrq(interface);
397  }
398  else if(interface->switchDriver != NULL)
399  {
400  //Enable Ethernet switch interrupts
401  interface->switchDriver->enableIrq(interface);
402  }
403  else
404  {
405  //Just for sanity
406  }
407 }
408 
409 
410 /**
411  * @brief Disable interrupts
412  * @param[in] interface Underlying network interface
413  **/
414 
416 {
417  //Disable Ethernet MAC interrupts
418  NVIC_DisableIRQ(ETHERNET_IRQn);
419 
420  //Valid Ethernet PHY or switch driver?
421  if(interface->phyDriver != NULL)
422  {
423  //Disable Ethernet PHY interrupts
424  interface->phyDriver->disableIrq(interface);
425  }
426  else if(interface->switchDriver != NULL)
427  {
428  //Disable Ethernet switch interrupts
429  interface->switchDriver->disableIrq(interface);
430  }
431  else
432  {
433  //Just for sanity
434  }
435 }
436 
437 
438 /**
439  * @brief LPC43xx Ethernet MAC interrupt service routine
440  **/
441 
443 {
444  bool_t flag;
445  uint32_t status;
446 
447  //Interrupt service routine prologue
448  osEnterIsr();
449 
450  //This flag will be set if a higher priority task must be woken
451  flag = FALSE;
452 
453  //Read DMA status register
454  status = LPC_ETHERNET->DMA_STAT;
455 
456  //Packet transmitted?
457  if((status & (ETHERNET_DMA_STAT_TI_Msk | ETHERNET_DMA_STAT_UNF_Msk)) != 0)
458  {
459  //Clear TI and UNF interrupt flags
460  LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_TI_Msk | ETHERNET_DMA_STAT_UNF_Msk;
461 
462  //Check whether the TX buffer is available for writing
463  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
464  {
465  //Notify the TCP/IP stack that the transmitter is ready to send
466  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
467  }
468  }
469 
470  //Packet received?
471  if((status & (ETHERNET_DMA_STAT_RI_Msk | ETHERNET_DMA_STAT_OVF_Msk)) != 0)
472  {
473  //Disable RIE and OVE interrupts
474  LPC_ETHERNET->DMA_INT_EN &= ~(ETHERNET_DMA_INT_EN_RIE_Msk |
475  ETHERNET_DMA_INT_EN_OVE_Msk);
476 
477  //Set event flag
478  nicDriverInterface->nicEvent = TRUE;
479  //Notify the TCP/IP stack of the event
480  flag |= osSetEventFromIsr(&netEvent);
481  }
482 
483  //Clear NIS and AIS interrupt flags
484  LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_NIS_Msk | ETHERNET_DMA_STAT_AIE_Msk;
485 
486  //Interrupt service routine epilogue
487  osExitIsr(flag);
488 }
489 
490 
491 /**
492  * @brief LPC43xx Ethernet MAC event handler
493  * @param[in] interface Underlying network interface
494  **/
495 
497 {
498  error_t error;
499 
500  //Packet received?
501  if((LPC_ETHERNET->DMA_STAT & (ETHERNET_DMA_STAT_RI_Msk | ETHERNET_DMA_STAT_OVF_Msk)) != 0)
502  {
503  //Clear RI and OVF interrupt flags
504  LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_RI_Msk | ETHERNET_DMA_STAT_OVF_Msk;
505 
506  //Process all pending packets
507  do
508  {
509  //Read incoming packet
510  error = lpc43xxEthReceivePacket(interface);
511 
512  //No more data in the receive buffer?
513  } while(error != ERROR_BUFFER_EMPTY);
514  }
515 
516  //Re-enable DMA interrupts
517  LPC_ETHERNET->DMA_INT_EN = ETHERNET_DMA_INT_EN_NIE_Msk |
518  ETHERNET_DMA_INT_EN_AIE_Msk | ETHERNET_DMA_INT_EN_RIE_Msk |
519  ETHERNET_DMA_INT_EN_OVE_Msk | ETHERNET_DMA_INT_EN_TIE_Msk |
520  ETHERNET_DMA_INT_EN_UNE_Msk;
521 }
522 
523 
524 /**
525  * @brief Send a packet
526  * @param[in] interface Underlying network interface
527  * @param[in] buffer Multi-part buffer containing the data to send
528  * @param[in] offset Offset to the first data byte
529  * @param[in] ancillary Additional options passed to the stack along with
530  * the packet
531  * @return Error code
532  **/
533 
535  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
536 {
537  size_t length;
538 
539  //Retrieve the length of the packet
540  length = netBufferGetLength(buffer) - offset;
541 
542  //Check the frame length
544  {
545  //The transmitter can accept another packet
546  osSetEvent(&interface->nicTxEvent);
547  //Report an error
548  return ERROR_INVALID_LENGTH;
549  }
550 
551  //Make sure the current buffer is available for writing
552  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) != 0)
553  {
554  return ERROR_FAILURE;
555  }
556 
557  //Copy user data to the transmit buffer
558  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
559 
560  //Write the number of bytes to send
561  txCurDmaDesc->tdes1 = length & ETH_TDES1_TBS1;
562  //Set LS and FS flags as the data fits in a single buffer
563  txCurDmaDesc->tdes0 |= ETH_TDES0_LS | ETH_TDES0_FS;
564  //Give the ownership of the descriptor to the DMA
565  txCurDmaDesc->tdes0 |= ETH_TDES0_OWN;
566 
567  //Clear TU flag to resume processing
568  LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_TU_Msk;
569  //Instruct the DMA to poll the transmit descriptor list
570  LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 0;
571 
572  //Point to the next descriptor in the list
573  txCurDmaDesc = (Lpc43xxTxDmaDesc *) txCurDmaDesc->tdes3;
574 
575  //Check whether the next buffer is available for writing
576  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
577  {
578  //The transmitter can accept another packet
579  osSetEvent(&interface->nicTxEvent);
580  }
581 
582  //Data successfully written
583  return NO_ERROR;
584 }
585 
586 
587 /**
588  * @brief Receive a packet
589  * @param[in] interface Underlying network interface
590  * @return Error code
591  **/
592 
594 {
595  error_t error;
596  size_t n;
597  NetRxAncillary ancillary;
598 
599  //Current buffer available for reading?
600  if((rxCurDmaDesc->rdes0 & ETH_RDES0_OWN) == 0)
601  {
602  //FS and LS flags should be set
603  if((rxCurDmaDesc->rdes0 & ETH_RDES0_FS) != 0 &&
604  (rxCurDmaDesc->rdes0 & ETH_RDES0_LS) != 0)
605  {
606  //Make sure no error occurred
607  if((rxCurDmaDesc->rdes0 & ETH_RDES0_ES) == 0)
608  {
609  //Retrieve the length of the frame
610  n = (rxCurDmaDesc->rdes0 & ETH_RDES0_FL) >> 16;
611  //Limit the number of data to read
613 
614  //Additional options can be passed to the stack along with the packet
615  ancillary = NET_DEFAULT_RX_ANCILLARY;
616 
617  //Pass the packet to the upper layer
618  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
619  &ancillary);
620 
621  //Valid packet received
622  error = NO_ERROR;
623  }
624  else
625  {
626  //The received packet contains an error
627  error = ERROR_INVALID_PACKET;
628  }
629  }
630  else
631  {
632  //The packet is not valid
633  error = ERROR_INVALID_PACKET;
634  }
635 
636  //Give the ownership of the descriptor back to the DMA
637  rxCurDmaDesc->rdes0 = ETH_RDES0_OWN;
638  //Point to the next descriptor in the list
639  rxCurDmaDesc = (Lpc43xxRxDmaDesc *) rxCurDmaDesc->rdes3;
640  }
641  else
642  {
643  //No more data in the receive buffer
644  error = ERROR_BUFFER_EMPTY;
645  }
646 
647  //Clear RU flag to resume processing
648  LPC_ETHERNET->DMA_STAT = ETHERNET_DMA_STAT_RU_Msk;
649  //Instruct the DMA to poll the receive descriptor list
650  LPC_ETHERNET->DMA_REC_POLL_DEMAND = 0;
651 
652  //Return status code
653  return error;
654 }
655 
656 
657 /**
658  * @brief Configure MAC address filtering
659  * @param[in] interface Underlying network interface
660  * @return Error code
661  **/
662 
664 {
665  uint_t i;
666  uint_t k;
667  uint32_t crc;
668  uint32_t hashTable[2];
669  MacFilterEntry *entry;
670 
671  //Debug message
672  TRACE_DEBUG("Updating MAC filter...\r\n");
673 
674  //Set the MAC address of the station
675  LPC_ETHERNET->MAC_ADDR0_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
676  LPC_ETHERNET->MAC_ADDR0_HIGH = interface->macAddr.w[2];
677 
678  //Clear hash table
679  hashTable[0] = 0;
680  hashTable[1] = 0;
681 
682  //The MAC address filter contains the list of MAC addresses to accept
683  //when receiving an Ethernet frame
684  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
685  {
686  //Point to the current entry
687  entry = &interface->macAddrFilter[i];
688 
689  //Valid entry?
690  if(entry->refCount > 0)
691  {
692  //Compute CRC over the current MAC address
693  crc = lpc43xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
694 
695  //The upper 6 bits in the CRC register are used to index the
696  //contents of the hash table
697  k = (crc >> 26) & 0x3F;
698 
699  //Update hash table contents
700  hashTable[k / 32] |= (1 << (k % 32));
701  }
702  }
703 
704  //Write the hash table
705  LPC_ETHERNET->MAC_HASHTABLE_LOW = hashTable[0];
706  LPC_ETHERNET->MAC_HASHTABLE_HIGH = hashTable[1];
707 
708  //Debug message
709  TRACE_DEBUG(" MAC_HASHTABLE_LOW = %08" PRIX32 "\r\n", LPC_ETHERNET->MAC_HASHTABLE_LOW);
710  TRACE_DEBUG(" MAC_HASHTABLE_HIGH = %08" PRIX32 "\r\n", LPC_ETHERNET->MAC_HASHTABLE_HIGH);
711 
712  //Successful processing
713  return NO_ERROR;
714 }
715 
716 
717 /**
718  * @brief Adjust MAC configuration parameters for proper operation
719  * @param[in] interface Underlying network interface
720  * @return Error code
721  **/
722 
724 {
725  uint32_t config;
726 
727  //Read current MAC configuration
728  config = LPC_ETHERNET->MAC_CONFIG;
729 
730  //10BASE-T or 100BASE-TX operation mode?
731  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
732  {
733  config |= ETHERNET_MAC_CONFIG_FES_Msk;
734  }
735  else
736  {
737  config &= ~ETHERNET_MAC_CONFIG_FES_Msk;
738  }
739 
740  //Half-duplex or full-duplex mode?
741  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
742  {
743  config |= ETHERNET_MAC_CONFIG_DM_Msk;
744  }
745  else
746  {
747  config &= ~ETHERNET_MAC_CONFIG_DM_Msk;
748  }
749 
750  //Update MAC configuration register
751  LPC_ETHERNET->MAC_CONFIG = config;
752 
753  //Successful processing
754  return NO_ERROR;
755 }
756 
757 
758 /**
759  * @brief Write PHY register
760  * @param[in] opcode Access type (2 bits)
761  * @param[in] phyAddr PHY address (5 bits)
762  * @param[in] regAddr Register address (5 bits)
763  * @param[in] data Register value
764  **/
765 
766 void lpc43xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
767  uint8_t regAddr, uint16_t data)
768 {
769  uint32_t temp;
770 
771  //Valid opcode?
772  if(opcode == SMI_OPCODE_WRITE)
773  {
774  //Take care not to alter MDC clock configuration
775  temp = LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_CR_Msk;
776  //Set up a write operation
777  temp |= ETHERNET_MAC_MII_ADDR_W_Msk | ETHERNET_MAC_MII_ADDR_GB_Msk;
778  //PHY address
779  temp |= (phyAddr << ETHERNET_MAC_MII_ADDR_PA_Pos) & ETHERNET_MAC_MII_ADDR_PA_Msk;
780  //Register address
781  temp |= (regAddr << ETHERNET_MAC_MII_ADDR_GR_Pos) & ETHERNET_MAC_MII_ADDR_GR_Msk;
782 
783  //Data to be written in the PHY register
784  LPC_ETHERNET->MAC_MII_DATA = data & ETHERNET_MAC_MII_DATA_GD_Msk;
785 
786  //Start a write operation
787  LPC_ETHERNET->MAC_MII_ADDR = temp;
788  //Wait for the write to complete
789  while((LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_GB_Msk) != 0)
790  {
791  }
792  }
793  else
794  {
795  //The MAC peripheral only supports standard Clause 22 opcodes
796  }
797 }
798 
799 
800 /**
801  * @brief Read PHY register
802  * @param[in] opcode Access type (2 bits)
803  * @param[in] phyAddr PHY address (5 bits)
804  * @param[in] regAddr Register address (5 bits)
805  * @return Register value
806  **/
807 
808 uint16_t lpc43xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
809  uint8_t regAddr)
810 {
811  uint16_t data;
812  uint32_t temp;
813 
814  //Valid opcode?
815  if(opcode == SMI_OPCODE_READ)
816  {
817  //Take care not to alter MDC clock configuration
818  temp = LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_CR_Msk;
819  //Set up a read operation
820  temp |= ETHERNET_MAC_MII_ADDR_GB_Msk;
821  //PHY address
822  temp |= (phyAddr << ETHERNET_MAC_MII_ADDR_PA_Pos) & ETHERNET_MAC_MII_ADDR_PA_Msk;
823  //Register address
824  temp |= (regAddr << ETHERNET_MAC_MII_ADDR_GR_Pos) & ETHERNET_MAC_MII_ADDR_GR_Msk;
825 
826  //Start a read operation
827  LPC_ETHERNET->MAC_MII_ADDR = temp;
828  //Wait for the read to complete
829  while((LPC_ETHERNET->MAC_MII_ADDR & ETHERNET_MAC_MII_ADDR_GB_Msk) != 0)
830  {
831  }
832 
833  //Get register value
834  data = LPC_ETHERNET->MAC_MII_DATA & ETHERNET_MAC_MII_DATA_GD_Msk;
835  }
836  else
837  {
838  //The MAC peripheral only supports standard Clause 22 opcodes
839  data = 0;
840  }
841 
842  //Return the value of the PHY register
843  return data;
844 }
845 
846 
847 /**
848  * @brief CRC calculation
849  * @param[in] data Pointer to the data over which to calculate the CRC
850  * @param[in] length Number of bytes to process
851  * @return Resulting CRC value
852  **/
853 
854 uint32_t lpc43xxEthCalcCrc(const void *data, size_t length)
855 {
856  uint_t i;
857  uint_t j;
858  uint32_t crc;
859  const uint8_t *p;
860 
861  //Point to the data over which to calculate the CRC
862  p = (uint8_t *) data;
863  //CRC preset value
864  crc = 0xFFFFFFFF;
865 
866  //Loop through data
867  for(i = 0; i < length; i++)
868  {
869  //The message is processed bit by bit
870  for(j = 0; j < 8; j++)
871  {
872  //Update CRC value
873  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
874  {
875  crc = (crc << 1) ^ 0x04C11DB7;
876  }
877  else
878  {
879  crc = crc << 1;
880  }
881  }
882  }
883 
884  //Return CRC value
885  return ~crc;
886 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
error_t lpc43xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
uint8_t opcode
Definition: dns_common.h:190
int bool_t
Definition: compiler_port.h:61
#define netEvent
Definition: net_legacy.h:196
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define LPC43XX_ETH_RX_BUFFER_COUNT
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 CREG6_ETHMODE_RMII
#define ETH_TDES1_TBS1
#define LPC43XX_ETH_TX_BUFFER_COUNT
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
uint32_t lpc43xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
error_t lpc43xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define ETH_RDES0_LS
#define ETHERNET_DMA_BUS_MODE_RPBL_1
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:392
uint16_t lpc43xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define osExitIsr(flag)
#define SMI_OPCODE_WRITE
Definition: nic.h:66
void lpc43xxEthEventHandler(NetInterface *interface)
LPC43xx Ethernet MAC event handler.
#define LPC43XX_ETH_TX_BUFFER_SIZE
#define FALSE
Definition: os_port.h:46
LPC4300 Ethernet MAC driver.
#define ETH_RDES0_FL
error_t
Error codes.
Definition: error.h:43
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:105
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define ETHERNET_MAC_MII_ADDR_CR_DIV62
#define txBuffer
#define ETH_RDES0_OWN
#define ETHERNET_DMA_BUS_MODE_PBL_1
void lpc43xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:265
void lpc43xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
void lpc43xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
#define ETH_RDES0_FS
#define NetTxAncillary
Definition: net_misc.h:36
#define LPC43XX_ETH_IRQ_GROUP_PRIORITY
void lpc43xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
#define SMI_OPCODE_READ
Definition: nic.h:67
#define TRACE_INFO(...)
Definition: debug.h:105
#define ETH_TDES0_OWN
uint8_t length
Definition: tcp.h:375
#define ETH_TDES0_TCH
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define ETHERNET_DMA_OP_MODE_TTC_64
#define MIN(a, b)
Definition: os_port.h:63
#define ETH_RDES0_ES
#define rxBuffer
MacAddr
Definition: ethernet.h:197
#define ETH_TDES0_IC
#define TRACE_DEBUG(...)
Definition: debug.h:119
error_t lpc43xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
__weak_func void lpc43xxEthInitGpio(NetInterface *interface)
GPIO configuration.
Enhanced RX DMA descriptor.
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
#define ETH_TDES0_FS
MAC filter table entry.
Definition: ethernet.h:264
#define ETH_RDES1_RCH
void ETHERNET_IRQHandler(void)
LPC43xx Ethernet MAC interrupt service routine.
#define ETHERNET_DMA_OP_MODE_RTC_32
#define osEnterIsr()
#define LPC43XX_ETH_IRQ_SUB_PRIORITY
const NicDriver lpc43xxEthDriver
LPC43xx Ethernet MAC driver.
void lpc43xxEthTick(NetInterface *interface)
LPC43xx Ethernet MAC timer handler.
#define LPC43XX_ETH_IRQ_PRIORITY_GROUPING
#define rxDmaDesc
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ETH_TDES0_LS
#define txDmaDesc
Enhanced TX DMA descriptor.
#define ETH_RDES1_RBS1
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
#define LPC43XX_ETH_RX_BUFFER_SIZE
NIC driver.
Definition: nic.h:286
error_t lpc43xxEthReceivePacket(NetInterface *interface)
Receive a packet.
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
error_t lpc43xxEthInit(NetInterface *interface)
LPC43xx Ethernet MAC initialization.
#define ETHERNET_DMA_BUS_MODE_PR_1_1
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define LPC43XX_ETH_RAM_SECTION