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-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
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
238  osSetEvent(&interface->netContext->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 __weak_func 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  NetContext *context;
271  NetInterface *virtualInterface;
272 
273  //Point to the TCP/IP stack context
274  context = interface->netContext;
275 
276  //Loop through network interfaces
277  for(i = 0; i < context->numInterfaces; i++)
278  {
279  //Point to the current interface
280  virtualInterface = &context->interfaces[i];
281 
282  //Check whether the current virtual interface is attached to the
283  //physical interface
284  if(virtualInterface == interface ||
285  virtualInterface->parent == interface)
286  {
287  //Retrieve current link state
288  linkState = ksz8565GetLinkState(interface, virtualInterface->port);
289 
290  //Link up or link down event?
291  if(linkState != virtualInterface->linkState)
292  {
293  //Set event flag
294  interface->phyEvent = TRUE;
295  //Notify the TCP/IP stack of the event
296  osSetEvent(&interface->netContext->event);
297  }
298  }
299  }
300  }
301  else
302 #endif
303  {
304  //Initialize link state
305  linkState = FALSE;
306 
307  //Loop through the ports
309  {
310  //Retrieve current link state
311  if(ksz8565GetLinkState(interface, port))
312  {
313  linkState = TRUE;
314  }
315  }
316 
317  //Link up or link down event?
318  if(linkState != interface->linkState)
319  {
320  //Set event flag
321  interface->phyEvent = TRUE;
322  //Notify the TCP/IP stack of the event
323  osSetEvent(&interface->netContext->event);
324  }
325  }
326 }
327 
328 
329 /**
330  * @brief Enable interrupts
331  * @param[in] interface Underlying network interface
332  **/
333 
335 {
336 }
337 
338 
339 /**
340  * @brief Disable interrupts
341  * @param[in] interface Underlying network interface
342  **/
343 
345 {
346 }
347 
348 
349 /**
350  * @brief KSZ8565 event handler
351  * @param[in] interface Underlying network interface
352  **/
353 
354 __weak_func void ksz8565EventHandler(NetInterface *interface)
355 {
356  uint_t port;
357  bool_t linkState;
358 
359 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
360  //Port separation mode?
361  if(interface->port != 0)
362  {
363  uint_t i;
364  NetContext *context;
365  NetInterface *virtualInterface;
366 
367  //Point to the TCP/IP stack context
368  context = interface->netContext;
369 
370  //Loop through network interfaces
371  for(i = 0; i < context->numInterfaces; i++)
372  {
373  //Point to the current interface
374  virtualInterface = &context->interfaces[i];
375 
376  //Check whether the current virtual interface is attached to the
377  //physical interface
378  if(virtualInterface == interface ||
379  virtualInterface->parent == interface)
380  {
381  //Get the port number associated with the current interface
382  port = virtualInterface->port;
383 
384  //Valid port?
385  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
386  {
387  //Retrieve current link state
388  linkState = ksz8565GetLinkState(interface, port);
389 
390  //Link up event?
391  if(linkState && !virtualInterface->linkState)
392  {
393  //Retrieve host interface speed
394  interface->linkSpeed = ksz8565GetLinkSpeed(interface,
395  KSZ8565_PORT5);
396 
397  //Retrieve host interface duplex mode
398  interface->duplexMode = ksz8565GetDuplexMode(interface,
399  KSZ8565_PORT5);
400 
401  //Adjust MAC configuration parameters for proper operation
402  interface->nicDriver->updateMacConfig(interface);
403 
404  //Check current speed
405  virtualInterface->linkSpeed = ksz8565GetLinkSpeed(interface,
406  port);
407 
408  //Check current duplex mode
409  virtualInterface->duplexMode = ksz8565GetDuplexMode(interface,
410  port);
411 
412  //Update link state
413  virtualInterface->linkState = TRUE;
414 
415  //Process link state change event
416  nicNotifyLinkChange(virtualInterface);
417  }
418  //Link down event
419  else if(!linkState && virtualInterface->linkState)
420  {
421  //Update link state
422  virtualInterface->linkState = FALSE;
423 
424  //Process link state change event
425  nicNotifyLinkChange(virtualInterface);
426  }
427  }
428  }
429  }
430  }
431  else
432 #endif
433  {
434  //Initialize link state
435  linkState = FALSE;
436 
437  //Loop through the ports
439  {
440  //Retrieve current link state
441  if(ksz8565GetLinkState(interface, port))
442  {
443  linkState = TRUE;
444  }
445  }
446 
447  //Link up event?
448  if(linkState)
449  {
450  //Retrieve host interface speed
451  interface->linkSpeed = ksz8565GetLinkSpeed(interface, KSZ8565_PORT5);
452  //Retrieve host interface duplex mode
453  interface->duplexMode = ksz8565GetDuplexMode(interface, KSZ8565_PORT5);
454 
455  //Adjust MAC configuration parameters for proper operation
456  interface->nicDriver->updateMacConfig(interface);
457 
458  //Update link state
459  interface->linkState = TRUE;
460  }
461  else
462  {
463  //Update link state
464  interface->linkState = FALSE;
465  }
466 
467  //Process link state change event
468  nicNotifyLinkChange(interface);
469  }
470 }
471 
472 
473 /**
474  * @brief Add tail tag to Ethernet frame
475  * @param[in] interface Underlying network interface
476  * @param[in] buffer Multi-part buffer containing the payload
477  * @param[in,out] offset Offset to the first payload byte
478  * @param[in] ancillary Additional options passed to the stack along with
479  * the packet
480  * @return Error code
481  **/
482 
484  size_t *offset, NetTxAncillary *ancillary)
485 {
486  error_t error;
487 
488  //Initialize status code
489  error = NO_ERROR;
490 
491 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
492  //SPI slave mode?
493  if(interface->spiDriver != NULL)
494  {
495  //Valid port?
496  if(ancillary->port <= KSZ8565_PORT5)
497  {
498  size_t length;
499  const uint16_t *tailTag;
500 
501  //The two-byte tail tagging is used to indicate the destination port
502  tailTag = &ksz8565IngressTailTag[ancillary->port];
503 
504  //Retrieve the length of the Ethernet frame
505  length = netBufferGetLength(buffer) - *offset;
506 
507  //The host controller should manually add padding to the packet before
508  //inserting the tail tag
509  error = ethPadFrame(buffer, &length);
510 
511  //Check status code
512  if(!error)
513  {
514  //The tail tag is inserted at the end of the packet, just before
515  //the CRC
516  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
517  }
518  }
519  else
520  {
521  //The port number is not valid
522  error = ERROR_INVALID_PORT;
523  }
524  }
525 #endif
526 
527  //Return status code
528  return error;
529 }
530 
531 
532 /**
533  * @brief Decode tail tag from incoming Ethernet frame
534  * @param[in] interface Underlying network interface
535  * @param[in,out] frame Pointer to the received Ethernet frame
536  * @param[in,out] length Length of the frame, in bytes
537  * @param[in,out] ancillary Additional options passed to the stack along with
538  * the packet
539  * @return Error code
540  **/
541 
542 error_t ksz8565UntagFrame(NetInterface *interface, uint8_t **frame,
543  size_t *length, NetRxAncillary *ancillary)
544 {
545  error_t error;
546 
547  //Initialize status code
548  error = NO_ERROR;
549 
550 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
551  //SPI slave mode?
552  if(interface->spiDriver != NULL)
553  {
554  //Valid Ethernet frame received?
555  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
556  {
557  uint8_t *tailTag;
558 
559  //The tail tag is inserted at the end of the packet, just before
560  //the CRC
561  tailTag = *frame + *length - sizeof(uint8_t);
562 
563  //The one byte tail tagging is used to indicate the source port
564  ancillary->port = (*tailTag & KSZ8565_TAIL_TAG_SRC_PORT) + 1;
565 
566  //Strip tail tag from Ethernet frame
567  *length -= sizeof(uint8_t);
568  }
569  else
570  {
571  //Drop the received frame
572  error = ERROR_INVALID_LENGTH;
573  }
574  }
575  else
576  {
577  //Tail tagging mode cannot be enabled through MDC/MDIO interface
578  ancillary->port = 0;
579  }
580 #endif
581 
582  //Return status code
583  return error;
584 }
585 
586 
587 /**
588  * @brief Get link state
589  * @param[in] interface Underlying network interface
590  * @param[in] port Port number
591  * @return Link state
592  **/
593 
595 {
596  uint16_t value;
597  bool_t linkState;
598 
599  //Check port number
600  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
601  {
602  //Any link failure condition is latched in the BMSR register. Reading
603  //the register twice will always return the actual link status
604  value = ksz8565ReadPhyReg(interface, port, KSZ8565_BMSR);
605  value = ksz8565ReadPhyReg(interface, port, KSZ8565_BMSR);
606 
607  //Retrieve current link state
608  linkState = (value & KSZ8565_BMSR_LINK_STATUS) ? TRUE : FALSE;
609  }
610  else
611  {
612  //The specified port number is not valid
613  linkState = FALSE;
614  }
615 
616  //Return link status
617  return linkState;
618 }
619 
620 
621 /**
622  * @brief Get link speed
623  * @param[in] interface Underlying network interface
624  * @param[in] port Port number
625  * @return Link speed
626  **/
627 
628 uint32_t ksz8565GetLinkSpeed(NetInterface *interface, uint8_t port)
629 {
630  uint8_t type;
631  uint16_t value;
632  uint32_t linkSpeed;
633 
634  //Check port number
635  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
636  {
637  //Read PHY control register
639 
640  //Retrieve current link speed
642  {
643  //100BASE-TX
644  linkSpeed = NIC_LINK_SPEED_100MBPS;
645  }
646  else if((value & KSZ8565_PHYCON_SPEED_10BT) != 0)
647  {
648  //10BASE-T
649  linkSpeed = NIC_LINK_SPEED_10MBPS;
650  }
651  else
652  {
653  //The link speed is not valid
654  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
655  }
656  }
657  else if(port == KSZ8565_PORT5)
658  {
659  //SPI slave mode?
660  if(interface->spiDriver != NULL)
661  {
662  //Read port 5 XMII control 1 register
664 
665  //Retrieve host interface type
667 
668  //Gigabit interface?
671  {
672  //1000 Mb/s mode
673  linkSpeed = NIC_LINK_SPEED_1GBPS;
674  }
675  else
676  {
677  //Read port 5 XMII control 0 register
679 
680  //Retrieve host interface speed
682  {
683  //100 Mb/s mode
684  linkSpeed = NIC_LINK_SPEED_100MBPS;
685  }
686  else
687  {
688  //10 Mb/s mode
689  linkSpeed = NIC_LINK_SPEED_10MBPS;
690  }
691  }
692  }
693  else
694  {
695  //The MDC/MDIO interface does not have access to all the configuration
696  //registers. It can only access the standard MIIM registers
697  linkSpeed = NIC_LINK_SPEED_100MBPS;
698  }
699  }
700  else
701  {
702  //The specified port number is not valid
703  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
704  }
705 
706  //Return link speed
707  return linkSpeed;
708 }
709 
710 
711 /**
712  * @brief Get duplex mode
713  * @param[in] interface Underlying network interface
714  * @param[in] port Port number
715  * @return Duplex mode
716  **/
717 
719 {
720  uint16_t value;
721  NicDuplexMode duplexMode;
722 
723  //Check port number
724  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
725  {
726  //Read PHY control register
728 
729  //Retrieve current duplex mode
731  {
732  duplexMode = NIC_FULL_DUPLEX_MODE;
733  }
734  else
735  {
736  duplexMode = NIC_HALF_DUPLEX_MODE;
737  }
738  }
739  else if(port == KSZ8565_PORT5)
740  {
741  //SPI slave mode?
742  if(interface->spiDriver != NULL)
743  {
744  //Read port 5 XMII control 0 register
746 
747  //Retrieve host interface duplex mode
749  {
750  duplexMode = NIC_FULL_DUPLEX_MODE;
751  }
752  else
753  {
754  duplexMode = NIC_HALF_DUPLEX_MODE;
755  }
756  }
757  else
758  {
759  //The MDC/MDIO interface does not have access to all the configuration
760  //registers. It can only access the standard MIIM registers
761  duplexMode = NIC_FULL_DUPLEX_MODE;
762  }
763  }
764  else
765  {
766  //The specified port number is not valid
767  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
768  }
769 
770  //Return duplex mode
771  return duplexMode;
772 }
773 
774 
775 /**
776  * @brief Set port state
777  * @param[in] interface Underlying network interface
778  * @param[in] port Port number
779  * @param[in] state Port state
780  **/
781 
782 void ksz8565SetPortState(NetInterface *interface, uint8_t port,
783  SwitchPortState state)
784 {
785  uint8_t temp;
786 
787  //Check port number
788  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
789  {
790  //Read MSTP state register
792 
793  //Update port state
794  switch(state)
795  {
796  //Listening state
801  break;
802 
803  //Learning state
808  break;
809 
810  //Forwarding state
815  break;
816 
817  //Disabled state
818  default:
822  break;
823  }
824 
825  //Write the value back to MSTP state register
827  }
828 }
829 
830 
831 /**
832  * @brief Get port state
833  * @param[in] interface Underlying network interface
834  * @param[in] port Port number
835  * @return Port state
836  **/
837 
839 {
840  uint8_t temp;
841  SwitchPortState state;
842 
843  //Check port number
844  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT4)
845  {
846  //Read MSTP state register
848 
849  //Check port state
850  if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
851  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
853  {
854  //Disabled state
856  }
857  else if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
858  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
860  {
861  //Listening state
863  }
864  else if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
865  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
867  {
868  //Learning state
870  }
871  else if((temp & KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
872  (temp & KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
874  {
875  //Forwarding state
877  }
878  else
879  {
880  //Unknown state
882  }
883  }
884  else
885  {
886  //The specified port number is not valid
888  }
889 
890  //Return port state
891  return state;
892 }
893 
894 
895 /**
896  * @brief Set aging time for dynamic filtering entries
897  * @param[in] interface Underlying network interface
898  * @param[in] agingTime Aging time, in seconds
899  **/
900 
901 void ksz8565SetAgingTime(NetInterface *interface, uint32_t agingTime)
902 {
903  //The Age Period in combination with the Age Count field determines the
904  //aging time of dynamic entries in the address lookup table
905  agingTime = (agingTime + 3) / 4;
906 
907  //Limit the range of the parameter
908  agingTime = MIN(agingTime, 255);
909 
910  //Write the value to Switch Lookup Engine Control 3 register
912  (uint8_t) agingTime);
913 }
914 
915 
916 /**
917  * @brief Enable IGMP snooping
918  * @param[in] interface Underlying network interface
919  * @param[in] enable Enable or disable IGMP snooping
920  **/
921 
923 {
924  uint8_t temp;
925 
926  //Read the Global Port Mirroring and Snooping Control register
927  temp = ksz8565ReadSwitchReg8(interface,
929 
930  //Enable or disable IGMP snooping
931  if(enable)
932  {
934  }
935  else
936  {
938  }
939 
940  //Write the value back to Global Port Mirroring and Snooping Control register
942  temp);
943 }
944 
945 
946 /**
947  * @brief Enable MLD snooping
948  * @param[in] interface Underlying network interface
949  * @param[in] enable Enable or disable MLD snooping
950  **/
951 
953 {
954  uint8_t temp;
955 
956  //Read the Global Port Mirroring and Snooping Control register
957  temp = ksz8565ReadSwitchReg8(interface,
959 
960  //Enable or disable MLD snooping
961  if(enable)
962  {
964  }
965  else
966  {
968  }
969 
970  //Write the value back to Global Port Mirroring and Snooping Control register
972  temp);
973 }
974 
975 
976 /**
977  * @brief Enable reserved multicast table
978  * @param[in] interface Underlying network interface
979  * @param[in] enable Enable or disable reserved group addresses
980  **/
981 
983 {
984  uint8_t temp;
985 
986  //Read the Switch Lookup Engine Control 0 register
988 
989  //Enable or disable the reserved multicast table
990  if(enable)
991  {
993  }
994  else
995  {
997  }
998 
999  //Write the value back to Switch Lookup Engine Control 0 register
1001 }
1002 
1003 
1004 /**
1005  * @brief Add a new entry to the static MAC table
1006  * @param[in] interface Underlying network interface
1007  * @param[in] entry Pointer to the forwarding database entry
1008  * @return Error code
1009  **/
1010 
1012  const SwitchFdbEntry *entry)
1013 {
1014  error_t error;
1015  uint_t i;
1016  uint_t j;
1017  uint32_t value;
1018  SwitchFdbEntry currentEntry;
1019 
1020  //Keep track of the first free entry
1022 
1023  //Loop through the static MAC table
1024  for(i = 0; i < KSZ8565_STATIC_MAC_TABLE_SIZE; i++)
1025  {
1026  //Read current entry
1027  error = ksz8565GetStaticFdbEntry(interface, i, &currentEntry);
1028 
1029  //Valid entry?
1030  if(!error)
1031  {
1032  //Check whether the table already contains the specified MAC address
1033  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1034  {
1035  j = i;
1036  break;
1037  }
1038  }
1039  else
1040  {
1041  //Keep track of the first free entry
1043  {
1044  j = i;
1045  }
1046  }
1047  }
1048 
1049  //Any entry available?
1051  {
1052  //Write the Static Address Table Entry 1 register
1055 
1056  //Set the relevant forward ports
1057  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1058  {
1060  }
1061  else
1062  {
1063  value = entry->destPorts & KSZ8565_PORT_MASK;
1064  }
1065 
1066  //Enable overriding of port state
1067  if(entry->override)
1068  {
1070  }
1071 
1072  //Write the Static Address Table Entry 2 register
1074 
1075  //Copy MAC address (first 16 bits)
1076  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1077 
1078  //Write the Static Address Table Entry 3 register
1080 
1081  //Copy MAC address (last 32 bits)
1082  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1083  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1084 
1085  //Write the Static Address Table Entry 4 register
1087 
1088  //Write the TABLE_INDEX field with the 4-bit index value
1090  //Set the TABLE_SELECT bit to 0 to select the static address table
1092  //Set the ACTION bit to 0 to indicate a write operation
1094  //Set the START_FINISH bit to 1 to initiate the operation
1096 
1097  //Start the write operation
1099  value);
1100 
1101  //When the operation is complete, the START_FINISH bit will be cleared
1102  //automatically
1103  do
1104  {
1105  //Read the Static Address and Reserved Multicast Table Control register
1106  value = ksz8565ReadSwitchReg32(interface,
1108 
1109  //Poll the START_FINISH bit
1111 
1112  //Successful processing
1113  error = NO_ERROR;
1114  }
1115  else
1116  {
1117  //The static MAC table is full
1118  error = ERROR_TABLE_FULL;
1119  }
1120 
1121  //Return status code
1122  return error;
1123 }
1124 
1125 
1126 /**
1127  * @brief Remove an entry from the static MAC table
1128  * @param[in] interface Underlying network interface
1129  * @param[in] entry Forwarding database entry to remove from the table
1130  * @return Error code
1131  **/
1132 
1134  const SwitchFdbEntry *entry)
1135 {
1136  error_t error;
1137  uint_t j;
1138  uint32_t value;
1139  SwitchFdbEntry currentEntry;
1140 
1141  //Loop through the static MAC table
1142  for(j = 0; j < KSZ8565_STATIC_MAC_TABLE_SIZE; j++)
1143  {
1144  //Read current entry
1145  error = ksz8565GetStaticFdbEntry(interface, j, &currentEntry);
1146 
1147  //Valid entry?
1148  if(!error)
1149  {
1150  //Check whether the table contains the specified MAC address
1151  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1152  {
1153  break;
1154  }
1155  }
1156  }
1157 
1158  //Any matching entry?
1160  {
1161  //Clear Static Address Table Entry registers
1166 
1167  //Write the TABLE_INDEX field with the 4-bit index value
1169  //Set the TABLE_SELECT bit to 0 to select the static address table
1171  //Set the ACTION bit to 0 to indicate a write operation
1173  //Set the START_FINISH bit to 1 to initiate the operation
1175 
1176  //Start the write operation
1178  value);
1179 
1180  //When the operation is complete, the START_FINISH bit will be cleared
1181  //automatically
1182  do
1183  {
1184  //Read the Static Address and Reserved Multicast Table Control register
1185  value = ksz8565ReadSwitchReg32(interface,
1187 
1188  //Poll the START_FINISH bit
1190 
1191  //Successful processing
1192  error = NO_ERROR;
1193  }
1194  else
1195  {
1196  //The static MAC table does not contain the specified address
1197  error = ERROR_NOT_FOUND;
1198  }
1199 
1200  //Return status code
1201  return error;
1202 }
1203 
1204 
1205 /**
1206  * @brief Read an entry from the static MAC table
1207  * @param[in] interface Underlying network interface
1208  * @param[in] index Zero-based index of the entry to read
1209  * @param[out] entry Pointer to the forwarding database entry
1210  * @return Error code
1211  **/
1212 
1214  SwitchFdbEntry *entry)
1215 {
1216  error_t error;
1217  uint32_t value;
1218 
1219  //Check index parameter
1220  if(index < KSZ8565_STATIC_MAC_TABLE_SIZE)
1221  {
1222  //Write the TABLE_INDEX field with the 4-bit index value
1224  //Set the TABLE_SELECT bit to 0 to select the static address table
1226  //Set the ACTION bit to 1 to indicate a read operation
1228  //Set the START_FINISH bit to 1 to initiate the operation
1230 
1231  //Start the read operation
1233  value);
1234 
1235  //When the operation is complete, the START_FINISH bit will be cleared
1236  //automatically
1237  do
1238  {
1239  //Read the Static Address and Reserved Multicast Table Control register
1240  value = ksz8565ReadSwitchReg32(interface,
1242 
1243  //Poll the START_FINISH bit
1245 
1246  //Read the Static Address Table Entry 1 register
1248 
1249  //Valid entry?
1251  {
1252  //Read the Static Address Table Entry 2 register
1254 
1255  //Retrieve the ports associated with this MAC address
1256  entry->srcPort = 0;
1258 
1259  //Check the value of the OVERRIDE bit
1261  {
1262  entry->override = TRUE;
1263  }
1264  else
1265  {
1266  entry->override = FALSE;
1267  }
1268 
1269  //Read the Static Address Table Entry 3 register
1271 
1272  //Copy MAC address (first 16 bits)
1273  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1274  entry->macAddr.b[1] = value & 0xFF;
1275 
1276  //Read the Static Address Table Entry 4 register
1278 
1279  //Copy MAC address (last 32 bits)
1280  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1281  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1282  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1283  entry->macAddr.b[5] = value & 0xFF;
1284 
1285  //Successful processing
1286  error = NO_ERROR;
1287  }
1288  else
1289  {
1290  //The entry is not valid
1291  error = ERROR_INVALID_ENTRY;
1292  }
1293  }
1294  else
1295  {
1296  //The end of the table has been reached
1297  error = ERROR_END_OF_TABLE;
1298  }
1299 
1300  //Return status code
1301  return error;
1302 }
1303 
1304 
1305 /**
1306  * @brief Flush static MAC table
1307  * @param[in] interface Underlying network interface
1308  **/
1309 
1311 {
1312  uint_t i;
1313  uint32_t value;
1314 
1315  //Loop through the static MAC table
1316  for(i = 0; i < KSZ8565_STATIC_MAC_TABLE_SIZE; i++)
1317  {
1318  //Clear Static Address Table Entry registers
1323 
1324  //Write the TABLE_INDEX field with the 4-bit index value
1326  //Set the TABLE_SELECT bit to 0 to select the static address table
1328  //Set the ACTION bit to 0 to indicate a write operation
1330  //Set the START_FINISH bit to 1 to initiate the operation
1332 
1333  //Start the write operation
1335  value);
1336 
1337  //When the operation is complete, the START_FINISH bit will be cleared
1338  //automatically
1339  do
1340  {
1341  //Read the Static Address and Reserved Multicast Table Control register
1342  value = ksz8565ReadSwitchReg32(interface,
1344 
1345  //Poll the START_FINISH bit
1347  }
1348 }
1349 
1350 
1351 /**
1352  * @brief Read an entry from the dynamic MAC table
1353  * @param[in] interface Underlying network interface
1354  * @param[in] index Zero-based index of the entry to read
1355  * @param[out] entry Pointer to the forwarding database entry
1356  * @return Error code
1357  **/
1358 
1360  SwitchFdbEntry *entry)
1361 {
1362  error_t error;
1363  uint32_t value;
1364 
1365  //First entry?
1366  if(index == 0)
1367  {
1368  //Clear the ALU Table Access Control register to stop any operation
1370 
1371  //Start the search operation
1375  }
1376 
1377  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1378  do
1379  {
1380  //Read the ALU Table Access Control register
1382 
1383  //This bit goes high to indicate either a new valid entry is returned or
1384  //the search is complete
1386 
1387  //Check whether the next valid entry is ready
1388  if((value & KSZ8565_ALU_TABLE_CTRL_VALID) != 0)
1389  {
1390  //Store the data from the ALU table entry
1391  entry->destPorts = 0;
1392  entry->override = FALSE;
1393 
1394  //Read the ALU Table Entry 1 and 2 registers
1397 
1398  //Retrieve the port associated with this MAC address
1400  {
1402  entry->srcPort = KSZ8565_PORT1;
1403  break;
1405  entry->srcPort = KSZ8565_PORT2;
1406  break;
1408  entry->srcPort = KSZ8565_PORT3;
1409  break;
1411  entry->srcPort = KSZ8565_PORT4;
1412  break;
1414  entry->srcPort = KSZ8565_PORT5;
1415  break;
1416  default:
1417  entry->srcPort = 0;
1418  break;
1419  }
1420 
1421  //Read the ALU Table Entry 3 register
1423 
1424  //Copy MAC address (first 16 bits)
1425  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1426  entry->macAddr.b[1] = value & 0xFF;
1427 
1428  //Read the ALU Table Entry 4 register
1430 
1431  //Copy MAC address (last 32 bits)
1432  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1433  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1434  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1435  entry->macAddr.b[5] = value & 0xFF;
1436 
1437  //Successful processing
1438  error = NO_ERROR;
1439  }
1440  else
1441  {
1442  //The search can be stopped any time by setting the START_FINISH bit to 0
1444 
1445  //The end of the table has been reached
1446  error = ERROR_END_OF_TABLE;
1447  }
1448 
1449  //Return status code
1450  return error;
1451 }
1452 
1453 
1454 /**
1455  * @brief Flush dynamic MAC table
1456  * @param[in] interface Underlying network interface
1457  * @param[in] port Port number
1458  **/
1459 
1461 {
1462  uint_t temp;
1463  uint8_t state;
1464 
1465  //Flush only dynamic table entries
1470 
1471  //Valid port number?
1472  if(port >= KSZ8565_PORT1 && port <= KSZ8565_PORT5 &&
1474  {
1475  //Save the current state of the port
1477 
1478  //Turn off learning capability
1481 
1482  //All the entries associated with a port that has its learning capability
1483  //being turned off will be flushed
1487 
1488  //Restore the original state of the port
1490  }
1491  else
1492  {
1493  //Trigger a flush of the entire address lookup table
1497  }
1498 }
1499 
1500 
1501 /**
1502  * @brief Set forward ports for unknown multicast packets
1503  * @param[in] interface Underlying network interface
1504  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1505  * @param[in] forwardPorts Port map
1506  **/
1507 
1509  bool_t enable, uint32_t forwardPorts)
1510 {
1511  uint32_t temp;
1512 
1513  //Read Unknown Multicast Control register
1515 
1516  //Clear port map
1518 
1519  //Enable or disable forwarding of unknown multicast packets
1520  if(enable)
1521  {
1522  //Enable forwarding
1524 
1525  //Check whether unknown multicast packets should be forwarded to the CPU port
1526  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1527  {
1529  }
1530 
1531  //Select the desired forward ports
1532  temp |= forwardPorts & KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL;
1533  }
1534  else
1535  {
1536  //Disable forwarding
1538  }
1539 
1540  //Write the value back to Unknown Multicast Control register
1542 }
1543 
1544 
1545 /**
1546  * @brief Write PHY register
1547  * @param[in] interface Underlying network interface
1548  * @param[in] port Port number
1549  * @param[in] address PHY register address
1550  * @param[in] data Register value
1551  **/
1552 
1553 void ksz8565WritePhyReg(NetInterface *interface, uint8_t port,
1554  uint8_t address, uint16_t data)
1555 {
1556  uint16_t n;
1557 
1558  //SPI slave mode?
1559  if(interface->spiDriver != NULL)
1560  {
1561  //The SPI interface provides access to all PHY registers
1563  //Write the 16-bit value
1564  ksz8565WriteSwitchReg16(interface, n, data);
1565  }
1566  else if(interface->smiDriver != NULL)
1567  {
1568  //Write the specified PHY register
1569  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1570  }
1571  else
1572  {
1573  //Write the specified PHY register
1574  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1575  }
1576 }
1577 
1578 
1579 /**
1580  * @brief Read PHY register
1581  * @param[in] interface Underlying network interface
1582  * @param[in] port Port number
1583  * @param[in] address PHY register address
1584  * @return Register value
1585  **/
1586 
1587 uint16_t ksz8565ReadPhyReg(NetInterface *interface, uint8_t port,
1588  uint8_t address)
1589 {
1590  uint16_t n;
1591  uint16_t data;
1592 
1593  //SPI slave mode?
1594  if(interface->spiDriver != NULL)
1595  {
1596  //The SPI interface provides access to all PHY registers
1598  //Read the 16-bit value
1599  data = ksz8565ReadSwitchReg16(interface, n);
1600  }
1601  else if(interface->smiDriver != NULL)
1602  {
1603  //Read the specified PHY register
1604  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1605  }
1606  else
1607  {
1608  //Read the specified PHY register
1609  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1610  }
1611 
1612  //Return register value
1613  return data;
1614 }
1615 
1616 
1617 /**
1618  * @brief Dump PHY registers for debugging purpose
1619  * @param[in] interface Underlying network interface
1620  * @param[in] port Port number
1621  **/
1622 
1623 void ksz8565DumpPhyReg(NetInterface *interface, uint8_t port)
1624 {
1625  uint8_t i;
1626 
1627  //Loop through PHY registers
1628  for(i = 0; i < 32; i++)
1629  {
1630  //Display current PHY register
1631  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1632  ksz8565ReadPhyReg(interface, port, i));
1633  }
1634 
1635  //Terminate with a line feed
1636  TRACE_DEBUG("\r\n");
1637 }
1638 
1639 
1640 /**
1641  * @brief Write MMD register
1642  * @param[in] interface Underlying network interface
1643  * @param[in] port Port number
1644  * @param[in] devAddr Device address
1645  * @param[in] regAddr Register address
1646  * @param[in] data Register value
1647  **/
1648 
1649 void ksz8565WriteMmdReg(NetInterface *interface, uint8_t port,
1650  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1651 {
1652  //Select register operation
1655 
1656  //Write MMD register address
1658 
1659  //Select data operation
1662 
1663  //Write the content of the MMD register
1665 }
1666 
1667 
1668 /**
1669  * @brief Read MMD register
1670  * @param[in] interface Underlying network interface
1671  * @param[in] port Port number
1672  * @param[in] devAddr Device address
1673  * @param[in] regAddr Register address
1674  * @return Register value
1675  **/
1676 
1677 uint16_t ksz8565ReadMmdReg(NetInterface *interface, uint8_t port,
1678  uint8_t devAddr, uint16_t regAddr)
1679 {
1680  //Select register operation
1683 
1684  //Write MMD register address
1686 
1687  //Select data operation
1690 
1691  //Read the content of the MMD register
1692  return ksz8565ReadPhyReg(interface, port, KSZ8565_MMDAADR);
1693 }
1694 
1695 
1696 /**
1697  * @brief Write switch register (8 bits)
1698  * @param[in] interface Underlying network interface
1699  * @param[in] address Switch register address
1700  * @param[in] data Register value
1701  **/
1702 
1703 void ksz8565WriteSwitchReg8(NetInterface *interface, uint16_t address,
1704  uint8_t data)
1705 {
1706  uint32_t command;
1707 
1708  //SPI slave mode?
1709  if(interface->spiDriver != NULL)
1710  {
1711  //Set up a write operation
1712  command = KSZ8565_SPI_CMD_WRITE;
1713  //Set register address
1714  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1715 
1716  //Pull the CS pin low
1717  interface->spiDriver->assertCs();
1718 
1719  //Write 32-bit command
1720  interface->spiDriver->transfer((command >> 24) & 0xFF);
1721  interface->spiDriver->transfer((command >> 16) & 0xFF);
1722  interface->spiDriver->transfer((command >> 8) & 0xFF);
1723  interface->spiDriver->transfer(command & 0xFF);
1724 
1725  //Write 8-bit data
1726  interface->spiDriver->transfer(data);
1727 
1728  //Terminate the operation by raising the CS pin
1729  interface->spiDriver->deassertCs();
1730  }
1731  else
1732  {
1733  //The MDC/MDIO interface does not have access to all the configuration
1734  //registers. It can only access the standard MIIM registers
1735  }
1736 }
1737 
1738 
1739 /**
1740  * @brief Read switch register (8 bits)
1741  * @param[in] interface Underlying network interface
1742  * @param[in] address Switch register address
1743  * @return Register value
1744  **/
1745 
1746 uint8_t ksz8565ReadSwitchReg8(NetInterface *interface, uint16_t address)
1747 {
1748  uint8_t data;
1749  uint32_t command;
1750 
1751  //SPI slave mode?
1752  if(interface->spiDriver != NULL)
1753  {
1754  //Set up a read operation
1755  command = KSZ8565_SPI_CMD_READ;
1756  //Set register address
1757  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1758 
1759  //Pull the CS pin low
1760  interface->spiDriver->assertCs();
1761 
1762  //Write 32-bit command
1763  interface->spiDriver->transfer((command >> 24) & 0xFF);
1764  interface->spiDriver->transfer((command >> 16) & 0xFF);
1765  interface->spiDriver->transfer((command >> 8) & 0xFF);
1766  interface->spiDriver->transfer(command & 0xFF);
1767 
1768  //Read 8-bit data
1769  data = interface->spiDriver->transfer(0xFF);
1770 
1771  //Terminate the operation by raising the CS pin
1772  interface->spiDriver->deassertCs();
1773  }
1774  else
1775  {
1776  //The MDC/MDIO interface does not have access to all the configuration
1777  //registers. It can only access the standard MIIM registers
1778  data = 0;
1779  }
1780 
1781  //Return register value
1782  return data;
1783 }
1784 
1785 
1786 /**
1787  * @brief Write switch register (16 bits)
1788  * @param[in] interface Underlying network interface
1789  * @param[in] address Switch register address
1790  * @param[in] data Register value
1791  **/
1792 
1794  uint16_t data)
1795 {
1796  uint32_t command;
1797 
1798  //SPI slave mode?
1799  if(interface->spiDriver != NULL)
1800  {
1801  //Set up a write operation
1802  command = KSZ8565_SPI_CMD_WRITE;
1803  //Set register address
1804  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1805 
1806  //Pull the CS pin low
1807  interface->spiDriver->assertCs();
1808 
1809  //Write 32-bit command
1810  interface->spiDriver->transfer((command >> 24) & 0xFF);
1811  interface->spiDriver->transfer((command >> 16) & 0xFF);
1812  interface->spiDriver->transfer((command >> 8) & 0xFF);
1813  interface->spiDriver->transfer(command & 0xFF);
1814 
1815  //Write 16-bit data
1816  interface->spiDriver->transfer((data >> 8) & 0xFF);
1817  interface->spiDriver->transfer(data & 0xFF);
1818 
1819  //Terminate the operation by raising the CS pin
1820  interface->spiDriver->deassertCs();
1821  }
1822  else
1823  {
1824  //The MDC/MDIO interface does not have access to all the configuration
1825  //registers. It can only access the standard MIIM registers
1826  }
1827 }
1828 
1829 
1830 /**
1831  * @brief Read switch register (16 bits)
1832  * @param[in] interface Underlying network interface
1833  * @param[in] address Switch register address
1834  * @return Register value
1835  **/
1836 
1837 uint16_t ksz8565ReadSwitchReg16(NetInterface *interface, uint16_t address)
1838 {
1839  uint16_t data;
1840  uint32_t command;
1841 
1842  //SPI slave mode?
1843  if(interface->spiDriver != NULL)
1844  {
1845  //Set up a read operation
1846  command = KSZ8565_SPI_CMD_READ;
1847  //Set register address
1848  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1849 
1850  //Pull the CS pin low
1851  interface->spiDriver->assertCs();
1852 
1853  //Write 32-bit command
1854  interface->spiDriver->transfer((command >> 24) & 0xFF);
1855  interface->spiDriver->transfer((command >> 16) & 0xFF);
1856  interface->spiDriver->transfer((command >> 8) & 0xFF);
1857  interface->spiDriver->transfer(command & 0xFF);
1858 
1859  //Read 16-bit data
1860  data = interface->spiDriver->transfer(0xFF) << 8;
1861  data |= interface->spiDriver->transfer(0xFF);
1862 
1863  //Terminate the operation by raising the CS pin
1864  interface->spiDriver->deassertCs();
1865  }
1866  else
1867  {
1868  //The MDC/MDIO interface does not have access to all the configuration
1869  //registers. It can only access the standard MIIM registers
1870  data = 0;
1871  }
1872 
1873  //Return register value
1874  return data;
1875 }
1876 
1877 
1878 /**
1879  * @brief Write switch register (32 bits)
1880  * @param[in] interface Underlying network interface
1881  * @param[in] address Switch register address
1882  * @param[in] data Register value
1883  **/
1884 
1886  uint32_t data)
1887 {
1888  uint32_t command;
1889 
1890  //SPI slave mode?
1891  if(interface->spiDriver != NULL)
1892  {
1893  //Set up a write operation
1894  command = KSZ8565_SPI_CMD_WRITE;
1895  //Set register address
1896  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1897 
1898  //Pull the CS pin low
1899  interface->spiDriver->assertCs();
1900 
1901  //Write 32-bit command
1902  interface->spiDriver->transfer((command >> 24) & 0xFF);
1903  interface->spiDriver->transfer((command >> 16) & 0xFF);
1904  interface->spiDriver->transfer((command >> 8) & 0xFF);
1905  interface->spiDriver->transfer(command & 0xFF);
1906 
1907  //Write 32-bit data
1908  interface->spiDriver->transfer((data >> 24) & 0xFF);
1909  interface->spiDriver->transfer((data >> 16) & 0xFF);
1910  interface->spiDriver->transfer((data >> 8) & 0xFF);
1911  interface->spiDriver->transfer(data & 0xFF);
1912 
1913  //Terminate the operation by raising the CS pin
1914  interface->spiDriver->deassertCs();
1915  }
1916  else
1917  {
1918  //The MDC/MDIO interface does not have access to all the configuration
1919  //registers. It can only access the standard MIIM registers
1920  }
1921 }
1922 
1923 
1924 /**
1925  * @brief Read switch register (32 bits)
1926  * @param[in] interface Underlying network interface
1927  * @param[in] address Switch register address
1928  * @return Register value
1929  **/
1930 
1931 uint32_t ksz8565ReadSwitchReg32(NetInterface *interface, uint16_t address)
1932 {
1933  uint32_t data;
1934  uint32_t command;
1935 
1936  //SPI slave mode?
1937  if(interface->spiDriver != NULL)
1938  {
1939  //Set up a read operation
1940  command = KSZ8565_SPI_CMD_READ;
1941  //Set register address
1942  command |= (address << 5) & KSZ8565_SPI_CMD_ADDR;
1943 
1944  //Pull the CS pin low
1945  interface->spiDriver->assertCs();
1946 
1947  //Write 32-bit command
1948  interface->spiDriver->transfer((command >> 24) & 0xFF);
1949  interface->spiDriver->transfer((command >> 16) & 0xFF);
1950  interface->spiDriver->transfer((command >> 8) & 0xFF);
1951  interface->spiDriver->transfer(command & 0xFF);
1952 
1953  //Read 32-bit data
1954  data = interface->spiDriver->transfer(0xFF) << 24;
1955  data |= interface->spiDriver->transfer(0xFF) << 16;
1956  data |= interface->spiDriver->transfer(0xFF) << 8;
1957  data |= interface->spiDriver->transfer(0xFF);
1958 
1959  //Terminate the operation by raising the CS pin
1960  interface->spiDriver->deassertCs();
1961  }
1962  else
1963  {
1964  //The MDC/MDIO interface does not have access to all the configuration
1965  //registers. It can only access the standard MIIM registers
1966  data = 0;
1967  }
1968 
1969  //Return register value
1970  return data;
1971 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
#define KSZ8565_CHIP_ID1_DEFAULT
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define KSZ8565_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define NetContext
Definition: net.h:36
int bool_t
Definition: compiler_port.h:63
#define KSZ8565_PORT1
@ ERROR_NOT_FOUND
Definition: error.h:148
#define KSZ8565_ALU_TABLE_ENTRY4
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
uint32_t destPorts
Definition: nic.h:152
#define KSZ8565_PORT5
#define KSZ8565_SWITCH_LUE_CTRL3
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define KSZ8565_PHYCON_DUPLEX_STATUS
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
#define KSZ8565_TAIL_TAG_PORT_BLOCKING_OVERRIDE
@ ERROR_END_OF_TABLE
Definition: error.h:292
error_t ksz8565Init(NetInterface *interface)
KSZ8565 Ethernet switch initialization.
#define KSZ8565_PORT5_XMII_CTRL1_SPEED_1000
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define TRUE
Definition: os_port.h:50
void ksz8565EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_ACTION
uint8_t data[]
Definition: ethernet.h:224
#define KSZ8565_MMD_LED_MODE
NicDuplexMode ksz8565GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
SwitchPortState ksz8565GetPortState(NetInterface *interface, uint8_t port)
Get port state.
void ksz8565EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
#define KSZ8565_TAIL_TAG_NORMAL_ADDR_LOOKUP
const SwitchDriver ksz8565SwitchDriver
KSZ8565 Ethernet switch driver.
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
#define KSZ8565_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
#define KSZ8565_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
#define KSZ8565_PHYCON_SPEED_10BT
uint32_t ksz8565GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
uint8_t type
Definition: coap_common.h:176
#define KSZ8565_TAIL_TAG_DEST_PORT3
#define KSZ8565_PHYCON_SPEED_100BTX
@ ERROR_INVALID_PORT
Definition: error.h:104
#define KSZ8565_MMDACR_FUNC_DATA_NO_POST_INC
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT5
#define KSZ8565_CHIP_ID1
@ ERROR_TABLE_FULL
Definition: error.h:291
void ksz8565WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
bool_t ksz8565GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
#define KSZ8565_TAIL_TAG_DEST_PORT1
EthHeader
Definition: ethernet.h:225
#define KSZ8565_ALU_TABLE_ENTRY2_PORT_FORWARD
#define KSZ8565_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
#define KSZ8565_PORT5_XMII_CTRL1_IF_TYPE
#define KSZ8565_ALU_TABLE_ENTRY1
error_t ksz8565AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define KSZ8565_PORTn_MSTP_STATE_TRANSMIT_EN
const uint16_t ksz8565IngressTailTag[5]
Tail tag rules (host to KSZ8565)
void ksz8565WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
#define KSZ8565_PORTn_MSTP_STATE(port)
#define KSZ8565_STATIC_TABLE_ENTRY2_OVERRIDE
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD
#define KSZ8565_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
void ksz8565DisableIrq(NetInterface *interface)
Disable interrupts.
#define KSZ8565_MMDAADR
#define FALSE
Definition: os_port.h:46
void ksz8565FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
#define KSZ8565_PORTn_OP_CTRL0_TAIL_TAG_EN
#define KSZ8565_SWITCH_MAC_CTRL0
error_t
Error codes.
Definition: error.h:43
void ksz8565SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
#define KSZ8565_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
#define KSZ8565_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
uint16_t ksz8565ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
void ksz8565FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
#define KSZ8565_PORT_RESERVED1
#define KSZ8565_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
uint8_t ksz8565ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
void ksz8565SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
#define KSZ8565_SWITCH_OP_START_SWITCH
#define KSZ8565_ALU_TABLE_ENTRY2_PORT1_FORWARD
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define KSZ8565_STATIC_MAC_TABLE_SIZE
#define KSZ8565_PORT3
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void ksz8565EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
void ksz8565WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
#define KSZ8565_ALU_TABLE_ENTRY2_PORT2_FORWARD
#define KSZ8565_PORT5_XMII_CTRL1_IF_TYPE_RGMII
#define KSZ8565_SPI_CMD_WRITE
#define KSZ8565_TAIL_TAG_SRC_PORT
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
#define KSZ8565_STATIC_TABLE_ENTRY4
#define KSZ8565_ALU_TABLE_ENTRY3
#define NetTxAncillary
Definition: net_misc.h:36
error_t ksz8565UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
#define KSZ8565_PORTn_MSTP_STATE_RECEIVE_EN
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
#define KSZ8565_STATIC_TABLE_ENTRY1
void ksz8565WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
error_t ksz8565DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
__weak_func void ksz8565EventHandler(NetInterface *interface)
KSZ8565 event handler.
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define KSZ8565_SWITCH_LUE_CTRL2_FLUSH_OPTION
#define MIN(a, b)
Definition: os_port.h:63
void ksz8565SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
#define KSZ8565_TAIL_TAG_DEST_PORT2
#define KSZ8565_PORTn_ETH_PHY_REG(port, addr)
#define KSZ8565_PHYCON
#define KSZ8565_ALU_TABLE_ENTRY2_PORT5_FORWARD
#define KSZ8565_SWITCH_LUE_CTRL0
#define KSZ8565_BMSR_LINK_STATUS
__weak_func void ksz8565InitHook(NetInterface *interface)
KSZ8565 custom configuration.
#define KSZ8565_ALU_TABLE_CTRL
#define KSZ8565_STATIC_MCAST_TABLE_CTRL
uint32_t ksz8565ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
#define KSZ8565_PORT5_XMII_CTRL0
#define KSZ8565_SWITCH_LUE_CTRL1
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
#define KSZ8565_MMDACR
uint16_t port
Definition: dns_common.h:270
#define KSZ8565_PORT5_XMII_CTRL1_RGMII_ID_EG
#define KSZ8565_MMDACR_DEVAD
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define KSZ8565_UNKONWN_MULTICAST_CTRL
#define KSZ8565_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
#define KSZ8565_ALU_TABLE_CTRL_VALID
#define KSZ8565_MMD_LED_MODE_RESERVED_DEFAULT
#define KSZ8565_PORT5_XMII_CTRL1_RGMII_ID_IG
#define KSZ8565_PORT5_OP_CTRL0
uint16_t regAddr
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
Ethernet switch driver.
Definition: nic.h:325
#define KSZ8565_BMSR
#define KSZ8565_ALU_TABLE_ENTRY2_PORT4_FORWARD
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
#define KSZ8565_PORT4
#define KSZ8565_PORT5_MASK
#define KSZ8565_PORT2
@ 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
uint16_t ksz8565ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
Ipv6Addr address[]
Definition: ipv6.h:345
#define KSZ8565_GLOBAL_PORT_MIRROR_SNOOP_CTRL
#define KSZ8565_MMD_LED_MODE_LED_MODE_SINGLE
#define KSZ8565_PORTn_MSTP_STATE_LEARNING_DIS
error_t ksz8565GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
NicDuplexMode
Duplex mode.
Definition: nic.h:122
#define KSZ8565_STATIC_TABLE_ENTRY1_VALID
MacAddr macAddr
Definition: nic.h:150
#define KSZ8565_PORT5_XMII_CTRL1
#define KSZ8565_PORT5_XMII_CTRL0_SPEED_10_100
uint8_t srcPort
Definition: nic.h:151
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
#define KSZ8565_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define KSZ8565_STATIC_MCAST_TABLE_CTRL_START_FINISH
uint8_t value[]
Definition: tcp.h:376
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
#define KSZ8565_UNKONWN_MULTICAST_CTRL_FWD_MAP
#define KSZ8565_ALU_TABLE_CTRL_ACTION_SEARCH
void ksz8565WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
void ksz8565DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
__weak_func void ksz8565Tick(NetInterface *interface)
KSZ8565 timer handler.
#define KSZ8565_PORT5_XMII_CTRL0_DUPLEX
#define KSZ8565_MMD_EEE_ADV
error_t ksz8565TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
#define KSZ8565_SWITCH_OP
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define KSZ8565_SPI_CMD_ADDR
#define KSZ8565_PORT_MASK
error_t ksz8565GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define KSZ8565_STATIC_TABLE_ENTRY2
void ksz8565EnableIrq(NetInterface *interface)
Enable interrupts.
#define KSZ8565_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
#define KSZ8565_TAIL_TAG_DEST_PORT4
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
#define KSZ8565_ALU_TABLE_ENTRY2_PORT3_FORWARD
#define KSZ8565_SWITCH_LUE_CTRL2
#define KSZ8565_MMDACR_FUNC_ADDR
KSZ8565 5-port Ethernet switch driver.
#define KSZ8565_ALU_TABLE_CTRL_START_FINISH
#define KSZ8565_PORT_RESERVED2
Helper functions for Ethernet.
#define KSZ8565_ALU_TABLE_ENTRY2
@ NO_ERROR
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:153
Debugging facilities.
Forwarding database entry.
Definition: nic.h:149
#define KSZ8565_SPI_CMD_READ
#define KSZ8565_STATIC_TABLE_ENTRY3
uint16_t ksz8565ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
#define KSZ8565_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN