sja1105_driver.c
Go to the documentation of this file.
1 /**
2  * @file sja1105_driver.c
3  * @brief SJA1105 5-port Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.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 SJA1105 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief SJA1105 Ethernet switch initialization
75  * @param[in] interface Underlying network interface
76  * @return Error code
77  **/
78 
80 {
81  error_t error;
82  uint32_t temp;
83 
84  //Debug message
85  TRACE_INFO("Initializing SJA1105...\r\n");
86 
87  //Initialize SPI interface
88  interface->spiDriver->init();
89 
90  //Wait for the serial interface to be ready
91  do
92  {
93  //Read CHIP_ID0 register
94  temp = sja1105ReadSingleReg(interface, SJA1105_DEVICE_ID);
95 
96  //The returned data is invalid until the serial interface is ready
97  } while(temp != SJA1105_DEVICE_ID_SJA1105PEL &&
99 
100  //Dump switch registers for debugging purpose
101  sja1105DumpReg(interface);
102 
103  //Perform custom configuration
104  error = sja1105InitHook(interface);
105 
106  //Check status code
107  if(!error)
108  {
109  //Force the TCP/IP stack to poll the link state at startup
110  interface->phyEvent = TRUE;
111  //Notify the TCP/IP stack of the event
113  }
114 
115  //Return status code
116  return error;
117 }
118 
119 
120 /**
121  * @brief SJA1105 custom configuration
122  * @param[in] interface Underlying network interface
123  * @return Error code
124  **/
125 
126 __weak_func error_t sja1105InitHook(NetInterface *interface)
127 {
128  //The static configuration must be loaded into the device
129  return ERROR_FAILURE;
130 }
131 
132 
133 /**
134  * @brief Load static configuration into the device
135  * @param[in] interface Underlying network interface
136  * @param[in] data Pointer to the HEX file to be loaded
137  * @param[in] length Length of the HEX file
138  * @return Error code
139  **/
140 
142  size_t length)
143 {
144  size_t i;
145  size_t j;
146  size_t n;
147  uint8_t type;
148  uint32_t offset;
149  uint32_t value;
150  char_t *p;
151  char_t buffer[9];
152 
153  //Debug message
154  TRACE_INFO("Loading static configuration...\r\n");
155 
156  //Read the Initial Device Configuration Flag register
158 
159  //if the CONFIGS flag set, the configuration is locked and cannot be
160  //overridden without resetting the device
163 
164  //The load operation is initiated by writing the device ID to relative
165  //address 0 (i.e. relative to the start address 0x20000)
166  offset = 0;
167 
168  //Parse HEX file
169  for(i = 0; i < length; i += n)
170  {
171  //The start of the record is marked by an ASCII colon
172  if(data[i] == ':')
173  {
174  //Check the length of the record
175  if((length - i) < 11)
176  return ERROR_INVALID_LENGTH;
177 
178  //The start code is followed by a 1 byte (2 hex digits) of byte count
179  buffer[0] = data[i + 1];
180  buffer[1] = data[i + 2];
181  buffer[2] = '\0';
182 
183  //Retrieve the number of bytes in the record
184  n = osStrtoul(buffer, &p, 16);
185 
186  //Malformed record?
187  if(*p != '\0')
188  return ERROR_INVALID_SYNTAX;
189 
190  //Check the length of the record
191  if((length - i) < (n + 11))
192  return ERROR_INVALID_LENGTH;
193 
194  //The byte count is followed by a 2 byte (4 hex digits) address
195  buffer[0] = data[i + 3];
196  buffer[1] = data[i + 4];
197  buffer[2] = data[i + 5];
198  buffer[3] = data[i + 6];
199  buffer[4] = '\0';
200 
201  //The address indicates the offset within the configuration file
202  osStrtoul(buffer, &p, 16);
203 
204  //Malformed record?
205  if(*p != '\0')
206  return ERROR_INVALID_SYNTAX;
207 
208  //The record type is 1 byte (2 hex digits) in size
209  buffer[0] = data[i + 7];
210  buffer[1] = data[i + 8];
211  buffer[2] = '\0';
212 
213  //Retrieve the number of bytes in the record
214  type = (uint8_t) osStrtoul(buffer, &p, 16);
215 
216  //Malformed record?
217  if(*p != '\0')
218  return ERROR_INVALID_SYNTAX;
219 
220  //The record type represents the type of data
221  if(type == 0x00)
222  {
223  //The static configuration is a stream of 32-bit data
224  if((n % 4) != 0)
225  return ERROR_INVALID_LENGTH;
226 
227  //Parse data
228  for(j = 0; j < (2 * n); j += 8)
229  {
230  //A 32-bit word consists of 8 hex digits
231  buffer[0] = data[i + j + 15];
232  buffer[1] = data[i + j + 16];
233  buffer[2] = data[i + j + 13];
234  buffer[3] = data[i + j + 14];
235  buffer[4] = data[i + j + 11];
236  buffer[5] = data[i + j + 12];
237  buffer[6] = data[i + j + 9];
238  buffer[7] = data[i + j + 10];
239  buffer[8] = '\0';
240 
241  //Retrieve the value of the 32-bit word
242  value = osStrtoul(buffer, &p, 16);
243 
244  //Malformed record?
245  if(*p != '\0')
246  return ERROR_INVALID_SYNTAX;
247 
248  //The load operation is relative to the start address 0x20000
250 
251  //Increment offset
252  offset++;
253  }
254  }
255  else if(type == 0x01)
256  {
257  //End of file
258  break;
259  }
260  else
261  {
262  //Ignore unknown records
263  }
264 
265  //Total length of the record
266  n = (2 * n) + 11;
267  }
268  else
269  {
270  //All characters preceding the start code should be ignored
271  n = 1;
272  }
273  }
274 
275  //Read the Initial Device Configuration Flag register
277 
278  //The CONFIGS flag should be checked after loading the static configuration
280  return ERROR_NOT_CONFIGURED;
281 
282  //Successful processing
283  return NO_ERROR;
284 }
285 
286 
287 /**
288  * @brief PLL1 setup for 50MHz
289  * @param[in] interface Underlying network interface
290  **/
291 
293 {
294  uint32_t config;
295 
296  //Debug message
297  TRACE_INFO("Configuring PLL1...\r\n");
298 
299  //PLL1 setup for 50MHz
303 
304  //Configure PLL1
305  sja1105WriteSingleReg(interface, SJA1105_PLL_1_C, config |
307 
308  //Enable PLL1
309  sja1105WriteSingleReg(interface, SJA1105_PLL_1_C, config);
310 }
311 
312 
313 /**
314  * @brief Clock generation unit setup
315  * @param[in] interface Underlying network interface
316  * @param[in] port Port number
317  * @return Error code
318  **/
319 
321 {
322  error_t error;
323  uint_t n;
324  uint32_t value;
325  uint32_t mode;
326  uint32_t speed;
327 
328  //Initialize status code
329  error = NO_ERROR;
330 
331  //Check port number
332  if(port >= SJA1105_PORT0 && port <= SJA1105_PORT4)
333  {
334  //Retrieve the zero-based index of the port
335  n = port - SJA1105_PORT0;
336 
337  //Debug message
338  TRACE_INFO("Configuring CGU (port %u)...\r\n", n);
339 
340  //Read port status register
342 
343  //Retrieve port mode
345  //Retrieve port speed
347 
348  //MII MAC mode?
350  {
351  //Disable IDIVx
355 
356  //Set CLKSRC field of MII_TX_CLK_x to TX_CLK_x
360 
361  //Set CLKSRC field of MII_RX_CLK_x to RX_CLK_x
365  }
366  //MII PHY mode?
368  {
369  //Check port speed
371  {
372  //Enable IDIVx and divide by 10
376  }
378  {
379  //Enable IDIVx and divide by 1
382  }
383  else
384  {
385  //Report an error
386  error = ERROR_FAILURE;
387  }
388 
389  //Check status code
390  if(!error)
391  {
392  //Set CLKSRC field of MII_TX_CLK_x to IDIVx
396 
397  //Set CLKSRC field of MII_RX_CLK_x to RX_CLK_x
401 
402  //Set CLKSRC field of EXT_TX_CLK_x to IDIVx
406 
407  //Set CLKSRC field of EXT_RX_CLK_x to IDIVx
411  }
412  }
413  //RMII MAC mode?
415  {
416  //Disable IDIVx
420 
421  //Set CLKSRC field of RMII_REF_CLK_x to TX_CLK_x
425 
426  //Set CLKSRC field of EXT_TX_CLK_x to PLL1
430  }
431  //RMII PHY mode?
433  {
434  //Disable IDIVx
438 
439  //Set CLKSRC field of RMII_REF_CLK_x to TX_CLK_x
443  }
444  //RGMII mode?
445  else if(mode == SJA1105_PORT_STATUS_MIIx_MODE_RGMII)
446  {
447  //Check port speed
449  {
450  //Enable IDIVx and divide by 10
454 
455  //Set CLKSRC field of RGMII_TXC_x to IDIVx
459  }
461  {
462  //Enable IDIVx and divide by 1
465 
466  //Set CLKSRC field of RGMII_TXC_x to IDIVx
470  }
471  else
472  {
473  //Disable IDIVx
477 
478  //Set CLKSRC field of RGMII_TXC_x to PLL0
482  }
483 
484  //Configure slew rate
494  }
495  //SGMII mode?
496  else if(mode == SJA1105_PORT_STATUS_MIIx_MODE_SGMII)
497  {
498  //No special CGU setup is required as the digital clock is always
499  //supplied automatically to the SGMII PHY
500  }
501  //Invalid mode?
502  else
503  {
504  //Report an error
505  error = ERROR_FAILURE;
506  }
507  }
508  else
509  {
510  //The specified port number is not valid
511  error = ERROR_INVALID_PARAMETER;
512  }
513 
514  //Return status code
515  return error;
516 }
517 
518 
519 /**
520  * @brief SJA1105 timer handler
521  * @param[in] interface Underlying network interface
522  **/
523 
524 void sja1105Tick(NetInterface *interface)
525 {
526  uint_t port;
527  bool_t linkState;
528 
529  //Initialize link state
530  linkState = FALSE;
531 
532  //Loop through the ports
534  {
535  //Retrieve current link state
536  if(sja1105GetLinkState(interface, port))
537  {
538  linkState = TRUE;
539  }
540  }
541 
542  //Link up or link down event?
543  if(linkState != interface->linkState)
544  {
545  //Set event flag
546  interface->phyEvent = TRUE;
547  //Notify the TCP/IP stack of the event
549  }
550 }
551 
552 
553 /**
554  * @brief Enable interrupts
555  * @param[in] interface Underlying network interface
556  **/
557 
559 {
560 }
561 
562 
563 /**
564  * @brief Disable interrupts
565  * @param[in] interface Underlying network interface
566  **/
567 
569 {
570 }
571 
572 
573 /**
574  * @brief SJA1105 event handler
575  * @param[in] interface Underlying network interface
576  **/
577 
579 {
580  uint_t port;
581  bool_t linkState;
582 
583  //Initialize link state
584  linkState = FALSE;
585 
586  //Loop through the ports
588  {
589  //Retrieve current link state
590  if(sja1105GetLinkState(interface, port))
591  {
592  linkState = TRUE;
593  }
594  }
595 
596  //Link up event?
597  if(linkState)
598  {
599  //Retrieve host interface speed
600  interface->linkSpeed = sja1105GetLinkSpeed(interface, SJA1105_PORT0);
601  //Retrieve host interface duplex mode
602  interface->duplexMode = sja1105GetDuplexMode(interface, SJA1105_PORT0);
603 
604  //Adjust MAC configuration parameters for proper operation
605  interface->nicDriver->updateMacConfig(interface);
606 
607  //Update link state
608  interface->linkState = TRUE;
609  }
610  else
611  {
612  //Update link state
613  interface->linkState = FALSE;
614  }
615 
616  //Process link state change event
617  nicNotifyLinkChange(interface);
618 }
619 
620 
621 /**
622  * @brief Add tail tag to Ethernet frame
623  * @param[in] interface Underlying network interface
624  * @param[in] buffer Multi-part buffer containing the payload
625  * @param[in,out] offset Offset to the first payload byte
626  * @param[in] ancillary Additional options passed to the stack along with
627  * the packet
628  * @return Error code
629  **/
630 
632  size_t *offset, NetTxAncillary *ancillary)
633 {
634  //Not implemented
635  return NO_ERROR;
636 }
637 
638 
639 /**
640  * @brief Decode tail tag from incoming Ethernet frame
641  * @param[in] interface Underlying network interface
642  * @param[in,out] frame Pointer to the received Ethernet frame
643  * @param[in,out] length Length of the frame, in bytes
644  * @param[in,out] ancillary Additional options passed to the stack along with
645  * the packet
646  * @return Error code
647  **/
648 
649 error_t sja1105UntagFrame(NetInterface *interface, uint8_t **frame,
650  size_t *length, NetRxAncillary *ancillary)
651 {
652  //Not implemented
653  return NO_ERROR;
654 }
655 
656 
657 /**
658  * @brief Get link state
659  * @param[in] interface Underlying network interface
660  * @param[in] port Port number
661  * @return Link state
662  **/
663 
664 __weak_func bool_t sja1105GetLinkState(NetInterface *interface, uint8_t port)
665 {
666  //Return current link status
667  return FALSE;
668 }
669 
670 
671 /**
672  * @brief Get link speed
673  * @param[in] interface Underlying network interface
674  * @param[in] port Port number
675  * @return Link speed
676  **/
677 
678 __weak_func uint32_t sja1105GetLinkSpeed(NetInterface *interface, uint8_t port)
679 {
680  //Return current link speed
681  return NIC_LINK_SPEED_UNKNOWN;
682 }
683 
684 
685 /**
686  * @brief Get duplex mode
687  * @param[in] interface Underlying network interface
688  * @param[in] port Port number
689  * @return Duplex mode
690  **/
691 
693  uint8_t port)
694 {
695  //The xMII interfaces support full duplex mode only
696  return NIC_FULL_DUPLEX_MODE;
697 }
698 
699 
700 /**
701  * @brief Reconfigure port speed
702  * @param[in] interface Underlying network interface
703  * @param[in] port Port number
704  * @param[in] speed Port speed
705  **/
706 
707 void sja1105SetPortSpeed(NetInterface *interface, uint8_t port, uint32_t speed)
708 {
709  uint32_t temp;
710 
711  //Check port number
712  if(port >= SJA1105_PORT0 && port <= SJA1105_PORT4)
713  {
714  //Debug message
715  TRACE_INFO("Configuring port speed (port %u)...\r\n", port - 1);
716 
717  //Read the corresponding entry from the MAC configuration table
718  sja1105ReadMacConfigEntry(interface, port);
719 
720  //Read the MAC Configuration Table Reconfiguration 4 register
721  temp = sja1105ReadSingleReg(interface,
723 
724  //Clear the SPEED field
726 
727  //Check port speed
728  if(speed == NIC_LINK_SPEED_10MBPS)
729  {
730  //Force 10Mbps operation
732  }
733  else if(speed == NIC_LINK_SPEED_100MBPS)
734  {
735  //Force 100Mbps operation
737  }
738  else
739  {
740  //Force 1Gbps operation
742  }
743 
744  //Update the entry
746  temp);
747 
748  //Reconfigure the MAC configuration table
749  sja1105WriteMacConfigEntry(interface, port);
750  }
751 }
752 
753 
754 /**
755  * @brief Set port state
756  * @param[in] interface Underlying network interface
757  * @param[in] port Port number
758  * @param[in] state Port state
759  **/
760 
761 void sja1105SetPortState(NetInterface *interface, uint8_t port,
762  SwitchPortState state)
763 {
764  //Not implemented
765 }
766 
767 
768 /**
769  * @brief Get port state
770  * @param[in] interface Underlying network interface
771  * @param[in] port Port number
772  * @return Port state
773  **/
774 
776 {
777  //Not implemented
779 }
780 
781 
782 /**
783  * @brief Set aging time for dynamic filtering entries
784  * @param[in] interface Underlying network interface
785  * @param[in] agingTime Aging time, in seconds
786  **/
787 
788 void sja1105SetAgingTime(NetInterface *interface, uint32_t agingTime)
789 {
790  //Not implemented
791 }
792 
793 
794 /**
795  * @brief Enable IGMP snooping
796  * @param[in] interface Underlying network interface
797  * @param[in] enable Enable or disable IGMP snooping
798  **/
799 
801 {
802  //Not implemented
803 }
804 
805 
806 /**
807  * @brief Enable MLD snooping
808  * @param[in] interface Underlying network interface
809  * @param[in] enable Enable or disable MLD snooping
810  **/
811 
813 {
814  //Not implemented
815 }
816 
817 
818 /**
819  * @brief Enable reserved multicast table
820  * @param[in] interface Underlying network interface
821  * @param[in] enable Enable or disable reserved group addresses
822  **/
823 
825 {
826  //Not implemented
827 }
828 
829 
830 /**
831  * @brief Add a new entry to the static MAC table
832  * @param[in] interface Underlying network interface
833  * @param[in] entry Pointer to the forwarding database entry
834  * @return Error code
835  **/
836 
838  const SwitchFdbEntry *entry)
839 {
840  //Not implemented
841  return ERROR_NOT_IMPLEMENTED;
842 }
843 
844 
845 /**
846  * @brief Remove an entry from the static MAC table
847  * @param[in] interface Underlying network interface
848  * @param[in] entry Forwarding database entry to remove from the table
849  * @return Error code
850  **/
851 
853  const SwitchFdbEntry *entry)
854 {
855  //Not implemented
856  return ERROR_NOT_IMPLEMENTED;
857 }
858 
859 
860 /**
861  * @brief Read an entry from the static MAC table
862  * @param[in] interface Underlying network interface
863  * @param[in] index Zero-based index of the entry to read
864  * @param[out] entry Pointer to the forwarding database entry
865  * @return Error code
866  **/
867 
869  SwitchFdbEntry *entry)
870 {
871  //Not implemented
872  return ERROR_NOT_IMPLEMENTED;
873 }
874 
875 
876 /**
877  * @brief Flush static MAC table
878  * @param[in] interface Underlying network interface
879  **/
880 
882 {
883  //Not implemented
884 }
885 
886 
887 /**
888  * @brief Set forward ports for unknown multicast packets
889  * @param[in] interface Underlying network interface
890  * @param[in] enable Enable or disable forwarding of unknown multicast packets
891  * @param[in] forwardPorts Port map
892  **/
893 
895  bool_t enable, uint32_t forwardPorts)
896 {
897  //Not implemented
898 }
899 
900 
901 /**
902  * @brief Read an entry from the dynamic MAC table
903  * @param[in] interface Underlying network interface
904  * @param[in] index Zero-based index of the entry to read
905  * @param[out] entry Pointer to the forwarding database entry
906  * @return Error code
907  **/
908 
910  SwitchFdbEntry *entry)
911 {
912  //Not implemented
913  return ERROR_NOT_IMPLEMENTED;
914 }
915 
916 
917 /**
918  * @brief Flush dynamic MAC table
919  * @param[in] interface Underlying network interface
920  * @param[in] port Port number
921  **/
922 
924 {
925  //Not implemented
926 }
927 
928 
929 /**
930  * @brief Reconfigure an entry in the MAC configuration table
931  * @param[in] interface Underlying network interface
932  * @param[in] port Port number
933  * @return Error code
934  **/
935 
937 {
938  error_t error;
939  uint_t n;
940  uint32_t temp;
941 
942  //Check port number
943  if(port >= SJA1105_PORT0 && port <= SJA1105_PORT4)
944  {
945  //Retrieve the zero-based index of the entry
946  n = port - SJA1105_PORT0;
947 
948  //Set up a write operation
951 
952  //The PORTIDX field specifies the port number which is affected by this
953  //dynamic reconfiguration
955 
956  //Start the write operation
958  temp);
959 
960  //The access completes when the VALID flags is cleared
961  do
962  {
963  //Read the MAC Configuration Table Reconfiguration register 0
964  temp = sja1105ReadSingleReg(interface,
966 
967  //Check the value of the VALID flag
968  } while((temp & SJA1105_MAC_CONFIG_TABLE_RECONFIG0_VALID) != 0);
969 
970  //Successful processing
971  error = NO_ERROR;
972  }
973  else
974  {
975  //The specified port number is not valid
976  error = ERROR_INVALID_PARAMETER;
977  }
978 
979  //Return status code
980  return error;
981 }
982 
983 
984 /**
985  * @brief Read an entry from the MAC configuration table
986  * @param[in] interface Underlying network interface
987  * @param[in] port Port number
988  * @return Error code
989  **/
990 
992 {
993  error_t error;
994  uint_t n;
995  uint32_t temp;
996 
997  //Check port number
998  if(port >= SJA1105_PORT0 && port <= SJA1105_PORT4)
999  {
1000  //Retrieve the zero-based index of the entry
1001  n = port - SJA1105_PORT0;
1002 
1003  //Set up a read operation
1005  //The PORTIDX field specifies the port number
1007 
1008  //Start the read operation
1010  temp);
1011 
1012  //The access completes when the VALID flags is cleared
1013  do
1014  {
1015  //Read the MAC Configuration Table Reconfiguration register 0
1016  temp = sja1105ReadSingleReg(interface,
1018 
1019  //Check the value of the VALID flag
1020  } while((temp & SJA1105_MAC_CONFIG_TABLE_RECONFIG0_VALID) != 0);
1021 
1022  //Successful processing
1023  error = NO_ERROR;
1024  }
1025  else
1026  {
1027  //The specified port number is not valid
1028  error = ERROR_INVALID_PARAMETER;
1029  }
1030 
1031  //Return status code
1032  return error;
1033 }
1034 
1035 
1036 /**
1037  * @brief Write a single register
1038  * @param[in] interface Underlying network interface
1039  * @param[in] address Register address
1040  * @param[in] data Register value
1041  **/
1042 
1043 void sja1105WriteSingleReg(NetInterface *interface, uint32_t address,
1044  uint32_t data)
1045 {
1046  //Perform write operation
1047  sja1105WriteMultipleRegs(interface, address, &data, 1);
1048 }
1049 
1050 
1051 /**
1052  * @brief Read a single register
1053  * @param[in] interface Underlying network interface
1054  * @param[in] address Register address
1055  * @return Register value
1056  **/
1057 
1058 uint32_t sja1105ReadSingleReg(NetInterface *interface, uint32_t address)
1059 {
1060  uint32_t data;
1061 
1062  //Perform read operation
1063  sja1105ReadMultipleRegs(interface, address, &data, 1);
1064 
1065  //Return register value
1066  return data;
1067 }
1068 
1069 
1070 /**
1071  * @brief Write multiple registers
1072  * @param[in] interface Underlying network interface
1073  * @param[in] address Address of the first register to be written
1074  * @param[in] data Values of the registers
1075  * @param[in] count Number of registers to write
1076  **/
1077 
1078 
1080  const uint32_t *data, uint_t count)
1081 {
1082  uint_t i;
1083  uint32_t control;
1084 
1085  //Set up a write operation
1087  //Specify the address
1089 
1090  //Pull the CS pin low
1091  interface->spiDriver->assertCs();
1092 
1093  //Set up a write operation
1095  //Specify the address
1097 
1098  //Control phase
1099  interface->spiDriver->transfer((control >> 24) & 0xFF);
1100  interface->spiDriver->transfer((control >> 16) & 0xFF);
1101  interface->spiDriver->transfer((control >> 8) & 0xFF);
1102  interface->spiDriver->transfer(control & 0xFF);
1103 
1104  //Data phase
1105  for(i = 0; i < count; i++)
1106  {
1107  //Write current 32-bit data word
1108  interface->spiDriver->transfer((data[i] >> 24) & 0xFF);
1109  interface->spiDriver->transfer((data[i] >> 16) & 0xFF);
1110  interface->spiDriver->transfer((data[i] >> 8) & 0xFF);
1111  interface->spiDriver->transfer(data[i] & 0xFF);
1112  }
1113 
1114  //Terminate the operation by raising the CS pin
1115  interface->spiDriver->deassertCs();
1116 }
1117 
1118 
1119 /**
1120  * @brief Read multiple registers
1121  * @param[in] interface Underlying network interface
1122  * @param[in] address Address of the first register to be read
1123  * @param[out] data Values of the registers
1124  * @param[in] count Number of registers to read
1125  **/
1126 
1128  uint32_t *data, uint_t count)
1129 {
1130  uint_t i;
1131  uint32_t control;
1132 
1133  //Pull the CS pin low
1134  interface->spiDriver->assertCs();
1135 
1136  //Set up a read operation
1138  //Specify the number of words to be read
1139  control |= (count << 25) & SJA1105_SPI_CTRL_RC;
1140  //Specify the address
1142 
1143  //Control phase
1144  interface->spiDriver->transfer((control >> 24) & 0xFF);
1145  interface->spiDriver->transfer((control >> 16) & 0xFF);
1146  interface->spiDriver->transfer((control >> 8) & 0xFF);
1147  interface->spiDriver->transfer(control & 0xFF);
1148 
1149  //Data phase
1150  for(i = 0; i < count; i++)
1151  {
1152  data[i] = interface->spiDriver->transfer(0xFF) << 24;
1153  data[i] |= interface->spiDriver->transfer(0xFF) << 16;
1154  data[i] |= interface->spiDriver->transfer(0xFF) << 8;
1155  data[i] |= interface->spiDriver->transfer(0xFF);
1156  }
1157 
1158  //Terminate the operation by raising the CS pin
1159  interface->spiDriver->deassertCs();
1160 }
1161 
1162 
1163 /**
1164  * @brief Dump registers for debugging purpose
1165  * @param[in] interface Underlying network interface
1166  **/
1167 
1169 {
1170  uint32_t i;
1171 
1172  //Loop through switch registers
1173  for(i = 0; i < 16; i++)
1174  {
1175  //Display current switch register
1176  TRACE_DEBUG("0x%02" PRIX32 " : 0x%08" PRIX32 "\r\n",
1177  i, sja1105ReadSingleReg(interface, i));
1178  }
1179 
1180  //Terminate with a line feed
1181  TRACE_DEBUG("\r\n");
1182 }
1183 
1184 
1185 /**
1186  * @brief Write PHY register
1187  * @param[in] interface Underlying network interface
1188  * @param[in] phyAddr PHY address
1189  * @param[in] regAddr Register address
1190  * @param[in] data Register value
1191  **/
1192 
1193 void sja1105WritePhyReg(NetInterface *interface, uint8_t phyAddr,
1194  uint8_t regAddr, uint16_t data)
1195 {
1196  //Write the specified PHY register
1197  if(interface->smiDriver != NULL)
1198  {
1199  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, phyAddr, regAddr,
1200  data);
1201  }
1202  else
1203  {
1204  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, phyAddr, regAddr,
1205  data);
1206  }
1207 }
1208 
1209 
1210 /**
1211  * @brief Read PHY register
1212  * @param[in] interface Underlying network interface
1213  * @param[in] phyAddr PHY address
1214  * @param[in] regAddr Register address
1215  * @return Register value
1216  **/
1217 
1218 uint16_t sja1105ReadPhyReg(NetInterface *interface, uint8_t phyAddr,
1219  uint8_t regAddr)
1220 {
1221  uint16_t data;
1222 
1223  //Read the specified PHY register
1224  if(interface->smiDriver != NULL)
1225  {
1226  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, phyAddr,
1227  regAddr);
1228  }
1229  else
1230  {
1231  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, phyAddr,
1232  regAddr);
1233  }
1234 
1235  //Return the value of the PHY register
1236  return data;
1237 }
1238 
1239 
1240 /**
1241  * @brief Dump PHY registers for debugging purpose
1242  * @param[in] interface Underlying network interface
1243  * @param[in] phyAddr PHY address
1244  **/
1245 
1246 void sja1105DumpPhyReg(NetInterface *interface, uint8_t phyAddr)
1247 {
1248  uint8_t i;
1249 
1250  //Loop through PHY registers
1251  for(i = 0; i < 32; i++)
1252  {
1253  //Display current PHY register
1254  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1255  sja1105ReadPhyReg(interface, phyAddr, i));
1256  }
1257 
1258  //Terminate with a line feed
1259  TRACE_DEBUG("\r\n");
1260 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
#define SJA1105_MIIx_CLK_CTRL_CLKSRC_PLL1
#define SJA1105_CFG_PAD_MIIx_TX_D32_OS_HIGH
error_t sja1105DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
int bool_t
Definition: compiler_port.h:53
#define SJA1105_ETH_STATIC_BASE
#define SJA1105_IDIV_x_C_PD
#define SJA1105_PLL_x_C_MSEL_DIV2
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
#define netEvent
Definition: net_legacy.h:196
#define SJA1105_INIT_DEV_CONFIG_FLAG
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
error_t sja1105AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
void sja1105EventHandler(NetInterface *interface)
SJA1105 event handler.
void sja1105DisableIrq(NetInterface *interface)
Disable interrupts.
@ ERROR_NOT_IMPLEMENTED
Definition: error.h:66
uint8_t control
Definition: ethernet.h:234
#define SJA1105_IDIV_x_C(port)
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG4_SPEED_1GBPS
#define TRUE
Definition: os_port.h:50
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG4_SPEED
#define SJA1105_INIT_DEV_CONFIG_FLAG_CONFIGS
uint8_t data[]
Definition: ethernet.h:222
#define SJA1105_CFG_PAD_MIIx_TX_CTRL_IPUD_PLAIN
#define SJA1105_PORT_STATUS_MIIx_SPEED
#define SJA1105_MIIx_CLK_CTRL_CLKSRC_PLL0
#define SJA1105_DEVICE_ID_SJA1105PEL
#define SJA1105_CFG_PAD_MIIx_TX_CLK_OS_HIGH
@ ERROR_ALREADY_CONFIGURED
Definition: error.h:218
void sja1105WriteMultipleRegs(NetInterface *interface, uint32_t address, const uint32_t *data, uint_t count)
Write multiple registers.
void sja1105EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
uint8_t type
Definition: coap_common.h:176
void sja1105SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
SwitchPortState sja1105GetPortState(NetInterface *interface, uint8_t port)
Get port state.
void sja1105FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
@ ERROR_NOT_CONFIGURED
Definition: error.h:217
error_t sja1105UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
#define SJA1105_PORT_STATUS_MIIx_MODE
#define SJA1105_SPI_CTRL_WRITE
#define SJA1105_IDIV_x_C_AUTOBLOCK
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define SJA1105_PORT_STATUS_MIIx_MODE_MII_MAC
#define SJA1105_PLL_x_C_FBSEL
#define SJA1105_PORT4
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
#define FALSE
Definition: os_port.h:46
error_t sja1105Init(NetInterface *interface)
SJA1105 Ethernet switch initialization.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG0_VALID
error_t sja1105WriteMacConfigEntry(NetInterface *interface, uint8_t port)
Reconfigure an entry in the MAC configuration table.
error_t
Error codes.
Definition: error.h:43
#define SJA1105_EXT_RX_CLK_x(port)
#define SJA1105_PORT_STATUS_MIIx_MODE_RMII_MAC
void sja1105FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
void sja1105WriteSingleReg(NetInterface *interface, uint32_t address, uint32_t data)
Write a single register.
#define SJA1105_MIIx_CLK_CTRL_CLKSRC_RX_CLK_x(n)
void sja1105DumpReg(NetInterface *interface)
Dump registers for debugging purpose.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
__weak_func bool_t sja1105GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
#define SJA1105_PLL_x_C_PD
#define SJA1105_CFG_PAD_MIIx_TX_D32_IPUD_PLAIN
error_t sja1105TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
SJA1105 5-port Ethernet switch driver.
#define NetRxAncillary
Definition: net_misc.h:40
#define SJA1105_CFG_PAD_MIIx_TX_CLK_IPUD_PLAIN
#define NetInterface
Definition: net.h:36
#define SJA1105_MII_TX_CLK_x(port)
void sja1105EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
NicDuplexMode sja1105GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define SJA1105_SPI_CTRL_READ
@ ERROR_INVALID_LENGTH
Definition: error.h:111
uint16_t sja1105ReadPhyReg(NetInterface *interface, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define SJA1105_CFG_PAD_MIIx_TX(port)
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG4_SPEED_100MBPS
void sja1105Tick(NetInterface *interface)
SJA1105 timer handler.
#define NetTxAncillary
Definition: net_misc.h:36
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG0_RDWRSET
#define SJA1105_MIIx_CLK_CTRL_CLKSRC_IDIVx(n)
error_t sja1105GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
#define TRACE_INFO(...)
Definition: debug.h:95
#define SJA1105_PLL_x_C_PSEL_DIV2
uint8_t length
Definition: tcp.h:368
__weak_func error_t sja1105InitHook(NetInterface *interface)
SJA1105 custom configuration.
void sja1105DumpPhyReg(NetInterface *interface, uint8_t phyAddr)
Dump PHY registers for debugging purpose.
error_t sja1105ConfigureCgu(NetInterface *interface, uint8_t port)
Clock generation unit setup.
#define SJA1105_MII_RX_CLK_x(port)
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG0_PORTIDX
#define SJA1105_PLL_1_C
const SwitchDriver sja1105SwitchDriver
SJA1105 Ethernet switch driver.
#define SJA1105_PLL_x_C_PLLCLKSRC_XO66M_0
#define SJA1105_RMII_REF_CLK_x(port)
#define SJA1105_IDIV_x_C_IDIV_DIV10
uint16_t port
Definition: dns_common.h:267
#define osStrtoul(s, endptr, base)
Definition: os_port.h:255
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:48
error_t sja1105GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
#define SJA1105_PORT1
#define SJA1105_CFG_PAD_MIIx_TX_CTRL_OS_HIGH
uint16_t regAddr
#define SJA1105_CFG_PAD_MIIx_TX_D10_IPUD_PLAIN
#define SJA1105_PORT_STATUS_MIIx_SPEED_10MBPS
#define SJA1105_PORT_STATUS_MIIx_MODE_SGMII
void sja1105EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
Ethernet switch driver.
Definition: nic.h:325
uint32_t sja1105ReadSingleReg(NetInterface *interface, uint32_t address)
Read a single register.
void sja1105SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
#define SJA1105_PLL_x_C_AUTOBLOCK
#define SJA1105_SPI_CTRL_RC
uint8_t n
#define SJA1105_PORT_STATUS_MIIx_MODE_RMII_PHY
void sja1105WritePhyReg(NetInterface *interface, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
#define SJA1105_IDIV_x_C_IDIV_DIV1
#define SJA1105_PORT0
#define SJA1105_DEVICE_ID
Ipv6Addr address[]
Definition: ipv6.h:325
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG4
error_t sja1105LoadStaticConfig(NetInterface *interface, const char_t *data, size_t length)
Load static configuration into the device.
NicDuplexMode
Duplex mode.
Definition: nic.h:122
__weak_func uint32_t sja1105GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
#define SJA1105_PORT_STATUS_MIIx_MODE_MII_PHY
uint8_t value[]
Definition: tcp.h:369
void sja1105SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
#define SJA1105_SPI_CTRL_ADDR
#define SJA1105_CFG_PAD_MIIx_TX_D10_OS_HIGH
#define SJA1105_EXT_TX_CLK_x(port)
@ ERROR_INVALID_SYNTAX
Definition: error.h:68
#define SJA1105_PORT_STATUS_MIIx_MODE_RGMII
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG0
void sja1105ReadMultipleRegs(NetInterface *interface, uint32_t address, uint32_t *data, uint_t count)
Read multiple registers.
void sja1105SetPortSpeed(NetInterface *interface, uint8_t port, uint32_t speed)
Reconfigure port speed.
#define SJA1105_MIIx_CLK_CTRL_CLKSRC_TX_CLK_x(n)
#define SJA1105_PORT_STATUS_MIIx_SPEED_100MBPS
#define SJA1105_RGMII_TX_CLK_x(port)
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
error_t sja1105ReadMacConfigEntry(NetInterface *interface, uint8_t port)
Read an entry from the MAC configuration table.
void sja1105ConfigurePll1(NetInterface *interface)
PLL1 setup for 50MHz.
#define SJA1105_MAC_CONFIG_TABLE_RECONFIG4_SPEED_10MBPS
unsigned int uint_t
Definition: compiler_port.h:50
#define SJA1105_DEVICE_ID_SJA1105QEL
TCP/IP stack core.
void sja1105EnableIrq(NetInterface *interface)
Enable interrupts.
#define SJA1105_MIIx_CLK_CTRL_AUTOBLOCK
Helper functions for Ethernet.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
Forwarding database entry.
Definition: nic.h:149
#define SJA1105_IDIV_x_C_CLKSRC_XO66M_0
#define SJA1105_PORT_STATUS_MIIx(port)