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