xref: /openbmc/linux/drivers/net/dsa/microchip/ksz9477.c (revision 9144f784f852f9a125cabe9927b986d909bfa439)
1c2e86691STristram Ha // SPDX-License-Identifier: GPL-2.0
2c2e86691STristram Ha /*
3c2e86691STristram Ha  * Microchip KSZ9477 switch driver main logic
4c2e86691STristram Ha  *
5*7583dd59STristram Ha  * Copyright (C) 2017-2024 Microchip Technology Inc.
6c2e86691STristram Ha  */
7c2e86691STristram Ha 
8c2e86691STristram Ha #include <linux/kernel.h>
9c2e86691STristram Ha #include <linux/module.h>
107c6ff470STristram Ha #include <linux/iopoll.h>
11c2e86691STristram Ha #include <linux/platform_data/microchip-ksz.h>
12c2e86691STristram Ha #include <linux/phy.h>
13c2e86691STristram Ha #include <linux/if_bridge.h>
14e18058eaSOleksij Rempel #include <linux/if_vlan.h>
15c2e86691STristram Ha #include <net/dsa.h>
16c2e86691STristram Ha #include <net/switchdev.h>
17c2e86691STristram Ha 
1884bd1908STristram Ha #include "ksz9477_reg.h"
197c6ff470STristram Ha #include "ksz_common.h"
206ec23aaaSArun Ramadoss #include "ksz9477.h"
21c2e86691STristram Ha 
ksz_cfg(struct ksz_device * dev,u32 addr,u8 bits,bool set)22bafea01fSMarek Vasut static void ksz_cfg(struct ksz_device *dev, u32 addr, u8 bits, bool set)
23bafea01fSMarek Vasut {
24b8311f46SVladimir Oltean 	regmap_update_bits(ksz_regmap_8(dev), addr, bits, set ? bits : 0);
25bafea01fSMarek Vasut }
26bafea01fSMarek Vasut 
ksz_port_cfg(struct ksz_device * dev,int port,int offset,u8 bits,bool set)27bafea01fSMarek Vasut static void ksz_port_cfg(struct ksz_device *dev, int port, int offset, u8 bits,
28bafea01fSMarek Vasut 			 bool set)
29bafea01fSMarek Vasut {
30b8311f46SVladimir Oltean 	regmap_update_bits(ksz_regmap_8(dev), PORT_CTRL_ADDR(port, offset),
31d4bcd99cSMarek Vasut 			   bits, set ? bits : 0);
32bafea01fSMarek Vasut }
33bafea01fSMarek Vasut 
ksz9477_cfg32(struct ksz_device * dev,u32 addr,u32 bits,bool set)34c2e86691STristram Ha static void ksz9477_cfg32(struct ksz_device *dev, u32 addr, u32 bits, bool set)
35c2e86691STristram Ha {
36b8311f46SVladimir Oltean 	regmap_update_bits(ksz_regmap_32(dev), addr, bits, set ? bits : 0);
37c2e86691STristram Ha }
38c2e86691STristram Ha 
ksz9477_port_cfg32(struct ksz_device * dev,int port,int offset,u32 bits,bool set)39c2e86691STristram Ha static void ksz9477_port_cfg32(struct ksz_device *dev, int port, int offset,
40c2e86691STristram Ha 			       u32 bits, bool set)
41c2e86691STristram Ha {
42b8311f46SVladimir Oltean 	regmap_update_bits(ksz_regmap_32(dev), PORT_CTRL_ADDR(port, offset),
43d4bcd99cSMarek Vasut 			   bits, set ? bits : 0);
44c2e86691STristram Ha }
45c2e86691STristram Ha 
ksz9477_change_mtu(struct ksz_device * dev,int port,int mtu)466ec23aaaSArun Ramadoss int ksz9477_change_mtu(struct ksz_device *dev, int port, int mtu)
47e18058eaSOleksij Rempel {
481d0a1a6dSOleksij Rempel 	u16 frame_size;
491d0a1a6dSOleksij Rempel 
501d0a1a6dSOleksij Rempel 	if (!dsa_is_cpu_port(dev->ds, port))
511d0a1a6dSOleksij Rempel 		return 0;
52e18058eaSOleksij Rempel 
53e18058eaSOleksij Rempel 	frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
54e18058eaSOleksij Rempel 
55b8311f46SVladimir Oltean 	return regmap_update_bits(ksz_regmap_16(dev), REG_SW_MTU__2,
561d0a1a6dSOleksij Rempel 				  REG_SW_MTU_MASK, frame_size);
57e18058eaSOleksij Rempel }
58e18058eaSOleksij Rempel 
ksz9477_wait_vlan_ctrl_ready(struct ksz_device * dev)590f9c36e3SMarek Vasut static int ksz9477_wait_vlan_ctrl_ready(struct ksz_device *dev)
60c2e86691STristram Ha {
610f9c36e3SMarek Vasut 	unsigned int val;
62c2e86691STristram Ha 
63b8311f46SVladimir Oltean 	return regmap_read_poll_timeout(ksz_regmap_8(dev), REG_SW_VLAN_CTRL,
640f9c36e3SMarek Vasut 					val, !(val & VLAN_START), 10, 1000);
65c2e86691STristram Ha }
66c2e86691STristram Ha 
ksz9477_get_vlan_table(struct ksz_device * dev,u16 vid,u32 * vlan_table)67c2e86691STristram Ha static int ksz9477_get_vlan_table(struct ksz_device *dev, u16 vid,
68c2e86691STristram Ha 				  u32 *vlan_table)
69c2e86691STristram Ha {
70c2e86691STristram Ha 	int ret;
71c2e86691STristram Ha 
72c2e86691STristram Ha 	mutex_lock(&dev->vlan_mutex);
73c2e86691STristram Ha 
74c2e86691STristram Ha 	ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M);
75c2e86691STristram Ha 	ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_READ | VLAN_START);
76c2e86691STristram Ha 
77c2e86691STristram Ha 	/* wait to be cleared */
780f9c36e3SMarek Vasut 	ret = ksz9477_wait_vlan_ctrl_ready(dev);
790f9c36e3SMarek Vasut 	if (ret) {
80c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to read vlan table\n");
81c2e86691STristram Ha 		goto exit;
82c2e86691STristram Ha 	}
83c2e86691STristram Ha 
84c2e86691STristram Ha 	ksz_read32(dev, REG_SW_VLAN_ENTRY__4, &vlan_table[0]);
85c2e86691STristram Ha 	ksz_read32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, &vlan_table[1]);
86c2e86691STristram Ha 	ksz_read32(dev, REG_SW_VLAN_ENTRY_PORTS__4, &vlan_table[2]);
87c2e86691STristram Ha 
88c2e86691STristram Ha 	ksz_write8(dev, REG_SW_VLAN_CTRL, 0);
89c2e86691STristram Ha 
90c2e86691STristram Ha exit:
91c2e86691STristram Ha 	mutex_unlock(&dev->vlan_mutex);
92c2e86691STristram Ha 
93c2e86691STristram Ha 	return ret;
94c2e86691STristram Ha }
95c2e86691STristram Ha 
ksz9477_set_vlan_table(struct ksz_device * dev,u16 vid,u32 * vlan_table)96c2e86691STristram Ha static int ksz9477_set_vlan_table(struct ksz_device *dev, u16 vid,
97c2e86691STristram Ha 				  u32 *vlan_table)
98c2e86691STristram Ha {
99c2e86691STristram Ha 	int ret;
100c2e86691STristram Ha 
101c2e86691STristram Ha 	mutex_lock(&dev->vlan_mutex);
102c2e86691STristram Ha 
103c2e86691STristram Ha 	ksz_write32(dev, REG_SW_VLAN_ENTRY__4, vlan_table[0]);
104c2e86691STristram Ha 	ksz_write32(dev, REG_SW_VLAN_ENTRY_UNTAG__4, vlan_table[1]);
105c2e86691STristram Ha 	ksz_write32(dev, REG_SW_VLAN_ENTRY_PORTS__4, vlan_table[2]);
106c2e86691STristram Ha 
107c2e86691STristram Ha 	ksz_write16(dev, REG_SW_VLAN_ENTRY_INDEX__2, vid & VLAN_INDEX_M);
108c2e86691STristram Ha 	ksz_write8(dev, REG_SW_VLAN_CTRL, VLAN_START | VLAN_WRITE);
109c2e86691STristram Ha 
110c2e86691STristram Ha 	/* wait to be cleared */
1110f9c36e3SMarek Vasut 	ret = ksz9477_wait_vlan_ctrl_ready(dev);
1120f9c36e3SMarek Vasut 	if (ret) {
113c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to write vlan table\n");
114c2e86691STristram Ha 		goto exit;
115c2e86691STristram Ha 	}
116c2e86691STristram Ha 
117c2e86691STristram Ha 	ksz_write8(dev, REG_SW_VLAN_CTRL, 0);
118c2e86691STristram Ha 
119c2e86691STristram Ha 	/* update vlan cache table */
120c2e86691STristram Ha 	dev->vlan_cache[vid].table[0] = vlan_table[0];
121c2e86691STristram Ha 	dev->vlan_cache[vid].table[1] = vlan_table[1];
122c2e86691STristram Ha 	dev->vlan_cache[vid].table[2] = vlan_table[2];
123c2e86691STristram Ha 
124c2e86691STristram Ha exit:
125c2e86691STristram Ha 	mutex_unlock(&dev->vlan_mutex);
126c2e86691STristram Ha 
127c2e86691STristram Ha 	return ret;
128c2e86691STristram Ha }
129c2e86691STristram Ha 
ksz9477_read_table(struct ksz_device * dev,u32 * table)130c2e86691STristram Ha static void ksz9477_read_table(struct ksz_device *dev, u32 *table)
131c2e86691STristram Ha {
132c2e86691STristram Ha 	ksz_read32(dev, REG_SW_ALU_VAL_A, &table[0]);
133c2e86691STristram Ha 	ksz_read32(dev, REG_SW_ALU_VAL_B, &table[1]);
134c2e86691STristram Ha 	ksz_read32(dev, REG_SW_ALU_VAL_C, &table[2]);
135c2e86691STristram Ha 	ksz_read32(dev, REG_SW_ALU_VAL_D, &table[3]);
136c2e86691STristram Ha }
137c2e86691STristram Ha 
ksz9477_write_table(struct ksz_device * dev,u32 * table)138c2e86691STristram Ha static void ksz9477_write_table(struct ksz_device *dev, u32 *table)
139c2e86691STristram Ha {
140c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_VAL_A, table[0]);
141c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_VAL_B, table[1]);
142c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_VAL_C, table[2]);
143c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_VAL_D, table[3]);
144c2e86691STristram Ha }
145c2e86691STristram Ha 
ksz9477_wait_alu_ready(struct ksz_device * dev)146ef534195SMarek Vasut static int ksz9477_wait_alu_ready(struct ksz_device *dev)
147c2e86691STristram Ha {
148ef534195SMarek Vasut 	unsigned int val;
149c2e86691STristram Ha 
150b8311f46SVladimir Oltean 	return regmap_read_poll_timeout(ksz_regmap_32(dev), REG_SW_ALU_CTRL__4,
151ef534195SMarek Vasut 					val, !(val & ALU_START), 10, 1000);
152c2e86691STristram Ha }
153c2e86691STristram Ha 
ksz9477_wait_alu_sta_ready(struct ksz_device * dev)1543371efbcSMarek Vasut static int ksz9477_wait_alu_sta_ready(struct ksz_device *dev)
155c2e86691STristram Ha {
1563371efbcSMarek Vasut 	unsigned int val;
157c2e86691STristram Ha 
158b8311f46SVladimir Oltean 	return regmap_read_poll_timeout(ksz_regmap_32(dev),
1593371efbcSMarek Vasut 					REG_SW_ALU_STAT_CTRL__4,
1603371efbcSMarek Vasut 					val, !(val & ALU_STAT_START),
1613371efbcSMarek Vasut 					10, 1000);
162c2e86691STristram Ha }
163c2e86691STristram Ha 
ksz9477_reset_switch(struct ksz_device * dev)1646ec23aaaSArun Ramadoss int ksz9477_reset_switch(struct ksz_device *dev)
165c2e86691STristram Ha {
166c2e86691STristram Ha 	u8 data8;
167c2e86691STristram Ha 	u32 data32;
168c2e86691STristram Ha 
169c2e86691STristram Ha 	/* reset switch */
170c2e86691STristram Ha 	ksz_cfg(dev, REG_SW_OPERATION, SW_RESET, true);
171c2e86691STristram Ha 
172c2e86691STristram Ha 	/* turn off SPI DO Edge select */
173b8311f46SVladimir Oltean 	regmap_update_bits(ksz_regmap_8(dev), REG_SW_GLOBAL_SERIAL_CTRL_0,
174ee353e45SMarek Vasut 			   SPI_AUTO_EDGE_DETECTION, 0);
175c2e86691STristram Ha 
176c2e86691STristram Ha 	/* default configuration */
1772ef957deSTristram Ha 	ksz_write8(dev, REG_SW_LUE_CTRL_1,
1782ef957deSTristram Ha 		   SW_AGING_ENABLE | SW_LINK_AUTO_AGING | SW_SRC_ADDR_FILTER);
179c2e86691STristram Ha 
180c2e86691STristram Ha 	/* disable interrupts */
181c2e86691STristram Ha 	ksz_write32(dev, REG_SW_INT_MASK__4, SWITCH_INT_MASK);
182c2e86691STristram Ha 	ksz_write32(dev, REG_SW_PORT_INT_MASK__4, 0x7F);
183c2e86691STristram Ha 	ksz_read32(dev, REG_SW_PORT_INT_STATUS__4, &data32);
184c2e86691STristram Ha 
185b5708dc6SOleksij Rempel 	/* KSZ9893 compatible chips do not support refclk configuration */
186b5708dc6SOleksij Rempel 	if (dev->chip_id == KSZ9893_CHIP_ID ||
187ef912fe4SRakesh Sankaranarayanan 	    dev->chip_id == KSZ8563_CHIP_ID ||
188ef912fe4SRakesh Sankaranarayanan 	    dev->chip_id == KSZ9563_CHIP_ID)
189b5708dc6SOleksij Rempel 		return 0;
190b5708dc6SOleksij Rempel 
19148bf8b8aSRobert Hancock 	data8 = SW_ENABLE_REFCLKO;
19248bf8b8aSRobert Hancock 	if (dev->synclko_disable)
19348bf8b8aSRobert Hancock 		data8 = 0;
19448bf8b8aSRobert Hancock 	else if (dev->synclko_125)
19548bf8b8aSRobert Hancock 		data8 = SW_ENABLE_REFCLKO | SW_REFCLKO_IS_125MHZ;
19648bf8b8aSRobert Hancock 	ksz_write8(dev, REG_SW_GLOBAL_OUTPUT_CTRL__1, data8);
19779c8bd15SRobert Hancock 
198c2e86691STristram Ha 	return 0;
199c2e86691STristram Ha }
200c2e86691STristram Ha 
ksz9477_r_mib_cnt(struct ksz_device * dev,int port,u16 addr,u64 * cnt)2016ec23aaaSArun Ramadoss void ksz9477_r_mib_cnt(struct ksz_device *dev, int port, u16 addr, u64 *cnt)
2027c6ff470STristram Ha {
2037c6ff470STristram Ha 	struct ksz_port *p = &dev->ports[port];
2041c1eb580SMarek Vasut 	unsigned int val;
2057c6ff470STristram Ha 	u32 data;
2067c6ff470STristram Ha 	int ret;
2077c6ff470STristram Ha 
2087c6ff470STristram Ha 	/* retain the flush/freeze bit */
2097c6ff470STristram Ha 	data = p->freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
2107c6ff470STristram Ha 	data |= MIB_COUNTER_READ;
2117c6ff470STristram Ha 	data |= (addr << MIB_COUNTER_INDEX_S);
2127c6ff470STristram Ha 	ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, data);
2137c6ff470STristram Ha 
214b8311f46SVladimir Oltean 	ret = regmap_read_poll_timeout(ksz_regmap_32(dev),
2151c1eb580SMarek Vasut 			PORT_CTRL_ADDR(port, REG_PORT_MIB_CTRL_STAT__4),
2161c1eb580SMarek Vasut 			val, !(val & MIB_COUNTER_READ), 10, 1000);
2177c6ff470STristram Ha 	/* failed to read MIB. get out of loop */
2181c1eb580SMarek Vasut 	if (ret) {
2197c6ff470STristram Ha 		dev_dbg(dev->dev, "Failed to get MIB\n");
2207c6ff470STristram Ha 		return;
2217c6ff470STristram Ha 	}
2227c6ff470STristram Ha 
2237c6ff470STristram Ha 	/* count resets upon read */
2247c6ff470STristram Ha 	ksz_pread32(dev, port, REG_PORT_MIB_DATA, &data);
2257c6ff470STristram Ha 	*cnt += data;
2267c6ff470STristram Ha }
2277c6ff470STristram Ha 
ksz9477_r_mib_pkt(struct ksz_device * dev,int port,u16 addr,u64 * dropped,u64 * cnt)2286ec23aaaSArun Ramadoss void ksz9477_r_mib_pkt(struct ksz_device *dev, int port, u16 addr,
2297c6ff470STristram Ha 		       u64 *dropped, u64 *cnt)
2307c6ff470STristram Ha {
231a530e6f2SArun Ramadoss 	addr = dev->info->mib_names[addr].index;
2327c6ff470STristram Ha 	ksz9477_r_mib_cnt(dev, port, addr, cnt);
2337c6ff470STristram Ha }
2347c6ff470STristram Ha 
ksz9477_freeze_mib(struct ksz_device * dev,int port,bool freeze)2356ec23aaaSArun Ramadoss void ksz9477_freeze_mib(struct ksz_device *dev, int port, bool freeze)
2367c6ff470STristram Ha {
2377c6ff470STristram Ha 	u32 val = freeze ? MIB_COUNTER_FLUSH_FREEZE : 0;
2387c6ff470STristram Ha 	struct ksz_port *p = &dev->ports[port];
2397c6ff470STristram Ha 
2407c6ff470STristram Ha 	/* enable/disable the port for flush/freeze function */
2417c6ff470STristram Ha 	mutex_lock(&p->mib.cnt_mutex);
2427c6ff470STristram Ha 	ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, val);
2437c6ff470STristram Ha 
2447c6ff470STristram Ha 	/* used by MIB counter reading code to know freeze is enabled */
2457c6ff470STristram Ha 	p->freeze = freeze;
2467c6ff470STristram Ha 	mutex_unlock(&p->mib.cnt_mutex);
2477c6ff470STristram Ha }
2487c6ff470STristram Ha 
ksz9477_port_init_cnt(struct ksz_device * dev,int port)2496ec23aaaSArun Ramadoss void ksz9477_port_init_cnt(struct ksz_device *dev, int port)
2507c6ff470STristram Ha {
2517c6ff470STristram Ha 	struct ksz_port_mib *mib = &dev->ports[port].mib;
2527c6ff470STristram Ha 
2537c6ff470STristram Ha 	/* flush all enabled port MIB counters */
2547c6ff470STristram Ha 	mutex_lock(&mib->cnt_mutex);
2557c6ff470STristram Ha 	ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4,
2567c6ff470STristram Ha 		     MIB_COUNTER_FLUSH_FREEZE);
2577c6ff470STristram Ha 	ksz_write8(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FLUSH);
2587c6ff470STristram Ha 	ksz_pwrite32(dev, port, REG_PORT_MIB_CTRL_STAT__4, 0);
2597c6ff470STristram Ha 	mutex_unlock(&mib->cnt_mutex);
2607c6ff470STristram Ha }
2617c6ff470STristram Ha 
ksz9477_r_phy_quirks(struct ksz_device * dev,u16 addr,u16 reg,u16 * data)262d7539fc2SOleksij Rempel static void ksz9477_r_phy_quirks(struct ksz_device *dev, u16 addr, u16 reg,
263d7539fc2SOleksij Rempel 				 u16 *data)
264d7539fc2SOleksij Rempel {
265d7539fc2SOleksij Rempel 	/* KSZ8563R do not have extended registers but BMSR_ESTATEN and
266d7539fc2SOleksij Rempel 	 * BMSR_ERCAP bits are set.
267d7539fc2SOleksij Rempel 	 */
268d7539fc2SOleksij Rempel 	if (dev->chip_id == KSZ8563_CHIP_ID && reg == MII_BMSR)
269d7539fc2SOleksij Rempel 		*data &= ~(BMSR_ESTATEN | BMSR_ERCAP);
270d7539fc2SOleksij Rempel }
271d7539fc2SOleksij Rempel 
ksz9477_r_phy(struct ksz_device * dev,u16 addr,u16 reg,u16 * data)2728f420456SOleksij Rempel int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data)
273c2e86691STristram Ha {
274c2e86691STristram Ha 	u16 val = 0xffff;
2759da975e1SOleksij Rempel 	int ret;
276c2e86691STristram Ha 
277c2e86691STristram Ha 	/* No real PHY after this. Simulate the PHY.
278c2e86691STristram Ha 	 * A fixed PHY can be setup in the device tree, but this function is
279c2e86691STristram Ha 	 * still called for that port during initialization.
280c2e86691STristram Ha 	 * For RGMII PHY there is no way to access it so the fixed PHY should
281c2e86691STristram Ha 	 * be used.  For SGMII PHY the supporting code will be added later.
282c2e86691STristram Ha 	 */
2830a7fbd51SOleksij Rempel 	if (!dev->info->internal_phy[addr]) {
284c2e86691STristram Ha 		struct ksz_port *p = &dev->ports[addr];
285c2e86691STristram Ha 
286c2e86691STristram Ha 		switch (reg) {
287c2e86691STristram Ha 		case MII_BMCR:
288c2e86691STristram Ha 			val = 0x1140;
289c2e86691STristram Ha 			break;
290c2e86691STristram Ha 		case MII_BMSR:
291c2e86691STristram Ha 			val = 0x796d;
292c2e86691STristram Ha 			break;
293c2e86691STristram Ha 		case MII_PHYSID1:
294c2e86691STristram Ha 			val = 0x0022;
295c2e86691STristram Ha 			break;
296c2e86691STristram Ha 		case MII_PHYSID2:
297c2e86691STristram Ha 			val = 0x1631;
298c2e86691STristram Ha 			break;
299c2e86691STristram Ha 		case MII_ADVERTISE:
300c2e86691STristram Ha 			val = 0x05e1;
301c2e86691STristram Ha 			break;
302c2e86691STristram Ha 		case MII_LPA:
303c2e86691STristram Ha 			val = 0xc5e1;
304c2e86691STristram Ha 			break;
305c2e86691STristram Ha 		case MII_CTRL1000:
306c2e86691STristram Ha 			val = 0x0700;
307c2e86691STristram Ha 			break;
308c2e86691STristram Ha 		case MII_STAT1000:
309c2e86691STristram Ha 			if (p->phydev.speed == SPEED_1000)
310c2e86691STristram Ha 				val = 0x3800;
311c2e86691STristram Ha 			else
312c2e86691STristram Ha 				val = 0;
313c2e86691STristram Ha 			break;
314c2e86691STristram Ha 		}
315c2e86691STristram Ha 	} else {
3169da975e1SOleksij Rempel 		ret = ksz_pread16(dev, addr, 0x100 + (reg << 1), &val);
3179da975e1SOleksij Rempel 		if (ret)
3189da975e1SOleksij Rempel 			return ret;
3199da975e1SOleksij Rempel 
320d7539fc2SOleksij Rempel 		ksz9477_r_phy_quirks(dev, addr, reg, &val);
321c2e86691STristram Ha 	}
322c2e86691STristram Ha 
323930e5790SArun Ramadoss 	*data = val;
3248f420456SOleksij Rempel 
3258f420456SOleksij Rempel 	return 0;
326c2e86691STristram Ha }
327c2e86691STristram Ha 
ksz9477_w_phy(struct ksz_device * dev,u16 addr,u16 reg,u16 val)3288f420456SOleksij Rempel int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val)
329c2e86691STristram Ha {
3305c844d57SRasmus Villemoes 	u32 mask, val32;
3315c844d57SRasmus Villemoes 
332c2e86691STristram Ha 	/* No real PHY after this. */
3330a7fbd51SOleksij Rempel 	if (!dev->info->internal_phy[addr])
3348f420456SOleksij Rempel 		return 0;
3358c29bebbSTristram Ha 
3365c844d57SRasmus Villemoes 	if (reg < 0x10)
3379da975e1SOleksij Rempel 		return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val);
3385c844d57SRasmus Villemoes 
3395c844d57SRasmus Villemoes 	/* Errata: When using SPI, I2C, or in-band register access,
3405c844d57SRasmus Villemoes 	 * writes to certain PHY registers should be performed as
3415c844d57SRasmus Villemoes 	 * 32-bit writes instead of 16-bit writes.
3425c844d57SRasmus Villemoes 	 */
3435c844d57SRasmus Villemoes 	val32 = val;
3445c844d57SRasmus Villemoes 	mask = 0xffff;
3455c844d57SRasmus Villemoes 	if ((reg & 1) == 0) {
3465c844d57SRasmus Villemoes 		val32 <<= 16;
3475c844d57SRasmus Villemoes 		mask <<= 16;
3485c844d57SRasmus Villemoes 	}
3495c844d57SRasmus Villemoes 	reg &= ~1;
3505c844d57SRasmus Villemoes 	return ksz_prmw32(dev, addr, 0x100 + (reg << 1), mask, val32);
351c2e86691STristram Ha }
352c2e86691STristram Ha 
ksz9477_cfg_port_member(struct ksz_device * dev,int port,u8 member)3536ec23aaaSArun Ramadoss void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member)
354c2e86691STristram Ha {
355c2e86691STristram Ha 	ksz_pwrite32(dev, port, REG_PORT_VLAN_MEMBERSHIP__4, member);
356c2e86691STristram Ha }
357c2e86691STristram Ha 
ksz9477_flush_dyn_mac_table(struct ksz_device * dev,int port)3586ec23aaaSArun Ramadoss void ksz9477_flush_dyn_mac_table(struct ksz_device *dev, int port)
359c2e86691STristram Ha {
3606877102fSArun Ramadoss 	const u16 *regs = dev->info->regs;
361c2e86691STristram Ha 	u8 data;
362c2e86691STristram Ha 
363b8311f46SVladimir Oltean 	regmap_update_bits(ksz_regmap_8(dev), REG_SW_LUE_CTRL_2,
364ee353e45SMarek Vasut 			   SW_FLUSH_OPTION_M << SW_FLUSH_OPTION_S,
365ee353e45SMarek Vasut 			   SW_FLUSH_OPTION_DYN_MAC << SW_FLUSH_OPTION_S);
366ee353e45SMarek Vasut 
367462d5250SArun Ramadoss 	if (port < dev->info->port_cnt) {
368c2e86691STristram Ha 		/* flush individual port */
3696877102fSArun Ramadoss 		ksz_pread8(dev, port, regs[P_STP_CTRL], &data);
370c2e86691STristram Ha 		if (!(data & PORT_LEARN_DISABLE))
3716877102fSArun Ramadoss 			ksz_pwrite8(dev, port, regs[P_STP_CTRL],
372c2e86691STristram Ha 				    data | PORT_LEARN_DISABLE);
373c2e86691STristram Ha 		ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_DYN_MAC_TABLE, true);
3746877102fSArun Ramadoss 		ksz_pwrite8(dev, port, regs[P_STP_CTRL], data);
375c2e86691STristram Ha 	} else {
376c2e86691STristram Ha 		/* flush all */
377c2e86691STristram Ha 		ksz_cfg(dev, S_FLUSH_TABLE_CTRL, SW_FLUSH_STP_TABLE, true);
378c2e86691STristram Ha 	}
379c2e86691STristram Ha }
380c2e86691STristram Ha 
ksz9477_port_vlan_filtering(struct ksz_device * dev,int port,bool flag,struct netlink_ext_ack * extack)3816ec23aaaSArun Ramadoss int ksz9477_port_vlan_filtering(struct ksz_device *dev, int port,
3826ec23aaaSArun Ramadoss 				bool flag, struct netlink_ext_ack *extack)
383c2e86691STristram Ha {
384c2e86691STristram Ha 	if (flag) {
385c2e86691STristram Ha 		ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
386c2e86691STristram Ha 			     PORT_VLAN_LOOKUP_VID_0, true);
387c2e86691STristram Ha 		ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, true);
388c2e86691STristram Ha 	} else {
389c2e86691STristram Ha 		ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_VLAN_ENABLE, false);
390c2e86691STristram Ha 		ksz_port_cfg(dev, port, REG_PORT_LUE_CTRL,
391c2e86691STristram Ha 			     PORT_VLAN_LOOKUP_VID_0, false);
392c2e86691STristram Ha 	}
393c2e86691STristram Ha 
394c2e86691STristram Ha 	return 0;
395c2e86691STristram Ha }
396c2e86691STristram Ha 
ksz9477_port_vlan_add(struct ksz_device * dev,int port,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)3976ec23aaaSArun Ramadoss int ksz9477_port_vlan_add(struct ksz_device *dev, int port,
39831046a5fSVladimir Oltean 			  const struct switchdev_obj_port_vlan *vlan,
39931046a5fSVladimir Oltean 			  struct netlink_ext_ack *extack)
400c2e86691STristram Ha {
401c2e86691STristram Ha 	u32 vlan_table[3];
402c2e86691STristram Ha 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
4031958d581SVladimir Oltean 	int err;
404c2e86691STristram Ha 
4051958d581SVladimir Oltean 	err = ksz9477_get_vlan_table(dev, vlan->vid, vlan_table);
4061958d581SVladimir Oltean 	if (err) {
40731046a5fSVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack, "Failed to get vlan table");
4081958d581SVladimir Oltean 		return err;
409c2e86691STristram Ha 	}
410c2e86691STristram Ha 
411b7a9e0daSVladimir Oltean 	vlan_table[0] = VLAN_VALID | (vlan->vid & VLAN_FID_M);
412c2e86691STristram Ha 	if (untagged)
413c2e86691STristram Ha 		vlan_table[1] |= BIT(port);
414c2e86691STristram Ha 	else
415c2e86691STristram Ha 		vlan_table[1] &= ~BIT(port);
416c2e86691STristram Ha 	vlan_table[1] &= ~(BIT(dev->cpu_port));
417c2e86691STristram Ha 
418c2e86691STristram Ha 	vlan_table[2] |= BIT(port) | BIT(dev->cpu_port);
419c2e86691STristram Ha 
4201958d581SVladimir Oltean 	err = ksz9477_set_vlan_table(dev, vlan->vid, vlan_table);
4211958d581SVladimir Oltean 	if (err) {
42231046a5fSVladimir Oltean 		NL_SET_ERR_MSG_MOD(extack, "Failed to set vlan table");
4231958d581SVladimir Oltean 		return err;
424c2e86691STristram Ha 	}
425c2e86691STristram Ha 
426c2e86691STristram Ha 	/* change PVID */
427c2e86691STristram Ha 	if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
428b7a9e0daSVladimir Oltean 		ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, vlan->vid);
4291958d581SVladimir Oltean 
4301958d581SVladimir Oltean 	return 0;
431c2e86691STristram Ha }
432c2e86691STristram Ha 
ksz9477_port_vlan_del(struct ksz_device * dev,int port,const struct switchdev_obj_port_vlan * vlan)4336ec23aaaSArun Ramadoss int ksz9477_port_vlan_del(struct ksz_device *dev, int port,
434c2e86691STristram Ha 			  const struct switchdev_obj_port_vlan *vlan)
435c2e86691STristram Ha {
436c2e86691STristram Ha 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
437c2e86691STristram Ha 	u32 vlan_table[3];
438c2e86691STristram Ha 	u16 pvid;
439c2e86691STristram Ha 
440c2e86691STristram Ha 	ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &pvid);
441c2e86691STristram Ha 	pvid = pvid & 0xFFF;
442c2e86691STristram Ha 
443b7a9e0daSVladimir Oltean 	if (ksz9477_get_vlan_table(dev, vlan->vid, vlan_table)) {
444c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to get vlan table\n");
445c2e86691STristram Ha 		return -ETIMEDOUT;
446c2e86691STristram Ha 	}
447c2e86691STristram Ha 
448c2e86691STristram Ha 	vlan_table[2] &= ~BIT(port);
449c2e86691STristram Ha 
450b7a9e0daSVladimir Oltean 	if (pvid == vlan->vid)
451c2e86691STristram Ha 		pvid = 1;
452c2e86691STristram Ha 
453c2e86691STristram Ha 	if (untagged)
454c2e86691STristram Ha 		vlan_table[1] &= ~BIT(port);
455c2e86691STristram Ha 
456b7a9e0daSVladimir Oltean 	if (ksz9477_set_vlan_table(dev, vlan->vid, vlan_table)) {
457c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to set vlan table\n");
458c2e86691STristram Ha 		return -ETIMEDOUT;
459c2e86691STristram Ha 	}
460c2e86691STristram Ha 
461c2e86691STristram Ha 	ksz_pwrite16(dev, port, REG_PORT_DEFAULT_VID, pvid);
462c2e86691STristram Ha 
463c2e86691STristram Ha 	return 0;
464c2e86691STristram Ha }
465c2e86691STristram Ha 
ksz9477_fdb_add(struct ksz_device * dev,int port,const unsigned char * addr,u16 vid,struct dsa_db db)4666ec23aaaSArun Ramadoss int ksz9477_fdb_add(struct ksz_device *dev, int port,
4676ec23aaaSArun Ramadoss 		    const unsigned char *addr, u16 vid, struct dsa_db db)
468c2e86691STristram Ha {
469c2e86691STristram Ha 	u32 alu_table[4];
470c2e86691STristram Ha 	u32 data;
471c2e86691STristram Ha 	int ret = 0;
472c2e86691STristram Ha 
473c2e86691STristram Ha 	mutex_lock(&dev->alu_mutex);
474c2e86691STristram Ha 
475c2e86691STristram Ha 	/* find any entry with mac & vid */
476c2e86691STristram Ha 	data = vid << ALU_FID_INDEX_S;
477c2e86691STristram Ha 	data |= ((addr[0] << 8) | addr[1]);
478c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_INDEX_0, data);
479c2e86691STristram Ha 
480c2e86691STristram Ha 	data = ((addr[2] << 24) | (addr[3] << 16));
481c2e86691STristram Ha 	data |= ((addr[4] << 8) | addr[5]);
482c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_INDEX_1, data);
483c2e86691STristram Ha 
484c2e86691STristram Ha 	/* start read operation */
485c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START);
486c2e86691STristram Ha 
487c2e86691STristram Ha 	/* wait to be finished */
488ef534195SMarek Vasut 	ret = ksz9477_wait_alu_ready(dev);
489ef534195SMarek Vasut 	if (ret) {
490c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to read ALU\n");
491c2e86691STristram Ha 		goto exit;
492c2e86691STristram Ha 	}
493c2e86691STristram Ha 
494c2e86691STristram Ha 	/* read ALU entry */
495c2e86691STristram Ha 	ksz9477_read_table(dev, alu_table);
496c2e86691STristram Ha 
497c2e86691STristram Ha 	/* update ALU entry */
498c2e86691STristram Ha 	alu_table[0] = ALU_V_STATIC_VALID;
499c2e86691STristram Ha 	alu_table[1] |= BIT(port);
500c2e86691STristram Ha 	if (vid)
501c2e86691STristram Ha 		alu_table[1] |= ALU_V_USE_FID;
502c2e86691STristram Ha 	alu_table[2] = (vid << ALU_V_FID_S);
503c2e86691STristram Ha 	alu_table[2] |= ((addr[0] << 8) | addr[1]);
504c2e86691STristram Ha 	alu_table[3] = ((addr[2] << 24) | (addr[3] << 16));
505c2e86691STristram Ha 	alu_table[3] |= ((addr[4] << 8) | addr[5]);
506c2e86691STristram Ha 
507c2e86691STristram Ha 	ksz9477_write_table(dev, alu_table);
508c2e86691STristram Ha 
509c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START);
510c2e86691STristram Ha 
511c2e86691STristram Ha 	/* wait to be finished */
512ef534195SMarek Vasut 	ret = ksz9477_wait_alu_ready(dev);
513ef534195SMarek Vasut 	if (ret)
514c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to write ALU\n");
515c2e86691STristram Ha 
516c2e86691STristram Ha exit:
517c2e86691STristram Ha 	mutex_unlock(&dev->alu_mutex);
518c2e86691STristram Ha 
519c2e86691STristram Ha 	return ret;
520c2e86691STristram Ha }
521c2e86691STristram Ha 
ksz9477_fdb_del(struct ksz_device * dev,int port,const unsigned char * addr,u16 vid,struct dsa_db db)5226ec23aaaSArun Ramadoss int ksz9477_fdb_del(struct ksz_device *dev, int port,
5236ec23aaaSArun Ramadoss 		    const unsigned char *addr, u16 vid, struct dsa_db db)
524c2e86691STristram Ha {
525c2e86691STristram Ha 	u32 alu_table[4];
526c2e86691STristram Ha 	u32 data;
527c2e86691STristram Ha 	int ret = 0;
528c2e86691STristram Ha 
529c2e86691STristram Ha 	mutex_lock(&dev->alu_mutex);
530c2e86691STristram Ha 
531c2e86691STristram Ha 	/* read any entry with mac & vid */
532c2e86691STristram Ha 	data = vid << ALU_FID_INDEX_S;
533c2e86691STristram Ha 	data |= ((addr[0] << 8) | addr[1]);
534c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_INDEX_0, data);
535c2e86691STristram Ha 
536c2e86691STristram Ha 	data = ((addr[2] << 24) | (addr[3] << 16));
537c2e86691STristram Ha 	data |= ((addr[4] << 8) | addr[5]);
538c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_INDEX_1, data);
539c2e86691STristram Ha 
540c2e86691STristram Ha 	/* start read operation */
541c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START);
542c2e86691STristram Ha 
543c2e86691STristram Ha 	/* wait to be finished */
544ef534195SMarek Vasut 	ret = ksz9477_wait_alu_ready(dev);
545ef534195SMarek Vasut 	if (ret) {
546c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to read ALU\n");
547c2e86691STristram Ha 		goto exit;
548c2e86691STristram Ha 	}
549c2e86691STristram Ha 
550c2e86691STristram Ha 	ksz_read32(dev, REG_SW_ALU_VAL_A, &alu_table[0]);
551c2e86691STristram Ha 	if (alu_table[0] & ALU_V_STATIC_VALID) {
552c2e86691STristram Ha 		ksz_read32(dev, REG_SW_ALU_VAL_B, &alu_table[1]);
553c2e86691STristram Ha 		ksz_read32(dev, REG_SW_ALU_VAL_C, &alu_table[2]);
554c2e86691STristram Ha 		ksz_read32(dev, REG_SW_ALU_VAL_D, &alu_table[3]);
555c2e86691STristram Ha 
556c2e86691STristram Ha 		/* clear forwarding port */
5576c977c5cSRakesh Sankaranarayanan 		alu_table[1] &= ~BIT(port);
558c2e86691STristram Ha 
559c2e86691STristram Ha 		/* if there is no port to forward, clear table */
5606c977c5cSRakesh Sankaranarayanan 		if ((alu_table[1] & ALU_V_PORT_MAP) == 0) {
561c2e86691STristram Ha 			alu_table[0] = 0;
562c2e86691STristram Ha 			alu_table[1] = 0;
563c2e86691STristram Ha 			alu_table[2] = 0;
564c2e86691STristram Ha 			alu_table[3] = 0;
565c2e86691STristram Ha 		}
566c2e86691STristram Ha 	} else {
567c2e86691STristram Ha 		alu_table[0] = 0;
568c2e86691STristram Ha 		alu_table[1] = 0;
569c2e86691STristram Ha 		alu_table[2] = 0;
570c2e86691STristram Ha 		alu_table[3] = 0;
571c2e86691STristram Ha 	}
572c2e86691STristram Ha 
573c2e86691STristram Ha 	ksz9477_write_table(dev, alu_table);
574c2e86691STristram Ha 
575c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START);
576c2e86691STristram Ha 
577c2e86691STristram Ha 	/* wait to be finished */
578ef534195SMarek Vasut 	ret = ksz9477_wait_alu_ready(dev);
579ef534195SMarek Vasut 	if (ret)
580c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to write ALU\n");
581c2e86691STristram Ha 
582c2e86691STristram Ha exit:
583c2e86691STristram Ha 	mutex_unlock(&dev->alu_mutex);
584c2e86691STristram Ha 
585c2e86691STristram Ha 	return ret;
586c2e86691STristram Ha }
587c2e86691STristram Ha 
ksz9477_convert_alu(struct alu_struct * alu,u32 * alu_table)588c2e86691STristram Ha static void ksz9477_convert_alu(struct alu_struct *alu, u32 *alu_table)
589c2e86691STristram Ha {
590c2e86691STristram Ha 	alu->is_static = !!(alu_table[0] & ALU_V_STATIC_VALID);
591c2e86691STristram Ha 	alu->is_src_filter = !!(alu_table[0] & ALU_V_SRC_FILTER);
592c2e86691STristram Ha 	alu->is_dst_filter = !!(alu_table[0] & ALU_V_DST_FILTER);
593c2e86691STristram Ha 	alu->prio_age = (alu_table[0] >> ALU_V_PRIO_AGE_CNT_S) &
594c2e86691STristram Ha 			ALU_V_PRIO_AGE_CNT_M;
595c2e86691STristram Ha 	alu->mstp = alu_table[0] & ALU_V_MSTP_M;
596c2e86691STristram Ha 
597c2e86691STristram Ha 	alu->is_override = !!(alu_table[1] & ALU_V_OVERRIDE);
598c2e86691STristram Ha 	alu->is_use_fid = !!(alu_table[1] & ALU_V_USE_FID);
599c2e86691STristram Ha 	alu->port_forward = alu_table[1] & ALU_V_PORT_MAP;
600c2e86691STristram Ha 
601c2e86691STristram Ha 	alu->fid = (alu_table[2] >> ALU_V_FID_S) & ALU_V_FID_M;
602c2e86691STristram Ha 
603c2e86691STristram Ha 	alu->mac[0] = (alu_table[2] >> 8) & 0xFF;
604c2e86691STristram Ha 	alu->mac[1] = alu_table[2] & 0xFF;
605c2e86691STristram Ha 	alu->mac[2] = (alu_table[3] >> 24) & 0xFF;
606c2e86691STristram Ha 	alu->mac[3] = (alu_table[3] >> 16) & 0xFF;
607c2e86691STristram Ha 	alu->mac[4] = (alu_table[3] >> 8) & 0xFF;
608c2e86691STristram Ha 	alu->mac[5] = alu_table[3] & 0xFF;
609c2e86691STristram Ha }
610c2e86691STristram Ha 
ksz9477_fdb_dump(struct ksz_device * dev,int port,dsa_fdb_dump_cb_t * cb,void * data)6116ec23aaaSArun Ramadoss int ksz9477_fdb_dump(struct ksz_device *dev, int port,
612c2e86691STristram Ha 		     dsa_fdb_dump_cb_t *cb, void *data)
613c2e86691STristram Ha {
614c2e86691STristram Ha 	int ret = 0;
615c2e86691STristram Ha 	u32 ksz_data;
616c2e86691STristram Ha 	u32 alu_table[4];
617c2e86691STristram Ha 	struct alu_struct alu;
618c2e86691STristram Ha 	int timeout;
619c2e86691STristram Ha 
620c2e86691STristram Ha 	mutex_lock(&dev->alu_mutex);
621c2e86691STristram Ha 
622c2e86691STristram Ha 	/* start ALU search */
623c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_START | ALU_SEARCH);
624c2e86691STristram Ha 
625c2e86691STristram Ha 	do {
626c2e86691STristram Ha 		timeout = 1000;
627c2e86691STristram Ha 		do {
628c2e86691STristram Ha 			ksz_read32(dev, REG_SW_ALU_CTRL__4, &ksz_data);
629c2e86691STristram Ha 			if ((ksz_data & ALU_VALID) || !(ksz_data & ALU_START))
630c2e86691STristram Ha 				break;
631c2e86691STristram Ha 			usleep_range(1, 10);
632c2e86691STristram Ha 		} while (timeout-- > 0);
633c2e86691STristram Ha 
634c2e86691STristram Ha 		if (!timeout) {
635c2e86691STristram Ha 			dev_dbg(dev->dev, "Failed to search ALU\n");
636c2e86691STristram Ha 			ret = -ETIMEDOUT;
637c2e86691STristram Ha 			goto exit;
638c2e86691STristram Ha 		}
639c2e86691STristram Ha 
64036c0d935SArun Ramadoss 		if (!(ksz_data & ALU_VALID))
64136c0d935SArun Ramadoss 			continue;
64236c0d935SArun Ramadoss 
643c2e86691STristram Ha 		/* read ALU table */
644c2e86691STristram Ha 		ksz9477_read_table(dev, alu_table);
645c2e86691STristram Ha 
646c2e86691STristram Ha 		ksz9477_convert_alu(&alu, alu_table);
647c2e86691STristram Ha 
648c2e86691STristram Ha 		if (alu.port_forward & BIT(port)) {
649c2e86691STristram Ha 			ret = cb(alu.mac, alu.fid, alu.is_static, data);
650c2e86691STristram Ha 			if (ret)
651c2e86691STristram Ha 				goto exit;
652c2e86691STristram Ha 		}
653c2e86691STristram Ha 	} while (ksz_data & ALU_START);
654c2e86691STristram Ha 
655c2e86691STristram Ha exit:
656c2e86691STristram Ha 
657c2e86691STristram Ha 	/* stop ALU search */
658c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_CTRL__4, 0);
659c2e86691STristram Ha 
660c2e86691STristram Ha 	mutex_unlock(&dev->alu_mutex);
661c2e86691STristram Ha 
662c2e86691STristram Ha 	return ret;
663c2e86691STristram Ha }
664c2e86691STristram Ha 
ksz9477_mdb_add(struct ksz_device * dev,int port,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)6656ec23aaaSArun Ramadoss int ksz9477_mdb_add(struct ksz_device *dev, int port,
6666ec23aaaSArun Ramadoss 		    const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
667c2e86691STristram Ha {
668c2e86691STristram Ha 	u32 static_table[4];
669457c182aSArun Ramadoss 	const u8 *shifts;
670457c182aSArun Ramadoss 	const u32 *masks;
671c2e86691STristram Ha 	u32 data;
672c2e86691STristram Ha 	int index;
673c2e86691STristram Ha 	u32 mac_hi, mac_lo;
674a52b2da7SVladimir Oltean 	int err = 0;
675c2e86691STristram Ha 
676457c182aSArun Ramadoss 	shifts = dev->info->shifts;
677457c182aSArun Ramadoss 	masks = dev->info->masks;
678457c182aSArun Ramadoss 
679c2e86691STristram Ha 	mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]);
680c2e86691STristram Ha 	mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16));
681c2e86691STristram Ha 	mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]);
682c2e86691STristram Ha 
683c2e86691STristram Ha 	mutex_lock(&dev->alu_mutex);
684c2e86691STristram Ha 
685462d5250SArun Ramadoss 	for (index = 0; index < dev->info->num_statics; index++) {
686c2e86691STristram Ha 		/* find empty slot first */
687457c182aSArun Ramadoss 		data = (index << shifts[ALU_STAT_INDEX]) |
688457c182aSArun Ramadoss 			masks[ALU_STAT_READ] | ALU_STAT_START;
689c2e86691STristram Ha 		ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
690c2e86691STristram Ha 
691c2e86691STristram Ha 		/* wait to be finished */
692a52b2da7SVladimir Oltean 		err = ksz9477_wait_alu_sta_ready(dev);
693a52b2da7SVladimir Oltean 		if (err) {
694c2e86691STristram Ha 			dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
695c2e86691STristram Ha 			goto exit;
696c2e86691STristram Ha 		}
697c2e86691STristram Ha 
698c2e86691STristram Ha 		/* read ALU static table */
699c2e86691STristram Ha 		ksz9477_read_table(dev, static_table);
700c2e86691STristram Ha 
701c2e86691STristram Ha 		if (static_table[0] & ALU_V_STATIC_VALID) {
702c2e86691STristram Ha 			/* check this has same vid & mac address */
703c2e86691STristram Ha 			if (((static_table[2] >> ALU_V_FID_S) == mdb->vid) &&
704c2e86691STristram Ha 			    ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) &&
705c2e86691STristram Ha 			    static_table[3] == mac_lo) {
706c2e86691STristram Ha 				/* found matching one */
707c2e86691STristram Ha 				break;
708c2e86691STristram Ha 			}
709c2e86691STristram Ha 		} else {
710c2e86691STristram Ha 			/* found empty one */
711c2e86691STristram Ha 			break;
712c2e86691STristram Ha 		}
713c2e86691STristram Ha 	}
714c2e86691STristram Ha 
715c2e86691STristram Ha 	/* no available entry */
716462d5250SArun Ramadoss 	if (index == dev->info->num_statics) {
717a52b2da7SVladimir Oltean 		err = -ENOSPC;
718c2e86691STristram Ha 		goto exit;
719a52b2da7SVladimir Oltean 	}
720c2e86691STristram Ha 
721c2e86691STristram Ha 	/* add entry */
722c2e86691STristram Ha 	static_table[0] = ALU_V_STATIC_VALID;
723c2e86691STristram Ha 	static_table[1] |= BIT(port);
724c2e86691STristram Ha 	if (mdb->vid)
725c2e86691STristram Ha 		static_table[1] |= ALU_V_USE_FID;
726c2e86691STristram Ha 	static_table[2] = (mdb->vid << ALU_V_FID_S);
727c2e86691STristram Ha 	static_table[2] |= mac_hi;
728c2e86691STristram Ha 	static_table[3] = mac_lo;
729c2e86691STristram Ha 
730c2e86691STristram Ha 	ksz9477_write_table(dev, static_table);
731c2e86691STristram Ha 
732457c182aSArun Ramadoss 	data = (index << shifts[ALU_STAT_INDEX]) | ALU_STAT_START;
733c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
734c2e86691STristram Ha 
735c2e86691STristram Ha 	/* wait to be finished */
7363371efbcSMarek Vasut 	if (ksz9477_wait_alu_sta_ready(dev))
737c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
738c2e86691STristram Ha 
739c2e86691STristram Ha exit:
740c2e86691STristram Ha 	mutex_unlock(&dev->alu_mutex);
741a52b2da7SVladimir Oltean 	return err;
742c2e86691STristram Ha }
743c2e86691STristram Ha 
ksz9477_mdb_del(struct ksz_device * dev,int port,const struct switchdev_obj_port_mdb * mdb,struct dsa_db db)7446ec23aaaSArun Ramadoss int ksz9477_mdb_del(struct ksz_device *dev, int port,
7456ec23aaaSArun Ramadoss 		    const struct switchdev_obj_port_mdb *mdb, struct dsa_db db)
746c2e86691STristram Ha {
747c2e86691STristram Ha 	u32 static_table[4];
748457c182aSArun Ramadoss 	const u8 *shifts;
749457c182aSArun Ramadoss 	const u32 *masks;
750c2e86691STristram Ha 	u32 data;
751c2e86691STristram Ha 	int index;
752c2e86691STristram Ha 	int ret = 0;
753c2e86691STristram Ha 	u32 mac_hi, mac_lo;
754c2e86691STristram Ha 
755457c182aSArun Ramadoss 	shifts = dev->info->shifts;
756457c182aSArun Ramadoss 	masks = dev->info->masks;
757457c182aSArun Ramadoss 
758c2e86691STristram Ha 	mac_hi = ((mdb->addr[0] << 8) | mdb->addr[1]);
759c2e86691STristram Ha 	mac_lo = ((mdb->addr[2] << 24) | (mdb->addr[3] << 16));
760c2e86691STristram Ha 	mac_lo |= ((mdb->addr[4] << 8) | mdb->addr[5]);
761c2e86691STristram Ha 
762c2e86691STristram Ha 	mutex_lock(&dev->alu_mutex);
763c2e86691STristram Ha 
764462d5250SArun Ramadoss 	for (index = 0; index < dev->info->num_statics; index++) {
765c2e86691STristram Ha 		/* find empty slot first */
766457c182aSArun Ramadoss 		data = (index << shifts[ALU_STAT_INDEX]) |
767457c182aSArun Ramadoss 			masks[ALU_STAT_READ] | ALU_STAT_START;
768c2e86691STristram Ha 		ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
769c2e86691STristram Ha 
770c2e86691STristram Ha 		/* wait to be finished */
7713371efbcSMarek Vasut 		ret = ksz9477_wait_alu_sta_ready(dev);
7723371efbcSMarek Vasut 		if (ret) {
773c2e86691STristram Ha 			dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
774c2e86691STristram Ha 			goto exit;
775c2e86691STristram Ha 		}
776c2e86691STristram Ha 
777c2e86691STristram Ha 		/* read ALU static table */
778c2e86691STristram Ha 		ksz9477_read_table(dev, static_table);
779c2e86691STristram Ha 
780c2e86691STristram Ha 		if (static_table[0] & ALU_V_STATIC_VALID) {
781c2e86691STristram Ha 			/* check this has same vid & mac address */
782c2e86691STristram Ha 
783c2e86691STristram Ha 			if (((static_table[2] >> ALU_V_FID_S) == mdb->vid) &&
784c2e86691STristram Ha 			    ((static_table[2] & ALU_V_MAC_ADDR_HI) == mac_hi) &&
785c2e86691STristram Ha 			    static_table[3] == mac_lo) {
786c2e86691STristram Ha 				/* found matching one */
787c2e86691STristram Ha 				break;
788c2e86691STristram Ha 			}
789c2e86691STristram Ha 		}
790c2e86691STristram Ha 	}
791c2e86691STristram Ha 
792c2e86691STristram Ha 	/* no available entry */
793462d5250SArun Ramadoss 	if (index == dev->info->num_statics)
794c2e86691STristram Ha 		goto exit;
795c2e86691STristram Ha 
796c2e86691STristram Ha 	/* clear port */
797c2e86691STristram Ha 	static_table[1] &= ~BIT(port);
798c2e86691STristram Ha 
799c2e86691STristram Ha 	if ((static_table[1] & ALU_V_PORT_MAP) == 0) {
800c2e86691STristram Ha 		/* delete entry */
801c2e86691STristram Ha 		static_table[0] = 0;
802c2e86691STristram Ha 		static_table[1] = 0;
803c2e86691STristram Ha 		static_table[2] = 0;
804c2e86691STristram Ha 		static_table[3] = 0;
805c2e86691STristram Ha 	}
806c2e86691STristram Ha 
807c2e86691STristram Ha 	ksz9477_write_table(dev, static_table);
808c2e86691STristram Ha 
809457c182aSArun Ramadoss 	data = (index << shifts[ALU_STAT_INDEX]) | ALU_STAT_START;
810c2e86691STristram Ha 	ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
811c2e86691STristram Ha 
812c2e86691STristram Ha 	/* wait to be finished */
8133371efbcSMarek Vasut 	ret = ksz9477_wait_alu_sta_ready(dev);
8143371efbcSMarek Vasut 	if (ret)
815c2e86691STristram Ha 		dev_dbg(dev->dev, "Failed to read ALU STATIC\n");
816c2e86691STristram Ha 
817c2e86691STristram Ha exit:
818c2e86691STristram Ha 	mutex_unlock(&dev->alu_mutex);
819c2e86691STristram Ha 
820c2e86691STristram Ha 	return ret;
821c2e86691STristram Ha }
822c2e86691STristram Ha 
ksz9477_port_mirror_add(struct ksz_device * dev,int port,struct dsa_mall_mirror_tc_entry * mirror,bool ingress,struct netlink_ext_ack * extack)8236ec23aaaSArun Ramadoss int ksz9477_port_mirror_add(struct ksz_device *dev, int port,
824c2e86691STristram Ha 			    struct dsa_mall_mirror_tc_entry *mirror,
8250148bb50SVladimir Oltean 			    bool ingress, struct netlink_ext_ack *extack)
826c2e86691STristram Ha {
827fee34dd1SArun Ramadoss 	u8 data;
828fee34dd1SArun Ramadoss 	int p;
829fee34dd1SArun Ramadoss 
830fee34dd1SArun Ramadoss 	/* Limit to one sniffer port
831fee34dd1SArun Ramadoss 	 * Check if any of the port is already set for sniffing
832fee34dd1SArun Ramadoss 	 * If yes, instruct the user to remove the previous entry & exit
833fee34dd1SArun Ramadoss 	 */
834462d5250SArun Ramadoss 	for (p = 0; p < dev->info->port_cnt; p++) {
835fee34dd1SArun Ramadoss 		/* Skip the current sniffing port */
836fee34dd1SArun Ramadoss 		if (p == mirror->to_local_port)
837fee34dd1SArun Ramadoss 			continue;
838fee34dd1SArun Ramadoss 
839fee34dd1SArun Ramadoss 		ksz_pread8(dev, p, P_MIRROR_CTRL, &data);
840fee34dd1SArun Ramadoss 
841fee34dd1SArun Ramadoss 		if (data & PORT_MIRROR_SNIFFER) {
842fee34dd1SArun Ramadoss 			NL_SET_ERR_MSG_MOD(extack,
843fee34dd1SArun Ramadoss 					   "Sniffer port is already configured, delete existing rules & retry");
844fee34dd1SArun Ramadoss 			return -EBUSY;
845fee34dd1SArun Ramadoss 		}
846fee34dd1SArun Ramadoss 	}
847c2e86691STristram Ha 
848c2e86691STristram Ha 	if (ingress)
849c2e86691STristram Ha 		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, true);
850c2e86691STristram Ha 	else
851c2e86691STristram Ha 		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, true);
852c2e86691STristram Ha 
853c2e86691STristram Ha 	/* configure mirror port */
854c2e86691STristram Ha 	ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
855c2e86691STristram Ha 		     PORT_MIRROR_SNIFFER, true);
856c2e86691STristram Ha 
857c2e86691STristram Ha 	ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
858c2e86691STristram Ha 
859c2e86691STristram Ha 	return 0;
860c2e86691STristram Ha }
861c2e86691STristram Ha 
ksz9477_port_mirror_del(struct ksz_device * dev,int port,struct dsa_mall_mirror_tc_entry * mirror)8626ec23aaaSArun Ramadoss void ksz9477_port_mirror_del(struct ksz_device *dev, int port,
863c2e86691STristram Ha 			     struct dsa_mall_mirror_tc_entry *mirror)
864c2e86691STristram Ha {
865fee34dd1SArun Ramadoss 	bool in_use = false;
866c2e86691STristram Ha 	u8 data;
867fee34dd1SArun Ramadoss 	int p;
868c2e86691STristram Ha 
869c2e86691STristram Ha 	if (mirror->ingress)
870c2e86691STristram Ha 		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_RX, false);
871c2e86691STristram Ha 	else
872c2e86691STristram Ha 		ksz_port_cfg(dev, port, P_MIRROR_CTRL, PORT_MIRROR_TX, false);
873c2e86691STristram Ha 
874c2e86691STristram Ha 
875fee34dd1SArun Ramadoss 	/* Check if any of the port is still referring to sniffer port */
876462d5250SArun Ramadoss 	for (p = 0; p < dev->info->port_cnt; p++) {
877fee34dd1SArun Ramadoss 		ksz_pread8(dev, p, P_MIRROR_CTRL, &data);
878fee34dd1SArun Ramadoss 
879fee34dd1SArun Ramadoss 		if ((data & (PORT_MIRROR_RX | PORT_MIRROR_TX))) {
880fee34dd1SArun Ramadoss 			in_use = true;
881fee34dd1SArun Ramadoss 			break;
882fee34dd1SArun Ramadoss 		}
883fee34dd1SArun Ramadoss 	}
884fee34dd1SArun Ramadoss 
885fee34dd1SArun Ramadoss 	/* delete sniffing if there are no other mirroring rules */
886fee34dd1SArun Ramadoss 	if (!in_use)
887c2e86691STristram Ha 		ksz_port_cfg(dev, mirror->to_local_port, P_MIRROR_CTRL,
888c2e86691STristram Ha 			     PORT_MIRROR_SNIFFER, false);
889c2e86691STristram Ha }
890c2e86691STristram Ha 
ksz9477_get_interface(struct ksz_device * dev,int port)8918c29bebbSTristram Ha static phy_interface_t ksz9477_get_interface(struct ksz_device *dev, int port)
8928c29bebbSTristram Ha {
8938c29bebbSTristram Ha 	phy_interface_t interface;
8948c29bebbSTristram Ha 	bool gbit;
8958c29bebbSTristram Ha 
8960a7fbd51SOleksij Rempel 	if (dev->info->internal_phy[port])
8978c29bebbSTristram Ha 		return PHY_INTERFACE_MODE_NA;
8980ab7f6bfSArun Ramadoss 
89946f80fa8SArun Ramadoss 	gbit = ksz_get_gbit(dev, port);
9000ab7f6bfSArun Ramadoss 
9010ab7f6bfSArun Ramadoss 	interface = ksz_get_xmii(dev, port, gbit);
9020ab7f6bfSArun Ramadoss 
9038c29bebbSTristram Ha 	return interface;
90442fc6a4cSTristram Ha }
90542fc6a4cSTristram Ha 
ksz9477_get_caps(struct ksz_device * dev,int port,struct phylink_config * config)9066ec23aaaSArun Ramadoss void ksz9477_get_caps(struct ksz_device *dev, int port,
90765ac79e1SArun Ramadoss 		      struct phylink_config *config)
90865ac79e1SArun Ramadoss {
9097a8988a1SArun Ramadoss 	config->mac_capabilities = MAC_10 | MAC_100 | MAC_ASYM_PAUSE |
9107a8988a1SArun Ramadoss 				   MAC_SYM_PAUSE;
9117a8988a1SArun Ramadoss 
912505bf320SOleksij Rempel 	if (dev->info->gbit_capable[port])
9137a8988a1SArun Ramadoss 		config->mac_capabilities |= MAC_1000FD;
91465ac79e1SArun Ramadoss }
91565ac79e1SArun Ramadoss 
ksz9477_set_ageing_time(struct ksz_device * dev,unsigned int msecs)9162c119d99SArun Ramadoss int ksz9477_set_ageing_time(struct ksz_device *dev, unsigned int msecs)
9172c119d99SArun Ramadoss {
9182c119d99SArun Ramadoss 	u32 secs = msecs / 1000;
919*7583dd59STristram Ha 	u8 data, mult, value;
920*7583dd59STristram Ha 	u32 max_val;
9212c119d99SArun Ramadoss 	int ret;
9222c119d99SArun Ramadoss 
923*7583dd59STristram Ha #define MAX_TIMER_VAL	((1 << 8) - 1)
9242c119d99SArun Ramadoss 
925*7583dd59STristram Ha 	/* The aging timer comprises a 3-bit multiplier and an 8-bit second
926*7583dd59STristram Ha 	 * value.  Either of them cannot be zero.  The maximum timer is then
927*7583dd59STristram Ha 	 * 7 * 255 = 1785 seconds.
928*7583dd59STristram Ha 	 */
929*7583dd59STristram Ha 	if (!secs)
930*7583dd59STristram Ha 		secs = 1;
9312c119d99SArun Ramadoss 
932*7583dd59STristram Ha 	/* Return error if too large. */
933*7583dd59STristram Ha 	else if (secs > 7 * MAX_TIMER_VAL)
934*7583dd59STristram Ha 		return -EINVAL;
9352c119d99SArun Ramadoss 
9362c119d99SArun Ramadoss 	ret = ksz_read8(dev, REG_SW_LUE_CTRL_0, &value);
9372c119d99SArun Ramadoss 	if (ret < 0)
9382c119d99SArun Ramadoss 		return ret;
9392c119d99SArun Ramadoss 
940*7583dd59STristram Ha 	/* Check whether there is need to update the multiplier. */
941*7583dd59STristram Ha 	mult = FIELD_GET(SW_AGE_CNT_M, value);
942*7583dd59STristram Ha 	max_val = MAX_TIMER_VAL;
943*7583dd59STristram Ha 	if (mult > 0) {
944*7583dd59STristram Ha 		/* Try to use the same multiplier already in the register as
945*7583dd59STristram Ha 		 * the hardware default uses multiplier 4 and 75 seconds for
946*7583dd59STristram Ha 		 * 300 seconds.
947*7583dd59STristram Ha 		 */
948*7583dd59STristram Ha 		max_val = DIV_ROUND_UP(secs, mult);
949*7583dd59STristram Ha 		if (max_val > MAX_TIMER_VAL || max_val * mult != secs)
950*7583dd59STristram Ha 			max_val = MAX_TIMER_VAL;
951*7583dd59STristram Ha 	}
952*7583dd59STristram Ha 
953*7583dd59STristram Ha 	data = DIV_ROUND_UP(secs, max_val);
954*7583dd59STristram Ha 	if (mult != data) {
9552c119d99SArun Ramadoss 		value &= ~SW_AGE_CNT_M;
9562c119d99SArun Ramadoss 		value |= FIELD_PREP(SW_AGE_CNT_M, data);
957*7583dd59STristram Ha 		ret = ksz_write8(dev, REG_SW_LUE_CTRL_0, value);
958*7583dd59STristram Ha 		if (ret < 0)
959*7583dd59STristram Ha 			return ret;
960*7583dd59STristram Ha 	}
9612c119d99SArun Ramadoss 
962*7583dd59STristram Ha 	value = DIV_ROUND_UP(secs, data);
963*7583dd59STristram Ha 	return ksz_write8(dev, REG_SW_LUE_CTRL_3, value);
9642c119d99SArun Ramadoss }
9652c119d99SArun Ramadoss 
ksz9477_port_queue_split(struct ksz_device * dev,int port)966e30f33a5SArun Ramadoss void ksz9477_port_queue_split(struct ksz_device *dev, int port)
967e30f33a5SArun Ramadoss {
968e30f33a5SArun Ramadoss 	u8 data;
969e30f33a5SArun Ramadoss 
970e30f33a5SArun Ramadoss 	if (dev->info->num_tx_queues == 8)
971e30f33a5SArun Ramadoss 		data = PORT_EIGHT_QUEUE;
972e30f33a5SArun Ramadoss 	else if (dev->info->num_tx_queues == 4)
973e30f33a5SArun Ramadoss 		data = PORT_FOUR_QUEUE;
974e30f33a5SArun Ramadoss 	else if (dev->info->num_tx_queues == 2)
975e30f33a5SArun Ramadoss 		data = PORT_TWO_QUEUE;
976e30f33a5SArun Ramadoss 	else
977e30f33a5SArun Ramadoss 		data = PORT_SINGLE_QUEUE;
978e30f33a5SArun Ramadoss 
979e30f33a5SArun Ramadoss 	ksz_prmw8(dev, port, REG_PORT_CTRL_0, PORT_QUEUE_SPLIT_MASK, data);
980e30f33a5SArun Ramadoss }
981e30f33a5SArun Ramadoss 
ksz9477_port_setup(struct ksz_device * dev,int port,bool cpu_port)9826ec23aaaSArun Ramadoss void ksz9477_port_setup(struct ksz_device *dev, int port, bool cpu_port)
983c2e86691STristram Ha {
984b3612ccdSOleksij Rempel 	struct dsa_switch *ds = dev->ds;
985b3612ccdSOleksij Rempel 	u16 data16;
9860ab7f6bfSArun Ramadoss 	u8 member;
987c2e86691STristram Ha 
988c2e86691STristram Ha 	/* enable tag tail for host port */
989c2e86691STristram Ha 	if (cpu_port)
990c2e86691STristram Ha 		ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_TAIL_TAG_ENABLE,
991c2e86691STristram Ha 			     true);
992c2e86691STristram Ha 
993e30f33a5SArun Ramadoss 	ksz9477_port_queue_split(dev, port);
994e30f33a5SArun Ramadoss 
995c2e86691STristram Ha 	ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_MAC_LOOPBACK, false);
996c2e86691STristram Ha 
997c2e86691STristram Ha 	/* set back pressure */
998c2e86691STristram Ha 	ksz_port_cfg(dev, port, REG_PORT_MAC_CTRL_1, PORT_BACK_PRESSURE, true);
999c2e86691STristram Ha 
1000c2e86691STristram Ha 	/* enable broadcast storm limit */
1001c2e86691STristram Ha 	ksz_port_cfg(dev, port, P_BCAST_STORM_CTRL, PORT_BROADCAST_STORM, true);
1002c2e86691STristram Ha 
1003c2e86691STristram Ha 	/* disable DiffServ priority */
1004c2e86691STristram Ha 	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_DIFFSERV_PRIO_ENABLE, false);
1005c2e86691STristram Ha 
1006c2e86691STristram Ha 	/* replace priority */
1007c2e86691STristram Ha 	ksz_port_cfg(dev, port, REG_PORT_MRI_MAC_CTRL, PORT_USER_PRIO_CEILING,
1008c2e86691STristram Ha 		     false);
1009c2e86691STristram Ha 	ksz9477_port_cfg32(dev, port, REG_PORT_MTI_QUEUE_CTRL_0__4,
1010c2e86691STristram Ha 			   MTI_PVID_REPLACE, false);
1011c2e86691STristram Ha 
1012c2e86691STristram Ha 	/* enable 802.1p priority */
1013c2e86691STristram Ha 	ksz_port_cfg(dev, port, P_PRIO_CTRL, PORT_802_1P_PRIO_ENABLE, true);
1014c2e86691STristram Ha 
10156068e6d7SRobert Hancock 	/* force flow control for non-PHY ports only */
1016c2e86691STristram Ha 	ksz_port_cfg(dev, port, REG_PORT_CTRL_0,
1017c2e86691STristram Ha 		     PORT_FORCE_TX_FLOW_CTRL | PORT_FORCE_RX_FLOW_CTRL,
10186068e6d7SRobert Hancock 		     !dev->info->internal_phy[port]);
1019b3612ccdSOleksij Rempel 
1020b20a6b29SCodrin Ciubotariu 	if (cpu_port)
1021b3612ccdSOleksij Rempel 		member = dsa_user_ports(ds);
1022b20a6b29SCodrin Ciubotariu 	else
1023b3612ccdSOleksij Rempel 		member = BIT(dsa_upstream_port(ds, port));
1024b3612ccdSOleksij Rempel 
1025c2e86691STristram Ha 	ksz9477_cfg_port_member(dev, port, member);
1026c2e86691STristram Ha 
1027c2e86691STristram Ha 	/* clear pending interrupts */
10280a7fbd51SOleksij Rempel 	if (dev->info->internal_phy[port])
1029c2e86691STristram Ha 		ksz_pread16(dev, port, REG_PORT_PHY_INT_ENABLE, &data16);
1030c2e86691STristram Ha }
1031c2e86691STristram Ha 
ksz9477_config_cpu_port(struct dsa_switch * ds)10326ec23aaaSArun Ramadoss void ksz9477_config_cpu_port(struct dsa_switch *ds)
1033c2e86691STristram Ha {
1034c2e86691STristram Ha 	struct ksz_device *dev = ds->priv;
1035c2e86691STristram Ha 	struct ksz_port *p;
1036c2e86691STristram Ha 	int i;
1037c2e86691STristram Ha 
1038462d5250SArun Ramadoss 	for (i = 0; i < dev->info->port_cnt; i++) {
1039462d5250SArun Ramadoss 		if (dsa_is_cpu_port(ds, i) &&
1040462d5250SArun Ramadoss 		    (dev->info->cpu_ports & (1 << i))) {
10418c29bebbSTristram Ha 			phy_interface_t interface;
1042805a7e6fSPaul Barker 			const char *prev_msg;
1043805a7e6fSPaul Barker 			const char *prev_mode;
10448c29bebbSTristram Ha 
1045c2e86691STristram Ha 			dev->cpu_port = i;
1046edecfa98SHelmut Grohne 			p = &dev->ports[i];
1047c2e86691STristram Ha 
10488c29bebbSTristram Ha 			/* Read from XMII register to determine host port
10498c29bebbSTristram Ha 			 * interface.  If set specifically in device tree
10508c29bebbSTristram Ha 			 * note the difference to help debugging.
10518c29bebbSTristram Ha 			 */
10528c29bebbSTristram Ha 			interface = ksz9477_get_interface(dev, i);
1053edecfa98SHelmut Grohne 			if (!p->interface) {
1054edecfa98SHelmut Grohne 				if (dev->compat_interface) {
1055edecfa98SHelmut Grohne 					dev_warn(dev->dev,
1056edecfa98SHelmut Grohne 						 "Using legacy switch \"phy-mode\" property, because it is missing on port %d node. "
1057edecfa98SHelmut Grohne 						 "Please update your device tree.\n",
1058edecfa98SHelmut Grohne 						 i);
1059edecfa98SHelmut Grohne 					p->interface = dev->compat_interface;
1060edecfa98SHelmut Grohne 				} else {
1061edecfa98SHelmut Grohne 					p->interface = interface;
1062edecfa98SHelmut Grohne 				}
1063edecfa98SHelmut Grohne 			}
10643ab0a7a0SDavid S. Miller 			if (interface && interface != p->interface) {
1065805a7e6fSPaul Barker 				prev_msg = " instead of ";
1066805a7e6fSPaul Barker 				prev_mode = phy_modes(interface);
1067805a7e6fSPaul Barker 			} else {
1068805a7e6fSPaul Barker 				prev_msg = "";
1069805a7e6fSPaul Barker 				prev_mode = "";
1070805a7e6fSPaul Barker 			}
10718c29bebbSTristram Ha 			dev_info(dev->dev,
1072805a7e6fSPaul Barker 				 "Port%d: using phy mode %s%s%s\n",
1073805a7e6fSPaul Barker 				 i,
1074edecfa98SHelmut Grohne 				 phy_modes(p->interface),
1075805a7e6fSPaul Barker 				 prev_msg,
1076805a7e6fSPaul Barker 				 prev_mode);
10778c29bebbSTristram Ha 
1078c2e86691STristram Ha 			/* enable cpu port */
1079c2e86691STristram Ha 			ksz9477_port_setup(dev, i, true);
1080c2e86691STristram Ha 		}
1081c2e86691STristram Ha 	}
1082c2e86691STristram Ha 
1083462d5250SArun Ramadoss 	for (i = 0; i < dev->info->port_cnt; i++) {
1084c2e86691STristram Ha 		if (i == dev->cpu_port)
1085c2e86691STristram Ha 			continue;
1086e593df51SArun Ramadoss 		ksz_port_stp_state_set(ds, i, BR_STATE_DISABLED);
1087c2e86691STristram Ha 	}
1088c2e86691STristram Ha }
1089c2e86691STristram Ha 
ksz9477_enable_stp_addr(struct ksz_device * dev)10906ec23aaaSArun Ramadoss int ksz9477_enable_stp_addr(struct ksz_device *dev)
1091331d64f7SArun Ramadoss {
1092457c182aSArun Ramadoss 	const u32 *masks;
1093331d64f7SArun Ramadoss 	u32 data;
1094331d64f7SArun Ramadoss 	int ret;
1095331d64f7SArun Ramadoss 
1096457c182aSArun Ramadoss 	masks = dev->info->masks;
1097457c182aSArun Ramadoss 
1098331d64f7SArun Ramadoss 	/* Enable Reserved multicast table */
1099331d64f7SArun Ramadoss 	ksz_cfg(dev, REG_SW_LUE_CTRL_0, SW_RESV_MCAST_ENABLE, true);
1100331d64f7SArun Ramadoss 
1101331d64f7SArun Ramadoss 	/* Set the Override bit for forwarding BPDU packet to CPU */
1102331d64f7SArun Ramadoss 	ret = ksz_write32(dev, REG_SW_ALU_VAL_B,
1103331d64f7SArun Ramadoss 			  ALU_V_OVERRIDE | BIT(dev->cpu_port));
1104331d64f7SArun Ramadoss 	if (ret < 0)
1105331d64f7SArun Ramadoss 		return ret;
1106331d64f7SArun Ramadoss 
1107457c182aSArun Ramadoss 	data = ALU_STAT_START | ALU_RESV_MCAST_ADDR | masks[ALU_STAT_WRITE];
1108331d64f7SArun Ramadoss 
1109331d64f7SArun Ramadoss 	ret = ksz_write32(dev, REG_SW_ALU_STAT_CTRL__4, data);
1110331d64f7SArun Ramadoss 	if (ret < 0)
1111331d64f7SArun Ramadoss 		return ret;
1112331d64f7SArun Ramadoss 
1113331d64f7SArun Ramadoss 	/* wait to be finished */
1114331d64f7SArun Ramadoss 	ret = ksz9477_wait_alu_sta_ready(dev);
1115331d64f7SArun Ramadoss 	if (ret < 0) {
1116331d64f7SArun Ramadoss 		dev_err(dev->dev, "Failed to update Reserved Multicast table\n");
1117331d64f7SArun Ramadoss 		return ret;
1118331d64f7SArun Ramadoss 	}
1119331d64f7SArun Ramadoss 
1120331d64f7SArun Ramadoss 	return 0;
1121331d64f7SArun Ramadoss }
1122331d64f7SArun Ramadoss 
ksz9477_setup(struct dsa_switch * ds)11236ec23aaaSArun Ramadoss int ksz9477_setup(struct dsa_switch *ds)
1124c2e86691STristram Ha {
1125c2e86691STristram Ha 	struct ksz_device *dev = ds->priv;
1126c2e86691STristram Ha 	int ret = 0;
1127c2e86691STristram Ha 
11286b30cfa8SOleksij Rempel 	ds->mtu_enforcement_ingress = true;
11296b30cfa8SOleksij Rempel 
1130962ad710STristram Ha 	/* Required for port partitioning. */
1131962ad710STristram Ha 	ksz9477_cfg32(dev, REG_SW_QM_CTRL__4, UNICAST_VLAN_BOUNDARY,
1132962ad710STristram Ha 		      true);
1133962ad710STristram Ha 
11348c29bebbSTristram Ha 	/* Do not work correctly with tail tagging. */
11358c29bebbSTristram Ha 	ksz_cfg(dev, REG_SW_MAC_CTRL_0, SW_CHECK_LENGTH, false);
11368c29bebbSTristram Ha 
1137e18058eaSOleksij Rempel 	/* Enable REG_SW_MTU__2 reg by setting SW_JUMBO_PACKET */
1138e18058eaSOleksij Rempel 	ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_JUMBO_PACKET, true);
1139e18058eaSOleksij Rempel 
11409d36f631SEnguerrand de Ribaucourt 	/* Use collision based back pressure mode. */
11419d36f631SEnguerrand de Ribaucourt 	ksz_cfg(dev, REG_SW_MAC_CTRL_1, SW_BACK_PRESSURE,
11429d36f631SEnguerrand de Ribaucourt 		SW_BACK_PRESSURE_COLLISION);
11439d36f631SEnguerrand de Ribaucourt 
1144e18058eaSOleksij Rempel 	/* Now we can configure default MTU value */
1145b8311f46SVladimir Oltean 	ret = regmap_update_bits(ksz_regmap_16(dev), REG_SW_MTU__2, REG_SW_MTU_MASK,
1146e18058eaSOleksij Rempel 				 VLAN_ETH_FRAME_LEN + ETH_FCS_LEN);
1147e18058eaSOleksij Rempel 	if (ret)
1148e18058eaSOleksij Rempel 		return ret;
1149c2e86691STristram Ha 
1150c2e86691STristram Ha 	/* queue based egress rate limit */
1151c2e86691STristram Ha 	ksz_cfg(dev, REG_SW_MAC_CTRL_5, SW_OUT_RATE_LIMIT_QUEUE_BASED, true);
1152c2e86691STristram Ha 
11537c6ff470STristram Ha 	/* enable global MIB counter freeze function */
11547c6ff470STristram Ha 	ksz_cfg(dev, REG_SW_MAC_CTRL_6, SW_MIB_COUNTER_FREEZE, true);
11557c6ff470STristram Ha 
1156c2e86691STristram Ha 	return 0;
1157c2e86691STristram Ha }
1158c2e86691STristram Ha 
ksz9477_get_port_addr(int port,int offset)11596ec23aaaSArun Ramadoss u32 ksz9477_get_port_addr(int port, int offset)
1160c2e86691STristram Ha {
1161c2e86691STristram Ha 	return PORT_CTRL_ADDR(port, offset);
1162c2e86691STristram Ha }
1163c2e86691STristram Ha 
ksz9477_tc_cbs_set_cinc(struct ksz_device * dev,int port,u32 val)116471d7920fSArun Ramadoss int ksz9477_tc_cbs_set_cinc(struct ksz_device *dev, int port, u32 val)
116571d7920fSArun Ramadoss {
116671d7920fSArun Ramadoss 	val = val >> 8;
116771d7920fSArun Ramadoss 
116871d7920fSArun Ramadoss 	return ksz_pwrite16(dev, port, REG_PORT_MTI_CREDIT_INCREMENT, val);
116971d7920fSArun Ramadoss }
117071d7920fSArun Ramadoss 
ksz9477_switch_init(struct ksz_device * dev)11716ec23aaaSArun Ramadoss int ksz9477_switch_init(struct ksz_device *dev)
117227faa0aaSArun Ramadoss {
117327faa0aaSArun Ramadoss 	u8 data8;
117427faa0aaSArun Ramadoss 	int ret;
117527faa0aaSArun Ramadoss 
117627faa0aaSArun Ramadoss 	dev->port_mask = (1 << dev->info->port_cnt) - 1;
117727faa0aaSArun Ramadoss 
1178c2e86691STristram Ha 	/* turn off SPI DO Edge select */
1179c2e86691STristram Ha 	ret = ksz_read8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, &data8);
1180c2e86691STristram Ha 	if (ret)
1181c2e86691STristram Ha 		return ret;
1182c2e86691STristram Ha 
1183c2e86691STristram Ha 	data8 &= ~SPI_AUTO_EDGE_DETECTION;
1184c2e86691STristram Ha 	ret = ksz_write8(dev, REG_SW_GLOBAL_SERIAL_CTRL_0, data8);
1185c2e86691STristram Ha 	if (ret)
1186c2e86691STristram Ha 		return ret;
1187c2e86691STristram Ha 
1188c2e86691STristram Ha 	return 0;
1189c2e86691STristram Ha }
1190c2e86691STristram Ha 
ksz9477_switch_exit(struct ksz_device * dev)11916ec23aaaSArun Ramadoss void ksz9477_switch_exit(struct ksz_device *dev)
1192c2e86691STristram Ha {
1193c2e86691STristram Ha 	ksz9477_reset_switch(dev);
1194c2e86691STristram Ha }
1195c2e86691STristram Ha 
1196c2e86691STristram Ha MODULE_AUTHOR("Woojung Huh <Woojung.Huh@microchip.com>");
1197c2e86691STristram Ha MODULE_DESCRIPTION("Microchip KSZ9477 Series Switch DSA Driver");
1198c2e86691STristram Ha MODULE_LICENSE("GPL");
1199