ksz8565_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz8565_driver.c
3  * @brief KSZ8565 5-port 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"
36 #include "core/ethernet_misc.h"
38 #include "debug.h"
39 
40 
41 /**
42  * @brief KSZ8565 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to KSZ8565)
75  **/
76 
77 const uint16_t ksz8565IngressTailTag[5] =
78 {
84 };
85 
86 
87 /**
88  * @brief KSZ8565 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 KSZ8565...\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 = ksz8565ReadSwitchReg8(interface, KSZ8565_CHIP_ID1);
112 
113  //The returned data is invalid until the serial interface is ready
114  } while(temp != KSZ8565_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 11)
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  ksz8565WriteMmdReg(interface, port, 0x01, 0x6F, 0xDD0B);
190  ksz8565WriteMmdReg(interface, port, 0x01, 0x8F, 0x6032);
191  ksz8565WriteMmdReg(interface, port, 0x01, 0x9D, 0x248C);
192  ksz8565WriteMmdReg(interface, port, 0x01, 0x75, 0x0060);
193  ksz8565WriteMmdReg(interface, port, 0x01, 0xD3, 0x7777);
194  ksz8565WriteMmdReg(interface, port, 0x1C, 0x06, 0x3008);
195  ksz8565WriteMmdReg(interface, port, 0x1C, 0x08, 0x2001);
196 
197  //Improve transmit waveform amplitude (silicon errata workaround 2)
198  ksz8565WriteMmdReg(interface, port, 0x1C, 0x04, 0x00D0);
199 
200  //EEE must be manually disabled (silicon errata workaround 3)
202 
203  //Adjust power supply settings (silicon errata workaround 6)
204  ksz8565WriteMmdReg(interface, port, 0x1C, 0x13, 0x6EFF);
205  ksz8565WriteMmdReg(interface, port, 0x1C, 0x14, 0xE6FF);
206  ksz8565WriteMmdReg(interface, port, 0x1C, 0x15, 0x6EFF);
207  ksz8565WriteMmdReg(interface, port, 0x1C, 0x16, 0xE6FF);
208  ksz8565WriteMmdReg(interface, port, 0x1C, 0x17, 0x00FF);
209  ksz8565WriteMmdReg(interface, port, 0x1C, 0x18, 0x43FF);
210  ksz8565WriteMmdReg(interface, port, 0x1C, 0x19, 0xC3FF);
211  ksz8565WriteMmdReg(interface, port, 0x1C, 0x1A, 0x6FFF);
212  ksz8565WriteMmdReg(interface, port, 0x1C, 0x1B, 0x07FF);
213  ksz8565WriteMmdReg(interface, port, 0x1C, 0x1C, 0x0FFF);
214  ksz8565WriteMmdReg(interface, port, 0x1C, 0x1D, 0xE7FF);
215  ksz8565WriteMmdReg(interface, port, 0x1C, 0x1E, 0xEFFF);
216  ksz8565WriteMmdReg(interface, port, 0x1C, 0x20, 0xEEEE);
217 
218  //Select single-LED mode
222 
223  //Implement workaround for single-LED mode
224  ksz8565WritePhyReg(interface, port, 0x1E, 0xFA00);
225 
226  //Debug message
227  TRACE_DEBUG("Port %u:\r\n", port);
228  //Dump PHY registers for debugging purpose
229  ksz8565DumpPhyReg(interface, port);
230  }
231 
232  //Perform custom configuration
233  ksz8565InitHook(interface);
234 
235  //Force the TCP/IP stack to poll the link state at startup
236  interface->phyEvent = TRUE;
237  //Notify the TCP/IP stack of the event
239 
240  //Successful initialization
241  return NO_ERROR;
242 }
243 
244 
245 /**
246  * @brief KSZ8565 custom configuration
247  * @param[in] interface Underlying network interface
248  **/
249 
250 __weak_func void ksz8565InitHook(NetInterface *interface)
251 {
252 }
253 
254 
255 /**
256  * @brief KSZ8565 timer handler
257  * @param[in] interface Underlying network interface
258  **/
259 
260 void ksz8565Tick(NetInterface *interface)
261 {
262  uint_t port;
263  bool_t linkState;
264 
265 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
266  //Port separation mode?
267  if(interface->port != 0)
268  {
269  uint_t i;
270  NetInterface *virtualInterface;
271 
272  //Loop through network interfaces
273  for(i = 0; i < NET_INTERFACE_COUNT; i++)
274  {
275  //Point to the current interface
276  virtualInterface = &netInterface[i];
277 
278  //Check whether the current virtual interface is attached to the
279  //physical interface
280  if(virtualInterface == interface ||
281  virtualInterface->parent == interface)
282  {
283  //Retrieve current link state
284  linkState = ksz8565GetLinkState(interface, virtualInterface->port);
285 
286  //Link up or link down event?
287  if(linkState != virtualInterface->linkState)
288  {
289  //Set event flag
290  interface->phyEvent = TRUE;
291  //Notify the TCP/IP stack of the event
293  }
294  }
295  }
296  }
297  else
298 #endif
299  {
300  //Initialize link state
301  linkState = FALSE;
302 
303  //Loop through the ports
305  {
306  //Retrieve current link state
307  if(ksz8565GetLinkState(interface, port))
308  {
309  linkState = TRUE;
310  }
311  }
312 
313  //Link up or link down event?
314  if(linkState != interface->linkState)
315  {
316  //Set event flag
317  interface->phyEvent = TRUE;
318  //Notify the TCP/IP stack of the event
320  }
321  }
322 }
323 
324 
325 /**
326  * @brief Enable interrupts
327  * @param[in] interface Underlying network interface
328  **/
329 
331 {
332 }
333 
334 
335 /**
336  * @brief Disable interrupts
337  * @param[in] interface Underlying network interface
338  **/
339 
341 {
342 }
343 
344 
345 /**
346  * @brief KSZ8565 event handler
347  * @param[in] interface Underlying network interface
348  **/
349 
351 {
352  uint_t port;
353  bool_t linkState;
354 
355 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
356  //Port separation mode?
357  if(interface->port != 0)
358  {
359  uint_t i;
360  NetInterface *virtualInterface;
361 
362  //Loop through network interfaces
363  for(i = 0; i < NET_INTERFACE_COUNT; i++)
364  {
365  //Point to the current interface
366  virtualInterface = &netInterface[i];
367 
368  //Check whether the current virtual interface is attached to the
369  //physical interface
370  if(virtualInterface == interface ||
371  virtualInterface->parent == interface)
372  {
373  //Get the port number associated with the current interface
374  port = virtualInterface->port;
375 
376  //Valid port?
377  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
378  {
379  //Retrieve current link state
380  linkState = ksz8565GetLinkState(interface, port);
381 
382  //Link up event?
383  if(linkState && !virtualInterface->linkState)
384  {
385  //Retrieve host interface speed
386  interface->linkSpeed = ksz8565GetLinkSpeed(interface,
387  KSZ8565_PORT5);
388 
389  //Retrieve host interface duplex mode
390  interface->duplexMode = ksz8565GetDuplexMode(interface,
391  KSZ8565_PORT5);
392 
393  //Adjust MAC configuration parameters for proper operation
394  interface->nicDriver->updateMacConfig(interface);
395 
396  //Check current speed
397  virtualInterface->linkSpeed = ksz8565GetLinkSpeed(interface,
398  port);
399 
400  //Check current duplex mode
401  virtualInterface->duplexMode = ksz8565GetDuplexMode(interface,
402  port);
403 
404  //Update link state
405  virtualInterface->linkState = TRUE;
406 
407  //Process link state change event
408  nicNotifyLinkChange(virtualInterface);
409  }
410  //Link down event
411  else if(!linkState && virtualInterface->linkState)
412  {
413  //Update link state
414  virtualInterface->linkState = FALSE;
415 
416  //Process link state change event
417  nicNotifyLinkChange(virtualInterface);
418  }
419  }
420  }
421  }
422  }
423  else
424 #endif
425  {
426  //Initialize link state
427  linkState = FALSE;
428 
429  //Loop through the ports
431  {
432  //Retrieve current link state
433  if(ksz8565GetLinkState(interface, port))
434  {
435  linkState = TRUE;
436  }
437  }
438 
439  //Link up event?
440  if(linkState)
441  {
442  //Retrieve host interface speed
443  interface->linkSpeed = ksz8565GetLinkSpeed(interface, KSZ8565_PORT5);
444  //Retrieve host interface duplex mode
445  interface->duplexMode = ksz8565GetDuplexMode(interface, KSZ8565_PORT5);
446 
447  //Adjust MAC configuration parameters for proper operation
448  interface->nicDriver->updateMacConfig(interface);
449 
450  //Update link state
451  interface->linkState = TRUE;
452  }
453  else
454  {
455  //Update link state
456  interface->linkState = FALSE;
457  }
458 
459  //Process link state change event
460  nicNotifyLinkChange(interface);
461  }
462 }
463 
464 
465 /**
466  * @brief Add tail tag to Ethernet frame
467  * @param[in] interface Underlying network interface
468  * @param[in] buffer Multi-part buffer containing the payload
469  * @param[in,out] offset Offset to the first payload byte
470  * @param[in] ancillary Additional options passed to the stack along with
471  * the packet
472  * @return Error code
473  **/
474 
476  size_t *offset, NetTxAncillary *ancillary)
477 {
478  error_t error;
479 
480  //Initialize status code
481  error = NO_ERROR;
482 
483 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
484  //SPI slave mode?
485  if(interface->spiDriver != NULL)
486  {
487  //Valid port?
488  if(ancillary->port <= KSZ8565_PORT5)
489  {
490  size_t length;
491  const uint16_t *tailTag;
492 
493  //The two-byte tail tagging is used to indicate the destination port
494  tailTag = &ksz8565IngressTailTag[ancillary->port];
495 
496  //Retrieve the length of the Ethernet frame
497  length = netBufferGetLength(buffer) - *offset;
498 
499  //The host controller should manually add padding to the packet before
500  //inserting the tail tag
501  error = ethPadFrame(buffer, &length);
502 
503  //Check status code
504  if(!error)
505  {
506  //The tail tag is inserted at the end of the packet, just before
507  //the CRC
508  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
509  }
510  }
511  else
512  {
513  //The port number is not valid
514  error = ERROR_INVALID_PORT;
515  }
516  }
517 #endif
518 
519  //Return status code
520  return error;
521 }
522 
523 
524 /**
525  * @brief Decode tail tag from incoming Ethernet frame
526  * @param[in] interface Underlying network interface
527  * @param[in,out] frame Pointer to the received Ethernet frame
528  * @param[in,out] length Length of the frame, in bytes
529  * @param[in,out] ancillary Additional options passed to the stack along with
530  * the packet
531  * @return Error code
532  **/
533 
534 error_t ksz8565UntagFrame(NetInterface *interface, uint8_t **frame,
535  size_t *length, NetRxAncillary *ancillary)
536 {
537  error_t error;
538 
539  //Initialize status code
540  error = NO_ERROR;
541 
542 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
543  //SPI slave mode?
544  if(interface->spiDriver != NULL)
545  {
546  //Valid Ethernet frame received?
547  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
548  {
549  uint8_t *tailTag;
550 
551  //The tail tag is inserted at the end of the packet, just before
552  //the CRC
553  tailTag = *frame + *length - sizeof(uint8_t);
554 
555  //The one byte tail tagging is used to indicate the source port
556  ancillary->port = (*tailTag & KSZ8565_TAIL_TAG_SRC_PORT) + 1;
557 
558  //Strip tail tag from Ethernet frame
559  *length -= sizeof(uint8_t);
560  }
561  else
562  {
563  //Drop the received frame
564  error = ERROR_INVALID_LENGTH;
565  }
566  }
567  else
568  {
569  //Tail tagging mode cannot be enabled through MDC/MDIO interface
570  ancillary->port = 0;
571  }
572 #endif
573 
574  //Return status code
575  return error;
576 }
577 
578 
579 /**
580  * @brief Get link state
581  * @param[in] interface Underlying network interface
582  * @param[in] port Port number
583  * @return Link state
584  **/
585 
587 {
588  uint16_t value;
589  bool_t linkState;
590 
591  //Check port number
592  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
593  {
594  //Any link failure condition is latched in the BMSR register. Reading
595  //the register twice will always return the actual link status
596  value = ksz8565ReadPhyReg(interface, port, KSZ8565_BMSR);
597  value = ksz8565ReadPhyReg(interface, port, KSZ8565_BMSR);
598 
599  //Retrieve current link state
600  linkState = (value & KSZ8565_BMSR_LINK_STATUS) ? TRUE : FALSE;
601  }
602  else
603  {
604  //The specified port number is not valid
605  linkState = FALSE;
606  }
607 
608  //Return link status
609  return linkState;
610 }
611 
612 
613 /**
614  * @brief Get link speed
615  * @param[in] interface Underlying network interface
616  * @param[in] port Port number
617  * @return Link speed
618  **/
619 
620 uint32_t ksz8565GetLinkSpeed(NetInterface *interface, uint8_t port)
621 {
622  uint8_t type;
623  uint16_t value;
624  uint32_t linkSpeed;
625 
626  //Check port number
627  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
628  {
629  //Read PHY control register
631 
632  //Retrieve current link speed
634  {
635  //100BASE-TX
636  linkSpeed = NIC_LINK_SPEED_100MBPS;
637  }
638  else if((value & KSZ8565_PHYCON_SPEED_10BT) != 0)
639  {
640  //10BASE-T
641  linkSpeed = NIC_LINK_SPEED_10MBPS;
642  }
643  else
644  {
645  //The link speed is not valid
646  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
647  }
648  }
649  else if(port == KSZ8565_PORT5)
650  {
651  //SPI slave mode?
652  if(interface->spiDriver != NULL)
653  {
654  //Read port 5 XMII control 1 register
656 
657  //Retrieve host interface type
659 
660  //Gigabit interface?
663  {
664  //1000 Mb/s mode
665  linkSpeed = NIC_LINK_SPEED_1GBPS;
666  }
667  else
668  {
669  //Read port 5 XMII control 0 register
671 
672  //Retrieve host interface speed
674  {
675  //100 Mb/s mode
676  linkSpeed = NIC_LINK_SPEED_100MBPS;
677  }
678  else
679  {
680  //10 Mb/s mode
681  linkSpeed = NIC_LINK_SPEED_10MBPS;
682  }
683  }
684  }
685  else
686  {
687  //The MDC/MDIO interface does not have access to all the configuration
688  //registers. It can only access the standard MIIM registers
689  linkSpeed = NIC_LINK_SPEED_100MBPS;
690  }
691  }
692  else
693  {
694  //The specified port number is not valid
695  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
696  }
697 
698  //Return link status
699  return linkSpeed;
700 }
701 
702 
703 /**
704  * @brief Get duplex mode
705  * @param[in] interface Underlying network interface
706  * @param[in] port Port number
707  * @return Duplex mode
708  **/
709 
711 {
712  uint16_t value;
713  NicDuplexMode duplexMode;
714 
715  //Check port number
716  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
717  {
718  //Read PHY control register
720 
721  //Retrieve current duplex mode
723  {
724  duplexMode = NIC_FULL_DUPLEX_MODE;
725  }
726  else
727  {
728  duplexMode = NIC_HALF_DUPLEX_MODE;
729  }
730  }
731  else if(port == KSZ8565_PORT5)
732  {
733  //SPI slave mode?
734  if(interface->spiDriver != NULL)
735  {
736  //Read port 5 XMII control 0 register
738 
739  //Retrieve host interface duplex mode
741  {
742  duplexMode = NIC_FULL_DUPLEX_MODE;
743  }
744  else
745  {
746  duplexMode = NIC_HALF_DUPLEX_MODE;
747  }
748  }
749  else
750  {
751  //The MDC/MDIO interface does not have access to all the configuration
752  //registers. It can only access the standard MIIM registers
753  duplexMode = NIC_FULL_DUPLEX_MODE;
754  }
755  }
756  else
757  {
758  //The specified port number is not valid
759  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
760  }
761 
762  //Return duplex mode
763  return duplexMode;
764 }
765 
766 
767 /**
768  * @brief Set port state
769  * @param[in] interface Underlying network interface
770  * @param[in] port Port number
771  * @param[in] state Port state
772  **/
773 
774 void ksz8565SetPortState(NetInterface *interface, uint8_t port,
775  SwitchPortState state)
776 {
777  uint8_t temp;
778 
779  //Check port number
780  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
781  {
782  //Read MSTP state register
784 
785  //Update port state
786  switch(state)
787  {
788  //Listening state
793  break;
794 
795  //Learning state
800  break;
801 
802  //Forwarding state
807  break;
808 
809  //Disabled state
810  default:
814  break;
815  }
816 
817  //Write the value back to MSTP state register
819  }
820 }
821 
822 
823 /**
824  * @brief Get port state
825  * @param[in] interface Underlying network interface
826  * @param[in] port Port number
827  * @return Port state
828  **/
829 
831 {
832  uint8_t temp;
833  SwitchPortState state;
834 
835  //Check port number
836  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
837  {
838  //Read MSTP state register
840 
841  //Check port state
842  if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
843  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
845  {
846  //Disabled state
848  }
849  else if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
850  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
852  {
853  //Listening state
855  }
856  else if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
857  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
859  {
860  //Learning state
862  }
863  else if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
864  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
866  {
867  //Forwarding state
869  }
870  else
871  {
872  //Unknown state
874  }
875  }
876  else
877  {
878  //The specified port number is not valid
880  }
881 
882  //Return port state
883  return state;
884 }
885 
886 
887 /**
888  * @brief Set aging time for dynamic filtering entries
889  * @param[in] interface Underlying network interface
890  * @param[in] agingTime Aging time, in seconds
891  **/
892 
893 void ksz8565SetAgingTime(NetInterface *interface, uint32_t agingTime)
894 {
895  //The Age Period in combination with the Age Count field determines the
896  //aging time of dynamic entries in the address lookup table
897  agingTime = (agingTime + 3) / 4;
898 
899  //Limit the range of the parameter
900  agingTime = MIN(agingTime, 255);
901 
902  //Write the value to Switch Lookup Engine Control 3 register
904  (uint8_t) agingTime);
905 }
906 
907 
908 /**
909  * @brief Enable IGMP snooping
910  * @param[in] interface Underlying network interface
911  * @param[in] enable Enable or disable IGMP snooping
912  **/
913 
915 {
916  uint8_t temp;
917 
918  //Read the Global Port Mirroring and Snooping Control register
919  temp = ksz8565ReadSwitchReg8(interface,
921 
922  //Enable or disable IGMP snooping
923  if(enable)
924  {
926  }
927  else
928  {
930  }
931 
932  //Write the value back to Global Port Mirroring and Snooping Control register
934  temp);
935 }
936 
937 
938 /**
939  * @brief Enable MLD snooping
940  * @param[in] interface Underlying network interface
941  * @param[in] enable Enable or disable MLD snooping
942  **/
943 
945 {
946  uint8_t temp;
947 
948  //Read the Global Port Mirroring and Snooping Control register
949  temp = ksz8565ReadSwitchReg8(interface,
951 
952  //Enable or disable MLD snooping
953  if(enable)
954  {
956  }
957  else
958  {
960  }
961 
962  //Write the value back to Global Port Mirroring and Snooping Control register
964  temp);
965 }
966 
967 
968 /**
969  * @brief Enable reserved multicast table
970  * @param[in] interface Underlying network interface
971  * @param[in] enable Enable or disable reserved group addresses
972  **/
973 
975 {
976  uint8_t temp;
977 
978  //Read the Switch Lookup Engine Control 0 register
980 
981  //Enable or disable the reserved multicast table
982  if(enable)
983  {
985  }
986  else
987  {
989  }
990 
991  //Write the value back to Switch Lookup Engine Control 0 register
993 }
994 
995 
996 /**
997  * @brief Add a new entry to the static MAC table
998  * @param[in] interface Underlying network interface
999  * @param[in] entry Pointer to the forwarding database entry
1000  * @return Error code
1001  **/
1002 
1004  const SwitchFdbEntry *entry)
1005 {
1006  error_t error;
1007  uint_t i;
1008  uint_t j;
1009  uint32_t value;
1010  SwitchFdbEntry currentEntry;
1011 
1012  //Keep track of the first free entry
1014 
1015  //Loop through the static MAC table
1016  for(i = 0; i < KSZ8565_STATIC_MAC_TABLE_SIZE; i++)
1017  {
1018  //Read current entry
1019  error = ksz8565GetStaticFdbEntry(interface, i, &currentEntry);
1020 
1021  //Valid entry?
1022  if(!error)
1023  {
1024  //Check whether the table already contains the specified MAC address
1025  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1026  {
1027  j = i;
1028  break;
1029  }
1030  }
1031  else
1032  {
1033  //Keep track of the first free entry
1035  {
1036  j = i;
1037  }
1038  }
1039  }
1040 
1041  //Any entry available?
1043  {
1044  //Write the Static Address Table Entry 1 register
1047 
1048  //Set the relevant forward ports
1049  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1050  {
1052  }
1053  else
1054  {
1055  value = entry->destPorts & KSZ8565_PORT_MASK;
1056  }
1057 
1058  //Enable overriding of port state
1059  if(entry->override)
1060  {
1062  }
1063 
1064  //Write the Static Address Table Entry 2 register
1066 
1067  //Copy MAC address (first 16 bits)
1068  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1069 
1070  //Write the Static Address Table Entry 3 register
1072 
1073  //Copy MAC address (last 32 bits)
1074  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1075  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1076 
1077  //Write the Static Address Table Entry 4 register
1079 
1080  //Write the TABLE_INDEX field with the 4-bit index value
1082  //Set the TABLE_SELECT bit to 0 to select the static address table
1084  //Set the ACTION bit to 0 to indicate a write operation
1086  //Set the START_FINISH bit to 1 to initiate the operation
1088 
1089  //Start the write operation
1091  value);
1092 
1093  //When the operation is complete, the START_FINISH bit will be cleared
1094  //automatically
1095  do
1096  {
1097  //Read the Static Address and Reserved Multicast Table Control register
1098  value = ksz8565ReadSwitchReg32(interface,
1100 
1101  //Poll the START_FINISH bit
1103 
1104  //Successful processing
1105  error = NO_ERROR;
1106  }
1107  else
1108  {
1109  //The static MAC table is full
1110  error = ERROR_TABLE_FULL;
1111  }
1112 
1113  //Return status code
1114  return error;
1115 }
1116 
1117 
1118 /**
1119  * @brief Remove an entry from the static MAC table
1120  * @param[in] interface Underlying network interface
1121  * @param[in] entry Forwarding database entry to remove from the table
1122  * @return Error code
1123  **/
1124 
1126  const SwitchFdbEntry *entry)
1127 {
1128  error_t error;
1129  uint_t j;
1130  uint32_t value;
1131  SwitchFdbEntry currentEntry;
1132 
1133  //Loop through the static MAC table
1134  for(j = 0; j < KSZ8565_STATIC_MAC_TABLE_SIZE; j++)
1135  {
1136  //Read current entry
1137  error = ksz8565GetStaticFdbEntry(interface, j, &currentEntry);
1138 
1139  //Valid entry?
1140  if(!error)
1141  {
1142  //Check whether the table contains the specified MAC address
1143  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1144  {
1145  break;
1146  }
1147  }
1148  }
1149 
1150  //Any matching entry?
1152  {
1153  //Clear Static Address Table Entry registers
1158 
1159  //Write the TABLE_INDEX field with the 4-bit index value
1161  //Set the TABLE_SELECT bit to 0 to select the static address table
1163  //Set the ACTION bit to 0 to indicate a write operation
1165  //Set the START_FINISH bit to 1 to initiate the operation
1167 
1168  //Start the write operation
1170  value);
1171 
1172  //When the operation is complete, the START_FINISH bit will be cleared
1173  //automatically
1174  do
1175  {
1176  //Read the Static Address and Reserved Multicast Table Control register
1177  value = ksz8565ReadSwitchReg32(interface,
1179 
1180  //Poll the START_FINISH bit
1182 
1183  //Successful processing
1184  error = NO_ERROR;
1185  }
1186  else
1187  {
1188  //The static MAC table does not contain the specified address
1189  error = ERROR_NOT_FOUND;
1190  }
1191 
1192  //Return status code
1193  return error;
1194 }
1195 
1196 
1197 /**
1198  * @brief Read an entry from the static MAC table
1199  * @param[in] interface Underlying network interface
1200  * @param[in] index Zero-based index of the entry to read
1201  * @param[out] entry Pointer to the forwarding database entry
1202  * @return Error code
1203  **/
1204 
1206  SwitchFdbEntry *entry)
1207 {
1208  error_t error;
1209  uint32_t value;
1210 
1211  //Check index parameter
1212  if(index < KSZ8565_STATIC_MAC_TABLE_SIZE)
1213  {
1214  //Write the TABLE_INDEX field with the 4-bit index value
1216  //Set the TABLE_SELECT bit to 0 to select the static address table
1218  //Set the ACTION bit to 1 to indicate a read operation
1220  //Set the START_FINISH bit to 1 to initiate the operation
1222 
1223  //Start the read operation
1225  value);
1226 
1227  //When the operation is complete, the START_FINISH bit will be cleared
1228  //automatically
1229  do
1230  {
1231  //Read the Static Address and Reserved Multicast Table Control register
1232  value = ksz8565ReadSwitchReg32(interface,
1234 
1235  //Poll the START_FINISH bit
1237 
1238  //Read the Static Address Table Entry 1 register
1240 
1241  //Valid entry?
1243  {
1244  //Read the Static Address Table Entry 2 register
1246 
1247  //Retrieve the ports associated with this MAC address
1248  entry->srcPort = 0;
1250 
1251  //Check the value of the OVERRIDE bit
1253  {
1254  entry->override = TRUE;
1255  }
1256  else
1257  {
1258  entry->override = FALSE;
1259  }
1260 
1261  //Read the Static Address Table Entry 3 register
1263 
1264  //Copy MAC address (first 16 bits)
1265  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1266  entry->macAddr.b[1] = value & 0xFF;
1267 
1268  //Read the Static Address Table Entry 4 register
1270 
1271  //Copy MAC address (last 32 bits)
1272  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1273  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1274  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1275  entry->macAddr.b[5] = value & 0xFF;
1276 
1277  //Successful processing
1278  error = NO_ERROR;
1279  }
1280  else
1281  {
1282  //The entry is not valid
1283  error = ERROR_INVALID_ENTRY;
1284  }
1285  }
1286  else
1287  {
1288  //The end of the table has been reached
1289  error = ERROR_END_OF_TABLE;
1290  }
1291 
1292  //Return status code
1293  return error;
1294 }
1295 
1296 
1297 /**
1298  * @brief Flush static MAC table
1299  * @param[in] interface Underlying network interface
1300  **/
1301 
1303 {
1304  uint_t i;
1305  uint32_t value;
1306 
1307  //Loop through the static MAC table
1308  for(i = 0; i < KSZ8565_STATIC_MAC_TABLE_SIZE; i++)
1309  {
1310  //Clear Static Address Table Entry registers
1315 
1316  //Write the TABLE_INDEX field with the 4-bit index value
1318  //Set the TABLE_SELECT bit to 0 to select the static address table
1320  //Set the ACTION bit to 0 to indicate a write operation
1322  //Set the START_FINISH bit to 1 to initiate the operation
1324 
1325  //Start the write operation
1327  value);
1328 
1329  //When the operation is complete, the START_FINISH bit will be cleared
1330  //automatically
1331  do
1332  {
1333  //Read the Static Address and Reserved Multicast Table Control register
1334  value = ksz8565ReadSwitchReg32(interface,
1336 
1337  //Poll the START_FINISH bit
1339  }
1340 }
1341 
1342 
1343 /**
1344  * @brief Read an entry from the dynamic MAC table
1345  * @param[in] interface Underlying network interface
1346  * @param[in] index Zero-based index of the entry to read
1347  * @param[out] entry Pointer to the forwarding database entry
1348  * @return Error code
1349  **/
1350 
1352  SwitchFdbEntry *entry)
1353 {
1354  error_t error;
1355  uint32_t value;
1356 
1357  //First entry?
1358  if(index == 0)
1359  {
1360  //Clear the ALU Table Access Control register to stop any operation
1362 
1363  //Start the search operation
1367  }
1368 
1369  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1370  do
1371  {
1372  //Read the ALU Table Access Control register
1374 
1375  //This bit goes high to indicate either a new valid entry is returned or
1376  //the search is complete
1378 
1379  //Check whether the next valid entry is ready
1380  if((value & KSZ8565_ALU_TABLE_CTRL_VALID) != 0)
1381  {
1382  //Store the data from the ALU table entry
1383  entry->destPorts = 0;
1384  entry->override = FALSE;
1385 
1386  //Read the ALU Table Entry 1 and 2 registers
1389 
1390  //Retrieve the port associated with this MAC address
1392  {
1394  entry->srcPort = KSZ8565_PORT1;
1395  break;
1397  entry->srcPort = KSZ8565_PORT2;
1398  break;
1400  entry->srcPort = KSZ8565_PORT3;
1401  break;
1403  entry->srcPort = KSZ8565_PORT4;
1404  break;
1406  entry->srcPort = KSZ8565_PORT5;
1407  break;
1408  default:
1409  entry->srcPort = 0;
1410  break;
1411  }
1412 
1413  //Read the ALU Table Entry 3 register
1415 
1416  //Copy MAC address (first 16 bits)
1417  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1418  entry->macAddr.b[1] = value & 0xFF;
1419 
1420  //Read the ALU Table Entry 4 register
1422 
1423  //Copy MAC address (last 32 bits)
1424  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1425  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1426  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1427  entry->macAddr.b[5] = value & 0xFF;
1428 
1429  //Successful processing
1430  error = NO_ERROR;
1431  }
1432  else
1433  {
1434  //The search can be stopped any time by setting the START_FINISH bit to 0
1436 
1437  //The end of the table has been reached
1438  error = ERROR_END_OF_TABLE;
1439  }
1440 
1441  //Return status code
1442  return error;
1443 }
1444 
1445 
1446 /**
1447  * @brief Flush dynamic MAC table
1448  * @param[in] interface Underlying network interface
1449  * @param[in] port Port number
1450  **/
1451 
1453 {
1454  uint_t temp;
1455  uint8_t state;
1456 
1457  //Flush only dynamic table entries
1462 
1463  //Valid port number?
1464  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT5 &&
1466  {
1467  //Save the current state of the port
1469 
1470  //Turn off learning capability
1473 
1474  //All the entries associated with a port that has its learning capability
1475  //being turned off will be flushed
1479 
1480  //Restore the original state of the port
1482  }
1483  else
1484  {
1485  //Trigger a flush of the entire address lookup table
1489  }
1490 }
1491 
1492 
1493 /**
1494  * @brief Set forward ports for unknown multicast packets
1495  * @param[in] interface Underlying network interface
1496  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1497  * @param[in] forwardPorts Port map
1498  **/
1499 
1501  bool_t enable, uint32_t forwardPorts)
1502 {
1503  uint32_t temp;
1504 
1505  //Read Unknown Multicast Control register
1507 
1508  //Clear port map
1510 
1511  //Enable or disable forwarding of unknown multicast packets
1512  if(enable)
1513  {
1514  //Enable forwarding
1516 
1517  //Check whether unknown multicast packets should be forwarded to the CPU port
1518  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1519  {
1521  }
1522 
1523  //Select the desired forward ports
1524  temp |= forwardPorts & KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL;
1525  }
1526  else
1527  {
1528  //Disable forwarding
1530  }
1531 
1532  //Write the value back to Unknown Multicast Control register
1534 }
1535 
1536 
1537 /**
1538  * @brief Write PHY register
1539  * @param[in] interface Underlying network interface
1540  * @param[in] port Port number
1541  * @param[in] address PHY register address
1542  * @param[in] data Register value
1543  **/
1544 
1545 void ksz8565WritePhyReg(NetInterface *interface, uint8_t port,
1546  uint8_t address, uint16_t data)
1547 {
1548  uint16_t n;
1549 
1550  //SPI slave mode?
1551  if(interface->spiDriver != NULL)
1552  {
1553  //The SPI interface provides access to all PHY registers
1555  //Write the 16-bit value
1556  ksz8565WriteSwitchReg16(interface, n, data);
1557  }
1558  else if(interface->smiDriver != NULL)
1559  {
1560  //Write the specified PHY register
1561  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1562  }
1563  else
1564  {
1565  //Write the specified PHY register
1566  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1567  }
1568 }
1569 
1570 
1571 /**
1572  * @brief Read PHY register
1573  * @param[in] interface Underlying network interface
1574  * @param[in] port Port number
1575  * @param[in] address PHY register address
1576  * @return Register value
1577  **/
1578 
1579 uint16_t ksz8565ReadPhyReg(NetInterface *interface, uint8_t port,
1580  uint8_t address)
1581 {
1582  uint16_t n;
1583  uint16_t data;
1584 
1585  //SPI slave mode?
1586  if(interface->spiDriver != NULL)
1587  {
1588  //The SPI interface provides access to all PHY registers
1590  //Read the 16-bit value
1591  data = ksz8565ReadSwitchReg16(interface, n);
1592  }
1593  else if(interface->smiDriver != NULL)
1594  {
1595  //Read the specified PHY register
1596  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1597  }
1598  else
1599  {
1600  //Read the specified PHY register
1601  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1602  }
1603 
1604  //Return register value
1605  return data;
1606 }
1607 
1608 
1609 /**
1610  * @brief Dump PHY registers for debugging purpose
1611  * @param[in] interface Underlying network interface
1612  * @param[in] port Port number
1613  **/
1614 
1615 void ksz8565DumpPhyReg(NetInterface *interface, uint8_t port)
1616 {
1617  uint8_t i;
1618 
1619  //Loop through PHY registers
1620  for(i = 0; i < 32; i++)
1621  {
1622  //Display current PHY register
1623  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1624  ksz8565ReadPhyReg(interface, port, i));
1625  }
1626 
1627  //Terminate with a line feed
1628  TRACE_DEBUG("\r\n");
1629 }
1630 
1631 
1632 /**
1633  * @brief Write MMD register
1634  * @param[in] interface Underlying network interface
1635  * @param[in] port Port number
1636  * @param[in] devAddr Device address
1637  * @param[in] regAddr Register address
1638  * @param[in] data Register value
1639  **/
1640 
1641 void ksz8565WriteMmdReg(NetInterface *interface, uint8_t port,
1642  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1643 {
1644  //Select register operation
1647 
1648  //Write MMD register address
1650 
1651  //Select data operation
1654 
1655  //Write the content of the MMD register
1657 }
1658 
1659 
1660 /**
1661  * @brief Read MMD register
1662  * @param[in] interface Underlying network interface
1663  * @param[in] port Port number
1664  * @param[in] devAddr Device address
1665  * @param[in] regAddr Register address
1666  * @return Register value
1667  **/
1668 
1669 uint16_t ksz8565ReadMmdReg(NetInterface *interface, uint8_t port,
1670  uint8_t devAddr, uint16_t regAddr)
1671 {
1672  //Select register operation
1675 
1676  //Write MMD register address
1678 
1679  //Select data operation
1682 
1683  //Read the content of the MMD register
1684  return ksz8565ReadPhyReg(interface, port, KSZ8565_MMDAADR);
1685 }
1686 
1687 
1688 /**
1689  * @brief Write switch register (8 bits)
1690  * @param[in] interface Underlying network interface
1691  * @param[in] address Switch register address
1692  * @param[in] data Register value
1693  **/
1694 
1695 void ksz8565WriteSwitchReg8(NetInterface *interface, uint16_t address,
1696  uint8_t data)
1697 {
1698  uint32_t command;
1699 
1700  //SPI slave mode?
1701  if(interface->spiDriver != NULL)
1702  {
1703  //Set up a write operation
1704  command = KSZ8565_SPI_CMD_WRITE;
1705  //Set register address
1706  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1707 
1708  //Pull the CS pin low
1709  interface->spiDriver->assertCs();
1710 
1711  //Write 32-bit command
1712  interface->spiDriver->transfer((command >> 24) & 0xFF);
1713  interface->spiDriver->transfer((command >> 16) & 0xFF);
1714  interface->spiDriver->transfer((command >> 8) & 0xFF);
1715  interface->spiDriver->transfer(command & 0xFF);
1716 
1717  //Write 8-bit data
1718  interface->spiDriver->transfer(data);
1719 
1720  //Terminate the operation by raising the CS pin
1721  interface->spiDriver->deassertCs();
1722  }
1723  else
1724  {
1725  //The MDC/MDIO interface does not have access to all the configuration
1726  //registers. It can only access the standard MIIM registers
1727  }
1728 }
1729 
1730 
1731 /**
1732  * @brief Read switch register (8 bits)
1733  * @param[in] interface Underlying network interface
1734  * @param[in] address Switch register address
1735  * @return Register value
1736  **/
1737 
1738 uint8_t ksz8565ReadSwitchReg8(NetInterface *interface, uint16_t address)
1739 {
1740  uint8_t data;
1741  uint32_t command;
1742 
1743  //SPI slave mode?
1744  if(interface->spiDriver != NULL)
1745  {
1746  //Set up a read operation
1747  command = KSZ8565_SPI_CMD_READ;
1748  //Set register address
1749  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1750 
1751  //Pull the CS pin low
1752  interface->spiDriver->assertCs();
1753 
1754  //Write 32-bit command
1755  interface->spiDriver->transfer((command >> 24) & 0xFF);
1756  interface->spiDriver->transfer((command >> 16) & 0xFF);
1757  interface->spiDriver->transfer((command >> 8) & 0xFF);
1758  interface->spiDriver->transfer(command & 0xFF);
1759 
1760  //Read 8-bit data
1761  data = interface->spiDriver->transfer(0xFF);
1762 
1763  //Terminate the operation by raising the CS pin
1764  interface->spiDriver->deassertCs();
1765  }
1766  else
1767  {
1768  //The MDC/MDIO interface does not have access to all the configuration
1769  //registers. It can only access the standard MIIM registers
1770  data = 0;
1771  }
1772 
1773  //Return register value
1774  return data;
1775 }
1776 
1777 
1778 /**
1779  * @brief Write switch register (16 bits)
1780  * @param[in] interface Underlying network interface
1781  * @param[in] address Switch register address
1782  * @param[in] data Register value
1783  **/
1784 
1786  uint16_t data)
1787 {
1788  uint32_t command;
1789 
1790  //SPI slave mode?
1791  if(interface->spiDriver != NULL)
1792  {
1793  //Set up a write operation
1794  command = KSZ8565_SPI_CMD_WRITE;
1795  //Set register address
1796  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1797 
1798  //Pull the CS pin low
1799  interface->spiDriver->assertCs();
1800 
1801  //Write 32-bit command
1802  interface->spiDriver->transfer((command >> 24) & 0xFF);
1803  interface->spiDriver->transfer((command >> 16) & 0xFF);
1804  interface->spiDriver->transfer((command >> 8) & 0xFF);
1805  interface->spiDriver->transfer(command & 0xFF);
1806 
1807  //Write 16-bit data
1808  interface->spiDriver->transfer((data >> 8) & 0xFF);
1809  interface->spiDriver->transfer(data & 0xFF);
1810 
1811  //Terminate the operation by raising the CS pin
1812  interface->spiDriver->deassertCs();
1813  }
1814  else
1815  {
1816  //The MDC/MDIO interface does not have access to all the configuration
1817  //registers. It can only access the standard MIIM registers
1818  }
1819 }
1820 
1821 
1822 /**
1823  * @brief Read switch register (16 bits)
1824  * @param[in] interface Underlying network interface
1825  * @param[in] address Switch register address
1826  * @return Register value
1827  **/
1828 
1829 uint16_t ksz8565ReadSwitchReg16(NetInterface *interface, uint16_t address)
1830 {
1831  uint16_t data;
1832  uint32_t command;
1833 
1834  //SPI slave mode?
1835  if(interface->spiDriver != NULL)
1836  {
1837  //Set up a read operation
1838  command = KSZ8565_SPI_CMD_READ;
1839  //Set register address
1840  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1841 
1842  //Pull the CS pin low
1843  interface->spiDriver->assertCs();
1844 
1845  //Write 32-bit command
1846  interface->spiDriver->transfer((command >> 24) & 0xFF);
1847  interface->spiDriver->transfer((command >> 16) & 0xFF);
1848  interface->spiDriver->transfer((command >> 8) & 0xFF);
1849  interface->spiDriver->transfer(command & 0xFF);
1850 
1851  //Read 16-bit data
1852  data = interface->spiDriver->transfer(0xFF) << 8;
1853  data |= interface->spiDriver->transfer(0xFF);
1854 
1855  //Terminate the operation by raising the CS pin
1856  interface->spiDriver->deassertCs();
1857  }
1858  else
1859  {
1860  //The MDC/MDIO interface does not have access to all the configuration
1861  //registers. It can only access the standard MIIM registers
1862  data = 0;
1863  }
1864 
1865  //Return register value
1866  return data;
1867 }
1868 
1869 
1870 /**
1871  * @brief Write switch register (32 bits)
1872  * @param[in] interface Underlying network interface
1873  * @param[in] address Switch register address
1874  * @param[in] data Register value
1875  **/
1876 
1878  uint32_t data)
1879 {
1880  uint32_t command;
1881 
1882  //SPI slave mode?
1883  if(interface->spiDriver != NULL)
1884  {
1885  //Set up a write operation
1886  command = KSZ8565_SPI_CMD_WRITE;
1887  //Set register address
1888  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1889 
1890  //Pull the CS pin low
1891  interface->spiDriver->assertCs();
1892 
1893  //Write 32-bit command
1894  interface->spiDriver->transfer((command >> 24) & 0xFF);
1895  interface->spiDriver->transfer((command >> 16) & 0xFF);
1896  interface->spiDriver->transfer((command >> 8) & 0xFF);
1897  interface->spiDriver->transfer(command & 0xFF);
1898 
1899  //Write 32-bit data
1900  interface->spiDriver->transfer((data >> 24) & 0xFF);
1901  interface->spiDriver->transfer((data >> 16) & 0xFF);
1902  interface->spiDriver->transfer((data >> 8) & 0xFF);
1903  interface->spiDriver->transfer(data & 0xFF);
1904 
1905  //Terminate the operation by raising the CS pin
1906  interface->spiDriver->deassertCs();
1907  }
1908  else
1909  {
1910  //The MDC/MDIO interface does not have access to all the configuration
1911  //registers. It can only access the standard MIIM registers
1912  }
1913 }
1914 
1915 
1916 /**
1917  * @brief Read switch register (32 bits)
1918  * @param[in] interface Underlying network interface
1919  * @param[in] address Switch register address
1920  * @return Register value
1921  **/
1922 
1923 uint32_t ksz8565ReadSwitchReg32(NetInterface *interface, uint16_t address)
1924 {
1925  uint32_t data;
1926  uint32_t command;
1927 
1928  //SPI slave mode?
1929  if(interface->spiDriver != NULL)
1930  {
1931  //Set up a read operation
1932  command = KSZ8565_SPI_CMD_READ;
1933  //Set register address
1934  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1935 
1936  //Pull the CS pin low
1937  interface->spiDriver->assertCs();
1938 
1939  //Write 32-bit command
1940  interface->spiDriver->transfer((command >> 24) & 0xFF);
1941  interface->spiDriver->transfer((command >> 16) & 0xFF);
1942  interface->spiDriver->transfer((command >> 8) & 0xFF);
1943  interface->spiDriver->transfer(command & 0xFF);
1944 
1945  //Read 32-bit data
1946  data = interface->spiDriver->transfer(0xFF) << 24;
1947  data |= interface->spiDriver->transfer(0xFF) << 16;
1948  data |= interface->spiDriver->transfer(0xFF) << 8;
1949  data |= interface->spiDriver->transfer(0xFF);
1950 
1951  //Terminate the operation by raising the CS pin
1952  interface->spiDriver->deassertCs();
1953  }
1954  else
1955  {
1956  //The MDC/MDIO interface does not have access to all the configuration
1957  //registers. It can only access the standard MIIM registers
1958  data = 0;
1959  }
1960 
1961  //Return register value
1962  return data;
1963 }
uint8_t type
Definition: coap_common.h:176
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
#define HTONS(value)
Definition: cpu_endian.h:410
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
@ ERROR_INVALID_PORT
Definition: error.h:104
@ ERROR_NOT_FOUND
Definition: error.h:147
@ ERROR_END_OF_TABLE
Definition: error.h:290
@ ERROR_INVALID_ENTRY
Definition: error.h:288
@ ERROR_TABLE_FULL
Definition: error.h:289
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
uint8_t data[]
Definition: ethernet.h:222
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
EthHeader
Definition: ethernet.h:223
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
Helper functions for Ethernet.
Ipv6Addr address[]
Definition: ipv6.h:316
void ksz8565SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
void ksz8565DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
const SwitchDriver ksz8565SwitchDriver
KSZ8565 Ethernet switch driver.
uint16_t ksz8565ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
error_t ksz8565AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
void ksz8565WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
uint32_t ksz8565ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
void ksz8565EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
void ksz8565SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
NicDuplexMode ksz8565GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
error_t ksz8565GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
error_t ksz8565TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
error_t ksz8565GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
__weak_func void ksz8565InitHook(NetInterface *interface)
KSZ8565 custom configuration.
void ksz8565FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
void ksz8565Tick(NetInterface *interface)
KSZ8565 timer handler.
void ksz8565EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
void ksz8565SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
error_t ksz8565DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
SwitchPortState ksz8565GetPortState(NetInterface *interface, uint8_t port)
Get port state.
void ksz8565WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
error_t ksz8565Init(NetInterface *interface)
KSZ8565 Ethernet switch initialization.
void ksz8565EnableIrq(NetInterface *interface)
Enable interrupts.
void ksz8565EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
void ksz8565WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
void ksz8565FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
uint8_t ksz8565ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
uint16_t ksz8565ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
void ksz8565DisableIrq(NetInterface *interface)
Disable interrupts.
void ksz8565WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
uint16_t ksz8565ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void ksz8565EventHandler(NetInterface *interface)
KSZ8565 event handler.
uint32_t ksz8565GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
bool_t ksz8565GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
error_t ksz8565UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
void ksz8565WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
const uint16_t ksz8565IngressTailTag[5]
Tail tag rules (host to KSZ8565)
KSZ8565 5-port Ethernet switch driver.
#define KSZ8565_STATIC_MAC_TABLE_SIZE
#define KSZ8565_TAIL_TAG_DEST_PORT4
#define KSZ8565_BMSR
#define KSZ8565_ALU_TABLE_ENTRY4
#define KSZ8565_PORT5
#define KSZ8565_STATIC_TABLE_ENTRY2
#define KSZ8565_SPI_CMD_READ
#define KSZ8565_ALU_TABLE_ENTRY2_PORT4_FORWARD
#define KSZ8565_SWITCH_MAC_CTRL0
#define KSZ8565_TAIL_TAG_DEST_PORT3
#define KSZ8565_SPI_CMD_ADDR
#define KSZ8565_ALU_TABLE_ENTRY2
#define KSZ8565_PHYCON_SPEED_100BTX
#define KSZ8565_PORT_RESERVED2
#define KSZ8565_TAIL_TAG_PORT_BLOCKING_OVERRIDE
#define KSZ8565_PORTn_OP_CTRL0_TAIL_TAG_EN
#define KSZ8565_SWITCH_OP
#define KSZ8565_ALU_TABLE_ENTRY2_PORT_FORWARD
#define KSZ8565_PORT3
#define KSZ8565_STATIC_TABLE_ENTRY1_VALID
#define KSZ8565_STATIC_TABLE_ENTRY3
#define KSZ8565_ALU_TABLE_ENTRY1
#define KSZ8565_MMD_LED_MODE_LED_MODE_SINGLE
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
#define KSZ8565_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define KSZ8565_PORT5_XMII_CTRL1_IF_TYPE
#define KSZ8565_PORT5_XMII_CTRL1_RGMII_ID_IG
#define KSZ8565_CHIP_ID1_DEFAULT
#define KSZ8565_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define KSZ8565_SWITCH_LUE_CTRL1
#define KSZ8565_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
#define KSZ8565_MMDACR_FUNC_DATA_NO_POST_INC
#define KSZ8565_PORT5_XMII_CTRL0_SPEED_10_100
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_ACTION
#define KSZ8565_SWITCH_LUE_CTRL2
#define KSZ8565_ALU_TABLE_CTRL_ACTION_SEARCH
#define KSZ8565_TAIL_TAG_DEST_PORT1
#define KSZ8565_ALU_TABLE_ENTRY2_PORT1_FORWARD
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_START_FINISH
#define KSZ8565_GLOBAL_PORT_MIRROR_SNOOP_CTRL
#define KSZ8565_PORTn_MSTP_STATE(port)
#define KSZ8565_SWITCH_LUE_CTRL3
#define KSZ8565_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
#define KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN
#define KSZ8565_SWITCH_OP_START_SWITCH
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT5
#define KSZ8565_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
#define KSZ8565_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
#define KSZ8565_TAIL_TAG_NORMAL_ADDR_LOOKUP
#define KSZ8565_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
#define KSZ8565_MMD_LED_MODE_RESERVED_DEFAULT
#define KSZ8565_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN
#define KSZ8565_PORT5_XMII_CTRL0_DUPLEX
#define KSZ8565_MMD_EEE_ADV
#define KSZ8565_ALU_TABLE_CTRL_VALID
#define KSZ8565_PORTn_ETH_PHY_REG(port, addr)
#define KSZ8565_SPI_CMD_WRITE
#define KSZ8565_MMDACR_FUNC_ADDR
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
#define KSZ8565_PORT_RESERVED1
#define KSZ8565_TAIL_TAG_DEST_PORT2
#define KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN
#define KSZ8565_SWITCH_LUE_CTRL2_FLUSH_OPTION
#define KSZ8565_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
#define KSZ8565_MMDAADR
#define KSZ8565_UNKONWN_MULTICAST_CTRL
#define KSZ8565_TAIL_TAG_SRC_PORT
#define KSZ8565_PORT5_XMII_CTRL1_SPEED_1000
#define KSZ8565_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
#define KSZ8565_STATIC_TABLE_ENTRY1
#define KSZ8565_PHYCON_SPEED_10BT
#define KSZ8565_PORT5_XMII_CTRL0
#define KSZ8565_MMDACR_DEVAD
#define KSZ8565_PORT2
#define KSZ8565_ALU_TABLE_ENTRY2_PORT3_FORWARD
#define KSZ8565_ALU_TABLE_ENTRY3
#define KSZ8565_PORTn_MSTP_STATE_LEARNING_DIS
#define KSZ8565_PORT5_XMII_CTRL1
#define KSZ8565_MMD_LED_MODE
#define KSZ8565_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
#define KSZ8565_PHYCON
#define KSZ8565_PORT5_OP_CTRL0
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
#define KSZ8565_PHYCON_DUPLEX_STATUS
#define KSZ8565_ALU_TABLE_ENTRY2_PORT5_FORWARD
#define KSZ8565_STATIC_TABLE_ENTRY2_OVERRIDE
#define KSZ8565_PORT5_XMII_CTRL1_RGMII_ID_EG
#define KSZ8565_PORT_MASK
#define KSZ8565_BMSR_LINK_STATUS
#define KSZ8565_PORT4
#define KSZ8565_CHIP_ID1
#define KSZ8565_SWITCH_LUE_CTRL0
#define KSZ8565_PORT1
#define KSZ8565_PORT5_MASK
#define KSZ8565_STATIC_MCAST_TABLE_CTRL
#define KSZ8565_ALU_TABLE_CTRL
#define KSZ8565_ALU_TABLE_CTRL_START_FINISH
#define KSZ8565_ALU_TABLE_ENTRY2_PORT2_FORWARD
#define KSZ8565_STATIC_TABLE_ENTRY4
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP
#define KSZ8565_PORT5_XMII_CTRL1_IF_TYPE_RGMII
#define KSZ8565_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
#define KSZ8565_MMDACR
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
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:588
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define SMI_OPCODE_READ
Definition: nic.h:67
NicDuplexMode
Duplex mode.
Definition: nic.h:122
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
SwitchPortState
Switch port state.
Definition: nic.h:134
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
Ethernet switch driver.
Definition: nic.h:322
Forwarding database entry.
Definition: nic.h:149
MacAddr macAddr
Definition: nic.h:150
uint32_t destPorts
Definition: nic.h:152
bool_t override
Definition: nic.h:153
uint8_t srcPort
Definition: nic.h:151
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369