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