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-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "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 controller 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 Ethernet controller...\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
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 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(&netEvent);
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(&netEvent);
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(&netEvent);
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(&netEvent);
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 
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  NetInterface *virtualInterface;
490 
491  //Loop through network interfaces
492  for(i = 0; i < NET_INTERFACE_COUNT; i++)
493  {
494  //Point to the current interface
495  virtualInterface = &netInterface[i];
496 
497  //Check whether the current virtual interface is attached to the
498  //physical interface
499  if(virtualInterface == interface ||
500  virtualInterface->parent == interface)
501  {
502  //Get the port number associated with the current interface
503  port = virtualInterface->port;
504 
505  //Valid port?
507  {
508  //Retrieve current link state
509  linkState = adin2111GetLinkState(interface, port);
510 
511  //Link up event?
512  if(linkState && !virtualInterface->linkState)
513  {
514  //The switch is only able to operate in 10 Mbps mode
515  virtualInterface->linkSpeed = NIC_LINK_SPEED_10MBPS;
516  virtualInterface->duplexMode = NIC_FULL_DUPLEX_MODE;
517 
518  //Update link state
519  virtualInterface->linkState = TRUE;
520 
521  //Process link state change event
522  nicNotifyLinkChange(virtualInterface);
523  }
524  //Link down event
525  else if(!linkState && virtualInterface->linkState)
526  {
527  //Update link state
528  virtualInterface->linkState = FALSE;
529 
530  //Process link state change event
531  nicNotifyLinkChange(virtualInterface);
532  }
533  }
534  }
535  }
536  }
537  else
538 #endif
539  {
540  //Initialize link state
541  linkState = FALSE;
542 
543  //Loop through the ports
545  {
546  //Retrieve current link state
547  if(adin2111GetLinkState(interface, port))
548  {
549  linkState = TRUE;
550  }
551  }
552 
553  //Link up event?
554  if(linkState)
555  {
556  //The switch is only able to operate in 10 Mbps mode
557  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
558  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
559 
560  //Update link state
561  interface->linkState = TRUE;
562  }
563  else
564  {
565  //Update link state
566  interface->linkState = FALSE;
567  }
568 
569  //Process link state change event
570  nicNotifyLinkChange(interface);
571  }
572 }
573 
574 
575 /**
576  * @brief Send a packet
577  * @param[in] interface Underlying network interface
578  * @param[in] buffer Multi-part buffer containing the data to send
579  * @param[in] offset Offset to the first data byte
580  * @param[in] ancillary Additional options passed to the stack along with
581  * the packet
582  * @return Error code
583  **/
584 
586  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
587 {
588  static uint8_t temp[ADIN2111_ETH_TX_BUFFER_SIZE];
589  size_t n;
590  size_t length;
591 
592  //Retrieve the length of the packet
593  length = netBufferGetLength(buffer) - offset;
594 
595  //Check the frame length
597  {
598  //The transmitter can accept another packet
599  osSetEvent(&interface->nicTxEvent);
600  //Report an error
601  return ERROR_INVALID_LENGTH;
602  }
603 
604  //The TX_SPACE register indicates the remaining space in the TX FIFO
605  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
607 
608  //Ensure that there is sufficient space for the Ethernet frame plus 2-byte
609  //header plus 2-byte size field
611  {
612  return ERROR_FAILURE;
613  }
614 
615  //Copy user data
616  netBufferRead(temp, buffer, offset, length);
617 
618 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
619  //Check port number
620  if(ancillary->port == ADIN2111_PORT1)
621  {
622  //TX_FSIZE is written with the original frame size + 2 bytes for the
623  //frame header
626 
627  //Write frame data (port 1)
629  }
630  else if(ancillary->port == ADIN2111_PORT2)
631  {
632  //TX_FSIZE is written with the original frame size + 2 bytes for the
633  //frame header
636 
637  //Write frame data (port 2)
639  }
640  else
641 #endif
642  {
643  //TX_FSIZE is written with the original frame size + 2 bytes for the
644  //frame header
647 
648  //Write frame data (port 1)
650 
651  //TX_FSIZE is written with the original frame size + 2 bytes for the
652  //frame header
655 
656  //Write frame data (port 2)
658  }
659 
660  //The TX_SPACE register indicates the remaining space in the TX FIFO
661  n = adin2111ReadReg(interface, ADIN2111_TX_SPACE) &
663 
664  //Verify that there is space for a new frame
666  {
667  //The transmitter can accept another packet
668  osSetEvent(&interface->nicTxEvent);
669  }
670 
671  //Successful processing
672  return NO_ERROR;
673 }
674 
675 
676 /**
677  * @brief Receive a packet
678  * @param[in] port Port number
679  * @param[in] interface Underlying network interface
680  **/
681 
682 void adin2111ReceivePacket(NetInterface *interface, uint8_t port)
683 {
684  static uint8_t temp[ADIN2111_ETH_RX_BUFFER_SIZE];
685  size_t length;
686  uint16_t header;
687 
688  //Check port number
689  if(port == ADIN2111_PORT1)
690  {
691  //Get the size of the frame at the head of the port 1 RX FIFO in bytes
694  }
695  else
696  {
697  //Get the size of the frame at the head of the port 2 RX FIFO in bytes
700  }
701 
702  //Any packet pending in the receive buffer?
704  {
705  NetRxAncillary ancillary;
706 
707  //The size of the frame includes the appended header
709  //Read frame data
710  adin2111ReadFifo(interface, port, &header, temp, length);
711 
712  //Limit the length of the payload
714  //Additional options can be passed to the stack along with the packet
715  ancillary = NET_DEFAULT_RX_ANCILLARY;
716 
717 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
718  //Save the port number on which the frame was received
719  ancillary.port = port;
720 #endif
721 
722  //Pass the packet to the upper layer
723  nicProcessPacket(interface, temp, length, &ancillary);
724  }
725 }
726 
727 
728 /**
729  * @brief Configure MAC address filtering
730  * @param[in] interface Underlying network interface
731  * @return Error code
732  **/
733 
735 {
736  uint_t i;
737  uint_t j;
738  uint32_t flags;
739  MacFilterEntry *entry;
740 
741  //Debug message
742  TRACE_DEBUG("Updating MAC filter...\r\n");
743 
744  //Set the upper 16 bits of the broadcast MAC address
749 
750  //Set the lower 32 bits of the broadcast MAC address
753 
754  //Set the upper 16 bits of the station MAC address
757  ADIN2111_ADDR_FILT_UPR_TO_HOST | (interface->macAddr.b[0] << 8) |
758  interface->macAddr.b[1]);
759 
760  //Set the lower 32 bits of the station MAC address
762  (interface->macAddr.b[2] << 24) | (interface->macAddr.b[3] << 16) |
763  (interface->macAddr.b[4] << 8) | interface->macAddr.b[5]);
764 
765  //The MAC address filter contains the list of MAC addresses to accept
766  //when receiving an Ethernet frame
767  for(i = 0, j = 2; i < MAC_ADDR_FILTER_SIZE &&
768  j < ADIN2111_ADDR_TABLE_SIZE; i++)
769  {
770  //Point to the current entry
771  entry = &interface->macAddrFilter[i];
772 
773  //Valid entry?
774  if(entry->refCount > 0)
775  {
776  //Specify forwarding rules
779 
780  //Multicast address?
781  if(macIsMulticastAddr(&entry->addr))
782  {
784  }
785 
786  //Set the upper 16 bits of the current MAC address
788  flags | (entry->addr.b[0] << 8) | entry->addr.b[1]);
789 
790  //Set the lower 32 bits of the current MAC address
792  (entry->addr.b[2] << 24) | (entry->addr.b[3] << 16) |
793  (entry->addr.b[4] << 8) | entry->addr.b[5]);
794 
795  //Increment index
796  j++;
797  }
798  }
799 
800  //Clear unused table entries
801  for(; j < ADIN2111_ADDR_TABLE_SIZE; j++)
802  {
803  //Clear current MAC address
804  adin2111WriteReg(interface, ADIN2111_ADDR_FILT_UPRn(j), 0);
805  adin2111WriteReg(interface, ADIN2111_ADDR_FILT_LWRn(j), 0);
806  }
807 
808  //Successful processing
809  return NO_ERROR;
810 }
811 
812 
813 /**
814  * @brief Get link state
815  * @param[in] interface Underlying network interface
816  * @param[in] port Port number
817  * @return Link state
818  **/
819 
821 {
822  uint16_t value;
823  bool_t linkState;
824 
825  //Check port number
827  {
828  //Any link failure condition is latched in the MI_STATUS register.
829  //Reading the register twice will always return the actual link status
832 
833  //Retrieve current link state
835  }
836  else
837  {
838  //The specified port number is not valid
839  linkState = FALSE;
840  }
841 
842  //Return link status
843  return linkState;
844 }
845 
846 
847 /**
848  * @brief Write SPI register
849  * @param[in] interface Underlying network interface
850  * @param[in] address Register address
851  * @param[in] data System register value
852  **/
853 
854 void adin2111WriteReg(NetInterface *interface, uint16_t address,
855  uint32_t data)
856 {
857  //Pull the CS pin low
858  interface->spiDriver->assertCs();
859 
860  //Write command
861  interface->spiDriver->transfer(ADIN2111_SPI_CMD_WRITE | (address >> 8));
862  interface->spiDriver->transfer(address & 0xFF);
863 
864  //Write data
865  interface->spiDriver->transfer((data >> 24) & 0xFF);
866  interface->spiDriver->transfer((data >> 16) & 0xFF);
867  interface->spiDriver->transfer((data >> 8) & 0xFF);
868  interface->spiDriver->transfer(data & 0xFF);
869 
870  //Terminate the operation by raising the CS pin
871  interface->spiDriver->deassertCs();
872 }
873 
874 
875 /**
876  * @brief Read SPI register
877  * @param[in] interface Underlying network interface
878  * @param[in] address System register address
879  * @return Register value
880  **/
881 
882 uint32_t adin2111ReadReg(NetInterface *interface, uint16_t address)
883 {
884  uint32_t data;
885 
886  //Pull the CS pin low
887  interface->spiDriver->assertCs();
888 
889  //Write command
890  interface->spiDriver->transfer(ADIN2111_SPI_CMD_READ | (address >> 8));
891  interface->spiDriver->transfer(address & 0xFF);
892 
893  //Turn around
894  interface->spiDriver->transfer(0x00);
895 
896  //Read data
897  data = interface->spiDriver->transfer(0x00) << 24;
898  data |= interface->spiDriver->transfer(0x00) << 16;
899  data |= interface->spiDriver->transfer(0x00) << 8;
900  data |= interface->spiDriver->transfer(0x00);
901 
902  //Terminate the operation by raising the CS pin
903  interface->spiDriver->deassertCs();
904 
905  //Return register value
906  return data;
907 }
908 
909 
910 /**
911  * @brief Dump SPI registers for debugging purpose
912  * @param[in] interface Underlying network interface
913  **/
914 
916 {
917  uint16_t i;
918 
919  //Loop through system registers
920  for(i = 0; i < 256; i++)
921  {
922  //Display current SPI register
923  TRACE_DEBUG("0x%02" PRIX16 ": 0x%08" PRIX32 "\r\n", i,
924  adin2111ReadReg(interface, i));
925  }
926 
927  //Terminate with a line feed
928  TRACE_DEBUG("\r\n");
929 }
930 
931 
932 /**
933  * @brief Write PHY register
934  * @param[in] interface Underlying network interface
935  * @param[in] port Port number
936  * @param[in] address PHY register address
937  * @param[in] data Register value
938  **/
939 
940 void adin2111WritePhyReg(NetInterface *interface, uint8_t port,
941  uint8_t address, uint16_t data)
942 {
943  uint32_t value;
944 
945  //Perform a Clause 22 write operation
947  //Set PHY address
949  //Set register address
951  //Set register value
953 
954  //Write MDIOACC0 register
956 
957  //Poll MDIOACC0.TRDONE to determine that the write operation has completed
958  do
959  {
960  //Read MDIOACC0 register
962 
963  //When the MDIO transaction completes, the TRDONE bit is set to 1
964  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
965 }
966 
967 
968 /**
969  * @brief Read PHY register
970  * @param[in] interface Underlying network interface
971  * @param[in] port Port number
972  * @param[in] address PHY register address
973  * @return Register value
974  **/
975 
976 uint16_t adin2111ReadPhyReg(NetInterface *interface, uint8_t port,
977  uint8_t address)
978 {
979  uint32_t value;
980 
981  //Perform a Clause 22 read operation
983  //Set PHY address
985  //Set register address
987 
988  //Write MDIOACC0 register
990 
991  //Poll MDIOACC0.TRDONE to determine that the read operation has completed
992  do
993  {
994  //Read MDIOACC0 register
996 
997  //When the MDIO transaction completes, the TRDONE bit is set to 1
998  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
999 
1000  //MDIOACC0.MDIO_DATA reflects the content of register
1002 }
1003 
1004 
1005 /**
1006  * @brief Dump PHY registers for debugging purpose
1007  * @param[in] interface Underlying network interface
1008  * @param[in] port Port number
1009  **/
1010 
1011 void adin2111DumpPhyReg(NetInterface *interface, uint8_t port)
1012 {
1013  uint8_t i;
1014 
1015  //Loop through PHY registers
1016  for(i = 0; i < 32; i++)
1017  {
1018  //Display current PHY register
1019  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1020  adin2111ReadPhyReg(interface, port, i));
1021  }
1022 
1023  //Terminate with a line feed
1024  TRACE_DEBUG("\r\n");
1025 }
1026 
1027 
1028 /**
1029  * @brief Write MMD register
1030  * @param[in] interface Underlying network interface
1031  * @param[in] port Port number
1032  * @param[in] devAddr Device address
1033  * @param[in] regAddr Register address
1034  * @param[in] data MMD register value
1035  **/
1036 
1037 void adin2111WriteMmdReg(NetInterface *interface, uint8_t port,
1038  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1039 {
1040  uint32_t value;
1041 
1042  //Perform a Clause 45 address write operation
1044  //MDIO_PRTAD is always written to 1
1045  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1046  //Set device address
1047  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1048  //Set register address
1050 
1051  //Write MDIOACC0 register
1053 
1054  //Perform a Clause 45 write operation
1056  //MDIO_PRTAD is always written to 1
1057  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1058  //Set device address
1059  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1060  //Set register value
1062 
1063  //Write MDIOACC1 register
1065 
1066  //Poll MDIOACC1.TRDONE to determine that the write operation has completed
1067  do
1068  {
1069  //Read MDIOACC1 register
1070  value = adin2111ReadReg(interface, ADIN2111_MDIOACC1);
1071 
1072  //When the MDIO transaction completes, the TRDONE bit is set to 1
1073  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1074 }
1075 
1076 
1077 /**
1078  * @brief Read MMD register
1079  * @param[in] interface Underlying network interface
1080  * @param[in] port Port number
1081  * @param[in] devAddr Device address
1082  * @param[in] regAddr Register address
1083  * @return MMD register value
1084  **/
1085 
1086 uint16_t adin2111ReadMmdReg(NetInterface *interface, uint8_t port,
1087  uint8_t devAddr, uint16_t regAddr)
1088 {
1089  uint32_t value;
1090 
1091  //Perform a Clause 45 address write operation
1093  //MDIO_PRTAD is always written to 1
1094  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1095  //Set device address
1096  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1097  //Set register address
1099 
1100  //Write MDIOACC0 register
1102 
1103  //Perform a Clause 45 read operation
1105  //MDIO_PRTAD is always written to 1
1106  value |= (port << 21) & ADIN2111_MDIOACC_MDIO_PRTAD;
1107  //Set device address
1108  value |= (devAddr << 16) & ADIN2111_MDIOACC_MDIO_DEVAD;
1109 
1110  //Write MDIOACC1 register
1112 
1113  //Poll MDIOACC1.TRDONE to determine that the read operation has completed
1114  do
1115  {
1116  //Read MDIOACC1 register
1117  value = adin2111ReadReg(interface, ADIN2111_MDIOACC1);
1118 
1119  //When the MDIO transaction completes, the TRDONE bit is set to 1
1120  } while((value & ADIN2111_MDIOACC_MDIO_TRDONE) == 0);
1121 
1122  //MDIOACC1.MDIO_DATA reflects the content of register
1124 }
1125 
1126 
1127 /**
1128  * @brief Write TX FIFO
1129  * @param[in] interface Underlying network interface
1130  * @param[in] header Frame header
1131  * @param[in] data Pointer to the data being written
1132  * @param[in] length Number of data to write
1133  **/
1134 
1135 void adin2111WriteFifo(NetInterface *interface, uint16_t header,
1136  const uint8_t *data, size_t length)
1137 {
1138  size_t i;
1139 
1140  //Pull the CS pin low
1141  interface->spiDriver->assertCs();
1142 
1143  //Write command
1144  interface->spiDriver->transfer(ADIN2111_SPI_CMD_WRITE | (ADIN2111_TX >> 8));
1145  interface->spiDriver->transfer(ADIN2111_TX & 0xFF);
1146 
1147  //The 2-byte frame header is appended to all transmitted frames. This always
1148  //precedes the frame data
1149  interface->spiDriver->transfer((header >> 8) & 0xFF);
1150  interface->spiDriver->transfer(header & 0xFF);
1151 
1152  //Write frame data
1153  for(i = 0; i < length; i++)
1154  {
1155  interface->spiDriver->transfer(data[i]);
1156  }
1157 
1158  //The burst write data must always be in multiples of 4 bytes
1159  for(; ((i + ADIN2111_FRAME_HEADER_SIZE) % 4) != 0; i++)
1160  {
1161  interface->spiDriver->transfer(0x00);
1162  }
1163 
1164  //Terminate the operation by raising the CS pin
1165  interface->spiDriver->deassertCs();
1166 }
1167 
1168 
1169 /**
1170  * @brief Read RX FIFO
1171  * @param[in] interface Underlying network interface
1172  * @param[in] port Port number
1173  * @param[out] header Frame header
1174  * @param[out] data Buffer where to store the incoming data
1175  * @param[in] length Number of data to read
1176  **/
1177 
1178 void adin2111ReadFifo(NetInterface *interface, uint8_t port,
1179  uint16_t *header, uint8_t *data, size_t length)
1180 {
1181  size_t i;
1182  uint16_t address;
1183 
1184  //Pull the CS pin low
1185  interface->spiDriver->assertCs();
1186 
1187  //Select the relevant RX FIFO
1188  if(port == ADIN2111_PORT1)
1189  {
1191  }
1192  else
1193  {
1195  }
1196 
1197  //Write command
1198  interface->spiDriver->transfer(ADIN2111_SPI_CMD_READ | (address >> 8));
1199  interface->spiDriver->transfer(address & 0xFF);
1200 
1201  //Turn around
1202  interface->spiDriver->transfer(0x00);
1203 
1204  //The 2-byte frame header is appended to all received frames. This always
1205  //precedes the frame data
1206  *header = interface->spiDriver->transfer(0x00) << 16;
1207  *header |= interface->spiDriver->transfer(0x00);
1208 
1209  //Read frame data
1210  for(i = 0; i < length && i < ADIN2111_ETH_RX_BUFFER_SIZE; i++)
1211  {
1212  data[i] = interface->spiDriver->transfer(0x00);
1213  }
1214 
1215  //Discard extra bytes
1216  for(; i < length; i++)
1217  {
1218  interface->spiDriver->transfer(0x00);
1219  }
1220 
1221  //The burst read data must always be in multiples of 4 bytes
1222  for(; ((i + ADIN2111_FRAME_HEADER_SIZE) % 4) != 0; i++)
1223  {
1224  interface->spiDriver->transfer(0x00);
1225  }
1226 
1227  //Terminate the operation by raising the CS pin
1228  interface->spiDriver->deassertCs();
1229 }
void adin2111EventHandler(NetInterface *interface)
ADIN2111 event handler.
error_t adin2111SendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
uint16_t adin2111ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void adin2111ReceivePacket(NetInterface *interface, uint8_t port)
Receive a packet.
void adin2111WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
error_t adin2111UpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void adin2111WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
const NicDriver adin2111Driver
ADIN2111 driver.
void adin2111LinkChangeEventHandler(NetInterface *interface)
ADIN2111 link status change event handler.
void adin2111WriteReg(NetInterface *interface, uint16_t address, uint32_t data)
Write SPI register.
uint32_t adin2111ReadReg(NetInterface *interface, uint16_t address)
Read SPI register.
void adin2111WriteFifo(NetInterface *interface, uint16_t header, const uint8_t *data, size_t length)
Write TX FIFO.
bool_t adin2111IrqHandler(NetInterface *interface)
ADIN2111 interrupt service routine.
void adin2111DisableIrq(NetInterface *interface)
Disable interrupts.
void adin2111Tick(NetInterface *interface)
ADIN2111 timer handler.
bool_t adin2111GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
void adin2111ReadFifo(NetInterface *interface, uint8_t port, uint16_t *header, uint8_t *data, size_t length)
Read RX FIFO.
uint16_t adin2111ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
void adin2111DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
__weak_func void adin2111InitHook(NetInterface *interface)
ADIN2111 custom configuration.
void adin2111EnableIrq(NetInterface *interface)
Enable interrupts.
error_t adin2111Init(NetInterface *interface)
ADIN2111 controller initialization.
void adin2111DumpReg(NetInterface *interface)
Dump SPI registers for debugging purpose.
ADIN2111 2-port 10Base-T1L Ethernet switch driver.
#define ADIN2111_RESET
#define ADIN2111_MI_STATUS
#define ADIN2111_LED_CNTRL_LED1_FUNCTION_OFF
#define ADIN2111_PHYID_MODEL_DEFAULT
#define ADIN2111_IMASK1_P1_RX_RDY_MASK
#define ADIN2111_P2_RX_FSIZE
#define ADIN2111_ADDR_FILT_UPR_APPLY2PORT2
#define ADIN2111_TX_FRAME_OVERHEAD
#define ADIN2111_ADDR_TABLE_SIZE
#define ADIN2111_TX_FSIZE
#define ADIN2111_MDIOACC_MDIO_ST_CLAUSE_45
#define ADIN2111_ADDR_FILT_LWRn(index)
#define ADIN2111_SPI_CMD_WRITE
#define ADIN2111_FRAME_HEADER_SIZE
#define ADIN2111_P2_RX
#define ADIN2111_CONFIG0_TXCTE
#define ADIN2111_MDIOACC_MDIO_TRDONE
#define ADIN2111_PHY_SUBSYS_IRQ_MASK_LINK_STAT_CHNG_IRQ_EN
#define ADIN2111_CRSM_SFT_PD_CNTRL
#define ADIN2111_ETH_RX_BUFFER_SIZE
#define ADIN2111_TX
#define ADIN2111_FRAME_HEADER_PORT1
#define ADIN2111_TX_SPACE
#define ADIN2111_PORT1
#define ADIN2111_ADDR_FILT_UPR_TO_OTHER_PORT
#define ADIN2111_STATUS1_TX_RDY
#define ADIN2111_ADDR_FILT_UPR_MAC_ADDR_47_32
#define ADIN2111_PORT2
#define ADIN2111_LED_POLARITY_LED1_POLARITY_ACTIVE_HIGH
#define ADIN2111_MDIOACC1
#define ADIN2111_MDIOACC_MDIO_OP_ADDR
#define ADIN2111_CRSM_IRQ_MASK
#define ADIN2111_P1_RX_FSIZE_P1_RX_FRM_SIZE
#define ADIN2111_CONFIG2_P2_FWD_UNK2P1
#define ADIN2111_MDIOACC_MDIO_ST_CLAUSE_22
#define ADIN2111_STATUS0
#define ADIN2111_IMASK0
#define ADIN2111_FRAME_HEADER_PORT2
#define ADIN2111_LED_CNTRL_LED0_EN
#define ADIN2111_PHYID_OUI_DEFAULT
#define ADIN2111_STATUS1_P2_RX_RDY
#define ADIN2111_CONFIG2_CRC_APPEND
#define ADIN2111_STATUS1_P2_PHYINT
#define ADIN2111_STATUS0_PHYINT
#define ADIN2111_IMASK1_P2_RX_RDY_MASK
#define ADIN2111_ETH_TX_BUFFER_SIZE
#define ADIN2111_MDIOACC_MDIO_PRTAD
#define ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH
#define ADIN2111_PHY_SUBSYS_IRQ_MASK
#define ADIN2111_ADDR_FILT_LWR_MAC_ADDR_31_0
#define ADIN2111_P1_RX_FSIZE
#define ADIN2111_LED_POLARITY_LED0_POLARITY_ACTIVE_HIGH
#define ADIN2111_LED_POLARITY
#define ADIN2111_TX_SPACE_TX_SPACE
#define ADIN2111_PHYID_REVISION_DEFAULT
#define ADIN2111_LED_CNTRL_LED0_FUNCTION_LINKUP_TXRX_ACTIVITY
#define ADIN2111_MDIOACC0
#define ADIN2111_LED_CNTRL_LED1_EN
#define ADIN2111_STATUS1_P1_RX_RDY
#define ADIN2111_MDIOACC_MDIO_OP_READ
#define ADIN2111_P2_RX_FSIZE_P2_RX_FRM_SIZE
#define ADIN2111_P1_RX
#define ADIN2111_CRSM_SFT_PD_CNTRL_CRSM_SFT_PD
#define ADIN2111_STATUS0_RESETC
#define ADIN2111_CONFIG0_RXCTE
#define ADIN2111_IMASK1
#define ADIN2111_SPI_CMD_READ
#define ADIN2111_ADDR_FILT_UPR_APPLY2PORT1
#define ADIN2111_IMASK1_P2_PHYINT_MASK
#define ADIN2111_CONFIG2
#define ADIN2111_MI_STATUS_MI_LINK_STAT_LAT
#define ADIN2111_MDIOACC_MDIO_DATA
#define ADIN2111_PHY_SUBSYS_IRQ_STATUS
#define ADIN2111_CRSM_IRQ_STATUS
#define ADIN2111_LED_CNTRL
#define ADIN2111_RESET_SWRESET
#define ADIN2111_MDIOACC_MDIO_OP_WRITE
#define ADIN2111_CONFIG2_P1_FWD_UNK2P2
#define ADIN2111_CONFIG0_SYNC
#define ADIN2111_IMASK1_TX_RDY_MASK
#define ADIN2111_CONFIG0
#define ADIN2111_ADDR_FILT_UPR_TO_HOST
#define ADIN2111_MDIOACC_MDIO_DEVAD
#define ADIN2111_STATUS1
#define ADIN2111_IMASK0_PHYINTM
#define ADIN2111_PHYID
#define ADIN2111_ADDR_FILT_UPRn(index)
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint16_t port
Definition: dns_common.h:267
error_t
Error codes.
Definition: error.h:43
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
Ipv6Addr address[]
Definition: ipv6.h:316
uint16_t regAddr
TCP/IP stack core.
#define NET_INTERFACE_COUNT
Definition: net.h:113
#define NetInterface
Definition: net.h:36
#define netInterface
Definition: net_legacy.h:199
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
MAC filter table entry.
Definition: ethernet.h:262
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369
uint8_t flags
Definition: tcp.h:351