ksz9897_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz9897_driver.c
3  * @brief KSZ9897 7-port Gigabit Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
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 KSZ9897 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to KSZ9897)
75  **/
76 
77 const uint16_t ksz9897IngressTailTag[6] =
78 {
85 };
86 
87 
88 /**
89  * @brief KSZ9897 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 KSZ9897...\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 = ksz9897ReadSwitchReg8(interface, KSZ9897_CHIP_ID1);
113 
114  //The returned data is invalid until the serial interface is ready
115  } while(temp != KSZ9897_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 13)
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  ksz9897WriteMmdReg(interface, port, 0x01, 0x6F, 0xDD0B);
191  ksz9897WriteMmdReg(interface, port, 0x01, 0x8F, 0x6032);
192  ksz9897WriteMmdReg(interface, port, 0x01, 0x9D, 0x248C);
193  ksz9897WriteMmdReg(interface, port, 0x01, 0x75, 0x0060);
194  ksz9897WriteMmdReg(interface, port, 0x01, 0xD3, 0x7777);
195  ksz9897WriteMmdReg(interface, port, 0x1C, 0x06, 0x3008);
196  ksz9897WriteMmdReg(interface, port, 0x1C, 0x08, 0x2001);
197 
198  //Improve transmit waveform amplitude (silicon errata workaround 2)
199  ksz9897WriteMmdReg(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  ksz9897WriteMmdReg(interface, port, 0x1C, 0x13, 0x6EFF);
206  ksz9897WriteMmdReg(interface, port, 0x1C, 0x14, 0xE6FF);
207  ksz9897WriteMmdReg(interface, port, 0x1C, 0x15, 0x6EFF);
208  ksz9897WriteMmdReg(interface, port, 0x1C, 0x16, 0xE6FF);
209  ksz9897WriteMmdReg(interface, port, 0x1C, 0x17, 0x00FF);
210  ksz9897WriteMmdReg(interface, port, 0x1C, 0x18, 0x43FF);
211  ksz9897WriteMmdReg(interface, port, 0x1C, 0x19, 0xC3FF);
212  ksz9897WriteMmdReg(interface, port, 0x1C, 0x1A, 0x6FFF);
213  ksz9897WriteMmdReg(interface, port, 0x1C, 0x1B, 0x07FF);
214  ksz9897WriteMmdReg(interface, port, 0x1C, 0x1C, 0x0FFF);
215  ksz9897WriteMmdReg(interface, port, 0x1C, 0x1D, 0xE7FF);
216  ksz9897WriteMmdReg(interface, port, 0x1C, 0x1E, 0xEFFF);
217  ksz9897WriteMmdReg(interface, port, 0x1C, 0x20, 0xEEEE);
218 
219  //Select tri-color dual-LED mode (silicon errata workaround 15)
223 
224  //Debug message
225  TRACE_DEBUG("Port %u:\r\n", port);
226  //Dump PHY registers for debugging purpose
227  ksz9897DumpPhyReg(interface, port);
228  }
229 
230  //Perform custom configuration
231  ksz9897InitHook(interface);
232 
233  //Force the TCP/IP stack to poll the link state at startup
234  interface->phyEvent = TRUE;
235  //Notify the TCP/IP stack of the event
237 
238  //Successful initialization
239  return NO_ERROR;
240 }
241 
242 
243 /**
244  * @brief KSZ9897 custom configuration
245  * @param[in] interface Underlying network interface
246  **/
247 
248 __weak_func void ksz9897InitHook(NetInterface *interface)
249 {
250 }
251 
252 
253 /**
254  * @brief KSZ9897 timer handler
255  * @param[in] interface Underlying network interface
256  **/
257 
258 void ksz9897Tick(NetInterface *interface)
259 {
260  uint_t port;
261  bool_t linkState;
262 
263 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
264  //Port separation mode?
265  if(interface->port != 0)
266  {
267  uint_t i;
268  NetInterface *virtualInterface;
269 
270  //Loop through network interfaces
271  for(i = 0; i < NET_INTERFACE_COUNT; i++)
272  {
273  //Point to the current interface
274  virtualInterface = &netInterface[i];
275 
276  //Check whether the current virtual interface is attached to the
277  //physical interface
278  if(virtualInterface == interface ||
279  virtualInterface->parent == interface)
280  {
281  //Retrieve current link state
282  linkState = ksz9897GetLinkState(interface, virtualInterface->port);
283 
284  //Link up or link down event?
285  if(linkState != virtualInterface->linkState)
286  {
287  //Set event flag
288  interface->phyEvent = TRUE;
289  //Notify the TCP/IP stack of the event
291  }
292  }
293  }
294  }
295  else
296 #endif
297  {
298  //Initialize link state
299  linkState = FALSE;
300 
301  //Loop through the ports
303  {
304  //Retrieve current link state
305  if(ksz9897GetLinkState(interface, port))
306  {
307  linkState = TRUE;
308  }
309  }
310 
311  //Link up or link down event?
312  if(linkState != interface->linkState)
313  {
314  //Set event flag
315  interface->phyEvent = TRUE;
316  //Notify the TCP/IP stack of the event
318  }
319  }
320 }
321 
322 
323 /**
324  * @brief Enable interrupts
325  * @param[in] interface Underlying network interface
326  **/
327 
329 {
330 }
331 
332 
333 /**
334  * @brief Disable interrupts
335  * @param[in] interface Underlying network interface
336  **/
337 
339 {
340 }
341 
342 
343 /**
344  * @brief KSZ9897 event handler
345  * @param[in] interface Underlying network interface
346  **/
347 
349 {
350  uint_t port;
351  bool_t linkState;
352 
353 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
354  //Port separation mode?
355  if(interface->port != 0)
356  {
357  uint_t i;
358  NetInterface *virtualInterface;
359 
360  //Loop through network interfaces
361  for(i = 0; i < NET_INTERFACE_COUNT; i++)
362  {
363  //Point to the current interface
364  virtualInterface = &netInterface[i];
365 
366  //Check whether the current virtual interface is attached to the
367  //physical interface
368  if(virtualInterface == interface ||
369  virtualInterface->parent == interface)
370  {
371  //Get the port number associated with the current interface
372  port = virtualInterface->port;
373 
374  //Valid port?
375  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT5)
376  {
377  //Retrieve current link state
378  linkState = ksz9897GetLinkState(interface, port);
379 
380  //Link up event?
381  if(linkState && !virtualInterface->linkState)
382  {
383  //Retrieve host interface speed
384  interface->linkSpeed = ksz9897GetLinkSpeed(interface,
385  KSZ9897_PORT6);
386 
387  //Retrieve host interface duplex mode
388  interface->duplexMode = ksz9897GetDuplexMode(interface,
389  KSZ9897_PORT6);
390 
391  //Adjust MAC configuration parameters for proper operation
392  interface->nicDriver->updateMacConfig(interface);
393 
394  //Check current speed
395  virtualInterface->linkSpeed = ksz9897GetLinkSpeed(interface,
396  port);
397 
398  //Check current duplex mode
399  virtualInterface->duplexMode = ksz9897GetDuplexMode(interface,
400  port);
401 
402  //Update link state
403  virtualInterface->linkState = TRUE;
404 
405  //Process link state change event
406  nicNotifyLinkChange(virtualInterface);
407  }
408  //Link down event
409  else if(!linkState && virtualInterface->linkState)
410  {
411  //Update link state
412  virtualInterface->linkState = FALSE;
413 
414  //Process link state change event
415  nicNotifyLinkChange(virtualInterface);
416  }
417  }
418  }
419  }
420  }
421  else
422 #endif
423  {
424  //Initialize link state
425  linkState = FALSE;
426 
427  //Loop through the ports
429  {
430  //Retrieve current link state
431  if(ksz9897GetLinkState(interface, port))
432  {
433  linkState = TRUE;
434  }
435  }
436 
437  //Link up event?
438  if(linkState)
439  {
440  //Retrieve host interface speed
441  interface->linkSpeed = ksz9897GetLinkSpeed(interface, KSZ9897_PORT6);
442  //Retrieve host interface duplex mode
443  interface->duplexMode = ksz9897GetDuplexMode(interface, KSZ9897_PORT6);
444 
445  //Adjust MAC configuration parameters for proper operation
446  interface->nicDriver->updateMacConfig(interface);
447 
448  //Update link state
449  interface->linkState = TRUE;
450  }
451  else
452  {
453  //Update link state
454  interface->linkState = FALSE;
455  }
456 
457  //Process link state change event
458  nicNotifyLinkChange(interface);
459  }
460 }
461 
462 
463 /**
464  * @brief Add tail tag to Ethernet frame
465  * @param[in] interface Underlying network interface
466  * @param[in] buffer Multi-part buffer containing the payload
467  * @param[in,out] offset Offset to the first payload byte
468  * @param[in] ancillary Additional options passed to the stack along with
469  * the packet
470  * @return Error code
471  **/
472 
474  size_t *offset, NetTxAncillary *ancillary)
475 {
476  error_t error;
477 
478  //Initialize status code
479  error = NO_ERROR;
480 
481 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
482  //SPI slave mode?
483  if(interface->spiDriver != NULL)
484  {
485  //Valid port?
486  if(ancillary->port <= KSZ9897_PORT5)
487  {
488  size_t length;
489  const uint16_t *tailTag;
490 
491  //The two-byte tail tagging is used to indicate the destination port
492  tailTag = &ksz9897IngressTailTag[ancillary->port];
493 
494  //Retrieve the length of the Ethernet frame
495  length = netBufferGetLength(buffer) - *offset;
496 
497  //The host controller should manually add padding to the packet before
498  //inserting the tail tag
499  error = ethPadFrame(buffer, &length);
500 
501  //Check status code
502  if(!error)
503  {
504  //The tail tag is inserted at the end of the packet, just before
505  //the CRC
506  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
507  }
508  }
509  else
510  {
511  //The port number is not valid
512  error = ERROR_INVALID_PORT;
513  }
514  }
515 #endif
516 
517  //Return status code
518  return error;
519 }
520 
521 
522 /**
523  * @brief Decode tail tag from incoming Ethernet frame
524  * @param[in] interface Underlying network interface
525  * @param[in,out] frame Pointer to the received Ethernet frame
526  * @param[in,out] length Length of the frame, in bytes
527  * @param[in,out] ancillary Additional options passed to the stack along with
528  * the packet
529  * @return Error code
530  **/
531 
532 error_t ksz9897UntagFrame(NetInterface *interface, uint8_t **frame,
533  size_t *length, NetRxAncillary *ancillary)
534 {
535  error_t error;
536 
537  //Initialize status code
538  error = NO_ERROR;
539 
540 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
541  //SPI slave mode?
542  if(interface->spiDriver != NULL)
543  {
544  //Valid Ethernet frame received?
545  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
546  {
547  uint8_t *tailTag;
548 
549  //The tail tag is inserted at the end of the packet, just before
550  //the CRC
551  tailTag = *frame + *length - sizeof(uint8_t);
552 
553  //The one byte tail tagging is used to indicate the source port
554  ancillary->port = (*tailTag & KSZ9897_TAIL_TAG_SRC_PORT) + 1;
555 
556  //Strip tail tag from Ethernet frame
557  *length -= sizeof(uint8_t);
558  }
559  else
560  {
561  //Drop the received frame
562  error = ERROR_INVALID_LENGTH;
563  }
564  }
565  else
566  {
567  //Tail tagging mode cannot be enabled through MDC/MDIO interface
568  ancillary->port = 0;
569  }
570 #endif
571 
572  //Return status code
573  return error;
574 }
575 
576 
577 /**
578  * @brief Get link state
579  * @param[in] interface Underlying network interface
580  * @param[in] port Port number
581  * @return Link state
582  **/
583 
585 {
586  uint16_t value;
587  bool_t linkState;
588 
589  //Check port number
590  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT5)
591  {
592  //Any link failure condition is latched in the BMSR register. Reading
593  //the register twice will always return the actual link status
594  value = ksz9897ReadPhyReg(interface, port, KSZ9897_BMSR);
595  value = ksz9897ReadPhyReg(interface, port, KSZ9897_BMSR);
596 
597  //Retrieve current link state
598  linkState = (value & KSZ9897_BMSR_LINK_STATUS) ? TRUE : FALSE;
599  }
600  else
601  {
602  //The specified port number is not valid
603  linkState = FALSE;
604  }
605 
606  //Return link status
607  return linkState;
608 }
609 
610 
611 /**
612  * @brief Get link speed
613  * @param[in] interface Underlying network interface
614  * @param[in] port Port number
615  * @return Link speed
616  **/
617 
618 uint32_t ksz9897GetLinkSpeed(NetInterface *interface, uint8_t port)
619 {
620  uint8_t type;
621  uint16_t value;
622  uint32_t linkSpeed;
623 
624  //Check port number
625  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT5)
626  {
627  //Read PHY control register
629 
630  //Retrieve current link speed
632  {
633  //1000BASE-T
634  linkSpeed = NIC_LINK_SPEED_1GBPS;
635  }
636  else if((value & KSZ9897_PHYCON_SPEED_100BTX) != 0)
637  {
638  //100BASE-TX
639  linkSpeed = NIC_LINK_SPEED_100MBPS;
640  }
641  else if((value & KSZ9897_PHYCON_SPEED_10BT) != 0)
642  {
643  //10BASE-T
644  linkSpeed = NIC_LINK_SPEED_10MBPS;
645  }
646  else
647  {
648  //The link speed is not valid
649  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
650  }
651  }
652  else if(port == KSZ9897_PORT6)
653  {
654  //SPI slave mode?
655  if(interface->spiDriver != NULL)
656  {
657  //Read port 6 XMII control 1 register
659 
660  //Retrieve host interface type
662 
663  //Gigabit interface?
666  {
667  //1000 Mb/s mode
668  linkSpeed = NIC_LINK_SPEED_1GBPS;
669  }
670  else
671  {
672  //Read port 6 XMII control 0 register
674 
675  //Retrieve host interface speed
677  {
678  //100 Mb/s mode
679  linkSpeed = NIC_LINK_SPEED_100MBPS;
680  }
681  else
682  {
683  //10 Mb/s mode
684  linkSpeed = NIC_LINK_SPEED_10MBPS;
685  }
686  }
687  }
688  else
689  {
690  //The MDC/MDIO interface does not have access to all the configuration
691  //registers. It can only access the standard MIIM registers
692  linkSpeed = NIC_LINK_SPEED_100MBPS;
693  }
694  }
695  else
696  {
697  //The specified port number is not valid
698  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
699  }
700 
701  //Return link status
702  return linkSpeed;
703 }
704 
705 
706 /**
707  * @brief Get duplex mode
708  * @param[in] interface Underlying network interface
709  * @param[in] port Port number
710  * @return Duplex mode
711  **/
712 
714 {
715  uint16_t value;
716  NicDuplexMode duplexMode;
717 
718  //Check port number
719  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT5)
720  {
721  //Read PHY control register
723 
724  //Retrieve current duplex mode
726  {
727  duplexMode = NIC_FULL_DUPLEX_MODE;
728  }
729  else
730  {
731  duplexMode = NIC_HALF_DUPLEX_MODE;
732  }
733  }
734  else if(port == KSZ9897_PORT6)
735  {
736  //SPI slave mode?
737  if(interface->spiDriver != NULL)
738  {
739  //Read port 6 XMII control 0 register
741 
742  //Retrieve host interface duplex mode
744  {
745  duplexMode = NIC_FULL_DUPLEX_MODE;
746  }
747  else
748  {
749  duplexMode = NIC_HALF_DUPLEX_MODE;
750  }
751  }
752  else
753  {
754  //The MDC/MDIO interface does not have access to all the configuration
755  //registers. It can only access the standard MIIM registers
756  duplexMode = NIC_FULL_DUPLEX_MODE;
757  }
758  }
759  else
760  {
761  //The specified port number is not valid
762  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
763  }
764 
765  //Return duplex mode
766  return duplexMode;
767 }
768 
769 
770 /**
771  * @brief Set port state
772  * @param[in] interface Underlying network interface
773  * @param[in] port Port number
774  * @param[in] state Port state
775  **/
776 
777 void ksz9897SetPortState(NetInterface *interface, uint8_t port,
778  SwitchPortState state)
779 {
780  uint8_t temp;
781 
782  //Check port number
783  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT5)
784  {
785  //Read MSTP state register
787 
788  //Update port state
789  switch(state)
790  {
791  //Listening state
796  break;
797 
798  //Learning state
803  break;
804 
805  //Forwarding state
810  break;
811 
812  //Disabled state
813  default:
817  break;
818  }
819 
820  //Write the value back to MSTP state register
822  }
823 }
824 
825 
826 /**
827  * @brief Get port state
828  * @param[in] interface Underlying network interface
829  * @param[in] port Port number
830  * @return Port state
831  **/
832 
834 {
835  uint8_t temp;
836  SwitchPortState state;
837 
838  //Check port number
839  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT5)
840  {
841  //Read MSTP state register
843 
844  //Check port state
845  if((temp & KSZ9897_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
846  (temp & KSZ9897_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
848  {
849  //Disabled state
851  }
852  else if((temp & KSZ9897_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
853  (temp & KSZ9897_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
855  {
856  //Listening state
858  }
859  else if((temp & KSZ9897_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
860  (temp & KSZ9897_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
862  {
863  //Learning state
865  }
866  else if((temp & KSZ9897_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
867  (temp & KSZ9897_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
869  {
870  //Forwarding state
872  }
873  else
874  {
875  //Unknown state
877  }
878  }
879  else
880  {
881  //The specified port number is not valid
883  }
884 
885  //Return port state
886  return state;
887 }
888 
889 
890 /**
891  * @brief Set aging time for dynamic filtering entries
892  * @param[in] interface Underlying network interface
893  * @param[in] agingTime Aging time, in seconds
894  **/
895 
896 void ksz9897SetAgingTime(NetInterface *interface, uint32_t agingTime)
897 {
898  //The Age Period in combination with the Age Count field determines the
899  //aging time of dynamic entries in the address lookup table
900  agingTime = (agingTime + 3) / 4;
901 
902  //Limit the range of the parameter
903  agingTime = MIN(agingTime, 255);
904 
905  //Write the value to Switch Lookup Engine Control 3 register
907  (uint8_t) agingTime);
908 }
909 
910 
911 /**
912  * @brief Enable IGMP snooping
913  * @param[in] interface Underlying network interface
914  * @param[in] enable Enable or disable IGMP snooping
915  **/
916 
918 {
919  uint8_t temp;
920 
921  //Read the Global Port Mirroring and Snooping Control register
922  temp = ksz9897ReadSwitchReg8(interface,
924 
925  //Enable or disable IGMP snooping
926  if(enable)
927  {
929  }
930  else
931  {
933  }
934 
935  //Write the value back to Global Port Mirroring and Snooping Control register
937  temp);
938 }
939 
940 
941 /**
942  * @brief Enable MLD snooping
943  * @param[in] interface Underlying network interface
944  * @param[in] enable Enable or disable MLD snooping
945  **/
946 
948 {
949  uint8_t temp;
950 
951  //Read the Global Port Mirroring and Snooping Control register
952  temp = ksz9897ReadSwitchReg8(interface,
954 
955  //Enable or disable MLD snooping
956  if(enable)
957  {
959  }
960  else
961  {
963  }
964 
965  //Write the value back to Global Port Mirroring and Snooping Control register
967  temp);
968 }
969 
970 
971 /**
972  * @brief Enable reserved multicast table
973  * @param[in] interface Underlying network interface
974  * @param[in] enable Enable or disable reserved group addresses
975  **/
976 
978 {
979  uint8_t temp;
980 
981  //Read the Switch Lookup Engine Control 0 register
983 
984  //Enable or disable the reserved multicast table
985  if(enable)
986  {
988  }
989  else
990  {
992  }
993 
994  //Write the value back to Switch Lookup Engine Control 0 register
996 }
997 
998 
999 /**
1000  * @brief Add a new entry to the static MAC table
1001  * @param[in] interface Underlying network interface
1002  * @param[in] entry Pointer to the forwarding database entry
1003  * @return Error code
1004  **/
1005 
1007  const SwitchFdbEntry *entry)
1008 {
1009  error_t error;
1010  uint_t i;
1011  uint_t j;
1012  uint32_t value;
1013  SwitchFdbEntry currentEntry;
1014 
1015  //Keep track of the first free entry
1017 
1018  //Loop through the static MAC table
1019  for(i = 0; i < KSZ9897_STATIC_MAC_TABLE_SIZE; i++)
1020  {
1021  //Read current entry
1022  error = ksz9897GetStaticFdbEntry(interface, i, &currentEntry);
1023 
1024  //Valid entry?
1025  if(!error)
1026  {
1027  //Check whether the table already contains the specified MAC address
1028  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1029  {
1030  j = i;
1031  break;
1032  }
1033  }
1034  else
1035  {
1036  //Keep track of the first free entry
1038  {
1039  j = i;
1040  }
1041  }
1042  }
1043 
1044  //Any entry available?
1046  {
1047  //Write the Static Address Table Entry 1 register
1050 
1051  //Set the relevant forward ports
1052  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1053  {
1055  }
1056  else
1057  {
1058  value = entry->destPorts & KSZ9897_PORT_MASK;
1059  }
1060 
1061  //Enable overriding of port state
1062  if(entry->override)
1063  {
1065  }
1066 
1067  //Write the Static Address Table Entry 2 register
1069 
1070  //Copy MAC address (first 16 bits)
1071  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1072 
1073  //Write the Static Address Table Entry 3 register
1075 
1076  //Copy MAC address (last 32 bits)
1077  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1078  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1079 
1080  //Write the Static Address Table Entry 4 register
1082 
1083  //Write the TABLE_INDEX field with the 4-bit index value
1085  //Set the TABLE_SELECT bit to 0 to select the static address table
1087  //Set the ACTION bit to 0 to indicate a write operation
1089  //Set the START_FINISH bit to 1 to initiate the operation
1091 
1092  //Start the write operation
1094  value);
1095 
1096  //When the operation is complete, the START_FINISH bit will be cleared
1097  //automatically
1098  do
1099  {
1100  //Read the Static Address and Reserved Multicast Table Control register
1101  value = ksz9897ReadSwitchReg32(interface,
1103 
1104  //Poll the START_FINISH bit
1106 
1107  //Successful processing
1108  error = NO_ERROR;
1109  }
1110  else
1111  {
1112  //The static MAC table is full
1113  error = ERROR_TABLE_FULL;
1114  }
1115 
1116  //Return status code
1117  return error;
1118 }
1119 
1120 
1121 /**
1122  * @brief Remove an entry from the static MAC table
1123  * @param[in] interface Underlying network interface
1124  * @param[in] entry Forwarding database entry to remove from the table
1125  * @return Error code
1126  **/
1127 
1129  const SwitchFdbEntry *entry)
1130 {
1131  error_t error;
1132  uint_t j;
1133  uint32_t value;
1134  SwitchFdbEntry currentEntry;
1135 
1136  //Loop through the static MAC table
1137  for(j = 0; j < KSZ9897_STATIC_MAC_TABLE_SIZE; j++)
1138  {
1139  //Read current entry
1140  error = ksz9897GetStaticFdbEntry(interface, j, &currentEntry);
1141 
1142  //Valid entry?
1143  if(!error)
1144  {
1145  //Check whether the table contains the specified MAC address
1146  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1147  {
1148  break;
1149  }
1150  }
1151  }
1152 
1153  //Any matching entry?
1155  {
1156  //Clear Static Address Table Entry registers
1161 
1162  //Write the TABLE_INDEX field with the 4-bit index value
1164  //Set the TABLE_SELECT bit to 0 to select the static address table
1166  //Set the ACTION bit to 0 to indicate a write operation
1168  //Set the START_FINISH bit to 1 to initiate the operation
1170 
1171  //Start the write operation
1173  value);
1174 
1175  //When the operation is complete, the START_FINISH bit will be cleared
1176  //automatically
1177  do
1178  {
1179  //Read the Static Address and Reserved Multicast Table Control register
1180  value = ksz9897ReadSwitchReg32(interface,
1182 
1183  //Poll the START_FINISH bit
1185 
1186  //Successful processing
1187  error = NO_ERROR;
1188  }
1189  else
1190  {
1191  //The static MAC table does not contain the specified address
1192  error = ERROR_NOT_FOUND;
1193  }
1194 
1195  //Return status code
1196  return error;
1197 }
1198 
1199 
1200 /**
1201  * @brief Read an entry from the static MAC table
1202  * @param[in] interface Underlying network interface
1203  * @param[in] index Zero-based index of the entry to read
1204  * @param[out] entry Pointer to the forwarding database entry
1205  * @return Error code
1206  **/
1207 
1209  SwitchFdbEntry *entry)
1210 {
1211  error_t error;
1212  uint32_t value;
1213 
1214  //Check index parameter
1215  if(index < KSZ9897_STATIC_MAC_TABLE_SIZE)
1216  {
1217  //Write the TABLE_INDEX field with the 4-bit index value
1219  //Set the TABLE_SELECT bit to 0 to select the static address table
1221  //Set the ACTION bit to 1 to indicate a read operation
1223  //Set the START_FINISH bit to 1 to initiate the operation
1225 
1226  //Start the read operation
1228  value);
1229 
1230  //When the operation is complete, the START_FINISH bit will be cleared
1231  //automatically
1232  do
1233  {
1234  //Read the Static Address and Reserved Multicast Table Control register
1235  value = ksz9897ReadSwitchReg32(interface,
1237 
1238  //Poll the START_FINISH bit
1240 
1241  //Read the Static Address Table Entry 1 register
1243 
1244  //Valid entry?
1246  {
1247  //Read the Static Address Table Entry 2 register
1249 
1250  //Retrieve the ports associated with this MAC address
1251  entry->srcPort = 0;
1253 
1254  //Check the value of the OVERRIDE bit
1256  {
1257  entry->override = TRUE;
1258  }
1259  else
1260  {
1261  entry->override = FALSE;
1262  }
1263 
1264  //Read the Static Address Table Entry 3 register
1266 
1267  //Copy MAC address (first 16 bits)
1268  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1269  entry->macAddr.b[1] = value & 0xFF;
1270 
1271  //Read the Static Address Table Entry 4 register
1273 
1274  //Copy MAC address (last 32 bits)
1275  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1276  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1277  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1278  entry->macAddr.b[5] = value & 0xFF;
1279 
1280  //Successful processing
1281  error = NO_ERROR;
1282  }
1283  else
1284  {
1285  //The entry is not valid
1286  error = ERROR_INVALID_ENTRY;
1287  }
1288  }
1289  else
1290  {
1291  //The end of the table has been reached
1292  error = ERROR_END_OF_TABLE;
1293  }
1294 
1295  //Return status code
1296  return error;
1297 }
1298 
1299 
1300 /**
1301  * @brief Flush static MAC table
1302  * @param[in] interface Underlying network interface
1303  **/
1304 
1306 {
1307  uint_t i;
1308  uint32_t value;
1309 
1310  //Loop through the static MAC table
1311  for(i = 0; i < KSZ9897_STATIC_MAC_TABLE_SIZE; i++)
1312  {
1313  //Clear Static Address Table Entry registers
1318 
1319  //Write the TABLE_INDEX field with the 4-bit index value
1321  //Set the TABLE_SELECT bit to 0 to select the static address table
1323  //Set the ACTION bit to 0 to indicate a write operation
1325  //Set the START_FINISH bit to 1 to initiate the operation
1327 
1328  //Start the write operation
1330  value);
1331 
1332  //When the operation is complete, the START_FINISH bit will be cleared
1333  //automatically
1334  do
1335  {
1336  //Read the Static Address and Reserved Multicast Table Control register
1337  value = ksz9897ReadSwitchReg32(interface,
1339 
1340  //Poll the START_FINISH bit
1342  }
1343 }
1344 
1345 
1346 /**
1347  * @brief Read an entry from the dynamic MAC table
1348  * @param[in] interface Underlying network interface
1349  * @param[in] index Zero-based index of the entry to read
1350  * @param[out] entry Pointer to the forwarding database entry
1351  * @return Error code
1352  **/
1353 
1355  SwitchFdbEntry *entry)
1356 {
1357  error_t error;
1358  uint32_t value;
1359 
1360  //First entry?
1361  if(index == 0)
1362  {
1363  //Clear the ALU Table Access Control register to stop any operation
1365 
1366  //Start the search operation
1370  }
1371 
1372  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1373  do
1374  {
1375  //Read the ALU Table Access Control register
1377 
1378  //This bit goes high to indicate either a new valid entry is returned or
1379  //the search is complete
1381 
1382  //Check whether the next valid entry is ready
1383  if((value & KSZ9897_ALU_TABLE_CTRL_VALID) != 0)
1384  {
1385  //Store the data from the ALU table entry
1386  entry->destPorts = 0;
1387  entry->override = FALSE;
1388 
1389  //Read the ALU Table Entry 1 and 2 registers
1392 
1393  //Retrieve the port associated with this MAC address
1395  {
1397  entry->srcPort = KSZ9897_PORT1;
1398  break;
1400  entry->srcPort = KSZ9897_PORT2;
1401  break;
1403  entry->srcPort = KSZ9897_PORT3;
1404  break;
1406  entry->srcPort = KSZ9897_PORT4;
1407  break;
1409  entry->srcPort = KSZ9897_PORT5;
1410  break;
1412  entry->srcPort = KSZ9897_PORT6;
1413  break;
1415  entry->srcPort = KSZ9897_PORT7;
1416  break;
1417  default:
1418  entry->srcPort = 0;
1419  break;
1420  }
1421 
1422  //Read the ALU Table Entry 3 register
1424 
1425  //Copy MAC address (first 16 bits)
1426  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1427  entry->macAddr.b[1] = value & 0xFF;
1428 
1429  //Read the ALU Table Entry 4 register
1431 
1432  //Copy MAC address (last 32 bits)
1433  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1434  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1435  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1436  entry->macAddr.b[5] = value & 0xFF;
1437 
1438  //Successful processing
1439  error = NO_ERROR;
1440  }
1441  else
1442  {
1443  //The search can be stopped any time by setting the START_FINISH bit to 0
1445 
1446  //The end of the table has been reached
1447  error = ERROR_END_OF_TABLE;
1448  }
1449 
1450  //Return status code
1451  return error;
1452 }
1453 
1454 
1455 /**
1456  * @brief Flush dynamic MAC table
1457  * @param[in] interface Underlying network interface
1458  * @param[in] port Port number
1459  **/
1460 
1462 {
1463  uint_t temp;
1464  uint8_t state;
1465 
1466  //Flush only dynamic table entries
1471 
1472  //Valid port number?
1473  if(port >= KSZ9897_PORT1 && port <= KSZ9897_PORT7)
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 & KSZ9897_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 ksz9897WritePhyReg(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  ksz9897WriteSwitchReg16(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 ksz9897ReadPhyReg(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 = ksz9897ReadSwitchReg16(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 ksz9897DumpPhyReg(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  ksz9897ReadPhyReg(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 ksz9897WriteMmdReg(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 ksz9897ReadMmdReg(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 ksz9897ReadPhyReg(interface, port, KSZ9897_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 ksz9897WriteSwitchReg8(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 = KSZ9897_SPI_CMD_WRITE;
1713  //Set register address
1714  command |= (address << 5) & KSZ9897_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 ksz9897ReadSwitchReg8(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 = KSZ9897_SPI_CMD_READ;
1756  //Set register address
1757  command |= (address << 5) & KSZ9897_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 = KSZ9897_SPI_CMD_WRITE;
1803  //Set register address
1804  command |= (address << 5) & KSZ9897_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 ksz9897ReadSwitchReg16(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 = KSZ9897_SPI_CMD_READ;
1847  //Set register address
1848  command |= (address << 5) & KSZ9897_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 = KSZ9897_SPI_CMD_WRITE;
1895  //Set register address
1896  command |= (address << 5) & KSZ9897_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 ksz9897ReadSwitchReg32(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 = KSZ9897_SPI_CMD_READ;
1941  //Set register address
1942  command |= (address << 5) & KSZ9897_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 }
uint16_t ksz9897ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
#define KSZ9897_STATIC_MCAST_TABLE_CTRL
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
#define KSZ9897_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define KSZ9897_STATIC_TABLE_ENTRY4
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
void ksz9897WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
error_t ksz9897TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
error_t ksz9897DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
#define KSZ9897_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
#define KSZ9897_UNKONWN_MULTICAST_CTRL_FWD
#define KSZ9897_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
int bool_t
Definition: compiler_port.h:53
@ ERROR_NOT_FOUND
Definition: error.h:147
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
#define KSZ9897_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
uint32_t destPorts
Definition: nic.h:152
#define netEvent
Definition: net_legacy.h:196
#define KSZ9897_ALU_TABLE_ENTRY2_PORT6_FORWARD
#define KSZ9897_BMSR
#define KSZ9897_PHYCON_DUPLEX_STATUS
void ksz9897EventHandler(NetInterface *interface)
KSZ9897 event handler.
#define KSZ9897_PORT6_XMII_CTRL1
#define KSZ9897_ALU_TABLE_ENTRY2_PORT7_FORWARD
#define KSZ9897_PORTn_XMII_CTRL1_IF_TYPE_RGMII
#define KSZ9897_MMDACR_DEVAD
void ksz9897EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
#define KSZ9897_STATIC_MAC_TABLE_SIZE
error_t ksz9897Init(NetInterface *interface)
KSZ9897 Ethernet switch initialization.
void ksz9897EnableIrq(NetInterface *interface)
Enable interrupts.
#define KSZ9897_PORTn_MSTP_STATE_TRANSMIT_EN
#define KSZ9897_TAIL_TAG_DEST_PORT3
#define KSZ9897_PORT6_OP_CTRL0
void ksz9897WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
@ ERROR_END_OF_TABLE
Definition: error.h:291
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define KSZ9897_MMDACR
#define TRUE
Definition: os_port.h:50
error_t ksz9897GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
uint8_t data[]
Definition: ethernet.h:222
#define KSZ9897_PHYCON_SPEED_100BTX
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
#define KSZ9897_PHYCON_SPEED_1000BT
#define KSZ9897_SWITCH_MAC_CTRL0
#define KSZ9897_ALU_TABLE_ENTRY2_PORT4_FORWARD
uint8_t type
Definition: coap_common.h:176
#define NET_INTERFACE_COUNT
Definition: net.h:114
void ksz9897SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
#define KSZ9897_ALU_TABLE_ENTRY1
void ksz9897WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
@ ERROR_INVALID_PORT
Definition: error.h:104
#define KSZ9897_PORTn_MSTP_STATE_LEARNING_DIS
#define KSZ9897_MMDAADR
#define KSZ9897_MMD_LED_MODE_RESERVED_DEFAULT
#define KSZ9897_SPI_CMD_READ
#define KSZ9897_PORTn_MSTP_STATE(port)
@ ERROR_TABLE_FULL
Definition: error.h:290
#define KSZ9897_PORT3
#define KSZ9897_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
#define KSZ9897_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
EthHeader
Definition: ethernet.h:223
#define KSZ9897_MMD_EEE_ADV
#define KSZ9897_SPI_CMD_ADDR
error_t ksz9897UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
void ksz9897FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define KSZ9897_MMDACR_FUNC_ADDR
#define KSZ9897_MMD_LED_MODE_LED_MODE_TRI_COLOR_DUAL
KSZ9897 7-port Gigabit Ethernet switch driver.
#define KSZ9897_PORTn_XMII_CTRL1_IF_TYPE
#define KSZ9897_STATIC_MCAST_TABLE_CTRL_ACTION
#define KSZ9897_PORT6_XMII_CTRL0
#define KSZ9897_PORT2
void ksz9897DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
uint8_t ksz9897ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
#define KSZ9897_PORT_MASK
#define KSZ9897_PORTn_XMII_CTRL0_SPEED_10_100
#define FALSE
Definition: os_port.h:46
const uint16_t ksz9897IngressTailTag[6]
Tail tag rules (host to KSZ9897)
#define KSZ9897_PORTn_MSTP_STATE_RECEIVE_EN
#define KSZ9897_ALU_TABLE_ENTRY2_PORT2_FORWARD
uint16_t ksz9897ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
error_t
Error codes.
Definition: error.h:43
#define netInterface
Definition: net_legacy.h:199
void ksz9897SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
#define KSZ9897_PORTn_XMII_CTRL0_DUPLEX
const SwitchDriver ksz9897SwitchDriver
KSZ9897 Ethernet switch driver.
#define KSZ9897_GLOBAL_PORT_MIRROR_SNOOP_CTRL
#define KSZ9897_PORTn_OP_CTRL0_TAIL_TAG_EN
#define KSZ9897_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define KSZ9897_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
#define KSZ9897_STATIC_TABLE_ENTRY1
#define NetRxAncillary
Definition: net_misc.h:40
#define KSZ9897_ALU_TABLE_CTRL_VALID
#define NetInterface
Definition: net.h:36
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define KSZ9897_ALU_TABLE_CTRL_START_FINISH
@ ERROR_INVALID_LENGTH
Definition: error.h:111
#define KSZ9897_ALU_TABLE_ENTRY2_PORT1_FORWARD
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
uint32_t ksz9897GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
#define KSZ9897_ALU_TABLE_CTRL_ACTION_SEARCH
#define KSZ9897_TAIL_TAG_DEST_PORT1
#define NetTxAncillary
Definition: net_misc.h:36
#define KSZ9897_STATIC_TABLE_ENTRY3
#define KSZ9897_UNKONWN_MULTICAST_CTRL_FWD_MAP
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
void ksz9897DisableIrq(NetInterface *interface)
Disable interrupts.
#define KSZ9897_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
#define KSZ9897_TAIL_TAG_SRC_PORT
#define KSZ9897_ALU_TABLE_ENTRY2_PORT3_FORWARD
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define KSZ9897_PORT6
#define KSZ9897_STATIC_TABLE_ENTRY2_OVERRIDE
uint32_t ksz9897ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
#define KSZ9897_ALU_TABLE_ENTRY2
#define MIN(a, b)
Definition: os_port.h:63
#define KSZ9897_PORT5
#define KSZ9897_BMSR_LINK_STATUS
__weak_func void ksz9897InitHook(NetInterface *interface)
KSZ9897 custom configuration.
#define KSZ9897_SWITCH_LUE_CTRL0
void ksz9897EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
void ksz9897EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
#define KSZ9897_PORT7
#define KSZ9897_PHYCON_SPEED_10BT
#define KSZ9897_SWITCH_LUE_CTRL2
#define KSZ9897_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
#define KSZ9897_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
#define KSZ9897_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
uint16_t port
Definition: dns_common.h:267
#define KSZ9897_ALU_TABLE_CTRL
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define KSZ9897_TAIL_TAG_DEST_PORT4
#define KSZ9897_MMDACR_FUNC_DATA_NO_POST_INC
#define KSZ9897_STATIC_TABLE_ENTRY1_VALID
#define KSZ9897_SWITCH_LUE_CTRL1
#define KSZ9897_SWITCH_OP_START_SWITCH
error_t ksz9897GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
uint16_t regAddr
Ethernet switch driver.
Definition: nic.h:325
#define KSZ9897_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN
#define KSZ9897_PORTn_XMII_CTRL1_RGMII_ID_EG
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
#define KSZ9897_UNKONWN_MULTICAST_CTRL
#define KSZ9897_TAIL_TAG_NORMAL_ADDR_LOOKUP
#define KSZ9897_PORTn_XMII_CTRL1_SPEED_1000
@ ERROR_INVALID_ENTRY
Definition: error.h:289
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
void ksz9897SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
Ipv6Addr address[]
Definition: ipv6.h:325
#define KSZ9897_PORT1
NicDuplexMode
Duplex mode.
Definition: nic.h:122
MacAddr macAddr
Definition: nic.h:150
#define KSZ9897_ALU_TABLE_ENTRY4
#define KSZ9897_MMD_LED_MODE
uint8_t srcPort
Definition: nic.h:151
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
#define KSZ9897_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT6
#define KSZ9897_TAIL_TAG_DEST_PORT2
uint8_t value[]
Definition: tcp.h:369
#define KSZ9897_ALU_TABLE_ENTRY3
#define KSZ9897_PORT4
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
uint16_t ksz9897ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define KSZ9897_SWITCH_OP
#define KSZ9897_SWITCH_LUE_CTRL2_FLUSH_OPTION
#define KSZ9897_PORTn_XMII_CTRL1_RGMII_ID_IG
#define KSZ9897_TAIL_TAG_PORT_BLOCKING_OVERRIDE
bool_t ksz9897GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
#define KSZ9897_SPI_CMD_WRITE
void ksz9897WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define KSZ9897_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
void ksz9897WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
#define KSZ9897_SWITCH_LUE_CTRL3
#define KSZ9897_STATIC_TABLE_ENTRY2
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
SwitchPortState ksz9897GetPortState(NetInterface *interface, uint8_t port)
Get port state.
#define KSZ9897_ALU_TABLE_ENTRY2_PORT5_FORWARD
#define KSZ9897_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
#define KSZ9897_CHIP_ID1_DEFAULT
#define KSZ9897_PHYCON
#define KSZ9897_TAIL_TAG_DEST_PORT5
Helper functions for Ethernet.
NicDuplexMode ksz9897GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
void ksz9897FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
#define KSZ9897_ALU_TABLE_ENTRY2_PORT_FORWARD
@ NO_ERROR
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:153
#define KSZ9897_PORT6_MASK
Debugging facilities.
Forwarding database entry.
Definition: nic.h:149
#define KSZ9897_PORTn_ETH_PHY_REG(port, addr)
#define KSZ9897_STATIC_MCAST_TABLE_CTRL_START_FINISH
error_t ksz9897AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
void ksz9897Tick(NetInterface *interface)
KSZ9897 timer handler.
#define KSZ9897_CHIP_ID1