tms570_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file tms570_eth_driver.c
3  * @brief TMS570 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 //Platform-specific dependencies
35 #if defined(_TMS570LC43x_)
36  #include "hl_hw_reg_access.h"
37  #include "hl_hw_emac.h"
38  #include "hl_hw_emac_ctrl.h"
39  #include "hl_hw_mdio.h"
40  #include "hl_gio.h"
41  #include "hl_sys_vim.h"
42 #else
43  #include "hw_reg_access.h"
44  #include "hw_emac.h"
45  #include "hw_emac_ctrl.h"
46  #include "hw_mdio.h"
47  #include "gio.h"
48  #include "sys_vim.h"
49 #endif
50 
51 //Dependencies
52 #include "core/net.h"
54 #include "debug.h"
55 
56 //MDIO input clock frequency
57 #define MDIO_INPUT_CLK 75000000
58 //MDIO output clock frequency
59 #define MDIO_OUTPUT_CLK 1000000
60 
61 //Byte-swapped read/write accesses to CPPI memory?
62 #if defined(_TMS570LC43x_)
63  #define CPPI_SWAP(x) swapInt32((uint32_t) (x))
64 #else
65  #define CPPI_SWAP(x) ((uint32_t) (x))
66 #endif
67 
68 //Underlying network interface
69 static NetInterface *nicDriverInterface;
70 
71 //IAR EWARM compiler?
72 #if defined(__ICCARM__)
73 
74 //Transmit buffer
75 #pragma data_alignment = 4
76 #pragma location = TMS570_ETH_RAM_SECTION
78 //Receive buffer
79 #pragma data_alignment = 4
80 #pragma location = TMS570_ETH_RAM_SECTION
82 //Transmit buffer descriptors
83 #pragma data_alignment = 4
84 #pragma location = TMS570_ETH_RAM_CPPI_SECTION
86 //Receive buffer descriptors
87 #pragma data_alignment = 4
88 #pragma location = TMS570_ETH_RAM_CPPI_SECTION
90 
91 //GCC compiler?
92 #else
93 
94 //Transmit buffer
96  __attribute__((aligned(4), __section__(TMS570_ETH_RAM_SECTION)));
97 //Receive buffer
99  __attribute__((aligned(4), __section__(TMS570_ETH_RAM_SECTION)));
100 //Transmit buffer descriptors
102  __attribute__((aligned(4), __section__(TMS570_ETH_RAM_CPPI_SECTION)));
103 //Receive buffer descriptors
105  __attribute__((aligned(4), __section__(TMS570_ETH_RAM_CPPI_SECTION)));
106 
107 #endif
108 
109 //Pointer to the current TX buffer descriptor
110 static Tms570TxBufferDesc *txCurBufferDesc;
111 //Pointer to the current RX buffer descriptor
112 static Tms570RxBufferDesc *rxCurBufferDesc;
113 
114 
115 /**
116  * @brief TMS570 Ethernet MAC driver
117  **/
118 
120 {
122  ETH_MTU,
133  FALSE,
134  TRUE,
135  TRUE,
136  FALSE
137 };
138 
139 
140 /**
141  * @brief TMS570 Ethernet MAC initialization
142  * @param[in] interface Underlying network interface
143  * @return Error code
144  **/
145 
147 {
148  error_t error;
149  uint_t channel;
150  uint32_t temp;
151 
152  //Debug message
153  TRACE_INFO("Initializing TMS570 Ethernet MAC...\r\n");
154 
155  //Save underlying network interface
156  nicDriverInterface = interface;
157 
158  //Select the interface mode (MII/RMII) and configure pin muxing
159  tms570EthInitGpio(interface);
160 
161  //Reset the EMAC control module
162  EMAC_CTRL_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET;
163  //Wait for the reset to complete
164  while((EMAC_CTRL_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0)
165  {
166  }
167 
168  //Reset the EMAC module
169  EMAC_SOFTRESET_R = EMAC_SOFTRESET_SOFTRESET;
170  //Wait for the reset to complete
171  while((EMAC_SOFTRESET_R & EMAC_SOFTRESET_SOFTRESET) != 0)
172  {
173  }
174 
175  //Calculate the MDC clock divider to be used
176  temp = (MDIO_INPUT_CLK / MDIO_OUTPUT_CLK) - 1;
177 
178  //Initialize MDIO interface
179  MDIO_CONTROL_R = MDIO_CONTROL_ENABLE |
180  MDIO_CONTROL_FAULTENB | (temp & MDIO_CONTROL_CLKDIV);
181 
182  //Valid Ethernet PHY or switch driver?
183  if(interface->phyDriver != NULL)
184  {
185  //Ethernet PHY initialization
186  error = interface->phyDriver->init(interface);
187  }
188  else if(interface->switchDriver != NULL)
189  {
190  //Ethernet switch initialization
191  error = interface->switchDriver->init(interface);
192  }
193  else
194  {
195  //The interface is not properly configured
196  error = ERROR_FAILURE;
197  }
198 
199  //Any error to report?
200  if(error)
201  {
202  return error;
203  }
204 
205  //Clear the control registers
206  EMAC_MACCONTROL_R = 0;
207  EMAC_RXCONTROL_R = 0;
208  EMAC_TXCONTROL_R = 0;
209 
210  //Initialize all 16 header descriptor pointer registers to 0
211  for(channel = EMAC_CH0; channel <= EMAC_CH7; channel++)
212  {
213  //TX head descriptor pointer
214  EMAC_TXHDP_R(channel) = 0;
215  //TX completion pointer
216  EMAC_TXCP_R(channel) = 0;
217  //RX head descriptor pointer
218  EMAC_RXHDP_R(channel) = 0;
219  //RX completion pointer
220  EMAC_RXCP_R(channel) = 0;
221  }
222 
223  //Set the upper 32 bits of the source MAC address
224  EMAC_MACSRCADDRHI_R = interface->macAddr.b[0] |
225  (interface->macAddr.b[1] << 8) |
226  (interface->macAddr.b[2] << 16) |
227  (interface->macAddr.b[3] << 24);
228 
229  //Set the lower 16 bits of the source MAC address
230  EMAC_MACSRCADDRLO_R = interface->macAddr.b[4] |
231  (interface->macAddr.b[5] << 8);
232 
233  //Write the channel number to the MAC index register
235 
236  //Set the upper 32 bits of the destination MAC address
237  EMAC_MACADDRHI_R = interface->macAddr.b[0] |
238  (interface->macAddr.b[1] << 8) |
239  (interface->macAddr.b[2] << 16) |
240  (interface->macAddr.b[3] << 24);
241 
242  //Set the lower 16 bits of the destination MAC address
243  temp = interface->macAddr.b[4] |
244  (interface->macAddr.b[5] << 8);
245 
246  //Use the current MAC address to match incoming packet addresses
247  EMAC_MACADDRLO_R = EMAC_MACADDRLO_VALID | EMAC_MACADDRLO_MATCHFILT |
248  (EMAC_CH0 << EMAC_MACADDRLO_CHANNEL_SHIFT) | temp;
249 
250  //Be sure to program all eight MAC address registers, whether the
251  //receive channel is to be enabled or not
252  for(channel = EMAC_CH1; channel <= EMAC_CH7; channel++)
253  {
254  //Write the channel number to the MAC index register
255  EMAC_MACINDEX_R = channel;
256  //The MAC address is not valid
257  EMAC_MACADDRLO_R = (channel << EMAC_MACADDRLO_CHANNEL_SHIFT);
258  }
259 
260  //Clear the MAC address hash registers
261  EMAC_MACHASH1_R = 0;
262  EMAC_MACHASH2_R = 0;
263 
264  //The RX buffer offset must be initialized to zero
266 
267  //Clear all unicast channels
268  EMAC_RXUNICASTCLEAR_R = 0xFF;
269 
270  //Accept unicast frames
271  EMAC_RXUNICASTSET_R |= (1 << EMAC_CH0);
272 
273  //Received CRC is transferred to memory for all channels
274  EMAC_RXMBPENABLE_R = EMAC_RXMBPENABLE_RXPASSCRC;
275 
276  //Accept broadcast frames
277  EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXBROADEN |
278  (EMAC_CH0 << EMAC_RXMBPENABLE_RXBROADCH_SHIFT);
279 
280  //Accept hash matching multicast frames
281  EMAC_RXMBPENABLE_R |= EMAC_RXMBPENABLE_RXMULTEN |
282  (EMAC_CH0 << EMAC_RXMBPENABLE_RXMULTCH_SHIFT);
283 
284  //Register TX interrupt handler
286  (t_isrFuncPTR) tms570EthTxIrqHandler);
287 
288  //Register RX interrupt handler
290  (t_isrFuncPTR) tms570EthRxIrqHandler);
291 
292  //Clear all unused channel interrupt bits
293  EMAC_TXINTMASKCLEAR_R = 0xFF;
294  EMAC_RXINTMASKCLEAR_R = 0xFF;
295 
296  //Enable the receive and transmit channel interrupt bits
297  EMAC_TXINTMASKSET_R = (1 << EMAC_CH0);
298  EMAC_RXINTMASKSET_R = (1 << EMAC_CH0);
299 
300  //Configure TX and RX buffer descriptors
301  tms570EthInitBufferDesc(interface);
302 
303  //Write the RX DMA head descriptor pointer
304  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
305 
306  //Enable the receive and transmit DMA controllers
307  EMAC_TXCONTROL_R = EMAC_TXCONTROL_TXEN;
308  EMAC_RXCONTROL_R = EMAC_RXCONTROL_RXEN;
309 
310  //Enable TX and RX
311  EMAC_MACCONTROL_R = EMAC_MACCONTROL_GMIIEN;
312 
313  //Enable TX and RX completion interrupts
316 
317  //Accept any packets from the upper layer
318  osSetEvent(&interface->nicTxEvent);
319 
320  //Successful initialization
321  return NO_ERROR;
322 }
323 
324 
325 /**
326  * @brief GPIO configuration
327  * @param[in] interface Underlying network interface
328  **/
329 
330 __weak_func void tms570EthInitGpio(NetInterface *interface)
331 {
332 //LAUNCHXL2-570LC43 evaluation board?
333 #if defined(USE_LAUNCHXL2_570LC43)
334  //Configure PHY_INT (PA_3) as an input
335  gioPORTA->DIR &= ~(1 << 3);
336  gioPORTA->PSL |= (1 << 3);
337  gioPORTA->PULDIS &= ~(1 << 3);
338 
339  //Configure PHY_RST (PA_4) as an output
340  gioPORTA->DIR |= (1 << 4);
341  gioPORTA->PDR &= ~(1 << 4);
342 
343  //Reset PHY transceiver
344  gioPORTA->DCLR = (1 << 4);
345  sleep(10);
346  gioPORTA->DSET = (1 << 4);
347  sleep(10);
348 #endif
349 }
350 
351 
352 /**
353  * @brief Initialize buffer descriptor lists
354  * @param[in] interface Underlying network interface
355  **/
356 
358 {
359  uint_t i;
360  uint_t nextIndex;
361  uint_t prevIndex;
362 
363  //Initialize TX buffer descriptor list
364  for(i = 0; i < TMS570_ETH_TX_BUFFER_COUNT; i++)
365  {
366  //Index of the next buffer
367  nextIndex = (i + 1) % TMS570_ETH_TX_BUFFER_COUNT;
368  //Index of the previous buffer
370 
371  //Next descriptor pointer
372  txBufferDesc[i].word0 = CPPI_SWAP(NULL);
373  //Buffer pointer
374  txBufferDesc[i].word1 = CPPI_SWAP(txBuffer[i]);
375  //Buffer offset and buffer length
376  txBufferDesc[i].word2 = CPPI_SWAP(0);
377  //Status flags and packet length
378  txBufferDesc[i].word3 = CPPI_SWAP(0);
379 
380  //Form a doubly linked list
381  txBufferDesc[i].next = &txBufferDesc[nextIndex];
382  txBufferDesc[i].prev = &txBufferDesc[prevIndex];
383  }
384 
385  //Point to the very first descriptor
386  txCurBufferDesc = &txBufferDesc[0];
387 
388  //Mark the end of the queue
389  txCurBufferDesc->prev->word3 = CPPI_SWAP(EMAC_TX_WORD3_SOP |
391 
392  //Initialize RX buffer descriptor list
393  for(i = 0; i < TMS570_ETH_RX_BUFFER_COUNT; i++)
394  {
395  //Index of the next buffer
396  nextIndex = (i + 1) % TMS570_ETH_RX_BUFFER_COUNT;
397  //Index of the previous buffer
399 
400  //Next descriptor pointer
401  rxBufferDesc[i].word0 = CPPI_SWAP(&rxBufferDesc[nextIndex]);
402  //Buffer pointer
403  rxBufferDesc[i].word1 = CPPI_SWAP(rxBuffer[i]);
404  //Buffer offset and buffer length
405  rxBufferDesc[i].word2 = CPPI_SWAP(TMS570_ETH_RX_BUFFER_SIZE);
406  //Status flags and packet length
407  rxBufferDesc[i].word3 = CPPI_SWAP(EMAC_RX_WORD3_OWNER);
408 
409  //Form a doubly linked list
410  rxBufferDesc[i].next = &rxBufferDesc[nextIndex];
411  rxBufferDesc[i].prev = &rxBufferDesc[prevIndex];
412  }
413 
414  //Point to the very first descriptor
415  rxCurBufferDesc = &rxBufferDesc[0];
416 
417  //Mark the end of the queue
418  rxCurBufferDesc->prev->word0 = CPPI_SWAP(NULL);
419 }
420 
421 
422 /**
423  * @brief TMS570 Ethernet MAC timer handler
424  *
425  * This routine is periodically called by the TCP/IP stack to handle periodic
426  * operations such as polling the link state
427  *
428  * @param[in] interface Underlying network interface
429  **/
430 
431 void tms570EthTick(NetInterface *interface)
432 {
433  //Valid Ethernet PHY or switch driver?
434  if(interface->phyDriver != NULL)
435  {
436  //Handle periodic operations
437  interface->phyDriver->tick(interface);
438  }
439  else if(interface->switchDriver != NULL)
440  {
441  //Handle periodic operations
442  interface->switchDriver->tick(interface);
443  }
444  else
445  {
446  //Just for sanity
447  }
448 
449  //Misqueued buffer condition?
450  if(CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_OWNER)
451  {
452  if(EMAC_RXHDP_R(EMAC_CH0) == 0)
453  {
454  //The host acts on the misqueued buffer condition by writing the added
455  //buffer descriptor address to the appropriate RX DMA head descriptor
456  //pointer
457  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
458  }
459  }
460 }
461 
462 
463 /**
464  * @brief Enable interrupts
465  * @param[in] interface Underlying network interface
466  **/
467 
469 {
470  //Enable Ethernet MAC interrupts
471  vimEnableInterrupt(TMS570_ETH_TX_IRQ_CHANNEL, SYS_IRQ);
472  vimEnableInterrupt(TMS570_ETH_RX_IRQ_CHANNEL, SYS_IRQ);
473 
474  //Valid Ethernet PHY or switch driver?
475  if(interface->phyDriver != NULL)
476  {
477  //Enable Ethernet PHY interrupts
478  interface->phyDriver->enableIrq(interface);
479  }
480  else if(interface->switchDriver != NULL)
481  {
482  //Enable Ethernet switch interrupts
483  interface->switchDriver->enableIrq(interface);
484  }
485  else
486  {
487  //Just for sanity
488  }
489 }
490 
491 
492 /**
493  * @brief Disable interrupts
494  * @param[in] interface Underlying network interface
495  **/
496 
498 {
499  //Disable Ethernet MAC interrupts
500  vimDisableInterrupt(TMS570_ETH_TX_IRQ_CHANNEL);
501  vimDisableInterrupt(TMS570_ETH_RX_IRQ_CHANNEL);
502 
503  //Valid Ethernet PHY or switch driver?
504  if(interface->phyDriver != NULL)
505  {
506  //Disable Ethernet PHY interrupts
507  interface->phyDriver->disableIrq(interface);
508  }
509  else if(interface->switchDriver != NULL)
510  {
511  //Disable Ethernet switch interrupts
512  interface->switchDriver->disableIrq(interface);
513  }
514  else
515  {
516  //Just for sanity
517  }
518 }
519 
520 
521 /**
522  * @brief Ethernet MAC transmit interrupt
523  **/
524 
525 #if defined(__ICCARM__)
526  __irq __arm
527 #else
528  #pragma CODE_STATE(tms570EthTxIrqHandler, 32)
529  #pragma INTERRUPT(tms570EthTxIrqHandler, IRQ)
530 #endif
531 
533 {
534  bool_t flag;
535  uint32_t status;
536  uint32_t temp;
538 
539  //Interrupt service routine prologue
540  osEnterIsr();
541 
542  //This flag will be set if a higher priority task must be woken
543  flag = FALSE;
544 
545  //Read the C0TXSTAT register to determine which channels caused the interrupt
546  status = EMAC_CTRL_C0TXSTAT_R;
547 
548  //Packet transmitted on channel 0?
549  if(status & (1 << EMAC_CH0))
550  {
551  //Point to the buffer descriptor
553 
554  //Read the status flags
555  temp = CPPI_SWAP(p->word3) & (EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
557 
558  //Misqueued buffer condition?
560  {
561  //Check whether the next descriptor pointer is non-zero
562  if(CPPI_SWAP(p->word0) != 0)
563  {
564  //The host corrects the misqueued buffer condition by writing the
565  //misqueued packet’s buffer descriptor address to the appropriate
566  //TX DMA head descriptor pointer
567  EMAC_TXHDP_R(EMAC_CH0) = CPPI_SWAP(p->word0);
568  }
569  }
570 
571  //Write the TX completion pointer
572  EMAC_TXCP_R(EMAC_CH0) = (uint32_t) p;
573 
574  //Check whether the TX buffer is available for writing
575  if((CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) == 0)
576  {
577  //Notify the TCP/IP stack that the transmitter is ready to send
578  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
579  }
580  }
581 
582  //Write the DMA end of interrupt vector
584 
585  //Interrupt service routine epilogue
586  osExitIsr(flag);
587 }
588 
589 
590 /**
591  * @brief Ethernet MAC receive interrupt
592  **/
593 
594 #if defined(__ICCARM__)
595  __irq __arm
596 #else
597  #pragma CODE_STATE(tms570EthRxIrqHandler, 32)
598  #pragma INTERRUPT(tms570EthRxIrqHandler, IRQ)
599 #endif
600 
602 {
603  bool_t flag;
604  uint32_t status;
605 
606  //Interrupt service routine prologue
607  osEnterIsr();
608 
609  //This flag will be set if a higher priority task must be woken
610  flag = FALSE;
611 
612  //Read the C0RXSTAT register to determine which channels caused the interrupt
613  status = EMAC_CTRL_C0RXSTAT_R;
614 
615  //Packet received on channel 0?
616  if(status & (1 << EMAC_CH0))
617  {
618  //Disable RX interrupts
620 
621  //Set event flag
622  nicDriverInterface->nicEvent = TRUE;
623  //Notify the TCP/IP stack of the event
624  flag |= osSetEventFromIsr(&netEvent);
625  }
626 
627  //Write the DMA end of interrupt vector
629 
630  //Interrupt service routine epilogue
631  osExitIsr(flag);
632 }
633 
634 
635 /**
636  * @brief TMS570 Ethernet MAC event handler
637  * @param[in] interface Underlying network interface
638  **/
639 
641 {
642  error_t error;
643 
644  //Process all pending packets
645  do
646  {
647  //Read incoming packet
648  error = tms570EthReceivePacket(interface);
649 
650  //No more data in the receive buffer?
651  } while(error != ERROR_BUFFER_EMPTY);
652 
653  //Re-enable RX interrupts
655 }
656 
657 
658 /**
659  * @brief Send a packet
660  * @param[in] interface Underlying network interface
661  * @param[in] buffer Multi-part buffer containing the data to send
662  * @param[in] offset Offset to the first data byte
663  * @param[in] ancillary Additional options passed to the stack along with
664  * the packet
665  * @return Error code
666  **/
667 
669  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
670 {
671  size_t length;
672  uint32_t temp;
673 
674  //Retrieve the length of the packet
675  length = netBufferGetLength(buffer) - offset;
676 
677  //Check the frame length
679  {
680  //The transmitter can accept another packet
681  osSetEvent(&interface->nicTxEvent);
682  //Report an error
683  return ERROR_INVALID_LENGTH;
684  }
685 
686  //Make sure the current buffer is available for writing
687  if(CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER)
688  {
689  return ERROR_FAILURE;
690  }
691 
692  //Mark the end of the queue with a NULL pointer
693  txCurBufferDesc->word0 = CPPI_SWAP(NULL);
694 
695  //Copy user data to the transmit buffer
696  netBufferRead((uint8_t *) CPPI_SWAP(txCurBufferDesc->word1), buffer,
697  offset, length);
698 
699  //Set the length of the buffer
700  txCurBufferDesc->word2 = CPPI_SWAP(length & EMAC_TX_WORD2_BUFFER_LENGTH);
701 
702  //Give the ownership of the descriptor to the DMA
703  txCurBufferDesc->word3 = CPPI_SWAP(EMAC_TX_WORD3_SOP | EMAC_TX_WORD3_EOP |
705 
706  //Link the current descriptor to the previous descriptor
707  txCurBufferDesc->prev->word0 = CPPI_SWAP(txCurBufferDesc);
708 
709  //Read the status flags of the previous descriptor
710  temp = CPPI_SWAP(txCurBufferDesc->prev->word3) & (EMAC_TX_WORD3_SOP |
712 
713  //Misqueued buffer condition?
715  {
716  //Clear the misqueued buffer condition
717  txCurBufferDesc->prev->word3 = CPPI_SWAP(0);
718 
719  //The host corrects the misqueued buffer condition by writing the
720  //misqueued packet’s buffer descriptor address to the appropriate
721  //TX DMA head descriptor pointer
722  EMAC_TXHDP_R(EMAC_CH0) = (uint32_t) txCurBufferDesc;
723  }
724 
725  //Point to the next descriptor in the list
726  txCurBufferDesc = txCurBufferDesc->next;
727 
728  //Check whether the next buffer is available for writing
729  if((CPPI_SWAP(txCurBufferDesc->word3) & EMAC_TX_WORD3_OWNER) == 0)
730  {
731  //The transmitter can accept another packet
732  osSetEvent(&interface->nicTxEvent);
733  }
734 
735  //Data successfully written
736  return NO_ERROR;
737 }
738 
739 
740 /**
741  * @brief Receive a packet
742  * @param[in] interface Underlying network interface
743  * @return Error code
744  **/
745 
747 {
748  static uint32_t buffer[TMS570_ETH_RX_BUFFER_SIZE / 4];
749  error_t error;
750  size_t n;
751  uint32_t temp;
752 
753  //Current buffer available for reading?
754  if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_OWNER) == 0)
755  {
756  //SOP and EOP flags should be set
757  if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_SOP) != 0 &&
758  (CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_EOP) != 0)
759  {
760  //Make sure no error occurred
761  if((CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_ERROR_MASK) == 0)
762  {
763  //Retrieve the length of the frame
764  n = CPPI_SWAP(rxCurBufferDesc->word3) & EMAC_RX_WORD3_PACKET_LENGTH;
765  //Limit the number of data to read
767 
768  //Copy data from the receive buffer
769  osMemcpy(buffer, (uint8_t *) CPPI_SWAP(rxCurBufferDesc->word1), n);
770 
771  //Valid packet received
772  error = NO_ERROR;
773  }
774  else
775  {
776  //The received packet contains an error
777  error = ERROR_INVALID_PACKET;
778  }
779  }
780  else
781  {
782  //The packet is not valid
783  error = ERROR_INVALID_PACKET;
784  }
785 
786  //Mark the end of the queue with a NULL pointer
787  rxCurBufferDesc->word0 = CPPI_SWAP(NULL);
788  //Restore the length of the buffer
789  rxCurBufferDesc->word2 = CPPI_SWAP(TMS570_ETH_RX_BUFFER_SIZE);
790  //Give the ownership of the descriptor back to the DMA
791  rxCurBufferDesc->word3 = CPPI_SWAP(EMAC_RX_WORD3_OWNER);
792 
793  //Link the current descriptor to the previous descriptor
794  rxCurBufferDesc->prev->word0 = CPPI_SWAP(rxCurBufferDesc);
795 
796  //Read the status flags of the previous descriptor
797  temp = CPPI_SWAP(rxCurBufferDesc->prev->word3) & (EMAC_RX_WORD3_SOP |
799 
800  //Misqueued buffer condition?
802  {
803  //The host acts on the misqueued buffer condition by writing the added
804  //buffer descriptor address to the appropriate RX DMA head descriptor
805  //pointer
806  EMAC_RXHDP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
807  }
808 
809  //Write the RX completion pointer
810  EMAC_RXCP_R(EMAC_CH0) = (uint32_t) rxCurBufferDesc;
811 
812  //Point to the next descriptor in the list
813  rxCurBufferDesc = rxCurBufferDesc->next;
814  }
815  else
816  {
817  //No more data in the receive buffer
818  error = ERROR_BUFFER_EMPTY;
819  }
820 
821  //Check whether a valid packet has been received
822  if(!error)
823  {
824  NetRxAncillary ancillary;
825 
826  //Additional options can be passed to the stack along with the packet
827  ancillary = NET_DEFAULT_RX_ANCILLARY;
828 
829  //Pass the packet to the upper layer
830  nicProcessPacket(interface, (uint8_t *) buffer, n, &ancillary);
831  }
832 
833  //Return status code
834  return error;
835 }
836 
837 
838 /**
839  * @brief Configure MAC address filtering
840  * @param[in] interface Underlying network interface
841  * @return Error code
842  **/
843 
845 {
846  uint_t i;
847  uint_t k;
848  uint8_t *p;
849  uint32_t hashTable[2];
850  MacFilterEntry *entry;
851 
852  //Debug message
853  TRACE_DEBUG("Updating MAC filter...\r\n");
854 
855  //Clear hash table
856  hashTable[0] = 0;
857  hashTable[1] = 0;
858 
859  //The MAC address filter contains the list of MAC addresses to accept
860  //when receiving an Ethernet frame
861  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
862  {
863  //Point to the current entry
864  entry = &interface->macAddrFilter[i];
865 
866  //Valid entry?
867  if(entry->refCount > 0)
868  {
869  //Point to the MAC address
870  p = entry->addr.b;
871 
872  //Apply the hash function
873  k = (p[0] >> 2) ^ (p[0] << 4);
874  k ^= (p[1] >> 4) ^ (p[1] << 2);
875  k ^= (p[2] >> 6) ^ p[2];
876  k ^= (p[3] >> 2) ^ (p[3] << 4);
877  k ^= (p[4] >> 4) ^ (p[4] << 2);
878  k ^= (p[5] >> 6) ^ p[5];
879 
880  //The hash value is reduced to a 6-bit index
881  k &= 0x3F;
882 
883  //Update hash table contents
884  hashTable[k / 32] |= (1 << (k % 32));
885  }
886  }
887 
888  //Write the hash table
889  EMAC_MACHASH1_R = hashTable[0];
890  EMAC_MACHASH2_R = hashTable[1];
891 
892  //Debug message
893  TRACE_DEBUG(" MACHASH1 = %08" PRIX32 "\r\n", EMAC_MACHASH1_R);
894  TRACE_DEBUG(" MACHASH2 = %08" PRIX32 "\r\n", EMAC_MACHASH2_R);
895 
896  //Successful processing
897  return NO_ERROR;
898 }
899 
900 
901 /**
902  * @brief Adjust MAC configuration parameters for proper operation
903  * @param[in] interface Underlying network interface
904  * @return Error code
905  **/
906 
908 {
909  uint32_t config;
910 
911  //Read MAC control register
912  config = EMAC_MACCONTROL_R;
913 
914  //100BASE-TX or 10BASE-T operation mode?
915  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
916  {
917  config |= EMAC_MACCONTROL_RMIISPEED;
918  }
919  else
920  {
921  config &= ~EMAC_MACCONTROL_RMIISPEED;
922  }
923 
924  //Half-duplex or full-duplex mode?
925  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
926  {
927  config |= EMAC_MACCONTROL_FULLDUPLEX;
928  }
929  else
930  {
931  config &= ~EMAC_MACCONTROL_FULLDUPLEX;
932  }
933 
934  //Update MAC control register
935  EMAC_MACCONTROL_R = config;
936 
937  //Successful processing
938  return NO_ERROR;
939 }
940 
941 
942 /**
943  * @brief Write PHY register
944  * @param[in] opcode Access type (2 bits)
945  * @param[in] phyAddr PHY address (5 bits)
946  * @param[in] regAddr Register address (5 bits)
947  * @param[in] data Register value
948  **/
949 
950 void tms570EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
951  uint8_t regAddr, uint16_t data)
952 {
953  uint32_t temp;
954 
955  //Valid opcode?
956  if(opcode == SMI_OPCODE_WRITE)
957  {
958  //Set up a write operation
959  temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_WRITE;
960  //PHY address
961  temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
962  //Register address
963  temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
964  //Register value
965  temp |= data & MDIO_USERACCESS0_DATA;
966 
967  //Start a write operation
968  MDIO_USERACCESS0_R = temp;
969  //Wait for the write to complete
970  while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0)
971  {
972  }
973  }
974  else
975  {
976  //The MAC peripheral only supports standard Clause 22 opcodes
977  }
978 }
979 
980 
981 /**
982  * @brief Read 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  * @return Register value
987  **/
988 
989 uint16_t tms570EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
990  uint8_t regAddr)
991 {
992  uint16_t data;
993  uint32_t temp;
994 
995  //Valid opcode?
996  if(opcode == SMI_OPCODE_READ)
997  {
998  //Set up a read operation
999  temp = MDIO_USERACCESS0_GO | MDIO_USERACCESS0_READ;
1000  //PHY address
1001  temp |= (phyAddr << MDIO_USERACCESS0_PHYADR_SHIFT) & MDIO_USERACCESS0_PHYADR;
1002  //Register address
1003  temp |= (regAddr << MDIO_USERACCESS0_REGADR_SHIFT) & MDIO_USERACCESS0_REGADR;
1004 
1005  //Start a read operation
1006  MDIO_USERACCESS0_R = temp;
1007  //Wait for the read to complete
1008  while((MDIO_USERACCESS0_R & MDIO_USERACCESS0_GO) != 0)
1009  {
1010  }
1011 
1012  //Get register value
1013  data = MDIO_USERACCESS0_R & MDIO_USERACCESS0_DATA;
1014  }
1015  else
1016  {
1017  //The MAC peripheral only supports standard Clause 22 opcodes
1018  data = 0;
1019  }
1020 
1021  //Return the value of the PHY register
1022  return data;
1023 }
#define rxBuffer
#define txBuffer
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint8_t opcode
Definition: dns_common.h:188
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
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 EMAC_CTRL_C0RXSTAT_R
#define EMAC_TXCONTROL_R
#define EMAC_TX_WORD3_EOQ
#define EMAC_MACEOIVECTOR_C0TX
#define EMAC_RX_WORD3_SOP
#define EMAC_TX_WORD2_BUFFER_LENGTH
#define EMAC_RXCONTROL_R
#define EMAC_RX_WORD3_PACKET_LENGTH
#define EMAC_RXMBPENABLE_R
#define EMAC_CH7
#define EMAC_RXHDP_R(n)
#define EMAC_RX_WORD3_OWNER
#define EMAC_TX_WORD3_OWNER
#define EMAC_RXINTMASKSET_R
#define MDIO_USERACCESS0_R
#define MDIO_CONTROL_R
#define EMAC_TXHDP_R(n)
#define EMAC_RXBUFFEROFFSET_R
#define EMAC_CH0
#define EMAC_CORE0
#define EMAC_SOFTRESET_R
#define EMAC_TXINTMASKSET_R
#define EMAC_RXUNICASTSET_R
#define EMAC_CTRL_CnRXEN_R(n)
#define EMAC_TX_WORD3_EOP
#define EMAC_RX_WORD3_ERROR_MASK
#define EMAC_CTRL_CnTXEN_R(n)
#define EMAC_MACHASH2_R
#define EMAC_TXINTMASKCLEAR_R
#define EMAC_RX_WORD3_EOP
#define EMAC_MACSRCADDRHI_R
#define EMAC_TX_WORD3_PACKET_LENGTH
#define EMAC_TXCP_R(n)
#define EMAC_MACEOIVECTOR_C0RX
#define EMAC_CTRL_C0TXSTAT_R
#define EMAC_RXINTMASKCLEAR_R
#define EMAC_MACADDRLO_R
#define EMAC_MACINDEX_R
#define EMAC_CH1
#define EMAC_MACADDRHI_R
#define EMAC_MACHASH1_R
#define EMAC_RXUNICASTCLEAR_R
#define EMAC_RXCP_R(n)
#define EMAC_MACEOIVECTOR_R
#define EMAC_CTRL_SOFTRESET_R
#define EMAC_RX_WORD3_EOQ
#define EMAC_TX_WORD3_SOP
#define EMAC_MACSRCADDRLO_R
#define EMAC_MACCONTROL_R
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define sleep(delay)
Definition: os_port.h:301
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osEnterIsr()
#define osExitIsr(flag)
RX buffer descriptor.
struct _Tms570RxBufferDesc * prev
struct _Tms570RxBufferDesc * next
TX buffer descriptor.
struct _Tms570TxBufferDesc * next
struct _Tms570TxBufferDesc * prev
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
__weak_func void tms570EthInitGpio(NetInterface *interface)
GPIO configuration.
error_t tms570EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void tms570EthEventHandler(NetInterface *interface)
TMS570 Ethernet MAC event handler.
error_t tms570EthReceivePacket(NetInterface *interface)
Receive a packet.
error_t tms570EthInit(NetInterface *interface)
TMS570 Ethernet MAC initialization.
error_t tms570EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
uint16_t tms570EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void tms570EthRxIrqHandler(void)
Ethernet MAC receive interrupt.
void tms570EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
void tms570EthTxIrqHandler(void)
Ethernet MAC transmit interrupt.
const NicDriver tms570EthDriver
TMS570 Ethernet MAC driver.
void tms570EthEnableIrq(NetInterface *interface)
Enable interrupts.
void tms570EthTick(NetInterface *interface)
TMS570 Ethernet MAC timer handler.
void tms570EthInitBufferDesc(NetInterface *interface)
Initialize buffer descriptor lists.
#define MDIO_OUTPUT_CLK
#define CPPI_SWAP(x)
#define MDIO_INPUT_CLK
error_t tms570EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void tms570EthDisableIrq(NetInterface *interface)
Disable interrupts.
TMS570 Ethernet MAC driver.
#define TMS570_ETH_TX_BUFFER_SIZE
#define TMS570_ETH_TX_IRQ_CHANNEL
#define TMS570_ETH_RX_IRQ_CHANNEL
#define TMS570_ETH_RAM_SECTION
#define TMS570_ETH_RX_BUFFER_COUNT
#define TMS570_ETH_TX_BUFFER_COUNT
#define TMS570_ETH_RX_BUFFER_SIZE
#define TMS570_ETH_RAM_CPPI_SECTION