xref: /OK3568_Linux_fs/kernel/drivers/net/dsa/vitesse-vsc73xx-core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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