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