adin2111_driver.c
Go to the documentation of this file.
1 /**
2  * @file adin2111_driver.c
3  * @brief ADIN2111 2-port 10Base-T1L Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
37 #include "debug.h"
38 
39 
40 /**
41  * @brief ADIN2111 driver
42  **/
43 
45 {
47  ETH_MTU,
55  NULL,
56  NULL,
57  NULL,
58  FALSE,
59  TRUE,
60  TRUE,
61  FALSE
62 };
63 
64 
65 /**
66  * @brief ADIN2111 Ethernet switch initialization
67  * @param[in] interface Underlying network interface
68  * @return Error code
69  **/
70 
72 {
73  uint_t port;
74  uint32_t value;
75 
76  //Debug message
77  TRACE_INFO("Initializing ADIN2111...\r\n");
78 
79  //Initialize SPI interface
80  interface->spiDriver->init();
81 
82  //Initialize external interrupt line driver
83  if(interface->extIntDriver != NULL)
84  {
85  interface->extIntDriver->init();
86  }
87 
88  //A full chip software reset can be initiated by writing 1 to the SWRESET
89  //field of the RESET register
91 
92  //Wait for the MAC to exit reset
93  do
94  {
95  //To confirm that the MAC has exited reset, read the PHY identification
96  //register
97  value = adin2111ReadReg(interface, ADIN2111_PHYID);
98 
99  //If the reset value of the register can be read, the device has exited
100  //reset and is ready for configuration
103 
104  //Next, the host must read the STATUS0 register and confirm that the RESETC
105  //field is 1
106  do
107  {
108  //Read the status register 0
109  value = adin2111ReadReg(interface, ADIN2111_STATUS0);
110 
111  //Check the value of the RESETC bit
112  } while((value & ADIN2111_STATUS0_RESETC) == 0);
113 
114  //Write 1 to the RESETC field in the STATUS0 register to clear this field
116 
117  //Dump SPI registers for debugging purpose
118  adin2111DumpReg(interface);
119 
120  //Loop through the ports
122  {
123  //Debug message
124  TRACE_DEBUG("Port %u:\r\n", port);
125  //Dump PHY registers for debugging purpose
126  adin2111DumpPhyReg(interface, port);
127  }
128 
129  //Configure MAC address filtering
130  adin2111UpdateMacAddrFilter(interface);
131 
132 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
133  //Configure the SPI protocol engine
137 #else
138  //Enable store and forward mode
139  value = adin2111ReadReg(interface, ADIN2111_CONFIG0);
142 #endif
143 
144  //Read MAC configuration register 2
145  value = adin2111ReadReg(interface, ADIN2111_CONFIG2);
146  //Enable CRC append in the MAC TX path
148 
149 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
150  //Port separation mode?
151  if(interface->port != 0)
152  {
153  //Drop frames with unknown DA
155  }
156  else
157 #endif
158  {
159  //Forward frames with unknown DA to the other port
161  }
162 
163  //Update MAC configuration register 2
165 
166  //Loop through the ports
168  {
169  //Disable system interrupts
171 
172  //Enable link status change interrupt
175  }
176 
177 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
178  //Disable generic SPI protocol interrupts
179  adin2111WriteReg(interface, ADIN2111_IMASK0, 0xFFFFFFFF);
180  adin2111WriteReg(interface, ADIN2111_IMASK1, 0xFFFFFFFF);
181 #else
182  //Write the IMASK0 register to enable interrupts as required
184 
185  //Write the IMASK1 register to enable interrupts as required
189 #endif
190 
191  //When the MAC is configured, write 1 to the SYNC field in the CONFIG0
192  //register to indicate that the MAC configuration is complete
193  value = adin2111ReadReg(interface, ADIN2111_CONFIG0);
196 
197  //Loop through the ports
199  {
200  //Configure LED0 and LED1 function
206 
207  //Set LED0 and LED1 polarity
211 
212  //Clear the CRSM_SFT_PD bit to exit software power-down mode. At this
213  //point, the MAC-PHY starts autonegotiation and attempts to bring up a
214  //link after autonegotiation completes
218  }
219 
220  //Perform custom configuration
221  adin2111InitHook(interface);
222 
223  //Accept any packets from the upper layer
224  osSetEvent(&interface->nicTxEvent);
225 
226  //Force the TCP/IP stack to poll the link state at startup
227  interface->nicEvent = TRUE;
228  //Notify the TCP/IP stack of the event
229  osSetEvent(&interface->netContext->event);
230 
231  //Successful initialization
232  return NO_ERROR;
233 }
234 
235 
236 /**
237  * @brief ADIN2111 custom configuration
238  * @param[in] interface Underlying network interface
239  **/
240 
241 __weak_func void adin2111InitHook(NetInterface *interface)
242 {
243 }
244 
245 
246 /**
247  * @brief ADIN2111 timer handler
248  * @param[in] interface Underlying network interface
249  **/
250 
251 __weak_func void adin2111Tick(NetInterface *interface)
252 {
253 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
254  uint_t port;
255  bool_t linkState;
256 
257 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
258  //Port separation mode?
259  if(interface->port != 0)
260  {
261  uint_t i;
262  NetContext *context;
263  NetInterface *virtualInterface;
264 
265  //Point to the TCP/IP stack context
266  context = interface->netContext;
267 
268  //Loop through network interfaces
269  for(i = 0; i < context->numInterfaces; i++)
270  {
271  //Point to the current interface
272  virtualInterface = &context->interfaces[i];
273 
274  //Check whether the current virtual interface is attached to the
275  //physical interface
276  if(virtualInterface == interface ||
277  virtualInterface->parent == interface)
278  {
279  //Get the port number associated with the current interface
280  port = virtualInterface->port;
281 
282  //Valid port?
284  {
285  //Retrieve current link state
286  linkState = adin2111GetLinkState(interface, port);
287 
288  //Link up event?
289  if(linkState && !virtualInterface->linkState)
290  {
291  //The switch is only able to operate in 10 Mbps mode
292  virtualInterface->linkSpeed = NIC_LINK_SPEED_10MBPS;
293  virtualInterface->duplexMode = NIC_FULL_DUPLEX_MODE;
294 
295  //Update link state
296  virtualInterface->linkState = TRUE;
297 
298  //Process link state change event
299  nicNotifyLinkChange(virtualInterface);
300  }
301  //Link down event
302  else if(!linkState && virtualInterface->linkState)
303  {
304  //Update link state
305  virtualInterface->linkState = FALSE;
306 
307  //Process link state change event
308  nicNotifyLinkChange(virtualInterface);
309  }
310  }
311  }
312  }
313  }
314  else
315 #endif
316  {
317  //Initialize link state
318  linkState = FALSE;
319 
320  //Loop through the ports
322  {
323  //Retrieve current link state
324  if(adin2111GetLinkState(interface, port))
325  {
326  linkState = TRUE;
327  }
328  }
329 
330  //Link up event?
331  if(linkState && !interface->linkState)
332  {
333  //The switch is only able to operate in 10 Mbps mode
334  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
335  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
336 
337  //Update link state
338  interface->linkState = TRUE;
339 
340  //Process link state change event
341  nicNotifyLinkChange(interface);
342  }
343  //Link down event
344  else if(!linkState && interface->linkState)
345  {
346  //Update link state
347  interface->linkState = FALSE;
348 
349  //Process link state change event
350  nicNotifyLinkChange(interface);
351  }
352  }
353 #endif
354 }
355 
356 
357 /**
358  * @brief Enable interrupts
359  * @param[in] interface Underlying network interface
360  **/
361 
363 {
364  //Enable interrupts
365  if(interface->extIntDriver != NULL)
366  {
367  interface->extIntDriver->enableIrq();
368  }
369 }
370 
371 
372 /**
373  * @brief Disable interrupts
374  * @param[in] interface Underlying network interface
375  **/
376 
378 {
379  //Disable interrupts
380  if(interface->extIntDriver != NULL)
381  {
382  interface->extIntDriver->disableIrq();
383  }
384 }
385 
386 
387 /**
388  * @brief ADIN2111 interrupt service routine
389  * @param[in] interface Underlying network interface
390  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
391  **/
392 
394 {
395 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
396  //When the SPI host detects an asserted IRQn from the MACPHY, it should
397  //initiate a data chunk transfer to obtain the current data footer
398  interface->nicEvent = TRUE;
399 
400  //Notify the TCP/IP stack of the event
401  return osSetEventFromIsr(&interface->netContext->event);
402 #else
403  bool_t flag;
404  size_t n;
405  uint32_t mask0;
406  uint32_t mask1;
407  uint32_t status0;
408  uint32_t status1;
409 
410  //This flag will be set if a higher priority task must be woken
411  flag = FALSE;
412 
413  //Save interrupt mask register values
414  mask0 = adin2111ReadReg(interface, ADIN2111_IMASK0);
415  mask1 = adin2111ReadReg(interface, ADIN2111_IMASK1);
416 
417  //Disable interrupts to release the interrupt line
418  adin2111WriteReg(interface, ADIN2111_IMASK0, 0xFFFFFFFF);
419  adin2111WriteReg(interface, ADIN2111_IMASK1, 0xFFFFFFFF);
420 
421  //Read interrupt status registers
422  status0 = adin2111ReadReg(interface, ADIN2111_STATUS0);
423  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
424 
425  //PHY interrupt on port 1?
426  if((status0 & ADIN2111_STATUS0_PHYINT) != 0)
427  {
428  //Disable link status changed interrupt
429  mask0 |= ADIN2111_IMASK0_PHYINTM;
430 
431  //Set event flag
432  interface->nicEvent = TRUE;
433  //Notify the TCP/IP stack of the event
434  flag |= osSetEventFromIsr(&interface->netContext->event);
435  }
436 
437  //PHY interrupt on port 2?
438  if((status1 & ADIN2111_STATUS1_P2_PHYINT) != 0)
439  {
440  //Disable link status changed interrupt
442 
443  //Set event flag
444  interface->nicEvent = TRUE;
445  //Notify the TCP/IP stack of the event
446  flag |= osSetEventFromIsr(&interface->netContext->event);
447  }
448 
449  //Packet received on port1?
450  if((status1 & ADIN2111_STATUS1_P1_RX_RDY) != 0)
451  {
452  //Disable P1_RX_RDY interrupt
454 
455  //Set event flag
456  interface->nicEvent = TRUE;
457  //Notify the TCP/IP stack of the event
458  flag |= osSetEventFromIsr(&interface->netContext->event);
459  }
460 
461  //Packet received on port2?
462  if((status1 & ADIN2111_STATUS1_P2_RX_RDY) != 0)
463  {
464  //Disable P2_RX_RDY interrupt
466 
467  //Set event flag
468  interface->nicEvent = TRUE;
469  //Notify the TCP/IP stack of the event
470  flag |= osSetEventFromIsr(&interface->netContext->event);
471  }
472 
473  //Packet transmission complete?
474  if((status1 & ADIN2111_STATUS1_TX_RDY) != 0)
475  {
476  //Clear interrupt flag
478 
479  //The TX_SPACE register indicates the remaining space in the TX FIFO, in
480  //half words
481  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
483 
484  //Verify that there is space for a new frame
486  {
487  //Notify the TCP/IP stack that the transmitter is ready to send
488  flag |= osSetEventFromIsr(&interface->nicTxEvent);
489  }
490  }
491 
492  //Re-enable interrupts once the interrupt has been serviced
493  adin2111WriteReg(interface, ADIN2111_IMASK0, mask0);
494  adin2111WriteReg(interface, ADIN2111_IMASK1, mask1);
495 
496  //A higher priority task must be woken?
497  return flag;
498 #endif
499 }
500 
501 
502 /**
503  * @brief ADIN2111 event handler
504  * @param[in] interface Underlying network interface
505  **/
506 
507 __weak_func void adin2111EventHandler(NetInterface *interface)
508 {
509 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
510  uint32_t status;
511 
512  //Read buffer status register
513  status = adin2111ReadReg(interface, ADIN2111_BUFSTS);
514 
515  //Process all the data chunks currently available
516  while((status & ADIN2111_BUFSTS_RCA) != 0)
517  {
518  //Read incoming packet
519  adin2111ReceivePacket(interface, 0);
520 
521  //Read buffer status register
522  status = adin2111ReadReg(interface, ADIN2111_BUFSTS);
523  }
524 #else
525  uint32_t status0;
526  uint32_t status1;
527  uint16_t phyStatus;
528 
529  //When an interrupt occurs, the system can poll the MAC status registers
530  //(STATUS0 and STATUS1) to determine the origin of the interrupt
531  status0 = adin2111ReadReg(interface, ADIN2111_STATUS0);
532  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
533 
534  //PHY interrupt on port 1?
535  if((status0 & ADIN2111_STATUS0_PHYINT) != 0)
536  {
537  //Host software must read the PHY_SUBSYS_IRQ_STATUS and CRSM_IRQ_STATUS
538  //registers to determine the source of the interrupt
539  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT1,
541 
542  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT1,
544 
545  //Link status change on port1?
547  {
548  //Handle link status change event
550  }
551  }
552 
553  //PHY interrupt on port 2?
554  if((status1 & ADIN2111_STATUS1_P2_PHYINT) != 0)
555  {
556  //Host software must read the PHY_SUBSYS_IRQ_STATUS and CRSM_IRQ_STATUS
557  //registers to determine the source of the interrupt
558  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT2,
560 
561  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT2,
563 
564  //Link status change on port2?
566  {
567  //Handle link status change event
569  }
570  }
571 
572  //Packet received on port 1?
573  if((status1 & ADIN2111_STATUS1_P1_RX_RDY) != 0)
574  {
575  //Process all pending packets
576  do
577  {
578  //Read incoming packet
580 
581  //Read STATUS1 again
582  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
583 
584  //If the P1_RX_RDY bit is set, another frame is available to read
585  } while((status1 & ADIN2111_STATUS1_P1_RX_RDY) != 0);
586  }
587 
588  //Packet received on port 2?
589  if((status1 & ADIN2111_STATUS1_P2_RX_RDY) != 0)
590  {
591  //Process all pending packets
592  do
593  {
594  //Read incoming packet
596 
597  //Read STATUS1 again
598  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
599 
600  //If the P2_RX_RDY bit is set, another frame is available to read
601  } while((status1 & ADIN2111_STATUS1_P2_RX_RDY) != 0);
602  }
603 
604  //Write the IMASK0 register to re-enable interrupts
606 
607  //Write the IMASK1 register to re-enable interrupts
611 #endif
612 }
613 
614 
615 /**
616  * @brief ADIN2111 link status change event handler
617  * @param[in] interface Underlying network interface
618  **/
619 
621 {
622  uint_t port;
623  bool_t linkState;
624 
625 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
626  //Port separation mode?
627  if(interface->port != 0)
628  {
629  uint_t i;
630  NetContext *context;
631  NetInterface *virtualInterface;
632 
633  //Point to the TCP/IP stack context
634  context = interface->netContext;
635 
636  //Loop through network interfaces
637  for(i = 0; i < context->numInterfaces; i++)
638  {
639  //Point to the current interface
640  virtualInterface = &context->interfaces[i];
641 
642  //Check whether the current virtual interface is attached to the
643  //physical interface
644  if(virtualInterface == interface ||
645  virtualInterface->parent == interface)
646  {
647  //Get the port number associated with the current interface
648  port = virtualInterface->port;
649 
650  //Valid port?
652  {
653  //Retrieve current link state
654  linkState = adin2111GetLinkState(interface, port);
655 
656  //Link up event?
657  if(linkState && !virtualInterface->linkState)
658  {
659  //The switch is only able to operate in 10 Mbps mode
660  virtualInterface->linkSpeed = NIC_LINK_SPEED_10MBPS;
661  virtualInterface->duplexMode = NIC_FULL_DUPLEX_MODE;
662 
663  //Update link state
664  virtualInterface->linkState = TRUE;
665 
666  //Process link state change event
667  nicNotifyLinkChange(virtualInterface);
668  }
669  //Link down event
670  else if(!linkState && virtualInterface->linkState)
671  {
672  //Update link state
673  virtualInterface->linkState = FALSE;
674 
675  //Process link state change event
676  nicNotifyLinkChange(virtualInterface);
677  }
678  }
679  }
680  }
681  }
682  else
683 #endif
684  {
685  //Initialize link state
686  linkState = FALSE;
687 
688  //Loop through the ports
690  {
691  //Retrieve current link state
692  if(adin2111GetLinkState(interface, port))
693  {
694  linkState = TRUE;
695  }
696  }
697 
698  //Link up event?
699  if(linkState)
700  {
701  //The switch is only able to operate in 10 Mbps mode
702  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
703  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
704 
705  //Update link state
706  interface->linkState = TRUE;
707  }
708  else
709  {
710  //Update link state
711  interface->linkState = FALSE;
712  }
713 
714  //Process link state change event
715  nicNotifyLinkChange(interface);
716  }
717 }
718 
719 
720 /**
721  * @brief Send a packet
722  * @param[in] interface Underlying network interface
723  * @param[in] buffer Multi-part buffer containing the data to send
724  * @param[in] offset Offset to the first data byte
725  * @param[in] ancillary Additional options passed to the stack along with
726  * the packet
727  * @return Error code
728  **/
729 
731  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
732 {
733 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
734  size_t i;
735  size_t j;
736  size_t n;
737  size_t length;
738  uint_t port;
739  uint32_t status;
740  uint32_t header;
741  uint32_t footer;
742  uint8_t chunk[ADIN2111_CHUNK_SIZE];
743 
744  //Retrieve the length of the packet
745  length = netBufferGetLength(buffer) - offset;
746 
747  //Loop through the ports
749  {
750 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
751  //Check port number
752  if(port != ancillary->port && ancillary->port != 0)
753  {
754  continue;
755  }
756 #endif
757 
758  //Read buffer status register
759  status = adin2111ReadReg(interface, ADIN2111_BUFSTS);
760  //Get the number of data chunks available in the transmit buffer
761  n = (status & ADIN2111_BUFSTS_TXC) >> 8;
762 
763  //Check the number of transmit credits available
765  {
766  //A data transaction consists of multiple chunks
767  for(i = 0; i < length; i += n)
768  {
769  //The default size of the data chunk payload is 64 bytes
771 
772  //Set up a data transfer
775 
776  //The vendor specific bit VS[0] indicates the destination port
777  if(port == ADIN2111_PORT1)
778  {
780  }
781  else
782  {
784  }
785 
786  //Start of packet?
787  if(i == 0)
788  {
789  //The SPI host shall set the SV bit when the beginning of an
790  //Ethernet frame is present in the current transmit data chunk
791  //payload
792  header |= ADIN2111_TX_HEADER_SV;
793  }
794 
795  //End of packet?
796  if((i + n) == length)
797  {
798  //The SPI host shall set the EV bit when the end of an Ethernet
799  //frame is present in the current transmit data chunk payload
800  header |= ADIN2111_TX_HEADER_EV;
801 
802  //When EV is 1, the EBO field shall contain the byte offset into
803  //the transmit data chunk payload that points to the last byte of
804  //the Ethernet frame to transmit
805  header |= ((n - 1) << 8) & ADIN2111_TX_HEADER_EBO;
806  }
807 
808  //The parity bit is calculated over the transmit data header
809  if(adin2111CalcParity(header) != 0)
810  {
811  header |= ADIN2111_CTRL_HEADER_P;
812  }
813 
814  //A chunk is composed of 4 bytes of overhead plus the configured
815  //payload size
816  STORE32BE(header, chunk);
817 
818  //Copy data chunk payload
820  offset + i, n);
821 
822  //Pad frames shorter than the data chunk payload
824  {
827  }
828 
829  //Pull the CS pin low
830  interface->spiDriver->assertCs();
831 
832  //Perform data transaction
833  for(j = 0; j < ADIN2111_CHUNK_SIZE; j++)
834  {
835  chunk[j] = interface->spiDriver->transfer(chunk[j]);
836  }
837 
838  //Terminate the operation by raising the CS pin
839  interface->spiDriver->deassertCs();
840 
841  //Receive data chunks consist of the receive data chunk payload
842  //followed by a 4-byte footer
843  footer = LOAD32BE(chunk + ADIN2111_CHUNK_PAYLOAD_SIZE);
844 
845  //The RCA field indicates the number of receive data chunks
846  //available
847  if((footer & ADIN2111_RX_FOOTER_RCA) != 0)
848  {
849  //Some data chunks are available for reading
850  interface->nicEvent = TRUE;
851  //Notify the TCP/IP stack of the event
852  osSetEvent(&interface->netContext->event);
853  }
854  }
855  }
856  else
857  {
858  //No sufficient credits available
859  }
860  }
861 
862  //The transmitter can accept another packet
863  osSetEvent(&interface->nicTxEvent);
864 
865  //Successful processing
866  return NO_ERROR;
867 #else
868  static uint8_t temp[ADIN2111_ETH_TX_BUFFER_SIZE];
869  size_t n;
870  size_t length;
871  uint_t port;
872  uint16_t header;
873 
874  //Retrieve the length of the packet
875  length = netBufferGetLength(buffer) - offset;
876 
877  //Check the frame length
879  {
880  //The transmitter can accept another packet
881  osSetEvent(&interface->nicTxEvent);
882  //Report an error
883  return ERROR_INVALID_LENGTH;
884  }
885 
886  //Loop through the ports
888  {
889 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
890  //Check port number
891  if(port != ancillary->port && ancillary->port != 0)
892  {
893  continue;
894  }
895 #endif
896 
897  //The TX_SPACE register indicates the remaining space in the TX FIFO, in
898  //half words
899  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
901 
902  //Ensure that there is sufficient space for the Ethernet frame plus 2-byte
903  //header plus 2-byte size field
904  if((n * 2) < (length + ADIN2111_TX_FIFO_OVERHEAD))
905  {
906  return ERROR_FAILURE;
907  }
908 
909  //Copy user data
910  netBufferRead(temp, buffer, offset, length);
911 
912  //Specify the destination port
913  if(port == ADIN2111_PORT1)
914  {
916  }
917  else
918  {
920  }
921 
922  //TX_FSIZE is written with the original frame size + 2 bytes for the frame
923  //header
926 
927  //Write TX FIFO
928  adin2111WriteFifo(interface, header, temp, length);
929  }
930 
931  //The TX_SPACE register indicates the remaining space in the TX FIFO, in
932  //half words
933  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
935 
936  //Verify that there is space for a new frame
938  {
939  //The transmitter can accept another packet
940  osSetEvent(&interface->nicTxEvent);
941  }
942 
943  //Successful processing
944  return NO_ERROR;
945 #endif
946 }
947 
948 
949 /**
950  * @brief Receive a packet
951  * @param[in] interface Underlying network interface
952  * @param[in] port Port number
953  * @return Error code
954  **/
955 
957 {
958 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
959  static uint8_t buffer[ADIN2111_ETH_RX_BUFFER_SIZE];
960  error_t error;
961  size_t i;
962  size_t n;
963  size_t length;
964  uint32_t header;
965  uint32_t footer;
966  uint8_t chunk[ADIN2111_CHUNK_SIZE];
967 
968  //Initialize variable
969  length = 0;
970 
971  //A data transaction consists of multiple chunks
972  while(1)
973  {
974  //Check the length of the received packet
976  {
977  error = ERROR_BUFFER_OVERFLOW;
978  break;
979  }
980 
981  //The SPI host sets NORX to 0 to indicate that it accepts and process
982  //any receive frame data within the current chunk
983  header = ADIN2111_TX_HEADER_DNC;
984 
985  //The parity bit is calculated over the transmit data header
986  if(adin2111CalcParity(header) != 0)
987  {
988  header |= ADIN2111_CTRL_HEADER_P;
989  }
990 
991  //Transmit data chunks consist of a 4-byte header followed by the
992  //transmit data chunk payload,
993  STORE32BE(header, chunk);
994 
995  //Clear data chunk payload
998 
999  //Pull the CS pin low
1000  interface->spiDriver->assertCs();
1001 
1002  //Perform data transaction
1003  for(i = 0; i < ADIN2111_CHUNK_SIZE; i++)
1004  {
1005  chunk[i] = interface->spiDriver->transfer(chunk[i]);
1006  }
1007 
1008  //Terminate the operation by raising the CS pin
1009  interface->spiDriver->deassertCs();
1010 
1011  //Receive data chunks consist of the receive data chunk payload followed
1012  //by a 4-byte footer
1013  footer = LOAD32BE(chunk + ADIN2111_CHUNK_PAYLOAD_SIZE);
1014 
1015  //When the DV bit is 0, the SPI host ignores the chunk payload
1016  if((footer & ADIN2111_RX_FOOTER_DV) == 0)
1017  {
1018  error = ERROR_BUFFER_EMPTY;
1019  break;
1020  }
1021 
1022  //When the SV bit is 1, the beginning of an Ethernet frame is present in
1023  //the current transmit data chunk payload
1024  if(length == 0)
1025  {
1026  if((footer & ADIN2111_RX_FOOTER_SV) == 0)
1027  {
1028  error = ERROR_INVALID_PACKET;
1029  break;
1030  }
1031  }
1032  else
1033  {
1034  if((footer & ADIN2111_RX_FOOTER_SV) != 0)
1035  {
1036  error = ERROR_INVALID_PACKET;
1037  break;
1038  }
1039  }
1040 
1041  //When SV is 1, the vendor specific bit VS[0] bit indicates the port
1042  //number on which the frame was received
1043  if((footer & ADIN2111_RX_FOOTER_SV) != 0)
1044  {
1046  {
1047  port = ADIN2111_PORT1;
1048  }
1049  else
1050  {
1051  port = ADIN2111_PORT2;
1052  }
1053  }
1054 
1055  //When EV is 1, the EBO field contains the byte offset into the
1056  //receive data chunk payload that points to the last byte of the
1057  //received Ethernet frame
1058  if((footer & ADIN2111_RX_FOOTER_EV) != 0)
1059  {
1060  n = ((footer & ADIN2111_RX_FOOTER_EBO) >> 8) + 1;
1061  }
1062  else
1063  {
1065  }
1066 
1067  //Copy data chunk payload
1068  osMemcpy(buffer + length, chunk, n);
1069  //Adjust the length of the packet
1070  length += n;
1071 
1072  //When the EV bit is 1, the end of an Ethernet frame is present in the
1073  //current receive data chunk payload
1074  if((footer & ADIN2111_RX_FOOTER_EV) != 0)
1075  {
1076  NetRxAncillary ancillary;
1077 
1078  //Additional options can be passed to the stack along with the packet
1079  ancillary = NET_DEFAULT_RX_ANCILLARY;
1080 
1081 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
1082  //Save the port number on which the frame was received
1083  ancillary.port = port;
1084 #endif
1085  //Pass the packet to the upper layer
1086  nicProcessPacket(interface, buffer, length, &ancillary);
1087 
1088  //Successful processing
1089  error = NO_ERROR;
1090  break;
1091  }
1092  }
1093 
1094  //Return status code
1095  return error;
1096 #else
1097  static uint8_t temp[ADIN2111_ETH_RX_BUFFER_SIZE];
1098  error_t error;
1099  size_t length;
1100  uint16_t header;
1101 
1102  //Check port number
1103  if(port == ADIN2111_PORT1)
1104  {
1105  //Get the size of the frame at the head of the port 1 RX FIFO in bytes
1108  }
1109  else
1110  {
1111  //Get the size of the frame at the head of the port 2 RX FIFO in bytes
1114  }
1115 
1116  //Any packet pending in the receive buffer?
1118  {
1119  NetRxAncillary ancillary;
1120 
1121  //The size of the frame includes the appended header
1123  //Read RX FIFO
1124  adin2111ReadFifo(interface, port, &header, temp, length);
1125 
1126  //Limit the length of the payload
1128  //Additional options can be passed to the stack along with the packet
1129  ancillary = NET_DEFAULT_RX_ANCILLARY;
1130 
1131 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
1132  //Save the port number on which the frame was received
1133  ancillary.port = port;
1134 #endif
1135 
1136  //Pass the packet to the upper layer
1137  nicProcessPacket(interface, temp, length, &ancillary);
1138 
1139  //Successful processing
1140  error = NO_ERROR;
1141  }
1142  else
1143  {
1144  //The RX FIFO is empty
1145  error = ERROR_BUFFER_EMPTY;
1146  }
1147 
1148  //Return status code
1149  return error;
1150 #endif
1151 }
1152 
1153 
1154 /**
1155  * @brief Configure MAC address filtering
1156  * @param[in] interface Underlying network interface
1157  * @return Error code
1158  **/
1159 
1161 {
1162  uint_t i;
1163  uint_t j;
1164  uint32_t flags;
1165  MacFilterEntry *entry;
1166 
1167  //Debug message
1168  TRACE_DEBUG("Updating MAC filter...\r\n");
1169 
1170  //Set the upper 16 bits of the broadcast MAC address
1175 
1176  //Set the lower 32 bits of the broadcast MAC address
1179 
1180  //Set the upper 16 bits of the station MAC address
1183  ADIN2111_ADDR_FILT_UPR_TO_HOST | (interface->macAddr.b[0] << 8) |
1184  interface->macAddr.b[1]);
1185 
1186  //Set the lower 32 bits of the station MAC address
1188  (interface->macAddr.b[2] << 24) | (interface->macAddr.b[3] << 16) |
1189  (interface->macAddr.b[4] << 8) | interface->macAddr.b[5]);
1190 
1191  //The MAC address filter contains the list of MAC addresses to accept
1192  //when receiving an Ethernet frame
1193  for(i = 0, j = 2; i < MAC_ADDR_FILTER_SIZE &&
1194  j < ADIN2111_ADDR_TABLE_SIZE; i++)
1195  {
1196  //Point to the current entry
1197  entry = &interface->macAddrFilter[i];
1198 
1199  //Valid entry?
1200  if(entry->refCount > 0)
1201  {
1202  //Specify forwarding rules
1205 
1206  //Multicast address?
1207  if(macIsMulticastAddr(&entry->addr))
1208  {
1210  }
1211 
1212  //Set the upper 16 bits of the current MAC address
1214  flags | (entry->addr.b[0] << 8) | entry->addr.b[1]);
1215 
1216  //Set the lower 32 bits of the current MAC address
1218  (entry->addr.b[2] << 24) | (entry->addr.b[3] << 16) |
1219  (entry->addr.b[4] << 8) | entry->addr.b[5]);
1220 
1221  //Increment index
1222  j++;
1223  }
1224  }
1225 
1226  //Clear unused table entries
1227  for(; j < ADIN2111_ADDR_TABLE_SIZE; j++)
1228  {
1229  //Clear current MAC address
1230  adin2111WriteReg(interface, ADIN2111_ADDR_FILT_UPRn(j), 0);
1231  adin2111WriteReg(interface, ADIN2111_ADDR_FILT_LWRn(j), 0);
1232  }
1233 
1234  //Successful processing
1235  return NO_ERROR;
1236 }
1237 
1238 
1239 /**
1240  * @brief Get link state
1241  * @param[in] interface Underlying network interface
1242  * @param[in] port Port number
1243  * @return Link state
1244  **/
1245 
1247 {
1248  uint16_t value;
1249  bool_t linkState;
1250 
1251  //Check port number
1252  if(port >= ADIN2111_PORT1 && port <= ADIN2111_PORT2)
1253  {
1254  //Any link failure condition is latched in the MI_STATUS register.
1255  //Reading the register twice will always return the actual link status
1258 
1259  //Retrieve current link state
1261  }
1262  else
1263  {
1264  //The specified port number is not valid
1265  linkState = FALSE;
1266  }
1267 
1268  //Return link status
1269  return linkState;
1270 }
1271 
1272 
1273 /**
1274  * @brief Write SPI register
1275  * @param[in] interface Underlying network interface
1276  * @param[in] address Register address
1277  * @param[in] data System register value
1278  **/
1279 
1280 void adin2111WriteReg(NetInterface *interface, uint16_t address,
1281  uint32_t data)
1282 {
1283 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
1284  uint32_t header;
1285 
1286  //Set up a register write operation
1288 
1289  //The MMS field selects the specific register memory map to access
1290  if(address < 0x30)
1291  {
1292  header |= (ADIN2111_MMS_STD << 24) & ADIN2111_CTRL_HEADER_MMS;
1293  }
1294  else
1295  {
1296  header |= (ADIN2111_MMS_MAC << 24) & ADIN2111_CTRL_HEADER_MMS;
1297  }
1298 
1299  //Address of the first register to access
1300  header |= (address << 8) & ADIN2111_CTRL_HEADER_ADDR;
1301  //Specifies the number of registers to write
1302  header |= (0 << 1) & ADIN2111_CTRL_HEADER_LEN;
1303 
1304  //The parity bit is calculated over the control command header
1305  if(adin2111CalcParity(header) != 0)
1306  {
1307  header |= ADIN2111_CTRL_HEADER_P;
1308  }
1309 
1310  //Pull the CS pin low
1311  interface->spiDriver->assertCs();
1312 
1313  //Write control command header
1314  interface->spiDriver->transfer((header >> 24) & 0xFF);
1315  interface->spiDriver->transfer((header >> 16) & 0xFF);
1316  interface->spiDriver->transfer((header >> 8) & 0xFF);
1317  interface->spiDriver->transfer(header & 0xFF);
1318 
1319  //Write data
1320  interface->spiDriver->transfer((data >> 24) & 0xFF);
1321  interface->spiDriver->transfer((data >> 16) & 0xFF);
1322  interface->spiDriver->transfer((data >> 8) & 0xFF);
1323  interface->spiDriver->transfer(data & 0xFF);
1324 
1325 #if (ADIN2111_PROTECTION_SUPPORT == ENABLED)
1326  //Protection is accomplished by duplication of each 32-bit word containing
1327  //register data with its ones' complement
1328  data = ~data;
1329 
1330  //Write complement
1331  interface->spiDriver->transfer((data >> 24) & 0xFF);
1332  interface->spiDriver->transfer((data >> 16) & 0xFF);
1333  interface->spiDriver->transfer((data >> 8) & 0xFF);
1334  interface->spiDriver->transfer(data & 0xFF);
1335 #endif
1336 
1337  //Send 32 bits of dummy data at the end of the control write command
1338  interface->spiDriver->transfer(0x00);
1339  interface->spiDriver->transfer(0x00);
1340  interface->spiDriver->transfer(0x00);
1341  interface->spiDriver->transfer(0x00);
1342 
1343  //Terminate the operation by raising the CS pin
1344  interface->spiDriver->deassertCs();
1345 #else
1346  //Pull the CS pin low
1347  interface->spiDriver->assertCs();
1348 
1349  //Write command
1350  interface->spiDriver->transfer(ADIN2111_SPI_CMD_WRITE | (address >> 8));
1351  interface->spiDriver->transfer(address & 0xFF);
1352 
1353  //Write data
1354  interface->spiDriver->transfer((data >> 24) & 0xFF);
1355  interface->spiDriver->transfer((data >> 16) & 0xFF);
1356  interface->spiDriver->transfer((data >> 8) & 0xFF);
1357  interface->spiDriver->transfer(data & 0xFF);
1358 
1359  //Terminate the operation by raising the CS pin
1360  interface->spiDriver->deassertCs();
1361 #endif
1362 }
1363 
1364 
1365 /**
1366  * @brief Read SPI register
1367  * @param[in] interface Underlying network interface
1368  * @param[in] address System register address
1369  * @return Register value
1370  **/
1371 
1372 uint32_t adin2111ReadReg(NetInterface *interface, uint16_t address)
1373 {
1374 #if (ADIN2111_OA_SPI_SUPPORT == ENABLED)
1375  uint32_t data;
1376  uint32_t header;
1377 
1378  //Set up a register read operation
1379  header = ADIN2111_CTRL_HEADER_AID;
1380 
1381  //The MMS field selects the specific register memory map to access
1382  if(address < 0x30)
1383  {
1384  header |= (ADIN2111_MMS_STD << 24) & ADIN2111_CTRL_HEADER_MMS;
1385  }
1386  else
1387  {
1388  header |= (ADIN2111_MMS_MAC << 24) & ADIN2111_CTRL_HEADER_MMS;
1389  }
1390 
1391  //Address of the first register to access
1392  header |= (address << 8) & ADIN2111_CTRL_HEADER_ADDR;
1393  //Specifies the number of registers to read
1394  header |= (0 << 1) & ADIN2111_CTRL_HEADER_LEN;
1395 
1396  //The parity bit is calculated over the control command header
1397  if(adin2111CalcParity(header) != 0)
1398  {
1399  header |= ADIN2111_CTRL_HEADER_P;
1400  }
1401 
1402  //Pull the CS pin low
1403  interface->spiDriver->assertCs();
1404 
1405  //Write control command header
1406  interface->spiDriver->transfer((header >> 24) & 0xFF);
1407  interface->spiDriver->transfer((header >> 16) & 0xFF);
1408  interface->spiDriver->transfer((header >> 8) & 0xFF);
1409  interface->spiDriver->transfer(header & 0xFF);
1410 
1411  //Discard the echoed control header
1412  interface->spiDriver->transfer(0x00);
1413  interface->spiDriver->transfer(0x00);
1414  interface->spiDriver->transfer(0x00);
1415  interface->spiDriver->transfer(0x00);
1416 
1417  //Read data
1418  data = interface->spiDriver->transfer(0x00) << 24;
1419  data |= interface->spiDriver->transfer(0x00) << 16;
1420  data |= interface->spiDriver->transfer(0x00) << 8;
1421  data |= interface->spiDriver->transfer(0x00);
1422 
1423 #if (ADIN2111_PROTECTION_SUPPORT == ENABLED)
1424  //Protection is accomplished by duplication of each 32-bit word containing
1425  //register data with its ones' complement
1426  interface->spiDriver->transfer(0x00);
1427  interface->spiDriver->transfer(0x00);
1428  interface->spiDriver->transfer(0x00);
1429  interface->spiDriver->transfer(0x00);
1430 #endif
1431 
1432  //Terminate the operation by raising the CS pin
1433  interface->spiDriver->deassertCs();
1434 
1435  //Return register value
1436  return data;
1437 #else
1438  uint32_t data;
1439 
1440  //Pull the CS pin low
1441  interface->spiDriver->assertCs();
1442 
1443  //Write command
1444  interface->spiDriver->transfer(ADIN2111_SPI_CMD_READ | (address >> 8));
1445  interface->spiDriver->transfer(address & 0xFF);
1446 
1447  //Turn around
1448  interface->spiDriver->transfer(0x00);
1449 
1450  //Read data
1451  data = interface->spiDriver->transfer(0x00) << 24;
1452  data |= interface->spiDriver->transfer(0x00) << 16;
1453  data |= interface->spiDriver->transfer(0x00) << 8;
1454  data |= interface->spiDriver->transfer(0x00);
1455 
1456  //Terminate the operation by raising the CS pin
1457  interface->spiDriver->deassertCs();
1458 
1459  //Return register value
1460  return data;
1461 #endif
1462 }
1463 
1464 
1465 /**
1466  * @brief Dump SPI registers for debugging purpose
1467  * @param[in] interface Underlying network interface
1468  **/
1469 
1471 {
1472  uint16_t i;
1473 
1474  //Loop through system registers
1475  for(i = 0; i < 256; i++)
1476  {
1477  //Display current SPI register
1478  TRACE_DEBUG("0x%02" PRIX16 ": 0x%08" PRIX32 "\r\n", i,
1479  adin2111ReadReg(interface, i));
1480  }
1481 
1482  //Terminate with a line feed
1483  TRACE_DEBUG("\r\n");
1484 }
1485 
1486 
1487 /**
1488  * @brief Write PHY register
1489  * @param[in] interface Underlying network interface
1490  * @param[in] port Port number
1491  * @param[in] address PHY register address
1492  * @param[in] data Register value
1493  **/
1494 
1495 void adin2111WritePhyReg(NetInterface *interface, uint8_t port,
1496  uint8_t address, uint16_t data)
1497 {
1498  uint32_t value;
1499 
1500  //Perform a Clause 22 write operation
1502  //Set PHY address
1503  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1504  //Set register address
1506  //Set register value
1508 
1509  //Write MDIOACC0 register
1511 
1512  //Poll MDIOACC0.TRDONE to determine that the write operation has completed
1513  do
1514  {
1515  //Read MDIOACC0 register
1516  value = adin2111ReadReg(interface, ADIN2111_MDIOACC0);
1517 
1518  //When the MDIO transaction completes, the TRDONE bit is set to 1
1519  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1520 }
1521 
1522 
1523 /**
1524  * @brief Read PHY register
1525  * @param[in] interface Underlying network interface
1526  * @param[in] port Port number
1527  * @param[in] address PHY register address
1528  * @return Register value
1529  **/
1530 
1531 uint16_t adin2111ReadPhyReg(NetInterface *interface, uint8_t port,
1532  uint8_t address)
1533 {
1534  uint32_t value;
1535 
1536  //Perform a Clause 22 read operation
1538  //Set PHY address
1539  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1540  //Set register address
1542 
1543  //Write MDIOACC0 register
1545 
1546  //Poll MDIOACC0.TRDONE to determine that the read operation has completed
1547  do
1548  {
1549  //Read MDIOACC0 register
1550  value = adin2111ReadReg(interface, ADIN2111_MDIOACC0);
1551 
1552  //When the MDIO transaction completes, the TRDONE bit is set to 1
1553  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1554 
1555  //MDIOACC0.MDIO_DATA reflects the content of register
1557 }
1558 
1559 
1560 /**
1561  * @brief Dump PHY registers for debugging purpose
1562  * @param[in] interface Underlying network interface
1563  * @param[in] port Port number
1564  **/
1565 
1566 void adin2111DumpPhyReg(NetInterface *interface, uint8_t port)
1567 {
1568  uint8_t i;
1569 
1570  //Loop through PHY registers
1571  for(i = 0; i < 32; i++)
1572  {
1573  //Display current PHY register
1574  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1575  adin2111ReadPhyReg(interface, port, i));
1576  }
1577 
1578  //Terminate with a line feed
1579  TRACE_DEBUG("\r\n");
1580 }
1581 
1582 
1583 /**
1584  * @brief Write MMD register
1585  * @param[in] interface Underlying network interface
1586  * @param[in] port Port number
1587  * @param[in] devAddr Device address
1588  * @param[in] regAddr Register address
1589  * @param[in] data MMD register value
1590  **/
1591 
1592 void adin2111WriteMmdReg(NetInterface *interface, uint8_t port,
1593  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1594 {
1595  uint32_t value;
1596 
1597  //Perform a Clause 45 address write operation
1599  //Set port address
1600  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1601  //Set device address
1602  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1603  //Set register address
1605 
1606  //Write MDIOACC0 register
1608 
1609  //Perform a Clause 45 write operation
1611  //Set port address
1612  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1613  //Set device address
1614  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1615  //Set register value
1617 
1618  //Write MDIOACC1 register
1620 
1621  //Poll MDIOACC1.TRDONE to determine that the write operation has completed
1622  do
1623  {
1624  //Read MDIOACC1 register
1625  value = adin2111ReadReg(interface, ADIN2111_MDIOACC1);
1626 
1627  //When the MDIO transaction completes, the TRDONE bit is set to 1
1628  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1629 }
1630 
1631 
1632 /**
1633  * @brief Read MMD register
1634  * @param[in] interface Underlying network interface
1635  * @param[in] port Port number
1636  * @param[in] devAddr Device address
1637  * @param[in] regAddr Register address
1638  * @return MMD register value
1639  **/
1640 
1641 uint16_t adin2111ReadMmdReg(NetInterface *interface, uint8_t port,
1642  uint8_t devAddr, uint16_t regAddr)
1643 {
1644  uint32_t value;
1645 
1646  //Perform a Clause 45 address write operation
1648  //Set port address
1649  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1650  //Set device address
1651  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1652  //Set register address
1654 
1655  //Write MDIOACC0 register
1657 
1658  //Perform a Clause 45 read operation
1660  //Set port address
1661  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1662  //Set device address
1663  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1664 
1665  //Write MDIOACC1 register
1667 
1668  //Poll MDIOACC1.TRDONE to determine that the read operation has completed
1669  do
1670  {
1671  //Read MDIOACC1 register
1672  value = adin2111ReadReg(interface, ADIN2111_MDIOACC1);
1673 
1674  //When the MDIO transaction completes, the TRDONE bit is set to 1
1675  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1676 
1677  //MDIOACC1.MDIO_DATA reflects the content of register
1679 }
1680 
1681 
1682 /**
1683  * @brief Write TX FIFO
1684  * @param[in] interface Underlying network interface
1685  * @param[in] header Frame header
1686  * @param[in] data Pointer to the data being written
1687  * @param[in] length Number of data to write
1688  **/
1689 
1690 void adin2111WriteFifo(NetInterface *interface, uint16_t header,
1691  const uint8_t *data, size_t length)
1692 {
1693 #if (ADIN2111_OA_SPI_SUPPORT == DISABLED)
1694  size_t i;
1695 
1696  //Pull the CS pin low
1697  interface->spiDriver->assertCs();
1698 
1699  //Write command
1700  interface->spiDriver->transfer(ADIN2111_SPI_CMD_WRITE | (ADIN2111_TX >> 8));
1701  interface->spiDriver->transfer(ADIN2111_TX & 0xFF);
1702 
1703  //The 2-byte frame header is appended to all transmitted frames. This always
1704  //precedes the frame data
1705  interface->spiDriver->transfer((header >> 8) & 0xFF);
1706  interface->spiDriver->transfer(header & 0xFF);
1707 
1708  //Write frame data
1709  for(i = 0; i < length; i++)
1710  {
1711  interface->spiDriver->transfer(data[i]);
1712  }
1713 
1714  //The burst write data must always be in multiples of 4 bytes
1715  for(; ((i + ADIN2111_FRAME_HEADER_SIZE) % 4) != 0; i++)
1716  {
1717  interface->spiDriver->transfer(0x00);
1718  }
1719 
1720  //Terminate the operation by raising the CS pin
1721  interface->spiDriver->deassertCs();
1722 #endif
1723 }
1724 
1725 
1726 /**
1727  * @brief Read RX FIFO
1728  * @param[in] interface Underlying network interface
1729  * @param[in] port Port number
1730  * @param[out] header Frame header
1731  * @param[out] data Buffer where to store the incoming data
1732  * @param[in] length Number of data to read
1733  **/
1734 
1735 void adin2111ReadFifo(NetInterface *interface, uint8_t port,
1736  uint16_t *header, uint8_t *data, size_t length)
1737 {
1738 #if (ADIN2111_OA_SPI_SUPPORT == DISABLED)
1739  size_t i;
1740  uint16_t address;
1741 
1742  //Pull the CS pin low
1743  interface->spiDriver->assertCs();
1744 
1745  //Select the relevant RX FIFO
1746  if(port == ADIN2111_PORT1)
1747  {
1749  }
1750  else
1751  {
1753  }
1754 
1755  //Write command
1756  interface->spiDriver->transfer(ADIN2111_SPI_CMD_READ | (address >> 8));
1757  interface->spiDriver->transfer(address & 0xFF);
1758 
1759  //Turn around
1760  interface->spiDriver->transfer(0x00);
1761 
1762  //The 2-byte frame header is appended to all received frames. This always
1763  //precedes the frame data
1764  *header = interface->spiDriver->transfer(0x00) << 16;
1765  *header |= interface->spiDriver->transfer(0x00);
1766 
1767  //Read frame data
1768  for(i = 0; i < length && i < ADIN2111_ETH_RX_BUFFER_SIZE; i++)
1769  {
1770  data[i] = interface->spiDriver->transfer(0x00);
1771  }
1772 
1773  //Discard extra bytes
1774  for(; i < length; i++)
1775  {
1776  interface->spiDriver->transfer(0x00);
1777  }
1778 
1779  //The burst read data must always be in multiples of 4 bytes
1780  for(; ((i + ADIN2111_FRAME_HEADER_SIZE) % 4) != 0; i++)
1781  {
1782  interface->spiDriver->transfer(0x00);
1783  }
1784 
1785  //Terminate the operation by raising the CS pin
1786  interface->spiDriver->deassertCs();
1787 #endif
1788 }
1789 
1790 
1791 /**
1792  * @brief Calculate parity bit over a 32-bit data
1793  * @param[in] data 32-bit bit stream
1794  * @return Odd parity bit computed over the supplied data
1795  **/
1796 
1797 uint32_t adin2111CalcParity(uint32_t data)
1798 {
1799  //Calculate the odd parity bit computed over the supplied bit stream
1800  data ^= data >> 1;
1801  data ^= data >> 2;
1802  data ^= data >> 4;
1803  data ^= data >> 8;
1804  data ^= data >> 16;
1805 
1806  //Return '1' when the number of bits set to one in the supplied bit
1807  //stream is even (resulting in an odd number of ones when the parity is
1808  //included), otherwise return '0'
1809  return ~data & 0x01;
1810 }
1811 
1812 
1813 /**
1814  * @brief CRC calculation
1815  * @param[in] data Pointer to the data over which to calculate the CRC
1816  * @param[in] length Number of bytes to process
1817  * @return Resulting CRC value
1818  **/
1819 
1820 uint8_t adin2111CalcCrc(const uint8_t *data, size_t length)
1821 {
1822  size_t i;
1823  uint_t j;
1824  uint8_t crc;
1825 
1826  //CRC preset value
1827  crc = 0x00;
1828 
1829  //Loop through data
1830  for(i = 0; i < length; i++)
1831  {
1832  //Update CRC value
1833  crc ^= data[i];
1834 
1835  //The message is processed bit by bit
1836  for(j = 0; j < 8; j++)
1837  {
1838  if((crc & 0x80) != 0)
1839  {
1840  crc = (crc << 1) ^ 0x07;
1841  }
1842  else
1843  {
1844  crc <<= 1;
1845  }
1846  }
1847  }
1848 
1849  //Return CRC value
1850  return crc;
1851 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
#define ADIN2111_CONFIG0_TXCTE
#define ADIN2111_PHY_SUBSYS_IRQ_MASK_LINK_STAT_CHNG_IRQ_EN
#define ADIN2111_TX_HEADER_EBO
#define ADIN2111_CHUNK_PAYLOAD_SIZE
#define ADIN2111_STATUS1_P2_PHYINT
#define ADIN2111_CHUNK_SIZE
#define ADIN2111_CRSM_IRQ_MASK
#define NetContext
Definition: net.h:36
#define ADIN2111_CONFIG2_P2_FWD_UNK2P1
int bool_t
Definition: compiler_port.h:63
#define ADIN2111_TX
#define ADIN2111_CTRL_HEADER_WNR
#define ADIN2111_RESET_SWRESET
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define LOAD32BE(p)
Definition: cpu_endian.h:210
#define ADIN2111_MDIOACC_MDIO_TRDONE
@ ERROR_BUFFER_OVERFLOW
Definition: error.h:143
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
#define ADIN2111_IMASK0_PHYINTM
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
void adin2111LinkChangeEventHandler(NetInterface *interface)
ADIN2111 link status change event handler.
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
uint8_t adin2111CalcCrc(const uint8_t *data, size_t length)
CRC calculation.
void adin2111WriteFifo(NetInterface *interface, uint16_t header, const uint8_t *data, size_t length)
Write TX FIFO.
uint8_t data[]
Definition: ethernet.h:224
#define ADIN2111_MDIOACC_MDIO_ST_CLAUSE_45
#define ADIN2111_P2_RX_FSIZE
#define ADIN2111_CTRL_HEADER_LEN
void adin2111WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
#define ADIN2111_PHY_SUBSYS_IRQ_MASK
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
#define ADIN2111_CONFIG0_SYNC
void adin2111DisableIrq(NetInterface *interface)
Disable interrupts.
#define ADIN2111_TX_FIFO_OVERHEAD
#define ADIN2111_ADDR_FILT_LWRn(index)
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define ADIN2111_ADDR_FILT_LWR_MAC_ADDR_31_0
#define ADIN2111_MDIOACC_MDIO_OP_WRITE
#define ADIN2111_LED_CNTRL_LED0_EN
bool_t adin2111GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
#define ADIN2111_P1_RX
#define ADIN2111_TX_HEADER_EV
#define ADIN2111_BUFSTS_TXC
#define ADIN2111_ADDR_FILT_UPR_MAC_ADDR_47_32
#define ADIN2111_ADDR_FILT_UPR_TO_HOST
#define ADIN2111_CONFIG2
#define ADIN2111_ADDR_FILT_UPRn(index)
bool_t adin2111IrqHandler(NetInterface *interface)
ADIN2111 interrupt service routine.
#define ADIN2111_LED_POLARITY
#define ADIN2111_MDIOACC0
error_t adin2111Init(NetInterface *interface)
ADIN2111 Ethernet switch initialization.
uint16_t adin2111ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
#define ADIN2111_FRAME_HEADER_PORT2
#define FALSE
Definition: os_port.h:46
#define ADIN2111_P1_RX_FSIZE
#define ADIN2111_FRAME_HEADER_SIZE
#define ADIN2111_PHYID_REVISION_DEFAULT
#define osMemcpy(dest, src, length)
Definition: os_port.h:147
#define ADIN2111_P2_RX_FSIZE_P2_RX_FRM_SIZE
error_t adin2111SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
#define ADIN2111_MI_STATUS
error_t
Error codes.
Definition: error.h:43
#define ADIN2111_RX_FOOTER_RCA
#define ADIN2111_STATUS1_TX_RDY
#define ADIN2111_CONFIG0
error_t adin2111ReceivePacket(NetInterface *interface, uint8_t port)
Receive a packet.
#define ADIN2111_MMS_STD
#define ADIN2111_SPI_CMD_WRITE
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH
const NicDriver adin2111Driver
ADIN2111 driver.
#define ADIN2111_CONFIG0_CSARFE
#define ADIN2111_RX_FOOTER_DV
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
#define ADIN2111_CTRL_HEADER_P
MacAddr addr
MAC address.
Definition: ethernet.h:265
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
uint16_t adin2111ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
#define ADIN2111_MDIOACC_MDIO_ST_CLAUSE_22
@ ERROR_INVALID_LENGTH
Definition: error.h:111
#define ADIN2111_MDIOACC_MDIO_OP_ADDR
#define ADIN2111_ETH_TX_BUFFER_SIZE
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
#define ADIN2111_BUFSTS
#define ADIN2111_PORT2
uint32_t adin2111CalcParity(uint32_t data)
Calculate parity bit over a 32-bit data.
#define ADIN2111_CTRL_HEADER_ADDR
#define NetTxAncillary
Definition: net_misc.h:36
#define ADIN2111_TX_SPACE_TX_SPACE
#define ADIN2111_STATUS1_P1_RX_RDY
void adin2111ReadFifo(NetInterface *interface, uint8_t port, uint16_t *header, uint8_t *data, size_t length)
Read RX FIFO.
#define ADIN2111_TX_HEADER_NORX
#define ADIN2111_STATUS0_PHYINT
#define ADIN2111_MI_STATUS_MI_LINK_STAT_LAT
#define ADIN2111_CRSM_SFT_PD_CNTRL_CRSM_SFT_PD
#define ADIN2111_IMASK1_TX_RDY_MASK
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define ADIN2111_TX_HEADER_DNC
#define ADIN2111_RX_FOOTER_VS0_PORT1
#define ADIN2111_MDIOACC_MDIO_OP_READ
ADIN2111 2-port 10Base-T1L Ethernet switch driver.
#define MIN(a, b)
Definition: os_port.h:63
#define ADIN2111_CTRL_HEADER_AID
#define ADIN2111_RESET
#define ADIN2111_CRSM_IRQ_STATUS
#define ADIN2111_CONFIG0_CPS_64B
#define ADIN2111_IMASK0
#define ADIN2111_STATUS0_RESETC
#define ADIN2111_IMASK1
#define ADIN2111_TX_SPACE
#define ADIN2111_ETH_RX_BUFFER_SIZE
__weak_func void adin2111Tick(NetInterface *interface)
ADIN2111 timer handler.
#define ADIN2111_CHUNK_HEADER_SIZE
#define ADIN2111_STATUS1_P2_RX_RDY
#define ADIN2111_IMASK1_P1_RX_RDY_MASK
uint16_t port
Definition: dns_common.h:272
#define ADIN2111_RX_FOOTER_SV
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define ADIN2111_BUFSTS_RCA
void adin2111WriteReg(NetInterface *interface, uint16_t address, uint32_t data)
Write SPI register.
uint16_t regAddr
void adin2111DumpReg(NetInterface *interface)
Dump SPI registers for debugging purpose.
#define ADIN2111_LED_POLARITY_LED1_POLARITY_ACTIVE_HIGH
#define ADIN2111_ADDR_FILT_UPR_APPLY2PORT2
#define ADIN2111_IMASK1_P2_RX_RDY_MASK
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
MAC filter table entry.
Definition: ethernet.h:264
#define ADIN2111_PHYID_OUI_DEFAULT
#define ADIN2111_P1_RX_FSIZE_P1_RX_FRM_SIZE
Ipv6Addr address[]
Definition: ipv6.h:347
#define ADIN2111_CONFIG0_ZARFE
#define ADIN2111_LED_CNTRL
#define ADIN2111_SPI_CMD_READ
#define ADIN2111_CONFIG2_CRC_APPEND
#define ADIN2111_PHYID
#define ADIN2111_TX_HEADER_SV
uint8_t value[]
Definition: tcp.h:376
void adin2111EnableIrq(NetInterface *interface)
Enable interrupts.
#define ADIN2111_MDIOACC_MDIO_DEVAD
#define ADIN2111_TX_HEADER_DV
#define ADIN2111_RX_FOOTER_VS0
#define ADIN2111_PORT1
#define ADIN2111_CONFIG0_TXCTHRESH_16_CREDITS
#define ADIN2111_TX_HEADER_VS0_PORT1
#define ADIN2111_PHYID_MODEL_DEFAULT
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ADIN2111_ADDR_TABLE_SIZE
#define ADIN2111_P2_RX
#define ADIN2111_TX_FSIZE
#define ADIN2111_MDIOACC1
#define ADIN2111_RX_FOOTER_EBO
#define ADIN2111_LED_CNTRL_LED0_FUNCTION_LINKUP_TXRX_ACTIVITY
#define ADIN2111_IMASK1_P2_PHYINT_MASK
uint8_t flags
Definition: tcp.h:358
#define ADIN2111_PHY_SUBSYS_IRQ_STATUS
error_t adin2111UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
unsigned int uint_t
Definition: compiler_port.h:57
#define ADIN2111_MMS_MAC
#define osMemset(p, value, length)
Definition: os_port.h:141
TCP/IP stack core.
#define ADIN2111_FRAME_HEADER_PORT1
#define ADIN2111_STATUS0
NIC driver.
Definition: nic.h:286
__weak_func void adin2111InitHook(NetInterface *interface)
ADIN2111 custom configuration.
#define ADIN2111_LED_CNTRL_LED1_EN
#define ADIN2111_MDIOACC_MDIO_PRTAD
#define ADIN2111_MDIOACC_MDIO_DATA
#define ADIN2111_LED_CNTRL_LED1_FUNCTION_OFF
void adin2111WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
#define ADIN2111_STATUS1
__weak_func void adin2111EventHandler(NetInterface *interface)
ADIN2111 event handler.
#define STORE32BE(a, p)
Definition: cpu_endian.h:286
#define ADIN2111_RX_FOOTER_EV
#define ADIN2111_CONFIG2_P1_FWD_UNK2P2
#define ADIN2111_TX_HEADER_VS0_PORT2
uint32_t adin2111ReadReg(NetInterface *interface, uint16_t address)
Read SPI register.
#define ADIN2111_ADDR_FILT_UPR_APPLY2PORT1
#define ADIN2111_CTRL_HEADER_MMS
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define ADIN2111_LED_POLARITY_LED0_POLARITY_ACTIVE_HIGH
#define ADIN2111_CRSM_SFT_PD_CNTRL
#define ADIN2111_ADDR_FILT_UPR_TO_OTHER_PORT
void adin2111DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define ADIN2111_CONFIG0_RXCTE