lpc54xxx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file lpc54xxx_eth_driver.c
3  * @brief LPC540xx/LPC546xx 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 "fsl_device_registers.h"
36 #include "fsl_power.h"
37 #include "fsl_reset.h"
38 #include "fsl_clock.h"
39 #include "fsl_iocon.h"
40 #include "fsl_gpio.h"
41 #include "core/net.h"
43 #include "debug.h"
44 
45 //Underlying network interface
46 static NetInterface *nicDriverInterface;
47 
48 //IAR EWARM compiler?
49 #if defined(__ICCARM__)
50 
51 //Transmit buffer
52 #pragma data_alignment = 4
54 //Receive buffer
55 #pragma data_alignment = 4
57 //Transmit DMA descriptors
58 #pragma data_alignment = 4
60 //Receive DMA descriptors
61 #pragma data_alignment = 4
63 
64 //Keil MDK-ARM or GCC compiler?
65 #else
66 
67 //Transmit buffer
69  __attribute__((aligned(4)));
70 //Receive buffer
72  __attribute__((aligned(4)));
73 //Transmit DMA descriptors
75  __attribute__((aligned(4)));
76 //Receive DMA descriptors
78  __attribute__((aligned(4)));
79 
80 #endif
81 
82 //Current transmit descriptor
83 static uint_t txIndex;
84 //Current receive descriptor
85 static uint_t rxIndex;
86 
87 
88 /**
89  * @brief LPC54xxx Ethernet MAC driver
90  **/
91 
93 {
95  ETH_MTU,
106  TRUE,
107  TRUE,
108  TRUE,
109  FALSE
110 };
111 
112 
113 /**
114  * @brief LPC54xxx Ethernet MAC initialization
115  * @param[in] interface Underlying network interface
116  * @return Error code
117  **/
118 
120 {
121  error_t error;
122  uint32_t temp;
123 
124  //Debug message
125  TRACE_INFO("Initializing LPC54xxx Ethernet MAC...\r\n");
126 
127  //Save underlying network interface
128  nicDriverInterface = interface;
129 
130  //Enable ENET peripheral clock
131  CLOCK_EnableClock(kCLOCK_Eth);
132  //Reset ENET module
133  RESET_PeripheralReset(kETH_RST_SHIFT_RSTn);
134 
135  //GPIO configuration
136  lpc54xxxEthInitGpio(interface);
137 
138  //Perform a software reset
139  ENET->DMA_MODE |= ENET_DMA_MODE_SWR_MASK;
140  //Wait for the reset to complete
141  while((ENET->DMA_MODE & ENET_DMA_MODE_SWR_MASK) != 0)
142  {
143  }
144 
145  //Adjust MDC clock range depending on CSR frequency
146  ENET->MAC_MDIO_ADDR = ENET_MAC_MDIO_ADDR_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  ENET->MAC_CONFIG = ENET_MAC_CONFIG_GPSLCE_MASK | ENET_MAC_CONFIG_PS_MASK |
173  ENET_MAC_CONFIG_DO_MASK;
174 
175  //Set the maximum packet size that can be accepted
176  temp = ENET->MAC_EXT_CONFIG & ~ENET_MAC_EXT_CONFIG_GPSL_MASK;
177  ENET->MAC_EXT_CONFIG = temp | LPC54XXX_ETH_RX_BUFFER_SIZE;
178 
179  //Set the MAC address of the station
180  ENET->MAC_ADDR_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
181  ENET->MAC_ADDR_HIGH = interface->macAddr.w[2];
182 
183  //Configure the receive filter
184  ENET->MAC_FRAME_FILTER = 0;
185 
186  //Disable flow control
187  ENET->MAC_TX_FLOW_CTRL_Q[0] = 0;
188  ENET->MAC_RX_FLOW_CTRL = 0;
189 
190  //Enable the first RX queue
191  ENET->MAC_RXQ_CTRL[0] = ENET_MAC_RXQ_CTRL_RXQ0EN(2);
192 
193  //Configure DMA operating mode
194  ENET->DMA_MODE = ENET_DMA_MODE_PR(0);
195  //Configure system bus mode
196  ENET->DMA_SYSBUS_MODE |= ENET_DMA_SYSBUS_MODE_AAL_MASK;
197 
198  //The DMA takes the descriptor table as contiguous
199  ENET->DMA_CH[0].DMA_CHX_CTRL = ENET_DMA_CH_DMA_CHX_CTRL_DSL(0);
200  //Configure TX features
201  ENET->DMA_CH[0].DMA_CHX_TX_CTRL = ENET_DMA_CH_DMA_CHX_TX_CTRL_TxPBL(32);
202 
203  //Configure RX features
204  ENET->DMA_CH[0].DMA_CHX_RX_CTRL = ENET_DMA_CH_DMA_CHX_RX_CTRL_RxPBL(32) |
205  ENET_DMA_CH_DMA_CHX_RX_CTRL_RBSZ(LPC54XXX_ETH_RX_BUFFER_SIZE / 4);
206 
207  //Enable store and forward mode for transmission
208  ENET->MTL_QUEUE[0].MTL_TXQX_OP_MODE |= ENET_MTL_QUEUE_MTL_TXQX_OP_MODE_TQS(7) |
209  ENET_MTL_QUEUE_MTL_TXQX_OP_MODE_TXQEN(2) |
210  ENET_MTL_QUEUE_MTL_TXQX_OP_MODE_TSF_MASK;
211 
212  //Enable store and forward mode for reception
213  ENET->MTL_QUEUE[0].MTL_RXQX_OP_MODE |= ENET_MTL_QUEUE_MTL_RXQX_OP_MODE_RQS(7) |
214  ENET_MTL_QUEUE_MTL_RXQX_OP_MODE_RSF_MASK;
215 
216  //Initialize DMA descriptor lists
217  lpc54xxxEthInitDmaDesc(interface);
218 
219  //Disable MAC interrupts
220  ENET->MAC_INTR_EN = 0;
221 
222  //Enable the desired DMA interrupts
223  ENET->DMA_CH[0].DMA_CHX_INT_EN = ENET_DMA_CH_DMA_CHX_INT_EN_NIE_MASK |
224  ENET_DMA_CH_DMA_CHX_INT_EN_RIE_MASK | ENET_DMA_CH_DMA_CHX_INT_EN_TIE_MASK;
225 
226  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
227  NVIC_SetPriorityGrouping(LPC54XXX_ETH_IRQ_PRIORITY_GROUPING);
228 
229  //Configure Ethernet interrupt priority
230  NVIC_SetPriority(ETHERNET_IRQn, NVIC_EncodePriority(LPC54XXX_ETH_IRQ_PRIORITY_GROUPING,
232 
233  //Enable MAC transmission and reception
234  ENET->MAC_CONFIG |= ENET_MAC_CONFIG_TE_MASK | ENET_MAC_CONFIG_RE_MASK;
235 
236  //Enable DMA transmission and reception
237  ENET->DMA_CH[0].DMA_CHX_TX_CTRL |= ENET_DMA_CH_DMA_CHX_TX_CTRL_ST_MASK;
238  ENET->DMA_CH[0].DMA_CHX_RX_CTRL |= ENET_DMA_CH_DMA_CHX_RX_CTRL_SR_MASK;
239 
240  //Accept any packets from the upper layer
241  osSetEvent(&interface->nicTxEvent);
242 
243  //Successful initialization
244  return NO_ERROR;
245 }
246 
247 
248 /**
249  * @brief GPIO configuration
250  * @param[in] interface Underlying network interface
251  **/
252 
253 __weak_func void lpc54xxxEthInitGpio(NetInterface *interface)
254 {
255 //LPCXpresso54S018, LPCXpresso54608, LPCXpresso54628 or LPC54018-IoT-Module
256 //evaluation board?
257 #if defined(USE_LPCXPRESSO_54S018) || defined(USE_LPCXPRESSO_54608) || \
258  defined(USE_LPCXPRESSO_54628) || defined(USE_LPC54018_IOT_MODULE)
259  gpio_pin_config_t pinConfig;
260 
261  //Select RMII interface mode
262  SYSCON->ETHPHYSEL |= SYSCON_ETHPHYSEL_PHY_SEL_MASK;
263 
264  //Enable IOCON clock
265  CLOCK_EnableClock(kCLOCK_Iocon);
266 
267  //Enable GPIO clocks
268  CLOCK_EnableClock(kCLOCK_Gpio0);
269  CLOCK_EnableClock(kCLOCK_Gpio2);
270  CLOCK_EnableClock(kCLOCK_Gpio4);
271 
272  //Configure ENET_TXD1 (P0_17)
273  IOCON_PinMuxSet(IOCON, 0, 17, IOCON_FUNC7 | IOCON_MODE_INACT |
274  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
275 
276  //Configure ENET_TXD0 (P4_8)
277  IOCON_PinMuxSet(IOCON, 4, 8, IOCON_FUNC1 | IOCON_MODE_INACT |
278  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
279 
280  //Configure ENET_RX_DV (P4_10)
281  IOCON_PinMuxSet(IOCON, 4, 10, IOCON_FUNC1 | IOCON_MODE_INACT |
282  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
283 
284  //Configure ENET_RXD0 (P4_11)
285  IOCON_PinMuxSet(IOCON, 4, 11, IOCON_FUNC1 | IOCON_MODE_INACT |
286  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
287 
288  //Configure ENET_RXD1 (P4_12)
289  IOCON_PinMuxSet(IOCON, 4, 12, IOCON_FUNC1 | IOCON_MODE_INACT |
290  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
291 
292  //Configure ENET_TX_EN (P4_13)
293  IOCON_PinMuxSet(IOCON, 4, 13, IOCON_FUNC1 | IOCON_MODE_INACT |
294  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
295 
296  //Configure ENET_RX_CLK (P4_14)
297  IOCON_PinMuxSet(IOCON, 4, 14, IOCON_FUNC1 | IOCON_MODE_INACT |
298  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
299 
300  //Configure ENET_MDC (P4_15)
301  IOCON_PinMuxSet(IOCON, 4, 15, IOCON_FUNC1 | IOCON_MODE_INACT |
302  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
303 
304  //Configure ENET_MDIO (P4_16)
305  IOCON_PinMuxSet(IOCON, 4, 16, IOCON_FUNC1 | IOCON_MODE_PULLUP |
306  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
307 
308  //Configure ENET_RST (P2_26) as an output
309  pinConfig.pinDirection = kGPIO_DigitalOutput;
310  pinConfig.outputLogic = 0;
311  GPIO_PinInit(GPIO, 2, 26, &pinConfig);
312 
313  //Reset PHY transceiver (hard reset)
314  GPIO_PinWrite(GPIO, 2, 26, 0);
315  sleep(10);
316  GPIO_PinWrite(GPIO, 2, 26, 1);
317  sleep(10);
318 
319 //LPCXpresso54S018M evaluation board?
320 #elif defined(USE_LPCXPRESSO_54S018M)
321  gpio_pin_config_t pinConfig;
322 
323  //Select RMII interface mode
324  SYSCON->ETHPHYSEL |= SYSCON_ETHPHYSEL_PHY_SEL_MASK;
325 
326  //Enable IOCON clock
327  CLOCK_EnableClock(kCLOCK_Iocon);
328 
329  //Enable GPIO clocks
330  CLOCK_EnableClock(kCLOCK_Gpio0);
331  CLOCK_EnableClock(kCLOCK_Gpio1);
332  CLOCK_EnableClock(kCLOCK_Gpio2);
333  CLOCK_EnableClock(kCLOCK_Gpio4);
334 
335  //Configure ENET_TXD1 (P0_17)
336  IOCON_PinMuxSet(IOCON, 0, 17, IOCON_FUNC7 | IOCON_MODE_INACT |
337  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
338 
339  //Configure ENET_MDC (P1_16)
340  IOCON_PinMuxSet(IOCON, 1, 16, IOCON_FUNC1 | IOCON_MODE_INACT |
341  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
342 
343  //Configure ENET_MDIO (P1_23)
344  IOCON_PinMuxSet(IOCON, 1, 23, IOCON_FUNC4 | IOCON_MODE_PULLUP |
345  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
346 
347  //Configure ENET_TXD0 (P4_8)
348  IOCON_PinMuxSet(IOCON, 4, 8, IOCON_FUNC1 | IOCON_MODE_INACT |
349  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
350 
351  //Configure ENET_RX_DV (P4_10)
352  IOCON_PinMuxSet(IOCON, 4, 10, IOCON_FUNC1 | IOCON_MODE_INACT |
353  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
354 
355  //Configure ENET_RXD0 (P4_11)
356  IOCON_PinMuxSet(IOCON, 4, 11, IOCON_FUNC1 | IOCON_MODE_INACT |
357  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
358 
359  //Configure ENET_RXD1 (P4_12)
360  IOCON_PinMuxSet(IOCON, 4, 12, IOCON_FUNC1 | IOCON_MODE_INACT |
361  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
362 
363  //Configure ENET_TX_EN (P4_13)
364  IOCON_PinMuxSet(IOCON, 4, 13, IOCON_FUNC1 | IOCON_MODE_INACT |
365  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
366 
367  //Configure ENET_RX_CLK (P4_14)
368  IOCON_PinMuxSet(IOCON, 4, 14, IOCON_FUNC1 | IOCON_MODE_INACT |
369  IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
370 
371  //Configure ENET_RST (P2_26) as an output
372  pinConfig.pinDirection = kGPIO_DigitalOutput;
373  pinConfig.outputLogic = 0;
374  GPIO_PinInit(GPIO, 2, 26, &pinConfig);
375 
376  //Reset PHY transceiver (hard reset)
377  GPIO_PinWrite(GPIO, 2, 26, 0);
378  sleep(10);
379  GPIO_PinWrite(GPIO, 2, 26, 1);
380  sleep(10);
381 #endif
382 }
383 
384 
385 /**
386  * @brief Initialize DMA descriptor lists
387  * @param[in] interface Underlying network interface
388  **/
389 
391 {
392  uint_t i;
393 
394  //Initialize TX DMA descriptor list
395  for(i = 0; i < LPC54XXX_ETH_TX_BUFFER_COUNT; i++)
396  {
397  //The descriptor is initially owned by the application
398  txDmaDesc[i].tdes0 = 0;
399  txDmaDesc[i].tdes1 = 0;
400  txDmaDesc[i].tdes2 = 0;
401  txDmaDesc[i].tdes3 = 0;
402  }
403 
404  //Initialize TX descriptor index
405  txIndex = 0;
406 
407  //Initialize RX DMA descriptor list
408  for(i = 0; i < LPC54XXX_ETH_RX_BUFFER_COUNT; i++)
409  {
410  //The descriptor is initially owned by the DMA
411  rxDmaDesc[i].rdes0 = (uint32_t) rxBuffer[i];
412  rxDmaDesc[i].rdes1 = 0;
413  rxDmaDesc[i].rdes2 = 0;
415  }
416 
417  //Initialize RX descriptor index
418  rxIndex = 0;
419 
420  //Start location of the TX descriptor list
421  ENET->DMA_CH[0].DMA_CHX_TXDESC_LIST_ADDR = (uint32_t) &txDmaDesc[0];
422  //Length of the transmit descriptor ring
423  ENET->DMA_CH[0].DMA_CHX_TXDESC_RING_LENGTH = LPC54XXX_ETH_TX_BUFFER_COUNT - 1;
424 
425  //Start location of the RX descriptor list
426  ENET->DMA_CH[0].DMA_CHX_RXDESC_LIST_ADDR = (uint32_t) &rxDmaDesc[0];
427  //Length of the receive descriptor ring
428  ENET->DMA_CH[0].DMA_CHX_RXDESC_RING_LENGTH = LPC54XXX_ETH_RX_BUFFER_COUNT - 1;
429 }
430 
431 
432 /**
433  * @brief LPC54xxx Ethernet MAC timer handler
434  *
435  * This routine is periodically called by the TCP/IP stack to handle periodic
436  * operations such as polling the link state
437  *
438  * @param[in] interface Underlying network interface
439  **/
440 
442 {
443  //Valid Ethernet PHY or switch driver?
444  if(interface->phyDriver != NULL)
445  {
446  //Handle periodic operations
447  interface->phyDriver->tick(interface);
448  }
449  else if(interface->switchDriver != NULL)
450  {
451  //Handle periodic operations
452  interface->switchDriver->tick(interface);
453  }
454  else
455  {
456  //Just for sanity
457  }
458 }
459 
460 
461 /**
462  * @brief Enable interrupts
463  * @param[in] interface Underlying network interface
464  **/
465 
467 {
468  //Enable Ethernet MAC interrupts
469  NVIC_EnableIRQ(ETHERNET_IRQn);
470 
471  //Valid Ethernet PHY or switch driver?
472  if(interface->phyDriver != NULL)
473  {
474  //Enable Ethernet PHY interrupts
475  interface->phyDriver->enableIrq(interface);
476  }
477  else if(interface->switchDriver != NULL)
478  {
479  //Enable Ethernet switch interrupts
480  interface->switchDriver->enableIrq(interface);
481  }
482  else
483  {
484  //Just for sanity
485  }
486 }
487 
488 
489 /**
490  * @brief Disable interrupts
491  * @param[in] interface Underlying network interface
492  **/
493 
495 {
496  //Disable Ethernet MAC interrupts
497  NVIC_DisableIRQ(ETHERNET_IRQn);
498 
499  //Valid Ethernet PHY or switch driver?
500  if(interface->phyDriver != NULL)
501  {
502  //Disable Ethernet PHY interrupts
503  interface->phyDriver->disableIrq(interface);
504  }
505  else if(interface->switchDriver != NULL)
506  {
507  //Disable Ethernet switch interrupts
508  interface->switchDriver->disableIrq(interface);
509  }
510  else
511  {
512  //Just for sanity
513  }
514 }
515 
516 
517 /**
518  * @brief LPC54xxx Ethernet MAC interrupt service routine
519  **/
520 
522 {
523  bool_t flag;
524  uint32_t status;
525 
526  //Interrupt service routine prologue
527  osEnterIsr();
528 
529  //This flag will be set if a higher priority task must be woken
530  flag = FALSE;
531 
532  //Read DMA status register
533  status = ENET->DMA_CH[0].DMA_CHX_STAT;
534 
535  //Packet transmitted?
536  if((status & ENET_DMA_CH_DMA_CHX_STAT_TI_MASK) != 0)
537  {
538  //Clear TI interrupt flag
539  ENET->DMA_CH[0].DMA_CHX_STAT = ENET_DMA_CH_DMA_CHX_STAT_TI_MASK;
540 
541  //Check whether the TX buffer is available for writing
542  if((txDmaDesc[txIndex].tdes3 & ENET_TDES3_OWN) == 0)
543  {
544  //Notify the TCP/IP stack that the transmitter is ready to send
545  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
546  }
547  }
548 
549  //Packet received?
550  if((status & ENET_DMA_CH_DMA_CHX_STAT_RI_MASK) != 0)
551  {
552  //Clear RI interrupt flag
553  ENET->DMA_CH[0].DMA_CHX_STAT = ENET_DMA_CH_DMA_CHX_STAT_RI_MASK;
554 
555  //Set event flag
556  nicDriverInterface->nicEvent = TRUE;
557  //Notify the TCP/IP stack of the event
558  flag |= osSetEventFromIsr(&netEvent);
559  }
560 
561  //Clear NIS interrupt flag
562  ENET->DMA_CH[0].DMA_CHX_STAT = ENET_DMA_CH_DMA_CHX_STAT_NIS_MASK;
563 
564  //Interrupt service routine epilogue
565  osExitIsr(flag);
566 }
567 
568 
569 /**
570  * @brief LPC54xxx Ethernet MAC event handler
571  * @param[in] interface Underlying network interface
572  **/
573 
575 {
576  error_t error;
577 
578  //Process all pending packets
579  do
580  {
581  //Read incoming packet
582  error = lpc54xxxEthReceivePacket(interface);
583 
584  //No more data in the receive buffer?
585  } while(error != ERROR_BUFFER_EMPTY);
586 }
587 
588 
589 /**
590  * @brief Send a packet
591  * @param[in] interface Underlying network interface
592  * @param[in] buffer Multi-part buffer containing the data to send
593  * @param[in] offset Offset to the first data byte
594  * @param[in] ancillary Additional options passed to the stack along with
595  * the packet
596  * @return Error code
597  **/
598 
600  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
601 {
602  size_t length;
603 
604  //Retrieve the length of the packet
605  length = netBufferGetLength(buffer) - offset;
606 
607  //Check the frame length
609  {
610  //The transmitter can accept another packet
611  osSetEvent(&interface->nicTxEvent);
612  //Report an error
613  return ERROR_INVALID_LENGTH;
614  }
615 
616  //Make sure the current buffer is available for writing
617  if((txDmaDesc[txIndex].tdes3 & ENET_TDES3_OWN) != 0)
618  {
619  return ERROR_FAILURE;
620  }
621 
622  //Copy user data to the transmit buffer
623  netBufferRead(txBuffer[txIndex], buffer, offset, length);
624 
625  //Set the start address of the buffer
626  txDmaDesc[txIndex].tdes0 = (uint32_t) txBuffer[txIndex];
627  //Write the number of bytes to send
628  txDmaDesc[txIndex].tdes2 = ENET_TDES2_IOC | (length & ENET_TDES2_B1L);
629  //Give the ownership of the descriptor to the DMA
631 
632  //Clear TBU flag to resume processing
633  ENET->DMA_CH[0].DMA_CHX_STAT = ENET_DMA_CH_DMA_CHX_STAT_TBU_MASK;
634  //Instruct the DMA to poll the transmit descriptor list
635  ENET->DMA_CH[0].DMA_CHX_TXDESC_TAIL_PTR = 0;
636 
637  //Increment index and wrap around if necessary
638  if(++txIndex >= LPC54XXX_ETH_TX_BUFFER_COUNT)
639  {
640  txIndex = 0;
641  }
642 
643  //Check whether the next buffer is available for writing
644  if((txDmaDesc[txIndex].tdes3 & ENET_TDES3_OWN) == 0)
645  {
646  //The transmitter can accept another packet
647  osSetEvent(&interface->nicTxEvent);
648  }
649 
650  //Data successfully written
651  return NO_ERROR;
652 }
653 
654 
655 /**
656  * @brief Receive a packet
657  * @param[in] interface Underlying network interface
658  * @return Error code
659  **/
660 
662 {
663  error_t error;
664  size_t n;
665  NetRxAncillary ancillary;
666 
667  //Current buffer available for reading?
668  if((rxDmaDesc[rxIndex].rdes3 & ENET_RDES3_OWN) == 0)
669  {
670  //FD and LD flags should be set
671  if((rxDmaDesc[rxIndex].rdes3 & ENET_RDES3_FD) != 0 &&
672  (rxDmaDesc[rxIndex].rdes3 & ENET_RDES3_LD) != 0)
673  {
674  //Make sure no error occurred
675  if((rxDmaDesc[rxIndex].rdes3 & ENET_RDES3_ES) == 0)
676  {
677  //Retrieve the length of the frame
678  n = rxDmaDesc[rxIndex].rdes3 & ENET_RDES3_PL;
679  //Limit the number of data to read
681 
682  //Additional options can be passed to the stack along with the packet
683  ancillary = NET_DEFAULT_RX_ANCILLARY;
684 
685  //Pass the packet to the upper layer
686  nicProcessPacket(interface, rxBuffer[rxIndex], n, &ancillary);
687 
688  //Valid packet received
689  error = NO_ERROR;
690  }
691  else
692  {
693  //The received packet contains an error
694  error = ERROR_INVALID_PACKET;
695  }
696  }
697  else
698  {
699  //The packet is not valid
700  error = ERROR_INVALID_PACKET;
701  }
702 
703  //Set the start address of the buffer
704  rxDmaDesc[rxIndex].rdes0 = (uint32_t) rxBuffer[rxIndex];
705  //Give the ownership of the descriptor back to the DMA
707 
708  //Increment index and wrap around if necessary
709  if(++rxIndex >= LPC54XXX_ETH_RX_BUFFER_COUNT)
710  {
711  rxIndex = 0;
712  }
713  }
714  else
715  {
716  //No more data in the receive buffer
717  error = ERROR_BUFFER_EMPTY;
718  }
719 
720  //Clear RBU flag to resume processing
721  ENET->DMA_CH[0].DMA_CHX_STAT = ENET_DMA_CH_DMA_CHX_STAT_RBU_MASK;
722  //Instruct the DMA to poll the receive descriptor list
723  ENET->DMA_CH[0].DMA_CHX_RXDESC_TAIL_PTR = 0;
724 
725  //Return status code
726  return error;
727 }
728 
729 
730 /**
731  * @brief Configure MAC address filtering
732  * @param[in] interface Underlying network interface
733  * @return Error code
734  **/
735 
737 {
738  uint_t i;
739  bool_t acceptMulticast;
740 
741  //Debug message
742  TRACE_DEBUG("Updating MAC filter...\r\n");
743 
744  //Set the MAC address of the station
745  ENET->MAC_ADDR_LOW = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
746  ENET->MAC_ADDR_HIGH = interface->macAddr.w[2];
747 
748  //This flag will be set if multicast addresses should be accepted
749  acceptMulticast = FALSE;
750 
751  //The MAC address filter contains the list of MAC addresses to accept
752  //when receiving an Ethernet frame
753  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
754  {
755  //Valid entry?
756  if(interface->macAddrFilter[i].refCount > 0)
757  {
758  //Accept multicast addresses
759  acceptMulticast = TRUE;
760  //We are done
761  break;
762  }
763  }
764 
765  //Enable or disable the reception of multicast frames
766  if(acceptMulticast)
767  {
768  ENET->MAC_FRAME_FILTER |= ENET_MAC_FRAME_FILTER_PM_MASK;
769  }
770  else
771  {
772  ENET->MAC_FRAME_FILTER &= ~ENET_MAC_FRAME_FILTER_PM_MASK;
773  }
774 
775  //Successful processing
776  return NO_ERROR;
777 }
778 
779 
780 /**
781  * @brief Adjust MAC configuration parameters for proper operation
782  * @param[in] interface Underlying network interface
783  * @return Error code
784  **/
785 
787 {
788  uint32_t config;
789 
790  //Read current MAC configuration
791  config = ENET->MAC_CONFIG;
792 
793  //10BASE-T or 100BASE-TX operation mode?
794  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
795  {
796  config |= ENET_MAC_CONFIG_FES_MASK;
797  }
798  else
799  {
800  config &= ~ENET_MAC_CONFIG_FES_MASK;
801  }
802 
803  //Half-duplex or full-duplex mode?
804  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
805  {
806  config |= ENET_MAC_CONFIG_DM_MASK;
807  }
808  else
809  {
810  config &= ~ENET_MAC_CONFIG_DM_MASK;
811  }
812 
813  //Update MAC configuration register
814  ENET->MAC_CONFIG = config;
815 
816  //Successful processing
817  return NO_ERROR;
818 }
819 
820 
821 /**
822  * @brief Write PHY register
823  * @param[in] opcode Access type (2 bits)
824  * @param[in] phyAddr PHY address (5 bits)
825  * @param[in] regAddr Register address (5 bits)
826  * @param[in] data Register value
827  **/
828 
829 void lpc54xxxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
830  uint8_t regAddr, uint16_t data)
831 {
832  uint32_t temp;
833 
834  //Valid opcode?
835  if(opcode == SMI_OPCODE_WRITE)
836  {
837  //Take care not to alter MDC clock configuration
838  temp = ENET->MAC_MDIO_ADDR & ENET_MAC_MDIO_ADDR_CR_MASK;
839  //Set up a write operation
840  temp |= ENET_MAC_MDIO_ADDR_MOC(1) | ENET_MAC_MDIO_ADDR_MB_MASK;
841  //PHY address
842  temp |= ENET_MAC_MDIO_ADDR_PA(phyAddr);
843  //Register address
844  temp |= ENET_MAC_MDIO_ADDR_RDA(regAddr);
845 
846  //Data to be written in the PHY register
847  ENET->MAC_MDIO_DATA = data & ENET_MAC_MDIO_DATA_MD_MASK;
848 
849  //Start a write operation
850  ENET->MAC_MDIO_ADDR = temp;
851  //Wait for the write to complete
852  while((ENET->MAC_MDIO_ADDR & ENET_MAC_MDIO_ADDR_MB_MASK) != 0)
853  {
854  }
855  }
856  else
857  {
858  //The MAC peripheral only supports standard Clause 22 opcodes
859  }
860 }
861 
862 
863 /**
864  * @brief Read PHY register
865  * @param[in] opcode Access type (2 bits)
866  * @param[in] phyAddr PHY address (5 bits)
867  * @param[in] regAddr Register address (5 bits)
868  * @return Register value
869  **/
870 
871 uint16_t lpc54xxxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
872  uint8_t regAddr)
873 {
874  uint16_t data;
875  uint32_t temp;
876 
877  //Valid opcode?
878  if(opcode == SMI_OPCODE_READ)
879  {
880  //Take care not to alter MDC clock configuration
881  temp = ENET->MAC_MDIO_ADDR & ENET_MAC_MDIO_ADDR_CR_MASK;
882  //Set up a read operation
883  temp |= ENET_MAC_MDIO_ADDR_MOC(3) | ENET_MAC_MDIO_ADDR_MB_MASK;
884  //PHY address
885  temp |= ENET_MAC_MDIO_ADDR_PA(phyAddr);
886  //Register address
887  temp |= ENET_MAC_MDIO_ADDR_RDA(regAddr);
888 
889  //Start a read operation
890  ENET->MAC_MDIO_ADDR = temp;
891  //Wait for the read to complete
892  while((ENET->MAC_MDIO_ADDR & ENET_MAC_MDIO_ADDR_MB_MASK) != 0)
893  {
894  }
895 
896  //Get register value
897  data = ENET->MAC_MDIO_DATA & ENET_MAC_MDIO_DATA_MD_MASK;
898  }
899  else
900  {
901  //The MAC peripheral only supports standard Clause 22 opcodes
902  data = 0;
903  }
904 
905  //Return the value of the PHY register
906  return data;
907 }
#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
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
const NicDriver lpc54xxxEthDriver
LPC54xxx Ethernet MAC driver.
error_t lpc54xxxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
error_t lpc54xxxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
error_t lpc54xxxEthReceivePacket(NetInterface *interface)
Receive a packet.
void lpc54xxxEthEnableIrq(NetInterface *interface)
Enable interrupts.
error_t lpc54xxxEthInit(NetInterface *interface)
LPC54xxx Ethernet MAC initialization.
void ETHERNET_IRQHandler(void)
LPC54xxx Ethernet MAC interrupt service routine.
uint16_t lpc54xxxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void lpc54xxxEthEventHandler(NetInterface *interface)
LPC54xxx Ethernet MAC event handler.
void lpc54xxxEthTick(NetInterface *interface)
LPC54xxx Ethernet MAC timer handler.
void lpc54xxxEthDisableIrq(NetInterface *interface)
Disable interrupts.
void lpc54xxxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
void lpc54xxxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
error_t lpc54xxxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
__weak_func void lpc54xxxEthInitGpio(NetInterface *interface)
GPIO configuration.
LPC540xx/LPC546xx Ethernet MAC driver.
#define LPC54XXX_ETH_RX_BUFFER_SIZE
#define ENET_RDES3_FD
#define ENET_RDES3_BUF1V
#define ENET_RDES3_LD
#define ENET_TDES3_OWN
#define LPC54XXX_ETH_TX_BUFFER_SIZE
#define LPC54XXX_ETH_RX_BUFFER_COUNT
#define ENET_RDES3_IOC
#define LPC54XXX_ETH_IRQ_GROUP_PRIORITY
#define ENET_TDES3_FD
#define ENET_RDES3_PL
#define LPC54XXX_ETH_TX_BUFFER_COUNT
#define ENET_TDES3_LD
#define ENET_RDES3_ES
#define ENET_RDES3_OWN
#define ENET_TDES2_B1L
#define ENET_TDES2_IOC
#define LPC54XXX_ETH_IRQ_PRIORITY_GROUPING
#define LPC54XXX_ETH_IRQ_SUB_PRIORITY
uint16_t regAddr
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
#define sleep(delay)
Definition: os_port.h:301
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osEnterIsr()
#define osExitIsr(flag)
Receive descriptor.
Transmit descriptor.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368