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-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.4
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  //Set the MAC address of the station
227  EMAC0_ADDR0L_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
228  EMAC0_ADDR0H_R = interface->macAddr.w[2];
229 
230  //The MAC supports 3 additional addresses for unicast perfect filtering
231  EMAC0_ADDR1L_R = 0;
232  EMAC0_ADDR1H_R = 0;
233  EMAC0_ADDR2L_R = 0;
234  EMAC0_ADDR2H_R = 0;
235  EMAC0_ADDR3L_R = 0;
236  EMAC0_ADDR3H_R = 0;
237 
238  //Initialize hash table
239  EMAC0_HASHTBLL_R = 0;
240  EMAC0_HASHTBLH_R = 0;
241 
242  //Configure the receive filter
243  EMAC0_FRAMEFLTR_R = EMAC_FRAMEFLTR_HPF | EMAC_FRAMEFLTR_HMC;
244  //Disable flow control
245  EMAC0_FLOWCTL_R = 0;
246  //Enable store and forward mode
247  EMAC0_DMAOPMODE_R = EMAC_DMAOPMODE_RSF | EMAC_DMAOPMODE_TSF;
248 
249  //Configure DMA bus mode
250  EMAC0_DMABUSMOD_R = EMAC_DMABUSMOD_AAL | EMAC_DMABUSMOD_USP |
252  EMAC_DMABUSMOD_ATDS;
253 
254  //Initialize DMA descriptor lists
255  tm4c129EthInitDmaDesc(interface);
256 
257  //Prevent interrupts from being generated when the transmit statistic
258  //counters reach half their maximum value
259  EMAC0_MMCTXIM_R = EMAC_MMCTXIM_OCTCNT | EMAC_MMCTXIM_MCOLLGF |
260  EMAC_MMCTXIM_SCOLLGF | EMAC_MMCTXIM_GBF;
261 
262  //Prevent interrupts from being generated when the receive statistic
263  //counters reach half their maximum value
264  EMAC0_MMCRXIM_R = EMAC_MMCRXIM_UCGF | EMAC_MMCRXIM_ALGNERR |
265  EMAC_MMCRXIM_CRCERR | EMAC_MMCRXIM_GBF;
266 
267  //Disable MAC interrupts
268  EMAC0_IM_R = EMAC_IM_TSI | EMAC_IM_PMT;
269  //Enable the desired DMA interrupts
270  EMAC0_DMAIM_R = EMAC_DMAIM_NIE | EMAC_DMAIM_RIE | EMAC_DMAIM_TIE;
271  //Enable PHY interrupts
272  EMAC0_EPHYIM_R = EMAC_EPHYIM_INT;
273 
274 #ifdef ti_sysbios_BIOS___VERS
275  //Configure Ethernet interrupt
276  Hwi_Params_init(&hwiParams);
277  hwiParams.enableInt = FALSE;
278  hwiParams.priority = TM4C129_ETH_IRQ_PRIORITY;
279 
280  //Register interrupt handler
281  Hwi_create(INT_EMAC0, (Hwi_FuncPtr) tm4c129EthIrqHandler, &hwiParams, NULL);
282 #else
283  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
284  IntPriorityGroupingSet(TM4C129_ETH_IRQ_PRIORITY_GROUPING);
285  //Configure Ethernet interrupt priority
286  IntPrioritySet(INT_EMAC0, TM4C129_ETH_IRQ_PRIORITY);
287 #endif
288 
289  //Enable MAC transmission and reception
290  EMAC0_CFG_R |= EMAC_CFG_TE | EMAC_CFG_RE;
291  //Enable DMA transmission and reception
292  EMAC0_DMAOPMODE_R |= EMAC_DMAOPMODE_ST | EMAC_DMAOPMODE_SR;
293 
294  //After completing Ethernet initialization, the user code must turn on the
295  //Flash Prefetch to restore system performance (silicon errata ETH#2)
296  temp = FLASH_CONF_R;
297  temp &= ~FLASH_CONF_FPFOFF;
298  temp |= FLASH_CONF_FPFON;
299  FLASH_CONF_R = temp;
300 
301  //Accept any packets from the upper layer
302  osSetEvent(&interface->nicTxEvent);
303 
304  //Successful initialization
305  return NO_ERROR;
306 }
307 
308 
309 /**
310  * @brief GPIO configuration
311  * @param[in] interface Underlying network interface
312  **/
313 
314 __weak_func void tm4c129EthInitGpio(NetInterface *interface)
315 {
316 //DK-TM4C129X evaluation board?
317 #if defined(USE_DK_TM4C129X)
318  //Enable GPIO clocks
319  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
320  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
321 
322  //Select the relevant alternate function for PF1, PK4 and PK6
323  GPIOPinConfigure(GPIO_PF1_EN0LED2);
324  GPIOPinConfigure(GPIO_PK4_EN0LED0);
325  GPIOPinConfigure(GPIO_PK6_EN0LED1);
326 
327  //Configure Ethernet LED pins for proper operation
328  GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_1);
329  GPIOPinTypeEthernetLED(GPIO_PORTK_BASE, GPIO_PIN_4 | GPIO_PIN_6);
330 
331 //EK-TM4C1294XL evaluation board?
332 #elif defined(USE_EK_TM4C1294XL)
333  //Enable GPIO clock
334  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
335 
336  //Select the relevant alternate function for PF0 and PF4
337  GPIOPinConfigure(GPIO_PF0_EN0LED0);
338  GPIOPinConfigure(GPIO_PF4_EN0LED1);
339 
340  //Configure Ethernet LED pins for proper operation
341  GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_4);
342 #endif
343 }
344 
345 
346 /**
347  * @brief Initialize DMA descriptor lists
348  * @param[in] interface Underlying network interface
349  **/
350 
352 {
353  uint_t i;
354 
355  //Initialize TX DMA descriptor list
356  for(i = 0; i < TM4C129_ETH_TX_BUFFER_COUNT; i++)
357  {
358  //Use chain structure rather than ring structure
360  //Initialize transmit buffer size
361  txDmaDesc[i].tdes1 = 0;
362  //Transmit buffer address
363  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
364  //Next descriptor address
365  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
366  //Reserved fields
367  txDmaDesc[i].tdes4 = 0;
368  txDmaDesc[i].tdes5 = 0;
369  //Transmit frame time stamp
370  txDmaDesc[i].tdes6 = 0;
371  txDmaDesc[i].tdes7 = 0;
372  }
373 
374  //The last descriptor is chained to the first entry
375  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
376  //Point to the very first descriptor
377  txCurDmaDesc = &txDmaDesc[0];
378 
379  //Initialize RX DMA descriptor list
380  for(i = 0; i < TM4C129_ETH_RX_BUFFER_COUNT; i++)
381  {
382  //The descriptor is initially owned by the DMA
383  rxDmaDesc[i].rdes0 = EMAC_RDES0_OWN;
384  //Use chain structure rather than ring structure
386  //Receive buffer address
387  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
388  //Next descriptor address
389  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
390  //Extended status
391  rxDmaDesc[i].rdes4 = 0;
392  //Reserved field
393  rxDmaDesc[i].rdes5 = 0;
394  //Receive frame time stamp
395  rxDmaDesc[i].rdes6 = 0;
396  rxDmaDesc[i].rdes7 = 0;
397  }
398 
399  //The last descriptor is chained to the first entry
400  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
401  //Point to the very first descriptor
402  rxCurDmaDesc = &rxDmaDesc[0];
403 
404  //Start location of the TX descriptor list
405  EMAC0_TXDLADDR_R = (uint32_t) txDmaDesc;
406  //Start location of the RX descriptor list
407  EMAC0_RXDLADDR_R = (uint32_t) rxDmaDesc;
408 }
409 
410 
411 /**
412  * @brief TM4C129 Ethernet MAC timer handler
413  *
414  * This routine is periodically called by the TCP/IP stack to handle periodic
415  * operations such as polling the link state
416  *
417  * @param[in] interface Underlying network interface
418  **/
419 
420 void tm4c129EthTick(NetInterface *interface)
421 {
422  //Valid Ethernet PHY or switch driver?
423  if(interface->phyDriver != NULL)
424  {
425  //Handle periodic operations
426  interface->phyDriver->tick(interface);
427  }
428  else if(interface->switchDriver != NULL)
429  {
430  //Handle periodic operations
431  interface->switchDriver->tick(interface);
432  }
433  else
434  {
435  //Just for sanity
436  }
437 }
438 
439 
440 /**
441  * @brief Enable interrupts
442  * @param[in] interface Underlying network interface
443  **/
444 
446 {
447 #ifdef ti_sysbios_BIOS___VERS
448  //Enable Ethernet MAC interrupts
449  Hwi_enableInterrupt(INT_EMAC0);
450 #else
451  //Enable Ethernet MAC interrupts
452  IntEnable(INT_EMAC0);
453 #endif
454 
455  //Valid Ethernet PHY or switch driver?
456  if(interface->phyDriver != NULL)
457  {
458  //Enable Ethernet PHY interrupts
459  interface->phyDriver->enableIrq(interface);
460  }
461  else if(interface->switchDriver != NULL)
462  {
463  //Enable Ethernet switch interrupts
464  interface->switchDriver->enableIrq(interface);
465  }
466  else
467  {
468  //Just for sanity
469  }
470 }
471 
472 
473 /**
474  * @brief Disable interrupts
475  * @param[in] interface Underlying network interface
476  **/
477 
479 {
480 #ifdef ti_sysbios_BIOS___VERS
481  //Disable Ethernet MAC interrupts
482  Hwi_disableInterrupt(INT_EMAC0);
483 #else
484  //Disable Ethernet MAC interrupts
485  IntDisable(INT_EMAC0);
486 #endif
487 
488  //Valid Ethernet PHY or switch driver?
489  if(interface->phyDriver != NULL)
490  {
491  //Disable Ethernet PHY interrupts
492  interface->phyDriver->disableIrq(interface);
493  }
494  else if(interface->switchDriver != NULL)
495  {
496  //Disable Ethernet switch interrupts
497  interface->switchDriver->disableIrq(interface);
498  }
499  else
500  {
501  //Just for sanity
502  }
503 }
504 
505 
506 /**
507  * @brief TM4C129 Ethernet MAC interrupt service routine
508  **/
509 
511 {
512  bool_t flag;
513  uint32_t status;
514 
515  //Interrupt service routine prologue
516  osEnterIsr();
517 
518  //This flag will be set if a higher priority task must be woken
519  flag = FALSE;
520 
521  //Read PHY status register
522  status = EMAC0_EPHYRIS_R;
523 
524  //PHY interrupt?
525  if((status & EMAC_EPHYRIS_INT) != 0)
526  {
527  //Disable PHY interrupt
528  EMAC0_EPHYIM_R &= ~EMAC_EPHYIM_INT;
529 
530  //Set event flag
531  nicDriverInterface->nicEvent = TRUE;
532  //Notify the TCP/IP stack of the event
533  flag |= osSetEventFromIsr(&netEvent);
534  }
535 
536  //Read DMA status register
537  status = EMAC0_DMARIS_R;
538 
539  //Packet transmitted?
540  if((status & EMAC_DMARIS_TI) != 0)
541  {
542  //Clear TI interrupt flag
543  EMAC0_DMARIS_R = EMAC_DMARIS_TI;
544 
545  //Check whether the TX buffer is available for writing
546  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
547  {
548  //Notify the TCP/IP stack that the transmitter is ready to send
549  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
550  }
551  }
552 
553  //Packet received?
554  if((status & EMAC_DMARIS_RI) != 0)
555  {
556  //Disable RIE interrupt
557  EMAC0_DMAIM_R &= ~EMAC_DMAIM_RIE;
558 
559  //Set event flag
560  nicDriverInterface->nicEvent = TRUE;
561  //Notify the TCP/IP stack of the event
562  flag |= osSetEventFromIsr(&netEvent);
563  }
564 
565  //Clear NIS interrupt flag
566  EMAC0_DMARIS_R = EMAC_DMARIS_NIS;
567 
568  //Interrupt service routine epilogue
569  osExitIsr(flag);
570 }
571 
572 
573 /**
574  * @brief TM4C129 Ethernet MAC event handler
575  * @param[in] interface Underlying network interface
576  **/
577 
579 {
580  error_t error;
581  uint32_t status;
582 
583  //PHY interrupt?
584  if((EMAC0_EPHYRIS_R & EMAC_EPHYRIS_INT) != 0)
585  {
586  //Clear PHY interrupt flag
587  EMAC0_EPHYMISC_R = EMAC_EPHYMISC_INT;
588 
589  //Internal or external Ethernet PHY?
590  if(interface->phyDriver != NULL)
591  {
592  //Handle events
593  interface->phyDriver->eventHandler(interface);
594  }
595  else if(interface->switchDriver != NULL)
596  {
597  //Handle events
598  interface->switchDriver->eventHandler(interface);
599  }
600  else
601  {
602  //Read PHY interrupt status register
603  status = tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_MISR1);
604 
605  //Check whether the link state has changed?
606  if((status & EPHY_MISR1_LINKSTAT) != 0)
607  {
608  //Read BMSR register
609  status = tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_BMSR);
610 
611  //Check whether the link is up
612  if((status & EPHY_BMSR_LINKSTAT) != 0)
613  {
614  //Read PHY status register
615  status = tm4c129EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_STS);
616 
617  //Check current speed
618  if((status & EPHY_STS_SPEED) != 0)
619  {
620  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
621  }
622  else
623  {
624  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
625  }
626 
627  //Check duplex mode
628  if((status & EPHY_STS_DUPLEX) != 0)
629  {
630  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
631  }
632  else
633  {
634  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
635  }
636 
637  //Update link state
638  interface->linkState = TRUE;
639 
640  //Adjust MAC configuration parameters for proper operation
641  tm4c129EthUpdateMacConfig(interface);
642  }
643  else
644  {
645  //Update link state
646  interface->linkState = FALSE;
647  }
648 
649  //Process link state change event
650  nicNotifyLinkChange(interface);
651  }
652  }
653  }
654 
655  //Packet received?
656  if((EMAC0_DMARIS_R & EMAC_DMARIS_RI) != 0)
657  {
658  //Clear interrupt flag
659  EMAC0_DMARIS_R = EMAC_DMARIS_RI;
660 
661  //Process all pending packets
662  do
663  {
664  //Read incoming packet
665  error = tm4c129EthReceivePacket(interface);
666 
667  //No more data in the receive buffer?
668  } while(error != ERROR_BUFFER_EMPTY);
669  }
670 
671  //Re-enable DMA interrupts
672  EMAC0_DMAIM_R = EMAC_DMAIM_NIE | EMAC_DMAIM_RIE | EMAC_DMAIM_TIE;
673  //Re-enable PHY interrupts
674  EMAC0_EPHYIM_R = EMAC_EPHYIM_INT;
675 }
676 
677 
678 /**
679  * @brief Send a packet
680  * @param[in] interface Underlying network interface
681  * @param[in] buffer Multi-part buffer containing the data to send
682  * @param[in] offset Offset to the first data byte
683  * @param[in] ancillary Additional options passed to the stack along with
684  * the packet
685  * @return Error code
686  **/
687 
689  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
690 {
691  size_t length;
692 
693  //Retrieve the length of the packet
694  length = netBufferGetLength(buffer) - offset;
695 
696  //Check the frame length
698  {
699  //The transmitter can accept another packet
700  osSetEvent(&interface->nicTxEvent);
701  //Report an error
702  return ERROR_INVALID_LENGTH;
703  }
704 
705  //Make sure the current buffer is available for writing
706  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) != 0)
707  {
708  return ERROR_FAILURE;
709  }
710 
711  //Copy user data to the transmit buffer
712  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
713 
714  //Write the number of bytes to send
715  txCurDmaDesc->tdes1 = length & EMAC_TDES1_TBS1;
716  //Set LS and FS flags as the data fits in a single buffer
717  txCurDmaDesc->tdes0 |= EMAC_TDES0_LS | EMAC_TDES0_FS;
718  //Give the ownership of the descriptor to the DMA
719  txCurDmaDesc->tdes0 |= EMAC_TDES0_OWN;
720 
721  //Clear TU flag to resume processing
722  EMAC0_DMARIS_R = EMAC_DMARIS_TU;
723  //Instruct the DMA to poll the transmit descriptor list
724  EMAC0_TXPOLLD_R = 0;
725 
726  //Point to the next descriptor in the list
727  txCurDmaDesc = (Tm4c129TxDmaDesc *) txCurDmaDesc->tdes3;
728 
729  //Check whether the next buffer is available for writing
730  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
731  {
732  //The transmitter can accept another packet
733  osSetEvent(&interface->nicTxEvent);
734  }
735 
736  //Data successfully written
737  return NO_ERROR;
738 }
739 
740 
741 /**
742  * @brief Receive a packet
743  * @param[in] interface Underlying network interface
744  * @return Error code
745  **/
746 
748 {
749  error_t error;
750  size_t n;
751  NetRxAncillary ancillary;
752 
753  //Current buffer available for reading?
754  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_OWN) == 0)
755  {
756  //FS and LS flags should be set
757  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_FS) != 0 &&
758  (rxCurDmaDesc->rdes0 & EMAC_RDES0_LS) != 0)
759  {
760  //Make sure no error occurred
761  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_ES) == 0)
762  {
763  //Retrieve the length of the frame
764  n = (rxCurDmaDesc->rdes0 & EMAC_RDES0_FL) >> 16;
765  //Limit the number of data to read
767 
768  //Additional options can be passed to the stack along with the packet
769  ancillary = NET_DEFAULT_RX_ANCILLARY;
770 
771  //Pass the packet to the upper layer
772  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
773  &ancillary);
774 
775  //Valid packet received
776  error = NO_ERROR;
777  }
778  else
779  {
780  //The received packet contains an error
781  error = ERROR_INVALID_PACKET;
782  }
783  }
784  else
785  {
786  //The packet is not valid
787  error = ERROR_INVALID_PACKET;
788  }
789 
790  //Give the ownership of the descriptor back to the DMA
791  rxCurDmaDesc->rdes0 = EMAC_RDES0_OWN;
792  //Point to the next descriptor in the list
793  rxCurDmaDesc = (Tm4c129RxDmaDesc *) rxCurDmaDesc->rdes3;
794  }
795  else
796  {
797  //No more data in the receive buffer
798  error = ERROR_BUFFER_EMPTY;
799  }
800 
801  //Clear RU flag to resume processing
802  EMAC0_DMARIS_R = EMAC_DMARIS_RU;
803  //Instruct the DMA to poll the receive descriptor list
804  EMAC0_RXPOLLD_R = 0;
805 
806  //Return status code
807  return error;
808 }
809 
810 
811 /**
812  * @brief Configure MAC address filtering
813  * @param[in] interface Underlying network interface
814  * @return Error code
815  **/
816 
818 {
819  uint_t i;
820  uint_t j;
821  uint_t k;
822  uint32_t crc;
823  uint32_t hashTable[2];
824  MacAddr unicastMacAddr[3];
825  MacFilterEntry *entry;
826 
827  //Debug message
828  TRACE_DEBUG("Updating MAC filter...\r\n");
829 
830  //Set the MAC address of the station
831  EMAC0_ADDR0L_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
832  EMAC0_ADDR0H_R = interface->macAddr.w[2];
833 
834  //The MAC supports 3 additional addresses for unicast perfect filtering
835  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
836  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
837  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
838 
839  //The hash table is used for multicast address filtering
840  hashTable[0] = 0;
841  hashTable[1] = 0;
842 
843  //The MAC address filter contains the list of MAC addresses to accept
844  //when receiving an Ethernet frame
845  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
846  {
847  //Point to the current entry
848  entry = &interface->macAddrFilter[i];
849 
850  //Valid entry?
851  if(entry->refCount > 0)
852  {
853  //Multicast address?
854  if(macIsMulticastAddr(&entry->addr))
855  {
856  //Compute CRC over the current MAC address
857  crc = tm4c129EthCalcCrc(&entry->addr, sizeof(MacAddr));
858 
859  //The upper 6 bits in the CRC register are used to index the
860  //contents of the hash table
861  k = (crc >> 26) & 0x3F;
862 
863  //Update hash table contents
864  hashTable[k / 32] |= (1 << (k % 32));
865  }
866  else
867  {
868  //Up to 3 additional MAC addresses can be specified
869  if(j < 3)
870  {
871  //Save the unicast address
872  unicastMacAddr[j++] = entry->addr;
873  }
874  }
875  }
876  }
877 
878  //Configure the first unicast address filter
879  if(j >= 1)
880  {
881  //When the AE bit is set, the entry is used for perfect filtering
882  EMAC0_ADDR1L_R = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
883  EMAC0_ADDR1H_R = unicastMacAddr[0].w[2] | EMAC_ADDR1H_AE;
884  }
885  else
886  {
887  //When the AE bit is cleared, the entry is ignored
888  EMAC0_ADDR1L_R = 0;
889  EMAC0_ADDR1H_R = 0;
890  }
891 
892  //Configure the second unicast address filter
893  if(j >= 2)
894  {
895  //When the AE bit is set, the entry is used for perfect filtering
896  EMAC0_ADDR2L_R = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
897  EMAC0_ADDR2H_R = unicastMacAddr[1].w[2] | EMAC_ADDR2H_AE;
898  }
899  else
900  {
901  //When the AE bit is cleared, the entry is ignored
902  EMAC0_ADDR2L_R = 0;
903  EMAC0_ADDR2H_R = 0;
904  }
905 
906  //Configure the third unicast address filter
907  if(j >= 3)
908  {
909  //When the AE bit is set, the entry is used for perfect filtering
910  EMAC0_ADDR3L_R = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
911  EMAC0_ADDR3H_R = unicastMacAddr[2].w[2] | EMAC_ADDR3H_AE;
912  }
913  else
914  {
915  //When the AE bit is cleared, the entry is ignored
916  EMAC0_ADDR3L_R = 0;
917  EMAC0_ADDR3H_R = 0;
918  }
919 
920  //Configure the multicast hash table
921  EMAC0_HASHTBLL_R = hashTable[0];
922  EMAC0_HASHTBLH_R = hashTable[1];
923 
924  //Debug message
925  TRACE_DEBUG(" HASHTBLL = %08" PRIX32 "\r\n", EMAC0_HASHTBLL_R);
926  TRACE_DEBUG(" HASHTBLH = %08" PRIX32 "\r\n", EMAC0_HASHTBLH_R);
927 
928  //Successful processing
929  return NO_ERROR;
930 }
931 
932 
933 /**
934  * @brief Adjust MAC configuration parameters for proper operation
935  * @param[in] interface Underlying network interface
936  * @return Error code
937  **/
938 
940 {
941  uint32_t config;
942 
943  //Read current MAC configuration
944  config = EMAC0_CFG_R;
945 
946  //10BASE-T or 100BASE-TX operation mode?
947  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
948  {
949  config |= EMAC_CFG_FES;
950  }
951  else
952  {
953  config &= ~EMAC_CFG_FES;
954  }
955 
956  //Half-duplex or full-duplex mode?
957  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
958  {
959  config |= EMAC_CFG_DUPM;
960  }
961  else
962  {
963  config &= ~EMAC_CFG_DUPM;
964  }
965 
966  //Update MAC configuration register
967  EMAC0_CFG_R = config;
968 
969  //Successful processing
970  return NO_ERROR;
971 }
972 
973 
974 /**
975  * @brief Write PHY register
976  * @param[in] opcode Access type (2 bits)
977  * @param[in] phyAddr PHY address (5 bits)
978  * @param[in] regAddr Register address (5 bits)
979  * @param[in] data Register value
980  **/
981 
982 void tm4c129EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
983  uint8_t regAddr, uint16_t data)
984 {
985  uint32_t temp;
986 
987  //Valid opcode?
988  if(opcode == SMI_OPCODE_WRITE)
989  {
990  //Take care not to alter MDC clock configuration
991  temp = EMAC0_MIIADDR_R & EMAC_MIIADDR_CR_M;
992  //Set up a write operation
993  temp |= EMAC_MIIADDR_MIIW | EMAC_MIIADDR_MIIB;
994  //PHY address
995  temp |= (phyAddr << EMAC_MIIADDR_PLA_S) & EMAC_MIIADDR_PLA_M;
996  //Register address
997  temp |= (regAddr << EMAC_MIIADDR_MII_S) & EMAC_MIIADDR_MII_M;
998 
999  //Data to be written in the PHY register
1000  EMAC0_MIIDATA_R = data & EMAC_MIIDATA_DATA_M;
1001 
1002  //Start a write operation
1003  EMAC0_MIIADDR_R = temp;
1004  //Wait for the write to complete
1005  while((EMAC0_MIIADDR_R & EMAC_MIIADDR_MIIB) != 0)
1006  {
1007  }
1008  }
1009  else
1010  {
1011  //The MAC peripheral only supports standard Clause 22 opcodes
1012  }
1013 }
1014 
1015 
1016 /**
1017  * @brief Read PHY register
1018  * @param[in] opcode Access type (2 bits)
1019  * @param[in] phyAddr PHY address (5 bits)
1020  * @param[in] regAddr Register address (5 bits)
1021  * @return Register value
1022  **/
1023 
1024 uint16_t tm4c129EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1025  uint8_t regAddr)
1026 {
1027  uint16_t data;
1028  uint32_t temp;
1029 
1030  //Valid opcode?
1031  if(opcode == SMI_OPCODE_READ)
1032  {
1033  //Take care not to alter MDC clock configuration
1034  temp = EMAC0_MIIADDR_R & EMAC_MIIADDR_CR_M;
1035  //Set up a read operation
1036  temp |= EMAC_MIIADDR_MIIB;
1037  //PHY address
1038  temp |= (phyAddr << EMAC_MIIADDR_PLA_S) & EMAC_MIIADDR_PLA_M;
1039  //Register address
1040  temp |= (regAddr << EMAC_MIIADDR_MII_S) & EMAC_MIIADDR_MII_M;
1041 
1042  //Start a read operation
1043  EMAC0_MIIADDR_R = temp;
1044  //Wait for the read to complete
1045  while((EMAC0_MIIADDR_R & EMAC_MIIADDR_MIIB) != 0)
1046  {
1047  }
1048 
1049  //Get register value
1050  data = EMAC0_MIIDATA_R & EMAC_MIIDATA_DATA_M;
1051  }
1052  else
1053  {
1054  //The MAC peripheral only supports standard Clause 22 opcodes
1055  data = 0;
1056  }
1057 
1058  //Return the value of the PHY register
1059  return data;
1060 }
1061 
1062 
1063 /**
1064  * @brief Dump PHY registers for debugging purpose
1065  **/
1066 
1068 {
1069  uint8_t i;
1070 
1071  //Loop through PHY registers
1072  for(i = 0; i < 32; i++)
1073  {
1074  //Display current PHY register
1075  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1077  }
1078 
1079  //Terminate with a line feed
1080  TRACE_DEBUG("\r\n");
1081 }
1082 
1083 
1084 /**
1085  * @brief CRC calculation
1086  * @param[in] data Pointer to the data over which to calculate the CRC
1087  * @param[in] length Number of bytes to process
1088  * @return Resulting CRC value
1089  **/
1090 
1091 uint32_t tm4c129EthCalcCrc(const void *data, size_t length)
1092 {
1093  uint_t i;
1094  uint_t j;
1095  uint32_t crc;
1096  const uint8_t *p;
1097 
1098  //Point to the data over which to calculate the CRC
1099  p = (uint8_t *) data;
1100  //CRC preset value
1101  crc = 0xFFFFFFFF;
1102 
1103  //Loop through data
1104  for(i = 0; i < length; i++)
1105  {
1106  //The message is processed bit by bit
1107  for(j = 0; j < 8; j++)
1108  {
1109  //Update CRC value
1110  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1111  {
1112  crc = (crc << 1) ^ 0x04C11DB7;
1113  }
1114  else
1115  {
1116  crc = crc << 1;
1117  }
1118  }
1119  }
1120 
1121  //Return CRC value
1122  return ~crc;
1123 }
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:559
#define EMAC_RDES1_RBS1
#define EMAC0_EPHYMISC_R
uint8_t opcode
Definition: dns_common.h:188
int bool_t
Definition: compiler_port.h:53
error_t tm4c129EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define netEvent
Definition: net_legacy.h:196
@ 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:222
#define EMAC0_HASHTBLH_R
#define TM4C129_ETH_RX_BUFFER_COUNT
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
#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:392
#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:104
@ 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:140
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:263
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
#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:95
uint8_t length
Definition: tcp.h:368
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:195
#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:107
#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:262
#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:50
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:53
@ 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