15b79c72eSTristram Ha // SPDX-License-Identifier: GPL-2.0
2b987e98eSWoojung Huh /*
3b987e98eSWoojung Huh  * Microchip switch driver main logic
4b987e98eSWoojung Huh  *
542fc6a4cSTristram Ha  * Copyright (C) 2017-2019 Microchip Technology Inc.
6b987e98eSWoojung Huh  */
7b987e98eSWoojung Huh 
8b987e98eSWoojung Huh #include <linux/delay.h>
9b987e98eSWoojung Huh #include <linux/export.h>
10924352c3SMarek Vasut #include <linux/gpio/consumer.h>
11b987e98eSWoojung Huh #include <linux/kernel.h>
12b987e98eSWoojung Huh #include <linux/module.h>
13b987e98eSWoojung Huh #include <linux/platform_data/microchip-ksz.h>
14b987e98eSWoojung Huh #include <linux/phy.h>
15b987e98eSWoojung Huh #include <linux/etherdevice.h>
16b987e98eSWoojung Huh #include <linux/if_bridge.h>
17eee16b14SArun Ramadoss #include <linux/of_device.h>
18c2e86691STristram Ha #include <linux/of_net.h>
191fe94f54SArun Ramadoss #include <linux/micrel_phy.h>
20b987e98eSWoojung Huh #include <net/dsa.h>
21b987e98eSWoojung Huh #include <net/switchdev.h>
22b987e98eSWoojung Huh 
23ffc60b55SMarek Vasut #include "ksz_common.h"
246ec23aaaSArun Ramadoss #include "ksz8.h"
256ec23aaaSArun Ramadoss #include "ksz9477.h"
2655ab6ffaSArun Ramadoss #include "lan937x.h"
277049f9b5STristram Ha 
28a530e6f2SArun Ramadoss #define MIB_COUNTER_NUM 0x20
29a530e6f2SArun Ramadoss 
30c6101dd7SArun Ramadoss struct ksz_stats_raw {
31c6101dd7SArun Ramadoss 	u64 rx_hi;
32c6101dd7SArun Ramadoss 	u64 rx_undersize;
33c6101dd7SArun Ramadoss 	u64 rx_fragments;
34c6101dd7SArun Ramadoss 	u64 rx_oversize;
35c6101dd7SArun Ramadoss 	u64 rx_jabbers;
36c6101dd7SArun Ramadoss 	u64 rx_symbol_err;
37c6101dd7SArun Ramadoss 	u64 rx_crc_err;
38c6101dd7SArun Ramadoss 	u64 rx_align_err;
39c6101dd7SArun Ramadoss 	u64 rx_mac_ctrl;
40c6101dd7SArun Ramadoss 	u64 rx_pause;
41c6101dd7SArun Ramadoss 	u64 rx_bcast;
42c6101dd7SArun Ramadoss 	u64 rx_mcast;
43c6101dd7SArun Ramadoss 	u64 rx_ucast;
44c6101dd7SArun Ramadoss 	u64 rx_64_or_less;
45c6101dd7SArun Ramadoss 	u64 rx_65_127;
46c6101dd7SArun Ramadoss 	u64 rx_128_255;
47c6101dd7SArun Ramadoss 	u64 rx_256_511;
48c6101dd7SArun Ramadoss 	u64 rx_512_1023;
49c6101dd7SArun Ramadoss 	u64 rx_1024_1522;
50c6101dd7SArun Ramadoss 	u64 rx_1523_2000;
51c6101dd7SArun Ramadoss 	u64 rx_2001;
52c6101dd7SArun Ramadoss 	u64 tx_hi;
53c6101dd7SArun Ramadoss 	u64 tx_late_col;
54c6101dd7SArun Ramadoss 	u64 tx_pause;
55c6101dd7SArun Ramadoss 	u64 tx_bcast;
56c6101dd7SArun Ramadoss 	u64 tx_mcast;
57c6101dd7SArun Ramadoss 	u64 tx_ucast;
58c6101dd7SArun Ramadoss 	u64 tx_deferred;
59c6101dd7SArun Ramadoss 	u64 tx_total_col;
60c6101dd7SArun Ramadoss 	u64 tx_exc_col;
61c6101dd7SArun Ramadoss 	u64 tx_single_col;
62c6101dd7SArun Ramadoss 	u64 tx_mult_col;
63c6101dd7SArun Ramadoss 	u64 rx_total;
64c6101dd7SArun Ramadoss 	u64 tx_total;
65c6101dd7SArun Ramadoss 	u64 rx_discards;
66c6101dd7SArun Ramadoss 	u64 tx_discards;
67c6101dd7SArun Ramadoss };
68c6101dd7SArun Ramadoss 
69a530e6f2SArun Ramadoss static const struct ksz_mib_names ksz88xx_mib_names[] = {
70a530e6f2SArun Ramadoss 	{ 0x00, "rx" },
71a530e6f2SArun Ramadoss 	{ 0x01, "rx_hi" },
72a530e6f2SArun Ramadoss 	{ 0x02, "rx_undersize" },
73a530e6f2SArun Ramadoss 	{ 0x03, "rx_fragments" },
74a530e6f2SArun Ramadoss 	{ 0x04, "rx_oversize" },
75a530e6f2SArun Ramadoss 	{ 0x05, "rx_jabbers" },
76a530e6f2SArun Ramadoss 	{ 0x06, "rx_symbol_err" },
77a530e6f2SArun Ramadoss 	{ 0x07, "rx_crc_err" },
78a530e6f2SArun Ramadoss 	{ 0x08, "rx_align_err" },
79a530e6f2SArun Ramadoss 	{ 0x09, "rx_mac_ctrl" },
80a530e6f2SArun Ramadoss 	{ 0x0a, "rx_pause" },
81a530e6f2SArun Ramadoss 	{ 0x0b, "rx_bcast" },
82a530e6f2SArun Ramadoss 	{ 0x0c, "rx_mcast" },
83a530e6f2SArun Ramadoss 	{ 0x0d, "rx_ucast" },
84a530e6f2SArun Ramadoss 	{ 0x0e, "rx_64_or_less" },
85a530e6f2SArun Ramadoss 	{ 0x0f, "rx_65_127" },
86a530e6f2SArun Ramadoss 	{ 0x10, "rx_128_255" },
87a530e6f2SArun Ramadoss 	{ 0x11, "rx_256_511" },
88a530e6f2SArun Ramadoss 	{ 0x12, "rx_512_1023" },
89a530e6f2SArun Ramadoss 	{ 0x13, "rx_1024_1522" },
90a530e6f2SArun Ramadoss 	{ 0x14, "tx" },
91a530e6f2SArun Ramadoss 	{ 0x15, "tx_hi" },
92a530e6f2SArun Ramadoss 	{ 0x16, "tx_late_col" },
93a530e6f2SArun Ramadoss 	{ 0x17, "tx_pause" },
94a530e6f2SArun Ramadoss 	{ 0x18, "tx_bcast" },
95a530e6f2SArun Ramadoss 	{ 0x19, "tx_mcast" },
96a530e6f2SArun Ramadoss 	{ 0x1a, "tx_ucast" },
97a530e6f2SArun Ramadoss 	{ 0x1b, "tx_deferred" },
98a530e6f2SArun Ramadoss 	{ 0x1c, "tx_total_col" },
99a530e6f2SArun Ramadoss 	{ 0x1d, "tx_exc_col" },
100a530e6f2SArun Ramadoss 	{ 0x1e, "tx_single_col" },
101a530e6f2SArun Ramadoss 	{ 0x1f, "tx_mult_col" },
102a530e6f2SArun Ramadoss 	{ 0x100, "rx_discards" },
103a530e6f2SArun Ramadoss 	{ 0x101, "tx_discards" },
104a530e6f2SArun Ramadoss };
105a530e6f2SArun Ramadoss 
106a530e6f2SArun Ramadoss static const struct ksz_mib_names ksz9477_mib_names[] = {
107a530e6f2SArun Ramadoss 	{ 0x00, "rx_hi" },
108a530e6f2SArun Ramadoss 	{ 0x01, "rx_undersize" },
109a530e6f2SArun Ramadoss 	{ 0x02, "rx_fragments" },
110a530e6f2SArun Ramadoss 	{ 0x03, "rx_oversize" },
111a530e6f2SArun Ramadoss 	{ 0x04, "rx_jabbers" },
112a530e6f2SArun Ramadoss 	{ 0x05, "rx_symbol_err" },
113a530e6f2SArun Ramadoss 	{ 0x06, "rx_crc_err" },
114a530e6f2SArun Ramadoss 	{ 0x07, "rx_align_err" },
115a530e6f2SArun Ramadoss 	{ 0x08, "rx_mac_ctrl" },
116a530e6f2SArun Ramadoss 	{ 0x09, "rx_pause" },
117a530e6f2SArun Ramadoss 	{ 0x0A, "rx_bcast" },
118a530e6f2SArun Ramadoss 	{ 0x0B, "rx_mcast" },
119a530e6f2SArun Ramadoss 	{ 0x0C, "rx_ucast" },
120a530e6f2SArun Ramadoss 	{ 0x0D, "rx_64_or_less" },
121a530e6f2SArun Ramadoss 	{ 0x0E, "rx_65_127" },
122a530e6f2SArun Ramadoss 	{ 0x0F, "rx_128_255" },
123a530e6f2SArun Ramadoss 	{ 0x10, "rx_256_511" },
124a530e6f2SArun Ramadoss 	{ 0x11, "rx_512_1023" },
125a530e6f2SArun Ramadoss 	{ 0x12, "rx_1024_1522" },
126a530e6f2SArun Ramadoss 	{ 0x13, "rx_1523_2000" },
127a530e6f2SArun Ramadoss 	{ 0x14, "rx_2001" },
128a530e6f2SArun Ramadoss 	{ 0x15, "tx_hi" },
129a530e6f2SArun Ramadoss 	{ 0x16, "tx_late_col" },
130a530e6f2SArun Ramadoss 	{ 0x17, "tx_pause" },
131a530e6f2SArun Ramadoss 	{ 0x18, "tx_bcast" },
132a530e6f2SArun Ramadoss 	{ 0x19, "tx_mcast" },
133a530e6f2SArun Ramadoss 	{ 0x1A, "tx_ucast" },
134a530e6f2SArun Ramadoss 	{ 0x1B, "tx_deferred" },
135a530e6f2SArun Ramadoss 	{ 0x1C, "tx_total_col" },
136a530e6f2SArun Ramadoss 	{ 0x1D, "tx_exc_col" },
137a530e6f2SArun Ramadoss 	{ 0x1E, "tx_single_col" },
138a530e6f2SArun Ramadoss 	{ 0x1F, "tx_mult_col" },
139a530e6f2SArun Ramadoss 	{ 0x80, "rx_total" },
140a530e6f2SArun Ramadoss 	{ 0x81, "tx_total" },
141a530e6f2SArun Ramadoss 	{ 0x82, "rx_discards" },
142a530e6f2SArun Ramadoss 	{ 0x83, "tx_discards" },
143a530e6f2SArun Ramadoss };
144a530e6f2SArun Ramadoss 
1456ec23aaaSArun Ramadoss static const struct ksz_dev_ops ksz8_dev_ops = {
1466ec23aaaSArun Ramadoss 	.setup = ksz8_setup,
1476ec23aaaSArun Ramadoss 	.get_port_addr = ksz8_get_port_addr,
1486ec23aaaSArun Ramadoss 	.cfg_port_member = ksz8_cfg_port_member,
1496ec23aaaSArun Ramadoss 	.flush_dyn_mac_table = ksz8_flush_dyn_mac_table,
1506ec23aaaSArun Ramadoss 	.port_setup = ksz8_port_setup,
1516ec23aaaSArun Ramadoss 	.r_phy = ksz8_r_phy,
1526ec23aaaSArun Ramadoss 	.w_phy = ksz8_w_phy,
153769e2695SArun Ramadoss 	.r_mib_cnt = ksz8_r_mib_cnt,
1546ec23aaaSArun Ramadoss 	.r_mib_pkt = ksz8_r_mib_pkt,
1556ec23aaaSArun Ramadoss 	.freeze_mib = ksz8_freeze_mib,
1566ec23aaaSArun Ramadoss 	.port_init_cnt = ksz8_port_init_cnt,
1576ec23aaaSArun Ramadoss 	.fdb_dump = ksz8_fdb_dump,
1586ec23aaaSArun Ramadoss 	.mdb_add = ksz8_mdb_add,
1596ec23aaaSArun Ramadoss 	.mdb_del = ksz8_mdb_del,
1606ec23aaaSArun Ramadoss 	.vlan_filtering = ksz8_port_vlan_filtering,
1616ec23aaaSArun Ramadoss 	.vlan_add = ksz8_port_vlan_add,
1626ec23aaaSArun Ramadoss 	.vlan_del = ksz8_port_vlan_del,
1636ec23aaaSArun Ramadoss 	.mirror_add = ksz8_port_mirror_add,
1646ec23aaaSArun Ramadoss 	.mirror_del = ksz8_port_mirror_del,
1656ec23aaaSArun Ramadoss 	.get_caps = ksz8_get_caps,
1666ec23aaaSArun Ramadoss 	.config_cpu_port = ksz8_config_cpu_port,
1676ec23aaaSArun Ramadoss 	.enable_stp_addr = ksz8_enable_stp_addr,
1686ec23aaaSArun Ramadoss 	.reset = ksz8_reset_switch,
1696ec23aaaSArun Ramadoss 	.init = ksz8_switch_init,
1706ec23aaaSArun Ramadoss 	.exit = ksz8_switch_exit,
1716ec23aaaSArun Ramadoss };
1726ec23aaaSArun Ramadoss 
1736ec23aaaSArun Ramadoss static const struct ksz_dev_ops ksz9477_dev_ops = {
1746ec23aaaSArun Ramadoss 	.setup = ksz9477_setup,
1756ec23aaaSArun Ramadoss 	.get_port_addr = ksz9477_get_port_addr,
1766ec23aaaSArun Ramadoss 	.cfg_port_member = ksz9477_cfg_port_member,
1776ec23aaaSArun Ramadoss 	.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
1786ec23aaaSArun Ramadoss 	.port_setup = ksz9477_port_setup,
1796ec23aaaSArun Ramadoss 	.r_phy = ksz9477_r_phy,
1806ec23aaaSArun Ramadoss 	.w_phy = ksz9477_w_phy,
1816ec23aaaSArun Ramadoss 	.r_mib_cnt = ksz9477_r_mib_cnt,
1826ec23aaaSArun Ramadoss 	.r_mib_pkt = ksz9477_r_mib_pkt,
1836ec23aaaSArun Ramadoss 	.r_mib_stat64 = ksz_r_mib_stats64,
1846ec23aaaSArun Ramadoss 	.freeze_mib = ksz9477_freeze_mib,
1856ec23aaaSArun Ramadoss 	.port_init_cnt = ksz9477_port_init_cnt,
1866ec23aaaSArun Ramadoss 	.vlan_filtering = ksz9477_port_vlan_filtering,
1876ec23aaaSArun Ramadoss 	.vlan_add = ksz9477_port_vlan_add,
1886ec23aaaSArun Ramadoss 	.vlan_del = ksz9477_port_vlan_del,
1896ec23aaaSArun Ramadoss 	.mirror_add = ksz9477_port_mirror_add,
1906ec23aaaSArun Ramadoss 	.mirror_del = ksz9477_port_mirror_del,
1916ec23aaaSArun Ramadoss 	.get_caps = ksz9477_get_caps,
1926ec23aaaSArun Ramadoss 	.fdb_dump = ksz9477_fdb_dump,
1936ec23aaaSArun Ramadoss 	.fdb_add = ksz9477_fdb_add,
1946ec23aaaSArun Ramadoss 	.fdb_del = ksz9477_fdb_del,
1956ec23aaaSArun Ramadoss 	.mdb_add = ksz9477_mdb_add,
1966ec23aaaSArun Ramadoss 	.mdb_del = ksz9477_mdb_del,
1976ec23aaaSArun Ramadoss 	.change_mtu = ksz9477_change_mtu,
1986ec23aaaSArun Ramadoss 	.max_mtu = ksz9477_max_mtu,
1996ec23aaaSArun Ramadoss 	.config_cpu_port = ksz9477_config_cpu_port,
2006ec23aaaSArun Ramadoss 	.enable_stp_addr = ksz9477_enable_stp_addr,
2016ec23aaaSArun Ramadoss 	.reset = ksz9477_reset_switch,
2026ec23aaaSArun Ramadoss 	.init = ksz9477_switch_init,
2036ec23aaaSArun Ramadoss 	.exit = ksz9477_switch_exit,
2046ec23aaaSArun Ramadoss };
2056ec23aaaSArun Ramadoss 
20655ab6ffaSArun Ramadoss static const struct ksz_dev_ops lan937x_dev_ops = {
20755ab6ffaSArun Ramadoss 	.setup = lan937x_setup,
20855ab6ffaSArun Ramadoss 	.get_port_addr = ksz9477_get_port_addr,
20955ab6ffaSArun Ramadoss 	.cfg_port_member = ksz9477_cfg_port_member,
210ab882368SArun Ramadoss 	.flush_dyn_mac_table = ksz9477_flush_dyn_mac_table,
21155ab6ffaSArun Ramadoss 	.port_setup = lan937x_port_setup,
212ffaf1de2SArun Ramadoss 	.r_phy = lan937x_r_phy,
213ffaf1de2SArun Ramadoss 	.w_phy = lan937x_w_phy,
21455ab6ffaSArun Ramadoss 	.r_mib_cnt = ksz9477_r_mib_cnt,
21555ab6ffaSArun Ramadoss 	.r_mib_pkt = ksz9477_r_mib_pkt,
21655ab6ffaSArun Ramadoss 	.r_mib_stat64 = ksz_r_mib_stats64,
21755ab6ffaSArun Ramadoss 	.freeze_mib = ksz9477_freeze_mib,
21855ab6ffaSArun Ramadoss 	.port_init_cnt = ksz9477_port_init_cnt,
21955ab6ffaSArun Ramadoss 	.vlan_filtering = ksz9477_port_vlan_filtering,
22055ab6ffaSArun Ramadoss 	.vlan_add = ksz9477_port_vlan_add,
22155ab6ffaSArun Ramadoss 	.vlan_del = ksz9477_port_vlan_del,
22255ab6ffaSArun Ramadoss 	.mirror_add = ksz9477_port_mirror_add,
22355ab6ffaSArun Ramadoss 	.mirror_del = ksz9477_port_mirror_del,
224c14e878dSArun Ramadoss 	.get_caps = lan937x_phylink_get_caps,
225a0cb1aa4SArun Ramadoss 	.phylink_mac_config = lan937x_phylink_mac_config,
226f597d3adSArun Ramadoss 	.phylink_mac_link_up = lan937x_phylink_mac_link_up,
22755ab6ffaSArun Ramadoss 	.fdb_dump = ksz9477_fdb_dump,
22855ab6ffaSArun Ramadoss 	.fdb_add = ksz9477_fdb_add,
22955ab6ffaSArun Ramadoss 	.fdb_del = ksz9477_fdb_del,
23055ab6ffaSArun Ramadoss 	.mdb_add = ksz9477_mdb_add,
23155ab6ffaSArun Ramadoss 	.mdb_del = ksz9477_mdb_del,
232ab882368SArun Ramadoss 	.change_mtu = lan937x_change_mtu,
23355ab6ffaSArun Ramadoss 	.max_mtu = ksz9477_max_mtu,
23455ab6ffaSArun Ramadoss 	.config_cpu_port = lan937x_config_cpu_port,
23555ab6ffaSArun Ramadoss 	.enable_stp_addr = ksz9477_enable_stp_addr,
23655ab6ffaSArun Ramadoss 	.reset = lan937x_reset_switch,
23755ab6ffaSArun Ramadoss 	.init = lan937x_switch_init,
23855ab6ffaSArun Ramadoss 	.exit = lan937x_switch_exit,
23955ab6ffaSArun Ramadoss };
24055ab6ffaSArun Ramadoss 
241a02579dfSArun Ramadoss static const u16 ksz8795_regs[] = {
242486f9ca7SArun Ramadoss 	[REG_IND_CTRL_0]		= 0x6E,
243486f9ca7SArun Ramadoss 	[REG_IND_DATA_8]		= 0x70,
244486f9ca7SArun Ramadoss 	[REG_IND_DATA_CHECK]		= 0x72,
245486f9ca7SArun Ramadoss 	[REG_IND_DATA_HI]		= 0x71,
246486f9ca7SArun Ramadoss 	[REG_IND_DATA_LO]		= 0x75,
247486f9ca7SArun Ramadoss 	[REG_IND_MIB_CHECK]		= 0x74,
248486f9ca7SArun Ramadoss 	[REG_IND_BYTE]			= 0xA0,
249486f9ca7SArun Ramadoss 	[P_FORCE_CTRL]			= 0x0C,
250486f9ca7SArun Ramadoss 	[P_LINK_STATUS]			= 0x0E,
251486f9ca7SArun Ramadoss 	[P_LOCAL_CTRL]			= 0x07,
252486f9ca7SArun Ramadoss 	[P_NEG_RESTART_CTRL]		= 0x0D,
253486f9ca7SArun Ramadoss 	[P_REMOTE_STATUS]		= 0x08,
254486f9ca7SArun Ramadoss 	[P_SPEED_STATUS]		= 0x09,
255486f9ca7SArun Ramadoss 	[S_TAIL_TAG_CTRL]		= 0x0C,
2566877102fSArun Ramadoss 	[P_STP_CTRL]			= 0x02,
2579d95329cSArun Ramadoss 	[S_START_CTRL]			= 0x01,
2589d95329cSArun Ramadoss 	[S_BROADCAST_CTRL]		= 0x06,
2599d95329cSArun Ramadoss 	[S_MULTICAST_CTRL]		= 0x04,
260*aa5b8b73SArun Ramadoss 	[P_XMII_CTRL_0]			= 0x06,
26146f80fa8SArun Ramadoss 	[P_XMII_CTRL_1]			= 0x56,
262486f9ca7SArun Ramadoss };
263486f9ca7SArun Ramadoss 
264d23a5e18SArun Ramadoss static const u32 ksz8795_masks[] = {
265d23a5e18SArun Ramadoss 	[PORT_802_1P_REMAPPING]		= BIT(7),
266d23a5e18SArun Ramadoss 	[SW_TAIL_TAG_ENABLE]		= BIT(1),
267d23a5e18SArun Ramadoss 	[MIB_COUNTER_OVERFLOW]		= BIT(6),
268d23a5e18SArun Ramadoss 	[MIB_COUNTER_VALID]		= BIT(5),
269d23a5e18SArun Ramadoss 	[VLAN_TABLE_FID]		= GENMASK(6, 0),
270d23a5e18SArun Ramadoss 	[VLAN_TABLE_MEMBERSHIP]		= GENMASK(11, 7),
271d23a5e18SArun Ramadoss 	[VLAN_TABLE_VALID]		= BIT(12),
272d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_VALID]	= BIT(21),
273d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_USE_FID]	= BIT(23),
274d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_FID]		= GENMASK(30, 24),
275d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_OVERRIDE]	= BIT(26),
276d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_FWD_PORTS]	= GENMASK(24, 20),
277d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_ENTRIES_H]	= GENMASK(6, 0),
278d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_MAC_EMPTY]	= BIT(8),
279d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_NOT_READY]	= BIT(7),
280d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_ENTRIES]	= GENMASK(31, 29),
281d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_FID]		= GENMASK(26, 20),
282d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_SRC_PORT]	= GENMASK(26, 24),
283d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_TIMESTAMP]	= GENMASK(28, 27),
284d23a5e18SArun Ramadoss };
285d23a5e18SArun Ramadoss 
286*aa5b8b73SArun Ramadoss static const u8 ksz8795_xmii_ctrl0[] = {
287*aa5b8b73SArun Ramadoss 	[P_MII_100MBIT]			= 0,
288*aa5b8b73SArun Ramadoss 	[P_MII_10MBIT]			= 1,
289*aa5b8b73SArun Ramadoss };
290*aa5b8b73SArun Ramadoss 
29146f80fa8SArun Ramadoss static const u8 ksz8795_xmii_ctrl1[] = {
29246f80fa8SArun Ramadoss 	[P_GMII_1GBIT]			= 1,
29346f80fa8SArun Ramadoss 	[P_GMII_NOT_1GBIT]		= 0,
29446f80fa8SArun Ramadoss };
29546f80fa8SArun Ramadoss 
29634e48383SArun Ramadoss static const u8 ksz8795_shifts[] = {
29734e48383SArun Ramadoss 	[VLAN_TABLE_MEMBERSHIP_S]	= 7,
29834e48383SArun Ramadoss 	[VLAN_TABLE]			= 16,
29934e48383SArun Ramadoss 	[STATIC_MAC_FWD_PORTS]		= 16,
30034e48383SArun Ramadoss 	[STATIC_MAC_FID]		= 24,
30134e48383SArun Ramadoss 	[DYNAMIC_MAC_ENTRIES_H]		= 3,
30234e48383SArun Ramadoss 	[DYNAMIC_MAC_ENTRIES]		= 29,
30334e48383SArun Ramadoss 	[DYNAMIC_MAC_FID]		= 16,
30434e48383SArun Ramadoss 	[DYNAMIC_MAC_TIMESTAMP]		= 27,
30534e48383SArun Ramadoss 	[DYNAMIC_MAC_SRC_PORT]		= 24,
30634e48383SArun Ramadoss };
30734e48383SArun Ramadoss 
308a02579dfSArun Ramadoss static const u16 ksz8863_regs[] = {
309486f9ca7SArun Ramadoss 	[REG_IND_CTRL_0]		= 0x79,
310486f9ca7SArun Ramadoss 	[REG_IND_DATA_8]		= 0x7B,
311486f9ca7SArun Ramadoss 	[REG_IND_DATA_CHECK]		= 0x7B,
312486f9ca7SArun Ramadoss 	[REG_IND_DATA_HI]		= 0x7C,
313486f9ca7SArun Ramadoss 	[REG_IND_DATA_LO]		= 0x80,
314486f9ca7SArun Ramadoss 	[REG_IND_MIB_CHECK]		= 0x80,
315486f9ca7SArun Ramadoss 	[P_FORCE_CTRL]			= 0x0C,
316486f9ca7SArun Ramadoss 	[P_LINK_STATUS]			= 0x0E,
317486f9ca7SArun Ramadoss 	[P_LOCAL_CTRL]			= 0x0C,
318486f9ca7SArun Ramadoss 	[P_NEG_RESTART_CTRL]		= 0x0D,
319486f9ca7SArun Ramadoss 	[P_REMOTE_STATUS]		= 0x0E,
320486f9ca7SArun Ramadoss 	[P_SPEED_STATUS]		= 0x0F,
321486f9ca7SArun Ramadoss 	[S_TAIL_TAG_CTRL]		= 0x03,
3226877102fSArun Ramadoss 	[P_STP_CTRL]			= 0x02,
3239d95329cSArun Ramadoss 	[S_START_CTRL]			= 0x01,
3249d95329cSArun Ramadoss 	[S_BROADCAST_CTRL]		= 0x06,
3259d95329cSArun Ramadoss 	[S_MULTICAST_CTRL]		= 0x04,
326486f9ca7SArun Ramadoss };
327486f9ca7SArun Ramadoss 
328d23a5e18SArun Ramadoss static const u32 ksz8863_masks[] = {
329d23a5e18SArun Ramadoss 	[PORT_802_1P_REMAPPING]		= BIT(3),
330d23a5e18SArun Ramadoss 	[SW_TAIL_TAG_ENABLE]		= BIT(6),
331d23a5e18SArun Ramadoss 	[MIB_COUNTER_OVERFLOW]		= BIT(7),
332d23a5e18SArun Ramadoss 	[MIB_COUNTER_VALID]		= BIT(6),
333d23a5e18SArun Ramadoss 	[VLAN_TABLE_FID]		= GENMASK(15, 12),
334d23a5e18SArun Ramadoss 	[VLAN_TABLE_MEMBERSHIP]		= GENMASK(18, 16),
335d23a5e18SArun Ramadoss 	[VLAN_TABLE_VALID]		= BIT(19),
336d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_VALID]	= BIT(19),
337d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_USE_FID]	= BIT(21),
338d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_FID]		= GENMASK(29, 26),
339d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_OVERRIDE]	= BIT(20),
340d23a5e18SArun Ramadoss 	[STATIC_MAC_TABLE_FWD_PORTS]	= GENMASK(18, 16),
341d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_ENTRIES_H]	= GENMASK(5, 0),
342d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_MAC_EMPTY]	= BIT(7),
343d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_NOT_READY]	= BIT(7),
344d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_ENTRIES]	= GENMASK(31, 28),
345d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_FID]		= GENMASK(19, 16),
346d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_SRC_PORT]	= GENMASK(21, 20),
347d23a5e18SArun Ramadoss 	[DYNAMIC_MAC_TABLE_TIMESTAMP]	= GENMASK(23, 22),
348d23a5e18SArun Ramadoss };
349d23a5e18SArun Ramadoss 
35034e48383SArun Ramadoss static u8 ksz8863_shifts[] = {
35134e48383SArun Ramadoss 	[VLAN_TABLE_MEMBERSHIP_S]	= 16,
35234e48383SArun Ramadoss 	[STATIC_MAC_FWD_PORTS]		= 16,
35334e48383SArun Ramadoss 	[STATIC_MAC_FID]		= 22,
35434e48383SArun Ramadoss 	[DYNAMIC_MAC_ENTRIES_H]		= 3,
35534e48383SArun Ramadoss 	[DYNAMIC_MAC_ENTRIES]		= 24,
35634e48383SArun Ramadoss 	[DYNAMIC_MAC_FID]		= 16,
35734e48383SArun Ramadoss 	[DYNAMIC_MAC_TIMESTAMP]		= 24,
35834e48383SArun Ramadoss 	[DYNAMIC_MAC_SRC_PORT]		= 20,
35934e48383SArun Ramadoss };
36034e48383SArun Ramadoss 
3616877102fSArun Ramadoss static const u16 ksz9477_regs[] = {
3626877102fSArun Ramadoss 	[P_STP_CTRL]			= 0x0B04,
3639d95329cSArun Ramadoss 	[S_START_CTRL]			= 0x0300,
3649d95329cSArun Ramadoss 	[S_BROADCAST_CTRL]		= 0x0332,
3659d95329cSArun Ramadoss 	[S_MULTICAST_CTRL]		= 0x0331,
366*aa5b8b73SArun Ramadoss 	[P_XMII_CTRL_0]			= 0x0300,
36746f80fa8SArun Ramadoss 	[P_XMII_CTRL_1]			= 0x0301,
368457c182aSArun Ramadoss };
3696877102fSArun Ramadoss 
370457c182aSArun Ramadoss static const u32 ksz9477_masks[] = {
371457c182aSArun Ramadoss 	[ALU_STAT_WRITE]		= 0,
372457c182aSArun Ramadoss 	[ALU_STAT_READ]			= 1,
373457c182aSArun Ramadoss };
374457c182aSArun Ramadoss 
375457c182aSArun Ramadoss static const u8 ksz9477_shifts[] = {
376457c182aSArun Ramadoss 	[ALU_STAT_INDEX]		= 16,
377457c182aSArun Ramadoss };
378457c182aSArun Ramadoss 
379*aa5b8b73SArun Ramadoss static const u8 ksz9477_xmii_ctrl0[] = {
380*aa5b8b73SArun Ramadoss 	[P_MII_100MBIT]			= 1,
381*aa5b8b73SArun Ramadoss 	[P_MII_10MBIT]			= 0,
382*aa5b8b73SArun Ramadoss };
383*aa5b8b73SArun Ramadoss 
38446f80fa8SArun Ramadoss static const u8 ksz9477_xmii_ctrl1[] = {
38546f80fa8SArun Ramadoss 	[P_GMII_1GBIT]			= 0,
38646f80fa8SArun Ramadoss 	[P_GMII_NOT_1GBIT]		= 1,
38746f80fa8SArun Ramadoss };
38846f80fa8SArun Ramadoss 
389457c182aSArun Ramadoss static const u32 lan937x_masks[] = {
390457c182aSArun Ramadoss 	[ALU_STAT_WRITE]		= 1,
391457c182aSArun Ramadoss 	[ALU_STAT_READ]			= 2,
392457c182aSArun Ramadoss };
393457c182aSArun Ramadoss 
394457c182aSArun Ramadoss static const u8 lan937x_shifts[] = {
395457c182aSArun Ramadoss 	[ALU_STAT_INDEX]		= 8,
3966877102fSArun Ramadoss };
3976877102fSArun Ramadoss 
398eee16b14SArun Ramadoss const struct ksz_chip_data ksz_switch_chips[] = {
399462d5250SArun Ramadoss 	[KSZ8795] = {
400462d5250SArun Ramadoss 		.chip_id = KSZ8795_CHIP_ID,
401462d5250SArun Ramadoss 		.dev_name = "KSZ8795",
402462d5250SArun Ramadoss 		.num_vlans = 4096,
403462d5250SArun Ramadoss 		.num_alus = 0,
404462d5250SArun Ramadoss 		.num_statics = 8,
405462d5250SArun Ramadoss 		.cpu_ports = 0x10,	/* can be configured as cpu port */
406462d5250SArun Ramadoss 		.port_cnt = 5,		/* total cpu and user ports */
4076ec23aaaSArun Ramadoss 		.ops = &ksz8_dev_ops,
408462d5250SArun Ramadoss 		.ksz87xx_eee_link_erratum = true,
409a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
410a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
411a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
412486f9ca7SArun Ramadoss 		.regs = ksz8795_regs,
413d23a5e18SArun Ramadoss 		.masks = ksz8795_masks,
41434e48383SArun Ramadoss 		.shifts = ksz8795_shifts,
415*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz8795_xmii_ctrl0,
41646f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz8795_xmii_ctrl1,
41765ac79e1SArun Ramadoss 		.supports_mii = {false, false, false, false, true},
41865ac79e1SArun Ramadoss 		.supports_rmii = {false, false, false, false, true},
41965ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false, true},
42065ac79e1SArun Ramadoss 		.internal_phy = {true, true, true, true, false},
421462d5250SArun Ramadoss 	},
422462d5250SArun Ramadoss 
423462d5250SArun Ramadoss 	[KSZ8794] = {
424462d5250SArun Ramadoss 		/* WARNING
425462d5250SArun Ramadoss 		 * =======
426462d5250SArun Ramadoss 		 * KSZ8794 is similar to KSZ8795, except the port map
427462d5250SArun Ramadoss 		 * contains a gap between external and CPU ports, the
428462d5250SArun Ramadoss 		 * port map is NOT continuous. The per-port register
429462d5250SArun Ramadoss 		 * map is shifted accordingly too, i.e. registers at
430462d5250SArun Ramadoss 		 * offset 0x40 are NOT used on KSZ8794 and they ARE
431462d5250SArun Ramadoss 		 * used on KSZ8795 for external port 3.
432462d5250SArun Ramadoss 		 *           external  cpu
433462d5250SArun Ramadoss 		 * KSZ8794   0,1,2      4
434462d5250SArun Ramadoss 		 * KSZ8795   0,1,2,3    4
435462d5250SArun Ramadoss 		 * KSZ8765   0,1,2,3    4
436462d5250SArun Ramadoss 		 * port_cnt is configured as 5, even though it is 4
437462d5250SArun Ramadoss 		 */
438462d5250SArun Ramadoss 		.chip_id = KSZ8794_CHIP_ID,
439462d5250SArun Ramadoss 		.dev_name = "KSZ8794",
440462d5250SArun Ramadoss 		.num_vlans = 4096,
441462d5250SArun Ramadoss 		.num_alus = 0,
442462d5250SArun Ramadoss 		.num_statics = 8,
443462d5250SArun Ramadoss 		.cpu_ports = 0x10,	/* can be configured as cpu port */
444462d5250SArun Ramadoss 		.port_cnt = 5,		/* total cpu and user ports */
4456ec23aaaSArun Ramadoss 		.ops = &ksz8_dev_ops,
446462d5250SArun Ramadoss 		.ksz87xx_eee_link_erratum = true,
447a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
448a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
449a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
450486f9ca7SArun Ramadoss 		.regs = ksz8795_regs,
451d23a5e18SArun Ramadoss 		.masks = ksz8795_masks,
45234e48383SArun Ramadoss 		.shifts = ksz8795_shifts,
453*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz8795_xmii_ctrl0,
45446f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz8795_xmii_ctrl1,
45565ac79e1SArun Ramadoss 		.supports_mii = {false, false, false, false, true},
45665ac79e1SArun Ramadoss 		.supports_rmii = {false, false, false, false, true},
45765ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false, true},
45865ac79e1SArun Ramadoss 		.internal_phy = {true, true, true, false, false},
459462d5250SArun Ramadoss 	},
460462d5250SArun Ramadoss 
461462d5250SArun Ramadoss 	[KSZ8765] = {
462462d5250SArun Ramadoss 		.chip_id = KSZ8765_CHIP_ID,
463462d5250SArun Ramadoss 		.dev_name = "KSZ8765",
464462d5250SArun Ramadoss 		.num_vlans = 4096,
465462d5250SArun Ramadoss 		.num_alus = 0,
466462d5250SArun Ramadoss 		.num_statics = 8,
467462d5250SArun Ramadoss 		.cpu_ports = 0x10,	/* can be configured as cpu port */
468462d5250SArun Ramadoss 		.port_cnt = 5,		/* total cpu and user ports */
4696ec23aaaSArun Ramadoss 		.ops = &ksz8_dev_ops,
470462d5250SArun Ramadoss 		.ksz87xx_eee_link_erratum = true,
471a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
472a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
473a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
474486f9ca7SArun Ramadoss 		.regs = ksz8795_regs,
475d23a5e18SArun Ramadoss 		.masks = ksz8795_masks,
47634e48383SArun Ramadoss 		.shifts = ksz8795_shifts,
477*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz8795_xmii_ctrl0,
47846f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz8795_xmii_ctrl1,
47965ac79e1SArun Ramadoss 		.supports_mii = {false, false, false, false, true},
48065ac79e1SArun Ramadoss 		.supports_rmii = {false, false, false, false, true},
48165ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false, true},
48265ac79e1SArun Ramadoss 		.internal_phy = {true, true, true, true, false},
483462d5250SArun Ramadoss 	},
484462d5250SArun Ramadoss 
485462d5250SArun Ramadoss 	[KSZ8830] = {
486462d5250SArun Ramadoss 		.chip_id = KSZ8830_CHIP_ID,
487462d5250SArun Ramadoss 		.dev_name = "KSZ8863/KSZ8873",
488462d5250SArun Ramadoss 		.num_vlans = 16,
489462d5250SArun Ramadoss 		.num_alus = 0,
490462d5250SArun Ramadoss 		.num_statics = 8,
491462d5250SArun Ramadoss 		.cpu_ports = 0x4,	/* can be configured as cpu port */
492462d5250SArun Ramadoss 		.port_cnt = 3,
4936ec23aaaSArun Ramadoss 		.ops = &ksz8_dev_ops,
494a530e6f2SArun Ramadoss 		.mib_names = ksz88xx_mib_names,
495a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz88xx_mib_names),
496a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
497486f9ca7SArun Ramadoss 		.regs = ksz8863_regs,
498d23a5e18SArun Ramadoss 		.masks = ksz8863_masks,
49934e48383SArun Ramadoss 		.shifts = ksz8863_shifts,
50065ac79e1SArun Ramadoss 		.supports_mii = {false, false, true},
50165ac79e1SArun Ramadoss 		.supports_rmii = {false, false, true},
50265ac79e1SArun Ramadoss 		.internal_phy = {true, true, false},
503462d5250SArun Ramadoss 	},
504462d5250SArun Ramadoss 
505462d5250SArun Ramadoss 	[KSZ9477] = {
506462d5250SArun Ramadoss 		.chip_id = KSZ9477_CHIP_ID,
507462d5250SArun Ramadoss 		.dev_name = "KSZ9477",
508462d5250SArun Ramadoss 		.num_vlans = 4096,
509462d5250SArun Ramadoss 		.num_alus = 4096,
510462d5250SArun Ramadoss 		.num_statics = 16,
511462d5250SArun Ramadoss 		.cpu_ports = 0x7F,	/* can be configured as cpu port */
512462d5250SArun Ramadoss 		.port_cnt = 7,		/* total physical port count */
5136ec23aaaSArun Ramadoss 		.ops = &ksz9477_dev_ops,
514462d5250SArun Ramadoss 		.phy_errata_9477 = true,
515a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
516a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
517a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
5186877102fSArun Ramadoss 		.regs = ksz9477_regs,
519457c182aSArun Ramadoss 		.masks = ksz9477_masks,
520457c182aSArun Ramadoss 		.shifts = ksz9477_shifts,
521*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
52246f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
52365ac79e1SArun Ramadoss 		.supports_mii	= {false, false, false, false,
52465ac79e1SArun Ramadoss 				   false, true, false},
52565ac79e1SArun Ramadoss 		.supports_rmii	= {false, false, false, false,
52665ac79e1SArun Ramadoss 				   false, true, false},
52765ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false,
52865ac79e1SArun Ramadoss 				   false, true, false},
52965ac79e1SArun Ramadoss 		.internal_phy	= {true, true, true, true,
53065ac79e1SArun Ramadoss 				   true, false, false},
531462d5250SArun Ramadoss 	},
532462d5250SArun Ramadoss 
533462d5250SArun Ramadoss 	[KSZ9897] = {
534462d5250SArun Ramadoss 		.chip_id = KSZ9897_CHIP_ID,
535462d5250SArun Ramadoss 		.dev_name = "KSZ9897",
536462d5250SArun Ramadoss 		.num_vlans = 4096,
537462d5250SArun Ramadoss 		.num_alus = 4096,
538462d5250SArun Ramadoss 		.num_statics = 16,
539462d5250SArun Ramadoss 		.cpu_ports = 0x7F,	/* can be configured as cpu port */
540462d5250SArun Ramadoss 		.port_cnt = 7,		/* total physical port count */
5416ec23aaaSArun Ramadoss 		.ops = &ksz9477_dev_ops,
542462d5250SArun Ramadoss 		.phy_errata_9477 = true,
543a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
544a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
545a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
5466877102fSArun Ramadoss 		.regs = ksz9477_regs,
547457c182aSArun Ramadoss 		.masks = ksz9477_masks,
548457c182aSArun Ramadoss 		.shifts = ksz9477_shifts,
549*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
55046f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
55165ac79e1SArun Ramadoss 		.supports_mii	= {false, false, false, false,
55265ac79e1SArun Ramadoss 				   false, true, true},
55365ac79e1SArun Ramadoss 		.supports_rmii	= {false, false, false, false,
55465ac79e1SArun Ramadoss 				   false, true, true},
55565ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false,
55665ac79e1SArun Ramadoss 				   false, true, true},
55765ac79e1SArun Ramadoss 		.internal_phy	= {true, true, true, true,
55865ac79e1SArun Ramadoss 				   true, false, false},
559462d5250SArun Ramadoss 	},
560462d5250SArun Ramadoss 
561462d5250SArun Ramadoss 	[KSZ9893] = {
562462d5250SArun Ramadoss 		.chip_id = KSZ9893_CHIP_ID,
563462d5250SArun Ramadoss 		.dev_name = "KSZ9893",
564462d5250SArun Ramadoss 		.num_vlans = 4096,
565462d5250SArun Ramadoss 		.num_alus = 4096,
566462d5250SArun Ramadoss 		.num_statics = 16,
567462d5250SArun Ramadoss 		.cpu_ports = 0x07,	/* can be configured as cpu port */
568462d5250SArun Ramadoss 		.port_cnt = 3,		/* total port count */
5696ec23aaaSArun Ramadoss 		.ops = &ksz9477_dev_ops,
570a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
571a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
572a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
5736877102fSArun Ramadoss 		.regs = ksz9477_regs,
574457c182aSArun Ramadoss 		.masks = ksz9477_masks,
575457c182aSArun Ramadoss 		.shifts = ksz9477_shifts,
576*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
57746f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz8795_xmii_ctrl1, /* Same as ksz8795 */
57865ac79e1SArun Ramadoss 		.supports_mii = {false, false, true},
57965ac79e1SArun Ramadoss 		.supports_rmii = {false, false, true},
58065ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, true},
58165ac79e1SArun Ramadoss 		.internal_phy = {true, true, false},
582462d5250SArun Ramadoss 	},
583462d5250SArun Ramadoss 
584462d5250SArun Ramadoss 	[KSZ9567] = {
585462d5250SArun Ramadoss 		.chip_id = KSZ9567_CHIP_ID,
586462d5250SArun Ramadoss 		.dev_name = "KSZ9567",
587462d5250SArun Ramadoss 		.num_vlans = 4096,
588462d5250SArun Ramadoss 		.num_alus = 4096,
589462d5250SArun Ramadoss 		.num_statics = 16,
590462d5250SArun Ramadoss 		.cpu_ports = 0x7F,	/* can be configured as cpu port */
591462d5250SArun Ramadoss 		.port_cnt = 7,		/* total physical port count */
5926ec23aaaSArun Ramadoss 		.ops = &ksz9477_dev_ops,
593462d5250SArun Ramadoss 		.phy_errata_9477 = true,
594a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
595a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
596a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
5976877102fSArun Ramadoss 		.regs = ksz9477_regs,
598457c182aSArun Ramadoss 		.masks = ksz9477_masks,
599457c182aSArun Ramadoss 		.shifts = ksz9477_shifts,
600*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
60146f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
60265ac79e1SArun Ramadoss 		.supports_mii	= {false, false, false, false,
60365ac79e1SArun Ramadoss 				   false, true, true},
60465ac79e1SArun Ramadoss 		.supports_rmii	= {false, false, false, false,
60565ac79e1SArun Ramadoss 				   false, true, true},
60665ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false,
60765ac79e1SArun Ramadoss 				   false, true, true},
60865ac79e1SArun Ramadoss 		.internal_phy	= {true, true, true, true,
60965ac79e1SArun Ramadoss 				   true, false, false},
610462d5250SArun Ramadoss 	},
611462d5250SArun Ramadoss 
612462d5250SArun Ramadoss 	[LAN9370] = {
613462d5250SArun Ramadoss 		.chip_id = LAN9370_CHIP_ID,
614462d5250SArun Ramadoss 		.dev_name = "LAN9370",
615462d5250SArun Ramadoss 		.num_vlans = 4096,
616462d5250SArun Ramadoss 		.num_alus = 1024,
617462d5250SArun Ramadoss 		.num_statics = 256,
618462d5250SArun Ramadoss 		.cpu_ports = 0x10,	/* can be configured as cpu port */
619462d5250SArun Ramadoss 		.port_cnt = 5,		/* total physical port count */
62055ab6ffaSArun Ramadoss 		.ops = &lan937x_dev_ops,
621a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
622a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
623a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
6246877102fSArun Ramadoss 		.regs = ksz9477_regs,
625457c182aSArun Ramadoss 		.masks = lan937x_masks,
626457c182aSArun Ramadoss 		.shifts = lan937x_shifts,
627*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
62846f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
62965ac79e1SArun Ramadoss 		.supports_mii = {false, false, false, false, true},
63065ac79e1SArun Ramadoss 		.supports_rmii = {false, false, false, false, true},
63165ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false, true},
63265ac79e1SArun Ramadoss 		.internal_phy = {true, true, true, true, false},
633462d5250SArun Ramadoss 	},
634462d5250SArun Ramadoss 
635462d5250SArun Ramadoss 	[LAN9371] = {
636462d5250SArun Ramadoss 		.chip_id = LAN9371_CHIP_ID,
637462d5250SArun Ramadoss 		.dev_name = "LAN9371",
638462d5250SArun Ramadoss 		.num_vlans = 4096,
639462d5250SArun Ramadoss 		.num_alus = 1024,
640462d5250SArun Ramadoss 		.num_statics = 256,
641462d5250SArun Ramadoss 		.cpu_ports = 0x30,	/* can be configured as cpu port */
642462d5250SArun Ramadoss 		.port_cnt = 6,		/* total physical port count */
64355ab6ffaSArun Ramadoss 		.ops = &lan937x_dev_ops,
644a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
645a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
646a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
6476877102fSArun Ramadoss 		.regs = ksz9477_regs,
648457c182aSArun Ramadoss 		.masks = lan937x_masks,
649457c182aSArun Ramadoss 		.shifts = lan937x_shifts,
650*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
65146f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
65265ac79e1SArun Ramadoss 		.supports_mii = {false, false, false, false, true, true},
65365ac79e1SArun Ramadoss 		.supports_rmii = {false, false, false, false, true, true},
65465ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false, true, true},
65565ac79e1SArun Ramadoss 		.internal_phy = {true, true, true, true, false, false},
656462d5250SArun Ramadoss 	},
657462d5250SArun Ramadoss 
658462d5250SArun Ramadoss 	[LAN9372] = {
659462d5250SArun Ramadoss 		.chip_id = LAN9372_CHIP_ID,
660462d5250SArun Ramadoss 		.dev_name = "LAN9372",
661462d5250SArun Ramadoss 		.num_vlans = 4096,
662462d5250SArun Ramadoss 		.num_alus = 1024,
663462d5250SArun Ramadoss 		.num_statics = 256,
664462d5250SArun Ramadoss 		.cpu_ports = 0x30,	/* can be configured as cpu port */
665462d5250SArun Ramadoss 		.port_cnt = 8,		/* total physical port count */
66655ab6ffaSArun Ramadoss 		.ops = &lan937x_dev_ops,
667a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
668a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
669a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
6706877102fSArun Ramadoss 		.regs = ksz9477_regs,
671457c182aSArun Ramadoss 		.masks = lan937x_masks,
672457c182aSArun Ramadoss 		.shifts = lan937x_shifts,
673*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
67446f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
67565ac79e1SArun Ramadoss 		.supports_mii	= {false, false, false, false,
67665ac79e1SArun Ramadoss 				   true, true, false, false},
67765ac79e1SArun Ramadoss 		.supports_rmii	= {false, false, false, false,
67865ac79e1SArun Ramadoss 				   true, true, false, false},
67965ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false,
68065ac79e1SArun Ramadoss 				   true, true, false, false},
68165ac79e1SArun Ramadoss 		.internal_phy	= {true, true, true, true,
68265ac79e1SArun Ramadoss 				   false, false, true, true},
683462d5250SArun Ramadoss 	},
684462d5250SArun Ramadoss 
685462d5250SArun Ramadoss 	[LAN9373] = {
686462d5250SArun Ramadoss 		.chip_id = LAN9373_CHIP_ID,
687462d5250SArun Ramadoss 		.dev_name = "LAN9373",
688462d5250SArun Ramadoss 		.num_vlans = 4096,
689462d5250SArun Ramadoss 		.num_alus = 1024,
690462d5250SArun Ramadoss 		.num_statics = 256,
691462d5250SArun Ramadoss 		.cpu_ports = 0x38,	/* can be configured as cpu port */
692462d5250SArun Ramadoss 		.port_cnt = 5,		/* total physical port count */
69355ab6ffaSArun Ramadoss 		.ops = &lan937x_dev_ops,
694a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
695a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
696a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
6976877102fSArun Ramadoss 		.regs = ksz9477_regs,
698457c182aSArun Ramadoss 		.masks = lan937x_masks,
699457c182aSArun Ramadoss 		.shifts = lan937x_shifts,
700*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
70146f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
70265ac79e1SArun Ramadoss 		.supports_mii	= {false, false, false, false,
70365ac79e1SArun Ramadoss 				   true, true, false, false},
70465ac79e1SArun Ramadoss 		.supports_rmii	= {false, false, false, false,
70565ac79e1SArun Ramadoss 				   true, true, false, false},
70665ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false,
70765ac79e1SArun Ramadoss 				   true, true, false, false},
70865ac79e1SArun Ramadoss 		.internal_phy	= {true, true, true, false,
70965ac79e1SArun Ramadoss 				   false, false, true, true},
710462d5250SArun Ramadoss 	},
711462d5250SArun Ramadoss 
712462d5250SArun Ramadoss 	[LAN9374] = {
713462d5250SArun Ramadoss 		.chip_id = LAN9374_CHIP_ID,
714462d5250SArun Ramadoss 		.dev_name = "LAN9374",
715462d5250SArun Ramadoss 		.num_vlans = 4096,
716462d5250SArun Ramadoss 		.num_alus = 1024,
717462d5250SArun Ramadoss 		.num_statics = 256,
718462d5250SArun Ramadoss 		.cpu_ports = 0x30,	/* can be configured as cpu port */
719462d5250SArun Ramadoss 		.port_cnt = 8,		/* total physical port count */
72055ab6ffaSArun Ramadoss 		.ops = &lan937x_dev_ops,
721a530e6f2SArun Ramadoss 		.mib_names = ksz9477_mib_names,
722a530e6f2SArun Ramadoss 		.mib_cnt = ARRAY_SIZE(ksz9477_mib_names),
723a530e6f2SArun Ramadoss 		.reg_mib_cnt = MIB_COUNTER_NUM,
7246877102fSArun Ramadoss 		.regs = ksz9477_regs,
725457c182aSArun Ramadoss 		.masks = lan937x_masks,
726457c182aSArun Ramadoss 		.shifts = lan937x_shifts,
727*aa5b8b73SArun Ramadoss 		.xmii_ctrl0 = ksz9477_xmii_ctrl0,
72846f80fa8SArun Ramadoss 		.xmii_ctrl1 = ksz9477_xmii_ctrl1,
72965ac79e1SArun Ramadoss 		.supports_mii	= {false, false, false, false,
73065ac79e1SArun Ramadoss 				   true, true, false, false},
73165ac79e1SArun Ramadoss 		.supports_rmii	= {false, false, false, false,
73265ac79e1SArun Ramadoss 				   true, true, false, false},
73365ac79e1SArun Ramadoss 		.supports_rgmii = {false, false, false, false,
73465ac79e1SArun Ramadoss 				   true, true, false, false},
73565ac79e1SArun Ramadoss 		.internal_phy	= {true, true, true, true,
73665ac79e1SArun Ramadoss 				   false, false, true, true},
737462d5250SArun Ramadoss 	},
738462d5250SArun Ramadoss };
739eee16b14SArun Ramadoss EXPORT_SYMBOL_GPL(ksz_switch_chips);
740462d5250SArun Ramadoss 
741462d5250SArun Ramadoss static const struct ksz_chip_data *ksz_lookup_info(unsigned int prod_num)
742462d5250SArun Ramadoss {
743462d5250SArun Ramadoss 	int i;
744462d5250SArun Ramadoss 
745462d5250SArun Ramadoss 	for (i = 0; i < ARRAY_SIZE(ksz_switch_chips); i++) {
746462d5250SArun Ramadoss 		const struct ksz_chip_data *chip = &ksz_switch_chips[i];
747462d5250SArun Ramadoss 
748462d5250SArun Ramadoss 		if (chip->chip_id == prod_num)
749462d5250SArun Ramadoss 			return chip;
750462d5250SArun Ramadoss 	}
751462d5250SArun Ramadoss 
752462d5250SArun Ramadoss 	return NULL;
753462d5250SArun Ramadoss }
754462d5250SArun Ramadoss 
755eee16b14SArun Ramadoss static int ksz_check_device_id(struct ksz_device *dev)
756eee16b14SArun Ramadoss {
757eee16b14SArun Ramadoss 	const struct ksz_chip_data *dt_chip_data;
758eee16b14SArun Ramadoss 
759eee16b14SArun Ramadoss 	dt_chip_data = of_device_get_match_data(dev->dev);
760eee16b14SArun Ramadoss 
761eee16b14SArun Ramadoss 	/* Check for Device Tree and Chip ID */
762eee16b14SArun Ramadoss 	if (dt_chip_data->chip_id != dev->chip_id) {
763eee16b14SArun Ramadoss 		dev_err(dev->dev,
764eee16b14SArun Ramadoss 			"Device tree specifies chip %s but found %s, please fix it!\n",
765eee16b14SArun Ramadoss 			dt_chip_data->dev_name, dev->info->dev_name);
766eee16b14SArun Ramadoss 		return -ENODEV;
767eee16b14SArun Ramadoss 	}
768eee16b14SArun Ramadoss 
769eee16b14SArun Ramadoss 	return 0;
770eee16b14SArun Ramadoss }
771eee16b14SArun Ramadoss 
7721958eee8SArun Ramadoss static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
77365ac79e1SArun Ramadoss 				 struct phylink_config *config)
77465ac79e1SArun Ramadoss {
77565ac79e1SArun Ramadoss 	struct ksz_device *dev = ds->priv;
77665ac79e1SArun Ramadoss 
77765ac79e1SArun Ramadoss 	config->legacy_pre_march2020 = false;
77865ac79e1SArun Ramadoss 
77965ac79e1SArun Ramadoss 	if (dev->info->supports_mii[port])
78065ac79e1SArun Ramadoss 		__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
78165ac79e1SArun Ramadoss 
78265ac79e1SArun Ramadoss 	if (dev->info->supports_rmii[port])
78365ac79e1SArun Ramadoss 		__set_bit(PHY_INTERFACE_MODE_RMII,
78465ac79e1SArun Ramadoss 			  config->supported_interfaces);
78565ac79e1SArun Ramadoss 
78665ac79e1SArun Ramadoss 	if (dev->info->supports_rgmii[port])
78765ac79e1SArun Ramadoss 		phy_interface_set_rgmii(config->supported_interfaces);
78865ac79e1SArun Ramadoss 
78965ac79e1SArun Ramadoss 	if (dev->info->internal_phy[port])
79065ac79e1SArun Ramadoss 		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
79165ac79e1SArun Ramadoss 			  config->supported_interfaces);
7927012033cSArun Ramadoss 
7937012033cSArun Ramadoss 	if (dev->dev_ops->get_caps)
7947012033cSArun Ramadoss 		dev->dev_ops->get_caps(dev, port, config);
79565ac79e1SArun Ramadoss }
79665ac79e1SArun Ramadoss 
797c6101dd7SArun Ramadoss void ksz_r_mib_stats64(struct ksz_device *dev, int port)
798c6101dd7SArun Ramadoss {
799c4748ff6SOleksij Rempel 	struct ethtool_pause_stats *pstats;
800c6101dd7SArun Ramadoss 	struct rtnl_link_stats64 *stats;
801c6101dd7SArun Ramadoss 	struct ksz_stats_raw *raw;
802c6101dd7SArun Ramadoss 	struct ksz_port_mib *mib;
803c6101dd7SArun Ramadoss 
804c6101dd7SArun Ramadoss 	mib = &dev->ports[port].mib;
805c6101dd7SArun Ramadoss 	stats = &mib->stats64;
806c4748ff6SOleksij Rempel 	pstats = &mib->pause_stats;
807c6101dd7SArun Ramadoss 	raw = (struct ksz_stats_raw *)mib->counters;
808c6101dd7SArun Ramadoss 
809c6101dd7SArun Ramadoss 	spin_lock(&mib->stats64_lock);
810c6101dd7SArun Ramadoss 
811961d6c70SOleksij Rempel 	stats->rx_packets = raw->rx_bcast + raw->rx_mcast + raw->rx_ucast +
812961d6c70SOleksij Rempel 		raw->rx_pause;
813961d6c70SOleksij Rempel 	stats->tx_packets = raw->tx_bcast + raw->tx_mcast + raw->tx_ucast +
814961d6c70SOleksij Rempel 		raw->tx_pause;
815c6101dd7SArun Ramadoss 
816c6101dd7SArun Ramadoss 	/* HW counters are counting bytes + FCS which is not acceptable
817c6101dd7SArun Ramadoss 	 * for rtnl_link_stats64 interface
818c6101dd7SArun Ramadoss 	 */
819c6101dd7SArun Ramadoss 	stats->rx_bytes = raw->rx_total - stats->rx_packets * ETH_FCS_LEN;
820c6101dd7SArun Ramadoss 	stats->tx_bytes = raw->tx_total - stats->tx_packets * ETH_FCS_LEN;
821c6101dd7SArun Ramadoss 
822c6101dd7SArun Ramadoss 	stats->rx_length_errors = raw->rx_undersize + raw->rx_fragments +
823c6101dd7SArun Ramadoss 		raw->rx_oversize;
824c6101dd7SArun Ramadoss 
825c6101dd7SArun Ramadoss 	stats->rx_crc_errors = raw->rx_crc_err;
826c6101dd7SArun Ramadoss 	stats->rx_frame_errors = raw->rx_align_err;
827c6101dd7SArun Ramadoss 	stats->rx_dropped = raw->rx_discards;
828c6101dd7SArun Ramadoss 	stats->rx_errors = stats->rx_length_errors + stats->rx_crc_errors +
829c6101dd7SArun Ramadoss 		stats->rx_frame_errors  + stats->rx_dropped;
830c6101dd7SArun Ramadoss 
831c6101dd7SArun Ramadoss 	stats->tx_window_errors = raw->tx_late_col;
832c6101dd7SArun Ramadoss 	stats->tx_fifo_errors = raw->tx_discards;
833c6101dd7SArun Ramadoss 	stats->tx_aborted_errors = raw->tx_exc_col;
834c6101dd7SArun Ramadoss 	stats->tx_errors = stats->tx_window_errors + stats->tx_fifo_errors +
835c6101dd7SArun Ramadoss 		stats->tx_aborted_errors;
836c6101dd7SArun Ramadoss 
837c6101dd7SArun Ramadoss 	stats->multicast = raw->rx_mcast;
838c6101dd7SArun Ramadoss 	stats->collisions = raw->tx_total_col;
839c6101dd7SArun Ramadoss 
840c4748ff6SOleksij Rempel 	pstats->tx_pause_frames = raw->tx_pause;
841c4748ff6SOleksij Rempel 	pstats->rx_pause_frames = raw->rx_pause;
842c4748ff6SOleksij Rempel 
843c6101dd7SArun Ramadoss 	spin_unlock(&mib->stats64_lock);
844c6101dd7SArun Ramadoss }
845c6101dd7SArun Ramadoss 
8461958eee8SArun Ramadoss static void ksz_get_stats64(struct dsa_switch *ds, int port,
847c6101dd7SArun Ramadoss 			    struct rtnl_link_stats64 *s)
848c6101dd7SArun Ramadoss {
849c6101dd7SArun Ramadoss 	struct ksz_device *dev = ds->priv;
850c6101dd7SArun Ramadoss 	struct ksz_port_mib *mib;
851c6101dd7SArun Ramadoss 
852c6101dd7SArun Ramadoss 	mib = &dev->ports[port].mib;
853c6101dd7SArun Ramadoss 
854c6101dd7SArun Ramadoss 	spin_lock(&mib->stats64_lock);
855c6101dd7SArun Ramadoss 	memcpy(s, &mib->stats64, sizeof(*s));
856c6101dd7SArun Ramadoss 	spin_unlock(&mib->stats64_lock);
857c6101dd7SArun Ramadoss }
858c6101dd7SArun Ramadoss 
859c4748ff6SOleksij Rempel static void ksz_get_pause_stats(struct dsa_switch *ds, int port,
860c4748ff6SOleksij Rempel 				struct ethtool_pause_stats *pause_stats)
861c4748ff6SOleksij Rempel {
862c4748ff6SOleksij Rempel 	struct ksz_device *dev = ds->priv;
863c4748ff6SOleksij Rempel 	struct ksz_port_mib *mib;
864c4748ff6SOleksij Rempel 
865c4748ff6SOleksij Rempel 	mib = &dev->ports[port].mib;
866c4748ff6SOleksij Rempel 
867c4748ff6SOleksij Rempel 	spin_lock(&mib->stats64_lock);
868c4748ff6SOleksij Rempel 	memcpy(pause_stats, &mib->pause_stats, sizeof(*pause_stats));
869c4748ff6SOleksij Rempel 	spin_unlock(&mib->stats64_lock);
870c4748ff6SOleksij Rempel }
871c4748ff6SOleksij Rempel 
8721958eee8SArun Ramadoss static void ksz_get_strings(struct dsa_switch *ds, int port,
873997d2126SArun Ramadoss 			    u32 stringset, uint8_t *buf)
874997d2126SArun Ramadoss {
875997d2126SArun Ramadoss 	struct ksz_device *dev = ds->priv;
876997d2126SArun Ramadoss 	int i;
877997d2126SArun Ramadoss 
878997d2126SArun Ramadoss 	if (stringset != ETH_SS_STATS)
879997d2126SArun Ramadoss 		return;
880997d2126SArun Ramadoss 
881997d2126SArun Ramadoss 	for (i = 0; i < dev->info->mib_cnt; i++) {
882997d2126SArun Ramadoss 		memcpy(buf + i * ETH_GSTRING_LEN,
883997d2126SArun Ramadoss 		       dev->info->mib_names[i].string, ETH_GSTRING_LEN);
884997d2126SArun Ramadoss 	}
885997d2126SArun Ramadoss }
886997d2126SArun Ramadoss 
887e593df51SArun Ramadoss static void ksz_update_port_member(struct ksz_device *dev, int port)
888b987e98eSWoojung Huh {
889b3612ccdSOleksij Rempel 	struct ksz_port *p = &dev->ports[port];
890b3612ccdSOleksij Rempel 	struct dsa_switch *ds = dev->ds;
891b3612ccdSOleksij Rempel 	u8 port_member = 0, cpu_port;
892b3612ccdSOleksij Rempel 	const struct dsa_port *dp;
8933d00827aSSvenning Sørensen 	int i, j;
894b987e98eSWoojung Huh 
895b3612ccdSOleksij Rempel 	if (!dsa_is_user_port(ds, port))
896b3612ccdSOleksij Rempel 		return;
897b3612ccdSOleksij Rempel 
898b3612ccdSOleksij Rempel 	dp = dsa_to_port(ds, port);
899b3612ccdSOleksij Rempel 	cpu_port = BIT(dsa_upstream_port(ds, port));
900b3612ccdSOleksij Rempel 
901b3612ccdSOleksij Rempel 	for (i = 0; i < ds->num_ports; i++) {
902b3612ccdSOleksij Rempel 		const struct dsa_port *other_dp = dsa_to_port(ds, i);
903b3612ccdSOleksij Rempel 		struct ksz_port *other_p = &dev->ports[i];
904b3612ccdSOleksij Rempel 		u8 val = 0;
905b3612ccdSOleksij Rempel 
906b3612ccdSOleksij Rempel 		if (!dsa_is_user_port(ds, i))
907c2e86691STristram Ha 			continue;
908b3612ccdSOleksij Rempel 		if (port == i)
909b3612ccdSOleksij Rempel 			continue;
91041fb0cf1SVladimir Oltean 		if (!dsa_port_bridge_same(dp, other_dp))
911c2e86691STristram Ha 			continue;
9123d00827aSSvenning Sørensen 		if (other_p->stp_state != BR_STATE_FORWARDING)
9133d00827aSSvenning Sørensen 			continue;
914b987e98eSWoojung Huh 
9153d00827aSSvenning Sørensen 		if (p->stp_state == BR_STATE_FORWARDING) {
916b3612ccdSOleksij Rempel 			val |= BIT(port);
917b3612ccdSOleksij Rempel 			port_member |= BIT(i);
918b987e98eSWoojung Huh 		}
919b3612ccdSOleksij Rempel 
9203d00827aSSvenning Sørensen 		/* Retain port [i]'s relationship to other ports than [port] */
9213d00827aSSvenning Sørensen 		for (j = 0; j < ds->num_ports; j++) {
9223d00827aSSvenning Sørensen 			const struct dsa_port *third_dp;
9233d00827aSSvenning Sørensen 			struct ksz_port *third_p;
9243d00827aSSvenning Sørensen 
9253d00827aSSvenning Sørensen 			if (j == i)
9263d00827aSSvenning Sørensen 				continue;
9273d00827aSSvenning Sørensen 			if (j == port)
9283d00827aSSvenning Sørensen 				continue;
9293d00827aSSvenning Sørensen 			if (!dsa_is_user_port(ds, j))
9303d00827aSSvenning Sørensen 				continue;
9313d00827aSSvenning Sørensen 			third_p = &dev->ports[j];
9323d00827aSSvenning Sørensen 			if (third_p->stp_state != BR_STATE_FORWARDING)
9333d00827aSSvenning Sørensen 				continue;
9343d00827aSSvenning Sørensen 			third_dp = dsa_to_port(ds, j);
9353d00827aSSvenning Sørensen 			if (dsa_port_bridge_same(other_dp, third_dp))
9363d00827aSSvenning Sørensen 				val |= BIT(j);
9373d00827aSSvenning Sørensen 		}
9383d00827aSSvenning Sørensen 
939b3612ccdSOleksij Rempel 		dev->dev_ops->cfg_port_member(dev, i, val | cpu_port);
940b3612ccdSOleksij Rempel 	}
941b3612ccdSOleksij Rempel 
942b3612ccdSOleksij Rempel 	dev->dev_ops->cfg_port_member(dev, port, port_member | cpu_port);
943b987e98eSWoojung Huh }
944b987e98eSWoojung Huh 
9451958eee8SArun Ramadoss static int ksz_setup(struct dsa_switch *ds)
946d2822e68SArun Ramadoss {
947d2822e68SArun Ramadoss 	struct ksz_device *dev = ds->priv;
9489d95329cSArun Ramadoss 	const u16 *regs;
949d2822e68SArun Ramadoss 	int ret;
950d2822e68SArun Ramadoss 
9519d95329cSArun Ramadoss 	regs = dev->info->regs;
9529d95329cSArun Ramadoss 
953d2822e68SArun Ramadoss 	dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
954d2822e68SArun Ramadoss 				       dev->info->num_vlans, GFP_KERNEL);
955d2822e68SArun Ramadoss 	if (!dev->vlan_cache)
956d2822e68SArun Ramadoss 		return -ENOMEM;
957d2822e68SArun Ramadoss 
958d2822e68SArun Ramadoss 	ret = dev->dev_ops->reset(dev);
959d2822e68SArun Ramadoss 	if (ret) {
960d2822e68SArun Ramadoss 		dev_err(ds->dev, "failed to reset switch\n");
961d2822e68SArun Ramadoss 		return ret;
962d2822e68SArun Ramadoss 	}
963d2822e68SArun Ramadoss 
9641ca6437fSArun Ramadoss 	/* set broadcast storm protection 10% rate */
9659d95329cSArun Ramadoss 	regmap_update_bits(dev->regmap[1], regs[S_BROADCAST_CTRL],
9661ca6437fSArun Ramadoss 			   BROADCAST_STORM_RATE,
9671ca6437fSArun Ramadoss 			   (BROADCAST_STORM_VALUE *
9681ca6437fSArun Ramadoss 			   BROADCAST_STORM_PROT_RATE) / 100);
9691ca6437fSArun Ramadoss 
970d2822e68SArun Ramadoss 	dev->dev_ops->config_cpu_port(ds);
971d2822e68SArun Ramadoss 
972d2822e68SArun Ramadoss 	dev->dev_ops->enable_stp_addr(dev);
973d2822e68SArun Ramadoss 
9749d95329cSArun Ramadoss 	regmap_update_bits(dev->regmap[0], regs[S_MULTICAST_CTRL],
9750abab9f3SArun Ramadoss 			   MULTICAST_STORM_DISABLE, MULTICAST_STORM_DISABLE);
9760abab9f3SArun Ramadoss 
977d2822e68SArun Ramadoss 	ksz_init_mib_timer(dev);
978d2822e68SArun Ramadoss 
979d2822e68SArun Ramadoss 	ds->configure_vlan_while_not_filtering = false;
980d2822e68SArun Ramadoss 
981d2822e68SArun Ramadoss 	if (dev->dev_ops->setup) {
982d2822e68SArun Ramadoss 		ret = dev->dev_ops->setup(ds);
983d2822e68SArun Ramadoss 		if (ret)
984d2822e68SArun Ramadoss 			return ret;
985d2822e68SArun Ramadoss 	}
986d2822e68SArun Ramadoss 
987ad08ac18SArun Ramadoss 	/* start switch */
9889d95329cSArun Ramadoss 	regmap_update_bits(dev->regmap[0], regs[S_START_CTRL],
989ad08ac18SArun Ramadoss 			   SW_START, SW_START);
990ad08ac18SArun Ramadoss 
991d2822e68SArun Ramadoss 	return 0;
992d2822e68SArun Ramadoss }
993d2822e68SArun Ramadoss 
9947c6ff470STristram Ha static void port_r_cnt(struct ksz_device *dev, int port)
9957c6ff470STristram Ha {
9967c6ff470STristram Ha 	struct ksz_port_mib *mib = &dev->ports[port].mib;
9977c6ff470STristram Ha 	u64 *dropped;
9987c6ff470STristram Ha 
9997c6ff470STristram Ha 	/* Some ports may not have MIB counters before SWITCH_COUNTER_NUM. */
1000a530e6f2SArun Ramadoss 	while (mib->cnt_ptr < dev->info->reg_mib_cnt) {
10017c6ff470STristram Ha 		dev->dev_ops->r_mib_cnt(dev, port, mib->cnt_ptr,
10027c6ff470STristram Ha 					&mib->counters[mib->cnt_ptr]);
10037c6ff470STristram Ha 		++mib->cnt_ptr;
10047c6ff470STristram Ha 	}
10057c6ff470STristram Ha 
10067c6ff470STristram Ha 	/* last one in storage */
1007a530e6f2SArun Ramadoss 	dropped = &mib->counters[dev->info->mib_cnt];
10087c6ff470STristram Ha 
10097c6ff470STristram Ha 	/* Some ports may not have MIB counters after SWITCH_COUNTER_NUM. */
1010a530e6f2SArun Ramadoss 	while (mib->cnt_ptr < dev->info->mib_cnt) {
10117c6ff470STristram Ha 		dev->dev_ops->r_mib_pkt(dev, port, mib->cnt_ptr,
10127c6ff470STristram Ha 					dropped, &mib->counters[mib->cnt_ptr]);
10137c6ff470STristram Ha 		++mib->cnt_ptr;
10147c6ff470STristram Ha 	}
10157c6ff470STristram Ha 	mib->cnt_ptr = 0;
10167c6ff470STristram Ha }
10177c6ff470STristram Ha 
10187c6ff470STristram Ha static void ksz_mib_read_work(struct work_struct *work)
10197c6ff470STristram Ha {
10207c6ff470STristram Ha 	struct ksz_device *dev = container_of(work, struct ksz_device,
1021469b390eSGeorge McCollister 					      mib_read.work);
10227c6ff470STristram Ha 	struct ksz_port_mib *mib;
10237c6ff470STristram Ha 	struct ksz_port *p;
10247c6ff470STristram Ha 	int i;
10257c6ff470STristram Ha 
1026462d5250SArun Ramadoss 	for (i = 0; i < dev->info->port_cnt; i++) {
10276bb9e376SRobert Hancock 		if (dsa_is_unused_port(dev->ds, i))
10286bb9e376SRobert Hancock 			continue;
10296bb9e376SRobert Hancock 
10307c6ff470STristram Ha 		p = &dev->ports[i];
10317c6ff470STristram Ha 		mib = &p->mib;
10327c6ff470STristram Ha 		mutex_lock(&mib->cnt_mutex);
10337c6ff470STristram Ha 
10347c6ff470STristram Ha 		/* Only read MIB counters when the port is told to do.
10357c6ff470STristram Ha 		 * If not, read only dropped counters when link is not up.
10367c6ff470STristram Ha 		 */
10377c6ff470STristram Ha 		if (!p->read) {
10387c6ff470STristram Ha 			const struct dsa_port *dp = dsa_to_port(dev->ds, i);
10397c6ff470STristram Ha 
10407c6ff470STristram Ha 			if (!netif_carrier_ok(dp->slave))
1041a530e6f2SArun Ramadoss 				mib->cnt_ptr = dev->info->reg_mib_cnt;
10427c6ff470STristram Ha 		}
10437c6ff470STristram Ha 		port_r_cnt(dev, i);
10447c6ff470STristram Ha 		p->read = false;
1045a7f4f13aSOleksij Rempel 
1046a7f4f13aSOleksij Rempel 		if (dev->dev_ops->r_mib_stat64)
1047a7f4f13aSOleksij Rempel 			dev->dev_ops->r_mib_stat64(dev, i);
1048a7f4f13aSOleksij Rempel 
10497c6ff470STristram Ha 		mutex_unlock(&mib->cnt_mutex);
10507c6ff470STristram Ha 	}
10517c6ff470STristram Ha 
1052469b390eSGeorge McCollister 	schedule_delayed_work(&dev->mib_read, dev->mib_read_interval);
10537c6ff470STristram Ha }
10547c6ff470STristram Ha 
10557c6ff470STristram Ha void ksz_init_mib_timer(struct ksz_device *dev)
10567c6ff470STristram Ha {
10577c6ff470STristram Ha 	int i;
10587c6ff470STristram Ha 
1059469b390eSGeorge McCollister 	INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work);
1060469b390eSGeorge McCollister 
1061b094c679SPrasanna Vengateshan 	for (i = 0; i < dev->info->port_cnt; i++) {
1062b094c679SPrasanna Vengateshan 		struct ksz_port_mib *mib = &dev->ports[i].mib;
1063b094c679SPrasanna Vengateshan 
10647c6ff470STristram Ha 		dev->dev_ops->port_init_cnt(dev, i);
1065b094c679SPrasanna Vengateshan 
1066b094c679SPrasanna Vengateshan 		mib->cnt_ptr = 0;
1067b094c679SPrasanna Vengateshan 		memset(mib->counters, 0, dev->info->mib_cnt * sizeof(u64));
1068b094c679SPrasanna Vengateshan 	}
10697c6ff470STristram Ha }
10707c6ff470STristram Ha 
10711958eee8SArun Ramadoss static int ksz_phy_read16(struct dsa_switch *ds, int addr, int reg)
1072b987e98eSWoojung Huh {
1073b987e98eSWoojung Huh 	struct ksz_device *dev = ds->priv;
1074c2e86691STristram Ha 	u16 val = 0xffff;
1075b987e98eSWoojung Huh 
1076c2e86691STristram Ha 	dev->dev_ops->r_phy(dev, addr, reg, &val);
1077b987e98eSWoojung Huh 
1078b987e98eSWoojung Huh 	return val;
1079b987e98eSWoojung Huh }
1080b987e98eSWoojung Huh 
10811958eee8SArun Ramadoss static int ksz_phy_write16(struct dsa_switch *ds, int addr, int reg, u16 val)
1082b987e98eSWoojung Huh {
1083b987e98eSWoojung Huh 	struct ksz_device *dev = ds->priv;
1084b987e98eSWoojung Huh 
1085c2e86691STristram Ha 	dev->dev_ops->w_phy(dev, addr, reg, val);
1086b987e98eSWoojung Huh 
1087b987e98eSWoojung Huh 	return 0;
1088b987e98eSWoojung Huh }
1089b987e98eSWoojung Huh 
10901958eee8SArun Ramadoss static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
10911fe94f54SArun Ramadoss {
10921fe94f54SArun Ramadoss 	struct ksz_device *dev = ds->priv;
10931fe94f54SArun Ramadoss 
10941fe94f54SArun Ramadoss 	if (dev->chip_id == KSZ8830_CHIP_ID) {
10951fe94f54SArun Ramadoss 		/* Silicon Errata Sheet (DS80000830A):
10961fe94f54SArun Ramadoss 		 * Port 1 does not work with LinkMD Cable-Testing.
10971fe94f54SArun Ramadoss 		 * Port 1 does not respond to received PAUSE control frames.
10981fe94f54SArun Ramadoss 		 */
10991fe94f54SArun Ramadoss 		if (!port)
11001fe94f54SArun Ramadoss 			return MICREL_KSZ8_P1_ERRATA;
11011fe94f54SArun Ramadoss 	}
11021fe94f54SArun Ramadoss 
11031fe94f54SArun Ramadoss 	return 0;
11041fe94f54SArun Ramadoss }
11051fe94f54SArun Ramadoss 
11061958eee8SArun Ramadoss static void ksz_mac_link_down(struct dsa_switch *ds, int port,
11071958eee8SArun Ramadoss 			      unsigned int mode, phy_interface_t interface)
1108c30d894bSTristram Ha {
1109c30d894bSTristram Ha 	struct ksz_device *dev = ds->priv;
1110c30d894bSTristram Ha 	struct ksz_port *p = &dev->ports[port];
1111c30d894bSTristram Ha 
1112c30d894bSTristram Ha 	/* Read all MIB counters when the link is going down. */
1113c30d894bSTristram Ha 	p->read = true;
11148098bd69SChristian Eggers 	/* timer started */
11158098bd69SChristian Eggers 	if (dev->mib_read_interval)
1116469b390eSGeorge McCollister 		schedule_delayed_work(&dev->mib_read, 0);
1117143a102eSCodrin Ciubotariu }
1118143a102eSCodrin Ciubotariu 
11191958eee8SArun Ramadoss static int ksz_sset_count(struct dsa_switch *ds, int port, int sset)
1120b987e98eSWoojung Huh {
1121b987e98eSWoojung Huh 	struct ksz_device *dev = ds->priv;
1122b987e98eSWoojung Huh 
112389f09048SFlorian Fainelli 	if (sset != ETH_SS_STATS)
112489f09048SFlorian Fainelli 		return 0;
112589f09048SFlorian Fainelli 
1126a530e6f2SArun Ramadoss 	return dev->info->mib_cnt;
1127b987e98eSWoojung Huh }
1128b987e98eSWoojung Huh 
11291958eee8SArun Ramadoss static void ksz_get_ethtool_stats(struct dsa_switch *ds, int port,
11301958eee8SArun Ramadoss 				  uint64_t *buf)
11317c6ff470STristram Ha {
11327c6ff470STristram Ha 	const struct dsa_port *dp = dsa_to_port(ds, port);
11337c6ff470STristram Ha 	struct ksz_device *dev = ds->priv;
11347c6ff470STristram Ha 	struct ksz_port_mib *mib;
11357c6ff470STristram Ha 
11367c6ff470STristram Ha 	mib = &dev->ports[port].mib;
11377c6ff470STristram Ha 	mutex_lock(&mib->cnt_mutex);
11387c6ff470STristram Ha 
11397c6ff470STristram Ha 	/* Only read dropped counters if no link. */
11407c6ff470STristram Ha 	if (!netif_carrier_ok(dp->slave))
1141a530e6f2SArun Ramadoss 		mib->cnt_ptr = dev->info->reg_mib_cnt;
11427c6ff470STristram Ha 	port_r_cnt(dev, port);
1143a530e6f2SArun Ramadoss 	memcpy(buf, mib->counters, dev->info->mib_cnt * sizeof(u64));
11447c6ff470STristram Ha 	mutex_unlock(&mib->cnt_mutex);
11457c6ff470STristram Ha }
11467c6ff470STristram Ha 
11471958eee8SArun Ramadoss static int ksz_port_bridge_join(struct dsa_switch *ds, int port,
1148b079922bSVladimir Oltean 				struct dsa_bridge bridge,
114906b9cce4SVladimir Oltean 				bool *tx_fwd_offload,
115006b9cce4SVladimir Oltean 				struct netlink_ext_ack *extack)
1151b987e98eSWoojung Huh {
1152c2e86691STristram Ha 	/* port_stp_state_set() will be called after to put the port in
1153c2e86691STristram Ha 	 * appropriate state so there is no need to do anything.
1154c2e86691STristram Ha 	 */
1155b987e98eSWoojung Huh 
1156b987e98eSWoojung Huh 	return 0;
1157b987e98eSWoojung Huh }
1158b987e98eSWoojung Huh 
11591958eee8SArun Ramadoss static void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
1160d3eed0e5SVladimir Oltean 				  struct dsa_bridge bridge)
1161c2e86691STristram Ha {
1162c2e86691STristram Ha 	/* port_stp_state_set() will be called after to put the port in
1163c2e86691STristram Ha 	 * forwarding state so there is no need to do anything.
1164c2e86691STristram Ha 	 */
1165c2e86691STristram Ha }
1166c2e86691STristram Ha 
11671958eee8SArun Ramadoss static void ksz_port_fast_age(struct dsa_switch *ds, int port)
1168c2e86691STristram Ha {
1169c2e86691STristram Ha 	struct ksz_device *dev = ds->priv;
1170c2e86691STristram Ha 
1171c2e86691STristram Ha 	dev->dev_ops->flush_dyn_mac_table(dev, port);
1172c2e86691STristram Ha }
1173c2e86691STristram Ha 
11741958eee8SArun Ramadoss static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
11751958eee8SArun Ramadoss 			    const unsigned char *addr, u16 vid,
11761958eee8SArun Ramadoss 			    struct dsa_db db)
1177e587be75SArun Ramadoss {
1178e587be75SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1179e587be75SArun Ramadoss 
1180e587be75SArun Ramadoss 	if (!dev->dev_ops->fdb_add)
1181e587be75SArun Ramadoss 		return -EOPNOTSUPP;
1182e587be75SArun Ramadoss 
1183e587be75SArun Ramadoss 	return dev->dev_ops->fdb_add(dev, port, addr, vid, db);
1184e587be75SArun Ramadoss }
1185e587be75SArun Ramadoss 
11861958eee8SArun Ramadoss static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
11871958eee8SArun Ramadoss 			    const unsigned char *addr,
11881958eee8SArun Ramadoss 			    u16 vid, struct dsa_db db)
1189e587be75SArun Ramadoss {
1190e587be75SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1191e587be75SArun Ramadoss 
1192e587be75SArun Ramadoss 	if (!dev->dev_ops->fdb_del)
1193e587be75SArun Ramadoss 		return -EOPNOTSUPP;
1194e587be75SArun Ramadoss 
1195e587be75SArun Ramadoss 	return dev->dev_ops->fdb_del(dev, port, addr, vid, db);
1196e587be75SArun Ramadoss }
1197e587be75SArun Ramadoss 
11981958eee8SArun Ramadoss static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
11991958eee8SArun Ramadoss 			     dsa_fdb_dump_cb_t *cb, void *data)
1200b987e98eSWoojung Huh {
1201b987e98eSWoojung Huh 	struct ksz_device *dev = ds->priv;
1202b987e98eSWoojung Huh 
1203e587be75SArun Ramadoss 	if (!dev->dev_ops->fdb_dump)
1204e587be75SArun Ramadoss 		return -EOPNOTSUPP;
1205b987e98eSWoojung Huh 
1206e587be75SArun Ramadoss 	return dev->dev_ops->fdb_dump(dev, port, cb, data);
1207b987e98eSWoojung Huh }
1208b987e98eSWoojung Huh 
12091958eee8SArun Ramadoss static int ksz_port_mdb_add(struct dsa_switch *ds, int port,
1210c2693363SVladimir Oltean 			    const struct switchdev_obj_port_mdb *mdb,
1211c2693363SVladimir Oltean 			    struct dsa_db db)
1212b987e98eSWoojung Huh {
1213b987e98eSWoojung Huh 	struct ksz_device *dev = ds->priv;
1214b987e98eSWoojung Huh 
1215980c7d17SArun Ramadoss 	if (!dev->dev_ops->mdb_add)
1216980c7d17SArun Ramadoss 		return -EOPNOTSUPP;
1217b987e98eSWoojung Huh 
1218980c7d17SArun Ramadoss 	return dev->dev_ops->mdb_add(dev, port, mdb, db);
1219c2e86691STristram Ha }
1220c2e86691STristram Ha 
12211958eee8SArun Ramadoss static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
1222c2693363SVladimir Oltean 			    const struct switchdev_obj_port_mdb *mdb,
1223c2693363SVladimir Oltean 			    struct dsa_db db)
1224c2e86691STristram Ha {
1225c2e86691STristram Ha 	struct ksz_device *dev = ds->priv;
1226b987e98eSWoojung Huh 
1227980c7d17SArun Ramadoss 	if (!dev->dev_ops->mdb_del)
1228980c7d17SArun Ramadoss 		return -EOPNOTSUPP;
1229b987e98eSWoojung Huh 
1230980c7d17SArun Ramadoss 	return dev->dev_ops->mdb_del(dev, port, mdb, db);
1231b987e98eSWoojung Huh }
1232b987e98eSWoojung Huh 
12331958eee8SArun Ramadoss static int ksz_enable_port(struct dsa_switch *ds, int port,
12341958eee8SArun Ramadoss 			   struct phy_device *phy)
1235b987e98eSWoojung Huh {
1236b987e98eSWoojung Huh 	struct ksz_device *dev = ds->priv;
1237b987e98eSWoojung Huh 
123874be4babSVivien Didelot 	if (!dsa_is_user_port(ds, port))
123974be4babSVivien Didelot 		return 0;
124074be4babSVivien Didelot 
1241c2e86691STristram Ha 	/* setup slave port */
1242c2e86691STristram Ha 	dev->dev_ops->port_setup(dev, port, false);
1243b987e98eSWoojung Huh 
1244c2e86691STristram Ha 	/* port_stp_state_set() will be called after to enable the port so
1245c2e86691STristram Ha 	 * there is no need to do anything.
1246c2e86691STristram Ha 	 */
1247b987e98eSWoojung Huh 
1248b987e98eSWoojung Huh 	return 0;
1249b987e98eSWoojung Huh }
1250b987e98eSWoojung Huh 
1251e593df51SArun Ramadoss void ksz_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
1252de6dd626SArun Ramadoss {
1253de6dd626SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1254de6dd626SArun Ramadoss 	struct ksz_port *p;
12556877102fSArun Ramadoss 	const u16 *regs;
1256de6dd626SArun Ramadoss 	u8 data;
1257e593df51SArun Ramadoss 
12586877102fSArun Ramadoss 	regs = dev->info->regs;
1259de6dd626SArun Ramadoss 
12606877102fSArun Ramadoss 	ksz_pread8(dev, port, regs[P_STP_CTRL], &data);
1261de6dd626SArun Ramadoss 	data &= ~(PORT_TX_ENABLE | PORT_RX_ENABLE | PORT_LEARN_DISABLE);
1262de6dd626SArun Ramadoss 
1263de6dd626SArun Ramadoss 	switch (state) {
1264de6dd626SArun Ramadoss 	case BR_STATE_DISABLED:
1265de6dd626SArun Ramadoss 		data |= PORT_LEARN_DISABLE;
1266de6dd626SArun Ramadoss 		break;
1267de6dd626SArun Ramadoss 	case BR_STATE_LISTENING:
1268de6dd626SArun Ramadoss 		data |= (PORT_RX_ENABLE | PORT_LEARN_DISABLE);
1269de6dd626SArun Ramadoss 		break;
1270de6dd626SArun Ramadoss 	case BR_STATE_LEARNING:
1271de6dd626SArun Ramadoss 		data |= PORT_RX_ENABLE;
1272de6dd626SArun Ramadoss 		break;
1273de6dd626SArun Ramadoss 	case BR_STATE_FORWARDING:
1274de6dd626SArun Ramadoss 		data |= (PORT_TX_ENABLE | PORT_RX_ENABLE);
1275de6dd626SArun Ramadoss 		break;
1276de6dd626SArun Ramadoss 	case BR_STATE_BLOCKING:
1277de6dd626SArun Ramadoss 		data |= PORT_LEARN_DISABLE;
1278de6dd626SArun Ramadoss 		break;
1279de6dd626SArun Ramadoss 	default:
1280de6dd626SArun Ramadoss 		dev_err(ds->dev, "invalid STP state: %d\n", state);
1281de6dd626SArun Ramadoss 		return;
1282de6dd626SArun Ramadoss 	}
1283de6dd626SArun Ramadoss 
12846877102fSArun Ramadoss 	ksz_pwrite8(dev, port, regs[P_STP_CTRL], data);
1285de6dd626SArun Ramadoss 
1286de6dd626SArun Ramadoss 	p = &dev->ports[port];
1287de6dd626SArun Ramadoss 	p->stp_state = state;
1288de6dd626SArun Ramadoss 
1289de6dd626SArun Ramadoss 	ksz_update_port_member(dev, port);
1290de6dd626SArun Ramadoss }
1291de6dd626SArun Ramadoss 
12921958eee8SArun Ramadoss static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds,
12931958eee8SArun Ramadoss 						  int port,
12941958eee8SArun Ramadoss 						  enum dsa_tag_protocol mp)
1295534a0431SArun Ramadoss {
1296534a0431SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1297534a0431SArun Ramadoss 	enum dsa_tag_protocol proto = DSA_TAG_PROTO_NONE;
1298534a0431SArun Ramadoss 
1299534a0431SArun Ramadoss 	if (dev->chip_id == KSZ8795_CHIP_ID ||
1300534a0431SArun Ramadoss 	    dev->chip_id == KSZ8794_CHIP_ID ||
1301534a0431SArun Ramadoss 	    dev->chip_id == KSZ8765_CHIP_ID)
1302534a0431SArun Ramadoss 		proto = DSA_TAG_PROTO_KSZ8795;
1303534a0431SArun Ramadoss 
1304534a0431SArun Ramadoss 	if (dev->chip_id == KSZ8830_CHIP_ID ||
1305534a0431SArun Ramadoss 	    dev->chip_id == KSZ9893_CHIP_ID)
1306534a0431SArun Ramadoss 		proto = DSA_TAG_PROTO_KSZ9893;
1307534a0431SArun Ramadoss 
1308534a0431SArun Ramadoss 	if (dev->chip_id == KSZ9477_CHIP_ID ||
1309534a0431SArun Ramadoss 	    dev->chip_id == KSZ9897_CHIP_ID ||
1310534a0431SArun Ramadoss 	    dev->chip_id == KSZ9567_CHIP_ID)
1311534a0431SArun Ramadoss 		proto = DSA_TAG_PROTO_KSZ9477;
1312534a0431SArun Ramadoss 
131399b16df0SArun Ramadoss 	if (is_lan937x(dev))
131499b16df0SArun Ramadoss 		proto = DSA_TAG_PROTO_LAN937X_VALUE;
131599b16df0SArun Ramadoss 
1316534a0431SArun Ramadoss 	return proto;
1317534a0431SArun Ramadoss }
1318534a0431SArun Ramadoss 
13191958eee8SArun Ramadoss static int ksz_port_vlan_filtering(struct dsa_switch *ds, int port,
1320f0d997e3SArun Ramadoss 				   bool flag, struct netlink_ext_ack *extack)
1321f0d997e3SArun Ramadoss {
1322f0d997e3SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1323f0d997e3SArun Ramadoss 
1324f0d997e3SArun Ramadoss 	if (!dev->dev_ops->vlan_filtering)
1325f0d997e3SArun Ramadoss 		return -EOPNOTSUPP;
1326f0d997e3SArun Ramadoss 
1327f0d997e3SArun Ramadoss 	return dev->dev_ops->vlan_filtering(dev, port, flag, extack);
1328f0d997e3SArun Ramadoss }
1329f0d997e3SArun Ramadoss 
13301958eee8SArun Ramadoss static int ksz_port_vlan_add(struct dsa_switch *ds, int port,
1331f0d997e3SArun Ramadoss 			     const struct switchdev_obj_port_vlan *vlan,
1332f0d997e3SArun Ramadoss 			     struct netlink_ext_ack *extack)
1333f0d997e3SArun Ramadoss {
1334f0d997e3SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1335f0d997e3SArun Ramadoss 
1336f0d997e3SArun Ramadoss 	if (!dev->dev_ops->vlan_add)
1337f0d997e3SArun Ramadoss 		return -EOPNOTSUPP;
1338f0d997e3SArun Ramadoss 
1339f0d997e3SArun Ramadoss 	return dev->dev_ops->vlan_add(dev, port, vlan, extack);
1340f0d997e3SArun Ramadoss }
1341f0d997e3SArun Ramadoss 
13421958eee8SArun Ramadoss static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
1343f0d997e3SArun Ramadoss 			     const struct switchdev_obj_port_vlan *vlan)
1344f0d997e3SArun Ramadoss {
1345f0d997e3SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1346f0d997e3SArun Ramadoss 
1347f0d997e3SArun Ramadoss 	if (!dev->dev_ops->vlan_del)
1348f0d997e3SArun Ramadoss 		return -EOPNOTSUPP;
1349f0d997e3SArun Ramadoss 
1350f0d997e3SArun Ramadoss 	return dev->dev_ops->vlan_del(dev, port, vlan);
1351f0d997e3SArun Ramadoss }
1352f0d997e3SArun Ramadoss 
13531958eee8SArun Ramadoss static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
135400a298bbSArun Ramadoss 			       struct dsa_mall_mirror_tc_entry *mirror,
135500a298bbSArun Ramadoss 			       bool ingress, struct netlink_ext_ack *extack)
135600a298bbSArun Ramadoss {
135700a298bbSArun Ramadoss 	struct ksz_device *dev = ds->priv;
135800a298bbSArun Ramadoss 
135900a298bbSArun Ramadoss 	if (!dev->dev_ops->mirror_add)
136000a298bbSArun Ramadoss 		return -EOPNOTSUPP;
136100a298bbSArun Ramadoss 
136200a298bbSArun Ramadoss 	return dev->dev_ops->mirror_add(dev, port, mirror, ingress, extack);
136300a298bbSArun Ramadoss }
136400a298bbSArun Ramadoss 
13651958eee8SArun Ramadoss static void ksz_port_mirror_del(struct dsa_switch *ds, int port,
136600a298bbSArun Ramadoss 				struct dsa_mall_mirror_tc_entry *mirror)
136700a298bbSArun Ramadoss {
136800a298bbSArun Ramadoss 	struct ksz_device *dev = ds->priv;
136900a298bbSArun Ramadoss 
137000a298bbSArun Ramadoss 	if (dev->dev_ops->mirror_del)
137100a298bbSArun Ramadoss 		dev->dev_ops->mirror_del(dev, port, mirror);
137200a298bbSArun Ramadoss }
137300a298bbSArun Ramadoss 
13741958eee8SArun Ramadoss static int ksz_change_mtu(struct dsa_switch *ds, int port, int mtu)
13751fe94f54SArun Ramadoss {
13761fe94f54SArun Ramadoss 	struct ksz_device *dev = ds->priv;
13771fe94f54SArun Ramadoss 
13781fe94f54SArun Ramadoss 	if (!dev->dev_ops->change_mtu)
13791fe94f54SArun Ramadoss 		return -EOPNOTSUPP;
13801fe94f54SArun Ramadoss 
13811fe94f54SArun Ramadoss 	return dev->dev_ops->change_mtu(dev, port, mtu);
13821fe94f54SArun Ramadoss }
13831fe94f54SArun Ramadoss 
13841958eee8SArun Ramadoss static int ksz_max_mtu(struct dsa_switch *ds, int port)
13851fe94f54SArun Ramadoss {
13861fe94f54SArun Ramadoss 	struct ksz_device *dev = ds->priv;
13871fe94f54SArun Ramadoss 
13881fe94f54SArun Ramadoss 	if (!dev->dev_ops->max_mtu)
13891fe94f54SArun Ramadoss 		return -EOPNOTSUPP;
13901fe94f54SArun Ramadoss 
13911fe94f54SArun Ramadoss 	return dev->dev_ops->max_mtu(dev, port);
13921fe94f54SArun Ramadoss }
13931fe94f54SArun Ramadoss 
1394a0cb1aa4SArun Ramadoss static void ksz_phylink_mac_config(struct dsa_switch *ds, int port,
1395a0cb1aa4SArun Ramadoss 				   unsigned int mode,
1396a0cb1aa4SArun Ramadoss 				   const struct phylink_link_state *state)
1397a0cb1aa4SArun Ramadoss {
1398a0cb1aa4SArun Ramadoss 	struct ksz_device *dev = ds->priv;
1399a0cb1aa4SArun Ramadoss 
1400a0cb1aa4SArun Ramadoss 	if (dev->dev_ops->phylink_mac_config)
1401a0cb1aa4SArun Ramadoss 		dev->dev_ops->phylink_mac_config(dev, port, mode, state);
1402a0cb1aa4SArun Ramadoss }
1403a0cb1aa4SArun Ramadoss 
140446f80fa8SArun Ramadoss bool ksz_get_gbit(struct ksz_device *dev, int port)
140546f80fa8SArun Ramadoss {
140646f80fa8SArun Ramadoss 	const u8 *bitval = dev->info->xmii_ctrl1;
140746f80fa8SArun Ramadoss 	const u16 *regs = dev->info->regs;
140846f80fa8SArun Ramadoss 	bool gbit = false;
140946f80fa8SArun Ramadoss 	u8 data8;
141046f80fa8SArun Ramadoss 	bool val;
141146f80fa8SArun Ramadoss 
141246f80fa8SArun Ramadoss 	ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8);
141346f80fa8SArun Ramadoss 
141446f80fa8SArun Ramadoss 	val = FIELD_GET(P_GMII_1GBIT_M, data8);
141546f80fa8SArun Ramadoss 
141646f80fa8SArun Ramadoss 	if (val == bitval[P_GMII_1GBIT])
141746f80fa8SArun Ramadoss 		gbit = true;
141846f80fa8SArun Ramadoss 
141946f80fa8SArun Ramadoss 	return gbit;
142046f80fa8SArun Ramadoss }
142146f80fa8SArun Ramadoss 
142246f80fa8SArun Ramadoss void ksz_set_gbit(struct ksz_device *dev, int port, bool gbit)
142346f80fa8SArun Ramadoss {
142446f80fa8SArun Ramadoss 	const u8 *bitval = dev->info->xmii_ctrl1;
142546f80fa8SArun Ramadoss 	const u16 *regs = dev->info->regs;
142646f80fa8SArun Ramadoss 	u8 data8;
142746f80fa8SArun Ramadoss 
142846f80fa8SArun Ramadoss 	ksz_pread8(dev, port, regs[P_XMII_CTRL_1], &data8);
142946f80fa8SArun Ramadoss 
143046f80fa8SArun Ramadoss 	data8 &= ~P_GMII_1GBIT_M;
143146f80fa8SArun Ramadoss 
143246f80fa8SArun Ramadoss 	if (gbit)
143346f80fa8SArun Ramadoss 		data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_1GBIT]);
143446f80fa8SArun Ramadoss 	else
143546f80fa8SArun Ramadoss 		data8 |= FIELD_PREP(P_GMII_1GBIT_M, bitval[P_GMII_NOT_1GBIT]);
143646f80fa8SArun Ramadoss 
143746f80fa8SArun Ramadoss 	/* Write the updated value */
143846f80fa8SArun Ramadoss 	ksz_pwrite8(dev, port, regs[P_XMII_CTRL_1], data8);
143946f80fa8SArun Ramadoss }
144046f80fa8SArun Ramadoss 
1441*aa5b8b73SArun Ramadoss static void ksz_set_100_10mbit(struct ksz_device *dev, int port, int speed)
1442*aa5b8b73SArun Ramadoss {
1443*aa5b8b73SArun Ramadoss 	const u8 *bitval = dev->info->xmii_ctrl0;
1444*aa5b8b73SArun Ramadoss 	const u16 *regs = dev->info->regs;
1445*aa5b8b73SArun Ramadoss 	u8 data8;
1446*aa5b8b73SArun Ramadoss 
1447*aa5b8b73SArun Ramadoss 	ksz_pread8(dev, port, regs[P_XMII_CTRL_0], &data8);
1448*aa5b8b73SArun Ramadoss 
1449*aa5b8b73SArun Ramadoss 	data8 &= ~P_MII_100MBIT_M;
1450*aa5b8b73SArun Ramadoss 
1451*aa5b8b73SArun Ramadoss 	if (speed == SPEED_100)
1452*aa5b8b73SArun Ramadoss 		data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_100MBIT]);
1453*aa5b8b73SArun Ramadoss 	else
1454*aa5b8b73SArun Ramadoss 		data8 |= FIELD_PREP(P_MII_100MBIT_M, bitval[P_MII_10MBIT]);
1455*aa5b8b73SArun Ramadoss 
1456*aa5b8b73SArun Ramadoss 	/* Write the updated value */
1457*aa5b8b73SArun Ramadoss 	ksz_pwrite8(dev, port, regs[P_XMII_CTRL_0], data8);
1458*aa5b8b73SArun Ramadoss }
1459*aa5b8b73SArun Ramadoss 
1460*aa5b8b73SArun Ramadoss void ksz_port_set_xmii_speed(struct ksz_device *dev, int port, int speed)
1461*aa5b8b73SArun Ramadoss {
1462*aa5b8b73SArun Ramadoss 	if (speed == SPEED_1000)
1463*aa5b8b73SArun Ramadoss 		ksz_set_gbit(dev, port, true);
1464*aa5b8b73SArun Ramadoss 	else
1465*aa5b8b73SArun Ramadoss 		ksz_set_gbit(dev, port, false);
1466*aa5b8b73SArun Ramadoss 
1467*aa5b8b73SArun Ramadoss 	if (speed == SPEED_100 || speed == SPEED_10)
1468*aa5b8b73SArun Ramadoss 		ksz_set_100_10mbit(dev, port, speed);
1469*aa5b8b73SArun Ramadoss }
1470*aa5b8b73SArun Ramadoss 
1471f597d3adSArun Ramadoss static void ksz_phylink_mac_link_up(struct dsa_switch *ds, int port,
1472f597d3adSArun Ramadoss 				    unsigned int mode,
1473f597d3adSArun Ramadoss 				    phy_interface_t interface,
1474f597d3adSArun Ramadoss 				    struct phy_device *phydev, int speed,
1475f597d3adSArun Ramadoss 				    int duplex, bool tx_pause, bool rx_pause)
1476f597d3adSArun Ramadoss {
1477f597d3adSArun Ramadoss 	struct ksz_device *dev = ds->priv;
1478f597d3adSArun Ramadoss 
1479f597d3adSArun Ramadoss 	if (dev->dev_ops->phylink_mac_link_up)
1480f597d3adSArun Ramadoss 		dev->dev_ops->phylink_mac_link_up(dev, port, mode, interface,
1481f597d3adSArun Ramadoss 						  phydev, speed, duplex,
1482f597d3adSArun Ramadoss 						  tx_pause, rx_pause);
1483f597d3adSArun Ramadoss }
1484f597d3adSArun Ramadoss 
148591a98917SArun Ramadoss static int ksz_switch_detect(struct ksz_device *dev)
148691a98917SArun Ramadoss {
148791a98917SArun Ramadoss 	u8 id1, id2;
148891a98917SArun Ramadoss 	u16 id16;
148991a98917SArun Ramadoss 	u32 id32;
149091a98917SArun Ramadoss 	int ret;
149191a98917SArun Ramadoss 
149291a98917SArun Ramadoss 	/* read chip id */
149391a98917SArun Ramadoss 	ret = ksz_read16(dev, REG_CHIP_ID0, &id16);
149491a98917SArun Ramadoss 	if (ret)
149591a98917SArun Ramadoss 		return ret;
149691a98917SArun Ramadoss 
149791a98917SArun Ramadoss 	id1 = FIELD_GET(SW_FAMILY_ID_M, id16);
149891a98917SArun Ramadoss 	id2 = FIELD_GET(SW_CHIP_ID_M, id16);
149991a98917SArun Ramadoss 
150091a98917SArun Ramadoss 	switch (id1) {
150191a98917SArun Ramadoss 	case KSZ87_FAMILY_ID:
150291a98917SArun Ramadoss 		if (id2 == KSZ87_CHIP_ID_95) {
150391a98917SArun Ramadoss 			u8 val;
150491a98917SArun Ramadoss 
150591a98917SArun Ramadoss 			dev->chip_id = KSZ8795_CHIP_ID;
150691a98917SArun Ramadoss 
150791a98917SArun Ramadoss 			ksz_read8(dev, KSZ8_PORT_STATUS_0, &val);
150891a98917SArun Ramadoss 			if (val & KSZ8_PORT_FIBER_MODE)
150991a98917SArun Ramadoss 				dev->chip_id = KSZ8765_CHIP_ID;
151091a98917SArun Ramadoss 		} else if (id2 == KSZ87_CHIP_ID_94) {
151191a98917SArun Ramadoss 			dev->chip_id = KSZ8794_CHIP_ID;
151291a98917SArun Ramadoss 		} else {
151391a98917SArun Ramadoss 			return -ENODEV;
151491a98917SArun Ramadoss 		}
151591a98917SArun Ramadoss 		break;
151691a98917SArun Ramadoss 	case KSZ88_FAMILY_ID:
151791a98917SArun Ramadoss 		if (id2 == KSZ88_CHIP_ID_63)
151891a98917SArun Ramadoss 			dev->chip_id = KSZ8830_CHIP_ID;
151991a98917SArun Ramadoss 		else
152091a98917SArun Ramadoss 			return -ENODEV;
152191a98917SArun Ramadoss 		break;
152291a98917SArun Ramadoss 	default:
152391a98917SArun Ramadoss 		ret = ksz_read32(dev, REG_CHIP_ID0, &id32);
152491a98917SArun Ramadoss 		if (ret)
152591a98917SArun Ramadoss 			return ret;
152691a98917SArun Ramadoss 
152791a98917SArun Ramadoss 		dev->chip_rev = FIELD_GET(SW_REV_ID_M, id32);
152891a98917SArun Ramadoss 		id32 &= ~0xFF;
152991a98917SArun Ramadoss 
153091a98917SArun Ramadoss 		switch (id32) {
153191a98917SArun Ramadoss 		case KSZ9477_CHIP_ID:
153291a98917SArun Ramadoss 		case KSZ9897_CHIP_ID:
153391a98917SArun Ramadoss 		case KSZ9893_CHIP_ID:
153491a98917SArun Ramadoss 		case KSZ9567_CHIP_ID:
153591a98917SArun Ramadoss 		case LAN9370_CHIP_ID:
153691a98917SArun Ramadoss 		case LAN9371_CHIP_ID:
153791a98917SArun Ramadoss 		case LAN9372_CHIP_ID:
153891a98917SArun Ramadoss 		case LAN9373_CHIP_ID:
153991a98917SArun Ramadoss 		case LAN9374_CHIP_ID:
154091a98917SArun Ramadoss 			dev->chip_id = id32;
154191a98917SArun Ramadoss 			break;
154291a98917SArun Ramadoss 		default:
154391a98917SArun Ramadoss 			dev_err(dev->dev,
154491a98917SArun Ramadoss 				"unsupported switch detected %x)\n", id32);
154591a98917SArun Ramadoss 			return -ENODEV;
154691a98917SArun Ramadoss 		}
154791a98917SArun Ramadoss 	}
154891a98917SArun Ramadoss 	return 0;
154991a98917SArun Ramadoss }
155091a98917SArun Ramadoss 
15511958eee8SArun Ramadoss static const struct dsa_switch_ops ksz_switch_ops = {
15521958eee8SArun Ramadoss 	.get_tag_protocol	= ksz_get_tag_protocol,
15531958eee8SArun Ramadoss 	.get_phy_flags		= ksz_get_phy_flags,
15541958eee8SArun Ramadoss 	.setup			= ksz_setup,
15551958eee8SArun Ramadoss 	.phy_read		= ksz_phy_read16,
15561958eee8SArun Ramadoss 	.phy_write		= ksz_phy_write16,
15571958eee8SArun Ramadoss 	.phylink_get_caps	= ksz_phylink_get_caps,
1558a0cb1aa4SArun Ramadoss 	.phylink_mac_config	= ksz_phylink_mac_config,
1559f597d3adSArun Ramadoss 	.phylink_mac_link_up	= ksz_phylink_mac_link_up,
15601958eee8SArun Ramadoss 	.phylink_mac_link_down	= ksz_mac_link_down,
15611958eee8SArun Ramadoss 	.port_enable		= ksz_enable_port,
15621958eee8SArun Ramadoss 	.get_strings		= ksz_get_strings,
15631958eee8SArun Ramadoss 	.get_ethtool_stats	= ksz_get_ethtool_stats,
15641958eee8SArun Ramadoss 	.get_sset_count		= ksz_sset_count,
15651958eee8SArun Ramadoss 	.port_bridge_join	= ksz_port_bridge_join,
15661958eee8SArun Ramadoss 	.port_bridge_leave	= ksz_port_bridge_leave,
15671958eee8SArun Ramadoss 	.port_stp_state_set	= ksz_port_stp_state_set,
15681958eee8SArun Ramadoss 	.port_fast_age		= ksz_port_fast_age,
15691958eee8SArun Ramadoss 	.port_vlan_filtering	= ksz_port_vlan_filtering,
15701958eee8SArun Ramadoss 	.port_vlan_add		= ksz_port_vlan_add,
15711958eee8SArun Ramadoss 	.port_vlan_del		= ksz_port_vlan_del,
15721958eee8SArun Ramadoss 	.port_fdb_dump		= ksz_port_fdb_dump,
15731958eee8SArun Ramadoss 	.port_fdb_add		= ksz_port_fdb_add,
15741958eee8SArun Ramadoss 	.port_fdb_del		= ksz_port_fdb_del,
15751958eee8SArun Ramadoss 	.port_mdb_add           = ksz_port_mdb_add,
15761958eee8SArun Ramadoss 	.port_mdb_del           = ksz_port_mdb_del,
15771958eee8SArun Ramadoss 	.port_mirror_add	= ksz_port_mirror_add,
15781958eee8SArun Ramadoss 	.port_mirror_del	= ksz_port_mirror_del,
15791958eee8SArun Ramadoss 	.get_stats64		= ksz_get_stats64,
1580c4748ff6SOleksij Rempel 	.get_pause_stats	= ksz_get_pause_stats,
15811958eee8SArun Ramadoss 	.port_change_mtu	= ksz_change_mtu,
15821958eee8SArun Ramadoss 	.port_max_mtu		= ksz_max_mtu,
15831958eee8SArun Ramadoss };
15841958eee8SArun Ramadoss 
1585ee394feaSMarek Vasut struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)
1586b987e98eSWoojung Huh {
1587b987e98eSWoojung Huh 	struct dsa_switch *ds;
1588b987e98eSWoojung Huh 	struct ksz_device *swdev;
1589b987e98eSWoojung Huh 
15907e99e347SVivien Didelot 	ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL);
1591b987e98eSWoojung Huh 	if (!ds)
1592b987e98eSWoojung Huh 		return NULL;
1593b987e98eSWoojung Huh 
15947e99e347SVivien Didelot 	ds->dev = base;
15957e99e347SVivien Didelot 	ds->num_ports = DSA_MAX_PORTS;
15961958eee8SArun Ramadoss 	ds->ops = &ksz_switch_ops;
15977e99e347SVivien Didelot 
1598b987e98eSWoojung Huh 	swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL);
1599b987e98eSWoojung Huh 	if (!swdev)
1600b987e98eSWoojung Huh 		return NULL;
1601b987e98eSWoojung Huh 
1602b987e98eSWoojung Huh 	ds->priv = swdev;
1603b987e98eSWoojung Huh 	swdev->dev = base;
1604b987e98eSWoojung Huh 
1605b987e98eSWoojung Huh 	swdev->ds = ds;
1606b987e98eSWoojung Huh 	swdev->priv = priv;
1607b987e98eSWoojung Huh 
1608b987e98eSWoojung Huh 	return swdev;
1609b987e98eSWoojung Huh }
1610b987e98eSWoojung Huh EXPORT_SYMBOL(ksz_switch_alloc);
1611b987e98eSWoojung Huh 
16126ec23aaaSArun Ramadoss int ksz_switch_register(struct ksz_device *dev)
1613b987e98eSWoojung Huh {
1614462d5250SArun Ramadoss 	const struct ksz_chip_data *info;
1615912aae27SHelmut Grohne 	struct device_node *port, *ports;
16160c65b2b9SAndrew Lunn 	phy_interface_t interface;
1617edecfa98SHelmut Grohne 	unsigned int port_num;
1618b987e98eSWoojung Huh 	int ret;
1619198b3478SArun Ramadoss 	int i;
1620b987e98eSWoojung Huh 
1621b987e98eSWoojung Huh 	if (dev->pdata)
1622b987e98eSWoojung Huh 		dev->chip_id = dev->pdata->chip_id;
1623b987e98eSWoojung Huh 
1624924352c3SMarek Vasut 	dev->reset_gpio = devm_gpiod_get_optional(dev->dev, "reset",
1625924352c3SMarek Vasut 						  GPIOD_OUT_LOW);
1626924352c3SMarek Vasut 	if (IS_ERR(dev->reset_gpio))
1627924352c3SMarek Vasut 		return PTR_ERR(dev->reset_gpio);
1628924352c3SMarek Vasut 
1629924352c3SMarek Vasut 	if (dev->reset_gpio) {
163022e72b5eSMarek Vasut 		gpiod_set_value_cansleep(dev->reset_gpio, 1);
16315b797980SPaul Barker 		usleep_range(10000, 12000);
163222e72b5eSMarek Vasut 		gpiod_set_value_cansleep(dev->reset_gpio, 0);
16331c45ba93SMarek Vasut 		msleep(100);
1634924352c3SMarek Vasut 	}
1635924352c3SMarek Vasut 
16367049f9b5STristram Ha 	mutex_init(&dev->dev_mutex);
1637013572a2SMarek Vasut 	mutex_init(&dev->regmap_mutex);
1638284fb78eSTristram Ha 	mutex_init(&dev->alu_mutex);
1639284fb78eSTristram Ha 	mutex_init(&dev->vlan_mutex);
1640284fb78eSTristram Ha 
164191a98917SArun Ramadoss 	ret = ksz_switch_detect(dev);
164291a98917SArun Ramadoss 	if (ret)
164391a98917SArun Ramadoss 		return ret;
1644b987e98eSWoojung Huh 
1645462d5250SArun Ramadoss 	info = ksz_lookup_info(dev->chip_id);
1646462d5250SArun Ramadoss 	if (!info)
1647462d5250SArun Ramadoss 		return -ENODEV;
1648462d5250SArun Ramadoss 
1649462d5250SArun Ramadoss 	/* Update the compatible info with the probed one */
1650462d5250SArun Ramadoss 	dev->info = info;
1651462d5250SArun Ramadoss 
165291a98917SArun Ramadoss 	dev_info(dev->dev, "found switch: %s, rev %i\n",
165391a98917SArun Ramadoss 		 dev->info->dev_name, dev->chip_rev);
165491a98917SArun Ramadoss 
1655eee16b14SArun Ramadoss 	ret = ksz_check_device_id(dev);
1656eee16b14SArun Ramadoss 	if (ret)
1657eee16b14SArun Ramadoss 		return ret;
1658eee16b14SArun Ramadoss 
16596ec23aaaSArun Ramadoss 	dev->dev_ops = dev->info->ops;
166091a98917SArun Ramadoss 
1661c2e86691STristram Ha 	ret = dev->dev_ops->init(dev);
1662b987e98eSWoojung Huh 	if (ret)
1663b987e98eSWoojung Huh 		return ret;
1664b987e98eSWoojung Huh 
1665198b3478SArun Ramadoss 	dev->ports = devm_kzalloc(dev->dev,
1666198b3478SArun Ramadoss 				  dev->info->port_cnt * sizeof(struct ksz_port),
1667198b3478SArun Ramadoss 				  GFP_KERNEL);
1668198b3478SArun Ramadoss 	if (!dev->ports)
1669198b3478SArun Ramadoss 		return -ENOMEM;
1670198b3478SArun Ramadoss 
1671198b3478SArun Ramadoss 	for (i = 0; i < dev->info->port_cnt; i++) {
1672198b3478SArun Ramadoss 		spin_lock_init(&dev->ports[i].mib.stats64_lock);
1673198b3478SArun Ramadoss 		mutex_init(&dev->ports[i].mib.cnt_mutex);
1674198b3478SArun Ramadoss 		dev->ports[i].mib.counters =
1675198b3478SArun Ramadoss 			devm_kzalloc(dev->dev,
1676198b3478SArun Ramadoss 				     sizeof(u64) * (dev->info->mib_cnt + 1),
1677198b3478SArun Ramadoss 				     GFP_KERNEL);
1678198b3478SArun Ramadoss 		if (!dev->ports[i].mib.counters)
1679198b3478SArun Ramadoss 			return -ENOMEM;
1680198b3478SArun Ramadoss 	}
1681198b3478SArun Ramadoss 
1682198b3478SArun Ramadoss 	/* set the real number of ports */
1683198b3478SArun Ramadoss 	dev->ds->num_ports = dev->info->port_cnt;
1684198b3478SArun Ramadoss 
16858c29bebbSTristram Ha 	/* Host port interface will be self detected, or specifically set in
16868c29bebbSTristram Ha 	 * device tree.
16878c29bebbSTristram Ha 	 */
1688462d5250SArun Ramadoss 	for (port_num = 0; port_num < dev->info->port_cnt; ++port_num)
1689edecfa98SHelmut Grohne 		dev->ports[port_num].interface = PHY_INTERFACE_MODE_NA;
1690c2e86691STristram Ha 	if (dev->dev->of_node) {
16910c65b2b9SAndrew Lunn 		ret = of_get_phy_mode(dev->dev->of_node, &interface);
16920c65b2b9SAndrew Lunn 		if (ret == 0)
1693edecfa98SHelmut Grohne 			dev->compat_interface = interface;
169444e53c88SChristian Eggers 		ports = of_get_child_by_name(dev->dev->of_node, "ethernet-ports");
169544e53c88SChristian Eggers 		if (!ports)
1696912aae27SHelmut Grohne 			ports = of_get_child_by_name(dev->dev->of_node, "ports");
1697a14bd747SLiang He 		if (ports) {
1698912aae27SHelmut Grohne 			for_each_available_child_of_node(ports, port) {
1699912aae27SHelmut Grohne 				if (of_property_read_u32(port, "reg",
1700912aae27SHelmut Grohne 							 &port_num))
1701edecfa98SHelmut Grohne 					continue;
170284f7e0bbSkernel test robot 				if (!(dev->port_mask & BIT(port_num))) {
170384f7e0bbSkernel test robot 					of_node_put(port);
1704a14bd747SLiang He 					of_node_put(ports);
1705edecfa98SHelmut Grohne 					return -EINVAL;
170684f7e0bbSkernel test robot 				}
1707912aae27SHelmut Grohne 				of_get_phy_mode(port,
1708912aae27SHelmut Grohne 						&dev->ports[port_num].interface);
1709edecfa98SHelmut Grohne 			}
1710a14bd747SLiang He 			of_node_put(ports);
1711a14bd747SLiang He 		}
171279c8bd15SRobert Hancock 		dev->synclko_125 = of_property_read_bool(dev->dev->of_node,
171379c8bd15SRobert Hancock 							 "microchip,synclko-125");
171448bf8b8aSRobert Hancock 		dev->synclko_disable = of_property_read_bool(dev->dev->of_node,
171548bf8b8aSRobert Hancock 							     "microchip,synclko-disable");
171648bf8b8aSRobert Hancock 		if (dev->synclko_125 && dev->synclko_disable) {
171748bf8b8aSRobert Hancock 			dev_err(dev->dev, "inconsistent synclko settings\n");
171848bf8b8aSRobert Hancock 			return -EINVAL;
171948bf8b8aSRobert Hancock 		}
1720c2e86691STristram Ha 	}
1721c2e86691STristram Ha 
1722c2e86691STristram Ha 	ret = dsa_register_switch(dev->ds);
1723c2e86691STristram Ha 	if (ret) {
1724c2e86691STristram Ha 		dev->dev_ops->exit(dev);
1725c2e86691STristram Ha 		return ret;
1726c2e86691STristram Ha 	}
1727c2e86691STristram Ha 
17288098bd69SChristian Eggers 	/* Read MIB counters every 30 seconds to avoid overflow. */
172912c740c8SOleksij Rempel 	dev->mib_read_interval = msecs_to_jiffies(5000);
17308098bd69SChristian Eggers 
17318098bd69SChristian Eggers 	/* Start the MIB timer. */
17328098bd69SChristian Eggers 	schedule_delayed_work(&dev->mib_read, 0);
17338098bd69SChristian Eggers 
17347a8988a1SArun Ramadoss 	return ret;
1735b987e98eSWoojung Huh }
1736b987e98eSWoojung Huh EXPORT_SYMBOL(ksz_switch_register);
1737b987e98eSWoojung Huh 
1738b987e98eSWoojung Huh void ksz_switch_remove(struct ksz_device *dev)
1739b987e98eSWoojung Huh {
17407c6ff470STristram Ha 	/* timer started */
1741ef1100efSArun Ramadoss 	if (dev->mib_read_interval) {
1742ef1100efSArun Ramadoss 		dev->mib_read_interval = 0;
1743469b390eSGeorge McCollister 		cancel_delayed_work_sync(&dev->mib_read);
1744ef1100efSArun Ramadoss 	}
17457c6ff470STristram Ha 
1746c2e86691STristram Ha 	dev->dev_ops->exit(dev);
1747b987e98eSWoojung Huh 	dsa_unregister_switch(dev->ds);
1748924352c3SMarek Vasut 
1749924352c3SMarek Vasut 	if (dev->reset_gpio)
175022e72b5eSMarek Vasut 		gpiod_set_value_cansleep(dev->reset_gpio, 1);
1751924352c3SMarek Vasut 
1752b987e98eSWoojung Huh }
1753b987e98eSWoojung Huh EXPORT_SYMBOL(ksz_switch_remove);
1754b987e98eSWoojung Huh 
1755b987e98eSWoojung Huh MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
1756b987e98eSWoojung Huh MODULE_DESCRIPTION("Microchip KSZ Series Switch DSA Driver");
1757b987e98eSWoojung Huh MODULE_LICENSE("GPL");
1758