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.0
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  //Enable store and forward mode
133  value = adin2111ReadReg(interface, ADIN2111_CONFIG0);
136 
137  //Read MAC configuration register 2
138  value = adin2111ReadReg(interface, ADIN2111_CONFIG2);
139  //Enable CRC append in the MAC TX path
141 
142 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
143  //Port separation mode?
144  if(interface->port != 0)
145  {
146  //Drop frames with unknown DA
148  }
149  else
150 #endif
151  {
152  //Forward frames with unknown DA to the other port
154  }
155 
156  //Update MAC configuration register 2
158 
159  //Loop through the ports
161  {
162  //Disable system interrupts
164 
165  //Enable link status change interrupt
168  }
169 
170  //Write the IMASK0 register to enable interrupts as required
172 
173  //Write the IMASK1 register to enable interrupts as required
177 
178  //When the MAC is configured, write 1 to the SYNC field in the CONFIG0
179  //register to indicate that the MAC configuration is complete
180  value = adin2111ReadReg(interface, ADIN2111_CONFIG0);
183 
184  //Loop through the ports
186  {
187  //Configure LED0 and LED1 function
193 
194  //Set LED0 and LED1 polarity
198 
199  //Clear the CRSM_SFT_PD bit to exit software power-down mode. At this
200  //point, the MAC-PHY starts autonegotiation and attempts to bring up a
201  //link after autonegotiation completes
205  }
206 
207  //Perform custom configuration
208  adin2111InitHook(interface);
209 
210  //Accept any packets from the upper layer
211  osSetEvent(&interface->nicTxEvent);
212 
213  //Force the TCP/IP stack to poll the link state at startup
214  interface->nicEvent = TRUE;
215  //Notify the TCP/IP stack of the event
216  osSetEvent(&interface->netContext->event);
217 
218  //Successful initialization
219  return NO_ERROR;
220 }
221 
222 
223 /**
224  * @brief ADIN2111 custom configuration
225  * @param[in] interface Underlying network interface
226  **/
227 
228 __weak_func void adin2111InitHook(NetInterface *interface)
229 {
230 }
231 
232 
233 /**
234  * @brief ADIN2111 timer handler
235  * @param[in] interface Underlying network interface
236  **/
237 
238 __weak_func void adin2111Tick(NetInterface *interface)
239 {
240 }
241 
242 
243 /**
244  * @brief Enable interrupts
245  * @param[in] interface Underlying network interface
246  **/
247 
249 {
250  //Enable interrupts
251  if(interface->extIntDriver != NULL)
252  {
253  interface->extIntDriver->enableIrq();
254  }
255 }
256 
257 
258 /**
259  * @brief Disable interrupts
260  * @param[in] interface Underlying network interface
261  **/
262 
264 {
265  //Disable interrupts
266  if(interface->extIntDriver != NULL)
267  {
268  interface->extIntDriver->disableIrq();
269  }
270 }
271 
272 
273 /**
274  * @brief ADIN2111 interrupt service routine
275  * @param[in] interface Underlying network interface
276  * @return TRUE if a higher priority task must be woken. Else FALSE is returned
277  **/
278 
280 {
281  bool_t flag;
282  size_t n;
283  uint32_t mask0;
284  uint32_t mask1;
285  uint32_t status0;
286  uint32_t status1;
287 
288  //This flag will be set if a higher priority task must be woken
289  flag = FALSE;
290 
291  //Save interrupt mask register values
292  mask0 = adin2111ReadReg(interface, ADIN2111_IMASK0);
293  mask1 = adin2111ReadReg(interface, ADIN2111_IMASK1);
294 
295  //Disable interrupts to release the interrupt line
296  adin2111WriteReg(interface, ADIN2111_IMASK0, 0xFFFFFFFF);
297  adin2111WriteReg(interface, ADIN2111_IMASK1, 0xFFFFFFFF);
298 
299  //Read interrupt status registers
300  status0 = adin2111ReadReg(interface, ADIN2111_STATUS0);
301  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
302 
303  //PHY interrupt on port 1?
304  if((status0 & ADIN2111_STATUS0_PHYINT) != 0)
305  {
306  //Disable link status changed interrupt
307  mask0 |= ADIN2111_IMASK0_PHYINTM;
308 
309  //Set event flag
310  interface->nicEvent = TRUE;
311  //Notify the TCP/IP stack of the event
312  flag |= osSetEventFromIsr(&interface->netContext->event);
313  }
314 
315  //PHY interrupt on port 2?
316  if((status1 & ADIN2111_STATUS1_P2_PHYINT) != 0)
317  {
318  //Disable link status changed interrupt
320 
321  //Set event flag
322  interface->nicEvent = TRUE;
323  //Notify the TCP/IP stack of the event
324  flag |= osSetEventFromIsr(&interface->netContext->event);
325  }
326 
327  //Packet received on port1?
328  if((status1 & ADIN2111_STATUS1_P1_RX_RDY) != 0)
329  {
330  //Disable P1_RX_RDY interrupt
332 
333  //Set event flag
334  interface->nicEvent = TRUE;
335  //Notify the TCP/IP stack of the event
336  flag |= osSetEventFromIsr(&interface->netContext->event);
337  }
338 
339  //Packet received on port2?
340  if((status1 & ADIN2111_STATUS1_P2_RX_RDY) != 0)
341  {
342  //Disable P2_RX_RDY interrupt
344 
345  //Set event flag
346  interface->nicEvent = TRUE;
347  //Notify the TCP/IP stack of the event
348  flag |= osSetEventFromIsr(&interface->netContext->event);
349  }
350 
351  //Packet transmission complete?
352  if((status1 & ADIN2111_STATUS1_TX_RDY) != 0)
353  {
354  //Clear interrupt flag
356 
357  //The TX_SPACE register indicates the remaining space in the TX FIFO
358  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
360 
361  //Verify that there is space for a new frame
363  {
364  //Notify the TCP/IP stack that the transmitter is ready to send
365  flag |= osSetEventFromIsr(&interface->nicTxEvent);
366  }
367  }
368 
369  //Re-enable interrupts once the interrupt has been serviced
370  adin2111WriteReg(interface, ADIN2111_IMASK0, mask0);
371  adin2111WriteReg(interface, ADIN2111_IMASK1, mask1);
372 
373  //A higher priority task must be woken?
374  return flag;
375 }
376 
377 
378 /**
379  * @brief ADIN2111 event handler
380  * @param[in] interface Underlying network interface
381  **/
382 
383 __weak_func void adin2111EventHandler(NetInterface *interface)
384 {
385  uint32_t status0;
386  uint32_t status1;
387  uint16_t phyStatus;
388 
389  //When an interrupt occurs, the system can poll the MAC status registers
390  //(STATUS0 and STATUS1) to determine the origin of the interrupt
391  status0 = adin2111ReadReg(interface, ADIN2111_STATUS0);
392  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
393 
394  //PHY interrupt on port 1?
395  if((status0 & ADIN2111_STATUS0_PHYINT) != 0)
396  {
397  //Host software must read the PHY_SUBSYS_IRQ_STATUS and CRSM_IRQ_STATUS
398  //registers to determine the source of the interrupt
399  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT1,
401 
402  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT1,
404 
405  //Link status change on port1?
407  {
408  //Handle link status change event
410  }
411  }
412 
413  //PHY interrupt on port 2?
414  if((status1 & ADIN2111_STATUS1_P2_PHYINT) != 0)
415  {
416  //Host software must read the PHY_SUBSYS_IRQ_STATUS and CRSM_IRQ_STATUS
417  //registers to determine the source of the interrupt
418  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT2,
420 
421  phyStatus = adin2111ReadMmdReg(interface, ADIN2111_PORT2,
423 
424  //Link status change on port2?
426  {
427  //Handle link status change event
429  }
430  }
431 
432  //Packet received on port 1?
433  if((status1 & ADIN2111_STATUS1_P1_RX_RDY) != 0)
434  {
435  //Process all pending packets
436  do
437  {
438  //Read incoming packet
440 
441  //Read STATUS1 again
442  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
443 
444  //If the P1_RX_RDY bit is set, another frame is available to read
445  } while((status1 & ADIN2111_STATUS1_P1_RX_RDY) != 0);
446  }
447 
448  //Packet received on port 2?
449  if((status1 & ADIN2111_STATUS1_P2_RX_RDY) != 0)
450  {
451  //Process all pending packets
452  do
453  {
454  //Read incoming packet
456 
457  //Read STATUS1 again
458  status1 = adin2111ReadReg(interface, ADIN2111_STATUS1);
459 
460  //If the P2_RX_RDY bit is set, another frame is available to read
461  } while((status1 & ADIN2111_STATUS1_P2_RX_RDY) != 0);
462  }
463 
464  //Write the IMASK0 register to re-enable interrupts
466 
467  //Write the IMASK1 register to re-enable interrupts
471 }
472 
473 
474 /**
475  * @brief ADIN2111 link status change event handler
476  * @param[in] interface Underlying network interface
477  **/
478 
480 {
481  uint_t port;
482  bool_t linkState;
483 
484 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
485  //Port separation mode?
486  if(interface->port != 0)
487  {
488  uint_t i;
489  NetContext *context;
490  NetInterface *virtualInterface;
491 
492  //Point to the TCP/IP stack context
493  context = interface->netContext;
494 
495  //Loop through network interfaces
496  for(i = 0; i < context->numInterfaces; i++)
497  {
498  //Point to the current interface
499  virtualInterface = &context->interfaces[i];
500 
501  //Check whether the current virtual interface is attached to the
502  //physical interface
503  if(virtualInterface == interface ||
504  virtualInterface->parent == interface)
505  {
506  //Get the port number associated with the current interface
507  port = virtualInterface->port;
508 
509  //Valid port?
511  {
512  //Retrieve current link state
513  linkState = adin2111GetLinkState(interface, port);
514 
515  //Link up event?
516  if(linkState && !virtualInterface->linkState)
517  {
518  //The switch is only able to operate in 10 Mbps mode
519  virtualInterface->linkSpeed = NIC_LINK_SPEED_10MBPS;
520  virtualInterface->duplexMode = NIC_FULL_DUPLEX_MODE;
521 
522  //Update link state
523  virtualInterface->linkState = TRUE;
524 
525  //Process link state change event
526  nicNotifyLinkChange(virtualInterface);
527  }
528  //Link down event
529  else if(!linkState && virtualInterface->linkState)
530  {
531  //Update link state
532  virtualInterface->linkState = FALSE;
533 
534  //Process link state change event
535  nicNotifyLinkChange(virtualInterface);
536  }
537  }
538  }
539  }
540  }
541  else
542 #endif
543  {
544  //Initialize link state
545  linkState = FALSE;
546 
547  //Loop through the ports
549  {
550  //Retrieve current link state
551  if(adin2111GetLinkState(interface, port))
552  {
553  linkState = TRUE;
554  }
555  }
556 
557  //Link up event?
558  if(linkState)
559  {
560  //The switch is only able to operate in 10 Mbps mode
561  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
562  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
563 
564  //Update link state
565  interface->linkState = TRUE;
566  }
567  else
568  {
569  //Update link state
570  interface->linkState = FALSE;
571  }
572 
573  //Process link state change event
574  nicNotifyLinkChange(interface);
575  }
576 }
577 
578 
579 /**
580  * @brief Send a packet
581  * @param[in] interface Underlying network interface
582  * @param[in] buffer Multi-part buffer containing the data to send
583  * @param[in] offset Offset to the first data byte
584  * @param[in] ancillary Additional options passed to the stack along with
585  * the packet
586  * @return Error code
587  **/
588 
590  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
591 {
592  static uint8_t temp[ADIN2111_ETH_TX_BUFFER_SIZE];
593  size_t n;
594  size_t length;
595 
596  //Retrieve the length of the packet
597  length = netBufferGetLength(buffer) - offset;
598 
599  //Check the frame length
601  {
602  //The transmitter can accept another packet
603  osSetEvent(&interface->nicTxEvent);
604  //Report an error
605  return ERROR_INVALID_LENGTH;
606  }
607 
608  //The TX_SPACE register indicates the remaining space in the TX FIFO
609  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
611 
612  //Ensure that there is sufficient space for the Ethernet frame plus 2-byte
613  //header plus 2-byte size field
615  {
616  return ERROR_FAILURE;
617  }
618 
619  //Copy user data
620  netBufferRead(temp, buffer, offset, length);
621 
622 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
623  //Check port number
624  if(ancillary->port == ADIN2111_PORT1)
625  {
626  //TX_FSIZE is written with the original frame size + 2 bytes for the
627  //frame header
630 
631  //Write frame data (port 1)
633  }
634  else if(ancillary->port == ADIN2111_PORT2)
635  {
636  //TX_FSIZE is written with the original frame size + 2 bytes for the
637  //frame header
640 
641  //Write frame data (port 2)
643  }
644  else
645 #endif
646  {
647  //TX_FSIZE is written with the original frame size + 2 bytes for the
648  //frame header
651 
652  //Write frame data (port 1)
654 
655  //TX_FSIZE is written with the original frame size + 2 bytes for the
656  //frame header
659 
660  //Write frame data (port 2)
662  }
663 
664  //The TX_SPACE register indicates the remaining space in the TX FIFO
665  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
667 
668  //Verify that there is space for a new frame
670  {
671  //The transmitter can accept another packet
672  osSetEvent(&interface->nicTxEvent);
673  }
674 
675  //Successful processing
676  return NO_ERROR;
677 }
678 
679 
680 /**
681  * @brief Receive a packet
682  * @param[in] port Port number
683  * @param[in] interface Underlying network interface
684  **/
685 
686 void adin2111ReceivePacket(NetInterface *interface, uint8_t port)
687 {
688  static uint8_t temp[ADIN2111_ETH_RX_BUFFER_SIZE];
689  size_t length;
690  uint16_t header;
691 
692  //Check port number
693  if(port == ADIN2111_PORT1)
694  {
695  //Get the size of the frame at the head of the port 1 RX FIFO in bytes
698  }
699  else
700  {
701  //Get the size of the frame at the head of the port 2 RX FIFO in bytes
704  }
705 
706  //Any packet pending in the receive buffer?
708  {
709  NetRxAncillary ancillary;
710 
711  //The size of the frame includes the appended header
713  //Read frame data
714  adin2111ReadFifo(interface, port, &header, temp, length);
715 
716  //Limit the length of the payload
718  //Additional options can be passed to the stack along with the packet
719  ancillary = NET_DEFAULT_RX_ANCILLARY;
720 
721 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
722  //Save the port number on which the frame was received
723  ancillary.port = port;
724 #endif
725 
726  //Pass the packet to the upper layer
727  nicProcessPacket(interface, temp, length, &ancillary);
728  }
729 }
730 
731 
732 /**
733  * @brief Configure MAC address filtering
734  * @param[in] interface Underlying network interface
735  * @return Error code
736  **/
737 
739 {
740  uint_t i;
741  uint_t j;
742  uint32_t flags;
743  MacFilterEntry *entry;
744 
745  //Debug message
746  TRACE_DEBUG("Updating MAC filter...\r\n");
747 
748  //Set the upper 16 bits of the broadcast MAC address
753 
754  //Set the lower 32 bits of the broadcast MAC address
757 
758  //Set the upper 16 bits of the station MAC address
761  ADIN2111_ADDR_FILT_UPR_TO_HOST | (interface->macAddr.b[0] << 8) |
762  interface->macAddr.b[1]);
763 
764  //Set the lower 32 bits of the station MAC address
766  (interface->macAddr.b[2] << 24) | (interface->macAddr.b[3] << 16) |
767  (interface->macAddr.b[4] << 8) | interface->macAddr.b[5]);
768 
769  //The MAC address filter contains the list of MAC addresses to accept
770  //when receiving an Ethernet frame
771  for(i = 0, j = 2; i < MAC_ADDR_FILTER_SIZE &&
772  j < ADIN2111_ADDR_TABLE_SIZE; i++)
773  {
774  //Point to the current entry
775  entry = &interface->macAddrFilter[i];
776 
777  //Valid entry?
778  if(entry->refCount > 0)
779  {
780  //Specify forwarding rules
783 
784  //Multicast address?
785  if(macIsMulticastAddr(&entry->addr))
786  {
788  }
789 
790  //Set the upper 16 bits of the current MAC address
792  flags | (entry->addr.b[0] << 8) | entry->addr.b[1]);
793 
794  //Set the lower 32 bits of the current MAC address
796  (entry->addr.b[2] << 24) | (entry->addr.b[3] << 16) |
797  (entry->addr.b[4] << 8) | entry->addr.b[5]);
798 
799  //Increment index
800  j++;
801  }
802  }
803 
804  //Clear unused table entries
805  for(; j < ADIN2111_ADDR_TABLE_SIZE; j++)
806  {
807  //Clear current MAC address
808  adin2111WriteReg(interface, ADIN2111_ADDR_FILT_UPRn(j), 0);
809  adin2111WriteReg(interface, ADIN2111_ADDR_FILT_LWRn(j), 0);
810  }
811 
812  //Successful processing
813  return NO_ERROR;
814 }
815 
816 
817 /**
818  * @brief Get link state
819  * @param[in] interface Underlying network interface
820  * @param[in] port Port number
821  * @return Link state
822  **/
823 
825 {
826  uint16_t value;
827  bool_t linkState;
828 
829  //Check port number
831  {
832  //Any link failure condition is latched in the MI_STATUS register.
833  //Reading the register twice will always return the actual link status
836 
837  //Retrieve current link state
839  }
840  else
841  {
842  //The specified port number is not valid
843  linkState = FALSE;
844  }
845 
846  //Return link status
847  return linkState;
848 }
849 
850 
851 /**
852  * @brief Write SPI register
853  * @param[in] interface Underlying network interface
854  * @param[in] address Register address
855  * @param[in] data System register value
856  **/
857 
858 void adin2111WriteReg(NetInterface *interface, uint16_t address,
859  uint32_t data)
860 {
861  //Pull the CS pin low
862  interface->spiDriver->assertCs();
863 
864  //Write command
865  interface->spiDriver->transfer(ADIN2111_SPI_CMD_WRITE | (address >> 8));
866  interface->spiDriver->transfer(address & 0xFF);
867 
868  //Write data
869  interface->spiDriver->transfer((data >> 24) & 0xFF);
870  interface->spiDriver->transfer((data >> 16) & 0xFF);
871  interface->spiDriver->transfer((data >> 8) & 0xFF);
872  interface->spiDriver->transfer(data & 0xFF);
873 
874  //Terminate the operation by raising the CS pin
875  interface->spiDriver->deassertCs();
876 }
877 
878 
879 /**
880  * @brief Read SPI register
881  * @param[in] interface Underlying network interface
882  * @param[in] address System register address
883  * @return Register value
884  **/
885 
886 uint32_t adin2111ReadReg(NetInterface *interface, uint16_t address)
887 {
888  uint32_t data;
889 
890  //Pull the CS pin low
891  interface->spiDriver->assertCs();
892 
893  //Write command
894  interface->spiDriver->transfer(ADIN2111_SPI_CMD_READ | (address >> 8));
895  interface->spiDriver->transfer(address & 0xFF);
896 
897  //Turn around
898  interface->spiDriver->transfer(0x00);
899 
900  //Read data
901  data = interface->spiDriver->transfer(0x00) << 24;
902  data |= interface->spiDriver->transfer(0x00) << 16;
903  data |= interface->spiDriver->transfer(0x00) << 8;
904  data |= interface->spiDriver->transfer(0x00);
905 
906  //Terminate the operation by raising the CS pin
907  interface->spiDriver->deassertCs();
908 
909  //Return register value
910  return data;
911 }
912 
913 
914 /**
915  * @brief Dump SPI registers for debugging purpose
916  * @param[in] interface Underlying network interface
917  **/
918 
920 {
921  uint16_t i;
922 
923  //Loop through system registers
924  for(i = 0; i < 256; i++)
925  {
926  //Display current SPI register
927  TRACE_DEBUG("0x%02" PRIX16 ": 0x%08" PRIX32 "\r\n", i,
928  adin2111ReadReg(interface, i));
929  }
930 
931  //Terminate with a line feed
932  TRACE_DEBUG("\r\n");
933 }
934 
935 
936 /**
937  * @brief Write PHY register
938  * @param[in] interface Underlying network interface
939  * @param[in] port Port number
940  * @param[in] address PHY register address
941  * @param[in] data Register value
942  **/
943 
944 void adin2111WritePhyReg(NetInterface *interface, uint8_t port,
945  uint8_t address, uint16_t data)
946 {
947  uint32_t value;
948 
949  //Perform a Clause 22 write operation
951  //Set PHY address
953  //Set register address
955  //Set register value
957 
958  //Write MDIOACC0 register
960 
961  //Poll MDIOACC0.TRDONE to determine that the write operation has completed
962  do
963  {
964  //Read MDIOACC0 register
966 
967  //When the MDIO transaction completes, the TRDONE bit is set to 1
968  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
969 }
970 
971 
972 /**
973  * @brief Read PHY register
974  * @param[in] interface Underlying network interface
975  * @param[in] port Port number
976  * @param[in] address PHY register address
977  * @return Register value
978  **/
979 
980 uint16_t adin2111ReadPhyReg(NetInterface *interface, uint8_t port,
981  uint8_t address)
982 {
983  uint32_t value;
984 
985  //Perform a Clause 22 read operation
987  //Set PHY address
989  //Set register address
991 
992  //Write MDIOACC0 register
994 
995  //Poll MDIOACC0.TRDONE to determine that the read operation has completed
996  do
997  {
998  //Read MDIOACC0 register
1000 
1001  //When the MDIO transaction completes, the TRDONE bit is set to 1
1002  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1003 
1004  //MDIOACC0.MDIO_DATA reflects the content of register
1006 }
1007 
1008 
1009 /**
1010  * @brief Dump PHY registers for debugging purpose
1011  * @param[in] interface Underlying network interface
1012  * @param[in] port Port number
1013  **/
1014 
1015 void adin2111DumpPhyReg(NetInterface *interface, uint8_t port)
1016 {
1017  uint8_t i;
1018 
1019  //Loop through PHY registers
1020  for(i = 0; i < 32; i++)
1021  {
1022  //Display current PHY register
1023  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1024  adin2111ReadPhyReg(interface, port, i));
1025  }
1026 
1027  //Terminate with a line feed
1028  TRACE_DEBUG("\r\n");
1029 }
1030 
1031 
1032 /**
1033  * @brief Write MMD register
1034  * @param[in] interface Underlying network interface
1035  * @param[in] port Port number
1036  * @param[in] devAddr Device address
1037  * @param[in] regAddr Register address
1038  * @param[in] data MMD register value
1039  **/
1040 
1041 void adin2111WriteMmdReg(NetInterface *interface, uint8_t port,
1042  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1043 {
1044  uint32_t value;
1045 
1046  //Perform a Clause 45 address write operation
1048  //MDIO_PRTAD is always written to 1
1049  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1050  //Set device address
1051  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1052  //Set register address
1054 
1055  //Write MDIOACC0 register
1057 
1058  //Perform a Clause 45 write operation
1060  //MDIO_PRTAD is always written to 1
1061  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1062  //Set device address
1063  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1064  //Set register value
1066 
1067  //Write MDIOACC1 register
1069 
1070  //Poll MDIOACC1.TRDONE to determine that the write operation has completed
1071  do
1072  {
1073  //Read MDIOACC1 register
1074  value = adin2111ReadReg(interface, ADIN2111_MDIOACC1);
1075 
1076  //When the MDIO transaction completes, the TRDONE bit is set to 1
1077  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1078 }
1079 
1080 
1081 /**
1082  * @brief Read MMD register
1083  * @param[in] interface Underlying network interface
1084  * @param[in] port Port number
1085  * @param[in] devAddr Device address
1086  * @param[in] regAddr Register address
1087  * @return MMD register value
1088  **/
1089 
1090 uint16_t adin2111ReadMmdReg(NetInterface *interface, uint8_t port,
1091  uint8_t devAddr, uint16_t regAddr)
1092 {
1093  uint32_t value;
1094 
1095  //Perform a Clause 45 address write operation
1097  //MDIO_PRTAD is always written to 1
1098  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1099  //Set device address
1100  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1101  //Set register address
1103 
1104  //Write MDIOACC0 register
1106 
1107  //Perform a Clause 45 read operation
1109  //MDIO_PRTAD is always written to 1
1110  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1111  //Set device address
1112  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1113 
1114  //Write MDIOACC1 register
1116 
1117  //Poll MDIOACC1.TRDONE to determine that the read operation has completed
1118  do
1119  {
1120  //Read MDIOACC1 register
1121  value = adin2111ReadReg(interface, ADIN2111_MDIOACC1);
1122 
1123  //When the MDIO transaction completes, the TRDONE bit is set to 1
1124  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1125 
1126  //MDIOACC1.MDIO_DATA reflects the content of register
1128 }
1129 
1130 
1131 /**
1132  * @brief Write TX FIFO
1133  * @param[in] interface Underlying network interface
1134  * @param[in] header Frame header
1135  * @param[in] data Pointer to the data being written
1136  * @param[in] length Number of data to write
1137  **/
1138 
1139 void adin2111WriteFifo(NetInterface *interface, uint16_t header,
1140  const uint8_t *data, size_t length)
1141 {
1142  size_t i;
1143 
1144  //Pull the CS pin low
1145  interface->spiDriver->assertCs();
1146 
1147  //Write command
1148  interface->spiDriver->transfer(ADIN2111_SPI_CMD_WRITE | (ADIN2111_TX >> 8));
1149  interface->spiDriver->transfer(ADIN2111_TX & 0xFF);
1150 
1151  //The 2-byte frame header is appended to all transmitted frames. This always
1152  //precedes the frame data
1153  interface->spiDriver->transfer((header >> 8) & 0xFF);
1154  interface->spiDriver->transfer(header & 0xFF);
1155 
1156  //Write frame data
1157  for(i = 0; i < length; i++)
1158  {
1159  interface->spiDriver->transfer(data[i]);
1160  }
1161 
1162  //The burst write data must always be in multiples of 4 bytes
1163  for(; ((i + ADIN2111_FRAME_HEADER_SIZE) % 4) != 0; i++)
1164  {
1165  interface->spiDriver->transfer(0x00);
1166  }
1167 
1168  //Terminate the operation by raising the CS pin
1169  interface->spiDriver->deassertCs();
1170 }
1171 
1172 
1173 /**
1174  * @brief Read RX FIFO
1175  * @param[in] interface Underlying network interface
1176  * @param[in] port Port number
1177  * @param[out] header Frame header
1178  * @param[out] data Buffer where to store the incoming data
1179  * @param[in] length Number of data to read
1180  **/
1181 
1182 void adin2111ReadFifo(NetInterface *interface, uint8_t port,
1183  uint16_t *header, uint8_t *data, size_t length)
1184 {
1185  size_t i;
1186  uint16_t address;
1187 
1188  //Pull the CS pin low
1189  interface->spiDriver->assertCs();
1190 
1191  //Select the relevant RX FIFO
1192  if(port == ADIN2111_PORT1)
1193  {
1195  }
1196  else
1197  {
1199  }
1200 
1201  //Write command
1202  interface->spiDriver->transfer(ADIN2111_SPI_CMD_READ | (address >> 8));
1203  interface->spiDriver->transfer(address & 0xFF);
1204 
1205  //Turn around
1206  interface->spiDriver->transfer(0x00);
1207 
1208  //The 2-byte frame header is appended to all received frames. This always
1209  //precedes the frame data
1210  *header = interface->spiDriver->transfer(0x00) << 16;
1211  *header |= interface->spiDriver->transfer(0x00);
1212 
1213  //Read frame data
1214  for(i = 0; i < length && i < ADIN2111_ETH_RX_BUFFER_SIZE; i++)
1215  {
1216  data[i] = interface->spiDriver->transfer(0x00);
1217  }
1218 
1219  //Discard extra bytes
1220  for(; i < length; i++)
1221  {
1222  interface->spiDriver->transfer(0x00);
1223  }
1224 
1225  //The burst read data must always be in multiples of 4 bytes
1226  for(; ((i + ADIN2111_FRAME_HEADER_SIZE) % 4) != 0; i++)
1227  {
1228  interface->spiDriver->transfer(0x00);
1229  }
1230 
1231  //Terminate the operation by raising the CS pin
1232  interface->spiDriver->deassertCs();
1233 }
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_STATUS1_P2_PHYINT
#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_RESET_SWRESET
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define ADIN2111_MDIOACC_MDIO_TRDONE
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
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
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_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_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 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_STATUS1_TX_RDY
#define ADIN2111_CONFIG0
#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 NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
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
#define ADIN2111_PORT2
#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_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_MDIOACC_MDIO_OP_READ
ADIN2111 2-port 10Base-T1L Ethernet switch driver.
#define MIN(a, b)
Definition: os_port.h:63
#define ADIN2111_RESET
#define ADIN2111_CRSM_IRQ_STATUS
#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_STATUS1_P2_RX_RDY
#define ADIN2111_IMASK1_P1_RX_RDY_MASK
uint16_t port
Definition: dns_common.h:270
#define TRACE_DEBUG(...)
Definition: debug.h:119
void adin2111WriteReg(NetInterface *interface, uint16_t address, uint32_t data)
Write SPI register.
uint16_t regAddr
#define ADIN2111_TX_FRAME_OVERHEAD
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:345
#define ADIN2111_LED_CNTRL
#define ADIN2111_SPI_CMD_READ
#define ADIN2111_CONFIG2_CRC_APPEND
#define ADIN2111_PHYID
uint8_t value[]
Definition: tcp.h:376
void adin2111EnableIrq(NetInterface *interface)
Enable interrupts.
#define ADIN2111_MDIOACC_MDIO_DEVAD
#define ADIN2111_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_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
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 ADIN2111_CONFIG2_P1_FWD_UNK2P2
uint32_t adin2111ReadReg(NetInterface *interface, uint16_t address)
Read SPI register.
#define ADIN2111_ADDR_FILT_UPR_APPLY2PORT1
@ NO_ERROR
Success.
Definition: error.h:44
void adin2111ReceivePacket(NetInterface *interface, uint8_t port)
Receive a packet.
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