xref: /linux/drivers/net/dsa/vitesse-vsc73xx-core.c (revision e3386ec4ec9083522c36ab0ddfc638c90395c741)
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>
2495711cd5SPawel Dembicki #include <linux/if_bridge.h>
256b783dedSPawel Dembicki #include <linux/if_vlan.h>
2695711cd5SPawel Dembicki #include <linux/etherdevice.h>
2795711cd5SPawel Dembicki #include <linux/gpio/consumer.h>
2895711cd5SPawel Dembicki #include <linux/gpio/driver.h>
296b783dedSPawel Dembicki #include <linux/dsa/8021q.h>
3095711cd5SPawel Dembicki #include <linux/random.h>
3195711cd5SPawel Dembicki #include <net/dsa.h>
3295711cd5SPawel Dembicki 
3395711cd5SPawel Dembicki #include "vitesse-vsc73xx.h"
3495711cd5SPawel Dembicki 
3595711cd5SPawel Dembicki #define VSC73XX_BLOCK_MAC	0x1 /* Subblocks 0-4, 6 (CPU port) */
3695711cd5SPawel Dembicki #define VSC73XX_BLOCK_ANALYZER	0x2 /* Only subblock 0 */
3795711cd5SPawel Dembicki #define VSC73XX_BLOCK_MII	0x3 /* Subblocks 0 and 1 */
3895711cd5SPawel Dembicki #define VSC73XX_BLOCK_MEMINIT	0x3 /* Only subblock 2 */
3995711cd5SPawel Dembicki #define VSC73XX_BLOCK_CAPTURE	0x4 /* Only subblock 2 */
4095711cd5SPawel Dembicki #define VSC73XX_BLOCK_ARBITER	0x5 /* Only subblock 0 */
4195711cd5SPawel Dembicki #define VSC73XX_BLOCK_SYSTEM	0x7 /* Only subblock 0 */
4295711cd5SPawel Dembicki 
4395711cd5SPawel Dembicki #define CPU_PORT	6 /* CPU port */
4495711cd5SPawel Dembicki 
4595711cd5SPawel Dembicki /* MAC Block registers */
4695711cd5SPawel Dembicki #define VSC73XX_MAC_CFG		0x00
4795711cd5SPawel Dembicki #define VSC73XX_MACHDXGAP	0x02
4895711cd5SPawel Dembicki #define VSC73XX_FCCONF		0x04
4995711cd5SPawel Dembicki #define VSC73XX_FCMACHI		0x08
5095711cd5SPawel Dembicki #define VSC73XX_FCMACLO		0x0c
5195711cd5SPawel Dembicki #define VSC73XX_MAXLEN		0x10
5295711cd5SPawel Dembicki #define VSC73XX_ADVPORTM	0x19
5395711cd5SPawel Dembicki #define VSC73XX_TXUPDCFG	0x24
5495711cd5SPawel Dembicki #define VSC73XX_TXQ_SELECT_CFG	0x28
5595711cd5SPawel Dembicki #define VSC73XX_RXOCT		0x50
5695711cd5SPawel Dembicki #define VSC73XX_TXOCT		0x51
5795711cd5SPawel Dembicki #define VSC73XX_C_RX0		0x52
5895711cd5SPawel Dembicki #define VSC73XX_C_RX1		0x53
5995711cd5SPawel Dembicki #define VSC73XX_C_RX2		0x54
6095711cd5SPawel Dembicki #define VSC73XX_C_TX0		0x55
6195711cd5SPawel Dembicki #define VSC73XX_C_TX1		0x56
6295711cd5SPawel Dembicki #define VSC73XX_C_TX2		0x57
6395711cd5SPawel Dembicki #define VSC73XX_C_CFG		0x58
6495711cd5SPawel Dembicki #define VSC73XX_CAT_DROP	0x6e
6595711cd5SPawel Dembicki #define VSC73XX_CAT_PR_MISC_L2	0x6f
6695711cd5SPawel Dembicki #define VSC73XX_CAT_PR_USR_PRIO	0x75
676b783dedSPawel Dembicki #define VSC73XX_CAT_VLAN_MISC	0x79
686b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN	0x7a
6995711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF	0xdf
7095711cd5SPawel Dembicki 
7195711cd5SPawel Dembicki /* MAC_CFG register bits */
7295711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_WEXC_DIS	BIT(31)
7395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_PORT_RST	BIT(29)
7495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_EN		BIT(28)
7595711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_SEED_LOAD	BIT(27)
7695711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_SEED_MASK	GENMASK(26, 19)
7795711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_SEED_OFFSET	19
7895711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_FDX		BIT(18)
7995711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_GIGA_MODE	BIT(17)
8095711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_RX_EN		BIT(16)
8195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_VLAN_DBLAWR	BIT(15)
8295711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_VLAN_AWR	BIT(14)
8395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_100_BASE_T	BIT(13) /* Not in manual */
8495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_MASK	GENMASK(10, 6)
8595711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_OFFSET	6
8695711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_1000M	(6 << VSC73XX_MAC_CFG_TX_IPG_OFFSET)
8795711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_TX_IPG_100_10M	(17 << VSC73XX_MAC_CFG_TX_IPG_OFFSET)
8895711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_MAC_RX_RST	BIT(5)
8995711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_MAC_TX_RST	BIT(4)
9095711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_MASK	GENMASK(2, 0)
9195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_OFFSET	0
9295711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_1000M	1
9395711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_100M	2
9495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_10M	3
9595711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_CLK_SEL_EXT	4
9695711cd5SPawel Dembicki 
9795711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_1000M_F_PHY	(VSC73XX_MAC_CFG_FDX | \
9895711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_GIGA_MODE | \
9995711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_TX_IPG_1000M | \
10095711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_EXT)
10195711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_100_10M_F_PHY	(VSC73XX_MAC_CFG_FDX | \
10295711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_TX_IPG_100_10M | \
10395711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_EXT)
10495711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_100_10M_H_PHY	(VSC73XX_MAC_CFG_TX_IPG_100_10M | \
10595711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_EXT)
10695711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_1000M_F_RGMII	(VSC73XX_MAC_CFG_FDX | \
10795711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_GIGA_MODE | \
10895711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_TX_IPG_1000M | \
10995711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_CLK_SEL_1000M)
11095711cd5SPawel Dembicki #define VSC73XX_MAC_CFG_RESET		(VSC73XX_MAC_CFG_PORT_RST | \
11195711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_MAC_RX_RST | \
11295711cd5SPawel Dembicki 					 VSC73XX_MAC_CFG_MAC_TX_RST)
11395711cd5SPawel Dembicki 
11495711cd5SPawel Dembicki /* Flow control register bits */
11595711cd5SPawel Dembicki #define VSC73XX_FCCONF_ZERO_PAUSE_EN	BIT(17)
11695711cd5SPawel Dembicki #define VSC73XX_FCCONF_FLOW_CTRL_OBEY	BIT(16)
11795711cd5SPawel Dembicki #define VSC73XX_FCCONF_PAUSE_VAL_MASK	GENMASK(15, 0)
11895711cd5SPawel Dembicki 
11995711cd5SPawel Dembicki /* ADVPORTM advanced port setup register bits */
12095711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_IFG_PPM	BIT(7)
12195711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_EXC_COL_CONT	BIT(6)
12295711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_EXT_PORT	BIT(5)
12395711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_INV_GTX	BIT(4)
12495711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_ENA_GTX	BIT(3)
12595711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_DDR_MODE	BIT(2)
12695711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_IO_LOOPBACK	BIT(1)
12795711cd5SPawel Dembicki #define VSC73XX_ADVPORTM_HOST_LOOPBACK	BIT(0)
12895711cd5SPawel Dembicki 
1296b783dedSPawel Dembicki /*  TXUPDCFG transmit modify setup bits */
1306b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_DSCP_REWR_MODE	GENMASK(20, 19)
1316b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_DSCP_REWR_ENA	BIT(18)
1326b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_INT_TO_USRPRIO_ENA	BIT(17)
1336b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UNTAGGED_VID	GENMASK(15, 4)
1346b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_ENA	BIT(3)
1356b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UPDATE_CRC_CPU_ENA	BIT(1)
1366b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_INSERT_TAG	BIT(0)
1376b783dedSPawel Dembicki 
1386b783dedSPawel Dembicki #define VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_SHIFT	4
1396b783dedSPawel Dembicki 
14095711cd5SPawel Dembicki /* CAT_DROP categorizer frame dropping register bits */
14195711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_DROP_MC_SMAC_ENA	BIT(6)
14295711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_FWD_CTRL_ENA		BIT(4)
14395711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_FWD_PAUSE_ENA		BIT(3)
14495711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_UNTAGGED_ENA		BIT(2)
14595711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_TAGGED_ENA		BIT(1)
14695711cd5SPawel Dembicki #define VSC73XX_CAT_DROP_NULL_MAC_ENA		BIT(0)
14795711cd5SPawel Dembicki 
14895711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_EXTENT_MEM		BIT(31)
14995711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_EARLY_TX_MASK	GENMASK(4, 1)
15095711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_EARLY_TX_512	(1 << 1)
15195711cd5SPawel Dembicki #define VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE	BIT(0)
15295711cd5SPawel Dembicki 
1536b783dedSPawel Dembicki /* CAT_VLAN_MISC categorizer VLAN miscellaneous bits */
1546b783dedSPawel Dembicki #define VSC73XX_CAT_VLAN_MISC_VLAN_TCI_IGNORE_ENA BIT(8)
1556b783dedSPawel Dembicki #define VSC73XX_CAT_VLAN_MISC_VLAN_KEEP_TAG_ENA BIT(7)
1566b783dedSPawel Dembicki 
1576b783dedSPawel Dembicki /* CAT_PORT_VLAN categorizer port VLAN */
1586b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN_VLAN_CFI BIT(15)
1596b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN_VLAN_USR_PRIO GENMASK(14, 12)
1606b783dedSPawel Dembicki #define VSC73XX_CAT_PORT_VLAN_VLAN_VID GENMASK(11, 0)
1616b783dedSPawel Dembicki 
16295711cd5SPawel Dembicki /* Frame analyzer block 2 registers */
16395711cd5SPawel Dembicki #define VSC73XX_STORMLIMIT	0x02
16495711cd5SPawel Dembicki #define VSC73XX_ADVLEARN	0x03
16595711cd5SPawel Dembicki #define VSC73XX_IFLODMSK	0x04
16695711cd5SPawel Dembicki #define VSC73XX_VLANMASK	0x05
16795711cd5SPawel Dembicki #define VSC73XX_MACHDATA	0x06
16895711cd5SPawel Dembicki #define VSC73XX_MACLDATA	0x07
16995711cd5SPawel Dembicki #define VSC73XX_ANMOVED		0x08
17095711cd5SPawel Dembicki #define VSC73XX_ANAGEFIL	0x09
17195711cd5SPawel Dembicki #define VSC73XX_ANEVENTS	0x0a
17295711cd5SPawel Dembicki #define VSC73XX_ANCNTMASK	0x0b
17395711cd5SPawel Dembicki #define VSC73XX_ANCNTVAL	0x0c
17495711cd5SPawel Dembicki #define VSC73XX_LEARNMASK	0x0d
17595711cd5SPawel Dembicki #define VSC73XX_UFLODMASK	0x0e
17695711cd5SPawel Dembicki #define VSC73XX_MFLODMASK	0x0f
17795711cd5SPawel Dembicki #define VSC73XX_RECVMASK	0x10
17895711cd5SPawel Dembicki #define VSC73XX_AGGRCTRL	0x20
17995711cd5SPawel Dembicki #define VSC73XX_AGGRMSKS	0x30 /* Until 0x3f */
18095711cd5SPawel Dembicki #define VSC73XX_DSTMASKS	0x40 /* Until 0x7f */
18195711cd5SPawel Dembicki #define VSC73XX_SRCMASKS	0x80 /* Until 0x87 */
18295711cd5SPawel Dembicki #define VSC73XX_CAPENAB		0xa0
18395711cd5SPawel Dembicki #define VSC73XX_MACACCESS	0xb0
18495711cd5SPawel Dembicki #define VSC73XX_IPMCACCESS	0xb1
18595711cd5SPawel Dembicki #define VSC73XX_MACTINDX	0xc0
18695711cd5SPawel Dembicki #define VSC73XX_VLANACCESS	0xd0
18795711cd5SPawel Dembicki #define VSC73XX_VLANTIDX	0xe0
18895711cd5SPawel Dembicki #define VSC73XX_AGENCTRL	0xf0
18995711cd5SPawel Dembicki #define VSC73XX_CAPRST		0xff
19095711cd5SPawel Dembicki 
1911e5b23e5SPawel Dembicki #define VSC73XX_SRCMASKS_CPU_COPY		BIT(27)
1921e5b23e5SPawel Dembicki #define VSC73XX_SRCMASKS_MIRROR			BIT(26)
1931e5b23e5SPawel Dembicki #define VSC73XX_SRCMASKS_PORTS_MASK		GENMASK(7, 0)
1941e5b23e5SPawel Dembicki 
19595711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CPU_COPY		BIT(14)
19695711cd5SPawel Dembicki #define VSC73XX_MACACCESS_FWD_KILL		BIT(13)
19795711cd5SPawel Dembicki #define VSC73XX_MACACCESS_IGNORE_VLAN		BIT(12)
19895711cd5SPawel Dembicki #define VSC73XX_MACACCESS_AGED_FLAG		BIT(11)
19995711cd5SPawel Dembicki #define VSC73XX_MACACCESS_VALID			BIT(10)
20095711cd5SPawel Dembicki #define VSC73XX_MACACCESS_LOCKED		BIT(9)
20195711cd5SPawel Dembicki #define VSC73XX_MACACCESS_DEST_IDX_MASK		GENMASK(8, 3)
20295711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_MASK		GENMASK(2, 0)
20395711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_IDLE		0
20495711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_LEARN		1
20595711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_FORGET		2
20695711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_AGE_TABLE		3
20795711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_FLUSH_TABLE	4
20895711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_CLEAR_TABLE	5
20995711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_READ_ENTRY	6
21095711cd5SPawel Dembicki #define VSC73XX_MACACCESS_CMD_WRITE_ENTRY	7
21195711cd5SPawel Dembicki 
21295711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_LEARN_DISABLED	BIT(30)
21395711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_MIRROR		BIT(29)
21495711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_SRC_CHECK	BIT(28)
21595711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_PORT_MASK	GENMASK(9, 2)
2166b783dedSPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_PORT_MASK_SHIFT	2
2176b783dedSPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK	GENMASK(1, 0)
21895711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_IDLE	0
21995711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_READ_ENTRY	1
22095711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_WRITE_ENTRY	2
22195711cd5SPawel Dembicki #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE	3
22295711cd5SPawel Dembicki 
22395711cd5SPawel Dembicki /* MII block 3 registers */
22495711cd5SPawel Dembicki #define VSC73XX_MII_STAT	0x0
22595711cd5SPawel Dembicki #define VSC73XX_MII_CMD		0x1
22695711cd5SPawel Dembicki #define VSC73XX_MII_DATA	0x2
22795711cd5SPawel Dembicki 
22895711cd5SPawel Dembicki /* Arbiter block 5 registers */
22995711cd5SPawel Dembicki #define VSC73XX_ARBEMPTY		0x0c
23095711cd5SPawel Dembicki #define VSC73XX_ARBDISC			0x0e
23195711cd5SPawel Dembicki #define VSC73XX_SBACKWDROP		0x12
23295711cd5SPawel Dembicki #define VSC73XX_DBACKWDROP		0x13
23395711cd5SPawel Dembicki #define VSC73XX_ARBBURSTPROB		0x15
23495711cd5SPawel Dembicki 
23595711cd5SPawel Dembicki /* System block 7 registers */
23695711cd5SPawel Dembicki #define VSC73XX_ICPU_SIPAD		0x01
23795711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY		0x05
23895711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL		0x10
23995711cd5SPawel Dembicki #define VSC73XX_ICPU_ADDR		0x11
24095711cd5SPawel Dembicki #define VSC73XX_ICPU_SRAM		0x12
24195711cd5SPawel Dembicki #define VSC73XX_HWSEM			0x13
24295711cd5SPawel Dembicki #define VSC73XX_GLORESET		0x14
24395711cd5SPawel Dembicki #define VSC73XX_ICPU_MBOX_VAL		0x15
24495711cd5SPawel Dembicki #define VSC73XX_ICPU_MBOX_SET		0x16
24595711cd5SPawel Dembicki #define VSC73XX_ICPU_MBOX_CLR		0x17
24695711cd5SPawel Dembicki #define VSC73XX_CHIPID			0x18
24795711cd5SPawel Dembicki #define VSC73XX_GPIO			0x34
24895711cd5SPawel Dembicki 
24995711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_NONE	0
25095711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_4_NS	1
25195711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_7_NS	2
25295711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_2_0_NS	3
25395711cd5SPawel Dembicki 
25495711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_NONE	(0 << 4)
25595711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_4_NS	(1 << 4)
25695711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_7_NS	(2 << 4)
25795711cd5SPawel Dembicki #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_2_0_NS	(3 << 4)
25895711cd5SPawel Dembicki 
25995711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_WATCHDOG_RST	BIT(31)
26095711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_CLK_DIV_MASK	GENMASK(12, 8)
26195711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_SRST_HOLD	BIT(7)
26295711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_ICPU_PI_EN	BIT(6)
26395711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_BOOT_EN	BIT(3)
26495711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_EXT_ACC_EN	BIT(2)
26595711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_CLK_EN	BIT(1)
26695711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_SRST		BIT(0)
26795711cd5SPawel Dembicki 
26895711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_SHIFT		12
26995711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_MASK		0xffff
27095711cd5SPawel Dembicki #define VSC73XX_CHIPID_REV_SHIFT	28
27195711cd5SPawel Dembicki #define VSC73XX_CHIPID_REV_MASK		0xf
27295711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7385		0x7385
27395711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7388		0x7388
27495711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7395		0x7395
27595711cd5SPawel Dembicki #define VSC73XX_CHIPID_ID_7398		0x7398
27695711cd5SPawel Dembicki 
27795711cd5SPawel Dembicki #define VSC73XX_GLORESET_STROBE		BIT(4)
27895711cd5SPawel Dembicki #define VSC73XX_GLORESET_ICPU_LOCK	BIT(3)
27995711cd5SPawel Dembicki #define VSC73XX_GLORESET_MEM_LOCK	BIT(2)
28095711cd5SPawel Dembicki #define VSC73XX_GLORESET_PHY_RESET	BIT(1)
28195711cd5SPawel Dembicki #define VSC73XX_GLORESET_MASTER_RESET	BIT(0)
28295711cd5SPawel Dembicki 
28395711cd5SPawel Dembicki #define VSC7385_CLOCK_DELAY		((3 << 4) | 3)
28495711cd5SPawel Dembicki #define VSC7385_CLOCK_DELAY_MASK	((3 << 4) | 3)
28595711cd5SPawel Dembicki 
28695711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_STOP	(VSC73XX_ICPU_CTRL_SRST_HOLD | \
28795711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_BOOT_EN | \
28895711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_EXT_ACC_EN)
28995711cd5SPawel Dembicki 
29095711cd5SPawel Dembicki #define VSC73XX_ICPU_CTRL_START	(VSC73XX_ICPU_CTRL_CLK_DIV | \
29195711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_BOOT_EN | \
29295711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_CLK_EN | \
29395711cd5SPawel Dembicki 				 VSC73XX_ICPU_CTRL_SRST)
29495711cd5SPawel Dembicki 
29595711cd5SPawel Dembicki #define IS_7385(a) ((a)->chipid == VSC73XX_CHIPID_ID_7385)
29695711cd5SPawel Dembicki #define IS_7388(a) ((a)->chipid == VSC73XX_CHIPID_ID_7388)
29795711cd5SPawel Dembicki #define IS_7395(a) ((a)->chipid == VSC73XX_CHIPID_ID_7395)
29895711cd5SPawel Dembicki #define IS_7398(a) ((a)->chipid == VSC73XX_CHIPID_ID_7398)
29995711cd5SPawel Dembicki #define IS_739X(a) (IS_7395(a) || IS_7398(a))
30095711cd5SPawel Dembicki 
301eb7e33d0SPawel Dembicki #define VSC73XX_POLL_SLEEP_US		1000
302eb7e33d0SPawel Dembicki #define VSC73XX_POLL_TIMEOUT_US		10000
303eb7e33d0SPawel Dembicki 
30495711cd5SPawel Dembicki struct vsc73xx_counter {
30595711cd5SPawel Dembicki 	u8 counter;
30695711cd5SPawel Dembicki 	const char *name;
30795711cd5SPawel Dembicki };
30895711cd5SPawel Dembicki 
30995711cd5SPawel Dembicki /* Counters are named according to the MIB standards where applicable.
31095711cd5SPawel Dembicki  * Some counters are custom, non-standard. The standard counters are
31195711cd5SPawel Dembicki  * named in accordance with RFC2819, RFC2021 and IEEE Std 802.3-2002 Annex
31295711cd5SPawel Dembicki  * 30A Counters.
31395711cd5SPawel Dembicki  */
31495711cd5SPawel Dembicki static const struct vsc73xx_counter vsc73xx_rx_counters[] = {
31595711cd5SPawel Dembicki 	{ 0, "RxEtherStatsPkts" },
31695711cd5SPawel Dembicki 	{ 1, "RxBroadcast+MulticastPkts" }, /* non-standard counter */
31795711cd5SPawel Dembicki 	{ 2, "RxTotalErrorPackets" }, /* non-standard counter */
31895711cd5SPawel Dembicki 	{ 3, "RxEtherStatsBroadcastPkts" },
31995711cd5SPawel Dembicki 	{ 4, "RxEtherStatsMulticastPkts" },
32095711cd5SPawel Dembicki 	{ 5, "RxEtherStatsPkts64Octets" },
32195711cd5SPawel Dembicki 	{ 6, "RxEtherStatsPkts65to127Octets" },
32295711cd5SPawel Dembicki 	{ 7, "RxEtherStatsPkts128to255Octets" },
32395711cd5SPawel Dembicki 	{ 8, "RxEtherStatsPkts256to511Octets" },
32495711cd5SPawel Dembicki 	{ 9, "RxEtherStatsPkts512to1023Octets" },
32595711cd5SPawel Dembicki 	{ 10, "RxEtherStatsPkts1024to1518Octets" },
32695711cd5SPawel Dembicki 	{ 11, "RxJumboFrames" }, /* non-standard counter */
32795711cd5SPawel Dembicki 	{ 12, "RxaPauseMACControlFramesTransmitted" },
32895711cd5SPawel Dembicki 	{ 13, "RxFIFODrops" }, /* non-standard counter */
32995711cd5SPawel Dembicki 	{ 14, "RxBackwardDrops" }, /* non-standard counter */
33095711cd5SPawel Dembicki 	{ 15, "RxClassifierDrops" }, /* non-standard counter */
33195711cd5SPawel Dembicki 	{ 16, "RxEtherStatsCRCAlignErrors" },
33295711cd5SPawel Dembicki 	{ 17, "RxEtherStatsUndersizePkts" },
33395711cd5SPawel Dembicki 	{ 18, "RxEtherStatsOversizePkts" },
33495711cd5SPawel Dembicki 	{ 19, "RxEtherStatsFragments" },
33595711cd5SPawel Dembicki 	{ 20, "RxEtherStatsJabbers" },
33695711cd5SPawel Dembicki 	{ 21, "RxaMACControlFramesReceived" },
33795711cd5SPawel Dembicki 	/* 22-24 are undefined */
33895711cd5SPawel Dembicki 	{ 25, "RxaFramesReceivedOK" },
33995711cd5SPawel Dembicki 	{ 26, "RxQoSClass0" }, /* non-standard counter */
34095711cd5SPawel Dembicki 	{ 27, "RxQoSClass1" }, /* non-standard counter */
34195711cd5SPawel Dembicki 	{ 28, "RxQoSClass2" }, /* non-standard counter */
34295711cd5SPawel Dembicki 	{ 29, "RxQoSClass3" }, /* non-standard counter */
34395711cd5SPawel Dembicki };
34495711cd5SPawel Dembicki 
34595711cd5SPawel Dembicki static const struct vsc73xx_counter vsc73xx_tx_counters[] = {
34695711cd5SPawel Dembicki 	{ 0, "TxEtherStatsPkts" },
34795711cd5SPawel Dembicki 	{ 1, "TxBroadcast+MulticastPkts" }, /* non-standard counter */
34895711cd5SPawel Dembicki 	{ 2, "TxTotalErrorPackets" }, /* non-standard counter */
34995711cd5SPawel Dembicki 	{ 3, "TxEtherStatsBroadcastPkts" },
35095711cd5SPawel Dembicki 	{ 4, "TxEtherStatsMulticastPkts" },
35195711cd5SPawel Dembicki 	{ 5, "TxEtherStatsPkts64Octets" },
35295711cd5SPawel Dembicki 	{ 6, "TxEtherStatsPkts65to127Octets" },
35395711cd5SPawel Dembicki 	{ 7, "TxEtherStatsPkts128to255Octets" },
35495711cd5SPawel Dembicki 	{ 8, "TxEtherStatsPkts256to511Octets" },
35595711cd5SPawel Dembicki 	{ 9, "TxEtherStatsPkts512to1023Octets" },
35695711cd5SPawel Dembicki 	{ 10, "TxEtherStatsPkts1024to1518Octets" },
35795711cd5SPawel Dembicki 	{ 11, "TxJumboFrames" }, /* non-standard counter */
35895711cd5SPawel Dembicki 	{ 12, "TxaPauseMACControlFramesTransmitted" },
35995711cd5SPawel Dembicki 	{ 13, "TxFIFODrops" }, /* non-standard counter */
36095711cd5SPawel Dembicki 	{ 14, "TxDrops" }, /* non-standard counter */
36195711cd5SPawel Dembicki 	{ 15, "TxEtherStatsCollisions" },
36295711cd5SPawel Dembicki 	{ 16, "TxEtherStatsCRCAlignErrors" },
36395711cd5SPawel Dembicki 	{ 17, "TxEtherStatsUndersizePkts" },
36495711cd5SPawel Dembicki 	{ 18, "TxEtherStatsOversizePkts" },
36595711cd5SPawel Dembicki 	{ 19, "TxEtherStatsFragments" },
36695711cd5SPawel Dembicki 	{ 20, "TxEtherStatsJabbers" },
36795711cd5SPawel Dembicki 	/* 21-24 are undefined */
36895711cd5SPawel Dembicki 	{ 25, "TxaFramesReceivedOK" },
36995711cd5SPawel Dembicki 	{ 26, "TxQoSClass0" }, /* non-standard counter */
37095711cd5SPawel Dembicki 	{ 27, "TxQoSClass1" }, /* non-standard counter */
37195711cd5SPawel Dembicki 	{ 28, "TxQoSClass2" }, /* non-standard counter */
37295711cd5SPawel Dembicki 	{ 29, "TxQoSClass3" }, /* non-standard counter */
37395711cd5SPawel Dembicki };
37495711cd5SPawel Dembicki 
3756b783dedSPawel Dembicki struct vsc73xx_vlan_summary {
3766b783dedSPawel Dembicki 	size_t num_tagged;
3776b783dedSPawel Dembicki 	size_t num_untagged;
3786b783dedSPawel Dembicki };
3796b783dedSPawel Dembicki 
3806b783dedSPawel Dembicki enum vsc73xx_port_vlan_conf {
3816b783dedSPawel Dembicki 	VSC73XX_VLAN_FILTER,
3826b783dedSPawel Dembicki 	VSC73XX_VLAN_FILTER_UNTAG_ALL,
3836b783dedSPawel Dembicki 	VSC73XX_VLAN_IGNORE,
3846b783dedSPawel Dembicki };
3856b783dedSPawel Dembicki 
38695711cd5SPawel Dembicki int vsc73xx_is_addr_valid(u8 block, u8 subblock)
38795711cd5SPawel Dembicki {
38895711cd5SPawel Dembicki 	switch (block) {
38995711cd5SPawel Dembicki 	case VSC73XX_BLOCK_MAC:
39095711cd5SPawel Dembicki 		switch (subblock) {
39195711cd5SPawel Dembicki 		case 0 ... 4:
39295711cd5SPawel Dembicki 		case 6:
39395711cd5SPawel Dembicki 			return 1;
39495711cd5SPawel Dembicki 		}
39595711cd5SPawel Dembicki 		break;
39695711cd5SPawel Dembicki 
39795711cd5SPawel Dembicki 	case VSC73XX_BLOCK_ANALYZER:
39895711cd5SPawel Dembicki 	case VSC73XX_BLOCK_SYSTEM:
39995711cd5SPawel Dembicki 		switch (subblock) {
40095711cd5SPawel Dembicki 		case 0:
40195711cd5SPawel Dembicki 			return 1;
40295711cd5SPawel Dembicki 		}
40395711cd5SPawel Dembicki 		break;
40495711cd5SPawel Dembicki 
40595711cd5SPawel Dembicki 	case VSC73XX_BLOCK_MII:
40695711cd5SPawel Dembicki 	case VSC73XX_BLOCK_CAPTURE:
40795711cd5SPawel Dembicki 	case VSC73XX_BLOCK_ARBITER:
40895711cd5SPawel Dembicki 		switch (subblock) {
40995711cd5SPawel Dembicki 		case 0 ... 1:
41095711cd5SPawel Dembicki 			return 1;
41195711cd5SPawel Dembicki 		}
41295711cd5SPawel Dembicki 		break;
41395711cd5SPawel Dembicki 	}
41495711cd5SPawel Dembicki 
41595711cd5SPawel Dembicki 	return 0;
41695711cd5SPawel Dembicki }
41795711cd5SPawel Dembicki EXPORT_SYMBOL(vsc73xx_is_addr_valid);
41895711cd5SPawel Dembicki 
41995711cd5SPawel Dembicki static int vsc73xx_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
42095711cd5SPawel Dembicki 			u32 *val)
42195711cd5SPawel Dembicki {
42295711cd5SPawel Dembicki 	return vsc->ops->read(vsc, block, subblock, reg, val);
42395711cd5SPawel Dembicki }
42495711cd5SPawel Dembicki 
42595711cd5SPawel Dembicki static int vsc73xx_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
42695711cd5SPawel Dembicki 			 u32 val)
42795711cd5SPawel Dembicki {
42895711cd5SPawel Dembicki 	return vsc->ops->write(vsc, block, subblock, reg, val);
42995711cd5SPawel Dembicki }
43095711cd5SPawel Dembicki 
43195711cd5SPawel Dembicki static int vsc73xx_update_bits(struct vsc73xx *vsc, u8 block, u8 subblock,
43295711cd5SPawel Dembicki 			       u8 reg, u32 mask, u32 val)
43395711cd5SPawel Dembicki {
43495711cd5SPawel Dembicki 	u32 tmp, orig;
43595711cd5SPawel Dembicki 	int ret;
43695711cd5SPawel Dembicki 
43795711cd5SPawel Dembicki 	/* Same read-modify-write algorithm as e.g. regmap */
43895711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, block, subblock, reg, &orig);
43995711cd5SPawel Dembicki 	if (ret)
44095711cd5SPawel Dembicki 		return ret;
44195711cd5SPawel Dembicki 	tmp = orig & ~mask;
44295711cd5SPawel Dembicki 	tmp |= val & mask;
44395711cd5SPawel Dembicki 	return vsc73xx_write(vsc, block, subblock, reg, tmp);
44495711cd5SPawel Dembicki }
44595711cd5SPawel Dembicki 
44695711cd5SPawel Dembicki static int vsc73xx_detect(struct vsc73xx *vsc)
44795711cd5SPawel Dembicki {
44895711cd5SPawel Dembicki 	bool icpu_si_boot_en;
44995711cd5SPawel Dembicki 	bool icpu_pi_en;
45095711cd5SPawel Dembicki 	u32 val;
45195711cd5SPawel Dembicki 	u32 rev;
45295711cd5SPawel Dembicki 	int ret;
45395711cd5SPawel Dembicki 	u32 id;
45495711cd5SPawel Dembicki 
45595711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
45695711cd5SPawel Dembicki 			   VSC73XX_ICPU_MBOX_VAL, &val);
45795711cd5SPawel Dembicki 	if (ret) {
45895711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to read mailbox (%d)\n", ret);
45995711cd5SPawel Dembicki 		return ret;
46095711cd5SPawel Dembicki 	}
46195711cd5SPawel Dembicki 
46295711cd5SPawel Dembicki 	if (val == 0xffffffff) {
4631da39ff0SPawel Dembicki 		dev_info(vsc->dev, "chip seems dead.\n");
4641da39ff0SPawel Dembicki 		return -EAGAIN;
46595711cd5SPawel Dembicki 	}
46695711cd5SPawel Dembicki 
46795711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
46895711cd5SPawel Dembicki 			   VSC73XX_CHIPID, &val);
46995711cd5SPawel Dembicki 	if (ret) {
47095711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to read chip id (%d)\n", ret);
47195711cd5SPawel Dembicki 		return ret;
47295711cd5SPawel Dembicki 	}
47395711cd5SPawel Dembicki 
47495711cd5SPawel Dembicki 	id = (val >> VSC73XX_CHIPID_ID_SHIFT) &
47595711cd5SPawel Dembicki 		VSC73XX_CHIPID_ID_MASK;
47695711cd5SPawel Dembicki 	switch (id) {
47795711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7385:
47895711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7388:
47995711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7395:
48095711cd5SPawel Dembicki 	case VSC73XX_CHIPID_ID_7398:
48195711cd5SPawel Dembicki 		break;
48295711cd5SPawel Dembicki 	default:
48395711cd5SPawel Dembicki 		dev_err(vsc->dev, "unsupported chip, id=%04x\n", id);
48495711cd5SPawel Dembicki 		return -ENODEV;
48595711cd5SPawel Dembicki 	}
48695711cd5SPawel Dembicki 
48795711cd5SPawel Dembicki 	vsc->chipid = id;
48895711cd5SPawel Dembicki 	rev = (val >> VSC73XX_CHIPID_REV_SHIFT) &
48995711cd5SPawel Dembicki 		VSC73XX_CHIPID_REV_MASK;
49095711cd5SPawel Dembicki 	dev_info(vsc->dev, "VSC%04X (rev: %d) switch found\n", id, rev);
49195711cd5SPawel Dembicki 
49295711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
49395711cd5SPawel Dembicki 			   VSC73XX_ICPU_CTRL, &val);
49495711cd5SPawel Dembicki 	if (ret) {
49595711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to read iCPU control\n");
49695711cd5SPawel Dembicki 		return ret;
49795711cd5SPawel Dembicki 	}
49895711cd5SPawel Dembicki 
49995711cd5SPawel Dembicki 	/* The iCPU can always be used but can boot in different ways.
50095711cd5SPawel Dembicki 	 * If it is initially disabled and has no external memory,
50195711cd5SPawel Dembicki 	 * we are in control and can do whatever we like, else we
50295711cd5SPawel Dembicki 	 * are probably in trouble (we need some way to communicate
50395711cd5SPawel Dembicki 	 * with the running firmware) so we bail out for now.
50495711cd5SPawel Dembicki 	 */
50595711cd5SPawel Dembicki 	icpu_pi_en = !!(val & VSC73XX_ICPU_CTRL_ICPU_PI_EN);
50695711cd5SPawel Dembicki 	icpu_si_boot_en = !!(val & VSC73XX_ICPU_CTRL_BOOT_EN);
50795711cd5SPawel Dembicki 	if (icpu_si_boot_en && icpu_pi_en) {
50895711cd5SPawel Dembicki 		dev_err(vsc->dev,
50995711cd5SPawel Dembicki 			"iCPU enabled boots from SI, has external memory\n");
51095711cd5SPawel Dembicki 		dev_err(vsc->dev, "no idea how to deal with this\n");
51195711cd5SPawel Dembicki 		return -ENODEV;
51295711cd5SPawel Dembicki 	}
51395711cd5SPawel Dembicki 	if (icpu_si_boot_en && !icpu_pi_en) {
51495711cd5SPawel Dembicki 		dev_err(vsc->dev,
5151da39ff0SPawel Dembicki 			"iCPU enabled boots from PI/SI, no external memory\n");
5161da39ff0SPawel Dembicki 		return -EAGAIN;
51795711cd5SPawel Dembicki 	}
51895711cd5SPawel Dembicki 	if (!icpu_si_boot_en && icpu_pi_en) {
51995711cd5SPawel Dembicki 		dev_err(vsc->dev,
52095711cd5SPawel Dembicki 			"iCPU enabled, boots from PI external memory\n");
52195711cd5SPawel Dembicki 		dev_err(vsc->dev, "no idea how to deal with this\n");
52295711cd5SPawel Dembicki 		return -ENODEV;
52395711cd5SPawel Dembicki 	}
52495711cd5SPawel Dembicki 	/* !icpu_si_boot_en && !cpu_pi_en */
52595711cd5SPawel Dembicki 	dev_info(vsc->dev, "iCPU disabled, no external memory\n");
52695711cd5SPawel Dembicki 
52795711cd5SPawel Dembicki 	return 0;
52895711cd5SPawel Dembicki }
52995711cd5SPawel Dembicki 
53095711cd5SPawel Dembicki static int vsc73xx_phy_read(struct dsa_switch *ds, int phy, int regnum)
53195711cd5SPawel Dembicki {
53295711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
53395711cd5SPawel Dembicki 	u32 cmd;
53495711cd5SPawel Dembicki 	u32 val;
53595711cd5SPawel Dembicki 	int ret;
53695711cd5SPawel Dembicki 
53795711cd5SPawel Dembicki 	/* Setting bit 26 means "read" */
53895711cd5SPawel Dembicki 	cmd = BIT(26) | (phy << 21) | (regnum << 16);
53995711cd5SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_MII, 0, 1, cmd);
54095711cd5SPawel Dembicki 	if (ret)
54195711cd5SPawel Dembicki 		return ret;
54295711cd5SPawel Dembicki 	msleep(2);
54395711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MII, 0, 2, &val);
54495711cd5SPawel Dembicki 	if (ret)
54595711cd5SPawel Dembicki 		return ret;
54695711cd5SPawel Dembicki 	if (val & BIT(16)) {
54795711cd5SPawel Dembicki 		dev_err(vsc->dev, "reading reg %02x from phy%d failed\n",
54895711cd5SPawel Dembicki 			regnum, phy);
54995711cd5SPawel Dembicki 		return -EIO;
55095711cd5SPawel Dembicki 	}
55195711cd5SPawel Dembicki 	val &= 0xFFFFU;
55295711cd5SPawel Dembicki 
55395711cd5SPawel Dembicki 	dev_dbg(vsc->dev, "read reg %02x from phy%d = %04x\n",
55495711cd5SPawel Dembicki 		regnum, phy, val);
55595711cd5SPawel Dembicki 
55695711cd5SPawel Dembicki 	return val;
55795711cd5SPawel Dembicki }
55895711cd5SPawel Dembicki 
55995711cd5SPawel Dembicki static int vsc73xx_phy_write(struct dsa_switch *ds, int phy, int regnum,
56095711cd5SPawel Dembicki 			     u16 val)
56195711cd5SPawel Dembicki {
56295711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
56395711cd5SPawel Dembicki 	u32 cmd;
56495711cd5SPawel Dembicki 	int ret;
56595711cd5SPawel Dembicki 
56695711cd5SPawel Dembicki 	/* It was found through tedious experiments that this router
56795711cd5SPawel Dembicki 	 * chip really hates to have it's PHYs reset. They
56895711cd5SPawel Dembicki 	 * never recover if that happens: autonegotiation stops
56995711cd5SPawel Dembicki 	 * working after a reset. Just filter out this command.
57095711cd5SPawel Dembicki 	 * (Resetting the whole chip is OK.)
57195711cd5SPawel Dembicki 	 */
57295711cd5SPawel Dembicki 	if (regnum == 0 && (val & BIT(15))) {
57395711cd5SPawel Dembicki 		dev_info(vsc->dev, "reset PHY - disallowed\n");
57495711cd5SPawel Dembicki 		return 0;
57595711cd5SPawel Dembicki 	}
57695711cd5SPawel Dembicki 
57795711cd5SPawel Dembicki 	cmd = (phy << 21) | (regnum << 16);
57895711cd5SPawel Dembicki 	ret = vsc73xx_write(vsc, VSC73XX_BLOCK_MII, 0, 1, cmd);
57995711cd5SPawel Dembicki 	if (ret)
58095711cd5SPawel Dembicki 		return ret;
58195711cd5SPawel Dembicki 
58295711cd5SPawel Dembicki 	dev_dbg(vsc->dev, "write %04x to reg %02x in phy%d\n",
58395711cd5SPawel Dembicki 		val, regnum, phy);
58495711cd5SPawel Dembicki 	return 0;
58595711cd5SPawel Dembicki }
58695711cd5SPawel Dembicki 
58795711cd5SPawel Dembicki static enum dsa_tag_protocol vsc73xx_get_tag_protocol(struct dsa_switch *ds,
5884d776482SFlorian Fainelli 						      int port,
5894d776482SFlorian Fainelli 						      enum dsa_tag_protocol mp)
59095711cd5SPawel Dembicki {
59195711cd5SPawel Dembicki 	/* The switch internally uses a 8 byte header with length,
59295711cd5SPawel Dembicki 	 * source port, tag, LPA and priority. This is supposedly
59395711cd5SPawel Dembicki 	 * only accessible when operating the switch using the internal
59495711cd5SPawel Dembicki 	 * CPU or with an external CPU mapping the device in, but not
59595711cd5SPawel Dembicki 	 * when operating the switch over SPI and putting frames in/out
59695711cd5SPawel Dembicki 	 * on port 6 (the CPU port). So far we must assume that we
59795711cd5SPawel Dembicki 	 * cannot access the tag. (See "Internal frame header" section
59895711cd5SPawel Dembicki 	 * 3.9.1 in the manual.)
59995711cd5SPawel Dembicki 	 */
600*e3386ec4SPawel Dembicki 	return DSA_TAG_PROTO_VSC73XX_8021Q;
60195711cd5SPawel Dembicki }
60295711cd5SPawel Dembicki 
6036b783dedSPawel Dembicki static int vsc73xx_wait_for_vlan_table_cmd(struct vsc73xx *vsc)
6046b783dedSPawel Dembicki {
6056b783dedSPawel Dembicki 	int ret, err;
6066b783dedSPawel Dembicki 	u32 val;
6076b783dedSPawel Dembicki 
6086b783dedSPawel Dembicki 	ret = read_poll_timeout(vsc73xx_read, err,
6096b783dedSPawel Dembicki 				err < 0 ||
6106b783dedSPawel Dembicki 				((val & VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK) ==
6116b783dedSPawel Dembicki 				VSC73XX_VLANACCESS_VLAN_TBL_CMD_IDLE),
6126b783dedSPawel Dembicki 				VSC73XX_POLL_SLEEP_US, VSC73XX_POLL_TIMEOUT_US,
6136b783dedSPawel Dembicki 				false, vsc, VSC73XX_BLOCK_ANALYZER,
6146b783dedSPawel Dembicki 				0, VSC73XX_VLANACCESS, &val);
6156b783dedSPawel Dembicki 	if (ret)
6166b783dedSPawel Dembicki 		return ret;
6176b783dedSPawel Dembicki 	return err;
6186b783dedSPawel Dembicki }
6196b783dedSPawel Dembicki 
6206b783dedSPawel Dembicki static int
6216b783dedSPawel Dembicki vsc73xx_read_vlan_table_entry(struct vsc73xx *vsc, u16 vid, u8 *portmap)
6226b783dedSPawel Dembicki {
6236b783dedSPawel Dembicki 	u32 val;
6246b783dedSPawel Dembicki 	int ret;
6256b783dedSPawel Dembicki 
6266b783dedSPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANTIDX, vid);
6276b783dedSPawel Dembicki 
6286b783dedSPawel Dembicki 	ret = vsc73xx_wait_for_vlan_table_cmd(vsc);
6296b783dedSPawel Dembicki 	if (ret)
6306b783dedSPawel Dembicki 		return ret;
6316b783dedSPawel Dembicki 
6326b783dedSPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANACCESS,
6336b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK,
6346b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_READ_ENTRY);
6356b783dedSPawel Dembicki 
6366b783dedSPawel Dembicki 	ret = vsc73xx_wait_for_vlan_table_cmd(vsc);
6376b783dedSPawel Dembicki 	if (ret)
6386b783dedSPawel Dembicki 		return ret;
6396b783dedSPawel Dembicki 
6406b783dedSPawel Dembicki 	vsc73xx_read(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANACCESS, &val);
6416b783dedSPawel Dembicki 	*portmap = (val & VSC73XX_VLANACCESS_VLAN_PORT_MASK) >>
6426b783dedSPawel Dembicki 		   VSC73XX_VLANACCESS_VLAN_PORT_MASK_SHIFT;
6436b783dedSPawel Dembicki 
6446b783dedSPawel Dembicki 	return 0;
6456b783dedSPawel Dembicki }
6466b783dedSPawel Dembicki 
6476b783dedSPawel Dembicki static int
6486b783dedSPawel Dembicki vsc73xx_write_vlan_table_entry(struct vsc73xx *vsc, u16 vid, u8 portmap)
6496b783dedSPawel Dembicki {
6506b783dedSPawel Dembicki 	int ret;
6516b783dedSPawel Dembicki 
6526b783dedSPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANTIDX, vid);
6536b783dedSPawel Dembicki 
6546b783dedSPawel Dembicki 	ret = vsc73xx_wait_for_vlan_table_cmd(vsc);
6556b783dedSPawel Dembicki 	if (ret)
6566b783dedSPawel Dembicki 		return ret;
6576b783dedSPawel Dembicki 
6586b783dedSPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANACCESS,
6596b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK |
6606b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_SRC_CHECK |
6616b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_PORT_MASK,
6626b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_TBL_CMD_WRITE_ENTRY |
6636b783dedSPawel Dembicki 			    VSC73XX_VLANACCESS_VLAN_SRC_CHECK |
6646b783dedSPawel Dembicki 			    (portmap << VSC73XX_VLANACCESS_VLAN_PORT_MASK_SHIFT));
6656b783dedSPawel Dembicki 
6666b783dedSPawel Dembicki 	return vsc73xx_wait_for_vlan_table_cmd(vsc);
6676b783dedSPawel Dembicki }
6686b783dedSPawel Dembicki 
6696b783dedSPawel Dembicki static int
6706b783dedSPawel Dembicki vsc73xx_update_vlan_table(struct vsc73xx *vsc, int port, u16 vid, bool set)
6716b783dedSPawel Dembicki {
6726b783dedSPawel Dembicki 	u8 portmap;
6736b783dedSPawel Dembicki 	int ret;
6746b783dedSPawel Dembicki 
6756b783dedSPawel Dembicki 	ret = vsc73xx_read_vlan_table_entry(vsc, vid, &portmap);
6766b783dedSPawel Dembicki 	if (ret)
6776b783dedSPawel Dembicki 		return ret;
6786b783dedSPawel Dembicki 
6796b783dedSPawel Dembicki 	if (set)
6806b783dedSPawel Dembicki 		portmap |= BIT(port);
6816b783dedSPawel Dembicki 	else
6826b783dedSPawel Dembicki 		portmap &= ~BIT(port);
6836b783dedSPawel Dembicki 
6846b783dedSPawel Dembicki 	return vsc73xx_write_vlan_table_entry(vsc, vid, portmap);
6856b783dedSPawel Dembicki }
6866b783dedSPawel Dembicki 
68795711cd5SPawel Dembicki static int vsc73xx_setup(struct dsa_switch *ds)
68895711cd5SPawel Dembicki {
68995711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
690*e3386ec4SPawel Dembicki 	int i, ret;
69195711cd5SPawel Dembicki 
69295711cd5SPawel Dembicki 	dev_info(vsc->dev, "set up the switch\n");
69395711cd5SPawel Dembicki 
69495711cd5SPawel Dembicki 	/* Issue RESET */
69595711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
69695711cd5SPawel Dembicki 		      VSC73XX_GLORESET_MASTER_RESET);
69795711cd5SPawel Dembicki 	usleep_range(125, 200);
69895711cd5SPawel Dembicki 
69995711cd5SPawel Dembicki 	/* Initialize memory, initialize RAM bank 0..15 except 6 and 7
70095711cd5SPawel Dembicki 	 * This sequence appears in the
70195711cd5SPawel Dembicki 	 * VSC7385 SparX-G5 datasheet section 6.6.1
70295711cd5SPawel Dembicki 	 * VSC7395 SparX-G5e datasheet section 6.6.1
70395711cd5SPawel Dembicki 	 * "initialization sequence".
70495711cd5SPawel Dembicki 	 * No explanation is given to the 0x1010400 magic number.
70595711cd5SPawel Dembicki 	 */
70695711cd5SPawel Dembicki 	for (i = 0; i <= 15; i++) {
70795711cd5SPawel Dembicki 		if (i != 6 && i != 7) {
70895711cd5SPawel Dembicki 			vsc73xx_write(vsc, VSC73XX_BLOCK_MEMINIT,
70995711cd5SPawel Dembicki 				      2,
71095711cd5SPawel Dembicki 				      0, 0x1010400 + i);
71195711cd5SPawel Dembicki 			mdelay(1);
71295711cd5SPawel Dembicki 		}
71395711cd5SPawel Dembicki 	}
71495711cd5SPawel Dembicki 	mdelay(30);
71595711cd5SPawel Dembicki 
71695711cd5SPawel Dembicki 	/* Clear MAC table */
71795711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
71895711cd5SPawel Dembicki 		      VSC73XX_MACACCESS,
71995711cd5SPawel Dembicki 		      VSC73XX_MACACCESS_CMD_CLEAR_TABLE);
72095711cd5SPawel Dembicki 
7216b783dedSPawel Dembicki 	/* Set VLAN table to default values */
72295711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
72395711cd5SPawel Dembicki 		      VSC73XX_VLANACCESS,
72495711cd5SPawel Dembicki 		      VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE);
72595711cd5SPawel Dembicki 
72695711cd5SPawel Dembicki 	msleep(40);
72795711cd5SPawel Dembicki 
72895711cd5SPawel Dembicki 	/* Use 20KiB buffers on all ports on VSC7395
72995711cd5SPawel Dembicki 	 * The VSC7385 has 16KiB buffers and that is the
73095711cd5SPawel Dembicki 	 * default if we don't set this up explicitly.
73195711cd5SPawel Dembicki 	 * Port "31" is "all ports".
73295711cd5SPawel Dembicki 	 */
73395711cd5SPawel Dembicki 	if (IS_739X(vsc))
73495711cd5SPawel Dembicki 		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 0x1f,
73595711cd5SPawel Dembicki 			      VSC73XX_Q_MISC_CONF,
73695711cd5SPawel Dembicki 			      VSC73XX_Q_MISC_CONF_EXTENT_MEM);
73795711cd5SPawel Dembicki 
73895711cd5SPawel Dembicki 	/* Put all ports into reset until enabled */
73995711cd5SPawel Dembicki 	for (i = 0; i < 7; i++) {
74095711cd5SPawel Dembicki 		if (i == 5)
74195711cd5SPawel Dembicki 			continue;
74295711cd5SPawel Dembicki 		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 4,
74395711cd5SPawel Dembicki 			      VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
74495711cd5SPawel Dembicki 	}
74595711cd5SPawel Dembicki 
74695711cd5SPawel Dembicki 	/* MII delay, set both GTX and RX delay to 2 ns */
74795711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GMIIDELAY,
74895711cd5SPawel Dembicki 		      VSC73XX_GMIIDELAY_GMII0_GTXDELAY_2_0_NS |
74995711cd5SPawel Dembicki 		      VSC73XX_GMIIDELAY_GMII0_RXDELAY_2_0_NS);
7506b783dedSPawel Dembicki 	/* Ingess VLAN reception mask (table 145) */
7516b783dedSPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_VLANMASK,
7526b783dedSPawel Dembicki 		      0xff);
75395711cd5SPawel Dembicki 	/* IP multicast flood mask (table 144) */
75495711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_IFLODMSK,
75595711cd5SPawel Dembicki 		      0xff);
75695711cd5SPawel Dembicki 
75795711cd5SPawel Dembicki 	mdelay(50);
75895711cd5SPawel Dembicki 
75995711cd5SPawel Dembicki 	/* Release reset from the internal PHYs */
76095711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
76195711cd5SPawel Dembicki 		      VSC73XX_GLORESET_PHY_RESET);
76295711cd5SPawel Dembicki 
76395711cd5SPawel Dembicki 	udelay(4);
76495711cd5SPawel Dembicki 
7656b783dedSPawel Dembicki 	/* Clear VLAN table */
7666b783dedSPawel Dembicki 	for (i = 0; i < VLAN_N_VID; i++)
7676b783dedSPawel Dembicki 		vsc73xx_write_vlan_table_entry(vsc, i, 0);
7686b783dedSPawel Dembicki 
7696b783dedSPawel Dembicki 	INIT_LIST_HEAD(&vsc->vlans);
7706b783dedSPawel Dembicki 
771*e3386ec4SPawel Dembicki 	rtnl_lock();
772*e3386ec4SPawel Dembicki 	ret = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
773*e3386ec4SPawel Dembicki 	rtnl_unlock();
774*e3386ec4SPawel Dembicki 
775*e3386ec4SPawel Dembicki 	return ret;
776*e3386ec4SPawel Dembicki }
777*e3386ec4SPawel Dembicki 
778*e3386ec4SPawel Dembicki static void vsc73xx_teardown(struct dsa_switch *ds)
779*e3386ec4SPawel Dembicki {
780*e3386ec4SPawel Dembicki 	rtnl_lock();
781*e3386ec4SPawel Dembicki 	dsa_tag_8021q_unregister(ds);
782*e3386ec4SPawel Dembicki 	rtnl_unlock();
78395711cd5SPawel Dembicki }
78495711cd5SPawel Dembicki 
78595711cd5SPawel Dembicki static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
78695711cd5SPawel Dembicki {
78795711cd5SPawel Dembicki 	u32 val;
78895711cd5SPawel Dembicki 
78995711cd5SPawel Dembicki 	/* MAC configure, first reset the port and then write defaults */
79095711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
79195711cd5SPawel Dembicki 		      port,
79295711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG,
79395711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG_RESET);
79495711cd5SPawel Dembicki 
79595711cd5SPawel Dembicki 	/* Take up the port in 1Gbit mode by default, this will be
79695711cd5SPawel Dembicki 	 * augmented after auto-negotiation on the PHY-facing
79795711cd5SPawel Dembicki 	 * ports.
79895711cd5SPawel Dembicki 	 */
79995711cd5SPawel Dembicki 	if (port == CPU_PORT)
80095711cd5SPawel Dembicki 		val = VSC73XX_MAC_CFG_1000M_F_RGMII;
80195711cd5SPawel Dembicki 	else
80295711cd5SPawel Dembicki 		val = VSC73XX_MAC_CFG_1000M_F_PHY;
80395711cd5SPawel Dembicki 
80495711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
80595711cd5SPawel Dembicki 		      port,
80695711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG,
80795711cd5SPawel Dembicki 		      val |
80895711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG_TX_EN |
80995711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG_RX_EN);
81095711cd5SPawel Dembicki 
81195711cd5SPawel Dembicki 	/* Flow control for the CPU port:
81295711cd5SPawel Dembicki 	 * Use a zero delay pause frame when pause condition is left
81395711cd5SPawel Dembicki 	 * Obey pause control frames
81495711cd5SPawel Dembicki 	 */
81595711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
81695711cd5SPawel Dembicki 		      port,
81795711cd5SPawel Dembicki 		      VSC73XX_FCCONF,
81895711cd5SPawel Dembicki 		      VSC73XX_FCCONF_ZERO_PAUSE_EN |
81995711cd5SPawel Dembicki 		      VSC73XX_FCCONF_FLOW_CTRL_OBEY);
82095711cd5SPawel Dembicki 
82195711cd5SPawel Dembicki 	/* Issue pause control frames on PHY facing ports.
82295711cd5SPawel Dembicki 	 * Allow early initiation of MAC transmission if the amount
82395711cd5SPawel Dembicki 	 * of egress data is below 512 bytes on CPU port.
82495711cd5SPawel Dembicki 	 * FIXME: enable 20KiB buffers?
82595711cd5SPawel Dembicki 	 */
82695711cd5SPawel Dembicki 	if (port == CPU_PORT)
82795711cd5SPawel Dembicki 		val = VSC73XX_Q_MISC_CONF_EARLY_TX_512;
82895711cd5SPawel Dembicki 	else
82995711cd5SPawel Dembicki 		val = VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE;
83095711cd5SPawel Dembicki 	val |= VSC73XX_Q_MISC_CONF_EXTENT_MEM;
83195711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
83295711cd5SPawel Dembicki 		      port,
83395711cd5SPawel Dembicki 		      VSC73XX_Q_MISC_CONF,
83495711cd5SPawel Dembicki 		      val);
83595711cd5SPawel Dembicki 
83695711cd5SPawel Dembicki 	/* Flow control MAC: a MAC address used in flow control frames */
83795711cd5SPawel Dembicki 	val = (vsc->addr[5] << 16) | (vsc->addr[4] << 8) | (vsc->addr[3]);
83895711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
83995711cd5SPawel Dembicki 		      port,
84095711cd5SPawel Dembicki 		      VSC73XX_FCMACHI,
84195711cd5SPawel Dembicki 		      val);
84295711cd5SPawel Dembicki 	val = (vsc->addr[2] << 16) | (vsc->addr[1] << 8) | (vsc->addr[0]);
84395711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
84495711cd5SPawel Dembicki 		      port,
84595711cd5SPawel Dembicki 		      VSC73XX_FCMACLO,
84695711cd5SPawel Dembicki 		      val);
84795711cd5SPawel Dembicki 
84895711cd5SPawel Dembicki 	/* Tell the categorizer to forward pause frames, not control
84995711cd5SPawel Dembicki 	 * frame. Do not drop anything.
85095711cd5SPawel Dembicki 	 */
85195711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
85295711cd5SPawel Dembicki 		      port,
85395711cd5SPawel Dembicki 		      VSC73XX_CAT_DROP,
85495711cd5SPawel Dembicki 		      VSC73XX_CAT_DROP_FWD_PAUSE_ENA);
85595711cd5SPawel Dembicki 
85695711cd5SPawel Dembicki 	/* Clear all counters */
85795711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
85895711cd5SPawel Dembicki 		      port, VSC73XX_C_RX0, 0);
85995711cd5SPawel Dembicki }
86095711cd5SPawel Dembicki 
86121fc3416SPawel Dembicki static void vsc73xx_reset_port(struct vsc73xx *vsc, int port, u32 initval)
86295711cd5SPawel Dembicki {
863eb7e33d0SPawel Dembicki 	int ret, err;
86421fc3416SPawel Dembicki 	u32 val;
86595711cd5SPawel Dembicki 
86695711cd5SPawel Dembicki 	/* Disable RX on this port */
86795711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
86895711cd5SPawel Dembicki 			    VSC73XX_MAC_CFG,
86995711cd5SPawel Dembicki 			    VSC73XX_MAC_CFG_RX_EN, 0);
87095711cd5SPawel Dembicki 
87195711cd5SPawel Dembicki 	/* Discard packets */
87295711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
87395711cd5SPawel Dembicki 			    VSC73XX_ARBDISC, BIT(port), BIT(port));
87495711cd5SPawel Dembicki 
87595711cd5SPawel Dembicki 	/* Wait until queue is empty */
876eb7e33d0SPawel Dembicki 	ret = read_poll_timeout(vsc73xx_read, err,
877eb7e33d0SPawel Dembicki 				err < 0 || (val & BIT(port)),
878eb7e33d0SPawel Dembicki 				VSC73XX_POLL_SLEEP_US,
879eb7e33d0SPawel Dembicki 				VSC73XX_POLL_TIMEOUT_US, false,
880eb7e33d0SPawel Dembicki 				vsc, VSC73XX_BLOCK_ARBITER, 0,
88195711cd5SPawel Dembicki 				VSC73XX_ARBEMPTY, &val);
882eb7e33d0SPawel Dembicki 	if (ret)
88395711cd5SPawel Dembicki 		dev_err(vsc->dev,
88495711cd5SPawel Dembicki 			"timeout waiting for block arbiter\n");
885eb7e33d0SPawel Dembicki 	else if (err < 0)
886eb7e33d0SPawel Dembicki 		dev_err(vsc->dev, "error reading arbiter\n");
88795711cd5SPawel Dembicki 
88895711cd5SPawel Dembicki 	/* Put this port into reset */
88995711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
89021fc3416SPawel Dembicki 		      VSC73XX_MAC_CFG_RESET | initval);
89121fc3416SPawel Dembicki }
89295711cd5SPawel Dembicki 
89321fc3416SPawel Dembicki static void vsc73xx_mac_config(struct phylink_config *config, unsigned int mode,
89421fc3416SPawel Dembicki 			       const struct phylink_link_state *state)
89521fc3416SPawel Dembicki {
89621fc3416SPawel Dembicki 	struct dsa_port *dp = dsa_phylink_to_port(config);
89721fc3416SPawel Dembicki 	struct vsc73xx *vsc = dp->ds->priv;
89821fc3416SPawel Dembicki 	int port = dp->index;
89921fc3416SPawel Dembicki 
90021fc3416SPawel Dembicki 	/* Special handling of the CPU-facing port */
90121fc3416SPawel Dembicki 	if (port == CPU_PORT) {
90221fc3416SPawel Dembicki 		/* Other ports are already initialized but not this one */
90321fc3416SPawel Dembicki 		vsc73xx_init_port(vsc, CPU_PORT);
90421fc3416SPawel Dembicki 		/* Select the external port for this interface (EXT_PORT)
90521fc3416SPawel Dembicki 		 * Enable the GMII GTX external clock
90621fc3416SPawel Dembicki 		 * Use double data rate (DDR mode)
90721fc3416SPawel Dembicki 		 */
90821fc3416SPawel Dembicki 		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
90921fc3416SPawel Dembicki 			      CPU_PORT,
91021fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM,
91121fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM_EXT_PORT |
91221fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM_ENA_GTX |
91321fc3416SPawel Dembicki 			      VSC73XX_ADVPORTM_DDR_MODE);
91421fc3416SPawel Dembicki 	}
91521fc3416SPawel Dembicki }
91621fc3416SPawel Dembicki 
91721fc3416SPawel Dembicki static void vsc73xx_mac_link_down(struct phylink_config *config,
91821fc3416SPawel Dembicki 				  unsigned int mode, phy_interface_t interface)
91921fc3416SPawel Dembicki {
92021fc3416SPawel Dembicki 	struct dsa_port *dp = dsa_phylink_to_port(config);
92121fc3416SPawel Dembicki 	struct vsc73xx *vsc = dp->ds->priv;
92221fc3416SPawel Dembicki 	int port = dp->index;
92321fc3416SPawel Dembicki 
92421fc3416SPawel Dembicki 	/* This routine is described in the datasheet (below ARBDISC register
92521fc3416SPawel Dembicki 	 * description)
92621fc3416SPawel Dembicki 	 */
92721fc3416SPawel Dembicki 	vsc73xx_reset_port(vsc, port, 0);
92895711cd5SPawel Dembicki 
92995711cd5SPawel Dembicki 	/* Allow backward dropping of frames from this port */
93095711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
93195711cd5SPawel Dembicki 			    VSC73XX_SBACKWDROP, BIT(port), BIT(port));
93295711cd5SPawel Dembicki }
93395711cd5SPawel Dembicki 
93421fc3416SPawel Dembicki static void vsc73xx_mac_link_up(struct phylink_config *config,
93521fc3416SPawel Dembicki 				struct phy_device *phy, unsigned int mode,
93621fc3416SPawel Dembicki 				phy_interface_t interface, int speed,
93721fc3416SPawel Dembicki 				int duplex, bool tx_pause, bool rx_pause)
93821fc3416SPawel Dembicki {
93921fc3416SPawel Dembicki 	struct dsa_port *dp = dsa_phylink_to_port(config);
94021fc3416SPawel Dembicki 	struct vsc73xx *vsc = dp->ds->priv;
94121fc3416SPawel Dembicki 	int port = dp->index;
94221fc3416SPawel Dembicki 	u32 val;
94321fc3416SPawel Dembicki 	u8 seed;
94495711cd5SPawel Dembicki 
94521fc3416SPawel Dembicki 	if (speed == SPEED_1000)
94621fc3416SPawel Dembicki 		val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M;
94795711cd5SPawel Dembicki 	else
94821fc3416SPawel Dembicki 		val = VSC73XX_MAC_CFG_TX_IPG_100_10M;
94995711cd5SPawel Dembicki 
95012af94b2SPawel Dembicki 	if (phy_interface_mode_is_rgmii(interface))
95121fc3416SPawel Dembicki 		val |= VSC73XX_MAC_CFG_CLK_SEL_1000M;
95221fc3416SPawel Dembicki 	else
95321fc3416SPawel Dembicki 		val |= VSC73XX_MAC_CFG_CLK_SEL_EXT;
95421fc3416SPawel Dembicki 
95521fc3416SPawel Dembicki 	if (duplex == DUPLEX_FULL)
95621fc3416SPawel Dembicki 		val |= VSC73XX_MAC_CFG_FDX;
95721fc3416SPawel Dembicki 
95821fc3416SPawel Dembicki 	/* This routine is described in the datasheet (below ARBDISC register
95921fc3416SPawel Dembicki 	 * description)
96021fc3416SPawel Dembicki 	 */
96121fc3416SPawel Dembicki 	vsc73xx_reset_port(vsc, port, val);
96221fc3416SPawel Dembicki 
96321fc3416SPawel Dembicki 	/* Seed the port randomness with randomness */
96421fc3416SPawel Dembicki 	get_random_bytes(&seed, 1);
96521fc3416SPawel Dembicki 	val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET;
96621fc3416SPawel Dembicki 	val |= VSC73XX_MAC_CFG_SEED_LOAD;
96721fc3416SPawel Dembicki 	val |= VSC73XX_MAC_CFG_WEXC_DIS;
9686b783dedSPawel Dembicki 
9696b783dedSPawel Dembicki 	/* Those bits are responsible for MTU only. Kernel takes care about MTU,
9706b783dedSPawel Dembicki 	 * let's enable +8 bytes frame length unconditionally.
9716b783dedSPawel Dembicki 	 */
9726b783dedSPawel Dembicki 	val |= VSC73XX_MAC_CFG_VLAN_AWR | VSC73XX_MAC_CFG_VLAN_DBLAWR;
9736b783dedSPawel Dembicki 
97421fc3416SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
97521fc3416SPawel Dembicki 
97621fc3416SPawel Dembicki 	/* Flow control for the PHY facing ports:
97721fc3416SPawel Dembicki 	 * Use a zero delay pause frame when pause condition is left
97821fc3416SPawel Dembicki 	 * Obey pause control frames
97921fc3416SPawel Dembicki 	 * When generating pause frames, use 0xff as pause value
98021fc3416SPawel Dembicki 	 */
98121fc3416SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
98221fc3416SPawel Dembicki 		      VSC73XX_FCCONF_ZERO_PAUSE_EN |
98321fc3416SPawel Dembicki 		      VSC73XX_FCCONF_FLOW_CTRL_OBEY |
98421fc3416SPawel Dembicki 		      0xff);
98521fc3416SPawel Dembicki 
98621fc3416SPawel Dembicki 	/* Accept packets again */
98721fc3416SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
98821fc3416SPawel Dembicki 			    VSC73XX_ARBDISC, BIT(port), 0);
98921fc3416SPawel Dembicki 
99021fc3416SPawel Dembicki 	/* Disallow backward dropping of frames from this port */
99121fc3416SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
99221fc3416SPawel Dembicki 			    VSC73XX_SBACKWDROP, BIT(port), 0);
99321fc3416SPawel Dembicki 
99421fc3416SPawel Dembicki 	/* Enable TX, RX, deassert reset, stop loading seed */
99521fc3416SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
99621fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG,
99721fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
99821fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN,
99921fc3416SPawel Dembicki 			    VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN);
100095711cd5SPawel Dembicki }
100195711cd5SPawel Dembicki 
10026b783dedSPawel Dembicki static bool vsc73xx_tag_8021q_active(struct dsa_port *dp)
10036b783dedSPawel Dembicki {
10046b783dedSPawel Dembicki 	return !dsa_port_is_vlan_filtering(dp);
10056b783dedSPawel Dembicki }
10066b783dedSPawel Dembicki 
10076b783dedSPawel Dembicki static struct vsc73xx_bridge_vlan *
10086b783dedSPawel Dembicki vsc73xx_bridge_vlan_find(struct vsc73xx *vsc, u16 vid)
10096b783dedSPawel Dembicki {
10106b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vlan;
10116b783dedSPawel Dembicki 
10126b783dedSPawel Dembicki 	list_for_each_entry(vlan, &vsc->vlans, list)
10136b783dedSPawel Dembicki 		if (vlan->vid == vid)
10146b783dedSPawel Dembicki 			return vlan;
10156b783dedSPawel Dembicki 
10166b783dedSPawel Dembicki 	return NULL;
10176b783dedSPawel Dembicki }
10186b783dedSPawel Dembicki 
10196b783dedSPawel Dembicki static void
10206b783dedSPawel Dembicki vsc73xx_bridge_vlan_remove_port(struct vsc73xx_bridge_vlan *vsc73xx_vlan,
10216b783dedSPawel Dembicki 				int port)
10226b783dedSPawel Dembicki {
10236b783dedSPawel Dembicki 	vsc73xx_vlan->portmask &= ~BIT(port);
10246b783dedSPawel Dembicki 
10256b783dedSPawel Dembicki 	if (vsc73xx_vlan->portmask)
10266b783dedSPawel Dembicki 		return;
10276b783dedSPawel Dembicki 
10286b783dedSPawel Dembicki 	list_del(&vsc73xx_vlan->list);
10296b783dedSPawel Dembicki 	kfree(vsc73xx_vlan);
10306b783dedSPawel Dembicki }
10316b783dedSPawel Dembicki 
10326b783dedSPawel Dembicki static void vsc73xx_bridge_vlan_summary(struct vsc73xx *vsc, int port,
10336b783dedSPawel Dembicki 					struct vsc73xx_vlan_summary *summary,
10346b783dedSPawel Dembicki 					u16 ignored_vid)
10356b783dedSPawel Dembicki {
10366b783dedSPawel Dembicki 	size_t num_tagged = 0, num_untagged = 0;
10376b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vlan;
10386b783dedSPawel Dembicki 
10396b783dedSPawel Dembicki 	list_for_each_entry(vlan, &vsc->vlans, list) {
10406b783dedSPawel Dembicki 		if (!(vlan->portmask & BIT(port)) || vlan->vid == ignored_vid)
10416b783dedSPawel Dembicki 			continue;
10426b783dedSPawel Dembicki 
10436b783dedSPawel Dembicki 		if (vlan->untagged & BIT(port))
10446b783dedSPawel Dembicki 			num_untagged++;
10456b783dedSPawel Dembicki 		else
10466b783dedSPawel Dembicki 			num_tagged++;
10476b783dedSPawel Dembicki 	}
10486b783dedSPawel Dembicki 
10496b783dedSPawel Dembicki 	summary->num_untagged = num_untagged;
10506b783dedSPawel Dembicki 	summary->num_tagged = num_tagged;
10516b783dedSPawel Dembicki }
10526b783dedSPawel Dembicki 
10536b783dedSPawel Dembicki static u16 vsc73xx_find_first_vlan_untagged(struct vsc73xx *vsc, int port)
10546b783dedSPawel Dembicki {
10556b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vlan;
10566b783dedSPawel Dembicki 
10576b783dedSPawel Dembicki 	list_for_each_entry(vlan, &vsc->vlans, list)
10586b783dedSPawel Dembicki 		if ((vlan->portmask & BIT(port)) &&
10596b783dedSPawel Dembicki 		    (vlan->untagged & BIT(port)))
10606b783dedSPawel Dembicki 			return vlan->vid;
10616b783dedSPawel Dembicki 
10626b783dedSPawel Dembicki 	return VLAN_N_VID;
10636b783dedSPawel Dembicki }
10646b783dedSPawel Dembicki 
10656b783dedSPawel Dembicki static int vsc73xx_set_vlan_conf(struct vsc73xx *vsc, int port,
10666b783dedSPawel Dembicki 				 enum vsc73xx_port_vlan_conf port_vlan_conf)
10676b783dedSPawel Dembicki {
10686b783dedSPawel Dembicki 	u32 val = 0;
10696b783dedSPawel Dembicki 	int ret;
10706b783dedSPawel Dembicki 
10716b783dedSPawel Dembicki 	if (port_vlan_conf == VSC73XX_VLAN_IGNORE)
10726b783dedSPawel Dembicki 		val = VSC73XX_CAT_VLAN_MISC_VLAN_TCI_IGNORE_ENA |
10736b783dedSPawel Dembicki 		      VSC73XX_CAT_VLAN_MISC_VLAN_KEEP_TAG_ENA;
10746b783dedSPawel Dembicki 
10756b783dedSPawel Dembicki 	ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
10766b783dedSPawel Dembicki 				  VSC73XX_CAT_VLAN_MISC,
10776b783dedSPawel Dembicki 				  VSC73XX_CAT_VLAN_MISC_VLAN_TCI_IGNORE_ENA |
10786b783dedSPawel Dembicki 				  VSC73XX_CAT_VLAN_MISC_VLAN_KEEP_TAG_ENA, val);
10796b783dedSPawel Dembicki 	if (ret)
10806b783dedSPawel Dembicki 		return ret;
10816b783dedSPawel Dembicki 
10826b783dedSPawel Dembicki 	val = (port_vlan_conf == VSC73XX_VLAN_FILTER) ?
10836b783dedSPawel Dembicki 	      VSC73XX_TXUPDCFG_TX_INSERT_TAG : 0;
10846b783dedSPawel Dembicki 
10856b783dedSPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
10866b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG,
10876b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG_TX_INSERT_TAG, val);
10886b783dedSPawel Dembicki }
10896b783dedSPawel Dembicki 
10906b783dedSPawel Dembicki /**
10916b783dedSPawel Dembicki  * vsc73xx_vlan_commit_conf - Update VLAN configuration of a port
10926b783dedSPawel Dembicki  * @vsc: Switch private data structure
10936b783dedSPawel Dembicki  * @port: Port index on which to operate
10946b783dedSPawel Dembicki  *
10956b783dedSPawel Dembicki  * Update the VLAN behavior of a port to make sure that when it is under
10966b783dedSPawel Dembicki  * a VLAN filtering bridge, the port is either filtering with tag
10976b783dedSPawel Dembicki  * preservation, or filtering with all VLANs egress-untagged. Otherwise,
10986b783dedSPawel Dembicki  * the port ignores VLAN tags from packets and applies the port-based
10996b783dedSPawel Dembicki  * VID.
11006b783dedSPawel Dembicki  *
11016b783dedSPawel Dembicki  * Must be called when changes are made to:
11026b783dedSPawel Dembicki  * - the bridge VLAN filtering state of the port
11036b783dedSPawel Dembicki  * - the number or attributes of VLANs from the bridge VLAN table,
11046b783dedSPawel Dembicki  *   while the port is currently VLAN-aware
11056b783dedSPawel Dembicki  *
11066b783dedSPawel Dembicki  * Return: 0 on success, or negative errno on error.
11076b783dedSPawel Dembicki  */
11086b783dedSPawel Dembicki static int vsc73xx_vlan_commit_conf(struct vsc73xx *vsc, int port)
11096b783dedSPawel Dembicki {
11106b783dedSPawel Dembicki 	enum vsc73xx_port_vlan_conf port_vlan_conf = VSC73XX_VLAN_IGNORE;
11116b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(vsc->ds, port);
11126b783dedSPawel Dembicki 
11136b783dedSPawel Dembicki 	if (port == CPU_PORT) {
11146b783dedSPawel Dembicki 		port_vlan_conf = VSC73XX_VLAN_FILTER;
11156b783dedSPawel Dembicki 	} else if (dsa_port_is_vlan_filtering(dp)) {
11166b783dedSPawel Dembicki 		struct vsc73xx_vlan_summary summary;
11176b783dedSPawel Dembicki 
11186b783dedSPawel Dembicki 		port_vlan_conf = VSC73XX_VLAN_FILTER;
11196b783dedSPawel Dembicki 
11206b783dedSPawel Dembicki 		vsc73xx_bridge_vlan_summary(vsc, port, &summary, VLAN_N_VID);
11216b783dedSPawel Dembicki 		if (summary.num_tagged == 0)
11226b783dedSPawel Dembicki 			port_vlan_conf = VSC73XX_VLAN_FILTER_UNTAG_ALL;
11236b783dedSPawel Dembicki 	}
11246b783dedSPawel Dembicki 
11256b783dedSPawel Dembicki 	return vsc73xx_set_vlan_conf(vsc, port, port_vlan_conf);
11266b783dedSPawel Dembicki }
11276b783dedSPawel Dembicki 
11286b783dedSPawel Dembicki static int
11296b783dedSPawel Dembicki vsc73xx_vlan_change_untagged(struct vsc73xx *vsc, int port, u16 vid, bool set)
11306b783dedSPawel Dembicki {
11316b783dedSPawel Dembicki 	u32 val = 0;
11326b783dedSPawel Dembicki 
11336b783dedSPawel Dembicki 	if (set)
11346b783dedSPawel Dembicki 		val = VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_ENA |
11356b783dedSPawel Dembicki 		      ((vid << VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_SHIFT) &
11366b783dedSPawel Dembicki 		       VSC73XX_TXUPDCFG_TX_UNTAGGED_VID);
11376b783dedSPawel Dembicki 
11386b783dedSPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
11396b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG,
11406b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG_TX_UNTAGGED_VID_ENA |
11416b783dedSPawel Dembicki 				   VSC73XX_TXUPDCFG_TX_UNTAGGED_VID, val);
11426b783dedSPawel Dembicki }
11436b783dedSPawel Dembicki 
11446b783dedSPawel Dembicki /**
11456b783dedSPawel Dembicki  * vsc73xx_vlan_commit_untagged - Update native VLAN of a port
11466b783dedSPawel Dembicki  * @vsc: Switch private data structure
11476b783dedSPawel Dembicki  * @port: Port index on which to operate
11486b783dedSPawel Dembicki  *
11496b783dedSPawel Dembicki  * Update the native VLAN of a port (the one VLAN which is transmitted
11506b783dedSPawel Dembicki  * as egress-tagged on a trunk port) when port is in VLAN filtering mode and
11516b783dedSPawel Dembicki  * only one untagged vid is configured.
11526b783dedSPawel Dembicki  * In other cases no need to configure it because switch can untag all vlans on
11536b783dedSPawel Dembicki  * the port.
11546b783dedSPawel Dembicki  *
11556b783dedSPawel Dembicki  * Return: 0 on success, or negative errno on error.
11566b783dedSPawel Dembicki  */
11576b783dedSPawel Dembicki static int vsc73xx_vlan_commit_untagged(struct vsc73xx *vsc, int port)
11586b783dedSPawel Dembicki {
11596b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(vsc->ds, port);
11606b783dedSPawel Dembicki 	struct vsc73xx_vlan_summary summary;
11616b783dedSPawel Dembicki 	u16 vid = 0;
11626b783dedSPawel Dembicki 	bool valid;
11636b783dedSPawel Dembicki 
11646b783dedSPawel Dembicki 	if (!dsa_port_is_vlan_filtering(dp))
11656b783dedSPawel Dembicki 		/* Port is configured to untag all vlans in that case.
11666b783dedSPawel Dembicki 		 * No need to commit untagged config change.
11676b783dedSPawel Dembicki 		 */
11686b783dedSPawel Dembicki 		return 0;
11696b783dedSPawel Dembicki 
11706b783dedSPawel Dembicki 	vsc73xx_bridge_vlan_summary(vsc, port, &summary, VLAN_N_VID);
11716b783dedSPawel Dembicki 
11726b783dedSPawel Dembicki 	if (summary.num_untagged > 1)
11736b783dedSPawel Dembicki 		/* Port must untag all vlans in that case.
11746b783dedSPawel Dembicki 		 * No need to commit untagged config change.
11756b783dedSPawel Dembicki 		 */
11766b783dedSPawel Dembicki 		return 0;
11776b783dedSPawel Dembicki 
11786b783dedSPawel Dembicki 	valid = (summary.num_untagged == 1);
11796b783dedSPawel Dembicki 	if (valid)
11806b783dedSPawel Dembicki 		vid = vsc73xx_find_first_vlan_untagged(vsc, port);
11816b783dedSPawel Dembicki 
11826b783dedSPawel Dembicki 	return vsc73xx_vlan_change_untagged(vsc, port, vid, valid);
11836b783dedSPawel Dembicki }
11846b783dedSPawel Dembicki 
11856b783dedSPawel Dembicki static int
11866b783dedSPawel Dembicki vsc73xx_vlan_change_pvid(struct vsc73xx *vsc, int port, u16 vid, bool set)
11876b783dedSPawel Dembicki {
11886b783dedSPawel Dembicki 	u32 val = 0;
11896b783dedSPawel Dembicki 	int ret;
11906b783dedSPawel Dembicki 
11916b783dedSPawel Dembicki 	val = set ? 0 : VSC73XX_CAT_DROP_UNTAGGED_ENA;
11926b783dedSPawel Dembicki 
11936b783dedSPawel Dembicki 	ret = vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
11946b783dedSPawel Dembicki 				  VSC73XX_CAT_DROP,
11956b783dedSPawel Dembicki 				  VSC73XX_CAT_DROP_UNTAGGED_ENA, val);
11966b783dedSPawel Dembicki 	if (!set || ret)
11976b783dedSPawel Dembicki 		return ret;
11986b783dedSPawel Dembicki 
11996b783dedSPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
12006b783dedSPawel Dembicki 				   VSC73XX_CAT_PORT_VLAN,
12016b783dedSPawel Dembicki 				   VSC73XX_CAT_PORT_VLAN_VLAN_VID,
12026b783dedSPawel Dembicki 				   vid & VSC73XX_CAT_PORT_VLAN_VLAN_VID);
12036b783dedSPawel Dembicki }
12046b783dedSPawel Dembicki 
12056b783dedSPawel Dembicki /**
12066b783dedSPawel Dembicki  * vsc73xx_vlan_commit_pvid - Update port-based default VLAN of a port
12076b783dedSPawel Dembicki  * @vsc: Switch private data structure
12086b783dedSPawel Dembicki  * @port: Port index on which to operate
12096b783dedSPawel Dembicki  *
12106b783dedSPawel Dembicki  * Update the PVID of a port so that it follows either the bridge PVID
12116b783dedSPawel Dembicki  * configuration, when the bridge is currently VLAN-aware, or the PVID
12126b783dedSPawel Dembicki  * from tag_8021q, when the port is standalone or under a VLAN-unaware
12136b783dedSPawel Dembicki  * bridge. A port with no PVID drops all untagged and VID 0 tagged
12146b783dedSPawel Dembicki  * traffic.
12156b783dedSPawel Dembicki  *
12166b783dedSPawel Dembicki  * Must be called when changes are made to:
12176b783dedSPawel Dembicki  * - the bridge VLAN filtering state of the port
12186b783dedSPawel Dembicki  * - the number or attributes of VLANs from the bridge VLAN table,
12196b783dedSPawel Dembicki  *   while the port is currently VLAN-aware
12206b783dedSPawel Dembicki  *
12216b783dedSPawel Dembicki  * Return: 0 on success, or negative errno on error.
12226b783dedSPawel Dembicki  */
12236b783dedSPawel Dembicki static int vsc73xx_vlan_commit_pvid(struct vsc73xx *vsc, int port)
12246b783dedSPawel Dembicki {
12256b783dedSPawel Dembicki 	struct vsc73xx_portinfo *portinfo = &vsc->portinfo[port];
12266b783dedSPawel Dembicki 	bool valid = portinfo->pvid_tag_8021q_configured;
12276b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(vsc->ds, port);
12286b783dedSPawel Dembicki 	u16 vid = portinfo->pvid_tag_8021q;
12296b783dedSPawel Dembicki 
12306b783dedSPawel Dembicki 	if (dsa_port_is_vlan_filtering(dp)) {
12316b783dedSPawel Dembicki 		vid = portinfo->pvid_vlan_filtering;
12326b783dedSPawel Dembicki 		valid = portinfo->pvid_vlan_filtering_configured;
12336b783dedSPawel Dembicki 	}
12346b783dedSPawel Dembicki 
12356b783dedSPawel Dembicki 	return vsc73xx_vlan_change_pvid(vsc, port, vid, valid);
12366b783dedSPawel Dembicki }
12376b783dedSPawel Dembicki 
12386b783dedSPawel Dembicki static int vsc73xx_vlan_commit_settings(struct vsc73xx *vsc, int port)
12396b783dedSPawel Dembicki {
12406b783dedSPawel Dembicki 	int ret;
12416b783dedSPawel Dembicki 
12426b783dedSPawel Dembicki 	ret = vsc73xx_vlan_commit_untagged(vsc, port);
12436b783dedSPawel Dembicki 	if (ret)
12446b783dedSPawel Dembicki 		return ret;
12456b783dedSPawel Dembicki 
12466b783dedSPawel Dembicki 	ret = vsc73xx_vlan_commit_pvid(vsc, port);
12476b783dedSPawel Dembicki 	if (ret)
12486b783dedSPawel Dembicki 		return ret;
12496b783dedSPawel Dembicki 
12506b783dedSPawel Dembicki 	return vsc73xx_vlan_commit_conf(vsc, port);
12516b783dedSPawel Dembicki }
12526b783dedSPawel Dembicki 
125395711cd5SPawel Dembicki static int vsc73xx_port_enable(struct dsa_switch *ds, int port,
125495711cd5SPawel Dembicki 			       struct phy_device *phy)
125595711cd5SPawel Dembicki {
125695711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
125795711cd5SPawel Dembicki 
125895711cd5SPawel Dembicki 	dev_info(vsc->dev, "enable port %d\n", port);
125995711cd5SPawel Dembicki 	vsc73xx_init_port(vsc, port);
126095711cd5SPawel Dembicki 
12616b783dedSPawel Dembicki 	return vsc73xx_vlan_commit_settings(vsc, port);
126295711cd5SPawel Dembicki }
126395711cd5SPawel Dembicki 
126495711cd5SPawel Dembicki static void vsc73xx_port_disable(struct dsa_switch *ds, int port)
126595711cd5SPawel Dembicki {
126695711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
126795711cd5SPawel Dembicki 
126895711cd5SPawel Dembicki 	/* Just put the port into reset */
126995711cd5SPawel Dembicki 	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
127095711cd5SPawel Dembicki 		      VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
127195711cd5SPawel Dembicki }
127295711cd5SPawel Dembicki 
127395711cd5SPawel Dembicki static const struct vsc73xx_counter *
127495711cd5SPawel Dembicki vsc73xx_find_counter(struct vsc73xx *vsc,
127595711cd5SPawel Dembicki 		     u8 counter,
127695711cd5SPawel Dembicki 		     bool tx)
127795711cd5SPawel Dembicki {
127895711cd5SPawel Dembicki 	const struct vsc73xx_counter *cnts;
127995711cd5SPawel Dembicki 	int num_cnts;
128095711cd5SPawel Dembicki 	int i;
128195711cd5SPawel Dembicki 
128295711cd5SPawel Dembicki 	if (tx) {
128395711cd5SPawel Dembicki 		cnts = vsc73xx_tx_counters;
128495711cd5SPawel Dembicki 		num_cnts = ARRAY_SIZE(vsc73xx_tx_counters);
128595711cd5SPawel Dembicki 	} else {
128695711cd5SPawel Dembicki 		cnts = vsc73xx_rx_counters;
128795711cd5SPawel Dembicki 		num_cnts = ARRAY_SIZE(vsc73xx_rx_counters);
128895711cd5SPawel Dembicki 	}
128995711cd5SPawel Dembicki 
129095711cd5SPawel Dembicki 	for (i = 0; i < num_cnts; i++) {
129195711cd5SPawel Dembicki 		const struct vsc73xx_counter *cnt;
129295711cd5SPawel Dembicki 
129395711cd5SPawel Dembicki 		cnt = &cnts[i];
129495711cd5SPawel Dembicki 		if (cnt->counter == counter)
129595711cd5SPawel Dembicki 			return cnt;
129695711cd5SPawel Dembicki 	}
129795711cd5SPawel Dembicki 
129895711cd5SPawel Dembicki 	return NULL;
129995711cd5SPawel Dembicki }
130095711cd5SPawel Dembicki 
130195711cd5SPawel Dembicki static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset,
130295711cd5SPawel Dembicki 				uint8_t *data)
130395711cd5SPawel Dembicki {
130495711cd5SPawel Dembicki 	const struct vsc73xx_counter *cnt;
130595711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
130695711cd5SPawel Dembicki 	u8 indices[6];
1307e3bbab47SJustin Stitt 	u8 *buf = data;
1308e3bbab47SJustin Stitt 	int i;
130995711cd5SPawel Dembicki 	u32 val;
131095711cd5SPawel Dembicki 	int ret;
131195711cd5SPawel Dembicki 
131295711cd5SPawel Dembicki 	if (stringset != ETH_SS_STATS)
131395711cd5SPawel Dembicki 		return;
131495711cd5SPawel Dembicki 
131595711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MAC, port,
131695711cd5SPawel Dembicki 			   VSC73XX_C_CFG, &val);
131795711cd5SPawel Dembicki 	if (ret)
131895711cd5SPawel Dembicki 		return;
131995711cd5SPawel Dembicki 
132095711cd5SPawel Dembicki 	indices[0] = (val & 0x1f); /* RX counter 0 */
132195711cd5SPawel Dembicki 	indices[1] = ((val >> 5) & 0x1f); /* RX counter 1 */
132295711cd5SPawel Dembicki 	indices[2] = ((val >> 10) & 0x1f); /* RX counter 2 */
132395711cd5SPawel Dembicki 	indices[3] = ((val >> 16) & 0x1f); /* TX counter 0 */
132495711cd5SPawel Dembicki 	indices[4] = ((val >> 21) & 0x1f); /* TX counter 1 */
132595711cd5SPawel Dembicki 	indices[5] = ((val >> 26) & 0x1f); /* TX counter 2 */
132695711cd5SPawel Dembicki 
132795711cd5SPawel Dembicki 	/* The first counters is the RX octets */
1328e403cfffSjustinstitt@google.com 	ethtool_puts(&buf, "RxEtherStatsOctets");
132995711cd5SPawel Dembicki 
133095711cd5SPawel Dembicki 	/* Each port supports recording 3 RX counters and 3 TX counters,
133195711cd5SPawel Dembicki 	 * figure out what counters we use in this set-up and return the
133295711cd5SPawel Dembicki 	 * names of them. The hardware default counters will be number of
133395711cd5SPawel Dembicki 	 * packets on RX/TX, combined broadcast+multicast packets RX/TX and
133495711cd5SPawel Dembicki 	 * total error packets RX/TX.
133595711cd5SPawel Dembicki 	 */
133695711cd5SPawel Dembicki 	for (i = 0; i < 3; i++) {
133795711cd5SPawel Dembicki 		cnt = vsc73xx_find_counter(vsc, indices[i], false);
1338e403cfffSjustinstitt@google.com 		ethtool_puts(&buf, cnt ? cnt->name : "");
133995711cd5SPawel Dembicki 	}
134095711cd5SPawel Dembicki 
134195711cd5SPawel Dembicki 	/* TX stats begins with the number of TX octets */
1342e403cfffSjustinstitt@google.com 	ethtool_puts(&buf, "TxEtherStatsOctets");
134395711cd5SPawel Dembicki 
134495711cd5SPawel Dembicki 	for (i = 3; i < 6; i++) {
134595711cd5SPawel Dembicki 		cnt = vsc73xx_find_counter(vsc, indices[i], true);
1346e403cfffSjustinstitt@google.com 		ethtool_puts(&buf, cnt ? cnt->name : "");
1347e3bbab47SJustin Stitt 
134895711cd5SPawel Dembicki 	}
134995711cd5SPawel Dembicki }
135095711cd5SPawel Dembicki 
135195711cd5SPawel Dembicki static int vsc73xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
135295711cd5SPawel Dembicki {
135395711cd5SPawel Dembicki 	/* We only support SS_STATS */
135495711cd5SPawel Dembicki 	if (sset != ETH_SS_STATS)
135595711cd5SPawel Dembicki 		return 0;
135695711cd5SPawel Dembicki 	/* RX and TX packets, then 3 RX counters, 3 TX counters */
135795711cd5SPawel Dembicki 	return 8;
135895711cd5SPawel Dembicki }
135995711cd5SPawel Dembicki 
136095711cd5SPawel Dembicki static void vsc73xx_get_ethtool_stats(struct dsa_switch *ds, int port,
136195711cd5SPawel Dembicki 				      uint64_t *data)
136295711cd5SPawel Dembicki {
136395711cd5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
136495711cd5SPawel Dembicki 	u8 regs[] = {
136595711cd5SPawel Dembicki 		VSC73XX_RXOCT,
136695711cd5SPawel Dembicki 		VSC73XX_C_RX0,
136795711cd5SPawel Dembicki 		VSC73XX_C_RX1,
136895711cd5SPawel Dembicki 		VSC73XX_C_RX2,
136995711cd5SPawel Dembicki 		VSC73XX_TXOCT,
137095711cd5SPawel Dembicki 		VSC73XX_C_TX0,
137195711cd5SPawel Dembicki 		VSC73XX_C_TX1,
137295711cd5SPawel Dembicki 		VSC73XX_C_TX2,
137395711cd5SPawel Dembicki 	};
137495711cd5SPawel Dembicki 	u32 val;
137595711cd5SPawel Dembicki 	int ret;
137695711cd5SPawel Dembicki 	int i;
137795711cd5SPawel Dembicki 
137895711cd5SPawel Dembicki 	for (i = 0; i < ARRAY_SIZE(regs); i++) {
137995711cd5SPawel Dembicki 		ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MAC, port,
138095711cd5SPawel Dembicki 				   regs[i], &val);
138195711cd5SPawel Dembicki 		if (ret) {
138295711cd5SPawel Dembicki 			dev_err(vsc->dev, "error reading counter %d\n", i);
138395711cd5SPawel Dembicki 			return;
138495711cd5SPawel Dembicki 		}
138595711cd5SPawel Dembicki 		data[i] = val;
138695711cd5SPawel Dembicki 	}
138795711cd5SPawel Dembicki }
138895711cd5SPawel Dembicki 
1389fb77ffc6SVladimir Oltean static int vsc73xx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
1390fb77ffc6SVladimir Oltean {
1391fb77ffc6SVladimir Oltean 	struct vsc73xx *vsc = ds->priv;
1392fb77ffc6SVladimir Oltean 
1393fb77ffc6SVladimir Oltean 	return vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
13943cf62c81SPawel Dembicki 			     VSC73XX_MAXLEN, new_mtu + ETH_HLEN + ETH_FCS_LEN);
1395fb77ffc6SVladimir Oltean }
1396fb77ffc6SVladimir Oltean 
1397fb77ffc6SVladimir Oltean /* According to application not "VSC7398 Jumbo Frames" setting
13983cf62c81SPawel Dembicki  * up the frame size to 9.6 KB does not affect the performance on standard
1399fb77ffc6SVladimir Oltean  * frames. It is clear from the application note that
1400fb77ffc6SVladimir Oltean  * "9.6 kilobytes" == 9600 bytes.
1401fb77ffc6SVladimir Oltean  */
1402fb77ffc6SVladimir Oltean static int vsc73xx_get_max_mtu(struct dsa_switch *ds, int port)
1403fb77ffc6SVladimir Oltean {
14043cf62c81SPawel Dembicki 	return 9600 - ETH_HLEN - ETH_FCS_LEN;
1405fb77ffc6SVladimir Oltean }
1406fb77ffc6SVladimir Oltean 
1407a026809cSRussell King (Oracle) static void vsc73xx_phylink_get_caps(struct dsa_switch *dsa, int port,
1408a026809cSRussell King (Oracle) 				     struct phylink_config *config)
1409a026809cSRussell King (Oracle) {
1410a026809cSRussell King (Oracle) 	unsigned long *interfaces = config->supported_interfaces;
1411a026809cSRussell King (Oracle) 
1412a026809cSRussell King (Oracle) 	if (port == 5)
1413a026809cSRussell King (Oracle) 		return;
1414a026809cSRussell King (Oracle) 
1415a026809cSRussell King (Oracle) 	if (port == CPU_PORT) {
1416a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_MII, interfaces);
1417a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_REVMII, interfaces);
1418a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
1419a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_RGMII, interfaces);
1420a026809cSRussell King (Oracle) 	}
1421a026809cSRussell King (Oracle) 
1422a026809cSRussell King (Oracle) 	if (port <= 4) {
1423a026809cSRussell King (Oracle) 		/* Internal PHYs */
1424a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);
1425a026809cSRussell King (Oracle) 		/* phylib default */
1426a026809cSRussell King (Oracle) 		__set_bit(PHY_INTERFACE_MODE_GMII, interfaces);
1427a026809cSRussell King (Oracle) 	}
1428a026809cSRussell King (Oracle) 
1429a026809cSRussell King (Oracle) 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000;
1430a026809cSRussell King (Oracle) }
1431a026809cSRussell King (Oracle) 
14326b783dedSPawel Dembicki static int
14336b783dedSPawel Dembicki vsc73xx_port_vlan_filtering(struct dsa_switch *ds, int port,
14346b783dedSPawel Dembicki 			    bool vlan_filtering, struct netlink_ext_ack *extack)
14356b783dedSPawel Dembicki {
14366b783dedSPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
14376b783dedSPawel Dembicki 
14386b783dedSPawel Dembicki 	/* The commit to hardware processed below is required because vsc73xx
14396b783dedSPawel Dembicki 	 * is using tag_8021q. When vlan_filtering is disabled, tag_8021q uses
14406b783dedSPawel Dembicki 	 * pvid/untagged vlans for port recognition. The values configured for
14416b783dedSPawel Dembicki 	 * vlans and pvid/untagged states are stored in portinfo structure.
14426b783dedSPawel Dembicki 	 * When vlan_filtering is enabled, we need to restore pvid/untagged from
14436b783dedSPawel Dembicki 	 * portinfo structure. Analogous routine is processed when
14446b783dedSPawel Dembicki 	 * vlan_filtering is disabled, but values used for tag_8021q are
14456b783dedSPawel Dembicki 	 * restored.
14466b783dedSPawel Dembicki 	 */
14476b783dedSPawel Dembicki 
14486b783dedSPawel Dembicki 	return vsc73xx_vlan_commit_settings(vsc, port);
14496b783dedSPawel Dembicki }
14506b783dedSPawel Dembicki 
14516b783dedSPawel Dembicki static int vsc73xx_port_vlan_add(struct dsa_switch *ds, int port,
14526b783dedSPawel Dembicki 				 const struct switchdev_obj_port_vlan *vlan,
14536b783dedSPawel Dembicki 				 struct netlink_ext_ack *extack)
14546b783dedSPawel Dembicki {
14556b783dedSPawel Dembicki 	bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
14566b783dedSPawel Dembicki 	bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
14576b783dedSPawel Dembicki 	struct dsa_port *dp = dsa_to_port(ds, port);
14586b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vsc73xx_vlan;
14596b783dedSPawel Dembicki 	struct vsc73xx_vlan_summary summary;
14606b783dedSPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
14616b783dedSPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
14626b783dedSPawel Dembicki 	bool commit_to_hardware;
14636b783dedSPawel Dembicki 	int ret = 0;
14646b783dedSPawel Dembicki 
14656b783dedSPawel Dembicki 	/* Be sure to deny alterations to the configuration done by tag_8021q.
14666b783dedSPawel Dembicki 	 */
14676b783dedSPawel Dembicki 	if (vid_is_dsa_8021q(vlan->vid)) {
14686b783dedSPawel Dembicki 		NL_SET_ERR_MSG_MOD(extack,
14696b783dedSPawel Dembicki 				   "Range 3072-4095 reserved for dsa_8021q operation");
14706b783dedSPawel Dembicki 		return -EBUSY;
14716b783dedSPawel Dembicki 	}
14726b783dedSPawel Dembicki 
14736b783dedSPawel Dembicki 	/* The processed vlan->vid is excluded from the search because the VLAN
14746b783dedSPawel Dembicki 	 * can be re-added with a different set of flags, so it's easiest to
14756b783dedSPawel Dembicki 	 * ignore its old flags from the VLAN database software copy.
14766b783dedSPawel Dembicki 	 */
14776b783dedSPawel Dembicki 	vsc73xx_bridge_vlan_summary(vsc, port, &summary, vlan->vid);
14786b783dedSPawel Dembicki 
14796b783dedSPawel Dembicki 	/* VSC73XX allows only three untagged states: none, one or all */
14806b783dedSPawel Dembicki 	if ((untagged && summary.num_tagged > 0 && summary.num_untagged > 0) ||
14816b783dedSPawel Dembicki 	    (!untagged && summary.num_untagged > 1)) {
14826b783dedSPawel Dembicki 		NL_SET_ERR_MSG_MOD(extack,
14836b783dedSPawel Dembicki 				   "Port can have only none, one or all untagged vlan");
14846b783dedSPawel Dembicki 		return -EBUSY;
14856b783dedSPawel Dembicki 	}
14866b783dedSPawel Dembicki 
14876b783dedSPawel Dembicki 	vsc73xx_vlan = vsc73xx_bridge_vlan_find(vsc, vlan->vid);
14886b783dedSPawel Dembicki 
14896b783dedSPawel Dembicki 	if (!vsc73xx_vlan) {
14906b783dedSPawel Dembicki 		vsc73xx_vlan = kzalloc(sizeof(*vsc73xx_vlan), GFP_KERNEL);
14916b783dedSPawel Dembicki 		if (!vsc73xx_vlan)
14926b783dedSPawel Dembicki 			return -ENOMEM;
14936b783dedSPawel Dembicki 
14946b783dedSPawel Dembicki 		vsc73xx_vlan->vid = vlan->vid;
14956b783dedSPawel Dembicki 
14966b783dedSPawel Dembicki 		list_add_tail(&vsc73xx_vlan->list, &vsc->vlans);
14976b783dedSPawel Dembicki 	}
14986b783dedSPawel Dembicki 
14996b783dedSPawel Dembicki 	vsc73xx_vlan->portmask |= BIT(port);
15006b783dedSPawel Dembicki 
15016b783dedSPawel Dembicki 	/* CPU port must be always tagged because source port identification is
15026b783dedSPawel Dembicki 	 * based on tag_8021q.
15036b783dedSPawel Dembicki 	 */
15046b783dedSPawel Dembicki 	if (port == CPU_PORT)
15056b783dedSPawel Dembicki 		goto update_vlan_table;
15066b783dedSPawel Dembicki 
15076b783dedSPawel Dembicki 	if (untagged)
15086b783dedSPawel Dembicki 		vsc73xx_vlan->untagged |= BIT(port);
15096b783dedSPawel Dembicki 	else
15106b783dedSPawel Dembicki 		vsc73xx_vlan->untagged &= ~BIT(port);
15116b783dedSPawel Dembicki 
15126b783dedSPawel Dembicki 	portinfo = &vsc->portinfo[port];
15136b783dedSPawel Dembicki 
15146b783dedSPawel Dembicki 	if (pvid) {
15156b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering_configured = true;
15166b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering = vlan->vid;
15176b783dedSPawel Dembicki 	} else if (portinfo->pvid_vlan_filtering_configured &&
15186b783dedSPawel Dembicki 		   portinfo->pvid_vlan_filtering == vlan->vid) {
15196b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering_configured = false;
15206b783dedSPawel Dembicki 	}
15216b783dedSPawel Dembicki 
15226b783dedSPawel Dembicki 	commit_to_hardware = !vsc73xx_tag_8021q_active(dp);
15236b783dedSPawel Dembicki 	if (commit_to_hardware) {
15246b783dedSPawel Dembicki 		ret = vsc73xx_vlan_commit_settings(vsc, port);
15256b783dedSPawel Dembicki 		if (ret)
15266b783dedSPawel Dembicki 			goto err;
15276b783dedSPawel Dembicki 	}
15286b783dedSPawel Dembicki 
15296b783dedSPawel Dembicki update_vlan_table:
15306b783dedSPawel Dembicki 	ret = vsc73xx_update_vlan_table(vsc, port, vlan->vid, true);
15316b783dedSPawel Dembicki 	if (!ret)
15326b783dedSPawel Dembicki 		return 0;
15336b783dedSPawel Dembicki err:
15346b783dedSPawel Dembicki 	vsc73xx_bridge_vlan_remove_port(vsc73xx_vlan, port);
15356b783dedSPawel Dembicki 	return ret;
15366b783dedSPawel Dembicki }
15376b783dedSPawel Dembicki 
15386b783dedSPawel Dembicki static int vsc73xx_port_vlan_del(struct dsa_switch *ds, int port,
15396b783dedSPawel Dembicki 				 const struct switchdev_obj_port_vlan *vlan)
15406b783dedSPawel Dembicki {
15416b783dedSPawel Dembicki 	struct vsc73xx_bridge_vlan *vsc73xx_vlan;
15426b783dedSPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
15436b783dedSPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
15446b783dedSPawel Dembicki 	bool commit_to_hardware;
15456b783dedSPawel Dembicki 	int ret;
15466b783dedSPawel Dembicki 
15476b783dedSPawel Dembicki 	ret = vsc73xx_update_vlan_table(vsc, port, vlan->vid, false);
15486b783dedSPawel Dembicki 	if (ret)
15496b783dedSPawel Dembicki 		return ret;
15506b783dedSPawel Dembicki 
15516b783dedSPawel Dembicki 	portinfo = &vsc->portinfo[port];
15526b783dedSPawel Dembicki 
15536b783dedSPawel Dembicki 	if (portinfo->pvid_vlan_filtering_configured &&
15546b783dedSPawel Dembicki 	    portinfo->pvid_vlan_filtering == vlan->vid)
15556b783dedSPawel Dembicki 		portinfo->pvid_vlan_filtering_configured = false;
15566b783dedSPawel Dembicki 
15576b783dedSPawel Dembicki 	vsc73xx_vlan = vsc73xx_bridge_vlan_find(vsc, vlan->vid);
15586b783dedSPawel Dembicki 
15596b783dedSPawel Dembicki 	if (vsc73xx_vlan)
15606b783dedSPawel Dembicki 		vsc73xx_bridge_vlan_remove_port(vsc73xx_vlan, port);
15616b783dedSPawel Dembicki 
15626b783dedSPawel Dembicki 	commit_to_hardware = !vsc73xx_tag_8021q_active(dsa_to_port(ds, port));
1563*e3386ec4SPawel Dembicki 
15646b783dedSPawel Dembicki 	if (commit_to_hardware)
15656b783dedSPawel Dembicki 		return vsc73xx_vlan_commit_settings(vsc, port);
15666b783dedSPawel Dembicki 
15676b783dedSPawel Dembicki 	return 0;
15686b783dedSPawel Dembicki }
15696b783dedSPawel Dembicki 
1570*e3386ec4SPawel Dembicki static int vsc73xx_tag_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
1571*e3386ec4SPawel Dembicki 				      u16 flags)
1572*e3386ec4SPawel Dembicki {
1573*e3386ec4SPawel Dembicki 	bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
1574*e3386ec4SPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
1575*e3386ec4SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
1576*e3386ec4SPawel Dembicki 	bool commit_to_hardware;
1577*e3386ec4SPawel Dembicki 	int ret;
1578*e3386ec4SPawel Dembicki 
1579*e3386ec4SPawel Dembicki 	portinfo = &vsc->portinfo[port];
1580*e3386ec4SPawel Dembicki 
1581*e3386ec4SPawel Dembicki 	if (pvid) {
1582*e3386ec4SPawel Dembicki 		portinfo->pvid_tag_8021q_configured = true;
1583*e3386ec4SPawel Dembicki 		portinfo->pvid_tag_8021q = vid;
1584*e3386ec4SPawel Dembicki 	}
1585*e3386ec4SPawel Dembicki 
1586*e3386ec4SPawel Dembicki 	commit_to_hardware = vsc73xx_tag_8021q_active(dsa_to_port(ds, port));
1587*e3386ec4SPawel Dembicki 	if (commit_to_hardware) {
1588*e3386ec4SPawel Dembicki 		ret = vsc73xx_vlan_commit_settings(vsc, port);
1589*e3386ec4SPawel Dembicki 		if (ret)
1590*e3386ec4SPawel Dembicki 			return ret;
1591*e3386ec4SPawel Dembicki 	}
1592*e3386ec4SPawel Dembicki 
1593*e3386ec4SPawel Dembicki 	return vsc73xx_update_vlan_table(vsc, port, vid, true);
1594*e3386ec4SPawel Dembicki }
1595*e3386ec4SPawel Dembicki 
1596*e3386ec4SPawel Dembicki static int vsc73xx_tag_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
1597*e3386ec4SPawel Dembicki {
1598*e3386ec4SPawel Dembicki 	struct vsc73xx_portinfo *portinfo;
1599*e3386ec4SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
1600*e3386ec4SPawel Dembicki 
1601*e3386ec4SPawel Dembicki 	portinfo = &vsc->portinfo[port];
1602*e3386ec4SPawel Dembicki 
1603*e3386ec4SPawel Dembicki 	if (portinfo->pvid_tag_8021q_configured &&
1604*e3386ec4SPawel Dembicki 	    portinfo->pvid_tag_8021q == vid) {
1605*e3386ec4SPawel Dembicki 		struct dsa_port *dp = dsa_to_port(ds, port);
1606*e3386ec4SPawel Dembicki 		bool commit_to_hardware;
1607*e3386ec4SPawel Dembicki 		int err;
1608*e3386ec4SPawel Dembicki 
1609*e3386ec4SPawel Dembicki 		portinfo->pvid_tag_8021q_configured = false;
1610*e3386ec4SPawel Dembicki 
1611*e3386ec4SPawel Dembicki 		commit_to_hardware = vsc73xx_tag_8021q_active(dp);
1612*e3386ec4SPawel Dembicki 		if (commit_to_hardware) {
1613*e3386ec4SPawel Dembicki 			err = vsc73xx_vlan_commit_settings(vsc, port);
1614*e3386ec4SPawel Dembicki 			if (err)
1615*e3386ec4SPawel Dembicki 				return err;
1616*e3386ec4SPawel Dembicki 		}
1617*e3386ec4SPawel Dembicki 	}
1618*e3386ec4SPawel Dembicki 
1619*e3386ec4SPawel Dembicki 	return vsc73xx_update_vlan_table(vsc, port, vid, false);
1620*e3386ec4SPawel Dembicki }
1621*e3386ec4SPawel Dembicki 
16221e5b23e5SPawel Dembicki static void vsc73xx_refresh_fwd_map(struct dsa_switch *ds, int port, u8 state)
16231e5b23e5SPawel Dembicki {
16241e5b23e5SPawel Dembicki 	struct dsa_port *other_dp, *dp = dsa_to_port(ds, port);
16251e5b23e5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
16261e5b23e5SPawel Dembicki 	u16 mask;
16271e5b23e5SPawel Dembicki 
16281e5b23e5SPawel Dembicki 	if (state != BR_STATE_FORWARDING) {
16291e5b23e5SPawel Dembicki 		/* Ports that aren't in the forwarding state must not
16301e5b23e5SPawel Dembicki 		 * forward packets anywhere.
16311e5b23e5SPawel Dembicki 		 */
16321e5b23e5SPawel Dembicki 		vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16331e5b23e5SPawel Dembicki 				    VSC73XX_SRCMASKS + port,
16341e5b23e5SPawel Dembicki 				    VSC73XX_SRCMASKS_PORTS_MASK, 0);
16351e5b23e5SPawel Dembicki 
16361e5b23e5SPawel Dembicki 		dsa_switch_for_each_available_port(other_dp, ds) {
16371e5b23e5SPawel Dembicki 			if (other_dp == dp)
16381e5b23e5SPawel Dembicki 				continue;
16391e5b23e5SPawel Dembicki 			vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16401e5b23e5SPawel Dembicki 					    VSC73XX_SRCMASKS + other_dp->index,
16411e5b23e5SPawel Dembicki 					    BIT(port), 0);
16421e5b23e5SPawel Dembicki 		}
16431e5b23e5SPawel Dembicki 
16441e5b23e5SPawel Dembicki 		return;
16451e5b23e5SPawel Dembicki 	}
16461e5b23e5SPawel Dembicki 
16471e5b23e5SPawel Dembicki 	/* Forwarding ports must forward to the CPU and to other ports
16481e5b23e5SPawel Dembicki 	 * in the same bridge
16491e5b23e5SPawel Dembicki 	 */
16501e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16511e5b23e5SPawel Dembicki 			    VSC73XX_SRCMASKS + CPU_PORT, BIT(port), BIT(port));
16521e5b23e5SPawel Dembicki 
16531e5b23e5SPawel Dembicki 	mask = BIT(CPU_PORT);
16541e5b23e5SPawel Dembicki 
16551e5b23e5SPawel Dembicki 	dsa_switch_for_each_user_port(other_dp, ds) {
16561e5b23e5SPawel Dembicki 		int other_port = other_dp->index;
16571e5b23e5SPawel Dembicki 
16581e5b23e5SPawel Dembicki 		if (port == other_port || !dsa_port_bridge_same(dp, other_dp) ||
16591e5b23e5SPawel Dembicki 		    other_dp->stp_state != BR_STATE_FORWARDING)
16601e5b23e5SPawel Dembicki 			continue;
16611e5b23e5SPawel Dembicki 
16621e5b23e5SPawel Dembicki 		mask |= BIT(other_port);
16631e5b23e5SPawel Dembicki 
16641e5b23e5SPawel Dembicki 		vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16651e5b23e5SPawel Dembicki 				    VSC73XX_SRCMASKS + other_port,
16661e5b23e5SPawel Dembicki 				    BIT(port), BIT(port));
16671e5b23e5SPawel Dembicki 	}
16681e5b23e5SPawel Dembicki 
16691e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16701e5b23e5SPawel Dembicki 			    VSC73XX_SRCMASKS + port,
16711e5b23e5SPawel Dembicki 			    VSC73XX_SRCMASKS_PORTS_MASK, mask);
16721e5b23e5SPawel Dembicki }
16731e5b23e5SPawel Dembicki 
16741e5b23e5SPawel Dembicki /* FIXME: STP frames aren't forwarded at this moment. BPDU frames are
16751e5b23e5SPawel Dembicki  * forwarded only from and to PI/SI interface. For more info see chapter
16761e5b23e5SPawel Dembicki  * 2.7.1 (CPU Forwarding) in datasheet.
16771e5b23e5SPawel Dembicki  * This function is required for tag_8021q operations.
16781e5b23e5SPawel Dembicki  */
16791e5b23e5SPawel Dembicki static void vsc73xx_port_stp_state_set(struct dsa_switch *ds, int port,
16801e5b23e5SPawel Dembicki 				       u8 state)
16811e5b23e5SPawel Dembicki {
16821e5b23e5SPawel Dembicki 	struct vsc73xx *vsc = ds->priv;
16831e5b23e5SPawel Dembicki 	u32 val;
16841e5b23e5SPawel Dembicki 
16851e5b23e5SPawel Dembicki 	val = (state == BR_STATE_BLOCKING || state == BR_STATE_DISABLED) ?
16861e5b23e5SPawel Dembicki 	      0 : BIT(port);
16871e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16881e5b23e5SPawel Dembicki 			    VSC73XX_RECVMASK, BIT(port), val);
16891e5b23e5SPawel Dembicki 
16901e5b23e5SPawel Dembicki 	val = (state == BR_STATE_LEARNING || state == BR_STATE_FORWARDING) ?
16911e5b23e5SPawel Dembicki 	      BIT(port) : 0;
16921e5b23e5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
16931e5b23e5SPawel Dembicki 			    VSC73XX_LEARNMASK, BIT(port), val);
16941e5b23e5SPawel Dembicki 
16951e5b23e5SPawel Dembicki 	/* CPU Port should always forward packets when user ports are forwarding
16961e5b23e5SPawel Dembicki 	 * so let's configure it from other ports only.
16971e5b23e5SPawel Dembicki 	 */
16981e5b23e5SPawel Dembicki 	if (port != CPU_PORT)
16991e5b23e5SPawel Dembicki 		vsc73xx_refresh_fwd_map(ds, port, state);
17001e5b23e5SPawel Dembicki }
17011e5b23e5SPawel Dembicki 
170221fc3416SPawel Dembicki static const struct phylink_mac_ops vsc73xx_phylink_mac_ops = {
170321fc3416SPawel Dembicki 	.mac_config = vsc73xx_mac_config,
170421fc3416SPawel Dembicki 	.mac_link_down = vsc73xx_mac_link_down,
170521fc3416SPawel Dembicki 	.mac_link_up = vsc73xx_mac_link_up,
170621fc3416SPawel Dembicki };
170721fc3416SPawel Dembicki 
170895711cd5SPawel Dembicki static const struct dsa_switch_ops vsc73xx_ds_ops = {
170995711cd5SPawel Dembicki 	.get_tag_protocol = vsc73xx_get_tag_protocol,
171095711cd5SPawel Dembicki 	.setup = vsc73xx_setup,
1711*e3386ec4SPawel Dembicki 	.teardown = vsc73xx_teardown,
171295711cd5SPawel Dembicki 	.phy_read = vsc73xx_phy_read,
171395711cd5SPawel Dembicki 	.phy_write = vsc73xx_phy_write,
171495711cd5SPawel Dembicki 	.get_strings = vsc73xx_get_strings,
171595711cd5SPawel Dembicki 	.get_ethtool_stats = vsc73xx_get_ethtool_stats,
171695711cd5SPawel Dembicki 	.get_sset_count = vsc73xx_get_sset_count,
171795711cd5SPawel Dembicki 	.port_enable = vsc73xx_port_enable,
171895711cd5SPawel Dembicki 	.port_disable = vsc73xx_port_disable,
1719fb77ffc6SVladimir Oltean 	.port_change_mtu = vsc73xx_change_mtu,
1720fb77ffc6SVladimir Oltean 	.port_max_mtu = vsc73xx_get_max_mtu,
17211e5b23e5SPawel Dembicki 	.port_stp_state_set = vsc73xx_port_stp_state_set,
17226b783dedSPawel Dembicki 	.port_vlan_filtering = vsc73xx_port_vlan_filtering,
17236b783dedSPawel Dembicki 	.port_vlan_add = vsc73xx_port_vlan_add,
17246b783dedSPawel Dembicki 	.port_vlan_del = vsc73xx_port_vlan_del,
1725a026809cSRussell King (Oracle) 	.phylink_get_caps = vsc73xx_phylink_get_caps,
1726*e3386ec4SPawel Dembicki 	.tag_8021q_vlan_add = vsc73xx_tag_8021q_vlan_add,
1727*e3386ec4SPawel Dembicki 	.tag_8021q_vlan_del = vsc73xx_tag_8021q_vlan_del,
172895711cd5SPawel Dembicki };
172995711cd5SPawel Dembicki 
173095711cd5SPawel Dembicki static int vsc73xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
173195711cd5SPawel Dembicki {
173295711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
173395711cd5SPawel Dembicki 	u32 val;
173495711cd5SPawel Dembicki 	int ret;
173595711cd5SPawel Dembicki 
173695711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
173795711cd5SPawel Dembicki 			   VSC73XX_GPIO, &val);
173895711cd5SPawel Dembicki 	if (ret)
173995711cd5SPawel Dembicki 		return ret;
174095711cd5SPawel Dembicki 
174195711cd5SPawel Dembicki 	return !!(val & BIT(offset));
174295711cd5SPawel Dembicki }
174395711cd5SPawel Dembicki 
174495711cd5SPawel Dembicki static void vsc73xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
174595711cd5SPawel Dembicki 			     int val)
174695711cd5SPawel Dembicki {
174795711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
174895711cd5SPawel Dembicki 	u32 tmp = val ? BIT(offset) : 0;
174995711cd5SPawel Dembicki 
175095711cd5SPawel Dembicki 	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
175195711cd5SPawel Dembicki 			    VSC73XX_GPIO, BIT(offset), tmp);
175295711cd5SPawel Dembicki }
175395711cd5SPawel Dembicki 
175495711cd5SPawel Dembicki static int vsc73xx_gpio_direction_output(struct gpio_chip *chip,
175595711cd5SPawel Dembicki 					 unsigned int offset, int val)
175695711cd5SPawel Dembicki {
175795711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
175895711cd5SPawel Dembicki 	u32 tmp = val ? BIT(offset) : 0;
175995711cd5SPawel Dembicki 
176095711cd5SPawel Dembicki 	return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
176195711cd5SPawel Dembicki 				   VSC73XX_GPIO, BIT(offset + 4) | BIT(offset),
176295711cd5SPawel Dembicki 				   BIT(offset + 4) | tmp);
176395711cd5SPawel Dembicki }
176495711cd5SPawel Dembicki 
176595711cd5SPawel Dembicki static int vsc73xx_gpio_direction_input(struct gpio_chip *chip,
176695711cd5SPawel Dembicki 					unsigned int offset)
176795711cd5SPawel Dembicki {
176895711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
176995711cd5SPawel Dembicki 
177095711cd5SPawel Dembicki 	return  vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
177195711cd5SPawel Dembicki 				    VSC73XX_GPIO, BIT(offset + 4),
177295711cd5SPawel Dembicki 				    0);
177395711cd5SPawel Dembicki }
177495711cd5SPawel Dembicki 
177595711cd5SPawel Dembicki static int vsc73xx_gpio_get_direction(struct gpio_chip *chip,
177695711cd5SPawel Dembicki 				      unsigned int offset)
177795711cd5SPawel Dembicki {
177895711cd5SPawel Dembicki 	struct vsc73xx *vsc = gpiochip_get_data(chip);
177995711cd5SPawel Dembicki 	u32 val;
178095711cd5SPawel Dembicki 	int ret;
178195711cd5SPawel Dembicki 
178295711cd5SPawel Dembicki 	ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
178395711cd5SPawel Dembicki 			   VSC73XX_GPIO, &val);
178495711cd5SPawel Dembicki 	if (ret)
178595711cd5SPawel Dembicki 		return ret;
178695711cd5SPawel Dembicki 
178795711cd5SPawel Dembicki 	return !(val & BIT(offset + 4));
178895711cd5SPawel Dembicki }
178995711cd5SPawel Dembicki 
179095711cd5SPawel Dembicki static int vsc73xx_gpio_probe(struct vsc73xx *vsc)
179195711cd5SPawel Dembicki {
179295711cd5SPawel Dembicki 	int ret;
179395711cd5SPawel Dembicki 
179495711cd5SPawel Dembicki 	vsc->gc.label = devm_kasprintf(vsc->dev, GFP_KERNEL, "VSC%04x",
179595711cd5SPawel Dembicki 				       vsc->chipid);
1796776dac5aSKunwu Chan 	if (!vsc->gc.label)
1797776dac5aSKunwu Chan 		return -ENOMEM;
179895711cd5SPawel Dembicki 	vsc->gc.ngpio = 4;
179995711cd5SPawel Dembicki 	vsc->gc.owner = THIS_MODULE;
180095711cd5SPawel Dembicki 	vsc->gc.parent = vsc->dev;
180195711cd5SPawel Dembicki 	vsc->gc.base = -1;
180295711cd5SPawel Dembicki 	vsc->gc.get = vsc73xx_gpio_get;
180395711cd5SPawel Dembicki 	vsc->gc.set = vsc73xx_gpio_set;
180495711cd5SPawel Dembicki 	vsc->gc.direction_input = vsc73xx_gpio_direction_input;
180595711cd5SPawel Dembicki 	vsc->gc.direction_output = vsc73xx_gpio_direction_output;
180695711cd5SPawel Dembicki 	vsc->gc.get_direction = vsc73xx_gpio_get_direction;
180795711cd5SPawel Dembicki 	vsc->gc.can_sleep = true;
180895711cd5SPawel Dembicki 	ret = devm_gpiochip_add_data(vsc->dev, &vsc->gc, vsc);
180995711cd5SPawel Dembicki 	if (ret) {
181095711cd5SPawel Dembicki 		dev_err(vsc->dev, "unable to register GPIO chip\n");
181195711cd5SPawel Dembicki 		return ret;
181295711cd5SPawel Dembicki 	}
181395711cd5SPawel Dembicki 	return 0;
181495711cd5SPawel Dembicki }
181595711cd5SPawel Dembicki 
181695711cd5SPawel Dembicki int vsc73xx_probe(struct vsc73xx *vsc)
181795711cd5SPawel Dembicki {
181895711cd5SPawel Dembicki 	struct device *dev = vsc->dev;
181995711cd5SPawel Dembicki 	int ret;
182095711cd5SPawel Dembicki 
182195711cd5SPawel Dembicki 	/* Release reset, if any */
182295711cd5SPawel Dembicki 	vsc->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
182395711cd5SPawel Dembicki 	if (IS_ERR(vsc->reset)) {
182495711cd5SPawel Dembicki 		dev_err(dev, "failed to get RESET GPIO\n");
182595711cd5SPawel Dembicki 		return PTR_ERR(vsc->reset);
182695711cd5SPawel Dembicki 	}
182795711cd5SPawel Dembicki 	if (vsc->reset)
182895711cd5SPawel Dembicki 		/* Wait 20ms according to datasheet table 245 */
182995711cd5SPawel Dembicki 		msleep(20);
183095711cd5SPawel Dembicki 
183195711cd5SPawel Dembicki 	ret = vsc73xx_detect(vsc);
18321da39ff0SPawel Dembicki 	if (ret == -EAGAIN) {
18331da39ff0SPawel Dembicki 		dev_err(vsc->dev,
18341da39ff0SPawel Dembicki 			"Chip seems to be out of control. Assert reset and try again.\n");
18351da39ff0SPawel Dembicki 		gpiod_set_value_cansleep(vsc->reset, 1);
18361da39ff0SPawel Dembicki 		/* Reset pulse should be 20ns minimum, according to datasheet
18371da39ff0SPawel Dembicki 		 * table 245, so 10us should be fine
18381da39ff0SPawel Dembicki 		 */
18391da39ff0SPawel Dembicki 		usleep_range(10, 100);
18401da39ff0SPawel Dembicki 		gpiod_set_value_cansleep(vsc->reset, 0);
18411da39ff0SPawel Dembicki 		/* Wait 20ms according to datasheet table 245 */
18421da39ff0SPawel Dembicki 		msleep(20);
18431da39ff0SPawel Dembicki 		ret = vsc73xx_detect(vsc);
18441da39ff0SPawel Dembicki 	}
184595711cd5SPawel Dembicki 	if (ret) {
184695711cd5SPawel Dembicki 		dev_err(dev, "no chip found (%d)\n", ret);
184795711cd5SPawel Dembicki 		return -ENODEV;
184895711cd5SPawel Dembicki 	}
184995711cd5SPawel Dembicki 
185095711cd5SPawel Dembicki 	eth_random_addr(vsc->addr);
185195711cd5SPawel Dembicki 	dev_info(vsc->dev,
185295711cd5SPawel Dembicki 		 "MAC for control frames: %02X:%02X:%02X:%02X:%02X:%02X\n",
185395711cd5SPawel Dembicki 		 vsc->addr[0], vsc->addr[1], vsc->addr[2],
185495711cd5SPawel Dembicki 		 vsc->addr[3], vsc->addr[4], vsc->addr[5]);
185595711cd5SPawel Dembicki 
18567e99e347SVivien Didelot 	vsc->ds = devm_kzalloc(dev, sizeof(*vsc->ds), GFP_KERNEL);
185795711cd5SPawel Dembicki 	if (!vsc->ds)
185895711cd5SPawel Dembicki 		return -ENOMEM;
18597e99e347SVivien Didelot 
18607e99e347SVivien Didelot 	vsc->ds->dev = dev;
18616cc5280aSPawel Dembicki 	vsc->ds->num_ports = VSC73XX_MAX_NUM_PORTS;
186295711cd5SPawel Dembicki 	vsc->ds->priv = vsc;
186395711cd5SPawel Dembicki 
186495711cd5SPawel Dembicki 	vsc->ds->ops = &vsc73xx_ds_ops;
186521fc3416SPawel Dembicki 	vsc->ds->phylink_mac_ops = &vsc73xx_phylink_mac_ops;
186695711cd5SPawel Dembicki 	ret = dsa_register_switch(vsc->ds);
186795711cd5SPawel Dembicki 	if (ret) {
186895711cd5SPawel Dembicki 		dev_err(dev, "unable to register switch (%d)\n", ret);
186995711cd5SPawel Dembicki 		return ret;
187095711cd5SPawel Dembicki 	}
187195711cd5SPawel Dembicki 
187295711cd5SPawel Dembicki 	ret = vsc73xx_gpio_probe(vsc);
187395711cd5SPawel Dembicki 	if (ret) {
187495711cd5SPawel Dembicki 		dsa_unregister_switch(vsc->ds);
187595711cd5SPawel Dembicki 		return ret;
187695711cd5SPawel Dembicki 	}
187795711cd5SPawel Dembicki 
187895711cd5SPawel Dembicki 	return 0;
187995711cd5SPawel Dembicki }
188095711cd5SPawel Dembicki EXPORT_SYMBOL(vsc73xx_probe);
188195711cd5SPawel Dembicki 
1882e99fa423SUwe Kleine-König void vsc73xx_remove(struct vsc73xx *vsc)
188395711cd5SPawel Dembicki {
188495711cd5SPawel Dembicki 	dsa_unregister_switch(vsc->ds);
188595711cd5SPawel Dembicki 	gpiod_set_value(vsc->reset, 1);
188695711cd5SPawel Dembicki }
188795711cd5SPawel Dembicki EXPORT_SYMBOL(vsc73xx_remove);
188895711cd5SPawel Dembicki 
18890650bf52SVladimir Oltean void vsc73xx_shutdown(struct vsc73xx *vsc)
18900650bf52SVladimir Oltean {
18910650bf52SVladimir Oltean 	dsa_switch_shutdown(vsc->ds);
18920650bf52SVladimir Oltean }
18930650bf52SVladimir Oltean EXPORT_SYMBOL(vsc73xx_shutdown);
18940650bf52SVladimir Oltean 
189595711cd5SPawel Dembicki MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
189695711cd5SPawel Dembicki MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 driver");
189795711cd5SPawel Dembicki MODULE_LICENSE("GPL v2");
1898