tm4c129_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file tm4c129_eth_driver.c
3  * @brief Tiva TM4C129 Ethernet controller
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include <stdint.h>
36 #include <stdbool.h>
37 #include "inc/hw_emac.h"
38 #include "inc/hw_flash.h"
39 #include "inc/hw_ints.h"
40 #include "inc/hw_memmap.h"
41 #include "inc/hw_types.h"
42 #include "driverlib/gpio.h"
43 #include "driverlib/interrupt.h"
44 #include "driverlib/pin_map.h"
45 #include "driverlib/sysctl.h"
46 #include "core/net.h"
48 #include "debug.h"
49 
50 //Underlying network interface
51 static NetInterface *nicDriverInterface;
52 
53 //IAR EWARM compiler?
54 #if defined(__ICCARM__)
55 
56 //Transmit buffer
57 #pragma data_alignment = 4
59 //Receive buffer
60 #pragma data_alignment = 4
62 //Transmit DMA descriptors
63 #pragma data_alignment = 4
65 //Receive DMA descriptors
66 #pragma data_alignment = 4
68 
69 //Keil MDK-ARM or GCC compiler?
70 #else
71 
72 //Transmit buffer
74  __attribute__((aligned(4)));
75 //Receive buffer
77  __attribute__((aligned(4)));
78 //Transmit DMA descriptors
80  __attribute__((aligned(4)));
81 //Receive DMA descriptors
83  __attribute__((aligned(4)));
84 
85 #endif
86 
87 //Pointer to the current TX DMA descriptor
88 static Tm4c129TxDmaDesc *txCurDmaDesc;
89 //Pointer to the current RX DMA descriptor
90 static Tm4c129RxDmaDesc *rxCurDmaDesc;
91 
92 
93 /**
94  * @brief TM4C129 Ethernet MAC driver
95  **/
96 
98 {
100  ETH_MTU,
111  TRUE,
112  TRUE,
113  TRUE,
114  FALSE
115 };
116 
117 
118 /**
119  * @brief TM4C129 Ethernet MAC initialization
120  * @param[in] interface Underlying network interface
121  * @return Error code
122  **/
123 
125 {
126  error_t error;
127  uint32_t temp;
128 #ifdef ti_sysbios_BIOS___VERS
129  Hwi_Params hwiParams;
130 #endif
131 
132  //Debug message
133  TRACE_INFO("Initializing TM4C129 Ethernet controller...\r\n");
134 
135  //Save underlying network interface
136  nicDriverInterface = interface;
137 
138  //Before Ethernet initialization the Flash Prefetch must be turned
139  //off (silicon errata ETH#2)
140  temp = FLASH_CONF_R;
141  temp &= ~FLASH_CONF_FPFON;
142  temp |= FLASH_CONF_FPFOFF;
143  FLASH_CONF_R = temp;
144 
145  //Enable and reset EMAC peripheral
146  SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
147  SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
148 
149  //Wait for the EMAC peripheral to be ready
150  while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
151  {
152  }
153 
154  //Enable and reset PHY peripheral
155  SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
156  SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
157 
158  //Wait for the PHY peripheral to be ready
159  while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0))
160  {
161  }
162 
163  //GPIO configuration
164  tm4c129EthInitGpio(interface);
165 
166  //Perform a software reset
167  EMAC0_DMABUSMOD_R |= EMAC_DMABUSMOD_SWR;
168  //Wait for the reset to complete
169  while((EMAC0_DMABUSMOD_R & EMAC_DMABUSMOD_SWR) != 0)
170  {
171  }
172 
173  //Adjust MDC clock range depending on SYSCLK frequency
174  EMAC0_MIIADDR_R = EMAC_MIIADDR_CR_100_150;
175 
176  //Internal or external Ethernet PHY?
177  if(interface->phyDriver != NULL)
178  {
179  //Ethernet PHY initialization
180  error = interface->phyDriver->init(interface);
181  }
182  else if(interface->switchDriver != NULL)
183  {
184  //Ethernet switch initialization
185  error = interface->switchDriver->init(interface);
186  }
187  else
188  {
189  //Reset internal PHY transceiver
191  EPHY_BMCR_MIIRESET);
192 
193  //Wait for the reset to complete
194  while(tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_BMCR) &
195  EPHY_BMCR_MIIRESET)
196  {
197  }
198 
199  //Dump PHY registers for debugging purpose
201 
202  //Configure LED0, LED1 and LED2
203  tm4c129EthWritePhyReg(SMI_OPCODE_WRITE, 0, EPHY_LEDCFG,
204  EPHY_LEDCFG_LED0_TX | EPHY_LEDCFG_LED1_RX | EPHY_LEDCFG_LED2_LINK);
205 
206  //Configure PHY interrupts as desired
208  EPHY_MISR1_LINKSTATEN);
209 
210  //Enable PHY interrupts
211  tm4c129EthWritePhyReg(SMI_OPCODE_WRITE, 0, EPHY_SCR, EPHY_SCR_INTEN);
212 
213  //The internal Ethernet PHY is initialized
214  error = NO_ERROR;
215  }
216 
217  //Any error to report?
218  if(error)
219  {
220  return error;
221  }
222 
223  //Use default MAC configuration
224  EMAC0_CFG_R = EMAC_CFG_DRO;
225 
226  //Configure MAC address filtering
228 
229  //Disable flow control
230  EMAC0_FLOWCTL_R = 0;
231  //Enable store and forward mode
232  EMAC0_DMAOPMODE_R = EMAC_DMAOPMODE_RSF | EMAC_DMAOPMODE_TSF;
233 
234  //Configure DMA bus mode
235  EMAC0_DMABUSMOD_R = EMAC_DMABUSMOD_AAL | EMAC_DMABUSMOD_USP |
237  EMAC_DMABUSMOD_ATDS;
238 
239  //Initialize DMA descriptor lists
240  tm4c129EthInitDmaDesc(interface);
241 
242  //Prevent interrupts from being generated when the transmit statistic
243  //counters reach half their maximum value
244  EMAC0_MMCTXIM_R = EMAC_MMCTXIM_OCTCNT | EMAC_MMCTXIM_MCOLLGF |
245  EMAC_MMCTXIM_SCOLLGF | EMAC_MMCTXIM_GBF;
246 
247  //Prevent interrupts from being generated when the receive statistic
248  //counters reach half their maximum value
249  EMAC0_MMCRXIM_R = EMAC_MMCRXIM_UCGF | EMAC_MMCRXIM_ALGNERR |
250  EMAC_MMCRXIM_CRCERR | EMAC_MMCRXIM_GBF;
251 
252  //Disable MAC interrupts
253  EMAC0_IM_R = EMAC_IM_TSI | EMAC_IM_PMT;
254  //Enable the desired DMA interrupts
255  EMAC0_DMAIM_R = EMAC_DMAIM_NIE | EMAC_DMAIM_RIE | EMAC_DMAIM_TIE;
256  //Enable PHY interrupts
257  EMAC0_EPHYIM_R = EMAC_EPHYIM_INT;
258 
259 #ifdef ti_sysbios_BIOS___VERS
260  //Configure Ethernet interrupt
261  Hwi_Params_init(&hwiParams);
262  hwiParams.enableInt = FALSE;
263  hwiParams.priority = TM4C129_ETH_IRQ_PRIORITY;
264 
265  //Register interrupt handler
266  Hwi_create(INT_EMAC0, (Hwi_FuncPtr) tm4c129EthIrqHandler, &hwiParams, NULL);
267 #else
268  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
269  IntPriorityGroupingSet(TM4C129_ETH_IRQ_PRIORITY_GROUPING);
270  //Configure Ethernet interrupt priority
271  IntPrioritySet(INT_EMAC0, TM4C129_ETH_IRQ_PRIORITY);
272 #endif
273 
274  //Enable MAC transmission and reception
275  EMAC0_CFG_R |= EMAC_CFG_TE | EMAC_CFG_RE;
276  //Enable DMA transmission and reception
277  EMAC0_DMAOPMODE_R |= EMAC_DMAOPMODE_ST | EMAC_DMAOPMODE_SR;
278 
279  //After completing Ethernet initialization, the user code must turn on the
280  //Flash Prefetch to restore system performance (silicon errata ETH#2)
281  temp = FLASH_CONF_R;
282  temp &= ~FLASH_CONF_FPFOFF;
283  temp |= FLASH_CONF_FPFON;
284  FLASH_CONF_R = temp;
285 
286  //Accept any packets from the upper layer
287  osSetEvent(&interface->nicTxEvent);
288 
289  //Successful initialization
290  return NO_ERROR;
291 }
292 
293 
294 /**
295  * @brief GPIO configuration
296  * @param[in] interface Underlying network interface
297  **/
298 
299 __weak_func void tm4c129EthInitGpio(NetInterface *interface)
300 {
301 //DK-TM4C129X evaluation board?
302 #if defined(USE_DK_TM4C129X)
303  //Enable GPIO clocks
304  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
305  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
306 
307  //Select the relevant alternate function for PF1, PK4 and PK6
308  GPIOPinConfigure(GPIO_PF1_EN0LED2);
309  GPIOPinConfigure(GPIO_PK4_EN0LED0);
310  GPIOPinConfigure(GPIO_PK6_EN0LED1);
311 
312  //Configure Ethernet LED pins for proper operation
313  GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_1);
314  GPIOPinTypeEthernetLED(GPIO_PORTK_BASE, GPIO_PIN_4 | GPIO_PIN_6);
315 
316 //EK-TM4C1294XL evaluation board?
317 #elif defined(USE_EK_TM4C1294XL)
318  //Enable GPIO clock
319  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
320 
321  //Select the relevant alternate function for PF0 and PF4
322  GPIOPinConfigure(GPIO_PF0_EN0LED0);
323  GPIOPinConfigure(GPIO_PF4_EN0LED1);
324 
325  //Configure Ethernet LED pins for proper operation
326  GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_4);
327 #endif
328 }
329 
330 
331 /**
332  * @brief Initialize DMA descriptor lists
333  * @param[in] interface Underlying network interface
334  **/
335 
337 {
338  uint_t i;
339 
340  //Initialize TX DMA descriptor list
341  for(i = 0; i < TM4C129_ETH_TX_BUFFER_COUNT; i++)
342  {
343  //Use chain structure rather than ring structure
345  //Initialize transmit buffer size
346  txDmaDesc[i].tdes1 = 0;
347  //Transmit buffer address
348  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
349  //Next descriptor address
350  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
351  //Reserved fields
352  txDmaDesc[i].tdes4 = 0;
353  txDmaDesc[i].tdes5 = 0;
354  //Transmit frame time stamp
355  txDmaDesc[i].tdes6 = 0;
356  txDmaDesc[i].tdes7 = 0;
357  }
358 
359  //The last descriptor is chained to the first entry
360  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
361  //Point to the very first descriptor
362  txCurDmaDesc = &txDmaDesc[0];
363 
364  //Initialize RX DMA descriptor list
365  for(i = 0; i < TM4C129_ETH_RX_BUFFER_COUNT; i++)
366  {
367  //The descriptor is initially owned by the DMA
368  rxDmaDesc[i].rdes0 = EMAC_RDES0_OWN;
369  //Use chain structure rather than ring structure
371  //Receive buffer address
372  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
373  //Next descriptor address
374  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
375  //Extended status
376  rxDmaDesc[i].rdes4 = 0;
377  //Reserved field
378  rxDmaDesc[i].rdes5 = 0;
379  //Receive frame time stamp
380  rxDmaDesc[i].rdes6 = 0;
381  rxDmaDesc[i].rdes7 = 0;
382  }
383 
384  //The last descriptor is chained to the first entry
385  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
386  //Point to the very first descriptor
387  rxCurDmaDesc = &rxDmaDesc[0];
388 
389  //Start location of the TX descriptor list
390  EMAC0_TXDLADDR_R = (uint32_t) txDmaDesc;
391  //Start location of the RX descriptor list
392  EMAC0_RXDLADDR_R = (uint32_t) rxDmaDesc;
393 }
394 
395 
396 /**
397  * @brief TM4C129 Ethernet MAC timer handler
398  *
399  * This routine is periodically called by the TCP/IP stack to handle periodic
400  * operations such as polling the link state
401  *
402  * @param[in] interface Underlying network interface
403  **/
404 
405 void tm4c129EthTick(NetInterface *interface)
406 {
407  //Valid Ethernet PHY or switch driver?
408  if(interface->phyDriver != NULL)
409  {
410  //Handle periodic operations
411  interface->phyDriver->tick(interface);
412  }
413  else if(interface->switchDriver != NULL)
414  {
415  //Handle periodic operations
416  interface->switchDriver->tick(interface);
417  }
418  else
419  {
420  //Just for sanity
421  }
422 }
423 
424 
425 /**
426  * @brief Enable interrupts
427  * @param[in] interface Underlying network interface
428  **/
429 
431 {
432 #ifdef ti_sysbios_BIOS___VERS
433  //Enable Ethernet MAC interrupts
434  Hwi_enableInterrupt(INT_EMAC0);
435 #else
436  //Enable Ethernet MAC interrupts
437  IntEnable(INT_EMAC0);
438 #endif
439 
440  //Valid Ethernet PHY or switch driver?
441  if(interface->phyDriver != NULL)
442  {
443  //Enable Ethernet PHY interrupts
444  interface->phyDriver->enableIrq(interface);
445  }
446  else if(interface->switchDriver != NULL)
447  {
448  //Enable Ethernet switch interrupts
449  interface->switchDriver->enableIrq(interface);
450  }
451  else
452  {
453  //Just for sanity
454  }
455 }
456 
457 
458 /**
459  * @brief Disable interrupts
460  * @param[in] interface Underlying network interface
461  **/
462 
464 {
465 #ifdef ti_sysbios_BIOS___VERS
466  //Disable Ethernet MAC interrupts
467  Hwi_disableInterrupt(INT_EMAC0);
468 #else
469  //Disable Ethernet MAC interrupts
470  IntDisable(INT_EMAC0);
471 #endif
472 
473  //Valid Ethernet PHY or switch driver?
474  if(interface->phyDriver != NULL)
475  {
476  //Disable Ethernet PHY interrupts
477  interface->phyDriver->disableIrq(interface);
478  }
479  else if(interface->switchDriver != NULL)
480  {
481  //Disable Ethernet switch interrupts
482  interface->switchDriver->disableIrq(interface);
483  }
484  else
485  {
486  //Just for sanity
487  }
488 }
489 
490 
491 /**
492  * @brief TM4C129 Ethernet MAC interrupt service routine
493  **/
494 
496 {
497  bool_t flag;
498  uint32_t status;
499 
500  //Interrupt service routine prologue
501  osEnterIsr();
502 
503  //This flag will be set if a higher priority task must be woken
504  flag = FALSE;
505 
506  //Read PHY status register
507  status = EMAC0_EPHYRIS_R;
508 
509  //PHY interrupt?
510  if((status & EMAC_EPHYRIS_INT) != 0)
511  {
512  //Disable PHY interrupt
513  EMAC0_EPHYIM_R &= ~EMAC_EPHYIM_INT;
514 
515  //Set event flag
516  nicDriverInterface->nicEvent = TRUE;
517  //Notify the TCP/IP stack of the event
518  flag |= osSetEventFromIsr(&nicDriverInterface->netContext->event);
519  }
520 
521  //Read DMA status register
522  status = EMAC0_DMARIS_R;
523 
524  //Packet transmitted?
525  if((status & EMAC_DMARIS_TI) != 0)
526  {
527  //Clear TI interrupt flag
528  EMAC0_DMARIS_R = EMAC_DMARIS_TI;
529 
530  //Check whether the TX buffer is available for writing
531  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
532  {
533  //Notify the TCP/IP stack that the transmitter is ready to send
534  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
535  }
536  }
537 
538  //Packet received?
539  if((status & EMAC_DMARIS_RI) != 0)
540  {
541  //Disable RIE interrupt
542  EMAC0_DMAIM_R &= ~EMAC_DMAIM_RIE;
543 
544  //Set event flag
545  nicDriverInterface->nicEvent = TRUE;
546  //Notify the TCP/IP stack of the event
547  flag |= osSetEventFromIsr(&nicDriverInterface->netContext->event);
548  }
549 
550  //Clear NIS interrupt flag
551  EMAC0_DMARIS_R = EMAC_DMARIS_NIS;
552 
553  //Interrupt service routine epilogue
554  osExitIsr(flag);
555 }
556 
557 
558 /**
559  * @brief TM4C129 Ethernet MAC event handler
560  * @param[in] interface Underlying network interface
561  **/
562 
564 {
565  error_t error;
566  uint32_t status;
567 
568  //PHY interrupt?
569  if((EMAC0_EPHYRIS_R & EMAC_EPHYRIS_INT) != 0)
570  {
571  //Clear PHY interrupt flag
572  EMAC0_EPHYMISC_R = EMAC_EPHYMISC_INT;
573 
574  //Internal or external Ethernet PHY?
575  if(interface->phyDriver != NULL)
576  {
577  //Handle events
578  interface->phyDriver->eventHandler(interface);
579  }
580  else if(interface->switchDriver != NULL)
581  {
582  //Handle events
583  interface->switchDriver->eventHandler(interface);
584  }
585  else
586  {
587  //Read PHY interrupt status register
588  status = tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_MISR1);
589 
590  //Check whether the link state has changed?
591  if((status & EPHY_MISR1_LINKSTAT) != 0)
592  {
593  //Read BMSR register
594  status = tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_BMSR);
595 
596  //Check whether the link is up
597  if((status & EPHY_BMSR_LINKSTAT) != 0)
598  {
599  //Read PHY status register
600  status = tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_STS);
601 
602  //Check current speed
603  if((status & EPHY_STS_SPEED) != 0)
604  {
605  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
606  }
607  else
608  {
609  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
610  }
611 
612  //Check duplex mode
613  if((status & EPHY_STS_DUPLEX) != 0)
614  {
615  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
616  }
617  else
618  {
619  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
620  }
621 
622  //Update link state
623  interface->linkState = TRUE;
624 
625  //Adjust MAC configuration parameters for proper operation
626  tm4c129EthUpdateMacConfig(interface);
627  }
628  else
629  {
630  //Update link state
631  interface->linkState = FALSE;
632  }
633 
634  //Process link state change event
635  nicNotifyLinkChange(interface);
636  }
637  }
638  }
639 
640  //Packet received?
641  if((EMAC0_DMARIS_R & EMAC_DMARIS_RI) != 0)
642  {
643  //Clear interrupt flag
644  EMAC0_DMARIS_R = EMAC_DMARIS_RI;
645 
646  //Process all pending packets
647  do
648  {
649  //Read incoming packet
650  error = tm4c129EthReceivePacket(interface);
651 
652  //No more data in the receive buffer?
653  } while(error != ERROR_BUFFER_EMPTY);
654  }
655 
656  //Re-enable DMA interrupts
657  EMAC0_DMAIM_R = EMAC_DMAIM_NIE | EMAC_DMAIM_RIE | EMAC_DMAIM_TIE;
658  //Re-enable PHY interrupts
659  EMAC0_EPHYIM_R = EMAC_EPHYIM_INT;
660 }
661 
662 
663 /**
664  * @brief Send a packet
665  * @param[in] interface Underlying network interface
666  * @param[in] buffer Multi-part buffer containing the data to send
667  * @param[in] offset Offset to the first data byte
668  * @param[in] ancillary Additional options passed to the stack along with
669  * the packet
670  * @return Error code
671  **/
672 
674  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
675 {
676  size_t length;
677 
678  //Retrieve the length of the packet
679  length = netBufferGetLength(buffer) - offset;
680 
681  //Check the frame length
683  {
684  //The transmitter can accept another packet
685  osSetEvent(&interface->nicTxEvent);
686  //Report an error
687  return ERROR_INVALID_LENGTH;
688  }
689 
690  //Make sure the current buffer is available for writing
691  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) != 0)
692  {
693  return ERROR_FAILURE;
694  }
695 
696  //Copy user data to the transmit buffer
697  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
698 
699  //Write the number of bytes to send
700  txCurDmaDesc->tdes1 = length & EMAC_TDES1_TBS1;
701  //Set LS and FS flags as the data fits in a single buffer
702  txCurDmaDesc->tdes0 |= EMAC_TDES0_LS | EMAC_TDES0_FS;
703  //Give the ownership of the descriptor to the DMA
704  txCurDmaDesc->tdes0 |= EMAC_TDES0_OWN;
705 
706  //Clear TU flag to resume processing
707  EMAC0_DMARIS_R = EMAC_DMARIS_TU;
708  //Instruct the DMA to poll the transmit descriptor list
709  EMAC0_TXPOLLD_R = 0;
710 
711  //Point to the next descriptor in the list
712  txCurDmaDesc = (Tm4c129TxDmaDesc *) txCurDmaDesc->tdes3;
713 
714  //Check whether the next buffer is available for writing
715  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
716  {
717  //The transmitter can accept another packet
718  osSetEvent(&interface->nicTxEvent);
719  }
720 
721  //Data successfully written
722  return NO_ERROR;
723 }
724 
725 
726 /**
727  * @brief Receive a packet
728  * @param[in] interface Underlying network interface
729  * @return Error code
730  **/
731 
733 {
734  error_t error;
735  size_t n;
736  NetRxAncillary ancillary;
737 
738  //Current buffer available for reading?
739  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_OWN) == 0)
740  {
741  //FS and LS flags should be set
742  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_FS) != 0 &&
743  (rxCurDmaDesc->rdes0 & EMAC_RDES0_LS) != 0)
744  {
745  //Make sure no error occurred
746  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_ES) == 0)
747  {
748  //Retrieve the length of the frame
749  n = (rxCurDmaDesc->rdes0 & EMAC_RDES0_FL) >> 16;
750  //Limit the number of data to read
752 
753  //Additional options can be passed to the stack along with the packet
754  ancillary = NET_DEFAULT_RX_ANCILLARY;
755 
756  //Pass the packet to the upper layer
757  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
758  &ancillary);
759 
760  //Valid packet received
761  error = NO_ERROR;
762  }
763  else
764  {
765  //The received packet contains an error
766  error = ERROR_INVALID_PACKET;
767  }
768  }
769  else
770  {
771  //The packet is not valid
772  error = ERROR_INVALID_PACKET;
773  }
774 
775  //Give the ownership of the descriptor back to the DMA
776  rxCurDmaDesc->rdes0 = EMAC_RDES0_OWN;
777  //Point to the next descriptor in the list
778  rxCurDmaDesc = (Tm4c129RxDmaDesc *) rxCurDmaDesc->rdes3;
779  }
780  else
781  {
782  //No more data in the receive buffer
783  error = ERROR_BUFFER_EMPTY;
784  }
785 
786  //Clear RU flag to resume processing
787  EMAC0_DMARIS_R = EMAC_DMARIS_RU;
788  //Instruct the DMA to poll the receive descriptor list
789  EMAC0_RXPOLLD_R = 0;
790 
791  //Return status code
792  return error;
793 }
794 
795 
796 /**
797  * @brief Configure MAC address filtering
798  * @param[in] interface Underlying network interface
799  * @return Error code
800  **/
801 
803 {
804  uint_t i;
805  uint_t j;
806  uint_t k;
807  uint32_t crc;
808  uint32_t hashTable[2];
809  MacAddr unicastMacAddr[3];
810  MacFilterEntry *entry;
811 
812  //Debug message
813  TRACE_DEBUG("Updating MAC filter...\r\n");
814 
815  //Promiscuous mode?
816  if(interface->promiscuous)
817  {
818  //Pass all incoming frames regardless of their destination address
819  EMAC0_FRAMEFLTR_R = EMAC_FRAMEFLTR_PR;
820  }
821  else
822  {
823  //Set the MAC address of the station
824  EMAC0_ADDR0L_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
825  EMAC0_ADDR0H_R = interface->macAddr.w[2];
826 
827  //The MAC supports 3 additional addresses for unicast perfect filtering
828  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
829  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
830  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
831 
832  //The hash table is used for multicast address filtering
833  hashTable[0] = 0;
834  hashTable[1] = 0;
835 
836  //The MAC address filter contains the list of MAC addresses to accept
837  //when receiving an Ethernet frame
838  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
839  {
840  //Point to the current entry
841  entry = &interface->macAddrFilter[i];
842 
843  //Valid entry?
844  if(entry->refCount > 0)
845  {
846  //Multicast address?
847  if(macIsMulticastAddr(&entry->addr))
848  {
849  //Compute CRC over the current MAC address
850  crc = tm4c129EthCalcCrc(&entry->addr, sizeof(MacAddr));
851 
852  //The upper 6 bits in the CRC register are used to index the
853  //contents of the hash table
854  k = (crc >> 26) & 0x3F;
855 
856  //Update hash table contents
857  hashTable[k / 32] |= (1 << (k % 32));
858  }
859  else
860  {
861  //Up to 3 additional MAC addresses can be specified
862  if(j < 3)
863  {
864  //Save the unicast address
865  unicastMacAddr[j++] = entry->addr;
866  }
867  }
868  }
869  }
870 
871  //Configure the first unicast address filter
872  if(j >= 1)
873  {
874  //When the AE bit is set, the entry is used for perfect filtering
875  EMAC0_ADDR1L_R = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
876  EMAC0_ADDR1H_R = unicastMacAddr[0].w[2] | EMAC_ADDR1H_AE;
877  }
878  else
879  {
880  //When the AE bit is cleared, the entry is ignored
881  EMAC0_ADDR1L_R = 0;
882  EMAC0_ADDR1H_R = 0;
883  }
884 
885  //Configure the second unicast address filter
886  if(j >= 2)
887  {
888  //When the AE bit is set, the entry is used for perfect filtering
889  EMAC0_ADDR2L_R = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
890  EMAC0_ADDR2H_R = unicastMacAddr[1].w[2] | EMAC_ADDR2H_AE;
891  }
892  else
893  {
894  //When the AE bit is cleared, the entry is ignored
895  EMAC0_ADDR2L_R = 0;
896  EMAC0_ADDR2H_R = 0;
897  }
898 
899  //Configure the third unicast address filter
900  if(j >= 3)
901  {
902  //When the AE bit is set, the entry is used for perfect filtering
903  EMAC0_ADDR3L_R = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
904  EMAC0_ADDR3H_R = unicastMacAddr[2].w[2] | EMAC_ADDR3H_AE;
905  }
906  else
907  {
908  //When the AE bit is cleared, the entry is ignored
909  EMAC0_ADDR3L_R = 0;
910  EMAC0_ADDR3H_R = 0;
911  }
912 
913  //Check whether frames with a multicast destination address should be
914  //accepted
915  if(interface->acceptAllMulticast)
916  {
917  //Configure the receive filter
918  EMAC0_FRAMEFLTR_R = EMAC_FRAMEFLTR_HPF | EMAC_FRAMEFLTR_PM;
919  }
920  else
921  {
922  //Configure the receive filter
923  EMAC0_FRAMEFLTR_R = EMAC_FRAMEFLTR_HPF | EMAC_FRAMEFLTR_HMC;
924 
925  //Configure the multicast hash table
926  EMAC0_HASHTBLL_R = hashTable[0];
927  EMAC0_HASHTBLH_R = hashTable[1];
928 
929  //Debug message
930  TRACE_DEBUG(" HASHTBLL = 0x%08" PRIX32 "\r\n", EMAC0_HASHTBLL_R);
931  TRACE_DEBUG(" HASHTBLH = 0x%08" PRIX32 "\r\n", EMAC0_HASHTBLH_R);
932  }
933  }
934 
935  //Successful processing
936  return NO_ERROR;
937 }
938 
939 
940 /**
941  * @brief Adjust MAC configuration parameters for proper operation
942  * @param[in] interface Underlying network interface
943  * @return Error code
944  **/
945 
947 {
948  uint32_t config;
949 
950  //Read current MAC configuration
951  config = EMAC0_CFG_R;
952 
953  //10BASE-T or 100BASE-TX operation mode?
954  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
955  {
956  config |= EMAC_CFG_FES;
957  }
958  else
959  {
960  config &= ~EMAC_CFG_FES;
961  }
962 
963  //Half-duplex or full-duplex mode?
964  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
965  {
966  config |= EMAC_CFG_DUPM;
967  }
968  else
969  {
970  config &= ~EMAC_CFG_DUPM;
971  }
972 
973  //Update MAC configuration register
974  EMAC0_CFG_R = config;
975 
976  //Successful processing
977  return NO_ERROR;
978 }
979 
980 
981 /**
982  * @brief Write PHY register
983  * @param[in] opcode Access type (2 bits)
984  * @param[in] phyAddr PHY address (5 bits)
985  * @param[in] regAddr Register address (5 bits)
986  * @param[in] data Register value
987  **/
988 
989 void tm4c129EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
990  uint8_t regAddr, uint16_t data)
991 {
992  uint32_t temp;
993 
994  //Valid opcode?
995  if(opcode == SMI_OPCODE_WRITE)
996  {
997  //Take care not to alter MDC clock configuration
998  temp = EMAC0_MIIADDR_R & EMAC_MIIADDR_CR_M;
999  //Set up a write operation
1000  temp |= EMAC_MIIADDR_MIIW | EMAC_MIIADDR_MIIB;
1001  //PHY address
1002  temp |= (phyAddr << EMAC_MIIADDR_PLA_S) & EMAC_MIIADDR_PLA_M;
1003  //Register address
1004  temp |= (regAddr << EMAC_MIIADDR_MII_S) & EMAC_MIIADDR_MII_M;
1005 
1006  //Data to be written in the PHY register
1007  EMAC0_MIIDATA_R = data & EMAC_MIIDATA_DATA_M;
1008 
1009  //Start a write operation
1010  EMAC0_MIIADDR_R = temp;
1011  //Wait for the write to complete
1012  while((EMAC0_MIIADDR_R & EMAC_MIIADDR_MIIB) != 0)
1013  {
1014  }
1015  }
1016  else
1017  {
1018  //The MAC peripheral only supports standard Clause 22 opcodes
1019  }
1020 }
1021 
1022 
1023 /**
1024  * @brief Read PHY register
1025  * @param[in] opcode Access type (2 bits)
1026  * @param[in] phyAddr PHY address (5 bits)
1027  * @param[in] regAddr Register address (5 bits)
1028  * @return Register value
1029  **/
1030 
1031 uint16_t tm4c129EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1032  uint8_t regAddr)
1033 {
1034  uint16_t data;
1035  uint32_t temp;
1036 
1037  //Valid opcode?
1038  if(opcode == SMI_OPCODE_READ)
1039  {
1040  //Take care not to alter MDC clock configuration
1041  temp = EMAC0_MIIADDR_R & EMAC_MIIADDR_CR_M;
1042  //Set up a read operation
1043  temp |= EMAC_MIIADDR_MIIB;
1044  //PHY address
1045  temp |= (phyAddr << EMAC_MIIADDR_PLA_S) & EMAC_MIIADDR_PLA_M;
1046  //Register address
1047  temp |= (regAddr << EMAC_MIIADDR_MII_S) & EMAC_MIIADDR_MII_M;
1048 
1049  //Start a read operation
1050  EMAC0_MIIADDR_R = temp;
1051  //Wait for the read to complete
1052  while((EMAC0_MIIADDR_R & EMAC_MIIADDR_MIIB) != 0)
1053  {
1054  }
1055 
1056  //Get register value
1057  data = EMAC0_MIIDATA_R & EMAC_MIIDATA_DATA_M;
1058  }
1059  else
1060  {
1061  //The MAC peripheral only supports standard Clause 22 opcodes
1062  data = 0;
1063  }
1064 
1065  //Return the value of the PHY register
1066  return data;
1067 }
1068 
1069 
1070 /**
1071  * @brief Dump PHY registers for debugging purpose
1072  **/
1073 
1075 {
1076  uint8_t i;
1077 
1078  //Loop through PHY registers
1079  for(i = 0; i < 32; i++)
1080  {
1081  //Display current PHY register
1082  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1084  }
1085 
1086  //Terminate with a line feed
1087  TRACE_DEBUG("\r\n");
1088 }
1089 
1090 
1091 /**
1092  * @brief CRC calculation
1093  * @param[in] data Pointer to the data over which to calculate the CRC
1094  * @param[in] length Number of bytes to process
1095  * @return Resulting CRC value
1096  **/
1097 
1098 uint32_t tm4c129EthCalcCrc(const void *data, size_t length)
1099 {
1100  uint_t i;
1101  uint_t j;
1102  uint32_t crc;
1103  const uint8_t *p;
1104 
1105  //Point to the data over which to calculate the CRC
1106  p = (uint8_t *) data;
1107  //CRC preset value
1108  crc = 0xFFFFFFFF;
1109 
1110  //Loop through data
1111  for(i = 0; i < length; i++)
1112  {
1113  //The message is processed bit by bit
1114  for(j = 0; j < 8; j++)
1115  {
1116  //Update CRC value
1117  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1118  {
1119  crc = (crc << 1) ^ 0x04C11DB7;
1120  }
1121  else
1122  {
1123  crc = crc << 1;
1124  }
1125  }
1126  }
1127 
1128  //Return CRC value
1129  return ~crc;
1130 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
#define EMAC_RDES1_RBS1
#define EMAC0_EPHYMISC_R
uint8_t opcode
Definition: dns_common.h:191
int bool_t
Definition: compiler_port.h:63
error_t tm4c129EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
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
Enhanced TX DMA descriptor.
#define EMAC_TDES0_OWN
#define EMAC0_DMABUSMOD_R
uint8_t p
Definition: ndp.h:300
#define EMAC_DMABUSMOD_RPBL_32
#define EMAC_RDES0_ES
__weak_func void tm4c129EthInitGpio(NetInterface *interface)
GPIO configuration.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
void tm4c129EthDumpPhyReg(void)
Dump PHY registers for debugging purpose.
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
#define EMAC0_ADDR1H_R
uint8_t data[]
Definition: ethernet.h:224
#define EMAC0_HASHTBLH_R
#define TM4C129_ETH_RX_BUFFER_COUNT
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
#define EMAC_TDES0_IC
#define EMAC0_TXDLADDR_R
#define FLASH_CONF_R
#define EMAC0_ADDR2H_R
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define EMAC0_ADDR1L_R
#define osExitIsr(flag)
error_t tm4c129EthReceivePacket(NetInterface *interface)
Receive a packet.
void tm4c129EthEnableIrq(NetInterface *interface)
Enable interrupts.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define EMAC0_IM_R
Tiva TM4C129 Ethernet controller.
#define FALSE
Definition: os_port.h:46
#define EMAC_RDES1_RCH
#define EMAC_TDES1_TBS1
#define EMAC_RDES0_LS
#define EMAC0_ADDR0L_R
error_t
Error codes.
Definition: error.h:43
#define EMAC0_ADDR2L_R
void tm4c129EthTick(NetInterface *interface)
TM4C129 Ethernet MAC timer handler.
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define EMAC0_MMCTXIM_R
#define txBuffer
#define EMAC0_CFG_R
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
MacAddr addr
MAC address.
Definition: ethernet.h:265
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
#define EMAC0_ADDR3L_R
#define EMAC0_ADDR3H_R
#define NetTxAncillary
Definition: net_misc.h:36
#define EMAC0_ADDR0H_R
void tm4c129EthEventHandler(NetInterface *interface)
TM4C129 Ethernet MAC event handler.
#define EMAC0_RXPOLLD_R
#define SMI_OPCODE_READ
Definition: nic.h:67
#define EMAC0_FLOWCTL_R
#define EMAC0_FRAMEFLTR_R
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MIN(a, b)
Definition: os_port.h:63
#define EMAC_TDES0_LS
#define rxBuffer
#define EMAC0_TXPOLLD_R
void tm4c129EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
uint32_t tm4c129EthCalcCrc(const void *data, size_t length)
CRC calculation.
#define EMAC0_MMCRXIM_R
MacAddr
Definition: ethernet.h:197
#define EMAC_TDES0_TCH
error_t tm4c129EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define TM4C129_ETH_TX_BUFFER_COUNT
void tm4c129EthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
#define EMAC_RDES0_FL
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define TM4C129_ETH_RX_BUFFER_SIZE
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
MAC filter table entry.
Definition: ethernet.h:264
#define EMAC0_RXDLADDR_R
error_t tm4c129EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
#define TM4C129_ETH_IRQ_PRIORITY
#define osEnterIsr()
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
#define EMAC0_DMARIS_R
uint16_t tm4c129EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
const NicDriver tm4c129EthDriver
TM4C129 Ethernet MAC driver.
#define EMAC_DMABUSMOD_PR_1_1
#define EMAC_DMABUSMOD_PBL_32
#define EMAC0_MIIADDR_R
#define EMAC0_MIIDATA_R
#define EMAC0_EPHYIM_R
#define EMAC_TDES0_FS
#define rxDmaDesc
void tm4c129EthIrqHandler(void)
TM4C129 Ethernet MAC interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define EMAC0_DMAOPMODE_R
#define EMAC0_DMAIM_R
#define EMAC0_EPHYRIS_R
#define txDmaDesc
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define TM4C129_ETH_IRQ_PRIORITY_GROUPING
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
NIC driver.
Definition: nic.h:286
#define EMAC_RDES0_OWN
Enhanced RX DMA descriptor.
void tm4c129EthDisableIrq(NetInterface *interface)
Disable interrupts.
#define EMAC0_HASHTBLL_R
error_t tm4c129EthInit(NetInterface *interface)
TM4C129 Ethernet MAC initialization.
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define EMAC_RDES0_FS
#define TM4C129_ETH_TX_BUFFER_SIZE