xref: /linux/drivers/net/dsa/vitesse-vsc73xx-core.c (revision 07d6bf634bc8f93caf8920c9d61df761645336e2)
195711cd5SPawel Dembicki // SPDX-License-Identifier: GPL-2.0
295711cd5SPawel Dembicki /* DSA driver for:
395711cd5SPawel Dembicki  * Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
495711cd5SPawel Dembicki  * Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
595711cd5SPawel Dembicki  * Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
695711cd5SPawel Dembicki  * Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
795711cd5SPawel Dembicki  *
895711cd5SPawel Dembicki  * These switches have a built-in 8051 CPU and can download and execute a
995711cd5SPawel Dembicki  * firmware in this CPU. They can also be configured to use an external CPU
1095711cd5SPawel Dembicki  * handling the switch in a memory-mapped manner by connecting to that external
1195711cd5SPawel Dembicki  * CPU's memory bus.
1295711cd5SPawel Dembicki  *
1395711cd5SPawel Dembicki  * Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
1495711cd5SPawel Dembicki  * Includes portions of code from the firmware uploader by:
1595711cd5SPawel Dembicki  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
1695711cd5SPawel Dembicki  */
1795711cd5SPawel Dembicki #include <linux/kernel.h>
1895711cd5SPawel Dembicki #include <linux/module.h>
1995711cd5SPawel Dembicki #include <linux/device.h>
20eb7e33d0SPawel Dembicki #include <linux/iopoll.h>
2195711cd5SPawel Dembicki #include <linux/of.h>
2295711cd5SPawel Dembicki #include <linux/of_mdio.h>
2395711cd5SPawel Dembicki #include <linux/bitops.h>
242524d6c2SPawel Dembicki #include <linux/bitfield.h>
2595711cd5SPawel Dembicki #include <linux/if_bridge.h>
266b783dedSPawel Dembicki #include <linux/if_vlan.h>
2795711cd5SPawel Dembicki #include <linux/etherdevice.h>
2895711cd5SPawel Dembicki #include <linux/gpio/consumer.h>
2995711cd5SPawel Dembicki #include <linux/gpio/driver.h>
306b783dedSPawel Dembicki #include <linux/dsa/8021q.h>
3195711cd5SPawel Dembicki #include <linux/random.h>
3295711cd5SPawel Dembicki #include <net/dsa.h>
3395711cd5SPawel Dembicki 
3495711cd5SPawel Dembicki #include "vitesse-vsc73xx.h"
3595711cd5SPawel Dembicki 
3695711cd5SPawel Dembicki #define VSC73XX_BLOCK_MAC	0x1 /* Subblocks 0-4, 6 (CPU port) */
3795711cd5SPawel Dembicki #define VSC73XX_BLOCK_ANALYZER	0x2 /* Only subblock 0 */
3895711cd5SPawel Dembicki #define VSC73XX_BLOCK_MII	0x3 /* Subblocks 0 and 1 */
3995711cd5SPawel Dembicki #define VSC73XX_BLOCK_MEMINIT	0x3 /* Only subblock 2 */
408e69c96dSPawel Dembicki #define VSC73XX_BLOCK_CAPTURE	0x4 /* Subblocks 0-4, 6, 7 */
4195711cd5SPawel Dembicki #define VSC73XX_BLOCK_ARBITER	0x5 /* Only subblock 0 */
4295711cd5SPawel Dembicki #define VSC73XX_BLOCK_SYSTEM	0x7 /* Only subblock 0 */
4395711cd5SPawel Dembicki 
448d5be2c4SPawel Dembicki /* MII Block subblock */
458d5be2c4SPawel Dembicki #define VSC73XX_BLOCK_MII_INTERNAL	0x0 /* Internal MDIO subblock */
462524d6c2SPawel Dembicki #define VSC73XX_BLOCK_MII_EXTERNAL	0x1 /* External MDIO subblock */
478d5be2c4SPawel Dembicki 
4895711cd5SPawel Dembicki #define CPU_PORT	6 /* CPU port */
49*075e3d30SPawel Dembicki #define VSC73XX_NUM_FDB_ROWS	2048
50*075e3d30SPawel Dembicki #define VSC73XX_NUM_BUCKETS	4
5195711cd5SPawel Dembicki 
5295711cd5SPawel Dembicki /* MAC Block registers */
5395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG		0x00
5495711cd5SPawel Dembicki #define VSC73XX_MACHDXGAP	0x02
5595711cd5SPawel Dembicki #define VSC73XX_FCCONF		0x04
5695711cd5SPawel Dembicki #define VSC73XX_FCMACHI		0x08
5795711cd5SPawel Dembicki #define VSC73XX_FCMACLO		0x0c
5895711cd5SPawel Dembicki #define VSC73XX_MAXLEN		0x10
5995711cd5SPawel Dembicki #define VSC73XX_ADVPORTM	0x19
6095711cd5SPawel Dembicki #define VSC73XX_TXUPDCFG	0x24
6195711cd5SPawel Dembicki #define VSC73XX_TXQ_SELECT_CFG	0x28
6295711cd5SPawel Dembicki #define VSC73XX_RXOCT		0x50
6395711cd5SPawel Dembicki #define VSC73XX_TXOCT		0x51
6495711cd5SPawel Dembicki #define VSC73XX_C_RX0		0x52
6595711cd5SPawel Dembicki #define VSC73XX_C_RX1		0x53
6695711cd5SPawel Dembicki #define VSC73XX_C_RX2		0x54
6795711cd5SPawel Dembicki #define VSC73XX_C_TX0		0x55
6895711cd5SPawel Dembicki #define VSC73XX_C_TX1		0x56
6995711cd5SPawel Dembicki #define VSC73XX_C_TX2		0x57
7095711cd5SPawel Dembicki #define VSC73XX_C_CFG		0x58
7195711cd5SPawel Dembicki #define VSC73XX_CAT_DROP	0x6e
7295711cd5SPawel Dembicki #define VSC73XX_CAT_PR_MISC_L2	0x6f
7395711cd5SPawel Dembicki #define VSC73XX_CAT_PR_USR_PRIO	0x75
746b783dedSPawel Dembicki #define VSC73XX_CAT_VLAN_MISC	0x79
756b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN	0x7a
7695711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF	0xdf
7795711cd5SPawel Dembicki 
7895711cd5SPawel Dembicki /* MAC_CFG register bits */
7995711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_WEXC_DIS	BIT(31)
8095711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_PORT_RST	BIT(29)
8195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_EN		BIT(28)
8295711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_SEED_LOAD	BIT(27)
8395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_SEED_MASK	GENMASK(26, 19)
8495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_SEED_OFFSET	19
8595711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_FDX		BIT(18)
8695711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_GIGA_MODE	BIT(17)
8795711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_RX_EN		BIT(16)
8895711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_VLAN_DBLAWR	BIT(15)
8995711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_VLAN_AWR	BIT(14)
9095711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_100_BASE_T	BIT(13) /* Not in manual */
9195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_MASK	GENMASK(10, 6)
9295711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_OFFSET	6
9395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_1000M	(6 << VSC73XX_MAC_CFG_TX_IPG_OFFSET)
9495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_100_10M	(17 << VSC73XX_MAC_CFG_TX_IPG_OFFSET)
9595711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_MAC_RX_RST	BIT(5)
9695711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_MAC_TX_RST	BIT(4)
9795711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_MASK	GENMASK(2, 0)
9895711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_OFFSET	0
9995711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_1000M	1
10095711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_100M	2
10195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_10M	3
10295711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_EXT	4
10395711cd5SPawel Dembicki 
10495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_1000M_F_PHY	(VSC73XX_MAC_CFG_FDX | \
10595711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_GIGA_MODE | \
10695711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_TX_IPG_1000M | \
10795711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_EXT)
10895711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_100_10M_F_PHY	(VSC73XX_MAC_CFG_FDX | \
10995711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_TX_IPG_100_10M | \
11095711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_EXT)
11195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_100_10M_H_PHY	(VSC73XX_MAC_CFG_TX_IPG_100_10M | \
11295711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_EXT)
11395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_1000M_F_RGMII	(VSC73XX_MAC_CFG_FDX | \
11495711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_GIGA_MODE | \
11595711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_TX_IPG_1000M | \
11695711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_1000M)
11795711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_RESET		(VSC73XX_MAC_CFG_PORT_RST | \
11895711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_MAC_RX_RST | \
11995711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_MAC_TX_RST)
12095711cd5SPawel Dembicki 
12195711cd5SPawel Dembicki /* Flow control register bits */
12295711cd5SPawel Dembicki #define VSC73XX_FCCONF_ZERO_PAUSE_EN	BIT(17)
12395711cd5SPawel Dembicki #define VSC73XX_FCCONF_FLOW_CTRL_OBEY	BIT(16)
12495711cd5SPawel Dembicki #define VSC73XX_FCCONF_PAUSE_VAL_MASK	GENMASK(15, 0)
12595711cd5SPawel Dembicki 
12695711cd5SPawel Dembicki /* ADVPORTM advanced port setup register bits */
12795711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_IFG_PPM	BIT(7)
12895711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_EXC_COL_CONT	BIT(6)
12995711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_EXT_PORT	BIT(5)
13095711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_INV_GTX	BIT(4)
13195711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_ENA_GTX	BIT(3)
13295711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_DDR_MODE	BIT(2)
13395711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_IO_LOOPBACK	BIT(1)
13495711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_HOST_LOOPBACK	BIT(0)
13595711cd5SPawel Dembicki 
1366b783dedSPawel Dembicki /*  TXUPDCFG transmit modify setup bits */
1376b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_DSCP_REWR_MODE	GENMASK(20, 19)
1386b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_DSCP_REWR_ENA	BIT(18)
1396b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_INT_TO_USRPRIO_ENA	BIT(17)
1406b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UNTAGGED_VID	GENMASK(15, 4)
1416b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_ENA	BIT(3)
1426b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UPDATE_CRC_CPU_ENA	BIT(1)
1436b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_INSERT_TAG	BIT(0)
1446b783dedSPawel Dembicki 
1456b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_SHIFT	4
1466b783dedSPawel Dembicki 
14795711cd5SPawel Dembicki /* CAT_DROP categorizer frame dropping register bits */
14895711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_DROP_MC_SMAC_ENA	BIT(6)
14995711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_FWD_CTRL_ENA		BIT(4)
15095711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_FWD_PAUSE_ENA		BIT(3)
15195711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_UNTAGGED_ENA		BIT(2)
15295711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_TAGGED_ENA		BIT(1)
15395711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_NULL_MAC_ENA		BIT(0)
15495711cd5SPawel Dembicki 
15595711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_EXTENT_MEM		BIT(31)
15695711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_EARLY_TX_MASK	GENMASK(4, 1)
15795711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_EARLY_TX_512	(1 << 1)
15895711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE	BIT(0)
15995711cd5SPawel Dembicki 
1606b783dedSPawel Dembicki /* CAT_VLAN_MISC categorizer VLAN miscellaneous bits */
1616b783dedSPawel Dembicki #define VSC73XX_CAT_VLAN_MISC_VLAN_TCI_IGNORE_ENA BIT(8)
1626b783dedSPawel Dembicki #define VSC73XX_CAT_VLAN_MISC_VLAN_KEEP_TAG_ENA BIT(7)
1636b783dedSPawel Dembicki 
1646b783dedSPawel Dembicki /* CAT_PORT_VLAN categorizer port VLAN */
1656b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN_VLAN_CFI BIT(15)
1666b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN_VLAN_USR_PRIO GENMASK(14, 12)
1676b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN_VLAN_VID GENMASK(11, 0)
1686b783dedSPawel Dembicki 
16995711cd5SPawel Dembicki /* Frame analyzer block 2 registers */
17095711cd5SPawel Dembicki #define VSC73XX_STORMLIMIT	0x02
17195711cd5SPawel Dembicki #define VSC73XX_ADVLEARN	0x03
17295711cd5SPawel Dembicki #define VSC73XX_IFLODMSK	0x04
17395711cd5SPawel Dembicki #define VSC73XX_VLANMASK	0x05
17495711cd5SPawel Dembicki #define VSC73XX_MACHDATA	0x06
17595711cd5SPawel Dembicki #define VSC73XX_MACLDATA	0x07
17695711cd5SPawel Dembicki #define VSC73XX_ANMOVED		0x08
17795711cd5SPawel Dembicki #define VSC73XX_ANAGEFIL	0x09
17895711cd5SPawel Dembicki #define VSC73XX_ANEVENTS	0x0a
17995711cd5SPawel Dembicki #define VSC73XX_ANCNTMASK	0x0b
18095711cd5SPawel Dembicki #define VSC73XX_ANCNTVAL	0x0c
18195711cd5SPawel Dembicki #define VSC73XX_LEARNMASK	0x0d
18295711cd5SPawel Dembicki #define VSC73XX_UFLODMASK	0x0e
18395711cd5SPawel Dembicki #define VSC73XX_MFLODMASK	0x0f
18495711cd5SPawel Dembicki #define VSC73XX_RECVMASK	0x10
18595711cd5SPawel Dembicki #define VSC73XX_AGGRCTRL	0x20
18695711cd5SPawel Dembicki #define VSC73XX_AGGRMSKS	0x30 /* Until 0x3f */
18795711cd5SPawel Dembicki #define VSC73XX_DSTMASKS	0x40 /* Until 0x7f */
18895711cd5SPawel Dembicki #define VSC73XX_SRCMASKS	0x80 /* Until 0x87 */
18995711cd5SPawel Dembicki #define VSC73XX_CAPENAB		0xa0
19095711cd5SPawel Dembicki #define VSC73XX_MACACCESS	0xb0
19195711cd5SPawel Dembicki #define VSC73XX_IPMCACCESS	0xb1
19295711cd5SPawel Dembicki #define VSC73XX_MACTINDX	0xc0
19395711cd5SPawel Dembicki #define VSC73XX_VLANACCESS	0xd0
19495711cd5SPawel Dembicki #define VSC73XX_VLANTIDX	0xe0
19595711cd5SPawel Dembicki #define VSC73XX_AGENCTRL	0xf0
19695711cd5SPawel Dembicki #define VSC73XX_CAPRST		0xff
19795711cd5SPawel Dembicki 
1981e5b23e5SPawel Dembicki #define VSC73XX_SRCMASKS_CPU_COPY		BIT(27)
1991e5b23e5SPawel Dembicki #define VSC73XX_SRCMASKS_MIRROR			BIT(26)
2001e5b23e5SPawel Dembicki #define VSC73XX_SRCMASKS_PORTS_MASK		GENMASK(7, 0)
2011e5b23e5SPawel Dembicki 
202*075e3d30SPawel Dembicki #define VSC73XX_MACHDATA_VID			GENMASK(27, 16)
203*075e3d30SPawel Dembicki #define VSC73XX_MACHDATA_MAC0			GENMASK(15, 8)
204*075e3d30SPawel Dembicki #define VSC73XX_MACHDATA_MAC1			GENMASK(7, 0)
205*075e3d30SPawel Dembicki #define VSC73XX_MACLDATA_MAC2			GENMASK(31, 24)
206*075e3d30SPawel Dembicki #define VSC73XX_MACLDATA_MAC3			GENMASK(23, 16)
207*075e3d30SPawel Dembicki #define VSC73XX_MACLDATA_MAC4			GENMASK(15, 8)
208*075e3d30SPawel Dembicki #define VSC73XX_MACLDATA_MAC5			GENMASK(7, 0)
209*075e3d30SPawel Dembicki 
210*075e3d30SPawel Dembicki #define VSC73XX_HASH0_VID_FROM_MASK		GENMASK(5, 0)
211*075e3d30SPawel Dembicki #define VSC73XX_HASH0_MAC0_FROM_MASK		GENMASK(7, 4)
212*075e3d30SPawel Dembicki #define VSC73XX_HASH1_MAC0_FROM_MASK		GENMASK(3, 0)
213*075e3d30SPawel Dembicki #define VSC73XX_HASH1_MAC1_FROM_MASK		GENMASK(7, 1)
214*075e3d30SPawel Dembicki #define VSC73XX_HASH2_MAC1_FROM_MASK		BIT(0)
215*075e3d30SPawel Dembicki #define VSC73XX_HASH2_MAC2_FROM_MASK		GENMASK(7, 0)
216*075e3d30SPawel Dembicki #define VSC73XX_HASH2_MAC3_FROM_MASK		GENMASK(7, 6)
217*075e3d30SPawel Dembicki #define VSC73XX_HASH3_MAC3_FROM_MASK		GENMASK(5, 0)
218*075e3d30SPawel Dembicki #define VSC73XX_HASH3_MAC4_FROM_MASK		GENMASK(7, 3)
219*075e3d30SPawel Dembicki #define VSC73XX_HASH4_MAC4_FROM_MASK		GENMASK(2, 0)
220*075e3d30SPawel Dembicki 
221*075e3d30SPawel Dembicki #define VSC73XX_HASH0_VID_TO_MASK		GENMASK(9, 4)
222*075e3d30SPawel Dembicki #define VSC73XX_HASH0_MAC0_TO_MASK		GENMASK(3, 0)
223*075e3d30SPawel Dembicki #define VSC73XX_HASH1_MAC0_TO_MASK		GENMASK(10, 7)
224*075e3d30SPawel Dembicki #define VSC73XX_HASH1_MAC1_TO_MASK		GENMASK(6, 0)
225*075e3d30SPawel Dembicki #define VSC73XX_HASH2_MAC1_TO_MASK		BIT(10)
226*075e3d30SPawel Dembicki #define VSC73XX_HASH2_MAC2_TO_MASK		GENMASK(9, 2)
227*075e3d30SPawel Dembicki #define VSC73XX_HASH2_MAC3_TO_MASK		GENMASK(1, 0)
228*075e3d30SPawel Dembicki #define VSC73XX_HASH3_MAC3_TO_MASK		GENMASK(10, 5)
229*075e3d30SPawel Dembicki #define VSC73XX_HASH3_MAC4_TO_MASK		GENMASK(4, 0)
230*075e3d30SPawel Dembicki #define VSC73XX_HASH4_MAC4_TO_MASK		GENMASK(10, 8)
231*075e3d30SPawel Dembicki 
232*075e3d30SPawel Dembicki #define VSC73XX_MACTINDX_SHADOW			BIT(13)
233*075e3d30SPawel Dembicki #define VSC73XX_MACTINDX_BUCKET_MSK		GENMASK(12, 11)
234*075e3d30SPawel Dembicki #define VSC73XX_MACTINDX_INDEX_MSK		GENMASK(10, 0)
235*075e3d30SPawel Dembicki 
23695711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CPU_COPY		BIT(14)
23795711cd5SPawel Dembicki #define VSC73XX_MACACCESS_FWD_KILL		BIT(13)
23895711cd5SPawel Dembicki #define VSC73XX_MACACCESS_IGNORE_VLAN		BIT(12)
23995711cd5SPawel Dembicki #define VSC73XX_MACACCESS_AGED_FLAG		BIT(11)
24095711cd5SPawel Dembicki #define VSC73XX_MACACCESS_VALID			BIT(10)
24195711cd5SPawel Dembicki #define VSC73XX_MACACCESS_LOCKED		BIT(9)
24295711cd5SPawel Dembicki #define VSC73XX_MACACCESS_DEST_IDX_MASK		GENMASK(8, 3)
24395711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_MASK		GENMASK(2, 0)
24495711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_IDLE		0
24595711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_LEARN		1
24695711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_FORGET		2
24795711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_AGE_TABLE		3
24895711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_FLUSH_TABLE	4
24995711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_CLEAR_TABLE	5
25095711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_READ_ENTRY	6
25195711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_WRITE_ENTRY	7
25295711cd5SPawel Dembicki 
25395711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_LEARN_DISABLED	BIT(30)
25495711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_MIRROR		BIT(29)
25595711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_SRC_CHECK	BIT(28)
25695711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_PORT_MASK	GENMASK(9, 2)
2576b783dedSPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_PORT_MASK_SHIFT	2
2586b783dedSPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK	GENMASK(1, 0)
25995711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_IDLE	0
26095711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_READ_ENTRY	1
26195711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_WRITE_ENTRY	2
26295711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE	3
26395711cd5SPawel Dembicki 
26495711cd5SPawel Dembicki /* MII block 3 registers */
26595711cd5SPawel Dembicki #define VSC73XX_MII_STAT		0x0
26695711cd5SPawel Dembicki #define VSC73XX_MII_CMD			0x1
26795711cd5SPawel Dembicki #define VSC73XX_MII_DATA		0x2
2688d5be2c4SPawel Dembicki #define VSC73XX_MII_MPRES		0x3
2698d5be2c4SPawel Dembicki 
2702524d6c2SPawel Dembicki #define VSC73XX_MII_STAT_BUSY		BIT(3)
2712524d6c2SPawel Dembicki #define VSC73XX_MII_STAT_READ		BIT(2)
2722524d6c2SPawel Dembicki #define VSC73XX_MII_STAT_WRITE		BIT(1)
2732524d6c2SPawel Dembicki 
2742524d6c2SPawel Dembicki #define VSC73XX_MII_CMD_SCAN		BIT(27)
2752524d6c2SPawel Dembicki #define VSC73XX_MII_CMD_OPERATION	BIT(26)
2762524d6c2SPawel Dembicki #define VSC73XX_MII_CMD_PHY_ADDR	GENMASK(25, 21)
2772524d6c2SPawel Dembicki #define VSC73XX_MII_CMD_PHY_REG		GENMASK(20, 16)
2782524d6c2SPawel Dembicki #define VSC73XX_MII_CMD_WRITE_DATA	GENMASK(15, 0)
2792524d6c2SPawel Dembicki 
2802524d6c2SPawel Dembicki #define VSC73XX_MII_DATA_FAILURE	BIT(16)
2812524d6c2SPawel Dembicki #define VSC73XX_MII_DATA_READ_DATA	GENMASK(15, 0)
2822524d6c2SPawel Dembicki 
2838d5be2c4SPawel Dembicki #define VSC73XX_MII_MPRES_NOPREAMBLE	BIT(6)
2848d5be2c4SPawel Dembicki #define VSC73XX_MII_MPRES_PRESCALEVAL	GENMASK(5, 0)
2858d5be2c4SPawel Dembicki #define VSC73XX_MII_PRESCALEVAL_MIN	3 /* min allowed mdio clock prescaler */
28695711cd5SPawel Dembicki 
287fa63c643SPawel Dembicki #define VSC73XX_MII_STAT_BUSY	BIT(3)
288fa63c643SPawel Dembicki 
28995711cd5SPawel Dembicki /* Arbiter block 5 registers */
29095711cd5SPawel Dembicki #define VSC73XX_ARBEMPTY		0x0c
29195711cd5SPawel Dembicki #define VSC73XX_ARBDISC			0x0e
29295711cd5SPawel Dembicki #define VSC73XX_SBACKWDROP		0x12
29395711cd5SPawel Dembicki #define VSC73XX_DBACKWDROP		0x13
29495711cd5SPawel Dembicki #define VSC73XX_ARBBURSTPROB		0x15
29595711cd5SPawel Dembicki 
29695711cd5SPawel Dembicki /* System block 7 registers */
29795711cd5SPawel Dembicki #define VSC73XX_ICPU_SIPAD		0x01
29895711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY		0x05
29995711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL		0x10
30095711cd5SPawel Dembicki #define VSC73XX_ICPU_ADDR		0x11
30195711cd5SPawel Dembicki #define VSC73XX_ICPU_SRAM		0x12
30295711cd5SPawel Dembicki #define VSC73XX_HWSEM			0x13
30395711cd5SPawel Dembicki #define VSC73XX_GLORESET		0x14
30495711cd5SPawel Dembicki #define VSC73XX_ICPU_MBOX_VAL		0x15
30595711cd5SPawel Dembicki #define VSC73XX_ICPU_MBOX_SET		0x16
30695711cd5SPawel Dembicki #define VSC73XX_ICPU_MBOX_CLR		0x17
30795711cd5SPawel Dembicki #define VSC73XX_CHIPID			0x18
30895711cd5SPawel Dembicki #define VSC73XX_GPIO			0x34
30995711cd5SPawel Dembicki 
31095711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_NONE	0
31195711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_4_NS	1
31295711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_7_NS	2
31395711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_2_0_NS	3
31495711cd5SPawel Dembicki 
31595711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_NONE	(0 << 4)
31695711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_4_NS	(1 << 4)
31795711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_7_NS	(2 << 4)
31895711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_2_0_NS	(3 << 4)
31995711cd5SPawel Dembicki 
32095711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_WATCHDOG_RST	BIT(31)
32195711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_CLK_DIV_MASK	GENMASK(12, 8)
32295711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_SRST_HOLD	BIT(7)
32395711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_ICPU_PI_EN	BIT(6)
32495711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_BOOT_EN	BIT(3)
32595711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_EXT_ACC_EN	BIT(2)
32695711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_CLK_EN	BIT(1)
32795711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_SRST		BIT(0)
32895711cd5SPawel Dembicki 
32995711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_SHIFT		12
33095711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_MASK		0xffff
33195711cd5SPawel Dembicki #define VSC73XX_CHIPID_REV_SHIFT	28
33295711cd5SPawel Dembicki #define VSC73XX_CHIPID_REV_MASK		0xf
33395711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7385		0x7385
33495711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7388		0x7388
33595711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7395		0x7395
33695711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7398		0x7398
33795711cd5SPawel Dembicki 
33895711cd5SPawel Dembicki #define VSC73XX_GLORESET_STROBE		BIT(4)
33995711cd5SPawel Dembicki #define VSC73XX_GLORESET_ICPU_LOCK	BIT(3)
34095711cd5SPawel Dembicki #define VSC73XX_GLORESET_MEM_LOCK	BIT(2)
34195711cd5SPawel Dembicki #define VSC73XX_GLORESET_PHY_RESET	BIT(1)
34295711cd5SPawel Dembicki #define VSC73XX_GLORESET_MASTER_RESET	BIT(0)
34395711cd5SPawel Dembicki 
34495711cd5SPawel Dembicki #define VSC7385_CLOCK_DELAY		((3 << 4) | 3)
34595711cd5SPawel Dembicki #define VSC7385_CLOCK_DELAY_MASK	((3 << 4) | 3)
34695711cd5SPawel Dembicki 
34795711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_STOP	(VSC73XX_ICPU_CTRL_SRST_HOLD | \
34895711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_BOOT_EN | \
34995711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_EXT_ACC_EN)
35095711cd5SPawel Dembicki 
35195711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_START	(VSC73XX_ICPU_CTRL_CLK_DIV | \
35295711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_BOOT_EN | \
35395711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_CLK_EN | \
35495711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_SRST)
35595711cd5SPawel Dembicki 
35695711cd5SPawel Dembicki #define IS_7385(a) ((a)->chipid == VSC73XX_CHIPID_ID_7385)
35795711cd5SPawel Dembicki #define IS_7388(a) ((a)->chipid == VSC73XX_CHIPID_ID_7388)
35895711cd5SPawel Dembicki #define IS_7395(a) ((a)->chipid == VSC73XX_CHIPID_ID_7395)
35995711cd5SPawel Dembicki #define IS_7398(a) ((a)->chipid == VSC73XX_CHIPID_ID_7398)
36095711cd5SPawel Dembicki #define IS_739X(a) (IS_7395(a) || IS_7398(a))
36195711cd5SPawel Dembicki 
362eb7e33d0SPawel Dembicki #define VSC73XX_POLL_SLEEP_US		1000
363fa63c643SPawel Dembicki #define VSC73XX_MDIO_POLL_SLEEP_US	5
364eb7e33d0SPawel Dembicki #define VSC73XX_POLL_TIMEOUT_US		10000
365eb7e33d0SPawel Dembicki 
36695711cd5SPawel Dembicki struct vsc73xx_counter {
36795711cd5SPawel Dembicki 	u8 counter;
36895711cd5SPawel Dembicki 	const char *name;
36995711cd5SPawel Dembicki };
37095711cd5SPawel Dembicki 
371*075e3d30SPawel Dembicki struct vsc73xx_fdb {
372*075e3d30SPawel Dembicki 	u16 vid;
373*075e3d30SPawel Dembicki 	u8 port;
374*075e3d30SPawel Dembicki 	u8 mac[ETH_ALEN];
375*075e3d30SPawel Dembicki 	bool valid;
376*075e3d30SPawel Dembicki };
377*075e3d30SPawel Dembicki 
37895711cd5SPawel Dembicki /* Counters are named according to the MIB standards where applicable.
37995711cd5SPawel Dembicki  * Some counters are custom, non-standard. The standard counters are
38095711cd5SPawel Dembicki  * named in accordance with RFC2819, RFC2021 and IEEE Std 802.3-2002 Annex
38195711cd5SPawel Dembicki  * 30A Counters.
38295711cd5SPawel Dembicki  */
38395711cd5SPawel Dembicki static const struct vsc73xx_counter vsc73xx_rx_counters[] = {
38495711cd5SPawel Dembicki 	{ 0, "RxEtherStatsPkts" },
38595711cd5SPawel Dembicki 	{ 1, "RxBroadcast+MulticastPkts" }, /* non-standard counter */
38695711cd5SPawel Dembicki 	{ 2, "RxTotalErrorPackets" }, /* non-standard counter */
38795711cd5SPawel Dembicki 	{ 3, "RxEtherStatsBroadcastPkts" },
38895711cd5SPawel Dembicki 	{ 4, "RxEtherStatsMulticastPkts" },
38995711cd5SPawel Dembicki 	{ 5, "RxEtherStatsPkts64Octets" },
39095711cd5SPawel Dembicki 	{ 6, "RxEtherStatsPkts65to127Octets" },
39195711cd5SPawel Dembicki 	{ 7, "RxEtherStatsPkts128to255Octets" },
39295711cd5SPawel Dembicki 	{ 8, "RxEtherStatsPkts256to511Octets" },
39395711cd5SPawel Dembicki 	{ 9, "RxEtherStatsPkts512to1023Octets" },
39495711cd5SPawel Dembicki 	{ 10, "RxEtherStatsPkts1024to1518Octets" },
39595711cd5SPawel Dembicki 	{ 11, "RxJumboFrames" }, /* non-standard counter */
39695711cd5SPawel Dembicki 	{ 12, "RxaPauseMACControlFramesTransmitted" },
39795711cd5SPawel Dembicki 	{ 13, "RxFIFODrops" }, /* non-standard counter */
39895711cd5SPawel Dembicki 	{ 14, "RxBackwardDrops" }, /* non-standard counter */
39995711cd5SPawel Dembicki 	{ 15, "RxClassifierDrops" }, /* non-standard counter */
40095711cd5SPawel Dembicki 	{ 16, "RxEtherStatsCRCAlignErrors" },
40195711cd5SPawel Dembicki 	{ 17, "RxEtherStatsUndersizePkts" },
40295711cd5SPawel Dembicki 	{ 18, "RxEtherStatsOversizePkts" },
40395711cd5SPawel Dembicki 	{ 19, "RxEtherStatsFragments" },
40495711cd5SPawel Dembicki 	{ 20, "RxEtherStatsJabbers" },
40595711cd5SPawel Dembicki 	{ 21, "RxaMACControlFramesReceived" },
40695711cd5SPawel Dembicki 	/* 22-24 are undefined */
40795711cd5SPawel Dembicki 	{ 25, "RxaFramesReceivedOK" },
40895711cd5SPawel Dembicki 	{ 26, "RxQoSClass0" }, /* non-standard counter */
40995711cd5SPawel Dembicki 	{ 27, "RxQoSClass1" }, /* non-standard counter */
41095711cd5SPawel Dembicki 	{ 28, "RxQoSClass2" }, /* non-standard counter */
41195711cd5SPawel Dembicki 	{ 29, "RxQoSClass3" }, /* non-standard counter */
41295711cd5SPawel Dembicki };
41395711cd5SPawel Dembicki 
41495711cd5SPawel Dembicki static const struct vsc73xx_counter vsc73xx_tx_counters[] = {
41595711cd5SPawel Dembicki 	{ 0, "TxEtherStatsPkts" },
41695711cd5SPawel Dembicki 	{ 1, "TxBroadcast+MulticastPkts" }, /* non-standard counter */
41795711cd5SPawel Dembicki 	{ 2, "TxTotalErrorPackets" }, /* non-standard counter */
41895711cd5SPawel Dembicki 	{ 3, "TxEtherStatsBroadcastPkts" },
41995711cd5SPawel Dembicki 	{ 4, "TxEtherStatsMulticastPkts" },
42095711cd5SPawel Dembicki 	{ 5, "TxEtherStatsPkts64Octets" },
42195711cd5SPawel Dembicki 	{ 6, "TxEtherStatsPkts65to127Octets" },
42295711cd5SPawel Dembicki 	{ 7, "TxEtherStatsPkts128to255Octets" },
42395711cd5SPawel Dembicki 	{ 8, "TxEtherStatsPkts256to511Octets" },
42495711cd5SPawel Dembicki 	{ 9, "TxEtherStatsPkts512to1023Octets" },
42595711cd5SPawel Dembicki 	{ 10, "TxEtherStatsPkts1024to1518Octets" },
42695711cd5SPawel Dembicki 	{ 11, "TxJumboFrames" }, /* non-standard counter */
42795711cd5SPawel Dembicki 	{ 12, "TxaPauseMACControlFramesTransmitted" },
42895711cd5SPawel Dembicki 	{ 13, "TxFIFODrops" }, /* non-standard counter */
42995711cd5SPawel Dembicki 	{ 14, "TxDrops" }, /* non-standard counter */
43095711cd5SPawel Dembicki 	{ 15, "TxEtherStatsCollisions" },
43195711cd5SPawel Dembicki 	{ 16, "TxEtherStatsCRCAlignErrors" },
43295711cd5SPawel Dembicki 	{ 17, "TxEtherStatsUndersizePkts" },
43395711cd5SPawel Dembicki 	{ 18, "TxEtherStatsOversizePkts" },
43495711cd5SPawel Dembicki 	{ 19, "TxEtherStatsFragments" },
43595711cd5SPawel Dembicki 	{ 20, "TxEtherStatsJabbers" },
43695711cd5SPawel Dembicki 	/* 21-24 are undefined */
43795711cd5SPawel Dembicki 	{ 25, "TxaFramesReceivedOK" },
43895711cd5SPawel Dembicki 	{ 26, "TxQoSClass0" }, /* non-standard counter */
43995711cd5SPawel Dembicki 	{ 27, "TxQoSClass1" }, /* non-standard counter */
44095711cd5SPawel Dembicki 	{ 28, "TxQoSClass2" }, /* non-standard counter */
44195711cd5SPawel Dembicki 	{ 29, "TxQoSClass3" }, /* non-standard counter */
44295711cd5SPawel Dembicki };
44395711cd5SPawel Dembicki 
4446b783dedSPawel Dembicki struct vsc73xx_vlan_summary {
4456b783dedSPawel Dembicki 	size_t num_tagged;
4466b783dedSPawel Dembicki 	size_t num_untagged;
4476b783dedSPawel Dembicki };
4486b783dedSPawel Dembicki 
4496b783dedSPawel Dembicki enum vsc73xx_port_vlan_conf {
4506b783dedSPawel Dembicki 	VSC73XX_VLAN_FILTER,
4516b783dedSPawel Dembicki 	VSC73XX_VLAN_FILTER_UNTAG_ALL,
4526b783dedSPawel Dembicki 	VSC73XX_VLAN_IGNORE,
4536b783dedSPawel Dembicki };
4546b783dedSPawel Dembicki 
vsc73xx_is_addr_valid(u8 block,u8 subblock)45595711cd5SPawel Dembicki int vsc73xx_is_addr_valid(u8 block, u8 subblock)
45695711cd5SPawel Dembicki {
45795711cd5SPawel Dembicki 	switch (block) {
45895711cd5SPawel Dembicki 	case VSC73XX_BLOCK_MAC:
45995711cd5SPawel Dembicki 		switch (subblock) {
46095711cd5SPawel Dembicki 		case 0 ... 4:
46195711cd5SPawel Dembicki 		case 6:
46295711cd5SPawel Dembicki 			return 1;
46395711cd5SPawel Dembicki 		}
46495711cd5SPawel Dembicki 		break;
46595711cd5SPawel Dembicki 
46695711cd5SPawel Dembicki 	case VSC73XX_BLOCK_ANALYZER:
46795711cd5SPawel Dembicki 	case VSC73XX_BLOCK_SYSTEM:
46895711cd5SPawel Dembicki 		switch (subblock) {
46995711cd5SPawel Dembicki 		case 0:
47095711cd5SPawel Dembicki 			return 1;
47195711cd5SPawel Dembicki 		}
47295711cd5SPawel Dembicki 		break;
47395711cd5SPawel Dembicki 
47495711cd5SPawel Dembicki 	case VSC73XX_BLOCK_MII:
47595711cd5SPawel Dembicki 	case VSC73XX_BLOCK_ARBITER:
47695711cd5SPawel Dembicki 		switch (subblock) {
47795711cd5SPawel Dembicki 		case 0 ... 1:
47895711cd5SPawel Dembicki 			return 1;
47995711cd5SPawel Dembicki 		}
48095711cd5SPawel Dembicki 		break;
4818e69c96dSPawel Dembicki 	case VSC73XX_BLOCK_CAPTURE:
4828e69c96dSPawel Dembicki 		switch (subblock) {
4838e69c96dSPawel Dembicki 		case 0 ... 4:
4848e69c96dSPawel Dembicki 		case 6 ... 7:
4858e69c96dSPawel Dembicki 			return 1;
4868e69c96dSPawel Dembicki 		}
4878e69c96dSPawel Dembicki 		break;
48895711cd5SPawel Dembicki 	}
48995711cd5SPawel Dembicki 
49095711cd5SPawel Dembicki 	return 0;
49195711cd5SPawel Dembicki }
49295711cd5SPawel Dembicki EXPORT_SYMBOL(vsc73xx_is_addr_valid);
49395711cd5SPawel Dembicki 
vsc73xx_read(struct vsc73xx * vsc,u8 block,u8 subblock,u8 reg,u32 * val)49495711cd5SPawel Dembicki static int vsc73xx_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
49595711cd5SPawel Dembicki 			u32 *val)
49695711cd5SPawel Dembicki {
49795711cd5SPawel Dembicki 	return vsc->ops->read(vsc, block, subblock, reg, val);
49895711cd5SPawel Dembicki }
49995711cd5SPawel Dembicki 
vsc73xx_write(struct vsc73xx * vsc,u8 block,u8 subblock,u8 reg,u32 val)50095711cd5SPawel Dembicki static int vsc73xx_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
50195711cd5SPawel Dembicki 			 u32 val)
50295711cd5SPawel Dembicki {
50395711cd5SPawel Dembicki 	return vsc->ops->write(vsc, block, subblock, reg, val);
50495711cd5SPawel Dembicki }
50595711cd5SPawel Dembicki 
vsc73xx_update_bits(struct vsc73xx * vsc,u8 block,u8 subblock,u8 reg,u32 mask,u32 val)50695711cd5SPawel Dembicki static int vsc73xx_update_bits(struct vsc73xx *vsc, u8 block, u8 subblock,
50795711cd5SPawel Dembicki 			       u8 reg, u32 mask, u32 val)
50895711cd5SPawel Dembicki {
50995711cd5SPawel Dembicki 	u32 tmp, orig;
51095711cd5SPawel Dembicki 	int ret;
51195711cd5SPawel Dembicki 
51295711cd5SPawel Dembicki 	/* Same read-modify-write algorithm as e.g. regmap */
51395711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, block, subblock, reg, &orig);
51495711cd5SPawel Dembicki 	if (ret)
51595711cd5SPawel Dembicki 		return ret;
51695711cd5SPawel Dembicki 	tmp = orig & ~mask;
51795711cd5SPawel Dembicki 	tmp |= val & mask;
51895711cd5SPawel Dembicki 	return vsc73xx_write(vsc, block, subblock, reg, tmp);
51995711cd5SPawel Dembicki }
52095711cd5SPawel Dembicki 
vsc73xx_detect(struct vsc73xx * vsc)52195711cd5SPawel Dembicki static int vsc73xx_detect(struct vsc73xx *vsc)
52295711cd5SPawel Dembicki {
52395711cd5SPawel Dembicki 	bool icpu_si_boot_en;
52495711cd5SPawel Dembicki 	bool icpu_pi_en;
52595711cd5SPawel Dembicki 	u32 val;
52695711cd5SPawel Dembicki 	u32 rev;
52795711cd5SPawel Dembicki 	int ret;
52895711cd5SPawel Dembicki 	u32 id;
52995711cd5SPawel Dembicki 
53095711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
53195711cd5SPawel Dembicki 			   VSC73XX_ICPU_MBOX_VAL, &val);
53295711cd5SPawel Dembicki 	if (ret) {
53395711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to read mailbox (%d)\n", ret);
53495711cd5SPawel Dembicki 		return ret;
53595711cd5SPawel Dembicki 	}
53695711cd5SPawel Dembicki 
53795711cd5SPawel Dembicki 	if (val == 0xffffffff) {
5381da39ff0SPawel Dembicki 		dev_info(vsc->dev, "chip seems dead.\n");
5391da39ff0SPawel Dembicki 		return -EAGAIN;
54095711cd5SPawel Dembicki 	}
54195711cd5SPawel Dembicki 
54295711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
54395711cd5SPawel Dembicki 			   VSC73XX_CHIPID, &val);
54495711cd5SPawel Dembicki 	if (ret) {
54595711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to read chip id (%d)\n", ret);
54695711cd5SPawel Dembicki 		return ret;
54795711cd5SPawel Dembicki 	}
54895711cd5SPawel Dembicki 
54995711cd5SPawel Dembicki 	id = (val >> VSC73XX_CHIPID_ID_SHIFT) &
55095711cd5SPawel Dembicki 		VSC73XX_CHIPID_ID_MASK;
55195711cd5SPawel Dembicki 	switch (id) {
55295711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7385:
55395711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7388:
55495711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7395:
55595711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7398:
55695711cd5SPawel Dembicki 		break;
55795711cd5SPawel Dembicki 	default:
55895711cd5SPawel Dembicki 		dev_err(vsc->dev, "unsupported chip, id=%04x\n", id);
55995711cd5SPawel Dembicki 		return -ENODEV;
56095711cd5SPawel Dembicki 	}
56195711cd5SPawel Dembicki 
56295711cd5SPawel Dembicki 	vsc->chipid = id;
56395711cd5SPawel Dembicki 	rev = (val >> VSC73XX_CHIPID_REV_SHIFT) &
56495711cd5SPawel Dembicki 		VSC73XX_CHIPID_REV_MASK;
56595711cd5SPawel Dembicki 	dev_info(vsc->dev, "VSC%04X (rev: %d) switch found\n", id, rev);
56695711cd5SPawel Dembicki 
56795711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
56895711cd5SPawel Dembicki 			   VSC73XX_ICPU_CTRL, &val);
56995711cd5SPawel Dembicki 	if (ret) {
57095711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to read iCPU control\n");
57195711cd5SPawel Dembicki 		return ret;
57295711cd5SPawel Dembicki 	}
57395711cd5SPawel Dembicki 
57495711cd5SPawel Dembicki 	/* The iCPU can always be used but can boot in different ways.
57595711cd5SPawel Dembicki 	 * If it is initially disabled and has no external memory,
57695711cd5SPawel Dembicki 	 * we are in control and can do whatever we like, else we
57795711cd5SPawel Dembicki 	 * are probably in trouble (we need some way to communicate
57895711cd5SPawel Dembicki 	 * with the running firmware) so we bail out for now.
57995711cd5SPawel Dembicki 	 */
58095711cd5SPawel Dembicki 	icpu_pi_en = !!(val & VSC73XX_ICPU_CTRL_ICPU_PI_EN);
58195711cd5SPawel Dembicki 	icpu_si_boot_en = !!(val & VSC73XX_ICPU_CTRL_BOOT_EN);
58295711cd5SPawel Dembicki 	if (icpu_si_boot_en && icpu_pi_en) {
58395711cd5SPawel Dembicki 		dev_err(vsc->dev,
58495711cd5SPawel Dembicki 			"iCPU enabled boots from SI, has external memory\n");
58595711cd5SPawel Dembicki 		dev_err(vsc->dev, "no idea how to deal with this\n");
58695711cd5SPawel Dembicki 		return -ENODEV;
58795711cd5SPawel Dembicki 	}
58895711cd5SPawel Dembicki 	if (icpu_si_boot_en && !icpu_pi_en) {
58995711cd5SPawel Dembicki 		dev_err(vsc->dev,
5901da39ff0SPawel Dembicki 			"iCPU enabled boots from PI/SI, no external memory\n");
5911da39ff0SPawel Dembicki 		return -EAGAIN;
59295711cd5SPawel Dembicki 	}
59395711cd5SPawel Dembicki 	if (!icpu_si_boot_en && icpu_pi_en) {
59495711cd5SPawel Dembicki 		dev_err(vsc->dev,
59595711cd5SPawel Dembicki 			"iCPU enabled, boots from PI external memory\n");
59695711cd5SPawel Dembicki 		dev_err(vsc->dev, "no idea how to deal with this\n");
59795711cd5SPawel Dembicki 		return -ENODEV;
59895711cd5SPawel Dembicki 	}
59995711cd5SPawel Dembicki 	/* !icpu_si_boot_en && !cpu_pi_en */
60095711cd5SPawel Dembicki 	dev_info(vsc->dev, "iCPU disabled, no external memory\n");
60195711cd5SPawel Dembicki 
60295711cd5SPawel Dembicki 	return 0;
60395711cd5SPawel Dembicki }
60495711cd5SPawel Dembicki 
vsc73xx_mdio_busy_check(struct vsc73xx * vsc)605fa63c643SPawel Dembicki static int vsc73xx_mdio_busy_check(struct vsc73xx *vsc)
606fa63c643SPawel Dembicki {
607fa63c643SPawel Dembicki 	int ret, err;
608fa63c643SPawel Dembicki 	u32 val;
609fa63c643SPawel Dembicki 
610fa63c643SPawel Dembicki 	ret = read_poll_timeout(vsc73xx_read, err,
611fa63c643SPawel Dembicki 				err < 0 || !(val & VSC73XX_MII_STAT_BUSY),
612fa63c643SPawel Dembicki 				VSC73XX_MDIO_POLL_SLEEP_US,
613fa63c643SPawel Dembicki 				VSC73XX_POLL_TIMEOUT_US, false, vsc,
614fa63c643SPawel Dembicki 				VSC73XX_BLOCK_MII, VSC73XX_BLOCK_MII_INTERNAL,
615fa63c643SPawel Dembicki 				VSC73XX_MII_STAT, &val);
616fa63c643SPawel Dembicki 	if (ret)
617fa63c643SPawel Dembicki 		return ret;
618fa63c643SPawel Dembicki 	return err;
619fa63c643SPawel Dembicki }
620fa63c643SPawel Dembicki 
vsc73xx_phy_read(struct dsa_switch * ds,int phy,int regnum)62195711cd5SPawel Dembicki static int vsc73xx_phy_read(struct dsa_switch *ds, int phy, int regnum)
62295711cd5SPawel Dembicki {
62395711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
62495711cd5SPawel Dembicki 	u32 cmd;
62595711cd5SPawel Dembicki 	u32 val;
62695711cd5SPawel Dembicki 	int ret;
62795711cd5SPawel Dembicki 
628fa63c643SPawel Dembicki 	ret = vsc73xx_mdio_busy_check(vsc);
629fa63c643SPawel Dembicki 	if (ret)
630fa63c643SPawel Dembicki 		return ret;
631fa63c643SPawel Dembicki 
63295711cd5SPawel Dembicki 	/* Setting bit 26 means "read" */
6332524d6c2SPawel Dembicki 	cmd = VSC73XX_MII_CMD_OPERATION |
6342524d6c2SPawel Dembicki 	      FIELD_PREP(VSC73XX_MII_CMD_PHY_ADDR, phy) |
6352524d6c2SPawel Dembicki 	      FIELD_PREP(VSC73XX_MII_CMD_PHY_REG, regnum);
6362524d6c2SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_MII, VSC73XX_BLOCK_MII_INTERNAL,
6372524d6c2SPawel Dembicki 			    VSC73XX_MII_CMD, cmd);
63895711cd5SPawel Dembicki 	if (ret)
63995711cd5SPawel Dembicki 		return ret;
640fa63c643SPawel Dembicki 
641fa63c643SPawel Dembicki 	ret = vsc73xx_mdio_busy_check(vsc);
642fa63c643SPawel Dembicki 	if (ret)
643fa63c643SPawel Dembicki 		return ret;
644fa63c643SPawel Dembicki 
6452524d6c2SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MII, VSC73XX_BLOCK_MII_INTERNAL,
6462524d6c2SPawel Dembicki 			   VSC73XX_MII_DATA, &val);
64795711cd5SPawel Dembicki 	if (ret)
64895711cd5SPawel Dembicki 		return ret;
6492524d6c2SPawel Dembicki 	if (val & VSC73XX_MII_DATA_FAILURE) {
65095711cd5SPawel Dembicki 		dev_err(vsc->dev, "reading reg %02x from phy%d failed\n",
65195711cd5SPawel Dembicki 			regnum, phy);
65295711cd5SPawel Dembicki 		return -EIO;
65395711cd5SPawel Dembicki 	}
6542524d6c2SPawel Dembicki 	val &= VSC73XX_MII_DATA_READ_DATA;
65595711cd5SPawel Dembicki 
65695711cd5SPawel Dembicki 	dev_dbg(vsc->dev, "read reg %02x from phy%d = %04x\n",
65795711cd5SPawel Dembicki 		regnum, phy, val);
65895711cd5SPawel Dembicki 
65995711cd5SPawel Dembicki 	return val;
66095711cd5SPawel Dembicki }
66195711cd5SPawel Dembicki 
vsc73xx_phy_write(struct dsa_switch * ds,int phy,int regnum,u16 val)66295711cd5SPawel Dembicki static int vsc73xx_phy_write(struct dsa_switch *ds, int phy, int regnum,
66395711cd5SPawel Dembicki 			     u16 val)
66495711cd5SPawel Dembicki {
66595711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
66695711cd5SPawel Dembicki 	u32 cmd;
66795711cd5SPawel Dembicki 	int ret;
66895711cd5SPawel Dembicki 
669fa63c643SPawel Dembicki 	ret = vsc73xx_mdio_busy_check(vsc);
670fa63c643SPawel Dembicki 	if (ret)
671fa63c643SPawel Dembicki 		return ret;
67295711cd5SPawel Dembicki 
6732524d6c2SPawel Dembicki 	cmd = FIELD_PREP(VSC73XX_MII_CMD_PHY_ADDR, phy) |
6744d3d3559SJakub Kicinski 	      FIELD_PREP(VSC73XX_MII_CMD_PHY_REG, regnum) |
6754d3d3559SJakub Kicinski 	      FIELD_PREP(VSC73XX_MII_CMD_WRITE_DATA, val);
6762524d6c2SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_MII, VSC73XX_BLOCK_MII_INTERNAL,
6772524d6c2SPawel Dembicki 			    VSC73XX_MII_CMD, cmd);
67895711cd5SPawel Dembicki 	if (ret)
67995711cd5SPawel Dembicki 		return ret;
68095711cd5SPawel Dembicki 
68195711cd5SPawel Dembicki 	dev_dbg(vsc->dev, "write %04x to reg %02x in phy%d\n",
68295711cd5SPawel Dembicki 		val, regnum, phy);
68395711cd5SPawel Dembicki 	return 0;
68495711cd5SPawel Dembicki }
68595711cd5SPawel Dembicki 
vsc73xx_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol mp)68695711cd5SPawel Dembicki static enum dsa_tag_protocol vsc73xx_get_tag_protocol(struct dsa_switch *ds,
6874d776482SFlorian Fainelli 						      int port,
6884d776482SFlorian Fainelli 						      enum dsa_tag_protocol mp)
68995711cd5SPawel Dembicki {
69095711cd5SPawel Dembicki 	/* The switch internally uses a 8 byte header with length,
69195711cd5SPawel Dembicki 	 * source port, tag, LPA and priority. This is supposedly
69295711cd5SPawel Dembicki 	 * only accessible when operating the switch using the internal
69395711cd5SPawel Dembicki 	 * CPU or with an external CPU mapping the device in, but not
69495711cd5SPawel Dembicki 	 * when operating the switch over SPI and putting frames in/out
69595711cd5SPawel Dembicki 	 * on port 6 (the CPU port). So far we must assume that we
69695711cd5SPawel Dembicki 	 * cannot access the tag. (See "Internal frame header" section
69795711cd5SPawel Dembicki 	 * 3.9.1 in the manual.)
69895711cd5SPawel Dembicki 	 */
699e3386ec4SPawel Dembicki 	return DSA_TAG_PROTO_VSC73XX_8021Q;
70095711cd5SPawel Dembicki }
70195711cd5SPawel Dembicki 
vsc73xx_wait_for_vlan_table_cmd(struct vsc73xx * vsc)7026b783dedSPawel Dembicki static int vsc73xx_wait_for_vlan_table_cmd(struct vsc73xx *vsc)
7036b783dedSPawel Dembicki {
7046b783dedSPawel Dembicki 	int ret, err;
7056b783dedSPawel Dembicki 	u32 val;
7066b783dedSPawel Dembicki 
7076b783dedSPawel Dembicki 	ret = read_poll_timeout(vsc73xx_read, err,
7086b783dedSPawel Dembicki 				err < 0 ||
7096b783dedSPawel Dembicki 				((val & VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK) ==
7106b783dedSPawel Dembicki 				VSC73XX_VLANACCESS_VLAN_TBL_CMD_IDLE),
7116b783dedSPawel Dembicki 				VSC73XX_POLL_SLEEP_US, VSC73XX_POLL_TIMEOUT_US,
7126b783dedSPawel Dembicki 				false, vsc, VSC73XX_BLOCK_ANALYZER,
7136b783dedSPawel Dembicki 				0, VSC73XX_VLANACCESS, &val);
7146b783dedSPawel Dembicki 	if (ret)
7156b783dedSPawel Dembicki 		return ret;
7166b783dedSPawel Dembicki 	return err;
7176b783dedSPawel Dembicki }
7186b783dedSPawel Dembicki 
7196b783dedSPawel Dembicki static int
vsc73xx_read_vlan_table_entry(struct vsc73xx * vsc,u16 vid,u8 * portmap)7206b783dedSPawel Dembicki vsc73xx_read_vlan_table_entry(struct vsc73xx *vsc, u16 vid, u8 *portmap)
7216b783dedSPawel Dembicki {
7226b783dedSPawel Dembicki 	u32 val;
7236b783dedSPawel Dembicki 	int ret;
7246b783dedSPawel Dembicki 
7256b783dedSPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANTIDX, vid);
7266b783dedSPawel Dembicki 
7276b783dedSPawel Dembicki 	ret = vsc73xx_wait_for_vlan_table_cmd(vsc);
7286b783dedSPawel Dembicki 	if (ret)
7296b783dedSPawel Dembicki 		return ret;
7306b783dedSPawel Dembicki 
7316b783dedSPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANACCESS,
7326b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK,
7336b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_READ_ENTRY);
7346b783dedSPawel Dembicki 
7356b783dedSPawel Dembicki 	ret = vsc73xx_wait_for_vlan_table_cmd(vsc);
7366b783dedSPawel Dembicki 	if (ret)
7376b783dedSPawel Dembicki 		return ret;
7386b783dedSPawel Dembicki 
7396b783dedSPawel Dembicki 	vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANACCESS, &val);
7406b783dedSPawel Dembicki 	*portmap = (val & VSC73XX_VLANACCESS_VLAN_PORT_MASK) >>
7416b783dedSPawel Dembicki 		   VSC73XX_VLANACCESS_VLAN_PORT_MASK_SHIFT;
7426b783dedSPawel Dembicki 
7436b783dedSPawel Dembicki 	return 0;
7446b783dedSPawel Dembicki }
7456b783dedSPawel Dembicki 
7466b783dedSPawel Dembicki static int
vsc73xx_write_vlan_table_entry(struct vsc73xx * vsc,u16 vid,u8 portmap)7476b783dedSPawel Dembicki vsc73xx_write_vlan_table_entry(struct vsc73xx *vsc, u16 vid, u8 portmap)
7486b783dedSPawel Dembicki {
7496b783dedSPawel Dembicki 	int ret;
7506b783dedSPawel Dembicki 
7516b783dedSPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANTIDX, vid);
7526b783dedSPawel Dembicki 
7536b783dedSPawel Dembicki 	ret = vsc73xx_wait_for_vlan_table_cmd(vsc);
7546b783dedSPawel Dembicki 	if (ret)
7556b783dedSPawel Dembicki 		return ret;
7566b783dedSPawel Dembicki 
7576b783dedSPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANACCESS,
7586b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK |
7596b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_SRC_CHECK |
7606b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_PORT_MASK,
7616b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_WRITE_ENTRY |
7626b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_SRC_CHECK |
7636b783dedSPawel Dembicki 			    (portmap << VSC73XX_VLANACCESS_VLAN_PORT_MASK_SHIFT));
7646b783dedSPawel Dembicki 
7656b783dedSPawel Dembicki 	return vsc73xx_wait_for_vlan_table_cmd(vsc);
7666b783dedSPawel Dembicki }
7676b783dedSPawel Dembicki 
7686b783dedSPawel Dembicki static int
vsc73xx_update_vlan_table(struct vsc73xx * vsc,int port,u16 vid,bool set)7696b783dedSPawel Dembicki vsc73xx_update_vlan_table(struct vsc73xx *vsc, int port, u16 vid, bool set)
7706b783dedSPawel Dembicki {
7716b783dedSPawel Dembicki 	u8 portmap;
7726b783dedSPawel Dembicki 	int ret;
7736b783dedSPawel Dembicki 
7746b783dedSPawel Dembicki 	ret = vsc73xx_read_vlan_table_entry(vsc, vid, &portmap);
7756b783dedSPawel Dembicki 	if (ret)
7766b783dedSPawel Dembicki 		return ret;
7776b783dedSPawel Dembicki 
7786b783dedSPawel Dembicki 	if (set)
7796b783dedSPawel Dembicki 		portmap |= BIT(port);
7806b783dedSPawel Dembicki 	else
7816b783dedSPawel Dembicki 		portmap &= ~BIT(port);
7826b783dedSPawel Dembicki 
7836b783dedSPawel Dembicki 	return vsc73xx_write_vlan_table_entry(vsc, vid, portmap);
7846b783dedSPawel Dembicki }
7856b783dedSPawel Dembicki 
vsc73xx_configure_rgmii_port_delay(struct dsa_switch * ds)7863b91b032SPawel Dembicki static int vsc73xx_configure_rgmii_port_delay(struct dsa_switch *ds)
7873b91b032SPawel Dembicki {
7883b91b032SPawel Dembicki 	/* Keep 2.0 ns delay for backward complatibility */
7893b91b032SPawel Dembicki 	u32 tx_delay = VSC73XX_GMIIDELAY_GMII0_GTXDELAY_2_0_NS;
7903b91b032SPawel Dembicki 	u32 rx_delay = VSC73XX_GMIIDELAY_GMII0_RXDELAY_2_0_NS;
7913b91b032SPawel Dembicki 	struct dsa_port *dp = dsa_to_port(ds, CPU_PORT);
7923b91b032SPawel Dembicki 	struct device_node *port_dn = dp->dn;
7933b91b032SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
7943b91b032SPawel Dembicki 	u32 delay;
7953b91b032SPawel Dembicki 
7963b91b032SPawel Dembicki 	if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) {
7973b91b032SPawel Dembicki 		switch (delay) {
7983b91b032SPawel Dembicki 		case 0:
7993b91b032SPawel Dembicki 			tx_delay = VSC73XX_GMIIDELAY_GMII0_GTXDELAY_NONE;
8003b91b032SPawel Dembicki 			break;
8013b91b032SPawel Dembicki 		case 1400:
8023b91b032SPawel Dembicki 			tx_delay = VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_4_NS;
8033b91b032SPawel Dembicki 			break;
8043b91b032SPawel Dembicki 		case 1700:
8053b91b032SPawel Dembicki 			tx_delay = VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_7_NS;
8063b91b032SPawel Dembicki 			break;
8073b91b032SPawel Dembicki 		case 2000:
8083b91b032SPawel Dembicki 			break;
8093b91b032SPawel Dembicki 		default:
8103b91b032SPawel Dembicki 			dev_err(vsc->dev,
8113b91b032SPawel Dembicki 				"Unsupported RGMII Transmit Clock Delay\n");
8123b91b032SPawel Dembicki 			return -EINVAL;
8133b91b032SPawel Dembicki 		}
8143b91b032SPawel Dembicki 	} else {
8153b91b032SPawel Dembicki 		dev_dbg(vsc->dev,
8163b91b032SPawel Dembicki 			"RGMII Transmit Clock Delay isn't configured, set to 2.0 ns\n");
8173b91b032SPawel Dembicki 	}
8183b91b032SPawel Dembicki 
8193b91b032SPawel Dembicki 	if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) {
8203b91b032SPawel Dembicki 		switch (delay) {
8213b91b032SPawel Dembicki 		case 0:
8223b91b032SPawel Dembicki 			rx_delay = VSC73XX_GMIIDELAY_GMII0_RXDELAY_NONE;
8233b91b032SPawel Dembicki 			break;
8243b91b032SPawel Dembicki 		case 1400:
8253b91b032SPawel Dembicki 			rx_delay = VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_4_NS;
8263b91b032SPawel Dembicki 			break;
8273b91b032SPawel Dembicki 		case 1700:
8283b91b032SPawel Dembicki 			rx_delay = VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_7_NS;
8293b91b032SPawel Dembicki 			break;
8303b91b032SPawel Dembicki 		case 2000:
8313b91b032SPawel Dembicki 			break;
8323b91b032SPawel Dembicki 		default:
8333b91b032SPawel Dembicki 			dev_err(vsc->dev,
8343b91b032SPawel Dembicki 				"Unsupported RGMII Receive Clock Delay value\n");
8353b91b032SPawel Dembicki 			return -EINVAL;
8363b91b032SPawel Dembicki 		}
8373b91b032SPawel Dembicki 	} else {
8383b91b032SPawel Dembicki 		dev_dbg(vsc->dev,
8393b91b032SPawel Dembicki 			"RGMII Receive Clock Delay isn't configured, set to 2.0 ns\n");
8403b91b032SPawel Dembicki 	}
8413b91b032SPawel Dembicki 
8423b91b032SPawel Dembicki 	/* MII delay, set both GTX and RX delay */
8433b91b032SPawel Dembicki 	return vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GMIIDELAY,
8443b91b032SPawel Dembicki 			     tx_delay | rx_delay);
8453b91b032SPawel Dembicki }
8463b91b032SPawel Dembicki 
vsc73xx_setup(struct dsa_switch * ds)84795711cd5SPawel Dembicki static int vsc73xx_setup(struct dsa_switch *ds)
84895711cd5SPawel Dembicki {
84995711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
8508d5be2c4SPawel Dembicki 	int i, ret, val;
85195711cd5SPawel Dembicki 
85295711cd5SPawel Dembicki 	dev_info(vsc->dev, "set up the switch\n");
85395711cd5SPawel Dembicki 
8546dfaaa27SPawel Dembicki 	ds->max_num_bridges = DSA_TAG_8021Q_MAX_NUM_BRIDGES;
855*075e3d30SPawel Dembicki 	ds->fdb_isolation = true;
8566dfaaa27SPawel Dembicki 
85795711cd5SPawel Dembicki 	/* Issue RESET */
85895711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
85995711cd5SPawel Dembicki 		      VSC73XX_GLORESET_MASTER_RESET);
86095711cd5SPawel Dembicki 	usleep_range(125, 200);
86195711cd5SPawel Dembicki 
86295711cd5SPawel Dembicki 	/* Initialize memory, initialize RAM bank 0..15 except 6 and 7
86395711cd5SPawel Dembicki 	 * This sequence appears in the
86495711cd5SPawel Dembicki 	 * VSC7385 SparX-G5 datasheet section 6.6.1
86595711cd5SPawel Dembicki 	 * VSC7395 SparX-G5e datasheet section 6.6.1
86695711cd5SPawel Dembicki 	 * "initialization sequence".
86795711cd5SPawel Dembicki 	 * No explanation is given to the 0x1010400 magic number.
86895711cd5SPawel Dembicki 	 */
86995711cd5SPawel Dembicki 	for (i = 0; i <= 15; i++) {
87095711cd5SPawel Dembicki 		if (i != 6 && i != 7) {
87195711cd5SPawel Dembicki 			vsc73xx_write(vsc, VSC73XX_BLOCK_MEMINIT,
87295711cd5SPawel Dembicki 				      2,
87395711cd5SPawel Dembicki 				      0, 0x1010400 + i);
87495711cd5SPawel Dembicki 			mdelay(1);
87595711cd5SPawel Dembicki 		}
87695711cd5SPawel Dembicki 	}
87795711cd5SPawel Dembicki 	mdelay(30);
87895711cd5SPawel Dembicki 
87995711cd5SPawel Dembicki 	/* Clear MAC table */
88095711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
88195711cd5SPawel Dembicki 		      VSC73XX_MACACCESS,
88295711cd5SPawel Dembicki 		      VSC73XX_MACACCESS_CMD_CLEAR_TABLE);
88395711cd5SPawel Dembicki 
8846b783dedSPawel Dembicki 	/* Set VLAN table to default values */
88595711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
88695711cd5SPawel Dembicki 		      VSC73XX_VLANACCESS,
88795711cd5SPawel Dembicki 		      VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE);
88895711cd5SPawel Dembicki 
88995711cd5SPawel Dembicki 	msleep(40);
89095711cd5SPawel Dembicki 
89195711cd5SPawel Dembicki 	/* Use 20KiB buffers on all ports on VSC7395
89295711cd5SPawel Dembicki 	 * The VSC7385 has 16KiB buffers and that is the
89395711cd5SPawel Dembicki 	 * default if we don't set this up explicitly.
89495711cd5SPawel Dembicki 	 * Port "31" is "all ports".
89595711cd5SPawel Dembicki 	 */
89695711cd5SPawel Dembicki 	if (IS_739X(vsc))
89795711cd5SPawel Dembicki 		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 0x1f,
89895711cd5SPawel Dembicki 			      VSC73XX_Q_MISC_CONF,
89995711cd5SPawel Dembicki 			      VSC73XX_Q_MISC_CONF_EXTENT_MEM);
90095711cd5SPawel Dembicki 
90195711cd5SPawel Dembicki 	/* Put all ports into reset until enabled */
90295711cd5SPawel Dembicki 	for (i = 0; i < 7; i++) {
90395711cd5SPawel Dembicki 		if (i == 5)
90495711cd5SPawel Dembicki 			continue;
90595711cd5SPawel Dembicki 		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 4,
90695711cd5SPawel Dembicki 			      VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
90795711cd5SPawel Dembicki 	}
90895711cd5SPawel Dembicki 
9093b91b032SPawel Dembicki 	/* Configure RGMII delay */
9103b91b032SPawel Dembicki 	ret = vsc73xx_configure_rgmii_port_delay(ds);
9113b91b032SPawel Dembicki 	if (ret)
9123b91b032SPawel Dembicki 		return ret;
9133b91b032SPawel Dembicki 
9146b783dedSPawel Dembicki 	/* Ingess VLAN reception mask (table 145) */
9156b783dedSPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANMASK,
9166b783dedSPawel Dembicki 		      0xff);
91795711cd5SPawel Dembicki 	/* IP multicast flood mask (table 144) */
91895711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_IFLODMSK,
91995711cd5SPawel Dembicki 		      0xff);
92095711cd5SPawel Dembicki 
92195711cd5SPawel Dembicki 	mdelay(50);
92295711cd5SPawel Dembicki 
9238d5be2c4SPawel Dembicki 	/* Disable preamble and use maximum allowed clock for the internal
9248d5be2c4SPawel Dembicki 	 * mdio bus, used for communication with internal PHYs only.
9258d5be2c4SPawel Dembicki 	 */
9268d5be2c4SPawel Dembicki 	val = VSC73XX_MII_MPRES_NOPREAMBLE |
9278d5be2c4SPawel Dembicki 	      FIELD_PREP(VSC73XX_MII_MPRES_PRESCALEVAL,
9288d5be2c4SPawel Dembicki 			 VSC73XX_MII_PRESCALEVAL_MIN);
9298d5be2c4SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MII, VSC73XX_BLOCK_MII_INTERNAL,
9308d5be2c4SPawel Dembicki 		      VSC73XX_MII_MPRES, val);
9318d5be2c4SPawel Dembicki 
93295711cd5SPawel Dembicki 	/* Release reset from the internal PHYs */
93395711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
93495711cd5SPawel Dembicki 		      VSC73XX_GLORESET_PHY_RESET);
93595711cd5SPawel Dembicki 
93695711cd5SPawel Dembicki 	udelay(4);
93795711cd5SPawel Dembicki 
9386b783dedSPawel Dembicki 	/* Clear VLAN table */
9396b783dedSPawel Dembicki 	for (i = 0; i < VLAN_N_VID; i++)
9406b783dedSPawel Dembicki 		vsc73xx_write_vlan_table_entry(vsc, i, 0);
9416b783dedSPawel Dembicki 
9426b783dedSPawel Dembicki 	INIT_LIST_HEAD(&vsc->vlans);
9436b783dedSPawel Dembicki 
944e3386ec4SPawel Dembicki 	rtnl_lock();
945e3386ec4SPawel Dembicki 	ret = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
946e3386ec4SPawel Dembicki 	rtnl_unlock();
947e3386ec4SPawel Dembicki 
948e3386ec4SPawel Dembicki 	return ret;
949e3386ec4SPawel Dembicki }
950e3386ec4SPawel Dembicki 
vsc73xx_teardown(struct dsa_switch * ds)951e3386ec4SPawel Dembicki static void vsc73xx_teardown(struct dsa_switch *ds)
952e3386ec4SPawel Dembicki {
953e3386ec4SPawel Dembicki 	rtnl_lock();
954e3386ec4SPawel Dembicki 	dsa_tag_8021q_unregister(ds);
955e3386ec4SPawel Dembicki 	rtnl_unlock();
95695711cd5SPawel Dembicki }
95795711cd5SPawel Dembicki 
vsc73xx_init_port(struct vsc73xx * vsc,int port)95895711cd5SPawel Dembicki static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
95995711cd5SPawel Dembicki {
96095711cd5SPawel Dembicki 	u32 val;
96195711cd5SPawel Dembicki 
96295711cd5SPawel Dembicki 	/* MAC configure, first reset the port and then write defaults */
96395711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
96495711cd5SPawel Dembicki 		      port,
96595711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG,
96695711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG_RESET);
96795711cd5SPawel Dembicki 
96895711cd5SPawel Dembicki 	/* Take up the port in 1Gbit mode by default, this will be
96995711cd5SPawel Dembicki 	 * augmented after auto-negotiation on the PHY-facing
97095711cd5SPawel Dembicki 	 * ports.
97195711cd5SPawel Dembicki 	 */
97295711cd5SPawel Dembicki 	if (port == CPU_PORT)
97395711cd5SPawel Dembicki 		val = VSC73XX_MAC_CFG_1000M_F_RGMII;
97495711cd5SPawel Dembicki 	else
97595711cd5SPawel Dembicki 		val = VSC73XX_MAC_CFG_1000M_F_PHY;
97695711cd5SPawel Dembicki 
97795711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
97895711cd5SPawel Dembicki 		      port,
97995711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG,
98095711cd5SPawel Dembicki 		      val |
98195711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG_TX_EN |
98295711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG_RX_EN);
98395711cd5SPawel Dembicki 
98495711cd5SPawel Dembicki 	/* Flow control for the CPU port:
98595711cd5SPawel Dembicki 	 * Use a zero delay pause frame when pause condition is left
98695711cd5SPawel Dembicki 	 * Obey pause control frames
98795711cd5SPawel Dembicki 	 */
98895711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
98995711cd5SPawel Dembicki 		      port,
99095711cd5SPawel Dembicki 		      VSC73XX_FCCONF,
99195711cd5SPawel Dembicki 		      VSC73XX_FCCONF_ZERO_PAUSE_EN |
99295711cd5SPawel Dembicki 		      VSC73XX_FCCONF_FLOW_CTRL_OBEY);
99395711cd5SPawel Dembicki 
99495711cd5SPawel Dembicki 	/* Issue pause control frames on PHY facing ports.
99595711cd5SPawel Dembicki 	 * Allow early initiation of MAC transmission if the amount
99695711cd5SPawel Dembicki 	 * of egress data is below 512 bytes on CPU port.
99795711cd5SPawel Dembicki 	 * FIXME: enable 20KiB buffers?
99895711cd5SPawel Dembicki 	 */
99995711cd5SPawel Dembicki 	if (port == CPU_PORT)
100095711cd5SPawel Dembicki 		val = VSC73XX_Q_MISC_CONF_EARLY_TX_512;
100195711cd5SPawel Dembicki 	else
100295711cd5SPawel Dembicki 		val = VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE;
100395711cd5SPawel Dembicki 	val |= VSC73XX_Q_MISC_CONF_EXTENT_MEM;
100495711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
100595711cd5SPawel Dembicki 		      port,
100695711cd5SPawel Dembicki 		      VSC73XX_Q_MISC_CONF,
100795711cd5SPawel Dembicki 		      val);
100895711cd5SPawel Dembicki 
100995711cd5SPawel Dembicki 	/* Flow control MAC: a MAC address used in flow control frames */
101095711cd5SPawel Dembicki 	val = (vsc->addr[5] << 16) | (vsc->addr[4] << 8) | (vsc->addr[3]);
101195711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
101295711cd5SPawel Dembicki 		      port,
101395711cd5SPawel Dembicki 		      VSC73XX_FCMACHI,
101495711cd5SPawel Dembicki 		      val);
101595711cd5SPawel Dembicki 	val = (vsc->addr[2] << 16) | (vsc->addr[1] << 8) | (vsc->addr[0]);
101695711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
101795711cd5SPawel Dembicki 		      port,
101895711cd5SPawel Dembicki 		      VSC73XX_FCMACLO,
101995711cd5SPawel Dembicki 		      val);
102095711cd5SPawel Dembicki 
102195711cd5SPawel Dembicki 	/* Tell the categorizer to forward pause frames, not control
102295711cd5SPawel Dembicki 	 * frame. Do not drop anything.
102395711cd5SPawel Dembicki 	 */
102495711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
102595711cd5SPawel Dembicki 		      port,
102695711cd5SPawel Dembicki 		      VSC73XX_CAT_DROP,
102795711cd5SPawel Dembicki 		      VSC73XX_CAT_DROP_FWD_PAUSE_ENA);
102895711cd5SPawel Dembicki 
102995711cd5SPawel Dembicki 	/* Clear all counters */
103095711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
103195711cd5SPawel Dembicki 		      port, VSC73XX_C_RX0, 0);
103295711cd5SPawel Dembicki }
103395711cd5SPawel Dembicki 
vsc73xx_reset_port(struct vsc73xx * vsc,int port,u32 initval)103421fc3416SPawel Dembicki static void vsc73xx_reset_port(struct vsc73xx *vsc, int port, u32 initval)
103595711cd5SPawel Dembicki {
1036eb7e33d0SPawel Dembicki 	int ret, err;
103721fc3416SPawel Dembicki 	u32 val;
103895711cd5SPawel Dembicki 
103995711cd5SPawel Dembicki 	/* Disable RX on this port */
104095711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
104195711cd5SPawel Dembicki 			    VSC73XX_MAC_CFG,
104295711cd5SPawel Dembicki 			    VSC73XX_MAC_CFG_RX_EN, 0);
104395711cd5SPawel Dembicki 
104495711cd5SPawel Dembicki 	/* Discard packets */
104595711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
104695711cd5SPawel Dembicki 			    VSC73XX_ARBDISC, BIT(port), BIT(port));
104795711cd5SPawel Dembicki 
104895711cd5SPawel Dembicki 	/* Wait until queue is empty */
1049eb7e33d0SPawel Dembicki 	ret = read_poll_timeout(vsc73xx_read, err,
1050eb7e33d0SPawel Dembicki 				err < 0 || (val & BIT(port)),
1051eb7e33d0SPawel Dembicki 				VSC73XX_POLL_SLEEP_US,
1052eb7e33d0SPawel Dembicki 				VSC73XX_POLL_TIMEOUT_US, false,
1053eb7e33d0SPawel Dembicki 				vsc, VSC73XX_BLOCK_ARBITER, 0,
105495711cd5SPawel Dembicki 				VSC73XX_ARBEMPTY, &val);
1055eb7e33d0SPawel Dembicki 	if (ret)
105695711cd5SPawel Dembicki 		dev_err(vsc->dev,
105795711cd5SPawel Dembicki 			"timeout waiting for block arbiter\n");
1058eb7e33d0SPawel Dembicki 	else if (err < 0)
1059eb7e33d0SPawel Dembicki 		dev_err(vsc->dev, "error reading arbiter\n");
106095711cd5SPawel Dembicki 
106195711cd5SPawel Dembicki 	/* Put this port into reset */
106295711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
106321fc3416SPawel Dembicki 		      VSC73XX_MAC_CFG_RESET | initval);
106421fc3416SPawel Dembicki }
106595711cd5SPawel Dembicki 
vsc73xx_mac_config(struct phylink_config * config,unsigned int mode,const struct phylink_link_state * state)106621fc3416SPawel Dembicki static void vsc73xx_mac_config(struct phylink_config *config, unsigned int mode,
106721fc3416SPawel Dembicki 			       const struct phylink_link_state *state)
106821fc3416SPawel Dembicki {
106921fc3416SPawel Dembicki 	struct dsa_port *dp = dsa_phylink_to_port(config);
107021fc3416SPawel Dembicki 	struct vsc73xx *vsc = dp->ds->priv;
107121fc3416SPawel Dembicki 	int port = dp->index;
107221fc3416SPawel Dembicki 
107321fc3416SPawel Dembicki 	/* Special handling of the CPU-facing port */
107421fc3416SPawel Dembicki 	if (port == CPU_PORT) {
107521fc3416SPawel Dembicki 		/* Other ports are already initialized but not this one */
107621fc3416SPawel Dembicki 		vsc73xx_init_port(vsc, CPU_PORT);
107721fc3416SPawel Dembicki 		/* Select the external port for this interface (EXT_PORT)
107821fc3416SPawel Dembicki 		 * Enable the GMII GTX external clock
107921fc3416SPawel Dembicki 		 * Use double data rate (DDR mode)
108021fc3416SPawel Dembicki 		 */
108121fc3416SPawel Dembicki 		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
108221fc3416SPawel Dembicki 			      CPU_PORT,
108321fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM,
108421fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM_EXT_PORT |
108521fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM_ENA_GTX |
108621fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM_DDR_MODE);
108721fc3416SPawel Dembicki 	}
108821fc3416SPawel Dembicki }
108921fc3416SPawel Dembicki 
vsc73xx_mac_link_down(struct phylink_config * config,unsigned int mode,phy_interface_t interface)109021fc3416SPawel Dembicki static void vsc73xx_mac_link_down(struct phylink_config *config,
109121fc3416SPawel Dembicki 				  unsigned int mode, phy_interface_t interface)
109221fc3416SPawel Dembicki {
109321fc3416SPawel Dembicki 	struct dsa_port *dp = dsa_phylink_to_port(config);
109421fc3416SPawel Dembicki 	struct vsc73xx *vsc = dp->ds->priv;
109521fc3416SPawel Dembicki 	int port = dp->index;
109621fc3416SPawel Dembicki 
109721fc3416SPawel Dembicki 	/* This routine is described in the datasheet (below ARBDISC register
109821fc3416SPawel Dembicki 	 * description)
109921fc3416SPawel Dembicki 	 */
110021fc3416SPawel Dembicki 	vsc73xx_reset_port(vsc, port, 0);
110195711cd5SPawel Dembicki 
110295711cd5SPawel Dembicki 	/* Allow backward dropping of frames from this port */
110395711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
110495711cd5SPawel Dembicki 			    VSC73XX_SBACKWDROP, BIT(port), BIT(port));
110595711cd5SPawel Dembicki }
110695711cd5SPawel Dembicki 
vsc73xx_mac_link_up(struct phylink_config * config,struct phy_device * phy,unsigned int mode,phy_interface_t interface,int speed,int duplex,bool tx_pause,bool rx_pause)110721fc3416SPawel Dembicki static void vsc73xx_mac_link_up(struct phylink_config *config,
110821fc3416SPawel Dembicki 				struct phy_device *phy, unsigned int mode,
110921fc3416SPawel Dembicki 				phy_interface_t interface, int speed,
111021fc3416SPawel Dembicki 				int duplex, bool tx_pause, bool rx_pause)
111121fc3416SPawel Dembicki {
111221fc3416SPawel Dembicki 	struct dsa_port *dp = dsa_phylink_to_port(config);
111321fc3416SPawel Dembicki 	struct vsc73xx *vsc = dp->ds->priv;
111421fc3416SPawel Dembicki 	int port = dp->index;
111521fc3416SPawel Dembicki 	u32 val;
111621fc3416SPawel Dembicki 	u8 seed;
111795711cd5SPawel Dembicki 
111821fc3416SPawel Dembicki 	if (speed == SPEED_1000)
111921fc3416SPawel Dembicki 		val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M;
112095711cd5SPawel Dembicki 	else
112121fc3416SPawel Dembicki 		val = VSC73XX_MAC_CFG_TX_IPG_100_10M;
112295711cd5SPawel Dembicki 
112312af94b2SPawel Dembicki 	if (phy_interface_mode_is_rgmii(interface))
112421fc3416SPawel Dembicki 		val |= VSC73XX_MAC_CFG_CLK_SEL_1000M;
112521fc3416SPawel Dembicki 	else
112621fc3416SPawel Dembicki 		val |= VSC73XX_MAC_CFG_CLK_SEL_EXT;
112721fc3416SPawel Dembicki 
112821fc3416SPawel Dembicki 	if (duplex == DUPLEX_FULL)
112921fc3416SPawel Dembicki 		val |= VSC73XX_MAC_CFG_FDX;
113063796bc2SPawel Dembicki 	else
113163796bc2SPawel Dembicki 		/* In datasheet description ("Port Mode Procedure" in 5.6.2)
113263796bc2SPawel Dembicki 		 * this bit is configured only for half duplex.
113363796bc2SPawel Dembicki 		 */
113463796bc2SPawel Dembicki 		val |= VSC73XX_MAC_CFG_WEXC_DIS;
113521fc3416SPawel Dembicki 
113621fc3416SPawel Dembicki 	/* This routine is described in the datasheet (below ARBDISC register
113721fc3416SPawel Dembicki 	 * description)
113821fc3416SPawel Dembicki 	 */
113921fc3416SPawel Dembicki 	vsc73xx_reset_port(vsc, port, val);
114021fc3416SPawel Dembicki 
114121fc3416SPawel Dembicki 	/* Seed the port randomness with randomness */
114221fc3416SPawel Dembicki 	get_random_bytes(&seed, 1);
114321fc3416SPawel Dembicki 	val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET;
114421fc3416SPawel Dembicki 	val |= VSC73XX_MAC_CFG_SEED_LOAD;
11456b783dedSPawel Dembicki 
11466b783dedSPawel Dembicki 	/* Those bits are responsible for MTU only. Kernel takes care about MTU,
11476b783dedSPawel Dembicki 	 * let's enable +8 bytes frame length unconditionally.
11486b783dedSPawel Dembicki 	 */
11496b783dedSPawel Dembicki 	val |= VSC73XX_MAC_CFG_VLAN_AWR | VSC73XX_MAC_CFG_VLAN_DBLAWR;
11506b783dedSPawel Dembicki 
115121fc3416SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
115221fc3416SPawel Dembicki 
115321fc3416SPawel Dembicki 	/* Flow control for the PHY facing ports:
115421fc3416SPawel Dembicki 	 * Use a zero delay pause frame when pause condition is left
115521fc3416SPawel Dembicki 	 * Obey pause control frames
115621fc3416SPawel Dembicki 	 * When generating pause frames, use 0xff as pause value
115721fc3416SPawel Dembicki 	 */
115821fc3416SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
115921fc3416SPawel Dembicki 		      VSC73XX_FCCONF_ZERO_PAUSE_EN |
116021fc3416SPawel Dembicki 		      VSC73XX_FCCONF_FLOW_CTRL_OBEY |
116121fc3416SPawel Dembicki 		      0xff);
116221fc3416SPawel Dembicki 
116321fc3416SPawel Dembicki 	/* Accept packets again */
116421fc3416SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
116521fc3416SPawel Dembicki 			    VSC73XX_ARBDISC, BIT(port), 0);
116621fc3416SPawel Dembicki 
116721fc3416SPawel Dembicki 	/* Disallow backward dropping of frames from this port */
116821fc3416SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
116921fc3416SPawel Dembicki 			    VSC73XX_SBACKWDROP, BIT(port), 0);
117021fc3416SPawel Dembicki 
117121fc3416SPawel Dembicki 	/* Enable TX, RX, deassert reset, stop loading seed */
117221fc3416SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
117321fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG,
117421fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
117521fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN,
117621fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN);
117795711cd5SPawel Dembicki }
117895711cd5SPawel Dembicki 
vsc73xx_tag_8021q_active(struct dsa_port * dp)11796b783dedSPawel Dembicki static bool vsc73xx_tag_8021q_active(struct dsa_port *dp)
11806b783dedSPawel Dembicki {
11816b783dedSPawel Dembicki 	return !dsa_port_is_vlan_filtering(dp);
11826b783dedSPawel Dembicki }
11836b783dedSPawel Dembicki 
11846b783dedSPawel Dembicki static struct vsc73xx_bridge_vlan *
vsc73xx_bridge_vlan_find(struct vsc73xx * vsc,u16 vid)11856b783dedSPawel Dembicki vsc73xx_bridge_vlan_find(struct vsc73xx *vsc, u16 vid)
11866b783dedSPawel Dembicki {
11876b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vlan;
11886b783dedSPawel Dembicki 
11896b783dedSPawel Dembicki 	list_for_each_entry(vlan, &vsc->vlans, list)
11906b783dedSPawel Dembicki 		if (vlan->vid == vid)
11916b783dedSPawel Dembicki 			return vlan;
11926b783dedSPawel Dembicki 
11936b783dedSPawel Dembicki 	return NULL;
11946b783dedSPawel Dembicki }
11956b783dedSPawel Dembicki 
11966b783dedSPawel Dembicki static void
vsc73xx_bridge_vlan_remove_port(struct vsc73xx_bridge_vlan * vsc73xx_vlan,int port)11976b783dedSPawel Dembicki vsc73xx_bridge_vlan_remove_port(struct vsc73xx_bridge_vlan *vsc73xx_vlan,
11986b783dedSPawel Dembicki 				int port)
11996b783dedSPawel Dembicki {
12006b783dedSPawel Dembicki 	vsc73xx_vlan->portmask &= ~BIT(port);
12016b783dedSPawel Dembicki 
12026b783dedSPawel Dembicki 	if (vsc73xx_vlan->portmask)
12036b783dedSPawel Dembicki 		return;
12046b783dedSPawel Dembicki 
12056b783dedSPawel Dembicki 	list_del(&vsc73xx_vlan->list);
12066b783dedSPawel Dembicki 	kfree(vsc73xx_vlan);
12076b783dedSPawel Dembicki }
12086b783dedSPawel Dembicki 
vsc73xx_bridge_vlan_summary(struct vsc73xx * vsc,int port,struct vsc73xx_vlan_summary * summary,u16 ignored_vid)12096b783dedSPawel Dembicki static void vsc73xx_bridge_vlan_summary(struct vsc73xx *vsc, int port,
12106b783dedSPawel Dembicki 					struct vsc73xx_vlan_summary *summary,
12116b783dedSPawel Dembicki 					u16 ignored_vid)
12126b783dedSPawel Dembicki {
12136b783dedSPawel Dembicki 	size_t num_tagged = 0, num_untagged = 0;
12146b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vlan;
12156b783dedSPawel Dembicki 
12166b783dedSPawel Dembicki 	list_for_each_entry(vlan, &vsc->vlans, list) {
12176b783dedSPawel Dembicki 		if (!(vlan->portmask & BIT(port)) || vlan->vid == ignored_vid)
12186b783dedSPawel Dembicki 			continue;
12196b783dedSPawel Dembicki 
12206b783dedSPawel Dembicki 		if (vlan->untagged & BIT(port))
12216b783dedSPawel Dembicki 			num_untagged++;
12226b783dedSPawel Dembicki 		else
12236b783dedSPawel Dembicki 			num_tagged++;
12246b783dedSPawel Dembicki 	}
12256b783dedSPawel Dembicki 
12266b783dedSPawel Dembicki 	summary->num_untagged = num_untagged;
12276b783dedSPawel Dembicki 	summary->num_tagged = num_tagged;
12286b783dedSPawel Dembicki }
12296b783dedSPawel Dembicki 
vsc73xx_find_first_vlan_untagged(struct vsc73xx * vsc,int port)12306b783dedSPawel Dembicki static u16 vsc73xx_find_first_vlan_untagged(struct vsc73xx *vsc, int port)
12316b783dedSPawel Dembicki {
12326b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vlan;
12336b783dedSPawel Dembicki 
12346b783dedSPawel Dembicki 	list_for_each_entry(vlan, &vsc->vlans, list)
12356b783dedSPawel Dembicki 		if ((vlan->portmask & BIT(port)) &&
12366b783dedSPawel Dembicki 		    (vlan->untagged & BIT(port)))
12376b783dedSPawel Dembicki 			return vlan->vid;
12386b783dedSPawel Dembicki 
12396b783dedSPawel Dembicki 	return VLAN_N_VID;
12406b783dedSPawel Dembicki }
12416b783dedSPawel Dembicki 
vsc73xx_set_vlan_conf(struct vsc73xx * vsc,int port,enum vsc73xx_port_vlan_conf port_vlan_conf)12426b783dedSPawel Dembicki static int vsc73xx_set_vlan_conf(struct vsc73xx *vsc, int port,
12436b783dedSPawel Dembicki 				 enum vsc73xx_port_vlan_conf port_vlan_conf)
12446b783dedSPawel Dembicki {
12456b783dedSPawel Dembicki 	u32 val = 0;
12466b783dedSPawel Dembicki 	int ret;
12476b783dedSPawel Dembicki 
12486b783dedSPawel Dembicki 	if (port_vlan_conf == VSC73XX_VLAN_IGNORE)
12496b783dedSPawel Dembicki 		val = VSC73XX_CAT_VLAN_MISC_VLAN_TCI_IGNORE_ENA |
12506b783dedSPawel Dembicki 		      VSC73XX_CAT_VLAN_MISC_VLAN_KEEP_TAG_ENA;
12516b783dedSPawel Dembicki 
12526b783dedSPawel Dembicki 	ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
12536b783dedSPawel Dembicki 				  VSC73XX_CAT_VLAN_MISC,
12546b783dedSPawel Dembicki 				  VSC73XX_CAT_VLAN_MISC_VLAN_TCI_IGNORE_ENA |
12556b783dedSPawel Dembicki 				  VSC73XX_CAT_VLAN_MISC_VLAN_KEEP_TAG_ENA, val);
12566b783dedSPawel Dembicki 	if (ret)
12576b783dedSPawel Dembicki 		return ret;
12586b783dedSPawel Dembicki 
12596b783dedSPawel Dembicki 	val = (port_vlan_conf == VSC73XX_VLAN_FILTER) ?
12606b783dedSPawel Dembicki 	      VSC73XX_TXUPDCFG_TX_INSERT_TAG : 0;
12616b783dedSPawel Dembicki 
12626b783dedSPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
12636b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG,
12646b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG_TX_INSERT_TAG, val);
12656b783dedSPawel Dembicki }
12666b783dedSPawel Dembicki 
12676b783dedSPawel Dembicki /**
12686b783dedSPawel Dembicki  * vsc73xx_vlan_commit_conf - Update VLAN configuration of a port
12696b783dedSPawel Dembicki  * @vsc: Switch private data structure
12706b783dedSPawel Dembicki  * @port: Port index on which to operate
12716b783dedSPawel Dembicki  *
12726b783dedSPawel Dembicki  * Update the VLAN behavior of a port to make sure that when it is under
12736b783dedSPawel Dembicki  * a VLAN filtering bridge, the port is either filtering with tag
12746b783dedSPawel Dembicki  * preservation, or filtering with all VLANs egress-untagged. Otherwise,
12756b783dedSPawel Dembicki  * the port ignores VLAN tags from packets and applies the port-based
12766b783dedSPawel Dembicki  * VID.
12776b783dedSPawel Dembicki  *
12786b783dedSPawel Dembicki  * Must be called when changes are made to:
12796b783dedSPawel Dembicki  * - the bridge VLAN filtering state of the port
12806b783dedSPawel Dembicki  * - the number or attributes of VLANs from the bridge VLAN table,
12816b783dedSPawel Dembicki  *   while the port is currently VLAN-aware
12826b783dedSPawel Dembicki  *
12836b783dedSPawel Dembicki  * Return: 0 on success, or negative errno on error.
12846b783dedSPawel Dembicki  */
vsc73xx_vlan_commit_conf(struct vsc73xx * vsc,int port)12856b783dedSPawel Dembicki static int vsc73xx_vlan_commit_conf(struct vsc73xx *vsc, int port)
12866b783dedSPawel Dembicki {
12876b783dedSPawel Dembicki 	enum vsc73xx_port_vlan_conf port_vlan_conf = VSC73XX_VLAN_IGNORE;
12886b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(vsc->ds, port);
12896b783dedSPawel Dembicki 
12906b783dedSPawel Dembicki 	if (port == CPU_PORT) {
12916b783dedSPawel Dembicki 		port_vlan_conf = VSC73XX_VLAN_FILTER;
12926b783dedSPawel Dembicki 	} else if (dsa_port_is_vlan_filtering(dp)) {
12936b783dedSPawel Dembicki 		struct vsc73xx_vlan_summary summary;
12946b783dedSPawel Dembicki 
12956b783dedSPawel Dembicki 		port_vlan_conf = VSC73XX_VLAN_FILTER;
12966b783dedSPawel Dembicki 
12976b783dedSPawel Dembicki 		vsc73xx_bridge_vlan_summary(vsc, port, &summary, VLAN_N_VID);
12986b783dedSPawel Dembicki 		if (summary.num_tagged == 0)
12996b783dedSPawel Dembicki 			port_vlan_conf = VSC73XX_VLAN_FILTER_UNTAG_ALL;
13006b783dedSPawel Dembicki 	}
13016b783dedSPawel Dembicki 
13026b783dedSPawel Dembicki 	return vsc73xx_set_vlan_conf(vsc, port, port_vlan_conf);
13036b783dedSPawel Dembicki }
13046b783dedSPawel Dembicki 
13056b783dedSPawel Dembicki static int
vsc73xx_vlan_change_untagged(struct vsc73xx * vsc,int port,u16 vid,bool set)13066b783dedSPawel Dembicki vsc73xx_vlan_change_untagged(struct vsc73xx *vsc, int port, u16 vid, bool set)
13076b783dedSPawel Dembicki {
13086b783dedSPawel Dembicki 	u32 val = 0;
13096b783dedSPawel Dembicki 
13106b783dedSPawel Dembicki 	if (set)
13116b783dedSPawel Dembicki 		val = VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_ENA |
13126b783dedSPawel Dembicki 		      ((vid << VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_SHIFT) &
13136b783dedSPawel Dembicki 		       VSC73XX_TXUPDCFG_TX_UNTAGGED_VID);
13146b783dedSPawel Dembicki 
13156b783dedSPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
13166b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG,
13176b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_ENA |
13186b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG_TX_UNTAGGED_VID, val);
13196b783dedSPawel Dembicki }
13206b783dedSPawel Dembicki 
13216b783dedSPawel Dembicki /**
13226b783dedSPawel Dembicki  * vsc73xx_vlan_commit_untagged - Update native VLAN of a port
13236b783dedSPawel Dembicki  * @vsc: Switch private data structure
13246b783dedSPawel Dembicki  * @port: Port index on which to operate
13256b783dedSPawel Dembicki  *
13266b783dedSPawel Dembicki  * Update the native VLAN of a port (the one VLAN which is transmitted
13276b783dedSPawel Dembicki  * as egress-tagged on a trunk port) when port is in VLAN filtering mode and
13286b783dedSPawel Dembicki  * only one untagged vid is configured.
13296b783dedSPawel Dembicki  * In other cases no need to configure it because switch can untag all vlans on
13306b783dedSPawel Dembicki  * the port.
13316b783dedSPawel Dembicki  *
13326b783dedSPawel Dembicki  * Return: 0 on success, or negative errno on error.
13336b783dedSPawel Dembicki  */
vsc73xx_vlan_commit_untagged(struct vsc73xx * vsc,int port)13346b783dedSPawel Dembicki static int vsc73xx_vlan_commit_untagged(struct vsc73xx *vsc, int port)
13356b783dedSPawel Dembicki {
13366b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(vsc->ds, port);
13376b783dedSPawel Dembicki 	struct vsc73xx_vlan_summary summary;
13386b783dedSPawel Dembicki 	u16 vid = 0;
13396b783dedSPawel Dembicki 	bool valid;
13406b783dedSPawel Dembicki 
13416b783dedSPawel Dembicki 	if (!dsa_port_is_vlan_filtering(dp))
13426b783dedSPawel Dembicki 		/* Port is configured to untag all vlans in that case.
13436b783dedSPawel Dembicki 		 * No need to commit untagged config change.
13446b783dedSPawel Dembicki 		 */
13456b783dedSPawel Dembicki 		return 0;
13466b783dedSPawel Dembicki 
13476b783dedSPawel Dembicki 	vsc73xx_bridge_vlan_summary(vsc, port, &summary, VLAN_N_VID);
13486b783dedSPawel Dembicki 
13496b783dedSPawel Dembicki 	if (summary.num_untagged > 1)
13506b783dedSPawel Dembicki 		/* Port must untag all vlans in that case.
13516b783dedSPawel Dembicki 		 * No need to commit untagged config change.
13526b783dedSPawel Dembicki 		 */
13536b783dedSPawel Dembicki 		return 0;
13546b783dedSPawel Dembicki 
13556b783dedSPawel Dembicki 	valid = (summary.num_untagged == 1);
13566b783dedSPawel Dembicki 	if (valid)
13576b783dedSPawel Dembicki 		vid = vsc73xx_find_first_vlan_untagged(vsc, port);
13586b783dedSPawel Dembicki 
13596b783dedSPawel Dembicki 	return vsc73xx_vlan_change_untagged(vsc, port, vid, valid);
13606b783dedSPawel Dembicki }
13616b783dedSPawel Dembicki 
13626b783dedSPawel Dembicki static int
vsc73xx_vlan_change_pvid(struct vsc73xx * vsc,int port,u16 vid,bool set)13636b783dedSPawel Dembicki vsc73xx_vlan_change_pvid(struct vsc73xx *vsc, int port, u16 vid, bool set)
13646b783dedSPawel Dembicki {
13656b783dedSPawel Dembicki 	u32 val = 0;
13666b783dedSPawel Dembicki 	int ret;
13676b783dedSPawel Dembicki 
13686b783dedSPawel Dembicki 	val = set ? 0 : VSC73XX_CAT_DROP_UNTAGGED_ENA;
13696b783dedSPawel Dembicki 
13706b783dedSPawel Dembicki 	ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
13716b783dedSPawel Dembicki 				  VSC73XX_CAT_DROP,
13726b783dedSPawel Dembicki 				  VSC73XX_CAT_DROP_UNTAGGED_ENA, val);
13736b783dedSPawel Dembicki 	if (!set || ret)
13746b783dedSPawel Dembicki 		return ret;
13756b783dedSPawel Dembicki 
13766b783dedSPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
13776b783dedSPawel Dembicki 				   VSC73XX_CAT_PORT_VLAN,
13786b783dedSPawel Dembicki 				   VSC73XX_CAT_PORT_VLAN_VLAN_VID,
13796b783dedSPawel Dembicki 				   vid & VSC73XX_CAT_PORT_VLAN_VLAN_VID);
13806b783dedSPawel Dembicki }
13816b783dedSPawel Dembicki 
13826b783dedSPawel Dembicki /**
13836b783dedSPawel Dembicki  * vsc73xx_vlan_commit_pvid - Update port-based default VLAN of a port
13846b783dedSPawel Dembicki  * @vsc: Switch private data structure
13856b783dedSPawel Dembicki  * @port: Port index on which to operate
13866b783dedSPawel Dembicki  *
13876b783dedSPawel Dembicki  * Update the PVID of a port so that it follows either the bridge PVID
13886b783dedSPawel Dembicki  * configuration, when the bridge is currently VLAN-aware, or the PVID
13896b783dedSPawel Dembicki  * from tag_8021q, when the port is standalone or under a VLAN-unaware
13906b783dedSPawel Dembicki  * bridge. A port with no PVID drops all untagged and VID 0 tagged
13916b783dedSPawel Dembicki  * traffic.
13926b783dedSPawel Dembicki  *
13936b783dedSPawel Dembicki  * Must be called when changes are made to:
13946b783dedSPawel Dembicki  * - the bridge VLAN filtering state of the port
13956b783dedSPawel Dembicki  * - the number or attributes of VLANs from the bridge VLAN table,
13966b783dedSPawel Dembicki  *   while the port is currently VLAN-aware
13976b783dedSPawel Dembicki  *
13986b783dedSPawel Dembicki  * Return: 0 on success, or negative errno on error.
13996b783dedSPawel Dembicki  */
vsc73xx_vlan_commit_pvid(struct vsc73xx * vsc,int port)14006b783dedSPawel Dembicki static int vsc73xx_vlan_commit_pvid(struct vsc73xx *vsc, int port)
14016b783dedSPawel Dembicki {
14026b783dedSPawel Dembicki 	struct vsc73xx_portinfo *portinfo = &vsc->portinfo[port];
14036b783dedSPawel Dembicki 	bool valid = portinfo->pvid_tag_8021q_configured;
14046b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(vsc->ds, port);
14056b783dedSPawel Dembicki 	u16 vid = portinfo->pvid_tag_8021q;
14066b783dedSPawel Dembicki 
14076b783dedSPawel Dembicki 	if (dsa_port_is_vlan_filtering(dp)) {
14086b783dedSPawel Dembicki 		vid = portinfo->pvid_vlan_filtering;
14096b783dedSPawel Dembicki 		valid = portinfo->pvid_vlan_filtering_configured;
14106b783dedSPawel Dembicki 	}
14116b783dedSPawel Dembicki 
14126b783dedSPawel Dembicki 	return vsc73xx_vlan_change_pvid(vsc, port, vid, valid);
14136b783dedSPawel Dembicki }
14146b783dedSPawel Dembicki 
vsc73xx_vlan_commit_settings(struct vsc73xx * vsc,int port)14156b783dedSPawel Dembicki static int vsc73xx_vlan_commit_settings(struct vsc73xx *vsc, int port)
14166b783dedSPawel Dembicki {
14176b783dedSPawel Dembicki 	int ret;
14186b783dedSPawel Dembicki 
14196b783dedSPawel Dembicki 	ret = vsc73xx_vlan_commit_untagged(vsc, port);
14206b783dedSPawel Dembicki 	if (ret)
14216b783dedSPawel Dembicki 		return ret;
14226b783dedSPawel Dembicki 
14236b783dedSPawel Dembicki 	ret = vsc73xx_vlan_commit_pvid(vsc, port);
14246b783dedSPawel Dembicki 	if (ret)
14256b783dedSPawel Dembicki 		return ret;
14266b783dedSPawel Dembicki 
14276b783dedSPawel Dembicki 	return vsc73xx_vlan_commit_conf(vsc, port);
14286b783dedSPawel Dembicki }
14296b783dedSPawel Dembicki 
vsc73xx_port_enable(struct dsa_switch * ds,int port,struct phy_device * phy)143095711cd5SPawel Dembicki static int vsc73xx_port_enable(struct dsa_switch *ds, int port,
143195711cd5SPawel Dembicki 			       struct phy_device *phy)
143295711cd5SPawel Dembicki {
143395711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
143495711cd5SPawel Dembicki 
143595711cd5SPawel Dembicki 	dev_info(vsc->dev, "enable port %d\n", port);
143695711cd5SPawel Dembicki 	vsc73xx_init_port(vsc, port);
143795711cd5SPawel Dembicki 
14386b783dedSPawel Dembicki 	return vsc73xx_vlan_commit_settings(vsc, port);
143995711cd5SPawel Dembicki }
144095711cd5SPawel Dembicki 
vsc73xx_port_disable(struct dsa_switch * ds,int port)144195711cd5SPawel Dembicki static void vsc73xx_port_disable(struct dsa_switch *ds, int port)
144295711cd5SPawel Dembicki {
144395711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
144495711cd5SPawel Dembicki 
144595711cd5SPawel Dembicki 	/* Just put the port into reset */
144695711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
144795711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
144895711cd5SPawel Dembicki }
144995711cd5SPawel Dembicki 
145095711cd5SPawel Dembicki static const struct vsc73xx_counter *
vsc73xx_find_counter(struct vsc73xx * vsc,u8 counter,bool tx)145195711cd5SPawel Dembicki vsc73xx_find_counter(struct vsc73xx *vsc,
145295711cd5SPawel Dembicki 		     u8 counter,
145395711cd5SPawel Dembicki 		     bool tx)
145495711cd5SPawel Dembicki {
145595711cd5SPawel Dembicki 	const struct vsc73xx_counter *cnts;
145695711cd5SPawel Dembicki 	int num_cnts;
145795711cd5SPawel Dembicki 	int i;
145895711cd5SPawel Dembicki 
145995711cd5SPawel Dembicki 	if (tx) {
146095711cd5SPawel Dembicki 		cnts = vsc73xx_tx_counters;
146195711cd5SPawel Dembicki 		num_cnts = ARRAY_SIZE(vsc73xx_tx_counters);
146295711cd5SPawel Dembicki 	} else {
146395711cd5SPawel Dembicki 		cnts = vsc73xx_rx_counters;
146495711cd5SPawel Dembicki 		num_cnts = ARRAY_SIZE(vsc73xx_rx_counters);
146595711cd5SPawel Dembicki 	}
146695711cd5SPawel Dembicki 
146795711cd5SPawel Dembicki 	for (i = 0; i < num_cnts; i++) {
146895711cd5SPawel Dembicki 		const struct vsc73xx_counter *cnt;
146995711cd5SPawel Dembicki 
147095711cd5SPawel Dembicki 		cnt = &cnts[i];
147195711cd5SPawel Dembicki 		if (cnt->counter == counter)
147295711cd5SPawel Dembicki 			return cnt;
147395711cd5SPawel Dembicki 	}
147495711cd5SPawel Dembicki 
147595711cd5SPawel Dembicki 	return NULL;
147695711cd5SPawel Dembicki }
147795711cd5SPawel Dembicki 
vsc73xx_get_strings(struct dsa_switch * ds,int port,u32 stringset,uint8_t * data)147895711cd5SPawel Dembicki static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset,
147995711cd5SPawel Dembicki 				uint8_t *data)
148095711cd5SPawel Dembicki {
148195711cd5SPawel Dembicki 	const struct vsc73xx_counter *cnt;
148295711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
148395711cd5SPawel Dembicki 	u8 indices[6];
1484e3bbab47SJustin Stitt 	u8 *buf = data;
1485e3bbab47SJustin Stitt 	int i;
148695711cd5SPawel Dembicki 	u32 val;
148795711cd5SPawel Dembicki 	int ret;
148895711cd5SPawel Dembicki 
148995711cd5SPawel Dembicki 	if (stringset != ETH_SS_STATS)
149095711cd5SPawel Dembicki 		return;
149195711cd5SPawel Dembicki 
149295711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MAC, port,
149395711cd5SPawel Dembicki 			   VSC73XX_C_CFG, &val);
149495711cd5SPawel Dembicki 	if (ret)
149595711cd5SPawel Dembicki 		return;
149695711cd5SPawel Dembicki 
149795711cd5SPawel Dembicki 	indices[0] = (val & 0x1f); /* RX counter 0 */
149895711cd5SPawel Dembicki 	indices[1] = ((val >> 5) & 0x1f); /* RX counter 1 */
149995711cd5SPawel Dembicki 	indices[2] = ((val >> 10) & 0x1f); /* RX counter 2 */
150095711cd5SPawel Dembicki 	indices[3] = ((val >> 16) & 0x1f); /* TX counter 0 */
150195711cd5SPawel Dembicki 	indices[4] = ((val >> 21) & 0x1f); /* TX counter 1 */
150295711cd5SPawel Dembicki 	indices[5] = ((val >> 26) & 0x1f); /* TX counter 2 */
150395711cd5SPawel Dembicki 
150495711cd5SPawel Dembicki 	/* The first counters is the RX octets */
1505e403cfffSjustinstitt@google.com 	ethtool_puts(&buf, "RxEtherStatsOctets");
150695711cd5SPawel Dembicki 
150795711cd5SPawel Dembicki 	/* Each port supports recording 3 RX counters and 3 TX counters,
150895711cd5SPawel Dembicki 	 * figure out what counters we use in this set-up and return the
150995711cd5SPawel Dembicki 	 * names of them. The hardware default counters will be number of
151095711cd5SPawel Dembicki 	 * packets on RX/TX, combined broadcast+multicast packets RX/TX and
151195711cd5SPawel Dembicki 	 * total error packets RX/TX.
151295711cd5SPawel Dembicki 	 */
151395711cd5SPawel Dembicki 	for (i = 0; i < 3; i++) {
151495711cd5SPawel Dembicki 		cnt = vsc73xx_find_counter(vsc, indices[i], false);
1515e403cfffSjustinstitt@google.com 		ethtool_puts(&buf, cnt ? cnt->name : "");
151695711cd5SPawel Dembicki 	}
151795711cd5SPawel Dembicki 
151895711cd5SPawel Dembicki 	/* TX stats begins with the number of TX octets */
1519e403cfffSjustinstitt@google.com 	ethtool_puts(&buf, "TxEtherStatsOctets");
152095711cd5SPawel Dembicki 
152195711cd5SPawel Dembicki 	for (i = 3; i < 6; i++) {
152295711cd5SPawel Dembicki 		cnt = vsc73xx_find_counter(vsc, indices[i], true);
1523e403cfffSjustinstitt@google.com 		ethtool_puts(&buf, cnt ? cnt->name : "");
1524e3bbab47SJustin Stitt 
152595711cd5SPawel Dembicki 	}
152695711cd5SPawel Dembicki }
152795711cd5SPawel Dembicki 
vsc73xx_get_sset_count(struct dsa_switch * ds,int port,int sset)152895711cd5SPawel Dembicki static int vsc73xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
152995711cd5SPawel Dembicki {
153095711cd5SPawel Dembicki 	/* We only support SS_STATS */
153195711cd5SPawel Dembicki 	if (sset != ETH_SS_STATS)
153295711cd5SPawel Dembicki 		return 0;
153395711cd5SPawel Dembicki 	/* RX and TX packets, then 3 RX counters, 3 TX counters */
153495711cd5SPawel Dembicki 	return 8;
153595711cd5SPawel Dembicki }
153695711cd5SPawel Dembicki 
vsc73xx_get_ethtool_stats(struct dsa_switch * ds,int port,uint64_t * data)153795711cd5SPawel Dembicki static void vsc73xx_get_ethtool_stats(struct dsa_switch *ds, int port,
153895711cd5SPawel Dembicki 				      uint64_t *data)
153995711cd5SPawel Dembicki {
154095711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
154195711cd5SPawel Dembicki 	u8 regs[] = {
154295711cd5SPawel Dembicki 		VSC73XX_RXOCT,
154395711cd5SPawel Dembicki 		VSC73XX_C_RX0,
154495711cd5SPawel Dembicki 		VSC73XX_C_RX1,
154595711cd5SPawel Dembicki 		VSC73XX_C_RX2,
154695711cd5SPawel Dembicki 		VSC73XX_TXOCT,
154795711cd5SPawel Dembicki 		VSC73XX_C_TX0,
154895711cd5SPawel Dembicki 		VSC73XX_C_TX1,
154995711cd5SPawel Dembicki 		VSC73XX_C_TX2,
155095711cd5SPawel Dembicki 	};
155195711cd5SPawel Dembicki 	u32 val;
155295711cd5SPawel Dembicki 	int ret;
155395711cd5SPawel Dembicki 	int i;
155495711cd5SPawel Dembicki 
155595711cd5SPawel Dembicki 	for (i = 0; i < ARRAY_SIZE(regs); i++) {
155695711cd5SPawel Dembicki 		ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MAC, port,
155795711cd5SPawel Dembicki 				   regs[i], &val);
155895711cd5SPawel Dembicki 		if (ret) {
155995711cd5SPawel Dembicki 			dev_err(vsc->dev, "error reading counter %d\n", i);
156095711cd5SPawel Dembicki 			return;
156195711cd5SPawel Dembicki 		}
156295711cd5SPawel Dembicki 		data[i] = val;
156395711cd5SPawel Dembicki 	}
156495711cd5SPawel Dembicki }
156595711cd5SPawel Dembicki 
vsc73xx_change_mtu(struct dsa_switch * ds,int port,int new_mtu)1566fb77ffc6SVladimir Oltean static int vsc73xx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
1567fb77ffc6SVladimir Oltean {
1568fb77ffc6SVladimir Oltean 	struct vsc73xx *vsc = ds->priv;
1569fb77ffc6SVladimir Oltean 
1570fb77ffc6SVladimir Oltean 	return vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
15713cf62c81SPawel Dembicki 			     VSC73XX_MAXLEN, new_mtu + ETH_HLEN + ETH_FCS_LEN);
1572fb77ffc6SVladimir Oltean }
1573fb77ffc6SVladimir Oltean 
1574fb77ffc6SVladimir Oltean /* According to application not "VSC7398 Jumbo Frames" setting
15753cf62c81SPawel Dembicki  * up the frame size to 9.6 KB does not affect the performance on standard
1576fb77ffc6SVladimir Oltean  * frames. It is clear from the application note that
1577fb77ffc6SVladimir Oltean  * "9.6 kilobytes" == 9600 bytes.
1578fb77ffc6SVladimir Oltean  */
vsc73xx_get_max_mtu(struct dsa_switch * ds,int port)1579fb77ffc6SVladimir Oltean static int vsc73xx_get_max_mtu(struct dsa_switch *ds, int port)
1580fb77ffc6SVladimir Oltean {
15813cf62c81SPawel Dembicki 	return 9600 - ETH_HLEN - ETH_FCS_LEN;
1582fb77ffc6SVladimir Oltean }
1583fb77ffc6SVladimir Oltean 
vsc73xx_phylink_get_caps(struct dsa_switch * dsa,int port,struct phylink_config * config)1584a026809cSRussell King (Oracle) static void vsc73xx_phylink_get_caps(struct dsa_switch *dsa, int port,
1585a026809cSRussell King (Oracle) 				     struct phylink_config *config)
1586a026809cSRussell King (Oracle) {
1587a026809cSRussell King (Oracle) 	unsigned long *interfaces = config->supported_interfaces;
1588a026809cSRussell King (Oracle) 
1589a026809cSRussell King (Oracle) 	if (port == 5)
1590a026809cSRussell King (Oracle) 		return;
1591a026809cSRussell King (Oracle) 
1592a026809cSRussell King (Oracle) 	if (port == CPU_PORT) {
1593a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_MII, interfaces);
1594a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_REVMII, interfaces);
1595a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
1596a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_RGMII, interfaces);
1597a026809cSRussell King (Oracle) 	}
1598a026809cSRussell King (Oracle) 
1599a026809cSRussell King (Oracle) 	if (port <= 4) {
1600a026809cSRussell King (Oracle) 		/* Internal PHYs */
1601a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);
1602a026809cSRussell King (Oracle) 		/* phylib default */
1603a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
1604a026809cSRussell King (Oracle) 	}
1605a026809cSRussell King (Oracle) 
1606a026809cSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000;
1607a026809cSRussell King (Oracle) }
1608a026809cSRussell King (Oracle) 
16096b783dedSPawel Dembicki static int
vsc73xx_port_vlan_filtering(struct dsa_switch * ds,int port,bool vlan_filtering,struct netlink_ext_ack * extack)16106b783dedSPawel Dembicki vsc73xx_port_vlan_filtering(struct dsa_switch *ds, int port,
16116b783dedSPawel Dembicki 			    bool vlan_filtering, struct netlink_ext_ack *extack)
16126b783dedSPawel Dembicki {
16136b783dedSPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
16146b783dedSPawel Dembicki 
16156b783dedSPawel Dembicki 	/* The commit to hardware processed below is required because vsc73xx
16166b783dedSPawel Dembicki 	 * is using tag_8021q. When vlan_filtering is disabled, tag_8021q uses
16176b783dedSPawel Dembicki 	 * pvid/untagged vlans for port recognition. The values configured for
16186b783dedSPawel Dembicki 	 * vlans and pvid/untagged states are stored in portinfo structure.
16196b783dedSPawel Dembicki 	 * When vlan_filtering is enabled, we need to restore pvid/untagged from
16206b783dedSPawel Dembicki 	 * portinfo structure. Analogous routine is processed when
16216b783dedSPawel Dembicki 	 * vlan_filtering is disabled, but values used for tag_8021q are
16226b783dedSPawel Dembicki 	 * restored.
16236b783dedSPawel Dembicki 	 */
16246b783dedSPawel Dembicki 
16256b783dedSPawel Dembicki 	return vsc73xx_vlan_commit_settings(vsc, port);
16266b783dedSPawel Dembicki }
16276b783dedSPawel Dembicki 
vsc73xx_port_vlan_add(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan,struct netlink_ext_ack * extack)16286b783dedSPawel Dembicki static int vsc73xx_port_vlan_add(struct dsa_switch *ds, int port,
16296b783dedSPawel Dembicki 				 const struct switchdev_obj_port_vlan *vlan,
16306b783dedSPawel Dembicki 				 struct netlink_ext_ack *extack)
16316b783dedSPawel Dembicki {
16326b783dedSPawel Dembicki 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
16336b783dedSPawel Dembicki 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
16346b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(ds, port);
16356b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vsc73xx_vlan;
16366b783dedSPawel Dembicki 	struct vsc73xx_vlan_summary summary;
16376b783dedSPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
16386b783dedSPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
16396b783dedSPawel Dembicki 	bool commit_to_hardware;
16406b783dedSPawel Dembicki 	int ret = 0;
16416b783dedSPawel Dembicki 
16426b783dedSPawel Dembicki 	/* Be sure to deny alterations to the configuration done by tag_8021q.
16436b783dedSPawel Dembicki 	 */
16446b783dedSPawel Dembicki 	if (vid_is_dsa_8021q(vlan->vid)) {
16456b783dedSPawel Dembicki 		NL_SET_ERR_MSG_MOD(extack,
16466b783dedSPawel Dembicki 				   "Range 3072-4095 reserved for dsa_8021q operation");
16476b783dedSPawel Dembicki 		return -EBUSY;
16486b783dedSPawel Dembicki 	}
16496b783dedSPawel Dembicki 
16506b783dedSPawel Dembicki 	/* The processed vlan->vid is excluded from the search because the VLAN
16516b783dedSPawel Dembicki 	 * can be re-added with a different set of flags, so it's easiest to
16526b783dedSPawel Dembicki 	 * ignore its old flags from the VLAN database software copy.
16536b783dedSPawel Dembicki 	 */
16546b783dedSPawel Dembicki 	vsc73xx_bridge_vlan_summary(vsc, port, &summary, vlan->vid);
16556b783dedSPawel Dembicki 
16566b783dedSPawel Dembicki 	/* VSC73XX allows only three untagged states: none, one or all */
16576b783dedSPawel Dembicki 	if ((untagged && summary.num_tagged > 0 && summary.num_untagged > 0) ||
16586b783dedSPawel Dembicki 	    (!untagged && summary.num_untagged > 1)) {
16596b783dedSPawel Dembicki 		NL_SET_ERR_MSG_MOD(extack,
16606b783dedSPawel Dembicki 				   "Port can have only none, one or all untagged vlan");
16616b783dedSPawel Dembicki 		return -EBUSY;
16626b783dedSPawel Dembicki 	}
16636b783dedSPawel Dembicki 
16646b783dedSPawel Dembicki 	vsc73xx_vlan = vsc73xx_bridge_vlan_find(vsc, vlan->vid);
16656b783dedSPawel Dembicki 
16666b783dedSPawel Dembicki 	if (!vsc73xx_vlan) {
16676b783dedSPawel Dembicki 		vsc73xx_vlan = kzalloc(sizeof(*vsc73xx_vlan), GFP_KERNEL);
16686b783dedSPawel Dembicki 		if (!vsc73xx_vlan)
16696b783dedSPawel Dembicki 			return -ENOMEM;
16706b783dedSPawel Dembicki 
16716b783dedSPawel Dembicki 		vsc73xx_vlan->vid = vlan->vid;
16726b783dedSPawel Dembicki 
16736b783dedSPawel Dembicki 		list_add_tail(&vsc73xx_vlan->list, &vsc->vlans);
16746b783dedSPawel Dembicki 	}
16756b783dedSPawel Dembicki 
16766b783dedSPawel Dembicki 	vsc73xx_vlan->portmask |= BIT(port);
16776b783dedSPawel Dembicki 
16786b783dedSPawel Dembicki 	/* CPU port must be always tagged because source port identification is
16796b783dedSPawel Dembicki 	 * based on tag_8021q.
16806b783dedSPawel Dembicki 	 */
16816b783dedSPawel Dembicki 	if (port == CPU_PORT)
16826b783dedSPawel Dembicki 		goto update_vlan_table;
16836b783dedSPawel Dembicki 
16846b783dedSPawel Dembicki 	if (untagged)
16856b783dedSPawel Dembicki 		vsc73xx_vlan->untagged |= BIT(port);
16866b783dedSPawel Dembicki 	else
16876b783dedSPawel Dembicki 		vsc73xx_vlan->untagged &= ~BIT(port);
16886b783dedSPawel Dembicki 
16896b783dedSPawel Dembicki 	portinfo = &vsc->portinfo[port];
16906b783dedSPawel Dembicki 
16916b783dedSPawel Dembicki 	if (pvid) {
16926b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering_configured = true;
16936b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering = vlan->vid;
16946b783dedSPawel Dembicki 	} else if (portinfo->pvid_vlan_filtering_configured &&
16956b783dedSPawel Dembicki 		   portinfo->pvid_vlan_filtering == vlan->vid) {
16966b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering_configured = false;
16976b783dedSPawel Dembicki 	}
16986b783dedSPawel Dembicki 
16996b783dedSPawel Dembicki 	commit_to_hardware = !vsc73xx_tag_8021q_active(dp);
17006b783dedSPawel Dembicki 	if (commit_to_hardware) {
17016b783dedSPawel Dembicki 		ret = vsc73xx_vlan_commit_settings(vsc, port);
17026b783dedSPawel Dembicki 		if (ret)
17036b783dedSPawel Dembicki 			goto err;
17046b783dedSPawel Dembicki 	}
17056b783dedSPawel Dembicki 
17066b783dedSPawel Dembicki update_vlan_table:
17076b783dedSPawel Dembicki 	ret = vsc73xx_update_vlan_table(vsc, port, vlan->vid, true);
17086b783dedSPawel Dembicki 	if (!ret)
17096b783dedSPawel Dembicki 		return 0;
17106b783dedSPawel Dembicki err:
17116b783dedSPawel Dembicki 	vsc73xx_bridge_vlan_remove_port(vsc73xx_vlan, port);
17126b783dedSPawel Dembicki 	return ret;
17136b783dedSPawel Dembicki }
17146b783dedSPawel Dembicki 
vsc73xx_port_vlan_del(struct dsa_switch * ds,int port,const struct switchdev_obj_port_vlan * vlan)17156b783dedSPawel Dembicki static int vsc73xx_port_vlan_del(struct dsa_switch *ds, int port,
17166b783dedSPawel Dembicki 				 const struct switchdev_obj_port_vlan *vlan)
17176b783dedSPawel Dembicki {
17186b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vsc73xx_vlan;
17196b783dedSPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
17206b783dedSPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
17216b783dedSPawel Dembicki 	bool commit_to_hardware;
17226b783dedSPawel Dembicki 	int ret;
17236b783dedSPawel Dembicki 
17246b783dedSPawel Dembicki 	ret = vsc73xx_update_vlan_table(vsc, port, vlan->vid, false);
17256b783dedSPawel Dembicki 	if (ret)
17266b783dedSPawel Dembicki 		return ret;
17276b783dedSPawel Dembicki 
17286b783dedSPawel Dembicki 	portinfo = &vsc->portinfo[port];
17296b783dedSPawel Dembicki 
17306b783dedSPawel Dembicki 	if (portinfo->pvid_vlan_filtering_configured &&
17316b783dedSPawel Dembicki 	    portinfo->pvid_vlan_filtering == vlan->vid)
17326b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering_configured = false;
17336b783dedSPawel Dembicki 
17346b783dedSPawel Dembicki 	vsc73xx_vlan = vsc73xx_bridge_vlan_find(vsc, vlan->vid);
17356b783dedSPawel Dembicki 
17366b783dedSPawel Dembicki 	if (vsc73xx_vlan)
17376b783dedSPawel Dembicki 		vsc73xx_bridge_vlan_remove_port(vsc73xx_vlan, port);
17386b783dedSPawel Dembicki 
17396b783dedSPawel Dembicki 	commit_to_hardware = !vsc73xx_tag_8021q_active(dsa_to_port(ds, port));
1740e3386ec4SPawel Dembicki 
17416b783dedSPawel Dembicki 	if (commit_to_hardware)
17426b783dedSPawel Dembicki 		return vsc73xx_vlan_commit_settings(vsc, port);
17436b783dedSPawel Dembicki 
17446b783dedSPawel Dembicki 	return 0;
17456b783dedSPawel Dembicki }
17466b783dedSPawel Dembicki 
vsc73xx_tag_8021q_vlan_add(struct dsa_switch * ds,int port,u16 vid,u16 flags)1747e3386ec4SPawel Dembicki static int vsc73xx_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
1748e3386ec4SPawel Dembicki 				      u16 flags)
1749e3386ec4SPawel Dembicki {
1750e3386ec4SPawel Dembicki 	bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
1751e3386ec4SPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
1752e3386ec4SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
1753e3386ec4SPawel Dembicki 	bool commit_to_hardware;
1754e3386ec4SPawel Dembicki 	int ret;
1755e3386ec4SPawel Dembicki 
1756e3386ec4SPawel Dembicki 	portinfo = &vsc->portinfo[port];
1757e3386ec4SPawel Dembicki 
1758e3386ec4SPawel Dembicki 	if (pvid) {
1759e3386ec4SPawel Dembicki 		portinfo->pvid_tag_8021q_configured = true;
1760e3386ec4SPawel Dembicki 		portinfo->pvid_tag_8021q = vid;
1761e3386ec4SPawel Dembicki 	}
1762e3386ec4SPawel Dembicki 
1763e3386ec4SPawel Dembicki 	commit_to_hardware = vsc73xx_tag_8021q_active(dsa_to_port(ds, port));
1764e3386ec4SPawel Dembicki 	if (commit_to_hardware) {
1765e3386ec4SPawel Dembicki 		ret = vsc73xx_vlan_commit_settings(vsc, port);
1766e3386ec4SPawel Dembicki 		if (ret)
1767e3386ec4SPawel Dembicki 			return ret;
1768e3386ec4SPawel Dembicki 	}
1769e3386ec4SPawel Dembicki 
1770e3386ec4SPawel Dembicki 	return vsc73xx_update_vlan_table(vsc, port, vid, true);
1771e3386ec4SPawel Dembicki }
1772e3386ec4SPawel Dembicki 
vsc73xx_tag_8021q_vlan_del(struct dsa_switch * ds,int port,u16 vid)1773e3386ec4SPawel Dembicki static int vsc73xx_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
1774e3386ec4SPawel Dembicki {
1775e3386ec4SPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
1776e3386ec4SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
1777e3386ec4SPawel Dembicki 
1778e3386ec4SPawel Dembicki 	portinfo = &vsc->portinfo[port];
1779e3386ec4SPawel Dembicki 
1780e3386ec4SPawel Dembicki 	if (portinfo->pvid_tag_8021q_configured &&
1781e3386ec4SPawel Dembicki 	    portinfo->pvid_tag_8021q == vid) {
1782e3386ec4SPawel Dembicki 		struct dsa_port *dp = dsa_to_port(ds, port);
1783e3386ec4SPawel Dembicki 		bool commit_to_hardware;
1784e3386ec4SPawel Dembicki 		int err;
1785e3386ec4SPawel Dembicki 
1786e3386ec4SPawel Dembicki 		portinfo->pvid_tag_8021q_configured = false;
1787e3386ec4SPawel Dembicki 
1788e3386ec4SPawel Dembicki 		commit_to_hardware = vsc73xx_tag_8021q_active(dp);
1789e3386ec4SPawel Dembicki 		if (commit_to_hardware) {
1790e3386ec4SPawel Dembicki 			err = vsc73xx_vlan_commit_settings(vsc, port);
1791e3386ec4SPawel Dembicki 			if (err)
1792e3386ec4SPawel Dembicki 				return err;
1793e3386ec4SPawel Dembicki 		}
1794e3386ec4SPawel Dembicki 	}
1795e3386ec4SPawel Dembicki 
1796e3386ec4SPawel Dembicki 	return vsc73xx_update_vlan_table(vsc, port, vid, false);
1797e3386ec4SPawel Dembicki }
1798e3386ec4SPawel Dembicki 
vsc73xx_port_pre_bridge_flags(struct dsa_switch * ds,int port,struct switchdev_brport_flags flags,struct netlink_ext_ack * extack)1799259a7061SPawel Dembicki static int vsc73xx_port_pre_bridge_flags(struct dsa_switch *ds, int port,
1800259a7061SPawel Dembicki 					 struct switchdev_brport_flags flags,
1801259a7061SPawel Dembicki 					 struct netlink_ext_ack *extack)
1802259a7061SPawel Dembicki {
1803259a7061SPawel Dembicki 	if (flags.mask & ~BR_LEARNING)
1804259a7061SPawel Dembicki 		return -EINVAL;
1805259a7061SPawel Dembicki 
1806259a7061SPawel Dembicki 	return 0;
1807259a7061SPawel Dembicki }
1808259a7061SPawel Dembicki 
vsc73xx_port_bridge_flags(struct dsa_switch * ds,int port,struct switchdev_brport_flags flags,struct netlink_ext_ack * extack)1809259a7061SPawel Dembicki static int vsc73xx_port_bridge_flags(struct dsa_switch *ds, int port,
1810259a7061SPawel Dembicki 				     struct switchdev_brport_flags flags,
1811259a7061SPawel Dembicki 				     struct netlink_ext_ack *extack)
1812259a7061SPawel Dembicki {
1813259a7061SPawel Dembicki 	if (flags.mask & BR_LEARNING) {
1814259a7061SPawel Dembicki 		u32 val = flags.val & BR_LEARNING ? BIT(port) : 0;
1815259a7061SPawel Dembicki 		struct vsc73xx *vsc = ds->priv;
1816259a7061SPawel Dembicki 
1817259a7061SPawel Dembicki 		return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
1818259a7061SPawel Dembicki 					   VSC73XX_LEARNMASK, BIT(port), val);
1819259a7061SPawel Dembicki 	}
1820259a7061SPawel Dembicki 
1821259a7061SPawel Dembicki 	return 0;
1822259a7061SPawel Dembicki }
1823259a7061SPawel Dembicki 
vsc73xx_refresh_fwd_map(struct dsa_switch * ds,int port,u8 state)18241e5b23e5SPawel Dembicki static void vsc73xx_refresh_fwd_map(struct dsa_switch *ds, int port, u8 state)
18251e5b23e5SPawel Dembicki {
18261e5b23e5SPawel Dembicki 	struct dsa_port *other_dp, *dp = dsa_to_port(ds, port);
18271e5b23e5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
18281e5b23e5SPawel Dembicki 	u16 mask;
18291e5b23e5SPawel Dembicki 
18301e5b23e5SPawel Dembicki 	if (state != BR_STATE_FORWARDING) {
18311e5b23e5SPawel Dembicki 		/* Ports that aren't in the forwarding state must not
18321e5b23e5SPawel Dembicki 		 * forward packets anywhere.
18331e5b23e5SPawel Dembicki 		 */
18341e5b23e5SPawel Dembicki 		vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
18351e5b23e5SPawel Dembicki 				    VSC73XX_SRCMASKS + port,
18361e5b23e5SPawel Dembicki 				    VSC73XX_SRCMASKS_PORTS_MASK, 0);
18371e5b23e5SPawel Dembicki 
18381e5b23e5SPawel Dembicki 		dsa_switch_for_each_available_port(other_dp, ds) {
18391e5b23e5SPawel Dembicki 			if (other_dp == dp)
18401e5b23e5SPawel Dembicki 				continue;
18411e5b23e5SPawel Dembicki 			vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
18421e5b23e5SPawel Dembicki 					    VSC73XX_SRCMASKS + other_dp->index,
18431e5b23e5SPawel Dembicki 					    BIT(port), 0);
18441e5b23e5SPawel Dembicki 		}
18451e5b23e5SPawel Dembicki 
18461e5b23e5SPawel Dembicki 		return;
18471e5b23e5SPawel Dembicki 	}
18481e5b23e5SPawel Dembicki 
18491e5b23e5SPawel Dembicki 	/* Forwarding ports must forward to the CPU and to other ports
18501e5b23e5SPawel Dembicki 	 * in the same bridge
18511e5b23e5SPawel Dembicki 	 */
18521e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
18531e5b23e5SPawel Dembicki 			    VSC73XX_SRCMASKS + CPU_PORT, BIT(port), BIT(port));
18541e5b23e5SPawel Dembicki 
18551e5b23e5SPawel Dembicki 	mask = BIT(CPU_PORT);
18561e5b23e5SPawel Dembicki 
18571e5b23e5SPawel Dembicki 	dsa_switch_for_each_user_port(other_dp, ds) {
18581e5b23e5SPawel Dembicki 		int other_port = other_dp->index;
18591e5b23e5SPawel Dembicki 
18601e5b23e5SPawel Dembicki 		if (port == other_port || !dsa_port_bridge_same(dp, other_dp) ||
18611e5b23e5SPawel Dembicki 		    other_dp->stp_state != BR_STATE_FORWARDING)
18621e5b23e5SPawel Dembicki 			continue;
18631e5b23e5SPawel Dembicki 
18641e5b23e5SPawel Dembicki 		mask |= BIT(other_port);
18651e5b23e5SPawel Dembicki 
18661e5b23e5SPawel Dembicki 		vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
18671e5b23e5SPawel Dembicki 				    VSC73XX_SRCMASKS + other_port,
18681e5b23e5SPawel Dembicki 				    BIT(port), BIT(port));
18691e5b23e5SPawel Dembicki 	}
18701e5b23e5SPawel Dembicki 
18711e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
18721e5b23e5SPawel Dembicki 			    VSC73XX_SRCMASKS + port,
18731e5b23e5SPawel Dembicki 			    VSC73XX_SRCMASKS_PORTS_MASK, mask);
18741e5b23e5SPawel Dembicki }
18751e5b23e5SPawel Dembicki 
18761e5b23e5SPawel Dembicki /* FIXME: STP frames aren't forwarded at this moment. BPDU frames are
18771e5b23e5SPawel Dembicki  * forwarded only from and to PI/SI interface. For more info see chapter
18781e5b23e5SPawel Dembicki  * 2.7.1 (CPU Forwarding) in datasheet.
18791e5b23e5SPawel Dembicki  * This function is required for tag_8021q operations.
18801e5b23e5SPawel Dembicki  */
vsc73xx_port_stp_state_set(struct dsa_switch * ds,int port,u8 state)18811e5b23e5SPawel Dembicki static void vsc73xx_port_stp_state_set(struct dsa_switch *ds, int port,
18821e5b23e5SPawel Dembicki 				       u8 state)
18831e5b23e5SPawel Dembicki {
1884259a7061SPawel Dembicki 	struct dsa_port *dp = dsa_to_port(ds, port);
18851e5b23e5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
1886259a7061SPawel Dembicki 	u32 val = 0;
1887259a7061SPawel Dembicki 
1888259a7061SPawel Dembicki 	if (state == BR_STATE_LEARNING || state == BR_STATE_FORWARDING)
1889259a7061SPawel Dembicki 		val = dp->learning ? BIT(port) : 0;
1890259a7061SPawel Dembicki 
1891259a7061SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
1892259a7061SPawel Dembicki 			    VSC73XX_LEARNMASK, BIT(port), val);
18931e5b23e5SPawel Dembicki 
18941e5b23e5SPawel Dembicki 	val = (state == BR_STATE_BLOCKING || state == BR_STATE_DISABLED) ?
18951e5b23e5SPawel Dembicki 	      0 : BIT(port);
18961e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
18971e5b23e5SPawel Dembicki 			    VSC73XX_RECVMASK, BIT(port), val);
18981e5b23e5SPawel Dembicki 
18991e5b23e5SPawel Dembicki 	/* CPU Port should always forward packets when user ports are forwarding
19001e5b23e5SPawel Dembicki 	 * so let's configure it from other ports only.
19011e5b23e5SPawel Dembicki 	 */
19021e5b23e5SPawel Dembicki 	if (port != CPU_PORT)
19031e5b23e5SPawel Dembicki 		vsc73xx_refresh_fwd_map(ds, port, state);
19041e5b23e5SPawel Dembicki }
19051e5b23e5SPawel Dembicki 
vsc73xx_calc_hash(const unsigned char * addr,u16 vid)1906*075e3d30SPawel Dembicki static u16 vsc73xx_calc_hash(const unsigned char *addr, u16 vid)
1907*075e3d30SPawel Dembicki {
1908*075e3d30SPawel Dembicki 	/* VID 5-0, MAC 47-44 */
1909*075e3d30SPawel Dembicki 	u16 hash = FIELD_PREP(VSC73XX_HASH0_VID_TO_MASK,
1910*075e3d30SPawel Dembicki 			      FIELD_GET(VSC73XX_HASH0_VID_FROM_MASK, vid)) |
1911*075e3d30SPawel Dembicki 		   FIELD_PREP(VSC73XX_HASH0_MAC0_TO_MASK,
1912*075e3d30SPawel Dembicki 			      FIELD_GET(VSC73XX_HASH0_MAC0_FROM_MASK, addr[0]));
1913*075e3d30SPawel Dembicki 	/* MAC 43-33 */
1914*075e3d30SPawel Dembicki 	hash ^= FIELD_PREP(VSC73XX_HASH1_MAC0_TO_MASK,
1915*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH1_MAC0_FROM_MASK, addr[0])) |
1916*075e3d30SPawel Dembicki 		FIELD_PREP(VSC73XX_HASH1_MAC1_TO_MASK,
1917*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH1_MAC1_FROM_MASK, addr[1]));
1918*075e3d30SPawel Dembicki 	/* MAC 32-22 */
1919*075e3d30SPawel Dembicki 	hash ^= FIELD_PREP(VSC73XX_HASH2_MAC1_TO_MASK,
1920*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH2_MAC1_FROM_MASK, addr[1])) |
1921*075e3d30SPawel Dembicki 		FIELD_PREP(VSC73XX_HASH2_MAC2_TO_MASK,
1922*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH2_MAC2_FROM_MASK, addr[2])) |
1923*075e3d30SPawel Dembicki 		FIELD_PREP(VSC73XX_HASH2_MAC3_TO_MASK,
1924*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH2_MAC3_FROM_MASK, addr[3]));
1925*075e3d30SPawel Dembicki 	/* MAC 21-11 */
1926*075e3d30SPawel Dembicki 	hash ^= FIELD_PREP(VSC73XX_HASH3_MAC3_TO_MASK,
1927*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH3_MAC3_FROM_MASK, addr[3])) |
1928*075e3d30SPawel Dembicki 		FIELD_PREP(VSC73XX_HASH3_MAC4_TO_MASK,
1929*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH3_MAC4_FROM_MASK, addr[4]));
1930*075e3d30SPawel Dembicki 	/* MAC 10-0 */
1931*075e3d30SPawel Dembicki 	hash ^= FIELD_PREP(VSC73XX_HASH4_MAC4_TO_MASK,
1932*075e3d30SPawel Dembicki 			   FIELD_GET(VSC73XX_HASH4_MAC4_FROM_MASK, addr[4])) |
1933*075e3d30SPawel Dembicki 		addr[5];
1934*075e3d30SPawel Dembicki 
1935*075e3d30SPawel Dembicki 	return hash;
1936*075e3d30SPawel Dembicki }
1937*075e3d30SPawel Dembicki 
1938*075e3d30SPawel Dembicki static int
vsc73xx_port_wait_for_mac_table_cmd(struct vsc73xx * vsc)1939*075e3d30SPawel Dembicki vsc73xx_port_wait_for_mac_table_cmd(struct vsc73xx *vsc)
1940*075e3d30SPawel Dembicki {
1941*075e3d30SPawel Dembicki 	int ret, err;
1942*075e3d30SPawel Dembicki 	u32 val;
1943*075e3d30SPawel Dembicki 
1944*075e3d30SPawel Dembicki 	ret = read_poll_timeout(vsc73xx_read, err,
1945*075e3d30SPawel Dembicki 				err < 0 ||
1946*075e3d30SPawel Dembicki 				((val & VSC73XX_MACACCESS_CMD_MASK) ==
1947*075e3d30SPawel Dembicki 				 VSC73XX_MACACCESS_CMD_IDLE),
1948*075e3d30SPawel Dembicki 				VSC73XX_POLL_SLEEP_US, VSC73XX_POLL_TIMEOUT_US,
1949*075e3d30SPawel Dembicki 				false, vsc, VSC73XX_BLOCK_ANALYZER,
1950*075e3d30SPawel Dembicki 				0, VSC73XX_MACACCESS, &val);
1951*075e3d30SPawel Dembicki 	if (ret)
1952*075e3d30SPawel Dembicki 		return ret;
1953*075e3d30SPawel Dembicki 	return err;
1954*075e3d30SPawel Dembicki }
1955*075e3d30SPawel Dembicki 
vsc73xx_port_read_mac_table_row(struct vsc73xx * vsc,u16 index,struct vsc73xx_fdb * fdb)1956*075e3d30SPawel Dembicki static int vsc73xx_port_read_mac_table_row(struct vsc73xx *vsc, u16 index,
1957*075e3d30SPawel Dembicki 					   struct vsc73xx_fdb *fdb)
1958*075e3d30SPawel Dembicki {
1959*075e3d30SPawel Dembicki 	int ret, i;
1960*075e3d30SPawel Dembicki 	u32 val;
1961*075e3d30SPawel Dembicki 
1962*075e3d30SPawel Dembicki 	if (!fdb)
1963*075e3d30SPawel Dembicki 		return -EINVAL;
1964*075e3d30SPawel Dembicki 	if (index >= VSC73XX_NUM_FDB_ROWS)
1965*075e3d30SPawel Dembicki 		return -EINVAL;
1966*075e3d30SPawel Dembicki 
1967*075e3d30SPawel Dembicki 	for (i = 0; i < VSC73XX_NUM_BUCKETS; i++) {
1968*075e3d30SPawel Dembicki 		ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
1969*075e3d30SPawel Dembicki 				    VSC73XX_MACTINDX,
1970*075e3d30SPawel Dembicki 				    (i ? 0 : VSC73XX_MACTINDX_SHADOW) |
1971*075e3d30SPawel Dembicki 				    FIELD_PREP(VSC73XX_MACTINDX_BUCKET_MSK, i) |
1972*075e3d30SPawel Dembicki 				    index);
1973*075e3d30SPawel Dembicki 		if (ret)
1974*075e3d30SPawel Dembicki 			return ret;
1975*075e3d30SPawel Dembicki 
1976*075e3d30SPawel Dembicki 		ret = vsc73xx_port_wait_for_mac_table_cmd(vsc);
1977*075e3d30SPawel Dembicki 		if (ret)
1978*075e3d30SPawel Dembicki 			return ret;
1979*075e3d30SPawel Dembicki 
1980*075e3d30SPawel Dembicki 		ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
1981*075e3d30SPawel Dembicki 					  VSC73XX_MACACCESS,
1982*075e3d30SPawel Dembicki 					  VSC73XX_MACACCESS_CMD_MASK,
1983*075e3d30SPawel Dembicki 					  VSC73XX_MACACCESS_CMD_READ_ENTRY);
1984*075e3d30SPawel Dembicki 		if (ret)
1985*075e3d30SPawel Dembicki 			return ret;
1986*075e3d30SPawel Dembicki 
1987*075e3d30SPawel Dembicki 		ret = vsc73xx_port_wait_for_mac_table_cmd(vsc);
1988*075e3d30SPawel Dembicki 		if (ret)
1989*075e3d30SPawel Dembicki 			return ret;
1990*075e3d30SPawel Dembicki 
1991*075e3d30SPawel Dembicki 		ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0,
1992*075e3d30SPawel Dembicki 				   VSC73XX_MACACCESS, &val);
1993*075e3d30SPawel Dembicki 		if (ret)
1994*075e3d30SPawel Dembicki 			return ret;
1995*075e3d30SPawel Dembicki 
1996*075e3d30SPawel Dembicki 		fdb[i].valid = FIELD_GET(VSC73XX_MACACCESS_VALID, val);
1997*075e3d30SPawel Dembicki 		if (!fdb[i].valid)
1998*075e3d30SPawel Dembicki 			continue;
1999*075e3d30SPawel Dembicki 
2000*075e3d30SPawel Dembicki 		fdb[i].port = FIELD_GET(VSC73XX_MACACCESS_DEST_IDX_MASK, val);
2001*075e3d30SPawel Dembicki 
2002*075e3d30SPawel Dembicki 		ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0,
2003*075e3d30SPawel Dembicki 				   VSC73XX_MACHDATA, &val);
2004*075e3d30SPawel Dembicki 		if (ret)
2005*075e3d30SPawel Dembicki 			return ret;
2006*075e3d30SPawel Dembicki 
2007*075e3d30SPawel Dembicki 		fdb[i].vid = FIELD_GET(VSC73XX_MACHDATA_VID, val);
2008*075e3d30SPawel Dembicki 		fdb[i].mac[0] = FIELD_GET(VSC73XX_MACHDATA_MAC0, val);
2009*075e3d30SPawel Dembicki 		fdb[i].mac[1] = FIELD_GET(VSC73XX_MACHDATA_MAC1, val);
2010*075e3d30SPawel Dembicki 
2011*075e3d30SPawel Dembicki 		ret = vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0,
2012*075e3d30SPawel Dembicki 				   VSC73XX_MACLDATA, &val);
2013*075e3d30SPawel Dembicki 		if (ret)
2014*075e3d30SPawel Dembicki 			return ret;
2015*075e3d30SPawel Dembicki 
2016*075e3d30SPawel Dembicki 		fdb[i].mac[2] = FIELD_GET(VSC73XX_MACLDATA_MAC2, val);
2017*075e3d30SPawel Dembicki 		fdb[i].mac[3] = FIELD_GET(VSC73XX_MACLDATA_MAC3, val);
2018*075e3d30SPawel Dembicki 		fdb[i].mac[4] = FIELD_GET(VSC73XX_MACLDATA_MAC4, val);
2019*075e3d30SPawel Dembicki 		fdb[i].mac[5] = FIELD_GET(VSC73XX_MACLDATA_MAC5, val);
2020*075e3d30SPawel Dembicki 	}
2021*075e3d30SPawel Dembicki 
2022*075e3d30SPawel Dembicki 	return ret;
2023*075e3d30SPawel Dembicki }
2024*075e3d30SPawel Dembicki 
2025*075e3d30SPawel Dembicki static int
vsc73xx_fdb_operation(struct vsc73xx * vsc,const unsigned char * addr,u16 vid,u16 hash,u16 cmd_mask,u16 cmd_val)2026*075e3d30SPawel Dembicki vsc73xx_fdb_operation(struct vsc73xx *vsc, const unsigned char *addr, u16 vid,
2027*075e3d30SPawel Dembicki 		      u16 hash, u16 cmd_mask, u16 cmd_val)
2028*075e3d30SPawel Dembicki {
2029*075e3d30SPawel Dembicki 	int ret;
2030*075e3d30SPawel Dembicki 	u32 val;
2031*075e3d30SPawel Dembicki 
2032*075e3d30SPawel Dembicki 	val = FIELD_PREP(VSC73XX_MACHDATA_VID, vid) |
2033*075e3d30SPawel Dembicki 	      FIELD_PREP(VSC73XX_MACHDATA_MAC0, addr[0]) |
2034*075e3d30SPawel Dembicki 	      FIELD_PREP(VSC73XX_MACHDATA_MAC1, addr[1]);
2035*075e3d30SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_MACHDATA,
2036*075e3d30SPawel Dembicki 			    val);
2037*075e3d30SPawel Dembicki 	if (ret)
2038*075e3d30SPawel Dembicki 		return ret;
2039*075e3d30SPawel Dembicki 
2040*075e3d30SPawel Dembicki 	val = FIELD_PREP(VSC73XX_MACLDATA_MAC2, addr[2]) |
2041*075e3d30SPawel Dembicki 	      FIELD_PREP(VSC73XX_MACLDATA_MAC3, addr[3]) |
2042*075e3d30SPawel Dembicki 	      FIELD_PREP(VSC73XX_MACLDATA_MAC4, addr[4]) |
2043*075e3d30SPawel Dembicki 	      FIELD_PREP(VSC73XX_MACLDATA_MAC5, addr[5]);
2044*075e3d30SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_MACLDATA,
2045*075e3d30SPawel Dembicki 			    val);
2046*075e3d30SPawel Dembicki 	if (ret)
2047*075e3d30SPawel Dembicki 		return ret;
2048*075e3d30SPawel Dembicki 
2049*075e3d30SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_MACTINDX,
2050*075e3d30SPawel Dembicki 			    hash);
2051*075e3d30SPawel Dembicki 	if (ret)
2052*075e3d30SPawel Dembicki 		return ret;
2053*075e3d30SPawel Dembicki 
2054*075e3d30SPawel Dembicki 	ret = vsc73xx_port_wait_for_mac_table_cmd(vsc);
2055*075e3d30SPawel Dembicki 	if (ret)
2056*075e3d30SPawel Dembicki 		return ret;
2057*075e3d30SPawel Dembicki 
2058*075e3d30SPawel Dembicki 	ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
2059*075e3d30SPawel Dembicki 				  VSC73XX_MACACCESS, cmd_mask, cmd_val);
2060*075e3d30SPawel Dembicki 	if (ret)
2061*075e3d30SPawel Dembicki 		return ret;
2062*075e3d30SPawel Dembicki 
2063*075e3d30SPawel Dembicki 	return vsc73xx_port_wait_for_mac_table_cmd(vsc);
2064*075e3d30SPawel Dembicki }
2065*075e3d30SPawel Dembicki 
vsc73xx_fdb_del_entry(struct vsc73xx * vsc,int port,const unsigned char * addr,u16 vid)2066*075e3d30SPawel Dembicki static int vsc73xx_fdb_del_entry(struct vsc73xx *vsc, int port,
2067*075e3d30SPawel Dembicki 				 const unsigned char *addr, u16 vid)
2068*075e3d30SPawel Dembicki {
2069*075e3d30SPawel Dembicki 	struct vsc73xx_fdb fdb[VSC73XX_NUM_BUCKETS];
2070*075e3d30SPawel Dembicki 	u16 hash = vsc73xx_calc_hash(addr, vid);
2071*075e3d30SPawel Dembicki 	int bucket, ret;
2072*075e3d30SPawel Dembicki 
2073*075e3d30SPawel Dembicki 	mutex_lock(&vsc->fdb_lock);
2074*075e3d30SPawel Dembicki 
2075*075e3d30SPawel Dembicki 	ret = vsc73xx_port_read_mac_table_row(vsc, hash, fdb);
2076*075e3d30SPawel Dembicki 	if (ret)
2077*075e3d30SPawel Dembicki 		goto err;
2078*075e3d30SPawel Dembicki 
2079*075e3d30SPawel Dembicki 	for (bucket = 0; bucket < VSC73XX_NUM_BUCKETS; bucket++) {
2080*075e3d30SPawel Dembicki 		if (fdb[bucket].valid && fdb[bucket].port == port &&
2081*075e3d30SPawel Dembicki 		    ether_addr_equal(addr, fdb[bucket].mac))
2082*075e3d30SPawel Dembicki 			break;
2083*075e3d30SPawel Dembicki 	}
2084*075e3d30SPawel Dembicki 
2085*075e3d30SPawel Dembicki 	if (bucket == VSC73XX_NUM_BUCKETS) {
2086*075e3d30SPawel Dembicki 		/* Can't find MAC in MAC table */
2087*075e3d30SPawel Dembicki 		ret = -ENODATA;
2088*075e3d30SPawel Dembicki 		goto err;
2089*075e3d30SPawel Dembicki 	}
2090*075e3d30SPawel Dembicki 
2091*075e3d30SPawel Dembicki 	ret = vsc73xx_fdb_operation(vsc, addr, vid, hash,
2092*075e3d30SPawel Dembicki 				    VSC73XX_MACACCESS_CMD_MASK,
2093*075e3d30SPawel Dembicki 				    VSC73XX_MACACCESS_CMD_FORGET);
2094*075e3d30SPawel Dembicki err:
2095*075e3d30SPawel Dembicki 	mutex_unlock(&vsc->fdb_lock);
2096*075e3d30SPawel Dembicki 	return ret;
2097*075e3d30SPawel Dembicki }
2098*075e3d30SPawel Dembicki 
vsc73xx_fdb_add_entry(struct vsc73xx * vsc,int port,const unsigned char * addr,u16 vid)2099*075e3d30SPawel Dembicki static int vsc73xx_fdb_add_entry(struct vsc73xx *vsc, int port,
2100*075e3d30SPawel Dembicki 				 const unsigned char *addr, u16 vid)
2101*075e3d30SPawel Dembicki {
2102*075e3d30SPawel Dembicki 	struct vsc73xx_fdb fdb[VSC73XX_NUM_BUCKETS];
2103*075e3d30SPawel Dembicki 	u16 hash = vsc73xx_calc_hash(addr, vid);
2104*075e3d30SPawel Dembicki 	int bucket, ret;
2105*075e3d30SPawel Dembicki 	u32 val;
2106*075e3d30SPawel Dembicki 
2107*075e3d30SPawel Dembicki 	mutex_lock(&vsc->fdb_lock);
2108*075e3d30SPawel Dembicki 
2109*075e3d30SPawel Dembicki 	ret = vsc73xx_port_read_mac_table_row(vsc, hash, fdb);
2110*075e3d30SPawel Dembicki 	if (ret)
2111*075e3d30SPawel Dembicki 		goto err;
2112*075e3d30SPawel Dembicki 
2113*075e3d30SPawel Dembicki 	for (bucket = 0; bucket < VSC73XX_NUM_BUCKETS; bucket++) {
2114*075e3d30SPawel Dembicki 		if (!fdb[bucket].valid)
2115*075e3d30SPawel Dembicki 			break;
2116*075e3d30SPawel Dembicki 	}
2117*075e3d30SPawel Dembicki 
2118*075e3d30SPawel Dembicki 	if (bucket == VSC73XX_NUM_BUCKETS) {
2119*075e3d30SPawel Dembicki 		/* Bucket is full */
2120*075e3d30SPawel Dembicki 		ret = -EOVERFLOW;
2121*075e3d30SPawel Dembicki 		goto err;
2122*075e3d30SPawel Dembicki 	}
2123*075e3d30SPawel Dembicki 
2124*075e3d30SPawel Dembicki 	val = VSC73XX_MACACCESS_VALID | VSC73XX_MACACCESS_LOCKED |
2125*075e3d30SPawel Dembicki 	      FIELD_PREP(VSC73XX_MACACCESS_DEST_IDX_MASK, port) |
2126*075e3d30SPawel Dembicki 	      VSC73XX_MACACCESS_CMD_LEARN;
2127*075e3d30SPawel Dembicki 	ret = vsc73xx_fdb_operation(vsc, addr, vid, hash,
2128*075e3d30SPawel Dembicki 				    VSC73XX_MACACCESS_VALID |
2129*075e3d30SPawel Dembicki 				    VSC73XX_MACACCESS_LOCKED |
2130*075e3d30SPawel Dembicki 				    VSC73XX_MACACCESS_DEST_IDX_MASK |
2131*075e3d30SPawel Dembicki 				    VSC73XX_MACACCESS_CMD_MASK, val);
2132*075e3d30SPawel Dembicki err:
2133*075e3d30SPawel Dembicki 	mutex_unlock(&vsc->fdb_lock);
2134*075e3d30SPawel Dembicki 	return ret;
2135*075e3d30SPawel Dembicki }
2136*075e3d30SPawel Dembicki 
vsc73xx_fdb_add(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)2137*075e3d30SPawel Dembicki static int vsc73xx_fdb_add(struct dsa_switch *ds, int port,
2138*075e3d30SPawel Dembicki 			   const unsigned char *addr, u16 vid, struct dsa_db db)
2139*075e3d30SPawel Dembicki {
2140*075e3d30SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
2141*075e3d30SPawel Dembicki 
2142*075e3d30SPawel Dembicki 	if (!vid) {
2143*075e3d30SPawel Dembicki 		switch (db.type) {
2144*075e3d30SPawel Dembicki 		case DSA_DB_PORT:
2145*075e3d30SPawel Dembicki 			vid = dsa_tag_8021q_standalone_vid(db.dp);
2146*075e3d30SPawel Dembicki 			break;
2147*075e3d30SPawel Dembicki 		case DSA_DB_BRIDGE:
2148*075e3d30SPawel Dembicki 			vid = dsa_tag_8021q_bridge_vid(db.bridge.num);
2149*075e3d30SPawel Dembicki 			break;
2150*075e3d30SPawel Dembicki 		default:
2151*075e3d30SPawel Dembicki 			return -EOPNOTSUPP;
2152*075e3d30SPawel Dembicki 		}
2153*075e3d30SPawel Dembicki 	}
2154*075e3d30SPawel Dembicki 
2155*075e3d30SPawel Dembicki 	return vsc73xx_fdb_add_entry(vsc, port, addr, vid);
2156*075e3d30SPawel Dembicki }
2157*075e3d30SPawel Dembicki 
vsc73xx_fdb_del(struct dsa_switch * ds,int port,const unsigned char * addr,u16 vid,struct dsa_db db)2158*075e3d30SPawel Dembicki static int vsc73xx_fdb_del(struct dsa_switch *ds, int port,
2159*075e3d30SPawel Dembicki 			   const unsigned char *addr, u16 vid, struct dsa_db db)
2160*075e3d30SPawel Dembicki {
2161*075e3d30SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
2162*075e3d30SPawel Dembicki 
2163*075e3d30SPawel Dembicki 	if (!vid) {
2164*075e3d30SPawel Dembicki 		switch (db.type) {
2165*075e3d30SPawel Dembicki 		case DSA_DB_PORT:
2166*075e3d30SPawel Dembicki 			vid = dsa_tag_8021q_standalone_vid(db.dp);
2167*075e3d30SPawel Dembicki 			break;
2168*075e3d30SPawel Dembicki 		case DSA_DB_BRIDGE:
2169*075e3d30SPawel Dembicki 			vid = dsa_tag_8021q_bridge_vid(db.bridge.num);
2170*075e3d30SPawel Dembicki 			break;
2171*075e3d30SPawel Dembicki 		default:
2172*075e3d30SPawel Dembicki 			return -EOPNOTSUPP;
2173*075e3d30SPawel Dembicki 		}
2174*075e3d30SPawel Dembicki 	}
2175*075e3d30SPawel Dembicki 
2176*075e3d30SPawel Dembicki 	return vsc73xx_fdb_del_entry(vsc, port, addr, vid);
2177*075e3d30SPawel Dembicki }
2178*075e3d30SPawel Dembicki 
vsc73xx_port_fdb_dump(struct dsa_switch * ds,int port,dsa_fdb_dump_cb_t * cb,void * data)2179*075e3d30SPawel Dembicki static int vsc73xx_port_fdb_dump(struct dsa_switch *ds,
2180*075e3d30SPawel Dembicki 				 int port, dsa_fdb_dump_cb_t *cb, void *data)
2181*075e3d30SPawel Dembicki {
2182*075e3d30SPawel Dembicki 	struct vsc73xx_fdb fdb[VSC73XX_NUM_BUCKETS];
2183*075e3d30SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
2184*075e3d30SPawel Dembicki 	u16 i, bucket;
2185*075e3d30SPawel Dembicki 	int err = 0;
2186*075e3d30SPawel Dembicki 
2187*075e3d30SPawel Dembicki 	mutex_lock(&vsc->fdb_lock);
2188*075e3d30SPawel Dembicki 
2189*075e3d30SPawel Dembicki 	for (i = 0; i < VSC73XX_NUM_FDB_ROWS; i++) {
2190*075e3d30SPawel Dembicki 		err = vsc73xx_port_read_mac_table_row(vsc, i, fdb);
2191*075e3d30SPawel Dembicki 		if (err)
2192*075e3d30SPawel Dembicki 			goto unlock;
2193*075e3d30SPawel Dembicki 
2194*075e3d30SPawel Dembicki 		for (bucket = 0; bucket < VSC73XX_NUM_BUCKETS; bucket++) {
2195*075e3d30SPawel Dembicki 			if (!fdb[bucket].valid || fdb[bucket].port != port)
2196*075e3d30SPawel Dembicki 				continue;
2197*075e3d30SPawel Dembicki 
2198*075e3d30SPawel Dembicki 			/* We need to hide dsa_8021q VLANs from the user */
2199*075e3d30SPawel Dembicki 			if (vid_is_dsa_8021q(fdb[bucket].vid))
2200*075e3d30SPawel Dembicki 				fdb[bucket].vid = 0;
2201*075e3d30SPawel Dembicki 
2202*075e3d30SPawel Dembicki 			err = cb(fdb[bucket].mac, fdb[bucket].vid, false, data);
2203*075e3d30SPawel Dembicki 			if (err)
2204*075e3d30SPawel Dembicki 				goto unlock;
2205*075e3d30SPawel Dembicki 		}
2206*075e3d30SPawel Dembicki 	}
2207*075e3d30SPawel Dembicki unlock:
2208*075e3d30SPawel Dembicki 	mutex_unlock(&vsc->fdb_lock);
2209*075e3d30SPawel Dembicki 	return err;
2210*075e3d30SPawel Dembicki }
2211*075e3d30SPawel Dembicki 
221221fc3416SPawel Dembicki static const struct phylink_mac_ops vsc73xx_phylink_mac_ops = {
221321fc3416SPawel Dembicki 	.mac_config = vsc73xx_mac_config,
221421fc3416SPawel Dembicki 	.mac_link_down = vsc73xx_mac_link_down,
221521fc3416SPawel Dembicki 	.mac_link_up = vsc73xx_mac_link_up,
221621fc3416SPawel Dembicki };
221721fc3416SPawel Dembicki 
221895711cd5SPawel Dembicki static const struct dsa_switch_ops vsc73xx_ds_ops = {
221995711cd5SPawel Dembicki 	.get_tag_protocol = vsc73xx_get_tag_protocol,
222095711cd5SPawel Dembicki 	.setup = vsc73xx_setup,
2221e3386ec4SPawel Dembicki 	.teardown = vsc73xx_teardown,
222295711cd5SPawel Dembicki 	.phy_read = vsc73xx_phy_read,
222395711cd5SPawel Dembicki 	.phy_write = vsc73xx_phy_write,
222495711cd5SPawel Dembicki 	.get_strings = vsc73xx_get_strings,
222595711cd5SPawel Dembicki 	.get_ethtool_stats = vsc73xx_get_ethtool_stats,
222695711cd5SPawel Dembicki 	.get_sset_count = vsc73xx_get_sset_count,
222795711cd5SPawel Dembicki 	.port_enable = vsc73xx_port_enable,
222895711cd5SPawel Dembicki 	.port_disable = vsc73xx_port_disable,
2229259a7061SPawel Dembicki 	.port_pre_bridge_flags = vsc73xx_port_pre_bridge_flags,
2230259a7061SPawel Dembicki 	.port_bridge_flags = vsc73xx_port_bridge_flags,
22316dfaaa27SPawel Dembicki 	.port_bridge_join = dsa_tag_8021q_bridge_join,
22326dfaaa27SPawel Dembicki 	.port_bridge_leave = dsa_tag_8021q_bridge_leave,
2233fb77ffc6SVladimir Oltean 	.port_change_mtu = vsc73xx_change_mtu,
2234*075e3d30SPawel Dembicki 	.port_fdb_add = vsc73xx_fdb_add,
2235*075e3d30SPawel Dembicki 	.port_fdb_del = vsc73xx_fdb_del,
2236*075e3d30SPawel Dembicki 	.port_fdb_dump = vsc73xx_port_fdb_dump,
2237fb77ffc6SVladimir Oltean 	.port_max_mtu = vsc73xx_get_max_mtu,
22381e5b23e5SPawel Dembicki 	.port_stp_state_set = vsc73xx_port_stp_state_set,
22396b783dedSPawel Dembicki 	.port_vlan_filtering = vsc73xx_port_vlan_filtering,
22406b783dedSPawel Dembicki 	.port_vlan_add = vsc73xx_port_vlan_add,
22416b783dedSPawel Dembicki 	.port_vlan_del = vsc73xx_port_vlan_del,
2242a026809cSRussell King (Oracle) 	.phylink_get_caps = vsc73xx_phylink_get_caps,
2243e3386ec4SPawel Dembicki 	.tag_8021q_vlan_add = vsc73xx_tag_8021q_vlan_add,
2244e3386ec4SPawel Dembicki 	.tag_8021q_vlan_del = vsc73xx_tag_8021q_vlan_del,
224595711cd5SPawel Dembicki };
224695711cd5SPawel Dembicki 
vsc73xx_gpio_get(struct gpio_chip * chip,unsigned int offset)224795711cd5SPawel Dembicki static int vsc73xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
224895711cd5SPawel Dembicki {
224995711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
225095711cd5SPawel Dembicki 	u32 val;
225195711cd5SPawel Dembicki 	int ret;
225295711cd5SPawel Dembicki 
225395711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
225495711cd5SPawel Dembicki 			   VSC73XX_GPIO, &val);
225595711cd5SPawel Dembicki 	if (ret)
225695711cd5SPawel Dembicki 		return ret;
225795711cd5SPawel Dembicki 
225895711cd5SPawel Dembicki 	return !!(val & BIT(offset));
225995711cd5SPawel Dembicki }
226095711cd5SPawel Dembicki 
vsc73xx_gpio_set(struct gpio_chip * chip,unsigned int offset,int val)226195711cd5SPawel Dembicki static void vsc73xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
226295711cd5SPawel Dembicki 			     int val)
226395711cd5SPawel Dembicki {
226495711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
226595711cd5SPawel Dembicki 	u32 tmp = val ? BIT(offset) : 0;
226695711cd5SPawel Dembicki 
226795711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
226895711cd5SPawel Dembicki 			    VSC73XX_GPIO, BIT(offset), tmp);
226995711cd5SPawel Dembicki }
227095711cd5SPawel Dembicki 
vsc73xx_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int val)227195711cd5SPawel Dembicki static int vsc73xx_gpio_direction_output(struct gpio_chip *chip,
227295711cd5SPawel Dembicki 					 unsigned int offset, int val)
227395711cd5SPawel Dembicki {
227495711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
227595711cd5SPawel Dembicki 	u32 tmp = val ? BIT(offset) : 0;
227695711cd5SPawel Dembicki 
227795711cd5SPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
227895711cd5SPawel Dembicki 				   VSC73XX_GPIO, BIT(offset + 4) | BIT(offset),
227995711cd5SPawel Dembicki 				   BIT(offset + 4) | tmp);
228095711cd5SPawel Dembicki }
228195711cd5SPawel Dembicki 
vsc73xx_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)228295711cd5SPawel Dembicki static int vsc73xx_gpio_direction_input(struct gpio_chip *chip,
228395711cd5SPawel Dembicki 					unsigned int offset)
228495711cd5SPawel Dembicki {
228595711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
228695711cd5SPawel Dembicki 
228795711cd5SPawel Dembicki 	return  vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
228895711cd5SPawel Dembicki 				    VSC73XX_GPIO, BIT(offset + 4),
228995711cd5SPawel Dembicki 				    0);
229095711cd5SPawel Dembicki }
229195711cd5SPawel Dembicki 
vsc73xx_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)229295711cd5SPawel Dembicki static int vsc73xx_gpio_get_direction(struct gpio_chip *chip,
229395711cd5SPawel Dembicki 				      unsigned int offset)
229495711cd5SPawel Dembicki {
229595711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
229695711cd5SPawel Dembicki 	u32 val;
229795711cd5SPawel Dembicki 	int ret;
229895711cd5SPawel Dembicki 
229995711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
230095711cd5SPawel Dembicki 			   VSC73XX_GPIO, &val);
230195711cd5SPawel Dembicki 	if (ret)
230295711cd5SPawel Dembicki 		return ret;
230395711cd5SPawel Dembicki 
230495711cd5SPawel Dembicki 	return !(val & BIT(offset + 4));
230595711cd5SPawel Dembicki }
230695711cd5SPawel Dembicki 
vsc73xx_gpio_probe(struct vsc73xx * vsc)230795711cd5SPawel Dembicki static int vsc73xx_gpio_probe(struct vsc73xx *vsc)
230895711cd5SPawel Dembicki {
230995711cd5SPawel Dembicki 	int ret;
231095711cd5SPawel Dembicki 
231195711cd5SPawel Dembicki 	vsc->gc.label = devm_kasprintf(vsc->dev, GFP_KERNEL, "VSC%04x",
231295711cd5SPawel Dembicki 				       vsc->chipid);
2313776dac5aSKunwu Chan 	if (!vsc->gc.label)
2314776dac5aSKunwu Chan 		return -ENOMEM;
231595711cd5SPawel Dembicki 	vsc->gc.ngpio = 4;
231695711cd5SPawel Dembicki 	vsc->gc.owner = THIS_MODULE;
231795711cd5SPawel Dembicki 	vsc->gc.parent = vsc->dev;
231895711cd5SPawel Dembicki 	vsc->gc.base = -1;
231995711cd5SPawel Dembicki 	vsc->gc.get = vsc73xx_gpio_get;
232095711cd5SPawel Dembicki 	vsc->gc.set = vsc73xx_gpio_set;
232195711cd5SPawel Dembicki 	vsc->gc.direction_input = vsc73xx_gpio_direction_input;
232295711cd5SPawel Dembicki 	vsc->gc.direction_output = vsc73xx_gpio_direction_output;
232395711cd5SPawel Dembicki 	vsc->gc.get_direction = vsc73xx_gpio_get_direction;
232495711cd5SPawel Dembicki 	vsc->gc.can_sleep = true;
232595711cd5SPawel Dembicki 	ret = devm_gpiochip_add_data(vsc->dev, &vsc->gc, vsc);
232695711cd5SPawel Dembicki 	if (ret) {
232795711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to register GPIO chip\n");
232895711cd5SPawel Dembicki 		return ret;
232995711cd5SPawel Dembicki 	}
233095711cd5SPawel Dembicki 	return 0;
233195711cd5SPawel Dembicki }
233295711cd5SPawel Dembicki 
vsc73xx_probe(struct vsc73xx * vsc)233395711cd5SPawel Dembicki int vsc73xx_probe(struct vsc73xx *vsc)
233495711cd5SPawel Dembicki {
233595711cd5SPawel Dembicki 	struct device *dev = vsc->dev;
233695711cd5SPawel Dembicki 	int ret;
233795711cd5SPawel Dembicki 
233895711cd5SPawel Dembicki 	/* Release reset, if any */
233995711cd5SPawel Dembicki 	vsc->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
234095711cd5SPawel Dembicki 	if (IS_ERR(vsc->reset)) {
234195711cd5SPawel Dembicki 		dev_err(dev, "failed to get RESET GPIO\n");
234295711cd5SPawel Dembicki 		return PTR_ERR(vsc->reset);
234395711cd5SPawel Dembicki 	}
234495711cd5SPawel Dembicki 	if (vsc->reset)
234595711cd5SPawel Dembicki 		/* Wait 20ms according to datasheet table 245 */
234695711cd5SPawel Dembicki 		msleep(20);
234795711cd5SPawel Dembicki 
234895711cd5SPawel Dembicki 	ret = vsc73xx_detect(vsc);
23491da39ff0SPawel Dembicki 	if (ret == -EAGAIN) {
23501da39ff0SPawel Dembicki 		dev_err(vsc->dev,
23511da39ff0SPawel Dembicki 			"Chip seems to be out of control. Assert reset and try again.\n");
23521da39ff0SPawel Dembicki 		gpiod_set_value_cansleep(vsc->reset, 1);
23531da39ff0SPawel Dembicki 		/* Reset pulse should be 20ns minimum, according to datasheet
23541da39ff0SPawel Dembicki 		 * table 245, so 10us should be fine
23551da39ff0SPawel Dembicki 		 */
23561da39ff0SPawel Dembicki 		usleep_range(10, 100);
23571da39ff0SPawel Dembicki 		gpiod_set_value_cansleep(vsc->reset, 0);
23581da39ff0SPawel Dembicki 		/* Wait 20ms according to datasheet table 245 */
23591da39ff0SPawel Dembicki 		msleep(20);
23601da39ff0SPawel Dembicki 		ret = vsc73xx_detect(vsc);
23611da39ff0SPawel Dembicki 	}
236295711cd5SPawel Dembicki 	if (ret) {
236395711cd5SPawel Dembicki 		dev_err(dev, "no chip found (%d)\n", ret);
236495711cd5SPawel Dembicki 		return -ENODEV;
236595711cd5SPawel Dembicki 	}
236695711cd5SPawel Dembicki 
2367*075e3d30SPawel Dembicki 	mutex_init(&vsc->fdb_lock);
2368*075e3d30SPawel Dembicki 
236995711cd5SPawel Dembicki 	eth_random_addr(vsc->addr);
237095711cd5SPawel Dembicki 	dev_info(vsc->dev,
237195711cd5SPawel Dembicki 		 "MAC for control frames: %02X:%02X:%02X:%02X:%02X:%02X\n",
237295711cd5SPawel Dembicki 		 vsc->addr[0], vsc->addr[1], vsc->addr[2],
237395711cd5SPawel Dembicki 		 vsc->addr[3], vsc->addr[4], vsc->addr[5]);
237495711cd5SPawel Dembicki 
23757e99e347SVivien Didelot 	vsc->ds = devm_kzalloc(dev, sizeof(*vsc->ds), GFP_KERNEL);
237695711cd5SPawel Dembicki 	if (!vsc->ds)
237795711cd5SPawel Dembicki 		return -ENOMEM;
23787e99e347SVivien Didelot 
23797e99e347SVivien Didelot 	vsc->ds->dev = dev;
23806cc5280aSPawel Dembicki 	vsc->ds->num_ports = VSC73XX_MAX_NUM_PORTS;
238195711cd5SPawel Dembicki 	vsc->ds->priv = vsc;
238295711cd5SPawel Dembicki 
238395711cd5SPawel Dembicki 	vsc->ds->ops = &vsc73xx_ds_ops;
238421fc3416SPawel Dembicki 	vsc->ds->phylink_mac_ops = &vsc73xx_phylink_mac_ops;
238595711cd5SPawel Dembicki 	ret = dsa_register_switch(vsc->ds);
238695711cd5SPawel Dembicki 	if (ret) {
238795711cd5SPawel Dembicki 		dev_err(dev, "unable to register switch (%d)\n", ret);
238895711cd5SPawel Dembicki 		return ret;
238995711cd5SPawel Dembicki 	}
239095711cd5SPawel Dembicki 
239195711cd5SPawel Dembicki 	ret = vsc73xx_gpio_probe(vsc);
239295711cd5SPawel Dembicki 	if (ret) {
239395711cd5SPawel Dembicki 		dsa_unregister_switch(vsc->ds);
239495711cd5SPawel Dembicki 		return ret;
239595711cd5SPawel Dembicki 	}
239695711cd5SPawel Dembicki 
239795711cd5SPawel Dembicki 	return 0;
239895711cd5SPawel Dembicki }
239995711cd5SPawel Dembicki EXPORT_SYMBOL(vsc73xx_probe);
240095711cd5SPawel Dembicki 
vsc73xx_remove(struct vsc73xx * vsc)2401e99fa423SUwe Kleine-König void vsc73xx_remove(struct vsc73xx *vsc)
240295711cd5SPawel Dembicki {
240395711cd5SPawel Dembicki 	dsa_unregister_switch(vsc->ds);
240495711cd5SPawel Dembicki 	gpiod_set_value(vsc->reset, 1);
240595711cd5SPawel Dembicki }
240695711cd5SPawel Dembicki EXPORT_SYMBOL(vsc73xx_remove);
240795711cd5SPawel Dembicki 
vsc73xx_shutdown(struct vsc73xx * vsc)24080650bf52SVladimir Oltean void vsc73xx_shutdown(struct vsc73xx *vsc)
24090650bf52SVladimir Oltean {
24100650bf52SVladimir Oltean 	dsa_switch_shutdown(vsc->ds);
24110650bf52SVladimir Oltean }
24120650bf52SVladimir Oltean EXPORT_SYMBOL(vsc73xx_shutdown);
24130650bf52SVladimir Oltean 
241495711cd5SPawel Dembicki MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
241595711cd5SPawel Dembicki MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 driver");
241695711cd5SPawel Dembicki MODULE_LICENSE("GPL v2");
2417