ksz8567_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz8567_driver.c
3  * @brief KSZ8567 7-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 KSZ8567 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to KSZ8567)
75  **/
76 
77 const uint16_t ksz8567IngressTailTag[6] =
78 {
85 };
86 
87 
88 /**
89  * @brief KSZ8567 Ethernet switch initialization
90  * @param[in] interface Underlying network interface
91  * @return Error code
92  **/
93 
95 {
96  uint_t port;
97  uint8_t temp;
98 
99  //Debug message
100  TRACE_INFO("Initializing KSZ8567...\r\n");
101 
102  //SPI slave mode?
103  if(interface->spiDriver != NULL)
104  {
105  //Initialize SPI interface
106  interface->spiDriver->init();
107 
108  //Wait for the serial interface to be ready
109  do
110  {
111  //Read CHIP_ID1 register
112  temp = ksz8567ReadSwitchReg8(interface, KSZ8567_CHIP_ID1);
113 
114  //The returned data is invalid until the serial interface is ready
115  } while(temp != KSZ8567_CHIP_ID1_DEFAULT);
116 
117 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
118  //Enable tail tag feature
122 
123  //Disable frame length check (silicon errata workaround 12)
127 #else
128  //Disable tail tag feature
132 
133  //Enable frame length check
137 #endif
138 
139  //Loop through the ports
141  {
142 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
143  //Port separation mode?
144  if(interface->port != 0)
145  {
146  //Disable packet transmission and address learning
148  }
149  else
150 #endif
151  {
152  //Enable transmission, reception and address learning
154  }
155  }
156 
157  //Restore default age count
161 
162  //Restore default age period
165 
166  //Add internal delay to ingress and egress RGMII clocks
171 
172  //Start switch operation
175  }
176  else if(interface->smiDriver != NULL)
177  {
178  //Initialize serial management interface
179  interface->smiDriver->init();
180  }
181  else
182  {
183  //Just for sanity
184  }
185 
186  //Loop through the ports
188  {
189  //Improve PHY receive performance (silicon errata workaround 1)
190  ksz8567WriteMmdReg(interface, port, 0x01, 0x6F, 0xDD0B);
191  ksz8567WriteMmdReg(interface, port, 0x01, 0x8F, 0x6032);
192  ksz8567WriteMmdReg(interface, port, 0x01, 0x9D, 0x248C);
193  ksz8567WriteMmdReg(interface, port, 0x01, 0x75, 0x0060);
194  ksz8567WriteMmdReg(interface, port, 0x01, 0xD3, 0x7777);
195  ksz8567WriteMmdReg(interface, port, 0x1C, 0x06, 0x3008);
196  ksz8567WriteMmdReg(interface, port, 0x1C, 0x08, 0x2001);
197 
198  //Improve transmit waveform amplitude (silicon errata workaround 2)
199  ksz8567WriteMmdReg(interface, port, 0x1C, 0x04, 0x00D0);
200 
201  //EEE must be manually disabled (silicon errata workaround 4)
203 
204  //Adjust power supply settings (silicon errata workaround 7)
205  ksz8567WriteMmdReg(interface, port, 0x1C, 0x13, 0x6EFF);
206  ksz8567WriteMmdReg(interface, port, 0x1C, 0x14, 0xE6FF);
207  ksz8567WriteMmdReg(interface, port, 0x1C, 0x15, 0x6EFF);
208  ksz8567WriteMmdReg(interface, port, 0x1C, 0x16, 0xE6FF);
209  ksz8567WriteMmdReg(interface, port, 0x1C, 0x17, 0x00FF);
210  ksz8567WriteMmdReg(interface, port, 0x1C, 0x18, 0x43FF);
211  ksz8567WriteMmdReg(interface, port, 0x1C, 0x19, 0xC3FF);
212  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1A, 0x6FFF);
213  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1B, 0x07FF);
214  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1C, 0x0FFF);
215  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1D, 0xE7FF);
216  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1E, 0xEFFF);
217  ksz8567WriteMmdReg(interface, port, 0x1C, 0x20, 0xEEEE);
218 
219  //Select single-LED mode
223 
224  //Implement workaround for single-LED mode
225  ksz8567WritePhyReg(interface, port, 0x1E, 0xFA00);
226 
227  //Debug message
228  TRACE_DEBUG("Port %u:\r\n", port);
229  //Dump PHY registers for debugging purpose
230  ksz8567DumpPhyReg(interface, port);
231  }
232 
233  //Perform custom configuration
234  ksz8567InitHook(interface);
235 
236  //Force the TCP/IP stack to poll the link state at startup
237  interface->phyEvent = TRUE;
238  //Notify the TCP/IP stack of the event
239  osSetEvent(&interface->netContext->event);
240 
241  //Successful initialization
242  return NO_ERROR;
243 }
244 
245 
246 /**
247  * @brief KSZ8567 custom configuration
248  * @param[in] interface Underlying network interface
249  **/
250 
251 __weak_func void ksz8567InitHook(NetInterface *interface)
252 {
253 }
254 
255 
256 /**
257  * @brief KSZ8567 timer handler
258  * @param[in] interface Underlying network interface
259  **/
260 
261 __weak_func void ksz8567Tick(NetInterface *interface)
262 {
263  uint_t port;
264  bool_t linkState;
265 
266 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
267  //Port separation mode?
268  if(interface->port != 0)
269  {
270  uint_t i;
271  NetContext *context;
272  NetInterface *virtualInterface;
273 
274  //Point to the TCP/IP stack context
275  context = interface->netContext;
276 
277  //Loop through network interfaces
278  for(i = 0; i < context->numInterfaces; i++)
279  {
280  //Point to the current interface
281  virtualInterface = &context->interfaces[i];
282 
283  //Check whether the current virtual interface is attached to the
284  //physical interface
285  if(virtualInterface == interface ||
286  virtualInterface->parent == interface)
287  {
288  //Retrieve current link state
289  linkState = ksz8567GetLinkState(interface, virtualInterface->port);
290 
291  //Link up or link down event?
292  if(linkState != virtualInterface->linkState)
293  {
294  //Set event flag
295  interface->phyEvent = TRUE;
296  //Notify the TCP/IP stack of the event
297  osSetEvent(&interface->netContext->event);
298  }
299  }
300  }
301  }
302  else
303 #endif
304  {
305  //Initialize link state
306  linkState = FALSE;
307 
308  //Loop through the ports
310  {
311  //Retrieve current link state
312  if(ksz8567GetLinkState(interface, port))
313  {
314  linkState = TRUE;
315  }
316  }
317 
318  //Link up or link down event?
319  if(linkState != interface->linkState)
320  {
321  //Set event flag
322  interface->phyEvent = TRUE;
323  //Notify the TCP/IP stack of the event
324  osSetEvent(&interface->netContext->event);
325  }
326  }
327 }
328 
329 
330 /**
331  * @brief Enable interrupts
332  * @param[in] interface Underlying network interface
333  **/
334 
336 {
337 }
338 
339 
340 /**
341  * @brief Disable interrupts
342  * @param[in] interface Underlying network interface
343  **/
344 
346 {
347 }
348 
349 
350 /**
351  * @brief KSZ8567 event handler
352  * @param[in] interface Underlying network interface
353  **/
354 
355 __weak_func void ksz8567EventHandler(NetInterface *interface)
356 {
357  uint_t port;
358  bool_t linkState;
359 
360 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
361  //Port separation mode?
362  if(interface->port != 0)
363  {
364  uint_t i;
365  NetContext *context;
366  NetInterface *virtualInterface;
367 
368  //Point to the TCP/IP stack context
369  context = interface->netContext;
370 
371  //Loop through network interfaces
372  for(i = 0; i < context->numInterfaces; i++)
373  {
374  //Point to the current interface
375  virtualInterface = &context->interfaces[i];
376 
377  //Check whether the current virtual interface is attached to the
378  //physical interface
379  if(virtualInterface == interface ||
380  virtualInterface->parent == interface)
381  {
382  //Get the port number associated with the current interface
383  port = virtualInterface->port;
384 
385  //Valid port?
386  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
387  {
388  //Retrieve current link state
389  linkState = ksz8567GetLinkState(interface, port);
390 
391  //Link up event?
392  if(linkState && !virtualInterface->linkState)
393  {
394  //Retrieve host interface speed
395  interface->linkSpeed = ksz8567GetLinkSpeed(interface,
396  KSZ8567_PORT6);
397 
398  //Retrieve host interface duplex mode
399  interface->duplexMode = ksz8567GetDuplexMode(interface,
400  KSZ8567_PORT6);
401 
402  //Adjust MAC configuration parameters for proper operation
403  interface->nicDriver->updateMacConfig(interface);
404 
405  //Check current speed
406  virtualInterface->linkSpeed = ksz8567GetLinkSpeed(interface,
407  port);
408 
409  //Check current duplex mode
410  virtualInterface->duplexMode = ksz8567GetDuplexMode(interface,
411  port);
412 
413  //Update link state
414  virtualInterface->linkState = TRUE;
415 
416  //Process link state change event
417  nicNotifyLinkChange(virtualInterface);
418  }
419  //Link down event
420  else if(!linkState && virtualInterface->linkState)
421  {
422  //Update link state
423  virtualInterface->linkState = FALSE;
424 
425  //Process link state change event
426  nicNotifyLinkChange(virtualInterface);
427  }
428  }
429  }
430  }
431  }
432  else
433 #endif
434  {
435  //Initialize link state
436  linkState = FALSE;
437 
438  //Loop through the ports
440  {
441  //Retrieve current link state
442  if(ksz8567GetLinkState(interface, port))
443  {
444  linkState = TRUE;
445  }
446  }
447 
448  //Link up event?
449  if(linkState)
450  {
451  //Retrieve host interface speed
452  interface->linkSpeed = ksz8567GetLinkSpeed(interface, KSZ8567_PORT6);
453  //Retrieve host interface duplex mode
454  interface->duplexMode = ksz8567GetDuplexMode(interface, KSZ8567_PORT6);
455 
456  //Adjust MAC configuration parameters for proper operation
457  interface->nicDriver->updateMacConfig(interface);
458 
459  //Update link state
460  interface->linkState = TRUE;
461  }
462  else
463  {
464  //Update link state
465  interface->linkState = FALSE;
466  }
467 
468  //Process link state change event
469  nicNotifyLinkChange(interface);
470  }
471 }
472 
473 
474 /**
475  * @brief Add tail tag to Ethernet frame
476  * @param[in] interface Underlying network interface
477  * @param[in] buffer Multi-part buffer containing the payload
478  * @param[in,out] offset Offset to the first payload byte
479  * @param[in] ancillary Additional options passed to the stack along with
480  * the packet
481  * @return Error code
482  **/
483 
485  size_t *offset, NetTxAncillary *ancillary)
486 {
487  error_t error;
488 
489  //Initialize status code
490  error = NO_ERROR;
491 
492 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
493  //SPI slave mode?
494  if(interface->spiDriver != NULL)
495  {
496  //Valid port?
497  if(ancillary->port <= KSZ8567_PORT5)
498  {
499  size_t length;
500  const uint16_t *tailTag;
501 
502  //The two-byte tail tagging is used to indicate the destination port
503  tailTag = &ksz8567IngressTailTag[ancillary->port];
504 
505  //Retrieve the length of the Ethernet frame
506  length = netBufferGetLength(buffer) - *offset;
507 
508  //The host controller should manually add padding to the packet before
509  //inserting the tail tag
510  error = ethPadFrame(buffer, &length);
511 
512  //Check status code
513  if(!error)
514  {
515  //The tail tag is inserted at the end of the packet, just before
516  //the CRC
517  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
518  }
519  }
520  else
521  {
522  //The port number is not valid
523  error = ERROR_INVALID_PORT;
524  }
525  }
526 #endif
527 
528  //Return status code
529  return error;
530 }
531 
532 
533 /**
534  * @brief Decode tail tag from incoming Ethernet frame
535  * @param[in] interface Underlying network interface
536  * @param[in,out] frame Pointer to the received Ethernet frame
537  * @param[in,out] length Length of the frame, in bytes
538  * @param[in,out] ancillary Additional options passed to the stack along with
539  * the packet
540  * @return Error code
541  **/
542 
543 error_t ksz8567UntagFrame(NetInterface *interface, uint8_t **frame,
544  size_t *length, NetRxAncillary *ancillary)
545 {
546  error_t error;
547 
548  //Initialize status code
549  error = NO_ERROR;
550 
551 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
552  //SPI slave mode?
553  if(interface->spiDriver != NULL)
554  {
555  //Valid Ethernet frame received?
556  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
557  {
558  uint8_t *tailTag;
559 
560  //The tail tag is inserted at the end of the packet, just before
561  //the CRC
562  tailTag = *frame + *length - sizeof(uint8_t);
563 
564  //The one byte tail tagging is used to indicate the source port
565  ancillary->port = (*tailTag & KSZ8567_TAIL_TAG_SRC_PORT) + 1;
566 
567  //Strip tail tag from Ethernet frame
568  *length -= sizeof(uint8_t);
569  }
570  else
571  {
572  //Drop the received frame
573  error = ERROR_INVALID_LENGTH;
574  }
575  }
576  else
577  {
578  //Tail tagging mode cannot be enabled through MDC/MDIO interface
579  ancillary->port = 0;
580  }
581 #endif
582 
583  //Return status code
584  return error;
585 }
586 
587 
588 /**
589  * @brief Get link state
590  * @param[in] interface Underlying network interface
591  * @param[in] port Port number
592  * @return Link state
593  **/
594 
596 {
597  uint16_t value;
598  bool_t linkState;
599 
600  //Check port number
601  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
602  {
603  //Any link failure condition is latched in the BMSR register. Reading
604  //the register twice will always return the actual link status
605  value = ksz8567ReadPhyReg(interface, port, KSZ8567_BMSR);
606  value = ksz8567ReadPhyReg(interface, port, KSZ8567_BMSR);
607 
608  //Retrieve current link state
609  linkState = (value & KSZ8567_BMSR_LINK_STATUS) ? TRUE : FALSE;
610  }
611  else
612  {
613  //The specified port number is not valid
614  linkState = FALSE;
615  }
616 
617  //Return link status
618  return linkState;
619 }
620 
621 
622 /**
623  * @brief Get link speed
624  * @param[in] interface Underlying network interface
625  * @param[in] port Port number
626  * @return Link speed
627  **/
628 
629 uint32_t ksz8567GetLinkSpeed(NetInterface *interface, uint8_t port)
630 {
631  uint8_t type;
632  uint16_t value;
633  uint32_t linkSpeed;
634 
635  //Check port number
636  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
637  {
638  //Read PHY control register
640 
641  //Retrieve current link speed
643  {
644  //100BASE-TX
645  linkSpeed = NIC_LINK_SPEED_100MBPS;
646  }
647  else if((value & KSZ8567_PHYCON_SPEED_10BT) != 0)
648  {
649  //10BASE-T
650  linkSpeed = NIC_LINK_SPEED_10MBPS;
651  }
652  else
653  {
654  //The link speed is not valid
655  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
656  }
657  }
658  else if(port == KSZ8567_PORT6)
659  {
660  //SPI slave mode?
661  if(interface->spiDriver != NULL)
662  {
663  //Read port 6 XMII control 1 register
665 
666  //Retrieve host interface type
668 
669  //Gigabit interface?
672  {
673  //1000 Mb/s mode
674  linkSpeed = NIC_LINK_SPEED_1GBPS;
675  }
676  else
677  {
678  //Read port 6 XMII control 0 register
680 
681  //Retrieve host interface speed
683  {
684  //100 Mb/s mode
685  linkSpeed = NIC_LINK_SPEED_100MBPS;
686  }
687  else
688  {
689  //10 Mb/s mode
690  linkSpeed = NIC_LINK_SPEED_10MBPS;
691  }
692  }
693  }
694  else
695  {
696  //The MDC/MDIO interface does not have access to all the configuration
697  //registers. It can only access the standard MIIM registers
698  linkSpeed = NIC_LINK_SPEED_100MBPS;
699  }
700  }
701  else
702  {
703  //The specified port number is not valid
704  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
705  }
706 
707  //Return link speed
708  return linkSpeed;
709 }
710 
711 
712 /**
713  * @brief Get duplex mode
714  * @param[in] interface Underlying network interface
715  * @param[in] port Port number
716  * @return Duplex mode
717  **/
718 
720 {
721  uint16_t value;
722  NicDuplexMode duplexMode;
723 
724  //Check port number
725  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
726  {
727  //Read PHY control register
729 
730  //Retrieve current duplex mode
732  {
733  duplexMode = NIC_FULL_DUPLEX_MODE;
734  }
735  else
736  {
737  duplexMode = NIC_HALF_DUPLEX_MODE;
738  }
739  }
740  else if(port == KSZ8567_PORT6)
741  {
742  //SPI slave mode?
743  if(interface->spiDriver != NULL)
744  {
745  //Read port 6 XMII control 0 register
747 
748  //Retrieve host interface duplex mode
750  {
751  duplexMode = NIC_FULL_DUPLEX_MODE;
752  }
753  else
754  {
755  duplexMode = NIC_HALF_DUPLEX_MODE;
756  }
757  }
758  else
759  {
760  //The MDC/MDIO interface does not have access to all the configuration
761  //registers. It can only access the standard MIIM registers
762  duplexMode = NIC_FULL_DUPLEX_MODE;
763  }
764  }
765  else
766  {
767  //The specified port number is not valid
768  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
769  }
770 
771  //Return duplex mode
772  return duplexMode;
773 }
774 
775 
776 /**
777  * @brief Set port state
778  * @param[in] interface Underlying network interface
779  * @param[in] port Port number
780  * @param[in] state Port state
781  **/
782 
783 void ksz8567SetPortState(NetInterface *interface, uint8_t port,
784  SwitchPortState state)
785 {
786  uint8_t temp;
787 
788  //Check port number
789  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
790  {
791  //Read MSTP state register
793 
794  //Update port state
795  switch(state)
796  {
797  //Listening state
802  break;
803 
804  //Learning state
809  break;
810 
811  //Forwarding state
816  break;
817 
818  //Disabled state
819  default:
823  break;
824  }
825 
826  //Write the value back to MSTP state register
828  }
829 }
830 
831 
832 /**
833  * @brief Get port state
834  * @param[in] interface Underlying network interface
835  * @param[in] port Port number
836  * @return Port state
837  **/
838 
840 {
841  uint8_t temp;
842  SwitchPortState state;
843 
844  //Check port number
845  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
846  {
847  //Read MSTP state register
849 
850  //Check port state
851  if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
852  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
854  {
855  //Disabled state
857  }
858  else if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
859  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
861  {
862  //Listening state
864  }
865  else if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
866  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
868  {
869  //Learning state
871  }
872  else if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
873  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
875  {
876  //Forwarding state
878  }
879  else
880  {
881  //Unknown state
883  }
884  }
885  else
886  {
887  //The specified port number is not valid
889  }
890 
891  //Return port state
892  return state;
893 }
894 
895 
896 /**
897  * @brief Set aging time for dynamic filtering entries
898  * @param[in] interface Underlying network interface
899  * @param[in] agingTime Aging time, in seconds
900  **/
901 
902 void ksz8567SetAgingTime(NetInterface *interface, uint32_t agingTime)
903 {
904  //The Age Period in combination with the Age Count field determines the
905  //aging time of dynamic entries in the address lookup table
906  agingTime = (agingTime + 3) / 4;
907 
908  //Limit the range of the parameter
909  agingTime = MIN(agingTime, 255);
910 
911  //Write the value to Switch Lookup Engine Control 3 register
913  (uint8_t) agingTime);
914 }
915 
916 
917 /**
918  * @brief Enable IGMP snooping
919  * @param[in] interface Underlying network interface
920  * @param[in] enable Enable or disable IGMP snooping
921  **/
922 
924 {
925  uint8_t temp;
926 
927  //Read the Global Port Mirroring and Snooping Control register
928  temp = ksz8567ReadSwitchReg8(interface,
930 
931  //Enable or disable IGMP snooping
932  if(enable)
933  {
935  }
936  else
937  {
939  }
940 
941  //Write the value back to Global Port Mirroring and Snooping Control register
943  temp);
944 }
945 
946 
947 /**
948  * @brief Enable MLD snooping
949  * @param[in] interface Underlying network interface
950  * @param[in] enable Enable or disable MLD snooping
951  **/
952 
954 {
955  uint8_t temp;
956 
957  //Read the Global Port Mirroring and Snooping Control register
958  temp = ksz8567ReadSwitchReg8(interface,
960 
961  //Enable or disable MLD snooping
962  if(enable)
963  {
965  }
966  else
967  {
969  }
970 
971  //Write the value back to Global Port Mirroring and Snooping Control register
973  temp);
974 }
975 
976 
977 /**
978  * @brief Enable reserved multicast table
979  * @param[in] interface Underlying network interface
980  * @param[in] enable Enable or disable reserved group addresses
981  **/
982 
984 {
985  uint8_t temp;
986 
987  //Read the Switch Lookup Engine Control 0 register
989 
990  //Enable or disable the reserved multicast table
991  if(enable)
992  {
994  }
995  else
996  {
998  }
999 
1000  //Write the value back to Switch Lookup Engine Control 0 register
1002 }
1003 
1004 
1005 /**
1006  * @brief Add a new entry to the static MAC table
1007  * @param[in] interface Underlying network interface
1008  * @param[in] entry Pointer to the forwarding database entry
1009  * @return Error code
1010  **/
1011 
1013  const SwitchFdbEntry *entry)
1014 {
1015  error_t error;
1016  uint_t i;
1017  uint_t j;
1018  uint32_t value;
1019  SwitchFdbEntry currentEntry;
1020 
1021  //Keep track of the first free entry
1023 
1024  //Loop through the static MAC table
1025  for(i = 0; i < KSZ8567_STATIC_MAC_TABLE_SIZE; i++)
1026  {
1027  //Read current entry
1028  error = ksz8567GetStaticFdbEntry(interface, i, &currentEntry);
1029 
1030  //Valid entry?
1031  if(!error)
1032  {
1033  //Check whether the table already contains the specified MAC address
1034  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1035  {
1036  j = i;
1037  break;
1038  }
1039  }
1040  else
1041  {
1042  //Keep track of the first free entry
1044  {
1045  j = i;
1046  }
1047  }
1048  }
1049 
1050  //Any entry available?
1052  {
1053  //Write the Static Address Table Entry 1 register
1056 
1057  //Set the relevant forward ports
1058  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1059  {
1061  }
1062  else
1063  {
1064  value = entry->destPorts & KSZ8567_PORT_MASK;
1065  }
1066 
1067  //Enable overriding of port state
1068  if(entry->override)
1069  {
1071  }
1072 
1073  //Write the Static Address Table Entry 2 register
1075 
1076  //Copy MAC address (first 16 bits)
1077  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1078 
1079  //Write the Static Address Table Entry 3 register
1081 
1082  //Copy MAC address (last 32 bits)
1083  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1084  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1085 
1086  //Write the Static Address Table Entry 4 register
1088 
1089  //Write the TABLE_INDEX field with the 4-bit index value
1091  //Set the TABLE_SELECT bit to 0 to select the static address table
1093  //Set the ACTION bit to 0 to indicate a write operation
1095  //Set the START_FINISH bit to 1 to initiate the operation
1097 
1098  //Start the write operation
1100  value);
1101 
1102  //When the operation is complete, the START_FINISH bit will be cleared
1103  //automatically
1104  do
1105  {
1106  //Read the Static Address and Reserved Multicast Table Control register
1107  value = ksz8567ReadSwitchReg32(interface,
1109 
1110  //Poll the START_FINISH bit
1112 
1113  //Successful processing
1114  error = NO_ERROR;
1115  }
1116  else
1117  {
1118  //The static MAC table is full
1119  error = ERROR_TABLE_FULL;
1120  }
1121 
1122  //Return status code
1123  return error;
1124 }
1125 
1126 
1127 /**
1128  * @brief Remove an entry from the static MAC table
1129  * @param[in] interface Underlying network interface
1130  * @param[in] entry Forwarding database entry to remove from the table
1131  * @return Error code
1132  **/
1133 
1135  const SwitchFdbEntry *entry)
1136 {
1137  error_t error;
1138  uint_t j;
1139  uint32_t value;
1140  SwitchFdbEntry currentEntry;
1141 
1142  //Loop through the static MAC table
1143  for(j = 0; j < KSZ8567_STATIC_MAC_TABLE_SIZE; j++)
1144  {
1145  //Read current entry
1146  error = ksz8567GetStaticFdbEntry(interface, j, &currentEntry);
1147 
1148  //Valid entry?
1149  if(!error)
1150  {
1151  //Check whether the table contains the specified MAC address
1152  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1153  {
1154  break;
1155  }
1156  }
1157  }
1158 
1159  //Any matching entry?
1161  {
1162  //Clear Static Address Table Entry registers
1167 
1168  //Write the TABLE_INDEX field with the 4-bit index value
1170  //Set the TABLE_SELECT bit to 0 to select the static address table
1172  //Set the ACTION bit to 0 to indicate a write operation
1174  //Set the START_FINISH bit to 1 to initiate the operation
1176 
1177  //Start the write operation
1179  value);
1180 
1181  //When the operation is complete, the START_FINISH bit will be cleared
1182  //automatically
1183  do
1184  {
1185  //Read the Static Address and Reserved Multicast Table Control register
1186  value = ksz8567ReadSwitchReg32(interface,
1188 
1189  //Poll the START_FINISH bit
1191 
1192  //Successful processing
1193  error = NO_ERROR;
1194  }
1195  else
1196  {
1197  //The static MAC table does not contain the specified address
1198  error = ERROR_NOT_FOUND;
1199  }
1200 
1201  //Return status code
1202  return error;
1203 }
1204 
1205 
1206 /**
1207  * @brief Read an entry from the static MAC table
1208  * @param[in] interface Underlying network interface
1209  * @param[in] index Zero-based index of the entry to read
1210  * @param[out] entry Pointer to the forwarding database entry
1211  * @return Error code
1212  **/
1213 
1215  SwitchFdbEntry *entry)
1216 {
1217  error_t error;
1218  uint32_t value;
1219 
1220  //Check index parameter
1221  if(index < KSZ8567_STATIC_MAC_TABLE_SIZE)
1222  {
1223  //Write the TABLE_INDEX field with the 4-bit index value
1225  //Set the TABLE_SELECT bit to 0 to select the static address table
1227  //Set the ACTION bit to 1 to indicate a read operation
1229  //Set the START_FINISH bit to 1 to initiate the operation
1231 
1232  //Start the read operation
1234  value);
1235 
1236  //When the operation is complete, the START_FINISH bit will be cleared
1237  //automatically
1238  do
1239  {
1240  //Read the Static Address and Reserved Multicast Table Control register
1241  value = ksz8567ReadSwitchReg32(interface,
1243 
1244  //Poll the START_FINISH bit
1246 
1247  //Read the Static Address Table Entry 1 register
1249 
1250  //Valid entry?
1252  {
1253  //Read the Static Address Table Entry 2 register
1255 
1256  //Retrieve the ports associated with this MAC address
1257  entry->srcPort = 0;
1259 
1260  //Check the value of the OVERRIDE bit
1262  {
1263  entry->override = TRUE;
1264  }
1265  else
1266  {
1267  entry->override = FALSE;
1268  }
1269 
1270  //Read the Static Address Table Entry 3 register
1272 
1273  //Copy MAC address (first 16 bits)
1274  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1275  entry->macAddr.b[1] = value & 0xFF;
1276 
1277  //Read the Static Address Table Entry 4 register
1279 
1280  //Copy MAC address (last 32 bits)
1281  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1282  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1283  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1284  entry->macAddr.b[5] = value & 0xFF;
1285 
1286  //Successful processing
1287  error = NO_ERROR;
1288  }
1289  else
1290  {
1291  //The entry is not valid
1292  error = ERROR_INVALID_ENTRY;
1293  }
1294  }
1295  else
1296  {
1297  //The end of the table has been reached
1298  error = ERROR_END_OF_TABLE;
1299  }
1300 
1301  //Return status code
1302  return error;
1303 }
1304 
1305 
1306 /**
1307  * @brief Flush static MAC table
1308  * @param[in] interface Underlying network interface
1309  **/
1310 
1312 {
1313  uint_t i;
1314  uint32_t value;
1315 
1316  //Loop through the static MAC table
1317  for(i = 0; i < KSZ8567_STATIC_MAC_TABLE_SIZE; i++)
1318  {
1319  //Clear Static Address Table Entry registers
1324 
1325  //Write the TABLE_INDEX field with the 4-bit index value
1327  //Set the TABLE_SELECT bit to 0 to select the static address table
1329  //Set the ACTION bit to 0 to indicate a write operation
1331  //Set the START_FINISH bit to 1 to initiate the operation
1333 
1334  //Start the write operation
1336  value);
1337 
1338  //When the operation is complete, the START_FINISH bit will be cleared
1339  //automatically
1340  do
1341  {
1342  //Read the Static Address and Reserved Multicast Table Control register
1343  value = ksz8567ReadSwitchReg32(interface,
1345 
1346  //Poll the START_FINISH bit
1348  }
1349 }
1350 
1351 
1352 /**
1353  * @brief Read an entry from the dynamic MAC table
1354  * @param[in] interface Underlying network interface
1355  * @param[in] index Zero-based index of the entry to read
1356  * @param[out] entry Pointer to the forwarding database entry
1357  * @return Error code
1358  **/
1359 
1361  SwitchFdbEntry *entry)
1362 {
1363  error_t error;
1364  uint32_t value;
1365 
1366  //First entry?
1367  if(index == 0)
1368  {
1369  //Clear the ALU Table Access Control register to stop any operation
1371 
1372  //Start the search operation
1376  }
1377 
1378  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1379  do
1380  {
1381  //Read the ALU Table Access Control register
1383 
1384  //This bit goes high to indicate either a new valid entry is returned or
1385  //the search is complete
1387 
1388  //Check whether the next valid entry is ready
1389  if((value & KSZ8567_ALU_TABLE_CTRL_VALID) != 0)
1390  {
1391  //Store the data from the ALU table entry
1392  entry->destPorts = 0;
1393  entry->override = FALSE;
1394 
1395  //Read the ALU Table Entry 1 and 2 registers
1398 
1399  //Retrieve the port associated with this MAC address
1401  {
1403  entry->srcPort = KSZ8567_PORT1;
1404  break;
1406  entry->srcPort = KSZ8567_PORT2;
1407  break;
1409  entry->srcPort = KSZ8567_PORT3;
1410  break;
1412  entry->srcPort = KSZ8567_PORT4;
1413  break;
1415  entry->srcPort = KSZ8567_PORT5;
1416  break;
1418  entry->srcPort = KSZ8567_PORT6;
1419  break;
1421  entry->srcPort = KSZ8567_PORT7;
1422  break;
1423  default:
1424  entry->srcPort = 0;
1425  break;
1426  }
1427 
1428  //Read the ALU Table Entry 3 register
1430 
1431  //Copy MAC address (first 16 bits)
1432  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1433  entry->macAddr.b[1] = value & 0xFF;
1434 
1435  //Read the ALU Table Entry 4 register
1437 
1438  //Copy MAC address (last 32 bits)
1439  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1440  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1441  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1442  entry->macAddr.b[5] = value & 0xFF;
1443 
1444  //Successful processing
1445  error = NO_ERROR;
1446  }
1447  else
1448  {
1449  //The search can be stopped any time by setting the START_FINISH bit to 0
1451 
1452  //The end of the table has been reached
1453  error = ERROR_END_OF_TABLE;
1454  }
1455 
1456  //Return status code
1457  return error;
1458 }
1459 
1460 
1461 /**
1462  * @brief Flush dynamic MAC table
1463  * @param[in] interface Underlying network interface
1464  * @param[in] port Port number
1465  **/
1466 
1468 {
1469  uint_t temp;
1470  uint8_t state;
1471 
1472  //Flush only dynamic table entries
1477 
1478  //Valid port number?
1479  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT7)
1480  {
1481  //Save the current state of the port
1483 
1484  //Turn off learning capability
1487 
1488  //All the entries associated with a port that has its learning capability
1489  //being turned off will be flushed
1493 
1494  //Restore the original state of the port
1496  }
1497  else
1498  {
1499  //Trigger a flush of the entire address lookup table
1503  }
1504 }
1505 
1506 
1507 /**
1508  * @brief Set forward ports for unknown multicast packets
1509  * @param[in] interface Underlying network interface
1510  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1511  * @param[in] forwardPorts Port map
1512  **/
1513 
1515  bool_t enable, uint32_t forwardPorts)
1516 {
1517  uint32_t temp;
1518 
1519  //Read Unknown Multicast Control register
1521 
1522  //Clear port map
1524 
1525  //Enable or disable forwarding of unknown multicast packets
1526  if(enable)
1527  {
1528  //Enable forwarding
1530 
1531  //Check whether unknown multicast packets should be forwarded to the CPU port
1532  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1533  {
1535  }
1536 
1537  //Select the desired forward ports
1538  temp |= forwardPorts & KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL;
1539  }
1540  else
1541  {
1542  //Disable forwarding
1544  }
1545 
1546  //Write the value back to Unknown Multicast Control register
1548 }
1549 
1550 
1551 /**
1552  * @brief Write PHY register
1553  * @param[in] interface Underlying network interface
1554  * @param[in] port Port number
1555  * @param[in] address PHY register address
1556  * @param[in] data Register value
1557  **/
1558 
1559 void ksz8567WritePhyReg(NetInterface *interface, uint8_t port,
1560  uint8_t address, uint16_t data)
1561 {
1562  uint16_t n;
1563 
1564  //SPI slave mode?
1565  if(interface->spiDriver != NULL)
1566  {
1567  //The SPI interface provides access to all PHY registers
1569  //Write the 16-bit value
1570  ksz8567WriteSwitchReg16(interface, n, data);
1571  }
1572  else if(interface->smiDriver != NULL)
1573  {
1574  //Write the specified PHY register
1575  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1576  }
1577  else
1578  {
1579  //Write the specified PHY register
1580  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1581  }
1582 }
1583 
1584 
1585 /**
1586  * @brief Read PHY register
1587  * @param[in] interface Underlying network interface
1588  * @param[in] port Port number
1589  * @param[in] address PHY register address
1590  * @return Register value
1591  **/
1592 
1593 uint16_t ksz8567ReadPhyReg(NetInterface *interface, uint8_t port,
1594  uint8_t address)
1595 {
1596  uint16_t n;
1597  uint16_t data;
1598 
1599  //SPI slave mode?
1600  if(interface->spiDriver != NULL)
1601  {
1602  //The SPI interface provides access to all PHY registers
1604  //Read the 16-bit value
1605  data = ksz8567ReadSwitchReg16(interface, n);
1606  }
1607  else if(interface->smiDriver != NULL)
1608  {
1609  //Read the specified PHY register
1610  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1611  }
1612  else
1613  {
1614  //Read the specified PHY register
1615  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1616  }
1617 
1618  //Return register value
1619  return data;
1620 }
1621 
1622 
1623 /**
1624  * @brief Dump PHY registers for debugging purpose
1625  * @param[in] interface Underlying network interface
1626  * @param[in] port Port number
1627  **/
1628 
1629 void ksz8567DumpPhyReg(NetInterface *interface, uint8_t port)
1630 {
1631  uint8_t i;
1632 
1633  //Loop through PHY registers
1634  for(i = 0; i < 32; i++)
1635  {
1636  //Display current PHY register
1637  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1638  ksz8567ReadPhyReg(interface, port, i));
1639  }
1640 
1641  //Terminate with a line feed
1642  TRACE_DEBUG("\r\n");
1643 }
1644 
1645 
1646 /**
1647  * @brief Write MMD register
1648  * @param[in] interface Underlying network interface
1649  * @param[in] port Port number
1650  * @param[in] devAddr Device address
1651  * @param[in] regAddr Register address
1652  * @param[in] data Register value
1653  **/
1654 
1655 void ksz8567WriteMmdReg(NetInterface *interface, uint8_t port,
1656  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1657 {
1658  //Select register operation
1661 
1662  //Write MMD register address
1664 
1665  //Select data operation
1668 
1669  //Write the content of the MMD register
1671 }
1672 
1673 
1674 /**
1675  * @brief Read MMD register
1676  * @param[in] interface Underlying network interface
1677  * @param[in] port Port number
1678  * @param[in] devAddr Device address
1679  * @param[in] regAddr Register address
1680  * @return Register value
1681  **/
1682 
1683 uint16_t ksz8567ReadMmdReg(NetInterface *interface, uint8_t port,
1684  uint8_t devAddr, uint16_t regAddr)
1685 {
1686  //Select register operation
1689 
1690  //Write MMD register address
1692 
1693  //Select data operation
1696 
1697  //Read the content of the MMD register
1698  return ksz8567ReadPhyReg(interface, port, KSZ8567_MMDAADR);
1699 }
1700 
1701 
1702 /**
1703  * @brief Write switch register (8 bits)
1704  * @param[in] interface Underlying network interface
1705  * @param[in] address Switch register address
1706  * @param[in] data Register value
1707  **/
1708 
1709 void ksz8567WriteSwitchReg8(NetInterface *interface, uint16_t address,
1710  uint8_t data)
1711 {
1712  uint32_t command;
1713 
1714  //SPI slave mode?
1715  if(interface->spiDriver != NULL)
1716  {
1717  //Set up a write operation
1718  command = KSZ8567_SPI_CMD_WRITE;
1719  //Set register address
1720  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1721 
1722  //Pull the CS pin low
1723  interface->spiDriver->assertCs();
1724 
1725  //Write 32-bit command
1726  interface->spiDriver->transfer((command >> 24) & 0xFF);
1727  interface->spiDriver->transfer((command >> 16) & 0xFF);
1728  interface->spiDriver->transfer((command >> 8) & 0xFF);
1729  interface->spiDriver->transfer(command & 0xFF);
1730 
1731  //Write 8-bit data
1732  interface->spiDriver->transfer(data);
1733 
1734  //Terminate the operation by raising the CS pin
1735  interface->spiDriver->deassertCs();
1736  }
1737  else
1738  {
1739  //The MDC/MDIO interface does not have access to all the configuration
1740  //registers. It can only access the standard MIIM registers
1741  }
1742 }
1743 
1744 
1745 /**
1746  * @brief Read switch register (8 bits)
1747  * @param[in] interface Underlying network interface
1748  * @param[in] address Switch register address
1749  * @return Register value
1750  **/
1751 
1752 uint8_t ksz8567ReadSwitchReg8(NetInterface *interface, uint16_t address)
1753 {
1754  uint8_t data;
1755  uint32_t command;
1756 
1757  //SPI slave mode?
1758  if(interface->spiDriver != NULL)
1759  {
1760  //Set up a read operation
1761  command = KSZ8567_SPI_CMD_READ;
1762  //Set register address
1763  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1764 
1765  //Pull the CS pin low
1766  interface->spiDriver->assertCs();
1767 
1768  //Write 32-bit command
1769  interface->spiDriver->transfer((command >> 24) & 0xFF);
1770  interface->spiDriver->transfer((command >> 16) & 0xFF);
1771  interface->spiDriver->transfer((command >> 8) & 0xFF);
1772  interface->spiDriver->transfer(command & 0xFF);
1773 
1774  //Read 8-bit data
1775  data = interface->spiDriver->transfer(0xFF);
1776 
1777  //Terminate the operation by raising the CS pin
1778  interface->spiDriver->deassertCs();
1779  }
1780  else
1781  {
1782  //The MDC/MDIO interface does not have access to all the configuration
1783  //registers. It can only access the standard MIIM registers
1784  data = 0;
1785  }
1786 
1787  //Return register value
1788  return data;
1789 }
1790 
1791 
1792 /**
1793  * @brief Write switch register (16 bits)
1794  * @param[in] interface Underlying network interface
1795  * @param[in] address Switch register address
1796  * @param[in] data Register value
1797  **/
1798 
1800  uint16_t data)
1801 {
1802  uint32_t command;
1803 
1804  //SPI slave mode?
1805  if(interface->spiDriver != NULL)
1806  {
1807  //Set up a write operation
1808  command = KSZ8567_SPI_CMD_WRITE;
1809  //Set register address
1810  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1811 
1812  //Pull the CS pin low
1813  interface->spiDriver->assertCs();
1814 
1815  //Write 32-bit command
1816  interface->spiDriver->transfer((command >> 24) & 0xFF);
1817  interface->spiDriver->transfer((command >> 16) & 0xFF);
1818  interface->spiDriver->transfer((command >> 8) & 0xFF);
1819  interface->spiDriver->transfer(command & 0xFF);
1820 
1821  //Write 16-bit data
1822  interface->spiDriver->transfer((data >> 8) & 0xFF);
1823  interface->spiDriver->transfer(data & 0xFF);
1824 
1825  //Terminate the operation by raising the CS pin
1826  interface->spiDriver->deassertCs();
1827  }
1828  else
1829  {
1830  //The MDC/MDIO interface does not have access to all the configuration
1831  //registers. It can only access the standard MIIM registers
1832  }
1833 }
1834 
1835 
1836 /**
1837  * @brief Read switch register (16 bits)
1838  * @param[in] interface Underlying network interface
1839  * @param[in] address Switch register address
1840  * @return Register value
1841  **/
1842 
1843 uint16_t ksz8567ReadSwitchReg16(NetInterface *interface, uint16_t address)
1844 {
1845  uint16_t data;
1846  uint32_t command;
1847 
1848  //SPI slave mode?
1849  if(interface->spiDriver != NULL)
1850  {
1851  //Set up a read operation
1852  command = KSZ8567_SPI_CMD_READ;
1853  //Set register address
1854  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1855 
1856  //Pull the CS pin low
1857  interface->spiDriver->assertCs();
1858 
1859  //Write 32-bit command
1860  interface->spiDriver->transfer((command >> 24) & 0xFF);
1861  interface->spiDriver->transfer((command >> 16) & 0xFF);
1862  interface->spiDriver->transfer((command >> 8) & 0xFF);
1863  interface->spiDriver->transfer(command & 0xFF);
1864 
1865  //Read 16-bit data
1866  data = interface->spiDriver->transfer(0xFF) << 8;
1867  data |= interface->spiDriver->transfer(0xFF);
1868 
1869  //Terminate the operation by raising the CS pin
1870  interface->spiDriver->deassertCs();
1871  }
1872  else
1873  {
1874  //The MDC/MDIO interface does not have access to all the configuration
1875  //registers. It can only access the standard MIIM registers
1876  data = 0;
1877  }
1878 
1879  //Return register value
1880  return data;
1881 }
1882 
1883 
1884 /**
1885  * @brief Write switch register (32 bits)
1886  * @param[in] interface Underlying network interface
1887  * @param[in] address Switch register address
1888  * @param[in] data Register value
1889  **/
1890 
1892  uint32_t data)
1893 {
1894  uint32_t command;
1895 
1896  //SPI slave mode?
1897  if(interface->spiDriver != NULL)
1898  {
1899  //Set up a write operation
1900  command = KSZ8567_SPI_CMD_WRITE;
1901  //Set register address
1902  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1903 
1904  //Pull the CS pin low
1905  interface->spiDriver->assertCs();
1906 
1907  //Write 32-bit command
1908  interface->spiDriver->transfer((command >> 24) & 0xFF);
1909  interface->spiDriver->transfer((command >> 16) & 0xFF);
1910  interface->spiDriver->transfer((command >> 8) & 0xFF);
1911  interface->spiDriver->transfer(command & 0xFF);
1912 
1913  //Write 32-bit data
1914  interface->spiDriver->transfer((data >> 24) & 0xFF);
1915  interface->spiDriver->transfer((data >> 16) & 0xFF);
1916  interface->spiDriver->transfer((data >> 8) & 0xFF);
1917  interface->spiDriver->transfer(data & 0xFF);
1918 
1919  //Terminate the operation by raising the CS pin
1920  interface->spiDriver->deassertCs();
1921  }
1922  else
1923  {
1924  //The MDC/MDIO interface does not have access to all the configuration
1925  //registers. It can only access the standard MIIM registers
1926  }
1927 }
1928 
1929 
1930 /**
1931  * @brief Read switch register (32 bits)
1932  * @param[in] interface Underlying network interface
1933  * @param[in] address Switch register address
1934  * @return Register value
1935  **/
1936 
1937 uint32_t ksz8567ReadSwitchReg32(NetInterface *interface, uint16_t address)
1938 {
1939  uint32_t data;
1940  uint32_t command;
1941 
1942  //SPI slave mode?
1943  if(interface->spiDriver != NULL)
1944  {
1945  //Set up a read operation
1946  command = KSZ8567_SPI_CMD_READ;
1947  //Set register address
1948  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1949 
1950  //Pull the CS pin low
1951  interface->spiDriver->assertCs();
1952 
1953  //Write 32-bit command
1954  interface->spiDriver->transfer((command >> 24) & 0xFF);
1955  interface->spiDriver->transfer((command >> 16) & 0xFF);
1956  interface->spiDriver->transfer((command >> 8) & 0xFF);
1957  interface->spiDriver->transfer(command & 0xFF);
1958 
1959  //Read 32-bit data
1960  data = interface->spiDriver->transfer(0xFF) << 24;
1961  data |= interface->spiDriver->transfer(0xFF) << 16;
1962  data |= interface->spiDriver->transfer(0xFF) << 8;
1963  data |= interface->spiDriver->transfer(0xFF);
1964 
1965  //Terminate the operation by raising the CS pin
1966  interface->spiDriver->deassertCs();
1967  }
1968  else
1969  {
1970  //The MDC/MDIO interface does not have access to all the configuration
1971  //registers. It can only access the standard MIIM registers
1972  data = 0;
1973  }
1974 
1975  //Return register value
1976  return data;
1977 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
void ksz8567DisableIrq(NetInterface *interface)
Disable interrupts.
#define KSZ8567_ALU_TABLE_ENTRY3
#define KSZ8567_ALU_TABLE_ENTRY2_PORT7_FORWARD
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define KSZ8567_BMSR_LINK_STATUS
#define KSZ8567_STATIC_TABLE_ENTRY4
#define NetContext
Definition: net.h:36
int bool_t
Definition: compiler_port.h:63
@ ERROR_NOT_FOUND
Definition: error.h:148
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
#define KSZ8567_TAIL_TAG_NORMAL_ADDR_LOOKUP
uint32_t destPorts
Definition: nic.h:152
#define KSZ8567_ALU_TABLE_CTRL_START_FINISH
#define KSZ8567_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define KSZ8567_ALU_TABLE_ENTRY4
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define KSZ8567_ALU_TABLE_CTRL_VALID
#define KSZ8567_ALU_TABLE_ENTRY2_PORT2_FORWARD
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP
__weak_func void ksz8567Tick(NetInterface *interface)
KSZ8567 timer handler.
uint32_t ksz8567ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
#define KSZ8567_TAIL_TAG_DEST_PORT2
#define KSZ8567_PORT5
#define KSZ8567_STATIC_TABLE_ENTRY1
uint8_t ksz8567ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
@ ERROR_END_OF_TABLE
Definition: error.h:292
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define KSZ8567_MMDACR
error_t ksz8567UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
#define KSZ8567_SPI_CMD_READ
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
#define KSZ8567_SPI_CMD_ADDR
uint8_t type
Definition: coap_common.h:176
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_START_FINISH
#define KSZ8567_SWITCH_LUE_CTRL1
KSZ8567 7-port Ethernet switch driver.
#define KSZ8567_ALU_TABLE_ENTRY2_PORT1_FORWARD
@ ERROR_INVALID_PORT
Definition: error.h:104
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD
@ ERROR_TABLE_FULL
Definition: error.h:291
#define KSZ8567_SWITCH_LUE_CTRL2_FLUSH_OPTION
#define KSZ8567_SWITCH_MAC_CTRL0
EthHeader
Definition: ethernet.h:225
#define KSZ8567_PORTn_XMII_CTRL1_RGMII_ID_IG
#define KSZ8567_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN
#define KSZ8567_SWITCH_LUE_CTRL0
const uint16_t ksz8567IngressTailTag[6]
Tail tag rules (host to KSZ8567)
#define KSZ8567_PORTn_XMII_CTRL1_RGMII_ID_EG
const SwitchDriver ksz8567SwitchDriver
KSZ8567 Ethernet switch driver.
#define KSZ8567_TAIL_TAG_DEST_PORT5
void ksz8567EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define KSZ8567_ALU_TABLE_ENTRY2
void ksz8567SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
#define KSZ8567_STATIC_TABLE_ENTRY1_VALID
uint16_t ksz8567ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
#define KSZ8567_STATIC_TABLE_ENTRY3
#define KSZ8567_PORT2
#define KSZ8567_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
#define KSZ8567_MMDACR_FUNC_DATA_NO_POST_INC
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
error_t ksz8567DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
#define FALSE
Definition: os_port.h:46
#define KSZ8567_PORT7
#define KSZ8567_PORT6
#define KSZ8567_ALU_TABLE_ENTRY2_PORT5_FORWARD
#define KSZ8567_MMDAADR
#define KSZ8567_ALU_TABLE_ENTRY2_PORT6_FORWARD
#define KSZ8567_SWITCH_OP
#define KSZ8567_ALU_TABLE_ENTRY2_PORT4_FORWARD
uint16_t ksz8567ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
void ksz8567SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
#define KSZ8567_MMDACR_FUNC_ADDR
error_t
Error codes.
Definition: error.h:43
#define KSZ8567_PORTn_ETH_PHY_REG(port, addr)
#define KSZ8567_MMD_EEE_ADV
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT6
#define KSZ8567_TAIL_TAG_PORT_BLOCKING_OVERRIDE
#define KSZ8567_PORTn_MSTP_STATE_LEARNING_DIS
#define KSZ8567_GLOBAL_PORT_MIRROR_SNOOP_CTRL
void ksz8567EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
#define KSZ8567_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define KSZ8567_PORTn_OP_CTRL0_TAIL_TAG_EN
#define KSZ8567_PORT6_OP_CTRL0
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define KSZ8567_PORT3
void ksz8567WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
@ ERROR_INVALID_LENGTH
Definition: error.h:111
#define KSZ8567_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_ACTION
#define KSZ8567_ALU_TABLE_ENTRY2_PORT_FORWARD
error_t ksz8567Init(NetInterface *interface)
KSZ8567 Ethernet switch initialization.
#define KSZ8567_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
NicDuplexMode ksz8567GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
#define NetTxAncillary
Definition: net_misc.h:36
#define KSZ8567_PHYCON_DUPLEX_STATUS
#define KSZ8567_TAIL_TAG_DEST_PORT3
error_t ksz8567GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
#define KSZ8567_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
__weak_func void ksz8567EventHandler(NetInterface *interface)
KSZ8567 event handler.
#define KSZ8567_SWITCH_OP_START_SWITCH
void ksz8567WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
#define KSZ8567_MMD_LED_MODE_RESERVED_DEFAULT
#define MIN(a, b)
Definition: os_port.h:63
#define KSZ8567_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
void ksz8567DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
#define KSZ8567_MMDACR_DEVAD
#define KSZ8567_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
#define KSZ8567_PORT_MASK
#define KSZ8567_PHYCON
void ksz8567WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
#define KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
uint16_t port
Definition: dns_common.h:270
#define KSZ8567_STATIC_MAC_TABLE_SIZE
error_t ksz8567AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define KSZ8567_ALU_TABLE_ENTRY2_PORT3_FORWARD
#define KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN
#define KSZ8567_PORTn_XMII_CTRL0_DUPLEX
#define KSZ8567_SWITCH_LUE_CTRL2
uint16_t regAddr
#define KSZ8567_PORTn_MSTP_STATE(port)
#define KSZ8567_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
Ethernet switch driver.
Definition: nic.h:325
error_t ksz8567GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
#define KSZ8567_PORTn_XMII_CTRL0_SPEED_10_100
@ 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 ksz8567ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
#define KSZ8567_PHYCON_SPEED_10BT
Ipv6Addr address[]
Definition: ipv6.h:345
#define KSZ8567_PORT6_MASK
#define KSZ8567_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
bool_t ksz8567GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
void ksz8567FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
NicDuplexMode
Duplex mode.
Definition: nic.h:122
MacAddr macAddr
Definition: nic.h:150
#define KSZ8567_SWITCH_LUE_CTRL3
uint8_t srcPort
Definition: nic.h:151
#define KSZ8567_PORTn_XMII_CTRL1_IF_TYPE_RGMII
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
uint8_t value[]
Definition: tcp.h:376
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
#define KSZ8567_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
#define KSZ8567_ALU_TABLE_ENTRY1
#define KSZ8567_TAIL_TAG_SRC_PORT
#define KSZ8567_BMSR
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
SwitchPortState ksz8567GetPortState(NetInterface *interface, uint8_t port)
Get port state.
#define KSZ8567_STATIC_TABLE_ENTRY2
#define KSZ8567_ALU_TABLE_CTRL
#define KSZ8567_STATIC_MCAST_TABLE_CTRL
#define KSZ8567_PORT1
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define KSZ8567_PORT6_XMII_CTRL0
#define KSZ8567_CHIP_ID1
#define KSZ8567_PORTn_XMII_CTRL1_SPEED_1000
#define KSZ8567_MMD_LED_MODE_LED_MODE_SINGLE
#define KSZ8567_TAIL_TAG_DEST_PORT1
#define KSZ8567_PORT6_XMII_CTRL1
#define KSZ8567_TAIL_TAG_DEST_PORT4
#define KSZ8567_UNKONWN_MULTICAST_CTRL
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
void ksz8567FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
uint32_t ksz8567GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
void ksz8567WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
#define KSZ8567_STATIC_TABLE_ENTRY2_OVERRIDE
__weak_func void ksz8567InitHook(NetInterface *interface)
KSZ8567 custom configuration.
#define KSZ8567_ALU_TABLE_CTRL_ACTION_SEARCH
void ksz8567SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
void ksz8567EnableIrq(NetInterface *interface)
Enable interrupts.
#define KSZ8567_SPI_CMD_WRITE
Helper functions for Ethernet.
void ksz8567WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
#define KSZ8567_MMD_LED_MODE
@ NO_ERROR
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:153
void ksz8567EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
Debugging facilities.
error_t ksz8567TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
Forwarding database entry.
Definition: nic.h:149
#define KSZ8567_CHIP_ID1_DEFAULT
#define KSZ8567_PHYCON_SPEED_100BTX
#define KSZ8567_PORTn_XMII_CTRL1_IF_TYPE
#define KSZ8567_PORT4