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