lan9646_driver.c
Go to the documentation of this file.
1 /**
2  * @file lan9646_driver.c
3  * @brief LAN9646 6-port Gigabit Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 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.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/ethernet_misc.h"
38 #include "debug.h"
39 
40 
41 /**
42  * @brief LAN9646 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to LAN9646)
75  **/
76 
77 const uint16_t lan9646IngressTailTag[6] =
78 {
84 };
85 
86 
87 /**
88  * @brief LAN9646 Ethernet switch initialization
89  * @param[in] interface Underlying network interface
90  * @return Error code
91  **/
92 
94 {
95  uint_t port;
96  uint8_t temp;
97 
98  //Debug message
99  TRACE_INFO("Initializing LAN9646...\r\n");
100 
101  //SPI slave mode?
102  if(interface->spiDriver != NULL)
103  {
104  //Initialize SPI interface
105  interface->spiDriver->init();
106 
107  //Wait for the serial interface to be ready
108  do
109  {
110  //Read CHIP_ID1 register
111  temp = lan9646ReadSwitchReg8(interface, LAN9646_CHIP_ID1);
112 
113  //The returned data is invalid until the serial interface is ready
114  } while(temp != LAN9646_CHIP_ID1_DEFAULT);
115 
116 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
117  //Enable tail tag feature
121 
122  //Disable frame length check (silicon errata workaround 13)
126 #else
127  //Disable tail tag feature
131 
132  //Enable frame length check
136 #endif
137 
138  //Loop through the ports
140  {
141 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
142  //Port separation mode?
143  if(interface->port != 0)
144  {
145  //Disable packet transmission and address learning
147  }
148  else
149 #endif
150  {
151  //Enable transmission, reception and address learning
153  }
154  }
155 
156  //Restore default age count
160 
161  //Restore default age period
164 
165  //Add internal delay to ingress and egress RGMII clocks
170 
171  //Start switch operation
174  }
175  else if(interface->smiDriver != NULL)
176  {
177  //Initialize serial management interface
178  interface->smiDriver->init();
179  }
180  else
181  {
182  //Just for sanity
183  }
184 
185  //Loop through the ports
187  {
188  //Improve PHY receive performance (silicon errata workaround 1)
189  lan9646WriteMmdReg(interface, port, 0x01, 0x6F, 0xDD0B);
190  lan9646WriteMmdReg(interface, port, 0x01, 0x8F, 0x6032);
191  lan9646WriteMmdReg(interface, port, 0x01, 0x9D, 0x248C);
192  lan9646WriteMmdReg(interface, port, 0x01, 0x75, 0x0060);
193  lan9646WriteMmdReg(interface, port, 0x01, 0xD3, 0x7777);
194  lan9646WriteMmdReg(interface, port, 0x1C, 0x06, 0x3008);
195  lan9646WriteMmdReg(interface, port, 0x1C, 0x08, 0x2001);
196 
197  //Improve transmit waveform amplitude (silicon errata workaround 2)
198  lan9646WriteMmdReg(interface, port, 0x1C, 0x04, 0x00D0);
199 
200  //EEE must be manually disabled (silicon errata workaround 4)
202 
203  //Adjust power supply settings (silicon errata workaround 7)
204  lan9646WriteMmdReg(interface, port, 0x1C, 0x13, 0x6EFF);
205  lan9646WriteMmdReg(interface, port, 0x1C, 0x14, 0xE6FF);
206  lan9646WriteMmdReg(interface, port, 0x1C, 0x15, 0x6EFF);
207  lan9646WriteMmdReg(interface, port, 0x1C, 0x16, 0xE6FF);
208  lan9646WriteMmdReg(interface, port, 0x1C, 0x17, 0x00FF);
209  lan9646WriteMmdReg(interface, port, 0x1C, 0x18, 0x43FF);
210  lan9646WriteMmdReg(interface, port, 0x1C, 0x19, 0xC3FF);
211  lan9646WriteMmdReg(interface, port, 0x1C, 0x1A, 0x6FFF);
212  lan9646WriteMmdReg(interface, port, 0x1C, 0x1B, 0x07FF);
213  lan9646WriteMmdReg(interface, port, 0x1C, 0x1C, 0x0FFF);
214  lan9646WriteMmdReg(interface, port, 0x1C, 0x1D, 0xE7FF);
215  lan9646WriteMmdReg(interface, port, 0x1C, 0x1E, 0xEFFF);
216  lan9646WriteMmdReg(interface, port, 0x1C, 0x20, 0xEEEE);
217 
218  //Select tri-color dual-LED mode (silicon errata workaround 15)
222 
223  //Debug message
224  TRACE_DEBUG("Port %u:\r\n", port);
225  //Dump PHY registers for debugging purpose
226  lan9646DumpPhyReg(interface, port);
227  }
228 
229  //Perform custom configuration
230  lan9646InitHook(interface);
231 
232  //Force the TCP/IP stack to poll the link state at startup
233  interface->phyEvent = TRUE;
234  //Notify the TCP/IP stack of the event
236 
237  //Successful initialization
238  return NO_ERROR;
239 }
240 
241 
242 /**
243  * @brief LAN9646 custom configuration
244  * @param[in] interface Underlying network interface
245  **/
246 
247 __weak_func void lan9646InitHook(NetInterface *interface)
248 {
249 }
250 
251 
252 /**
253  * @brief LAN9646 timer handler
254  * @param[in] interface Underlying network interface
255  **/
256 
257 void lan9646Tick(NetInterface *interface)
258 {
259  uint_t port;
260  bool_t linkState;
261 
262 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
263  //Port separation mode?
264  if(interface->port != 0)
265  {
266  uint_t i;
267  NetInterface *virtualInterface;
268 
269  //Loop through network interfaces
270  for(i = 0; i < NET_INTERFACE_COUNT; i++)
271  {
272  //Point to the current interface
273  virtualInterface = &netInterface[i];
274 
275  //Check whether the current virtual interface is attached to the
276  //physical interface
277  if(virtualInterface == interface ||
278  virtualInterface->parent == interface)
279  {
280  //Retrieve current link state
281  linkState = lan9646GetLinkState(interface, virtualInterface->port);
282 
283  //Link up or link down event?
284  if(linkState != virtualInterface->linkState)
285  {
286  //Set event flag
287  interface->phyEvent = TRUE;
288  //Notify the TCP/IP stack of the event
290  }
291  }
292  }
293  }
294  else
295 #endif
296  {
297  //Initialize link state
298  linkState = FALSE;
299 
300  //Loop through the ports
302  {
303  //Retrieve current link state
304  if(lan9646GetLinkState(interface, port))
305  {
306  linkState = TRUE;
307  }
308  }
309 
310  //Link up or link down event?
311  if(linkState != interface->linkState)
312  {
313  //Set event flag
314  interface->phyEvent = TRUE;
315  //Notify the TCP/IP stack of the event
317  }
318  }
319 }
320 
321 
322 /**
323  * @brief Enable interrupts
324  * @param[in] interface Underlying network interface
325  **/
326 
328 {
329 }
330 
331 
332 /**
333  * @brief Disable interrupts
334  * @param[in] interface Underlying network interface
335  **/
336 
338 {
339 }
340 
341 
342 /**
343  * @brief LAN9646 event handler
344  * @param[in] interface Underlying network interface
345  **/
346 
348 {
349  uint_t port;
350  bool_t linkState;
351 
352 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
353  //Port separation mode?
354  if(interface->port != 0)
355  {
356  uint_t i;
357  NetInterface *virtualInterface;
358 
359  //Loop through network interfaces
360  for(i = 0; i < NET_INTERFACE_COUNT; i++)
361  {
362  //Point to the current interface
363  virtualInterface = &netInterface[i];
364 
365  //Check whether the current virtual interface is attached to the
366  //physical interface
367  if(virtualInterface == interface ||
368  virtualInterface->parent == interface)
369  {
370  //Get the port number associated with the current interface
371  port = virtualInterface->port;
372 
373  //Valid port?
374  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
375  {
376  //Retrieve current link state
377  linkState = lan9646GetLinkState(interface, port);
378 
379  //Link up event?
380  if(linkState && !virtualInterface->linkState)
381  {
382  //Retrieve host interface speed
383  interface->linkSpeed = lan9646GetLinkSpeed(interface,
384  LAN9646_PORT6);
385 
386  //Retrieve host interface duplex mode
387  interface->duplexMode = lan9646GetDuplexMode(interface,
388  LAN9646_PORT6);
389 
390  //Adjust MAC configuration parameters for proper operation
391  interface->nicDriver->updateMacConfig(interface);
392 
393  //Check current speed
394  virtualInterface->linkSpeed = lan9646GetLinkSpeed(interface,
395  port);
396 
397  //Check current duplex mode
398  virtualInterface->duplexMode = lan9646GetDuplexMode(interface,
399  port);
400 
401  //Update link state
402  virtualInterface->linkState = TRUE;
403 
404  //Process link state change event
405  nicNotifyLinkChange(virtualInterface);
406  }
407  //Link down event
408  else if(!linkState && virtualInterface->linkState)
409  {
410  //Update link state
411  virtualInterface->linkState = FALSE;
412 
413  //Process link state change event
414  nicNotifyLinkChange(virtualInterface);
415  }
416  }
417  }
418  }
419  }
420  else
421 #endif
422  {
423  //Initialize link state
424  linkState = FALSE;
425 
426  //Loop through the ports
428  {
429  //Retrieve current link state
430  if(lan9646GetLinkState(interface, port))
431  {
432  linkState = TRUE;
433  }
434  }
435 
436  //Link up event?
437  if(linkState)
438  {
439  //Retrieve host interface speed
440  interface->linkSpeed = lan9646GetLinkSpeed(interface, LAN9646_PORT6);
441  //Retrieve host interface duplex mode
442  interface->duplexMode = lan9646GetDuplexMode(interface, LAN9646_PORT6);
443 
444  //Adjust MAC configuration parameters for proper operation
445  interface->nicDriver->updateMacConfig(interface);
446 
447  //Update link state
448  interface->linkState = TRUE;
449  }
450  else
451  {
452  //Update link state
453  interface->linkState = FALSE;
454  }
455 
456  //Process link state change event
457  nicNotifyLinkChange(interface);
458  }
459 }
460 
461 
462 /**
463  * @brief Add tail tag to Ethernet frame
464  * @param[in] interface Underlying network interface
465  * @param[in] buffer Multi-part buffer containing the payload
466  * @param[in,out] offset Offset to the first payload byte
467  * @param[in] ancillary Additional options passed to the stack along with
468  * the packet
469  * @return Error code
470  **/
471 
473  size_t *offset, NetTxAncillary *ancillary)
474 {
475  error_t error;
476 
477  //Initialize status code
478  error = NO_ERROR;
479 
480 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
481  //SPI slave mode?
482  if(interface->spiDriver != NULL)
483  {
484  //Valid port?
485  if(ancillary->port <= LAN9646_PORT4)
486  {
487  size_t length;
488  const uint16_t *tailTag;
489 
490  //The two-byte tail tagging is used to indicate the destination port
491  tailTag = &lan9646IngressTailTag[ancillary->port];
492 
493  //Retrieve the length of the Ethernet frame
494  length = netBufferGetLength(buffer) - *offset;
495 
496  //The host controller should manually add padding to the packet before
497  //inserting the tail tag
498  error = ethPadFrame(buffer, &length);
499 
500  //Check status code
501  if(!error)
502  {
503  //The tail tag is inserted at the end of the packet, just before
504  //the CRC
505  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
506  }
507  }
508  else
509  {
510  //The port number is not valid
511  error = ERROR_INVALID_PORT;
512  }
513  }
514 #endif
515 
516  //Return status code
517  return error;
518 }
519 
520 
521 /**
522  * @brief Decode tail tag from incoming Ethernet frame
523  * @param[in] interface Underlying network interface
524  * @param[in,out] frame Pointer to the received Ethernet frame
525  * @param[in,out] length Length of the frame, in bytes
526  * @param[in,out] ancillary Additional options passed to the stack along with
527  * the packet
528  * @return Error code
529  **/
530 
531 error_t lan9646UntagFrame(NetInterface *interface, uint8_t **frame,
532  size_t *length, NetRxAncillary *ancillary)
533 {
534  error_t error;
535 
536  //Initialize status code
537  error = NO_ERROR;
538 
539 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
540  //SPI slave mode?
541  if(interface->spiDriver != NULL)
542  {
543  //Valid Ethernet frame received?
544  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
545  {
546  uint8_t *tailTag;
547 
548  //The tail tag is inserted at the end of the packet, just before
549  //the CRC
550  tailTag = *frame + *length - sizeof(uint8_t);
551 
552  //The one byte tail tagging is used to indicate the source port
553  ancillary->port = (*tailTag & LAN9646_TAIL_TAG_SRC_PORT) + 1;
554 
555  //Strip tail tag from Ethernet frame
556  *length -= sizeof(uint8_t);
557  }
558  else
559  {
560  //Drop the received frame
561  error = ERROR_INVALID_LENGTH;
562  }
563  }
564  else
565  {
566  //Tail tagging mode cannot be enabled through MDC/MDIO interface
567  ancillary->port = 0;
568  }
569 #endif
570 
571  //Return status code
572  return error;
573 }
574 
575 
576 /**
577  * @brief Get link state
578  * @param[in] interface Underlying network interface
579  * @param[in] port Port number
580  * @return Link state
581  **/
582 
584 {
585  uint16_t value;
586  bool_t linkState;
587 
588  //Check port number
589  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
590  {
591  //Any link failure condition is latched in the BMSR register. Reading
592  //the register twice will always return the actual link status
593  value = lan9646ReadPhyReg(interface, port, LAN9646_BMSR);
594  value = lan9646ReadPhyReg(interface, port, LAN9646_BMSR);
595 
596  //Retrieve current link state
597  linkState = (value & LAN9646_BMSR_LINK_STATUS) ? TRUE : FALSE;
598  }
599  else
600  {
601  //The specified port number is not valid
602  linkState = FALSE;
603  }
604 
605  //Return link status
606  return linkState;
607 }
608 
609 
610 /**
611  * @brief Get link speed
612  * @param[in] interface Underlying network interface
613  * @param[in] port Port number
614  * @return Link speed
615  **/
616 
617 uint32_t lan9646GetLinkSpeed(NetInterface *interface, uint8_t port)
618 {
619  uint8_t type;
620  uint16_t value;
621  uint32_t linkSpeed;
622 
623  //Check port number
624  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
625  {
626  //Read PHY control register
628 
629  //Retrieve current link speed
631  {
632  //1000BASE-T
633  linkSpeed = NIC_LINK_SPEED_1GBPS;
634  }
635  else if((value & LAN9646_PHYCON_SPEED_100BTX) != 0)
636  {
637  //100BASE-TX
638  linkSpeed = NIC_LINK_SPEED_100MBPS;
639  }
640  else if((value & LAN9646_PHYCON_SPEED_10BT) != 0)
641  {
642  //10BASE-T
643  linkSpeed = NIC_LINK_SPEED_10MBPS;
644  }
645  else
646  {
647  //The link speed is not valid
648  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
649  }
650  }
651  else if(port == LAN9646_PORT6)
652  {
653  //SPI slave mode?
654  if(interface->spiDriver != NULL)
655  {
656  //Read port 6 XMII control 1 register
658 
659  //Retrieve host interface type
661 
662  //Gigabit interface?
665  {
666  //1000 Mb/s mode
667  linkSpeed = NIC_LINK_SPEED_1GBPS;
668  }
669  else
670  {
671  //Read port 6 XMII control 0 register
673 
674  //Retrieve host interface speed
676  {
677  //100 Mb/s mode
678  linkSpeed = NIC_LINK_SPEED_100MBPS;
679  }
680  else
681  {
682  //10 Mb/s mode
683  linkSpeed = NIC_LINK_SPEED_10MBPS;
684  }
685  }
686  }
687  else
688  {
689  //The MDC/MDIO interface does not have access to all the configuration
690  //registers. It can only access the standard MIIM registers
691  linkSpeed = NIC_LINK_SPEED_100MBPS;
692  }
693  }
694  else
695  {
696  //The specified port number is not valid
697  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
698  }
699 
700  //Return link status
701  return linkSpeed;
702 }
703 
704 
705 /**
706  * @brief Get duplex mode
707  * @param[in] interface Underlying network interface
708  * @param[in] port Port number
709  * @return Duplex mode
710  **/
711 
713 {
714  uint16_t value;
715  NicDuplexMode duplexMode;
716 
717  //Check port number
718  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
719  {
720  //Read PHY control register
722 
723  //Retrieve current duplex mode
725  {
726  duplexMode = NIC_FULL_DUPLEX_MODE;
727  }
728  else
729  {
730  duplexMode = NIC_HALF_DUPLEX_MODE;
731  }
732  }
733  else if(port == LAN9646_PORT6)
734  {
735  //SPI slave mode?
736  if(interface->spiDriver != NULL)
737  {
738  //Read port 6 XMII control 0 register
740 
741  //Retrieve host interface duplex mode
743  {
744  duplexMode = NIC_FULL_DUPLEX_MODE;
745  }
746  else
747  {
748  duplexMode = NIC_HALF_DUPLEX_MODE;
749  }
750  }
751  else
752  {
753  //The MDC/MDIO interface does not have access to all the configuration
754  //registers. It can only access the standard MIIM registers
755  duplexMode = NIC_FULL_DUPLEX_MODE;
756  }
757  }
758  else
759  {
760  //The specified port number is not valid
761  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
762  }
763 
764  //Return duplex mode
765  return duplexMode;
766 }
767 
768 
769 /**
770  * @brief Set port state
771  * @param[in] interface Underlying network interface
772  * @param[in] port Port number
773  * @param[in] state Port state
774  **/
775 
776 void lan9646SetPortState(NetInterface *interface, uint8_t port,
777  SwitchPortState state)
778 {
779  uint8_t temp;
780 
781  //Check port number
782  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
783  {
784  //Read MSTP state register
786 
787  //Update port state
788  switch(state)
789  {
790  //Listening state
795  break;
796 
797  //Learning state
802  break;
803 
804  //Forwarding state
809  break;
810 
811  //Disabled state
812  default:
816  break;
817  }
818 
819  //Write the value back to MSTP state register
821  }
822 }
823 
824 
825 /**
826  * @brief Get port state
827  * @param[in] interface Underlying network interface
828  * @param[in] port Port number
829  * @return Port state
830  **/
831 
833 {
834  uint8_t temp;
835  SwitchPortState state;
836 
837  //Check port number
838  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
839  {
840  //Read MSTP state register
842 
843  //Check port state
844  if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
845  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
847  {
848  //Disabled state
850  }
851  else if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
852  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
854  {
855  //Listening state
857  }
858  else if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
859  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
861  {
862  //Learning state
864  }
865  else if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
866  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
868  {
869  //Forwarding state
871  }
872  else
873  {
874  //Unknown state
876  }
877  }
878  else
879  {
880  //The specified port number is not valid
882  }
883 
884  //Return port state
885  return state;
886 }
887 
888 
889 /**
890  * @brief Set aging time for dynamic filtering entries
891  * @param[in] interface Underlying network interface
892  * @param[in] agingTime Aging time, in seconds
893  **/
894 
895 void lan9646SetAgingTime(NetInterface *interface, uint32_t agingTime)
896 {
897  //The Age Period in combination with the Age Count field determines the
898  //aging time of dynamic entries in the address lookup table
899  agingTime = (agingTime + 3) / 4;
900 
901  //Limit the range of the parameter
902  agingTime = MIN(agingTime, 255);
903 
904  //Write the value to Switch Lookup Engine Control 3 register
906  (uint8_t) agingTime);
907 }
908 
909 
910 /**
911  * @brief Enable IGMP snooping
912  * @param[in] interface Underlying network interface
913  * @param[in] enable Enable or disable IGMP snooping
914  **/
915 
917 {
918  uint8_t temp;
919 
920  //Read the Global Port Mirroring and Snooping Control register
921  temp = lan9646ReadSwitchReg8(interface,
923 
924  //Enable or disable IGMP snooping
925  if(enable)
926  {
928  }
929  else
930  {
932  }
933 
934  //Write the value back to Global Port Mirroring and Snooping Control register
936  temp);
937 }
938 
939 
940 /**
941  * @brief Enable MLD snooping
942  * @param[in] interface Underlying network interface
943  * @param[in] enable Enable or disable MLD snooping
944  **/
945 
947 {
948  uint8_t temp;
949 
950  //Read the Global Port Mirroring and Snooping Control register
951  temp = lan9646ReadSwitchReg8(interface,
953 
954  //Enable or disable MLD snooping
955  if(enable)
956  {
958  }
959  else
960  {
962  }
963 
964  //Write the value back to Global Port Mirroring and Snooping Control register
966  temp);
967 }
968 
969 
970 /**
971  * @brief Enable reserved multicast table
972  * @param[in] interface Underlying network interface
973  * @param[in] enable Enable or disable reserved group addresses
974  **/
975 
977 {
978  uint8_t temp;
979 
980  //Read the Switch Lookup Engine Control 0 register
982 
983  //Enable or disable the reserved multicast table
984  if(enable)
985  {
987  }
988  else
989  {
991  }
992 
993  //Write the value back to Switch Lookup Engine Control 0 register
995 }
996 
997 
998 /**
999  * @brief Add a new entry to the static MAC table
1000  * @param[in] interface Underlying network interface
1001  * @param[in] entry Pointer to the forwarding database entry
1002  * @return Error code
1003  **/
1004 
1006  const SwitchFdbEntry *entry)
1007 {
1008  error_t error;
1009  uint_t i;
1010  uint_t j;
1011  uint32_t value;
1012  SwitchFdbEntry currentEntry;
1013 
1014  //Keep track of the first free entry
1016 
1017  //Loop through the static MAC table
1018  for(i = 0; i < LAN9646_STATIC_MAC_TABLE_SIZE; i++)
1019  {
1020  //Read current entry
1021  error = lan9646GetStaticFdbEntry(interface, i, &currentEntry);
1022 
1023  //Valid entry?
1024  if(!error)
1025  {
1026  //Check whether the table already contains the specified MAC address
1027  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1028  {
1029  j = i;
1030  break;
1031  }
1032  }
1033  else
1034  {
1035  //Keep track of the first free entry
1037  {
1038  j = i;
1039  }
1040  }
1041  }
1042 
1043  //Any entry available?
1045  {
1046  //Write the Static Address Table Entry 1 register
1049 
1050  //Set the relevant forward ports
1051  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1052  {
1054  }
1055  else
1056  {
1057  value = entry->destPorts & LAN9646_PORT_MASK;
1058  }
1059 
1060  //Enable overriding of port state
1061  if(entry->override)
1062  {
1064  }
1065 
1066  //Write the Static Address Table Entry 2 register
1068 
1069  //Copy MAC address (first 16 bits)
1070  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1071 
1072  //Write the Static Address Table Entry 3 register
1074 
1075  //Copy MAC address (last 32 bits)
1076  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1077  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1078 
1079  //Write the Static Address Table Entry 4 register
1081 
1082  //Write the TABLE_INDEX field with the 4-bit index value
1084  //Set the TABLE_SELECT bit to 0 to select the static address table
1086  //Set the ACTION bit to 0 to indicate a write operation
1088  //Set the START_FINISH bit to 1 to initiate the operation
1090 
1091  //Start the write operation
1093  value);
1094 
1095  //When the operation is complete, the START_FINISH bit will be cleared
1096  //automatically
1097  do
1098  {
1099  //Read the Static Address and Reserved Multicast Table Control register
1100  value = lan9646ReadSwitchReg32(interface,
1102 
1103  //Poll the START_FINISH bit
1105 
1106  //Successful processing
1107  error = NO_ERROR;
1108  }
1109  else
1110  {
1111  //The static MAC table is full
1112  error = ERROR_TABLE_FULL;
1113  }
1114 
1115  //Return status code
1116  return error;
1117 }
1118 
1119 
1120 /**
1121  * @brief Remove an entry from the static MAC table
1122  * @param[in] interface Underlying network interface
1123  * @param[in] entry Forwarding database entry to remove from the table
1124  * @return Error code
1125  **/
1126 
1128  const SwitchFdbEntry *entry)
1129 {
1130  error_t error;
1131  uint_t j;
1132  uint32_t value;
1133  SwitchFdbEntry currentEntry;
1134 
1135  //Loop through the static MAC table
1136  for(j = 0; j < LAN9646_STATIC_MAC_TABLE_SIZE; j++)
1137  {
1138  //Read current entry
1139  error = lan9646GetStaticFdbEntry(interface, j, &currentEntry);
1140 
1141  //Valid entry?
1142  if(!error)
1143  {
1144  //Check whether the table contains the specified MAC address
1145  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1146  {
1147  break;
1148  }
1149  }
1150  }
1151 
1152  //Any matching entry?
1154  {
1155  //Clear Static Address Table Entry registers
1160 
1161  //Write the TABLE_INDEX field with the 4-bit index value
1163  //Set the TABLE_SELECT bit to 0 to select the static address table
1165  //Set the ACTION bit to 0 to indicate a write operation
1167  //Set the START_FINISH bit to 1 to initiate the operation
1169 
1170  //Start the write operation
1172  value);
1173 
1174  //When the operation is complete, the START_FINISH bit will be cleared
1175  //automatically
1176  do
1177  {
1178  //Read the Static Address and Reserved Multicast Table Control register
1179  value = lan9646ReadSwitchReg32(interface,
1181 
1182  //Poll the START_FINISH bit
1184 
1185  //Successful processing
1186  error = NO_ERROR;
1187  }
1188  else
1189  {
1190  //The static MAC table does not contain the specified address
1191  error = ERROR_NOT_FOUND;
1192  }
1193 
1194  //Return status code
1195  return error;
1196 }
1197 
1198 
1199 /**
1200  * @brief Read an entry from the static MAC table
1201  * @param[in] interface Underlying network interface
1202  * @param[in] index Zero-based index of the entry to read
1203  * @param[out] entry Pointer to the forwarding database entry
1204  * @return Error code
1205  **/
1206 
1208  SwitchFdbEntry *entry)
1209 {
1210  error_t error;
1211  uint32_t value;
1212 
1213  //Check index parameter
1214  if(index < LAN9646_STATIC_MAC_TABLE_SIZE)
1215  {
1216  //Write the TABLE_INDEX field with the 4-bit index value
1218  //Set the TABLE_SELECT bit to 0 to select the static address table
1220  //Set the ACTION bit to 1 to indicate a read operation
1222  //Set the START_FINISH bit to 1 to initiate the operation
1224 
1225  //Start the read operation
1227  value);
1228 
1229  //When the operation is complete, the START_FINISH bit will be cleared
1230  //automatically
1231  do
1232  {
1233  //Read the Static Address and Reserved Multicast Table Control register
1234  value = lan9646ReadSwitchReg32(interface,
1236 
1237  //Poll the START_FINISH bit
1239 
1240  //Read the Static Address Table Entry 1 register
1242 
1243  //Valid entry?
1245  {
1246  //Read the Static Address Table Entry 2 register
1248 
1249  //Retrieve the ports associated with this MAC address
1250  entry->srcPort = 0;
1252 
1253  //Check the value of the OVERRIDE bit
1255  {
1256  entry->override = TRUE;
1257  }
1258  else
1259  {
1260  entry->override = FALSE;
1261  }
1262 
1263  //Read the Static Address Table Entry 3 register
1265 
1266  //Copy MAC address (first 16 bits)
1267  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1268  entry->macAddr.b[1] = value & 0xFF;
1269 
1270  //Read the Static Address Table Entry 4 register
1272 
1273  //Copy MAC address (last 32 bits)
1274  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1275  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1276  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1277  entry->macAddr.b[5] = value & 0xFF;
1278 
1279  //Successful processing
1280  error = NO_ERROR;
1281  }
1282  else
1283  {
1284  //The entry is not valid
1285  error = ERROR_INVALID_ENTRY;
1286  }
1287  }
1288  else
1289  {
1290  //The end of the table has been reached
1291  error = ERROR_END_OF_TABLE;
1292  }
1293 
1294  //Return status code
1295  return error;
1296 }
1297 
1298 
1299 /**
1300  * @brief Flush static MAC table
1301  * @param[in] interface Underlying network interface
1302  **/
1303 
1305 {
1306  uint_t i;
1307  uint32_t value;
1308 
1309  //Loop through the static MAC table
1310  for(i = 0; i < LAN9646_STATIC_MAC_TABLE_SIZE; i++)
1311  {
1312  //Clear Static Address Table Entry registers
1317 
1318  //Write the TABLE_INDEX field with the 4-bit index value
1320  //Set the TABLE_SELECT bit to 0 to select the static address table
1322  //Set the ACTION bit to 0 to indicate a write operation
1324  //Set the START_FINISH bit to 1 to initiate the operation
1326 
1327  //Start the write operation
1329  value);
1330 
1331  //When the operation is complete, the START_FINISH bit will be cleared
1332  //automatically
1333  do
1334  {
1335  //Read the Static Address and Reserved Multicast Table Control register
1336  value = lan9646ReadSwitchReg32(interface,
1338 
1339  //Poll the START_FINISH bit
1341  }
1342 }
1343 
1344 
1345 /**
1346  * @brief Read an entry from the dynamic MAC table
1347  * @param[in] interface Underlying network interface
1348  * @param[in] index Zero-based index of the entry to read
1349  * @param[out] entry Pointer to the forwarding database entry
1350  * @return Error code
1351  **/
1352 
1354  SwitchFdbEntry *entry)
1355 {
1356  error_t error;
1357  uint32_t value;
1358 
1359  //First entry?
1360  if(index == 0)
1361  {
1362  //Clear the ALU Table Access Control register to stop any operation
1364 
1365  //Start the search operation
1369  }
1370 
1371  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1372  do
1373  {
1374  //Read the ALU Table Access Control register
1376 
1377  //This bit goes high to indicate either a new valid entry is returned or
1378  //the search is complete
1380 
1381  //Check whether the next valid entry is ready
1382  if((value & LAN9646_ALU_TABLE_CTRL_VALID) != 0)
1383  {
1384  //Store the data from the ALU table entry
1385  entry->destPorts = 0;
1386  entry->override = FALSE;
1387 
1388  //Read the ALU Table Entry 1 and 2 registers
1391 
1392  //Retrieve the port associated with this MAC address
1394  {
1396  entry->srcPort = LAN9646_PORT1;
1397  break;
1399  entry->srcPort = LAN9646_PORT2;
1400  break;
1402  entry->srcPort = LAN9646_PORT3;
1403  break;
1405  entry->srcPort = LAN9646_PORT4;
1406  break;
1408  entry->srcPort = LAN9646_PORT6;
1409  break;
1411  entry->srcPort = LAN9646_PORT7;
1412  break;
1413  default:
1414  entry->srcPort = 0;
1415  break;
1416  }
1417 
1418  //Read the ALU Table Entry 3 register
1420 
1421  //Copy MAC address (first 16 bits)
1422  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1423  entry->macAddr.b[1] = value & 0xFF;
1424 
1425  //Read the ALU Table Entry 4 register
1427 
1428  //Copy MAC address (last 32 bits)
1429  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1430  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1431  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1432  entry->macAddr.b[5] = value & 0xFF;
1433 
1434  //Successful processing
1435  error = NO_ERROR;
1436  }
1437  else
1438  {
1439  //The search can be stopped any time by setting the START_FINISH bit to 0
1441 
1442  //The end of the table has been reached
1443  error = ERROR_END_OF_TABLE;
1444  }
1445 
1446  //Return status code
1447  return error;
1448 }
1449 
1450 
1451 /**
1452  * @brief Flush dynamic MAC table
1453  * @param[in] interface Underlying network interface
1454  * @param[in] port Port number
1455  **/
1456 
1458 {
1459  uint_t temp;
1460  uint8_t state;
1461 
1462  //Flush only dynamic table entries
1467 
1468  //Valid port number?
1469  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT7)
1470  {
1471  //Save the current state of the port
1473 
1474  //Turn off learning capability
1477 
1478  //All the entries associated with a port that has its learning capability
1479  //being turned off will be flushed
1483 
1484  //Restore the original state of the port
1486  }
1487  else
1488  {
1489  //Trigger a flush of the entire address lookup table
1493  }
1494 }
1495 
1496 
1497 /**
1498  * @brief Set forward ports for unknown multicast packets
1499  * @param[in] interface Underlying network interface
1500  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1501  * @param[in] forwardPorts Port map
1502  **/
1503 
1505  bool_t enable, uint32_t forwardPorts)
1506 {
1507  uint32_t temp;
1508 
1509  //Read Unknown Multicast Control register
1511 
1512  //Clear port map
1514 
1515  //Enable or disable forwarding of unknown multicast packets
1516  if(enable)
1517  {
1518  //Enable forwarding
1520 
1521  //Check whether unknown multicast packets should be forwarded to the CPU port
1522  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1523  {
1525  }
1526 
1527  //Select the desired forward ports
1528  temp |= forwardPorts & LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL;
1529  }
1530  else
1531  {
1532  //Disable forwarding
1534  }
1535 
1536  //Write the value back to Unknown Multicast Control register
1538 }
1539 
1540 
1541 /**
1542  * @brief Write PHY register
1543  * @param[in] interface Underlying network interface
1544  * @param[in] port Port number
1545  * @param[in] address PHY register address
1546  * @param[in] data Register value
1547  **/
1548 
1549 void lan9646WritePhyReg(NetInterface *interface, uint8_t port,
1550  uint8_t address, uint16_t data)
1551 {
1552  uint16_t n;
1553 
1554  //SPI slave mode?
1555  if(interface->spiDriver != NULL)
1556  {
1557  //The SPI interface provides access to all PHY registers
1559  //Write the 16-bit value
1560  lan9646WriteSwitchReg16(interface, n, data);
1561  }
1562  else if(interface->smiDriver != NULL)
1563  {
1564  //Write the specified PHY register
1565  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1566  }
1567  else
1568  {
1569  //Write the specified PHY register
1570  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1571  }
1572 }
1573 
1574 
1575 /**
1576  * @brief Read PHY register
1577  * @param[in] interface Underlying network interface
1578  * @param[in] port Port number
1579  * @param[in] address PHY register address
1580  * @return Register value
1581  **/
1582 
1583 uint16_t lan9646ReadPhyReg(NetInterface *interface, uint8_t port,
1584  uint8_t address)
1585 {
1586  uint16_t n;
1587  uint16_t data;
1588 
1589  //SPI slave mode?
1590  if(interface->spiDriver != NULL)
1591  {
1592  //The SPI interface provides access to all PHY registers
1594  //Read the 16-bit value
1595  data = lan9646ReadSwitchReg16(interface, n);
1596  }
1597  else if(interface->smiDriver != NULL)
1598  {
1599  //Read the specified PHY register
1600  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1601  }
1602  else
1603  {
1604  //Read the specified PHY register
1605  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1606  }
1607 
1608  //Return register value
1609  return data;
1610 }
1611 
1612 
1613 /**
1614  * @brief Dump PHY registers for debugging purpose
1615  * @param[in] interface Underlying network interface
1616  * @param[in] port Port number
1617  **/
1618 
1619 void lan9646DumpPhyReg(NetInterface *interface, uint8_t port)
1620 {
1621  uint8_t i;
1622 
1623  //Loop through PHY registers
1624  for(i = 0; i < 32; i++)
1625  {
1626  //Display current PHY register
1627  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1628  lan9646ReadPhyReg(interface, port, i));
1629  }
1630 
1631  //Terminate with a line feed
1632  TRACE_DEBUG("\r\n");
1633 }
1634 
1635 
1636 /**
1637  * @brief Write MMD register
1638  * @param[in] interface Underlying network interface
1639  * @param[in] port Port number
1640  * @param[in] devAddr Device address
1641  * @param[in] regAddr Register address
1642  * @param[in] data Register value
1643  **/
1644 
1645 void lan9646WriteMmdReg(NetInterface *interface, uint8_t port,
1646  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1647 {
1648  //Select register operation
1651 
1652  //Write MMD register address
1654 
1655  //Select data operation
1658 
1659  //Write the content of the MMD register
1661 }
1662 
1663 
1664 /**
1665  * @brief Read MMD register
1666  * @param[in] interface Underlying network interface
1667  * @param[in] port Port number
1668  * @param[in] devAddr Device address
1669  * @param[in] regAddr Register address
1670  * @return Register value
1671  **/
1672 
1673 uint16_t lan9646ReadMmdReg(NetInterface *interface, uint8_t port,
1674  uint8_t devAddr, uint16_t regAddr)
1675 {
1676  //Select register operation
1679 
1680  //Write MMD register address
1682 
1683  //Select data operation
1686 
1687  //Read the content of the MMD register
1688  return lan9646ReadPhyReg(interface, port, LAN9646_MMDAADR);
1689 }
1690 
1691 
1692 /**
1693  * @brief Write switch register (8 bits)
1694  * @param[in] interface Underlying network interface
1695  * @param[in] address Switch register address
1696  * @param[in] data Register value
1697  **/
1698 
1699 void lan9646WriteSwitchReg8(NetInterface *interface, uint16_t address,
1700  uint8_t data)
1701 {
1702  uint32_t command;
1703 
1704  //SPI slave mode?
1705  if(interface->spiDriver != NULL)
1706  {
1707  //Set up a write operation
1708  command = LAN9646_SPI_CMD_WRITE;
1709  //Set register address
1710  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1711 
1712  //Pull the CS pin low
1713  interface->spiDriver->assertCs();
1714 
1715  //Write 32-bit command
1716  interface->spiDriver->transfer((command >> 24) & 0xFF);
1717  interface->spiDriver->transfer((command >> 16) & 0xFF);
1718  interface->spiDriver->transfer((command >> 8) & 0xFF);
1719  interface->spiDriver->transfer(command & 0xFF);
1720 
1721  //Write 8-bit data
1722  interface->spiDriver->transfer(data);
1723 
1724  //Terminate the operation by raising the CS pin
1725  interface->spiDriver->deassertCs();
1726  }
1727  else
1728  {
1729  //The MDC/MDIO interface does not have access to all the configuration
1730  //registers. It can only access the standard MIIM registers
1731  }
1732 }
1733 
1734 
1735 /**
1736  * @brief Read switch register (8 bits)
1737  * @param[in] interface Underlying network interface
1738  * @param[in] address Switch register address
1739  * @return Register value
1740  **/
1741 
1742 uint8_t lan9646ReadSwitchReg8(NetInterface *interface, uint16_t address)
1743 {
1744  uint8_t data;
1745  uint32_t command;
1746 
1747  //SPI slave mode?
1748  if(interface->spiDriver != NULL)
1749  {
1750  //Set up a read operation
1751  command = LAN9646_SPI_CMD_READ;
1752  //Set register address
1753  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1754 
1755  //Pull the CS pin low
1756  interface->spiDriver->assertCs();
1757 
1758  //Write 32-bit command
1759  interface->spiDriver->transfer((command >> 24) & 0xFF);
1760  interface->spiDriver->transfer((command >> 16) & 0xFF);
1761  interface->spiDriver->transfer((command >> 8) & 0xFF);
1762  interface->spiDriver->transfer(command & 0xFF);
1763 
1764  //Read 8-bit data
1765  data = interface->spiDriver->transfer(0xFF);
1766 
1767  //Terminate the operation by raising the CS pin
1768  interface->spiDriver->deassertCs();
1769  }
1770  else
1771  {
1772  //The MDC/MDIO interface does not have access to all the configuration
1773  //registers. It can only access the standard MIIM registers
1774  data = 0;
1775  }
1776 
1777  //Return register value
1778  return data;
1779 }
1780 
1781 
1782 /**
1783  * @brief Write switch register (16 bits)
1784  * @param[in] interface Underlying network interface
1785  * @param[in] address Switch register address
1786  * @param[in] data Register value
1787  **/
1788 
1790  uint16_t data)
1791 {
1792  uint32_t command;
1793 
1794  //SPI slave mode?
1795  if(interface->spiDriver != NULL)
1796  {
1797  //Set up a write operation
1798  command = LAN9646_SPI_CMD_WRITE;
1799  //Set register address
1800  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1801 
1802  //Pull the CS pin low
1803  interface->spiDriver->assertCs();
1804 
1805  //Write 32-bit command
1806  interface->spiDriver->transfer((command >> 24) & 0xFF);
1807  interface->spiDriver->transfer((command >> 16) & 0xFF);
1808  interface->spiDriver->transfer((command >> 8) & 0xFF);
1809  interface->spiDriver->transfer(command & 0xFF);
1810 
1811  //Write 16-bit data
1812  interface->spiDriver->transfer((data >> 8) & 0xFF);
1813  interface->spiDriver->transfer(data & 0xFF);
1814 
1815  //Terminate the operation by raising the CS pin
1816  interface->spiDriver->deassertCs();
1817  }
1818  else
1819  {
1820  //The MDC/MDIO interface does not have access to all the configuration
1821  //registers. It can only access the standard MIIM registers
1822  }
1823 }
1824 
1825 
1826 /**
1827  * @brief Read switch register (16 bits)
1828  * @param[in] interface Underlying network interface
1829  * @param[in] address Switch register address
1830  * @return Register value
1831  **/
1832 
1833 uint16_t lan9646ReadSwitchReg16(NetInterface *interface, uint16_t address)
1834 {
1835  uint16_t data;
1836  uint32_t command;
1837 
1838  //SPI slave mode?
1839  if(interface->spiDriver != NULL)
1840  {
1841  //Set up a read operation
1842  command = LAN9646_SPI_CMD_READ;
1843  //Set register address
1844  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1845 
1846  //Pull the CS pin low
1847  interface->spiDriver->assertCs();
1848 
1849  //Write 32-bit command
1850  interface->spiDriver->transfer((command >> 24) & 0xFF);
1851  interface->spiDriver->transfer((command >> 16) & 0xFF);
1852  interface->spiDriver->transfer((command >> 8) & 0xFF);
1853  interface->spiDriver->transfer(command & 0xFF);
1854 
1855  //Read 16-bit data
1856  data = interface->spiDriver->transfer(0xFF) << 8;
1857  data |= interface->spiDriver->transfer(0xFF);
1858 
1859  //Terminate the operation by raising the CS pin
1860  interface->spiDriver->deassertCs();
1861  }
1862  else
1863  {
1864  //The MDC/MDIO interface does not have access to all the configuration
1865  //registers. It can only access the standard MIIM registers
1866  data = 0;
1867  }
1868 
1869  //Return register value
1870  return data;
1871 }
1872 
1873 
1874 /**
1875  * @brief Write switch register (32 bits)
1876  * @param[in] interface Underlying network interface
1877  * @param[in] address Switch register address
1878  * @param[in] data Register value
1879  **/
1880 
1882  uint32_t data)
1883 {
1884  uint32_t command;
1885 
1886  //SPI slave mode?
1887  if(interface->spiDriver != NULL)
1888  {
1889  //Set up a write operation
1890  command = LAN9646_SPI_CMD_WRITE;
1891  //Set register address
1892  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1893 
1894  //Pull the CS pin low
1895  interface->spiDriver->assertCs();
1896 
1897  //Write 32-bit command
1898  interface->spiDriver->transfer((command >> 24) & 0xFF);
1899  interface->spiDriver->transfer((command >> 16) & 0xFF);
1900  interface->spiDriver->transfer((command >> 8) & 0xFF);
1901  interface->spiDriver->transfer(command & 0xFF);
1902 
1903  //Write 32-bit data
1904  interface->spiDriver->transfer((data >> 24) & 0xFF);
1905  interface->spiDriver->transfer((data >> 16) & 0xFF);
1906  interface->spiDriver->transfer((data >> 8) & 0xFF);
1907  interface->spiDriver->transfer(data & 0xFF);
1908 
1909  //Terminate the operation by raising the CS pin
1910  interface->spiDriver->deassertCs();
1911  }
1912  else
1913  {
1914  //The MDC/MDIO interface does not have access to all the configuration
1915  //registers. It can only access the standard MIIM registers
1916  }
1917 }
1918 
1919 
1920 /**
1921  * @brief Read switch register (32 bits)
1922  * @param[in] interface Underlying network interface
1923  * @param[in] address Switch register address
1924  * @return Register value
1925  **/
1926 
1927 uint32_t lan9646ReadSwitchReg32(NetInterface *interface, uint16_t address)
1928 {
1929  uint32_t data;
1930  uint32_t command;
1931 
1932  //SPI slave mode?
1933  if(interface->spiDriver != NULL)
1934  {
1935  //Set up a read operation
1936  command = LAN9646_SPI_CMD_READ;
1937  //Set register address
1938  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1939 
1940  //Pull the CS pin low
1941  interface->spiDriver->assertCs();
1942 
1943  //Write 32-bit command
1944  interface->spiDriver->transfer((command >> 24) & 0xFF);
1945  interface->spiDriver->transfer((command >> 16) & 0xFF);
1946  interface->spiDriver->transfer((command >> 8) & 0xFF);
1947  interface->spiDriver->transfer(command & 0xFF);
1948 
1949  //Read 32-bit data
1950  data = interface->spiDriver->transfer(0xFF) << 24;
1951  data |= interface->spiDriver->transfer(0xFF) << 16;
1952  data |= interface->spiDriver->transfer(0xFF) << 8;
1953  data |= interface->spiDriver->transfer(0xFF);
1954 
1955  //Terminate the operation by raising the CS pin
1956  interface->spiDriver->deassertCs();
1957  }
1958  else
1959  {
1960  //The MDC/MDIO interface does not have access to all the configuration
1961  //registers. It can only access the standard MIIM registers
1962  data = 0;
1963  }
1964 
1965  //Return register value
1966  return data;
1967 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
void lan9646WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
__weak_func void lan9646InitHook(NetInterface *interface)
LAN9646 custom configuration.
uint16_t lan9646ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
#define LAN9646_PORTn_XMII_CTRL1_SPEED_1000
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
SwitchPortState lan9646GetPortState(NetInterface *interface, uint8_t port)
Get port state.
#define LAN9646_PORT6_XMII_CTRL0
void lan9646EventHandler(NetInterface *interface)
LAN9646 event handler.
int bool_t
Definition: compiler_port.h:61
@ ERROR_NOT_FOUND
Definition: error.h:148
#define LAN9646_ALU_TABLE_ENTRY2_PORT3_FORWARD
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
uint32_t destPorts
Definition: nic.h:152
#define LAN9646_CHIP_ID1
#define netEvent
Definition: net_legacy.h:196
#define LAN9646_PORTn_XMII_CTRL1_RGMII_ID_EG
void lan9646DisableIrq(NetInterface *interface)
Disable interrupts.
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define LAN9646_SPI_CMD_ADDR
void lan9646WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
#define LAN9646_PHYCON_SPEED_10BT
#define LAN9646_ALU_TABLE_ENTRY2_PORT1_FORWARD
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
void lan9646FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
#define LAN9646_STATIC_TABLE_ENTRY2_OVERRIDE
void lan9646FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
@ ERROR_END_OF_TABLE
Definition: error.h:292
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
#define LAN9646_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define LAN9646_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
#define LAN9646_BMSR_LINK_STATUS
#define LAN9646_SWITCH_MAC_CTRL0
#define TRUE
Definition: os_port.h:50
#define LAN9646_MMDACR_DEVAD
uint8_t data[]
Definition: ethernet.h:224
#define LAN9646_ALU_TABLE_ENTRY2_PORT_FORWARD
#define LAN9646_TAIL_TAG_NORMAL_ADDR_LOOKUP
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
error_t lan9646DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
#define LAN9646_SWITCH_LUE_CTRL2_FLUSH_OPTION
uint8_t type
Definition: coap_common.h:176
#define LAN9646_ALU_TABLE_CTRL_ACTION_SEARCH
#define NET_INTERFACE_COUNT
Definition: net.h:115
#define LAN9646_ALU_TABLE_ENTRY2_PORT6_FORWARD
void lan9646EnableIrq(NetInterface *interface)
Enable interrupts.
@ ERROR_INVALID_PORT
Definition: error.h:104
#define LAN9646_STATIC_MCAST_TABLE_CTRL_START_FINISH
#define LAN9646_MMDAADR
void lan9646SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
@ ERROR_TABLE_FULL
Definition: error.h:291
#define LAN9646_SWITCH_OP
#define LAN9646_TAIL_TAG_SRC_PORT
error_t lan9646AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
#define LAN9646_TAIL_TAG_DEST_PORT1
error_t lan9646GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
EthHeader
Definition: ethernet.h:225
#define LAN9646_PORTn_MSTP_STATE_RECEIVE_EN
#define LAN9646_PHYCON_SPEED_100BTX
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD
#define SMI_OPCODE_WRITE
Definition: nic.h:66
uint32_t lan9646GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
#define LAN9646_PORT2
#define LAN9646_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
#define LAN9646_ALU_TABLE_ENTRY3
#define LAN9646_PORTn_XMII_CTRL0_DUPLEX
#define LAN9646_PORTn_XMII_CTRL0_SPEED_10_100
uint16_t lan9646ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
#define FALSE
Definition: os_port.h:46
#define LAN9646_PORT4
void lan9646EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
#define LAN9646_MMD_LED_MODE
#define LAN9646_MMDACR
error_t
Error codes.
Definition: error.h:43
#define netInterface
Definition: net_legacy.h:199
#define LAN9646_PORT1
#define LAN9646_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
#define LAN9646_STATIC_TABLE_ENTRY2
#define LAN9646_TAIL_TAG_DEST_PORT3
#define LAN9646_PORT6_OP_CTRL0
#define LAN9646_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
LAN9646 6-port Gigabit Ethernet switch driver.
NicDuplexMode lan9646GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
#define LAN9646_ALU_TABLE_CTRL_START_FINISH
#define LAN9646_MMD_EEE_ADV
#define LAN9646_MMDACR_FUNC_DATA_NO_POST_INC
#define LAN9646_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN
#define LAN9646_MMD_LED_MODE_RESERVED_DEFAULT
void lan9646SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
void lan9646DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
#define NetRxAncillary
Definition: net_misc.h:40
void lan9646WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
#define NetInterface
Definition: net.h:36
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void lan9646WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
uint32_t lan9646ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
#define LAN9646_ALU_TABLE_ENTRY1
#define LAN9646_ALU_TABLE_CTRL
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
#define LAN9646_SPI_CMD_READ
void lan9646WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
#define LAN9646_SPI_CMD_WRITE
#define LAN9646_GLOBAL_PORT_MIRROR_SNOOP_CTRL
#define NetTxAncillary
Definition: net_misc.h:36
#define LAN9646_BMSR
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
uint8_t lan9646ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
#define LAN9646_SWITCH_LUE_CTRL2
#define TRACE_INFO(...)
Definition: debug.h:105
#define LAN9646_PORT6
#define LAN9646_ALU_TABLE_ENTRY2_PORT2_FORWARD
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 LAN9646_PORTn_ETH_PHY_REG(port, addr)
#define LAN9646_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
#define MIN(a, b)
Definition: os_port.h:63
void lan9646EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
error_t lan9646UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
#define LAN9646_STATIC_TABLE_ENTRY1_VALID
#define LAN9646_TAIL_TAG_DEST_PORT2
#define LAN9646_PORT3
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
#define LAN9646_TAIL_TAG_PORT_BLOCKING_OVERRIDE
uint16_t port
Definition: dns_common.h:269
#define LAN9646_PHYCON_SPEED_1000BT
const SwitchDriver lan9646SwitchDriver
LAN9646 Ethernet switch driver.
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define LAN9646_PHYCON_DUPLEX_STATUS
#define LAN9646_STATIC_MCAST_TABLE_CTRL_ACTION
#define LAN9646_TAIL_TAG_DEST_PORT4
#define LAN9646_STATIC_MAC_TABLE_SIZE
#define LAN9646_STATIC_TABLE_ENTRY1
uint16_t regAddr
Ethernet switch driver.
Definition: nic.h:325
#define LAN9646_STATIC_TABLE_ENTRY4
#define LAN9646_PORT7
error_t lan9646TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
#define LAN9646_ALU_TABLE_ENTRY4
#define LAN9646_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
#define LAN9646_PORT_MASK
@ ERROR_INVALID_ENTRY
Definition: error.h:290
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
Ipv6Addr address[]
Definition: ipv6.h:325
#define LAN9646_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
#define LAN9646_ALU_TABLE_ENTRY2_PORT7_FORWARD
NicDuplexMode
Duplex mode.
Definition: nic.h:122
#define LAN9646_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
MacAddr macAddr
Definition: nic.h:150
#define LAN9646_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
uint8_t srcPort
Definition: nic.h:151
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
uint8_t value[]
Definition: tcp.h:376
#define LAN9646_CHIP_ID1_DEFAULT
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
error_t lan9646GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
#define LAN9646_STATIC_TABLE_ENTRY3
#define LAN9646_PORTn_XMII_CTRL1_IF_TYPE_RGMII
#define LAN9646_PORTn_MSTP_STATE(port)
#define LAN9646_UNKONWN_MULTICAST_CTRL
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define LAN9646_PHYCON
#define LAN9646_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define LAN9646_PORT6_MASK
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define LAN9646_STATIC_MCAST_TABLE_CTRL
#define LAN9646_SWITCH_LUE_CTRL1
#define LAN9646_ALU_TABLE_CTRL_VALID
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT6
#define LAN9646_ALU_TABLE_ENTRY2
#define LAN9646_PORTn_XMII_CTRL1_RGMII_ID_IG
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define LAN9646_MMDACR_FUNC_ADDR
#define LAN9646_SWITCH_LUE_CTRL0
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
#define LAN9646_PORT6_XMII_CTRL1
#define LAN9646_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
#define LAN9646_MMD_LED_MODE_LED_MODE_TRI_COLOR_DUAL
error_t lan9646Init(NetInterface *interface)
LAN9646 Ethernet switch initialization.
#define LAN9646_PORTn_OP_CTRL0_TAIL_TAG_EN
#define LAN9646_PORTn_XMII_CTRL1_IF_TYPE
void lan9646EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
void lan9646SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
uint16_t lan9646ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void lan9646Tick(NetInterface *interface)
LAN9646 timer handler.
#define LAN9646_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
const uint16_t lan9646IngressTailTag[6]
Tail tag rules (host to LAN9646)
Helper functions for Ethernet.
#define LAN9646_SWITCH_OP_START_SWITCH
bool_t lan9646GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
#define LAN9646_ALU_TABLE_ENTRY2_PORT4_FORWARD
@ NO_ERROR
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:153
Debugging facilities.
Forwarding database entry.
Definition: nic.h:149
#define LAN9646_PORTn_MSTP_STATE_LEARNING_DIS
#define LAN9646_SWITCH_LUE_CTRL3