1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* DSA driver for:
3*4882a593Smuzhiyun * Vitesse VSC7385 SparX-G5 5+1-port Integrated Gigabit Ethernet Switch
4*4882a593Smuzhiyun * Vitesse VSC7388 SparX-G8 8-port Integrated Gigabit Ethernet Switch
5*4882a593Smuzhiyun * Vitesse VSC7395 SparX-G5e 5+1-port Integrated Gigabit Ethernet Switch
6*4882a593Smuzhiyun * Vitesse VSC7398 SparX-G8e 8-port Integrated Gigabit Ethernet Switch
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * These switches have a built-in 8051 CPU and can download and execute a
9*4882a593Smuzhiyun * firmware in this CPU. They can also be configured to use an external CPU
10*4882a593Smuzhiyun * handling the switch in a memory-mapped manner by connecting to that external
11*4882a593Smuzhiyun * CPU's memory bus.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * Copyright (C) 2018 Linus Wallej <linus.walleij@linaro.org>
14*4882a593Smuzhiyun * Includes portions of code from the firmware uploader by:
15*4882a593Smuzhiyun * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
16*4882a593Smuzhiyun */
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/device.h>
20*4882a593Smuzhiyun #include <linux/of.h>
21*4882a593Smuzhiyun #include <linux/of_device.h>
22*4882a593Smuzhiyun #include <linux/of_mdio.h>
23*4882a593Smuzhiyun #include <linux/bitops.h>
24*4882a593Smuzhiyun #include <linux/if_bridge.h>
25*4882a593Smuzhiyun #include <linux/etherdevice.h>
26*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
27*4882a593Smuzhiyun #include <linux/gpio/driver.h>
28*4882a593Smuzhiyun #include <linux/random.h>
29*4882a593Smuzhiyun #include <net/dsa.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include "vitesse-vsc73xx.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define VSC73XX_BLOCK_MAC 0x1 /* Subblocks 0-4, 6 (CPU port) */
34*4882a593Smuzhiyun #define VSC73XX_BLOCK_ANALYZER 0x2 /* Only subblock 0 */
35*4882a593Smuzhiyun #define VSC73XX_BLOCK_MII 0x3 /* Subblocks 0 and 1 */
36*4882a593Smuzhiyun #define VSC73XX_BLOCK_MEMINIT 0x3 /* Only subblock 2 */
37*4882a593Smuzhiyun #define VSC73XX_BLOCK_CAPTURE 0x4 /* Only subblock 2 */
38*4882a593Smuzhiyun #define VSC73XX_BLOCK_ARBITER 0x5 /* Only subblock 0 */
39*4882a593Smuzhiyun #define VSC73XX_BLOCK_SYSTEM 0x7 /* Only subblock 0 */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define CPU_PORT 6 /* CPU port */
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /* MAC Block registers */
44*4882a593Smuzhiyun #define VSC73XX_MAC_CFG 0x00
45*4882a593Smuzhiyun #define VSC73XX_MACHDXGAP 0x02
46*4882a593Smuzhiyun #define VSC73XX_FCCONF 0x04
47*4882a593Smuzhiyun #define VSC73XX_FCMACHI 0x08
48*4882a593Smuzhiyun #define VSC73XX_FCMACLO 0x0c
49*4882a593Smuzhiyun #define VSC73XX_MAXLEN 0x10
50*4882a593Smuzhiyun #define VSC73XX_ADVPORTM 0x19
51*4882a593Smuzhiyun #define VSC73XX_TXUPDCFG 0x24
52*4882a593Smuzhiyun #define VSC73XX_TXQ_SELECT_CFG 0x28
53*4882a593Smuzhiyun #define VSC73XX_RXOCT 0x50
54*4882a593Smuzhiyun #define VSC73XX_TXOCT 0x51
55*4882a593Smuzhiyun #define VSC73XX_C_RX0 0x52
56*4882a593Smuzhiyun #define VSC73XX_C_RX1 0x53
57*4882a593Smuzhiyun #define VSC73XX_C_RX2 0x54
58*4882a593Smuzhiyun #define VSC73XX_C_TX0 0x55
59*4882a593Smuzhiyun #define VSC73XX_C_TX1 0x56
60*4882a593Smuzhiyun #define VSC73XX_C_TX2 0x57
61*4882a593Smuzhiyun #define VSC73XX_C_CFG 0x58
62*4882a593Smuzhiyun #define VSC73XX_CAT_DROP 0x6e
63*4882a593Smuzhiyun #define VSC73XX_CAT_PR_MISC_L2 0x6f
64*4882a593Smuzhiyun #define VSC73XX_CAT_PR_USR_PRIO 0x75
65*4882a593Smuzhiyun #define VSC73XX_Q_MISC_CONF 0xdf
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* MAC_CFG register bits */
68*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_WEXC_DIS BIT(31)
69*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_PORT_RST BIT(29)
70*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_TX_EN BIT(28)
71*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_SEED_LOAD BIT(27)
72*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_SEED_MASK GENMASK(26, 19)
73*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_SEED_OFFSET 19
74*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_FDX BIT(18)
75*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_GIGA_MODE BIT(17)
76*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_RX_EN BIT(16)
77*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_VLAN_DBLAWR BIT(15)
78*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_VLAN_AWR BIT(14)
79*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_100_BASE_T BIT(13) /* Not in manual */
80*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_TX_IPG_MASK GENMASK(10, 6)
81*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_TX_IPG_OFFSET 6
82*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_TX_IPG_1000M (6 << VSC73XX_MAC_CFG_TX_IPG_OFFSET)
83*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_TX_IPG_100_10M (17 << VSC73XX_MAC_CFG_TX_IPG_OFFSET)
84*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_MAC_RX_RST BIT(5)
85*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_MAC_TX_RST BIT(4)
86*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_CLK_SEL_MASK GENMASK(2, 0)
87*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_CLK_SEL_OFFSET 0
88*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_CLK_SEL_1000M 1
89*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_CLK_SEL_100M 2
90*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_CLK_SEL_10M 3
91*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_CLK_SEL_EXT 4
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_1000M_F_PHY (VSC73XX_MAC_CFG_FDX | \
94*4882a593Smuzhiyun VSC73XX_MAC_CFG_GIGA_MODE | \
95*4882a593Smuzhiyun VSC73XX_MAC_CFG_TX_IPG_1000M | \
96*4882a593Smuzhiyun VSC73XX_MAC_CFG_CLK_SEL_EXT)
97*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_100_10M_F_PHY (VSC73XX_MAC_CFG_FDX | \
98*4882a593Smuzhiyun VSC73XX_MAC_CFG_TX_IPG_100_10M | \
99*4882a593Smuzhiyun VSC73XX_MAC_CFG_CLK_SEL_EXT)
100*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_100_10M_H_PHY (VSC73XX_MAC_CFG_TX_IPG_100_10M | \
101*4882a593Smuzhiyun VSC73XX_MAC_CFG_CLK_SEL_EXT)
102*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_1000M_F_RGMII (VSC73XX_MAC_CFG_FDX | \
103*4882a593Smuzhiyun VSC73XX_MAC_CFG_GIGA_MODE | \
104*4882a593Smuzhiyun VSC73XX_MAC_CFG_TX_IPG_1000M | \
105*4882a593Smuzhiyun VSC73XX_MAC_CFG_CLK_SEL_1000M)
106*4882a593Smuzhiyun #define VSC73XX_MAC_CFG_RESET (VSC73XX_MAC_CFG_PORT_RST | \
107*4882a593Smuzhiyun VSC73XX_MAC_CFG_MAC_RX_RST | \
108*4882a593Smuzhiyun VSC73XX_MAC_CFG_MAC_TX_RST)
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun /* Flow control register bits */
111*4882a593Smuzhiyun #define VSC73XX_FCCONF_ZERO_PAUSE_EN BIT(17)
112*4882a593Smuzhiyun #define VSC73XX_FCCONF_FLOW_CTRL_OBEY BIT(16)
113*4882a593Smuzhiyun #define VSC73XX_FCCONF_PAUSE_VAL_MASK GENMASK(15, 0)
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* ADVPORTM advanced port setup register bits */
116*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_IFG_PPM BIT(7)
117*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_EXC_COL_CONT BIT(6)
118*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_EXT_PORT BIT(5)
119*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_INV_GTX BIT(4)
120*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_ENA_GTX BIT(3)
121*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_DDR_MODE BIT(2)
122*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_IO_LOOPBACK BIT(1)
123*4882a593Smuzhiyun #define VSC73XX_ADVPORTM_HOST_LOOPBACK BIT(0)
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /* CAT_DROP categorizer frame dropping register bits */
126*4882a593Smuzhiyun #define VSC73XX_CAT_DROP_DROP_MC_SMAC_ENA BIT(6)
127*4882a593Smuzhiyun #define VSC73XX_CAT_DROP_FWD_CTRL_ENA BIT(4)
128*4882a593Smuzhiyun #define VSC73XX_CAT_DROP_FWD_PAUSE_ENA BIT(3)
129*4882a593Smuzhiyun #define VSC73XX_CAT_DROP_UNTAGGED_ENA BIT(2)
130*4882a593Smuzhiyun #define VSC73XX_CAT_DROP_TAGGED_ENA BIT(1)
131*4882a593Smuzhiyun #define VSC73XX_CAT_DROP_NULL_MAC_ENA BIT(0)
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun #define VSC73XX_Q_MISC_CONF_EXTENT_MEM BIT(31)
134*4882a593Smuzhiyun #define VSC73XX_Q_MISC_CONF_EARLY_TX_MASK GENMASK(4, 1)
135*4882a593Smuzhiyun #define VSC73XX_Q_MISC_CONF_EARLY_TX_512 (1 << 1)
136*4882a593Smuzhiyun #define VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE BIT(0)
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* Frame analyzer block 2 registers */
139*4882a593Smuzhiyun #define VSC73XX_STORMLIMIT 0x02
140*4882a593Smuzhiyun #define VSC73XX_ADVLEARN 0x03
141*4882a593Smuzhiyun #define VSC73XX_IFLODMSK 0x04
142*4882a593Smuzhiyun #define VSC73XX_VLANMASK 0x05
143*4882a593Smuzhiyun #define VSC73XX_MACHDATA 0x06
144*4882a593Smuzhiyun #define VSC73XX_MACLDATA 0x07
145*4882a593Smuzhiyun #define VSC73XX_ANMOVED 0x08
146*4882a593Smuzhiyun #define VSC73XX_ANAGEFIL 0x09
147*4882a593Smuzhiyun #define VSC73XX_ANEVENTS 0x0a
148*4882a593Smuzhiyun #define VSC73XX_ANCNTMASK 0x0b
149*4882a593Smuzhiyun #define VSC73XX_ANCNTVAL 0x0c
150*4882a593Smuzhiyun #define VSC73XX_LEARNMASK 0x0d
151*4882a593Smuzhiyun #define VSC73XX_UFLODMASK 0x0e
152*4882a593Smuzhiyun #define VSC73XX_MFLODMASK 0x0f
153*4882a593Smuzhiyun #define VSC73XX_RECVMASK 0x10
154*4882a593Smuzhiyun #define VSC73XX_AGGRCTRL 0x20
155*4882a593Smuzhiyun #define VSC73XX_AGGRMSKS 0x30 /* Until 0x3f */
156*4882a593Smuzhiyun #define VSC73XX_DSTMASKS 0x40 /* Until 0x7f */
157*4882a593Smuzhiyun #define VSC73XX_SRCMASKS 0x80 /* Until 0x87 */
158*4882a593Smuzhiyun #define VSC73XX_CAPENAB 0xa0
159*4882a593Smuzhiyun #define VSC73XX_MACACCESS 0xb0
160*4882a593Smuzhiyun #define VSC73XX_IPMCACCESS 0xb1
161*4882a593Smuzhiyun #define VSC73XX_MACTINDX 0xc0
162*4882a593Smuzhiyun #define VSC73XX_VLANACCESS 0xd0
163*4882a593Smuzhiyun #define VSC73XX_VLANTIDX 0xe0
164*4882a593Smuzhiyun #define VSC73XX_AGENCTRL 0xf0
165*4882a593Smuzhiyun #define VSC73XX_CAPRST 0xff
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CPU_COPY BIT(14)
168*4882a593Smuzhiyun #define VSC73XX_MACACCESS_FWD_KILL BIT(13)
169*4882a593Smuzhiyun #define VSC73XX_MACACCESS_IGNORE_VLAN BIT(12)
170*4882a593Smuzhiyun #define VSC73XX_MACACCESS_AGED_FLAG BIT(11)
171*4882a593Smuzhiyun #define VSC73XX_MACACCESS_VALID BIT(10)
172*4882a593Smuzhiyun #define VSC73XX_MACACCESS_LOCKED BIT(9)
173*4882a593Smuzhiyun #define VSC73XX_MACACCESS_DEST_IDX_MASK GENMASK(8, 3)
174*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_MASK GENMASK(2, 0)
175*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_IDLE 0
176*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_LEARN 1
177*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_FORGET 2
178*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_AGE_TABLE 3
179*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_FLUSH_TABLE 4
180*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_CLEAR_TABLE 5
181*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_READ_ENTRY 6
182*4882a593Smuzhiyun #define VSC73XX_MACACCESS_CMD_WRITE_ENTRY 7
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_LEARN_DISABLED BIT(30)
185*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_MIRROR BIT(29)
186*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_SRC_CHECK BIT(28)
187*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_PORT_MASK GENMASK(9, 2)
188*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_MASK GENMASK(2, 0)
189*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_IDLE 0
190*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_READ_ENTRY 1
191*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_WRITE_ENTRY 2
192*4882a593Smuzhiyun #define VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE 3
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* MII block 3 registers */
195*4882a593Smuzhiyun #define VSC73XX_MII_STAT 0x0
196*4882a593Smuzhiyun #define VSC73XX_MII_CMD 0x1
197*4882a593Smuzhiyun #define VSC73XX_MII_DATA 0x2
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /* Arbiter block 5 registers */
200*4882a593Smuzhiyun #define VSC73XX_ARBEMPTY 0x0c
201*4882a593Smuzhiyun #define VSC73XX_ARBDISC 0x0e
202*4882a593Smuzhiyun #define VSC73XX_SBACKWDROP 0x12
203*4882a593Smuzhiyun #define VSC73XX_DBACKWDROP 0x13
204*4882a593Smuzhiyun #define VSC73XX_ARBBURSTPROB 0x15
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* System block 7 registers */
207*4882a593Smuzhiyun #define VSC73XX_ICPU_SIPAD 0x01
208*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY 0x05
209*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL 0x10
210*4882a593Smuzhiyun #define VSC73XX_ICPU_ADDR 0x11
211*4882a593Smuzhiyun #define VSC73XX_ICPU_SRAM 0x12
212*4882a593Smuzhiyun #define VSC73XX_HWSEM 0x13
213*4882a593Smuzhiyun #define VSC73XX_GLORESET 0x14
214*4882a593Smuzhiyun #define VSC73XX_ICPU_MBOX_VAL 0x15
215*4882a593Smuzhiyun #define VSC73XX_ICPU_MBOX_SET 0x16
216*4882a593Smuzhiyun #define VSC73XX_ICPU_MBOX_CLR 0x17
217*4882a593Smuzhiyun #define VSC73XX_CHIPID 0x18
218*4882a593Smuzhiyun #define VSC73XX_GPIO 0x34
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_NONE 0
221*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_4_NS 1
222*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_1_7_NS 2
223*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_GTXDELAY_2_0_NS 3
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_NONE (0 << 4)
226*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_4_NS (1 << 4)
227*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_1_7_NS (2 << 4)
228*4882a593Smuzhiyun #define VSC73XX_GMIIDELAY_GMII0_RXDELAY_2_0_NS (3 << 4)
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_WATCHDOG_RST BIT(31)
231*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_CLK_DIV_MASK GENMASK(12, 8)
232*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_SRST_HOLD BIT(7)
233*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_ICPU_PI_EN BIT(6)
234*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_BOOT_EN BIT(3)
235*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_EXT_ACC_EN BIT(2)
236*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_CLK_EN BIT(1)
237*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_SRST BIT(0)
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun #define VSC73XX_CHIPID_ID_SHIFT 12
240*4882a593Smuzhiyun #define VSC73XX_CHIPID_ID_MASK 0xffff
241*4882a593Smuzhiyun #define VSC73XX_CHIPID_REV_SHIFT 28
242*4882a593Smuzhiyun #define VSC73XX_CHIPID_REV_MASK 0xf
243*4882a593Smuzhiyun #define VSC73XX_CHIPID_ID_7385 0x7385
244*4882a593Smuzhiyun #define VSC73XX_CHIPID_ID_7388 0x7388
245*4882a593Smuzhiyun #define VSC73XX_CHIPID_ID_7395 0x7395
246*4882a593Smuzhiyun #define VSC73XX_CHIPID_ID_7398 0x7398
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun #define VSC73XX_GLORESET_STROBE BIT(4)
249*4882a593Smuzhiyun #define VSC73XX_GLORESET_ICPU_LOCK BIT(3)
250*4882a593Smuzhiyun #define VSC73XX_GLORESET_MEM_LOCK BIT(2)
251*4882a593Smuzhiyun #define VSC73XX_GLORESET_PHY_RESET BIT(1)
252*4882a593Smuzhiyun #define VSC73XX_GLORESET_MASTER_RESET BIT(0)
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun #define VSC7385_CLOCK_DELAY ((3 << 4) | 3)
255*4882a593Smuzhiyun #define VSC7385_CLOCK_DELAY_MASK ((3 << 4) | 3)
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_STOP (VSC73XX_ICPU_CTRL_SRST_HOLD | \
258*4882a593Smuzhiyun VSC73XX_ICPU_CTRL_BOOT_EN | \
259*4882a593Smuzhiyun VSC73XX_ICPU_CTRL_EXT_ACC_EN)
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun #define VSC73XX_ICPU_CTRL_START (VSC73XX_ICPU_CTRL_CLK_DIV | \
262*4882a593Smuzhiyun VSC73XX_ICPU_CTRL_BOOT_EN | \
263*4882a593Smuzhiyun VSC73XX_ICPU_CTRL_CLK_EN | \
264*4882a593Smuzhiyun VSC73XX_ICPU_CTRL_SRST)
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun #define IS_7385(a) ((a)->chipid == VSC73XX_CHIPID_ID_7385)
267*4882a593Smuzhiyun #define IS_7388(a) ((a)->chipid == VSC73XX_CHIPID_ID_7388)
268*4882a593Smuzhiyun #define IS_7395(a) ((a)->chipid == VSC73XX_CHIPID_ID_7395)
269*4882a593Smuzhiyun #define IS_7398(a) ((a)->chipid == VSC73XX_CHIPID_ID_7398)
270*4882a593Smuzhiyun #define IS_739X(a) (IS_7395(a) || IS_7398(a))
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun struct vsc73xx_counter {
273*4882a593Smuzhiyun u8 counter;
274*4882a593Smuzhiyun const char *name;
275*4882a593Smuzhiyun };
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun /* Counters are named according to the MIB standards where applicable.
278*4882a593Smuzhiyun * Some counters are custom, non-standard. The standard counters are
279*4882a593Smuzhiyun * named in accordance with RFC2819, RFC2021 and IEEE Std 802.3-2002 Annex
280*4882a593Smuzhiyun * 30A Counters.
281*4882a593Smuzhiyun */
282*4882a593Smuzhiyun static const struct vsc73xx_counter vsc73xx_rx_counters[] = {
283*4882a593Smuzhiyun { 0, "RxEtherStatsPkts" },
284*4882a593Smuzhiyun { 1, "RxBroadcast+MulticastPkts" }, /* non-standard counter */
285*4882a593Smuzhiyun { 2, "RxTotalErrorPackets" }, /* non-standard counter */
286*4882a593Smuzhiyun { 3, "RxEtherStatsBroadcastPkts" },
287*4882a593Smuzhiyun { 4, "RxEtherStatsMulticastPkts" },
288*4882a593Smuzhiyun { 5, "RxEtherStatsPkts64Octets" },
289*4882a593Smuzhiyun { 6, "RxEtherStatsPkts65to127Octets" },
290*4882a593Smuzhiyun { 7, "RxEtherStatsPkts128to255Octets" },
291*4882a593Smuzhiyun { 8, "RxEtherStatsPkts256to511Octets" },
292*4882a593Smuzhiyun { 9, "RxEtherStatsPkts512to1023Octets" },
293*4882a593Smuzhiyun { 10, "RxEtherStatsPkts1024to1518Octets" },
294*4882a593Smuzhiyun { 11, "RxJumboFrames" }, /* non-standard counter */
295*4882a593Smuzhiyun { 12, "RxaPauseMACControlFramesTransmitted" },
296*4882a593Smuzhiyun { 13, "RxFIFODrops" }, /* non-standard counter */
297*4882a593Smuzhiyun { 14, "RxBackwardDrops" }, /* non-standard counter */
298*4882a593Smuzhiyun { 15, "RxClassifierDrops" }, /* non-standard counter */
299*4882a593Smuzhiyun { 16, "RxEtherStatsCRCAlignErrors" },
300*4882a593Smuzhiyun { 17, "RxEtherStatsUndersizePkts" },
301*4882a593Smuzhiyun { 18, "RxEtherStatsOversizePkts" },
302*4882a593Smuzhiyun { 19, "RxEtherStatsFragments" },
303*4882a593Smuzhiyun { 20, "RxEtherStatsJabbers" },
304*4882a593Smuzhiyun { 21, "RxaMACControlFramesReceived" },
305*4882a593Smuzhiyun /* 22-24 are undefined */
306*4882a593Smuzhiyun { 25, "RxaFramesReceivedOK" },
307*4882a593Smuzhiyun { 26, "RxQoSClass0" }, /* non-standard counter */
308*4882a593Smuzhiyun { 27, "RxQoSClass1" }, /* non-standard counter */
309*4882a593Smuzhiyun { 28, "RxQoSClass2" }, /* non-standard counter */
310*4882a593Smuzhiyun { 29, "RxQoSClass3" }, /* non-standard counter */
311*4882a593Smuzhiyun };
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun static const struct vsc73xx_counter vsc73xx_tx_counters[] = {
314*4882a593Smuzhiyun { 0, "TxEtherStatsPkts" },
315*4882a593Smuzhiyun { 1, "TxBroadcast+MulticastPkts" }, /* non-standard counter */
316*4882a593Smuzhiyun { 2, "TxTotalErrorPackets" }, /* non-standard counter */
317*4882a593Smuzhiyun { 3, "TxEtherStatsBroadcastPkts" },
318*4882a593Smuzhiyun { 4, "TxEtherStatsMulticastPkts" },
319*4882a593Smuzhiyun { 5, "TxEtherStatsPkts64Octets" },
320*4882a593Smuzhiyun { 6, "TxEtherStatsPkts65to127Octets" },
321*4882a593Smuzhiyun { 7, "TxEtherStatsPkts128to255Octets" },
322*4882a593Smuzhiyun { 8, "TxEtherStatsPkts256to511Octets" },
323*4882a593Smuzhiyun { 9, "TxEtherStatsPkts512to1023Octets" },
324*4882a593Smuzhiyun { 10, "TxEtherStatsPkts1024to1518Octets" },
325*4882a593Smuzhiyun { 11, "TxJumboFrames" }, /* non-standard counter */
326*4882a593Smuzhiyun { 12, "TxaPauseMACControlFramesTransmitted" },
327*4882a593Smuzhiyun { 13, "TxFIFODrops" }, /* non-standard counter */
328*4882a593Smuzhiyun { 14, "TxDrops" }, /* non-standard counter */
329*4882a593Smuzhiyun { 15, "TxEtherStatsCollisions" },
330*4882a593Smuzhiyun { 16, "TxEtherStatsCRCAlignErrors" },
331*4882a593Smuzhiyun { 17, "TxEtherStatsUndersizePkts" },
332*4882a593Smuzhiyun { 18, "TxEtherStatsOversizePkts" },
333*4882a593Smuzhiyun { 19, "TxEtherStatsFragments" },
334*4882a593Smuzhiyun { 20, "TxEtherStatsJabbers" },
335*4882a593Smuzhiyun /* 21-24 are undefined */
336*4882a593Smuzhiyun { 25, "TxaFramesReceivedOK" },
337*4882a593Smuzhiyun { 26, "TxQoSClass0" }, /* non-standard counter */
338*4882a593Smuzhiyun { 27, "TxQoSClass1" }, /* non-standard counter */
339*4882a593Smuzhiyun { 28, "TxQoSClass2" }, /* non-standard counter */
340*4882a593Smuzhiyun { 29, "TxQoSClass3" }, /* non-standard counter */
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun
vsc73xx_is_addr_valid(u8 block,u8 subblock)343*4882a593Smuzhiyun int vsc73xx_is_addr_valid(u8 block, u8 subblock)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun switch (block) {
346*4882a593Smuzhiyun case VSC73XX_BLOCK_MAC:
347*4882a593Smuzhiyun switch (subblock) {
348*4882a593Smuzhiyun case 0 ... 4:
349*4882a593Smuzhiyun case 6:
350*4882a593Smuzhiyun return 1;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun case VSC73XX_BLOCK_ANALYZER:
355*4882a593Smuzhiyun case VSC73XX_BLOCK_SYSTEM:
356*4882a593Smuzhiyun switch (subblock) {
357*4882a593Smuzhiyun case 0:
358*4882a593Smuzhiyun return 1;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun break;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun case VSC73XX_BLOCK_MII:
363*4882a593Smuzhiyun case VSC73XX_BLOCK_CAPTURE:
364*4882a593Smuzhiyun case VSC73XX_BLOCK_ARBITER:
365*4882a593Smuzhiyun switch (subblock) {
366*4882a593Smuzhiyun case 0 ... 1:
367*4882a593Smuzhiyun return 1;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun break;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return 0;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun EXPORT_SYMBOL(vsc73xx_is_addr_valid);
375*4882a593Smuzhiyun
vsc73xx_read(struct vsc73xx * vsc,u8 block,u8 subblock,u8 reg,u32 * val)376*4882a593Smuzhiyun static int vsc73xx_read(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
377*4882a593Smuzhiyun u32 *val)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun return vsc->ops->read(vsc, block, subblock, reg, val);
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
vsc73xx_write(struct vsc73xx * vsc,u8 block,u8 subblock,u8 reg,u32 val)382*4882a593Smuzhiyun static int vsc73xx_write(struct vsc73xx *vsc, u8 block, u8 subblock, u8 reg,
383*4882a593Smuzhiyun u32 val)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun return vsc->ops->write(vsc, block, subblock, reg, val);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
vsc73xx_update_bits(struct vsc73xx * vsc,u8 block,u8 subblock,u8 reg,u32 mask,u32 val)388*4882a593Smuzhiyun static int vsc73xx_update_bits(struct vsc73xx *vsc, u8 block, u8 subblock,
389*4882a593Smuzhiyun u8 reg, u32 mask, u32 val)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun u32 tmp, orig;
392*4882a593Smuzhiyun int ret;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun /* Same read-modify-write algorithm as e.g. regmap */
395*4882a593Smuzhiyun ret = vsc73xx_read(vsc, block, subblock, reg, &orig);
396*4882a593Smuzhiyun if (ret)
397*4882a593Smuzhiyun return ret;
398*4882a593Smuzhiyun tmp = orig & ~mask;
399*4882a593Smuzhiyun tmp |= val & mask;
400*4882a593Smuzhiyun return vsc73xx_write(vsc, block, subblock, reg, tmp);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
vsc73xx_detect(struct vsc73xx * vsc)403*4882a593Smuzhiyun static int vsc73xx_detect(struct vsc73xx *vsc)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun bool icpu_si_boot_en;
406*4882a593Smuzhiyun bool icpu_pi_en;
407*4882a593Smuzhiyun u32 val;
408*4882a593Smuzhiyun u32 rev;
409*4882a593Smuzhiyun int ret;
410*4882a593Smuzhiyun u32 id;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
413*4882a593Smuzhiyun VSC73XX_ICPU_MBOX_VAL, &val);
414*4882a593Smuzhiyun if (ret) {
415*4882a593Smuzhiyun dev_err(vsc->dev, "unable to read mailbox (%d)\n", ret);
416*4882a593Smuzhiyun return ret;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (val == 0xffffffff) {
420*4882a593Smuzhiyun dev_info(vsc->dev, "chip seems dead.\n");
421*4882a593Smuzhiyun return -EAGAIN;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
425*4882a593Smuzhiyun VSC73XX_CHIPID, &val);
426*4882a593Smuzhiyun if (ret) {
427*4882a593Smuzhiyun dev_err(vsc->dev, "unable to read chip id (%d)\n", ret);
428*4882a593Smuzhiyun return ret;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun id = (val >> VSC73XX_CHIPID_ID_SHIFT) &
432*4882a593Smuzhiyun VSC73XX_CHIPID_ID_MASK;
433*4882a593Smuzhiyun switch (id) {
434*4882a593Smuzhiyun case VSC73XX_CHIPID_ID_7385:
435*4882a593Smuzhiyun case VSC73XX_CHIPID_ID_7388:
436*4882a593Smuzhiyun case VSC73XX_CHIPID_ID_7395:
437*4882a593Smuzhiyun case VSC73XX_CHIPID_ID_7398:
438*4882a593Smuzhiyun break;
439*4882a593Smuzhiyun default:
440*4882a593Smuzhiyun dev_err(vsc->dev, "unsupported chip, id=%04x\n", id);
441*4882a593Smuzhiyun return -ENODEV;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun vsc->chipid = id;
445*4882a593Smuzhiyun rev = (val >> VSC73XX_CHIPID_REV_SHIFT) &
446*4882a593Smuzhiyun VSC73XX_CHIPID_REV_MASK;
447*4882a593Smuzhiyun dev_info(vsc->dev, "VSC%04X (rev: %d) switch found\n", id, rev);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
450*4882a593Smuzhiyun VSC73XX_ICPU_CTRL, &val);
451*4882a593Smuzhiyun if (ret) {
452*4882a593Smuzhiyun dev_err(vsc->dev, "unable to read iCPU control\n");
453*4882a593Smuzhiyun return ret;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* The iCPU can always be used but can boot in different ways.
457*4882a593Smuzhiyun * If it is initially disabled and has no external memory,
458*4882a593Smuzhiyun * we are in control and can do whatever we like, else we
459*4882a593Smuzhiyun * are probably in trouble (we need some way to communicate
460*4882a593Smuzhiyun * with the running firmware) so we bail out for now.
461*4882a593Smuzhiyun */
462*4882a593Smuzhiyun icpu_pi_en = !!(val & VSC73XX_ICPU_CTRL_ICPU_PI_EN);
463*4882a593Smuzhiyun icpu_si_boot_en = !!(val & VSC73XX_ICPU_CTRL_BOOT_EN);
464*4882a593Smuzhiyun if (icpu_si_boot_en && icpu_pi_en) {
465*4882a593Smuzhiyun dev_err(vsc->dev,
466*4882a593Smuzhiyun "iCPU enabled boots from SI, has external memory\n");
467*4882a593Smuzhiyun dev_err(vsc->dev, "no idea how to deal with this\n");
468*4882a593Smuzhiyun return -ENODEV;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun if (icpu_si_boot_en && !icpu_pi_en) {
471*4882a593Smuzhiyun dev_err(vsc->dev,
472*4882a593Smuzhiyun "iCPU enabled boots from PI/SI, no external memory\n");
473*4882a593Smuzhiyun return -EAGAIN;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun if (!icpu_si_boot_en && icpu_pi_en) {
476*4882a593Smuzhiyun dev_err(vsc->dev,
477*4882a593Smuzhiyun "iCPU enabled, boots from PI external memory\n");
478*4882a593Smuzhiyun dev_err(vsc->dev, "no idea how to deal with this\n");
479*4882a593Smuzhiyun return -ENODEV;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun /* !icpu_si_boot_en && !cpu_pi_en */
482*4882a593Smuzhiyun dev_info(vsc->dev, "iCPU disabled, no external memory\n");
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
vsc73xx_phy_read(struct dsa_switch * ds,int phy,int regnum)487*4882a593Smuzhiyun static int vsc73xx_phy_read(struct dsa_switch *ds, int phy, int regnum)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
490*4882a593Smuzhiyun u32 cmd;
491*4882a593Smuzhiyun u32 val;
492*4882a593Smuzhiyun int ret;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun /* Setting bit 26 means "read" */
495*4882a593Smuzhiyun cmd = BIT(26) | (phy << 21) | (regnum << 16);
496*4882a593Smuzhiyun ret = vsc73xx_write(vsc, VSC73XX_BLOCK_MII, 0, 1, cmd);
497*4882a593Smuzhiyun if (ret)
498*4882a593Smuzhiyun return ret;
499*4882a593Smuzhiyun msleep(2);
500*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MII, 0, 2, &val);
501*4882a593Smuzhiyun if (ret)
502*4882a593Smuzhiyun return ret;
503*4882a593Smuzhiyun if (val & BIT(16)) {
504*4882a593Smuzhiyun dev_err(vsc->dev, "reading reg %02x from phy%d failed\n",
505*4882a593Smuzhiyun regnum, phy);
506*4882a593Smuzhiyun return -EIO;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun val &= 0xFFFFU;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun dev_dbg(vsc->dev, "read reg %02x from phy%d = %04x\n",
511*4882a593Smuzhiyun regnum, phy, val);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun return val;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
vsc73xx_phy_write(struct dsa_switch * ds,int phy,int regnum,u16 val)516*4882a593Smuzhiyun static int vsc73xx_phy_write(struct dsa_switch *ds, int phy, int regnum,
517*4882a593Smuzhiyun u16 val)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
520*4882a593Smuzhiyun u32 cmd;
521*4882a593Smuzhiyun int ret;
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /* It was found through tedious experiments that this router
524*4882a593Smuzhiyun * chip really hates to have it's PHYs reset. They
525*4882a593Smuzhiyun * never recover if that happens: autonegotiation stops
526*4882a593Smuzhiyun * working after a reset. Just filter out this command.
527*4882a593Smuzhiyun * (Resetting the whole chip is OK.)
528*4882a593Smuzhiyun */
529*4882a593Smuzhiyun if (regnum == 0 && (val & BIT(15))) {
530*4882a593Smuzhiyun dev_info(vsc->dev, "reset PHY - disallowed\n");
531*4882a593Smuzhiyun return 0;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun cmd = (phy << 21) | (regnum << 16);
535*4882a593Smuzhiyun ret = vsc73xx_write(vsc, VSC73XX_BLOCK_MII, 0, 1, cmd);
536*4882a593Smuzhiyun if (ret)
537*4882a593Smuzhiyun return ret;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun dev_dbg(vsc->dev, "write %04x to reg %02x in phy%d\n",
540*4882a593Smuzhiyun val, regnum, phy);
541*4882a593Smuzhiyun return 0;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
vsc73xx_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol mp)544*4882a593Smuzhiyun static enum dsa_tag_protocol vsc73xx_get_tag_protocol(struct dsa_switch *ds,
545*4882a593Smuzhiyun int port,
546*4882a593Smuzhiyun enum dsa_tag_protocol mp)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun /* The switch internally uses a 8 byte header with length,
549*4882a593Smuzhiyun * source port, tag, LPA and priority. This is supposedly
550*4882a593Smuzhiyun * only accessible when operating the switch using the internal
551*4882a593Smuzhiyun * CPU or with an external CPU mapping the device in, but not
552*4882a593Smuzhiyun * when operating the switch over SPI and putting frames in/out
553*4882a593Smuzhiyun * on port 6 (the CPU port). So far we must assume that we
554*4882a593Smuzhiyun * cannot access the tag. (See "Internal frame header" section
555*4882a593Smuzhiyun * 3.9.1 in the manual.)
556*4882a593Smuzhiyun */
557*4882a593Smuzhiyun return DSA_TAG_PROTO_NONE;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
vsc73xx_setup(struct dsa_switch * ds)560*4882a593Smuzhiyun static int vsc73xx_setup(struct dsa_switch *ds)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
563*4882a593Smuzhiyun int i;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun dev_info(vsc->dev, "set up the switch\n");
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /* Issue RESET */
568*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
569*4882a593Smuzhiyun VSC73XX_GLORESET_MASTER_RESET);
570*4882a593Smuzhiyun usleep_range(125, 200);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun /* Initialize memory, initialize RAM bank 0..15 except 6 and 7
573*4882a593Smuzhiyun * This sequence appears in the
574*4882a593Smuzhiyun * VSC7385 SparX-G5 datasheet section 6.6.1
575*4882a593Smuzhiyun * VSC7395 SparX-G5e datasheet section 6.6.1
576*4882a593Smuzhiyun * "initialization sequence".
577*4882a593Smuzhiyun * No explanation is given to the 0x1010400 magic number.
578*4882a593Smuzhiyun */
579*4882a593Smuzhiyun for (i = 0; i <= 15; i++) {
580*4882a593Smuzhiyun if (i != 6 && i != 7) {
581*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MEMINIT,
582*4882a593Smuzhiyun 2,
583*4882a593Smuzhiyun 0, 0x1010400 + i);
584*4882a593Smuzhiyun mdelay(1);
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun mdelay(30);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun /* Clear MAC table */
590*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
591*4882a593Smuzhiyun VSC73XX_MACACCESS,
592*4882a593Smuzhiyun VSC73XX_MACACCESS_CMD_CLEAR_TABLE);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /* Clear VLAN table */
595*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0,
596*4882a593Smuzhiyun VSC73XX_VLANACCESS,
597*4882a593Smuzhiyun VSC73XX_VLANACCESS_VLAN_TBL_CMD_CLEAR_TABLE);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun msleep(40);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /* Use 20KiB buffers on all ports on VSC7395
602*4882a593Smuzhiyun * The VSC7385 has 16KiB buffers and that is the
603*4882a593Smuzhiyun * default if we don't set this up explicitly.
604*4882a593Smuzhiyun * Port "31" is "all ports".
605*4882a593Smuzhiyun */
606*4882a593Smuzhiyun if (IS_739X(vsc))
607*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 0x1f,
608*4882a593Smuzhiyun VSC73XX_Q_MISC_CONF,
609*4882a593Smuzhiyun VSC73XX_Q_MISC_CONF_EXTENT_MEM);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun /* Put all ports into reset until enabled */
612*4882a593Smuzhiyun for (i = 0; i < 7; i++) {
613*4882a593Smuzhiyun if (i == 5)
614*4882a593Smuzhiyun continue;
615*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, 4,
616*4882a593Smuzhiyun VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /* MII delay, set both GTX and RX delay to 2 ns */
620*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GMIIDELAY,
621*4882a593Smuzhiyun VSC73XX_GMIIDELAY_GMII0_GTXDELAY_2_0_NS |
622*4882a593Smuzhiyun VSC73XX_GMIIDELAY_GMII0_RXDELAY_2_0_NS);
623*4882a593Smuzhiyun /* Enable reception of frames on all ports */
624*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_RECVMASK,
625*4882a593Smuzhiyun 0x5f);
626*4882a593Smuzhiyun /* IP multicast flood mask (table 144) */
627*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_ANALYZER, 0, VSC73XX_IFLODMSK,
628*4882a593Smuzhiyun 0xff);
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun mdelay(50);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun /* Release reset from the internal PHYs */
633*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_SYSTEM, 0, VSC73XX_GLORESET,
634*4882a593Smuzhiyun VSC73XX_GLORESET_PHY_RESET);
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun udelay(4);
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun return 0;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
vsc73xx_init_port(struct vsc73xx * vsc,int port)641*4882a593Smuzhiyun static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun u32 val;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /* MAC configure, first reset the port and then write defaults */
646*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
647*4882a593Smuzhiyun port,
648*4882a593Smuzhiyun VSC73XX_MAC_CFG,
649*4882a593Smuzhiyun VSC73XX_MAC_CFG_RESET);
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun /* Take up the port in 1Gbit mode by default, this will be
652*4882a593Smuzhiyun * augmented after auto-negotiation on the PHY-facing
653*4882a593Smuzhiyun * ports.
654*4882a593Smuzhiyun */
655*4882a593Smuzhiyun if (port == CPU_PORT)
656*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_1000M_F_RGMII;
657*4882a593Smuzhiyun else
658*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_1000M_F_PHY;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
661*4882a593Smuzhiyun port,
662*4882a593Smuzhiyun VSC73XX_MAC_CFG,
663*4882a593Smuzhiyun val |
664*4882a593Smuzhiyun VSC73XX_MAC_CFG_TX_EN |
665*4882a593Smuzhiyun VSC73XX_MAC_CFG_RX_EN);
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun /* Flow control for the CPU port:
668*4882a593Smuzhiyun * Use a zero delay pause frame when pause condition is left
669*4882a593Smuzhiyun * Obey pause control frames
670*4882a593Smuzhiyun */
671*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
672*4882a593Smuzhiyun port,
673*4882a593Smuzhiyun VSC73XX_FCCONF,
674*4882a593Smuzhiyun VSC73XX_FCCONF_ZERO_PAUSE_EN |
675*4882a593Smuzhiyun VSC73XX_FCCONF_FLOW_CTRL_OBEY);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* Issue pause control frames on PHY facing ports.
678*4882a593Smuzhiyun * Allow early initiation of MAC transmission if the amount
679*4882a593Smuzhiyun * of egress data is below 512 bytes on CPU port.
680*4882a593Smuzhiyun * FIXME: enable 20KiB buffers?
681*4882a593Smuzhiyun */
682*4882a593Smuzhiyun if (port == CPU_PORT)
683*4882a593Smuzhiyun val = VSC73XX_Q_MISC_CONF_EARLY_TX_512;
684*4882a593Smuzhiyun else
685*4882a593Smuzhiyun val = VSC73XX_Q_MISC_CONF_MAC_PAUSE_MODE;
686*4882a593Smuzhiyun val |= VSC73XX_Q_MISC_CONF_EXTENT_MEM;
687*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
688*4882a593Smuzhiyun port,
689*4882a593Smuzhiyun VSC73XX_Q_MISC_CONF,
690*4882a593Smuzhiyun val);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun /* Flow control MAC: a MAC address used in flow control frames */
693*4882a593Smuzhiyun val = (vsc->addr[5] << 16) | (vsc->addr[4] << 8) | (vsc->addr[3]);
694*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
695*4882a593Smuzhiyun port,
696*4882a593Smuzhiyun VSC73XX_FCMACHI,
697*4882a593Smuzhiyun val);
698*4882a593Smuzhiyun val = (vsc->addr[2] << 16) | (vsc->addr[1] << 8) | (vsc->addr[0]);
699*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
700*4882a593Smuzhiyun port,
701*4882a593Smuzhiyun VSC73XX_FCMACLO,
702*4882a593Smuzhiyun val);
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun /* Tell the categorizer to forward pause frames, not control
705*4882a593Smuzhiyun * frame. Do not drop anything.
706*4882a593Smuzhiyun */
707*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
708*4882a593Smuzhiyun port,
709*4882a593Smuzhiyun VSC73XX_CAT_DROP,
710*4882a593Smuzhiyun VSC73XX_CAT_DROP_FWD_PAUSE_ENA);
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun /* Clear all counters */
713*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
714*4882a593Smuzhiyun port, VSC73XX_C_RX0, 0);
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
vsc73xx_adjust_enable_port(struct vsc73xx * vsc,int port,struct phy_device * phydev,u32 initval)717*4882a593Smuzhiyun static void vsc73xx_adjust_enable_port(struct vsc73xx *vsc,
718*4882a593Smuzhiyun int port, struct phy_device *phydev,
719*4882a593Smuzhiyun u32 initval)
720*4882a593Smuzhiyun {
721*4882a593Smuzhiyun u32 val = initval;
722*4882a593Smuzhiyun u8 seed;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun /* Reset this port FIXME: break out subroutine */
725*4882a593Smuzhiyun val |= VSC73XX_MAC_CFG_RESET;
726*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun /* Seed the port randomness with randomness */
729*4882a593Smuzhiyun get_random_bytes(&seed, 1);
730*4882a593Smuzhiyun val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET;
731*4882a593Smuzhiyun val |= VSC73XX_MAC_CFG_SEED_LOAD;
732*4882a593Smuzhiyun val |= VSC73XX_MAC_CFG_WEXC_DIS;
733*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun /* Flow control for the PHY facing ports:
736*4882a593Smuzhiyun * Use a zero delay pause frame when pause condition is left
737*4882a593Smuzhiyun * Obey pause control frames
738*4882a593Smuzhiyun * When generating pause frames, use 0xff as pause value
739*4882a593Smuzhiyun */
740*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
741*4882a593Smuzhiyun VSC73XX_FCCONF_ZERO_PAUSE_EN |
742*4882a593Smuzhiyun VSC73XX_FCCONF_FLOW_CTRL_OBEY |
743*4882a593Smuzhiyun 0xff);
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun /* Disallow backward dropping of frames from this port */
746*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
747*4882a593Smuzhiyun VSC73XX_SBACKWDROP, BIT(port), 0);
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun /* Enable TX, RX, deassert reset, stop loading seed */
750*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
751*4882a593Smuzhiyun VSC73XX_MAC_CFG,
752*4882a593Smuzhiyun VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
753*4882a593Smuzhiyun VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN,
754*4882a593Smuzhiyun VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN);
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
vsc73xx_adjust_link(struct dsa_switch * ds,int port,struct phy_device * phydev)757*4882a593Smuzhiyun static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
758*4882a593Smuzhiyun struct phy_device *phydev)
759*4882a593Smuzhiyun {
760*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
761*4882a593Smuzhiyun u32 val;
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun /* Special handling of the CPU-facing port */
764*4882a593Smuzhiyun if (port == CPU_PORT) {
765*4882a593Smuzhiyun /* Other ports are already initialized but not this one */
766*4882a593Smuzhiyun vsc73xx_init_port(vsc, CPU_PORT);
767*4882a593Smuzhiyun /* Select the external port for this interface (EXT_PORT)
768*4882a593Smuzhiyun * Enable the GMII GTX external clock
769*4882a593Smuzhiyun * Use double data rate (DDR mode)
770*4882a593Smuzhiyun */
771*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
772*4882a593Smuzhiyun CPU_PORT,
773*4882a593Smuzhiyun VSC73XX_ADVPORTM,
774*4882a593Smuzhiyun VSC73XX_ADVPORTM_EXT_PORT |
775*4882a593Smuzhiyun VSC73XX_ADVPORTM_ENA_GTX |
776*4882a593Smuzhiyun VSC73XX_ADVPORTM_DDR_MODE);
777*4882a593Smuzhiyun }
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun /* This is the MAC confiuration that always need to happen
780*4882a593Smuzhiyun * after a PHY or the CPU port comes up or down.
781*4882a593Smuzhiyun */
782*4882a593Smuzhiyun if (!phydev->link) {
783*4882a593Smuzhiyun int maxloop = 10;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun dev_dbg(vsc->dev, "port %d: went down\n",
786*4882a593Smuzhiyun port);
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun /* Disable RX on this port */
789*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
790*4882a593Smuzhiyun VSC73XX_MAC_CFG,
791*4882a593Smuzhiyun VSC73XX_MAC_CFG_RX_EN, 0);
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun /* Discard packets */
794*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
795*4882a593Smuzhiyun VSC73XX_ARBDISC, BIT(port), BIT(port));
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun /* Wait until queue is empty */
798*4882a593Smuzhiyun vsc73xx_read(vsc, VSC73XX_BLOCK_ARBITER, 0,
799*4882a593Smuzhiyun VSC73XX_ARBEMPTY, &val);
800*4882a593Smuzhiyun while (!(val & BIT(port))) {
801*4882a593Smuzhiyun msleep(1);
802*4882a593Smuzhiyun vsc73xx_read(vsc, VSC73XX_BLOCK_ARBITER, 0,
803*4882a593Smuzhiyun VSC73XX_ARBEMPTY, &val);
804*4882a593Smuzhiyun if (--maxloop == 0) {
805*4882a593Smuzhiyun dev_err(vsc->dev,
806*4882a593Smuzhiyun "timeout waiting for block arbiter\n");
807*4882a593Smuzhiyun /* Continue anyway */
808*4882a593Smuzhiyun break;
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun /* Put this port into reset */
813*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
814*4882a593Smuzhiyun VSC73XX_MAC_CFG_RESET);
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun /* Accept packets again */
817*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
818*4882a593Smuzhiyun VSC73XX_ARBDISC, BIT(port), 0);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun /* Allow backward dropping of frames from this port */
821*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
822*4882a593Smuzhiyun VSC73XX_SBACKWDROP, BIT(port), BIT(port));
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun /* Receive mask (disable forwarding) */
825*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
826*4882a593Smuzhiyun VSC73XX_RECVMASK, BIT(port), 0);
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun return;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun /* Figure out what speed was negotiated */
832*4882a593Smuzhiyun if (phydev->speed == SPEED_1000) {
833*4882a593Smuzhiyun dev_dbg(vsc->dev, "port %d: 1000 Mbit mode full duplex\n",
834*4882a593Smuzhiyun port);
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun /* Set up default for internal port or external RGMII */
837*4882a593Smuzhiyun if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
838*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_1000M_F_RGMII;
839*4882a593Smuzhiyun else
840*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_1000M_F_PHY;
841*4882a593Smuzhiyun vsc73xx_adjust_enable_port(vsc, port, phydev, val);
842*4882a593Smuzhiyun } else if (phydev->speed == SPEED_100) {
843*4882a593Smuzhiyun if (phydev->duplex == DUPLEX_FULL) {
844*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_100_10M_F_PHY;
845*4882a593Smuzhiyun dev_dbg(vsc->dev,
846*4882a593Smuzhiyun "port %d: 100 Mbit full duplex mode\n",
847*4882a593Smuzhiyun port);
848*4882a593Smuzhiyun } else {
849*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_100_10M_H_PHY;
850*4882a593Smuzhiyun dev_dbg(vsc->dev,
851*4882a593Smuzhiyun "port %d: 100 Mbit half duplex mode\n",
852*4882a593Smuzhiyun port);
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun vsc73xx_adjust_enable_port(vsc, port, phydev, val);
855*4882a593Smuzhiyun } else if (phydev->speed == SPEED_10) {
856*4882a593Smuzhiyun if (phydev->duplex == DUPLEX_FULL) {
857*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_100_10M_F_PHY;
858*4882a593Smuzhiyun dev_dbg(vsc->dev,
859*4882a593Smuzhiyun "port %d: 10 Mbit full duplex mode\n",
860*4882a593Smuzhiyun port);
861*4882a593Smuzhiyun } else {
862*4882a593Smuzhiyun val = VSC73XX_MAC_CFG_100_10M_H_PHY;
863*4882a593Smuzhiyun dev_dbg(vsc->dev,
864*4882a593Smuzhiyun "port %d: 10 Mbit half duplex mode\n",
865*4882a593Smuzhiyun port);
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun vsc73xx_adjust_enable_port(vsc, port, phydev, val);
868*4882a593Smuzhiyun } else {
869*4882a593Smuzhiyun dev_err(vsc->dev,
870*4882a593Smuzhiyun "could not adjust link: unknown speed\n");
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun /* Enable port (forwarding) in the receieve mask */
874*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
875*4882a593Smuzhiyun VSC73XX_RECVMASK, BIT(port), BIT(port));
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun
vsc73xx_port_enable(struct dsa_switch * ds,int port,struct phy_device * phy)878*4882a593Smuzhiyun static int vsc73xx_port_enable(struct dsa_switch *ds, int port,
879*4882a593Smuzhiyun struct phy_device *phy)
880*4882a593Smuzhiyun {
881*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun dev_info(vsc->dev, "enable port %d\n", port);
884*4882a593Smuzhiyun vsc73xx_init_port(vsc, port);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun return 0;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun
vsc73xx_port_disable(struct dsa_switch * ds,int port)889*4882a593Smuzhiyun static void vsc73xx_port_disable(struct dsa_switch *ds, int port)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun /* Just put the port into reset */
894*4882a593Smuzhiyun vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
895*4882a593Smuzhiyun VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET);
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun static const struct vsc73xx_counter *
vsc73xx_find_counter(struct vsc73xx * vsc,u8 counter,bool tx)899*4882a593Smuzhiyun vsc73xx_find_counter(struct vsc73xx *vsc,
900*4882a593Smuzhiyun u8 counter,
901*4882a593Smuzhiyun bool tx)
902*4882a593Smuzhiyun {
903*4882a593Smuzhiyun const struct vsc73xx_counter *cnts;
904*4882a593Smuzhiyun int num_cnts;
905*4882a593Smuzhiyun int i;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun if (tx) {
908*4882a593Smuzhiyun cnts = vsc73xx_tx_counters;
909*4882a593Smuzhiyun num_cnts = ARRAY_SIZE(vsc73xx_tx_counters);
910*4882a593Smuzhiyun } else {
911*4882a593Smuzhiyun cnts = vsc73xx_rx_counters;
912*4882a593Smuzhiyun num_cnts = ARRAY_SIZE(vsc73xx_rx_counters);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun for (i = 0; i < num_cnts; i++) {
916*4882a593Smuzhiyun const struct vsc73xx_counter *cnt;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun cnt = &cnts[i];
919*4882a593Smuzhiyun if (cnt->counter == counter)
920*4882a593Smuzhiyun return cnt;
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun return NULL;
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
vsc73xx_get_strings(struct dsa_switch * ds,int port,u32 stringset,uint8_t * data)926*4882a593Smuzhiyun static void vsc73xx_get_strings(struct dsa_switch *ds, int port, u32 stringset,
927*4882a593Smuzhiyun uint8_t *data)
928*4882a593Smuzhiyun {
929*4882a593Smuzhiyun const struct vsc73xx_counter *cnt;
930*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
931*4882a593Smuzhiyun u8 indices[6];
932*4882a593Smuzhiyun int i, j;
933*4882a593Smuzhiyun u32 val;
934*4882a593Smuzhiyun int ret;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun if (stringset != ETH_SS_STATS)
937*4882a593Smuzhiyun return;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MAC, port,
940*4882a593Smuzhiyun VSC73XX_C_CFG, &val);
941*4882a593Smuzhiyun if (ret)
942*4882a593Smuzhiyun return;
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun indices[0] = (val & 0x1f); /* RX counter 0 */
945*4882a593Smuzhiyun indices[1] = ((val >> 5) & 0x1f); /* RX counter 1 */
946*4882a593Smuzhiyun indices[2] = ((val >> 10) & 0x1f); /* RX counter 2 */
947*4882a593Smuzhiyun indices[3] = ((val >> 16) & 0x1f); /* TX counter 0 */
948*4882a593Smuzhiyun indices[4] = ((val >> 21) & 0x1f); /* TX counter 1 */
949*4882a593Smuzhiyun indices[5] = ((val >> 26) & 0x1f); /* TX counter 2 */
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun /* The first counters is the RX octets */
952*4882a593Smuzhiyun j = 0;
953*4882a593Smuzhiyun strncpy(data + j * ETH_GSTRING_LEN,
954*4882a593Smuzhiyun "RxEtherStatsOctets", ETH_GSTRING_LEN);
955*4882a593Smuzhiyun j++;
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun /* Each port supports recording 3 RX counters and 3 TX counters,
958*4882a593Smuzhiyun * figure out what counters we use in this set-up and return the
959*4882a593Smuzhiyun * names of them. The hardware default counters will be number of
960*4882a593Smuzhiyun * packets on RX/TX, combined broadcast+multicast packets RX/TX and
961*4882a593Smuzhiyun * total error packets RX/TX.
962*4882a593Smuzhiyun */
963*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
964*4882a593Smuzhiyun cnt = vsc73xx_find_counter(vsc, indices[i], false);
965*4882a593Smuzhiyun if (cnt)
966*4882a593Smuzhiyun strncpy(data + j * ETH_GSTRING_LEN,
967*4882a593Smuzhiyun cnt->name, ETH_GSTRING_LEN);
968*4882a593Smuzhiyun j++;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun /* TX stats begins with the number of TX octets */
972*4882a593Smuzhiyun strncpy(data + j * ETH_GSTRING_LEN,
973*4882a593Smuzhiyun "TxEtherStatsOctets", ETH_GSTRING_LEN);
974*4882a593Smuzhiyun j++;
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun for (i = 3; i < 6; i++) {
977*4882a593Smuzhiyun cnt = vsc73xx_find_counter(vsc, indices[i], true);
978*4882a593Smuzhiyun if (cnt)
979*4882a593Smuzhiyun strncpy(data + j * ETH_GSTRING_LEN,
980*4882a593Smuzhiyun cnt->name, ETH_GSTRING_LEN);
981*4882a593Smuzhiyun j++;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun
vsc73xx_get_sset_count(struct dsa_switch * ds,int port,int sset)985*4882a593Smuzhiyun static int vsc73xx_get_sset_count(struct dsa_switch *ds, int port, int sset)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun /* We only support SS_STATS */
988*4882a593Smuzhiyun if (sset != ETH_SS_STATS)
989*4882a593Smuzhiyun return 0;
990*4882a593Smuzhiyun /* RX and TX packets, then 3 RX counters, 3 TX counters */
991*4882a593Smuzhiyun return 8;
992*4882a593Smuzhiyun }
993*4882a593Smuzhiyun
vsc73xx_get_ethtool_stats(struct dsa_switch * ds,int port,uint64_t * data)994*4882a593Smuzhiyun static void vsc73xx_get_ethtool_stats(struct dsa_switch *ds, int port,
995*4882a593Smuzhiyun uint64_t *data)
996*4882a593Smuzhiyun {
997*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
998*4882a593Smuzhiyun u8 regs[] = {
999*4882a593Smuzhiyun VSC73XX_RXOCT,
1000*4882a593Smuzhiyun VSC73XX_C_RX0,
1001*4882a593Smuzhiyun VSC73XX_C_RX1,
1002*4882a593Smuzhiyun VSC73XX_C_RX2,
1003*4882a593Smuzhiyun VSC73XX_TXOCT,
1004*4882a593Smuzhiyun VSC73XX_C_TX0,
1005*4882a593Smuzhiyun VSC73XX_C_TX1,
1006*4882a593Smuzhiyun VSC73XX_C_TX2,
1007*4882a593Smuzhiyun };
1008*4882a593Smuzhiyun u32 val;
1009*4882a593Smuzhiyun int ret;
1010*4882a593Smuzhiyun int i;
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(regs); i++) {
1013*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_MAC, port,
1014*4882a593Smuzhiyun regs[i], &val);
1015*4882a593Smuzhiyun if (ret) {
1016*4882a593Smuzhiyun dev_err(vsc->dev, "error reading counter %d\n", i);
1017*4882a593Smuzhiyun return;
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun data[i] = val;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun
vsc73xx_change_mtu(struct dsa_switch * ds,int port,int new_mtu)1023*4882a593Smuzhiyun static int vsc73xx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun struct vsc73xx *vsc = ds->priv;
1026*4882a593Smuzhiyun
1027*4882a593Smuzhiyun return vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port,
1028*4882a593Smuzhiyun VSC73XX_MAXLEN, new_mtu);
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun /* According to application not "VSC7398 Jumbo Frames" setting
1032*4882a593Smuzhiyun * up the MTU to 9.6 KB does not affect the performance on standard
1033*4882a593Smuzhiyun * frames. It is clear from the application note that
1034*4882a593Smuzhiyun * "9.6 kilobytes" == 9600 bytes.
1035*4882a593Smuzhiyun */
vsc73xx_get_max_mtu(struct dsa_switch * ds,int port)1036*4882a593Smuzhiyun static int vsc73xx_get_max_mtu(struct dsa_switch *ds, int port)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun return 9600;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun static const struct dsa_switch_ops vsc73xx_ds_ops = {
1042*4882a593Smuzhiyun .get_tag_protocol = vsc73xx_get_tag_protocol,
1043*4882a593Smuzhiyun .setup = vsc73xx_setup,
1044*4882a593Smuzhiyun .phy_read = vsc73xx_phy_read,
1045*4882a593Smuzhiyun .phy_write = vsc73xx_phy_write,
1046*4882a593Smuzhiyun .adjust_link = vsc73xx_adjust_link,
1047*4882a593Smuzhiyun .get_strings = vsc73xx_get_strings,
1048*4882a593Smuzhiyun .get_ethtool_stats = vsc73xx_get_ethtool_stats,
1049*4882a593Smuzhiyun .get_sset_count = vsc73xx_get_sset_count,
1050*4882a593Smuzhiyun .port_enable = vsc73xx_port_enable,
1051*4882a593Smuzhiyun .port_disable = vsc73xx_port_disable,
1052*4882a593Smuzhiyun .port_change_mtu = vsc73xx_change_mtu,
1053*4882a593Smuzhiyun .port_max_mtu = vsc73xx_get_max_mtu,
1054*4882a593Smuzhiyun };
1055*4882a593Smuzhiyun
vsc73xx_gpio_get(struct gpio_chip * chip,unsigned int offset)1056*4882a593Smuzhiyun static int vsc73xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
1057*4882a593Smuzhiyun {
1058*4882a593Smuzhiyun struct vsc73xx *vsc = gpiochip_get_data(chip);
1059*4882a593Smuzhiyun u32 val;
1060*4882a593Smuzhiyun int ret;
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
1063*4882a593Smuzhiyun VSC73XX_GPIO, &val);
1064*4882a593Smuzhiyun if (ret)
1065*4882a593Smuzhiyun return ret;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun return !!(val & BIT(offset));
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun
vsc73xx_gpio_set(struct gpio_chip * chip,unsigned int offset,int val)1070*4882a593Smuzhiyun static void vsc73xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
1071*4882a593Smuzhiyun int val)
1072*4882a593Smuzhiyun {
1073*4882a593Smuzhiyun struct vsc73xx *vsc = gpiochip_get_data(chip);
1074*4882a593Smuzhiyun u32 tmp = val ? BIT(offset) : 0;
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
1077*4882a593Smuzhiyun VSC73XX_GPIO, BIT(offset), tmp);
1078*4882a593Smuzhiyun }
1079*4882a593Smuzhiyun
vsc73xx_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int val)1080*4882a593Smuzhiyun static int vsc73xx_gpio_direction_output(struct gpio_chip *chip,
1081*4882a593Smuzhiyun unsigned int offset, int val)
1082*4882a593Smuzhiyun {
1083*4882a593Smuzhiyun struct vsc73xx *vsc = gpiochip_get_data(chip);
1084*4882a593Smuzhiyun u32 tmp = val ? BIT(offset) : 0;
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
1087*4882a593Smuzhiyun VSC73XX_GPIO, BIT(offset + 4) | BIT(offset),
1088*4882a593Smuzhiyun BIT(offset + 4) | tmp);
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun
vsc73xx_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)1091*4882a593Smuzhiyun static int vsc73xx_gpio_direction_input(struct gpio_chip *chip,
1092*4882a593Smuzhiyun unsigned int offset)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun struct vsc73xx *vsc = gpiochip_get_data(chip);
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun return vsc73xx_update_bits(vsc, VSC73XX_BLOCK_SYSTEM, 0,
1097*4882a593Smuzhiyun VSC73XX_GPIO, BIT(offset + 4),
1098*4882a593Smuzhiyun 0);
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun
vsc73xx_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)1101*4882a593Smuzhiyun static int vsc73xx_gpio_get_direction(struct gpio_chip *chip,
1102*4882a593Smuzhiyun unsigned int offset)
1103*4882a593Smuzhiyun {
1104*4882a593Smuzhiyun struct vsc73xx *vsc = gpiochip_get_data(chip);
1105*4882a593Smuzhiyun u32 val;
1106*4882a593Smuzhiyun int ret;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun ret = vsc73xx_read(vsc, VSC73XX_BLOCK_SYSTEM, 0,
1109*4882a593Smuzhiyun VSC73XX_GPIO, &val);
1110*4882a593Smuzhiyun if (ret)
1111*4882a593Smuzhiyun return ret;
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun return !(val & BIT(offset + 4));
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
vsc73xx_gpio_probe(struct vsc73xx * vsc)1116*4882a593Smuzhiyun static int vsc73xx_gpio_probe(struct vsc73xx *vsc)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun int ret;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun vsc->gc.label = devm_kasprintf(vsc->dev, GFP_KERNEL, "VSC%04x",
1121*4882a593Smuzhiyun vsc->chipid);
1122*4882a593Smuzhiyun vsc->gc.ngpio = 4;
1123*4882a593Smuzhiyun vsc->gc.owner = THIS_MODULE;
1124*4882a593Smuzhiyun vsc->gc.parent = vsc->dev;
1125*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_OF_GPIO)
1126*4882a593Smuzhiyun vsc->gc.of_node = vsc->dev->of_node;
1127*4882a593Smuzhiyun #endif
1128*4882a593Smuzhiyun vsc->gc.base = -1;
1129*4882a593Smuzhiyun vsc->gc.get = vsc73xx_gpio_get;
1130*4882a593Smuzhiyun vsc->gc.set = vsc73xx_gpio_set;
1131*4882a593Smuzhiyun vsc->gc.direction_input = vsc73xx_gpio_direction_input;
1132*4882a593Smuzhiyun vsc->gc.direction_output = vsc73xx_gpio_direction_output;
1133*4882a593Smuzhiyun vsc->gc.get_direction = vsc73xx_gpio_get_direction;
1134*4882a593Smuzhiyun vsc->gc.can_sleep = true;
1135*4882a593Smuzhiyun ret = devm_gpiochip_add_data(vsc->dev, &vsc->gc, vsc);
1136*4882a593Smuzhiyun if (ret) {
1137*4882a593Smuzhiyun dev_err(vsc->dev, "unable to register GPIO chip\n");
1138*4882a593Smuzhiyun return ret;
1139*4882a593Smuzhiyun }
1140*4882a593Smuzhiyun return 0;
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun
vsc73xx_probe(struct vsc73xx * vsc)1143*4882a593Smuzhiyun int vsc73xx_probe(struct vsc73xx *vsc)
1144*4882a593Smuzhiyun {
1145*4882a593Smuzhiyun struct device *dev = vsc->dev;
1146*4882a593Smuzhiyun int ret;
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun /* Release reset, if any */
1149*4882a593Smuzhiyun vsc->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
1150*4882a593Smuzhiyun if (IS_ERR(vsc->reset)) {
1151*4882a593Smuzhiyun dev_err(dev, "failed to get RESET GPIO\n");
1152*4882a593Smuzhiyun return PTR_ERR(vsc->reset);
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun if (vsc->reset)
1155*4882a593Smuzhiyun /* Wait 20ms according to datasheet table 245 */
1156*4882a593Smuzhiyun msleep(20);
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun ret = vsc73xx_detect(vsc);
1159*4882a593Smuzhiyun if (ret == -EAGAIN) {
1160*4882a593Smuzhiyun dev_err(vsc->dev,
1161*4882a593Smuzhiyun "Chip seems to be out of control. Assert reset and try again.\n");
1162*4882a593Smuzhiyun gpiod_set_value_cansleep(vsc->reset, 1);
1163*4882a593Smuzhiyun /* Reset pulse should be 20ns minimum, according to datasheet
1164*4882a593Smuzhiyun * table 245, so 10us should be fine
1165*4882a593Smuzhiyun */
1166*4882a593Smuzhiyun usleep_range(10, 100);
1167*4882a593Smuzhiyun gpiod_set_value_cansleep(vsc->reset, 0);
1168*4882a593Smuzhiyun /* Wait 20ms according to datasheet table 245 */
1169*4882a593Smuzhiyun msleep(20);
1170*4882a593Smuzhiyun ret = vsc73xx_detect(vsc);
1171*4882a593Smuzhiyun }
1172*4882a593Smuzhiyun if (ret) {
1173*4882a593Smuzhiyun dev_err(dev, "no chip found (%d)\n", ret);
1174*4882a593Smuzhiyun return -ENODEV;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun eth_random_addr(vsc->addr);
1178*4882a593Smuzhiyun dev_info(vsc->dev,
1179*4882a593Smuzhiyun "MAC for control frames: %02X:%02X:%02X:%02X:%02X:%02X\n",
1180*4882a593Smuzhiyun vsc->addr[0], vsc->addr[1], vsc->addr[2],
1181*4882a593Smuzhiyun vsc->addr[3], vsc->addr[4], vsc->addr[5]);
1182*4882a593Smuzhiyun
1183*4882a593Smuzhiyun /* The VSC7395 switch chips have 5+1 ports which means 5
1184*4882a593Smuzhiyun * ordinary ports and a sixth CPU port facing the processor
1185*4882a593Smuzhiyun * with an RGMII interface. These ports are numbered 0..4
1186*4882a593Smuzhiyun * and 6, so they leave a "hole" in the port map for port 5,
1187*4882a593Smuzhiyun * which is invalid.
1188*4882a593Smuzhiyun *
1189*4882a593Smuzhiyun * The VSC7398 has 8 ports, port 7 is again the CPU port.
1190*4882a593Smuzhiyun *
1191*4882a593Smuzhiyun * We allocate 8 ports and avoid access to the nonexistant
1192*4882a593Smuzhiyun * ports.
1193*4882a593Smuzhiyun */
1194*4882a593Smuzhiyun vsc->ds = devm_kzalloc(dev, sizeof(*vsc->ds), GFP_KERNEL);
1195*4882a593Smuzhiyun if (!vsc->ds)
1196*4882a593Smuzhiyun return -ENOMEM;
1197*4882a593Smuzhiyun
1198*4882a593Smuzhiyun vsc->ds->dev = dev;
1199*4882a593Smuzhiyun vsc->ds->num_ports = 8;
1200*4882a593Smuzhiyun vsc->ds->priv = vsc;
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun vsc->ds->ops = &vsc73xx_ds_ops;
1203*4882a593Smuzhiyun ret = dsa_register_switch(vsc->ds);
1204*4882a593Smuzhiyun if (ret) {
1205*4882a593Smuzhiyun dev_err(dev, "unable to register switch (%d)\n", ret);
1206*4882a593Smuzhiyun return ret;
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun ret = vsc73xx_gpio_probe(vsc);
1210*4882a593Smuzhiyun if (ret) {
1211*4882a593Smuzhiyun dsa_unregister_switch(vsc->ds);
1212*4882a593Smuzhiyun return ret;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun return 0;
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun EXPORT_SYMBOL(vsc73xx_probe);
1218*4882a593Smuzhiyun
vsc73xx_remove(struct vsc73xx * vsc)1219*4882a593Smuzhiyun int vsc73xx_remove(struct vsc73xx *vsc)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun dsa_unregister_switch(vsc->ds);
1222*4882a593Smuzhiyun gpiod_set_value(vsc->reset, 1);
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun return 0;
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun EXPORT_SYMBOL(vsc73xx_remove);
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
1229*4882a593Smuzhiyun MODULE_DESCRIPTION("Vitesse VSC7385/7388/7395/7398 driver");
1230*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1231