xref: /OK3568_Linux_fs/kernel/drivers/net/dsa/rtl8366rb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Realtek SMI subdriver for the Realtek RTL8366RB ethernet switch
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * This is a sparsely documented chip, the only viable documentation seems
5*4882a593Smuzhiyun  * to be a patched up code drop from the vendor that appear in various
6*4882a593Smuzhiyun  * GPL source trees.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
9*4882a593Smuzhiyun  * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
10*4882a593Smuzhiyun  * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com>
11*4882a593Smuzhiyun  * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv>
12*4882a593Smuzhiyun  * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com>
13*4882a593Smuzhiyun  */
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/bitops.h>
16*4882a593Smuzhiyun #include <linux/etherdevice.h>
17*4882a593Smuzhiyun #include <linux/interrupt.h>
18*4882a593Smuzhiyun #include <linux/irqdomain.h>
19*4882a593Smuzhiyun #include <linux/irqchip/chained_irq.h>
20*4882a593Smuzhiyun #include <linux/of_irq.h>
21*4882a593Smuzhiyun #include <linux/regmap.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include "realtek-smi-core.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define RTL8366RB_PORT_NUM_CPU		5
26*4882a593Smuzhiyun #define RTL8366RB_NUM_PORTS		6
27*4882a593Smuzhiyun #define RTL8366RB_PHY_NO_MAX		4
28*4882a593Smuzhiyun #define RTL8366RB_PHY_ADDR_MAX		31
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /* Switch Global Configuration register */
31*4882a593Smuzhiyun #define RTL8366RB_SGCR				0x0000
32*4882a593Smuzhiyun #define RTL8366RB_SGCR_EN_BC_STORM_CTRL		BIT(0)
33*4882a593Smuzhiyun #define RTL8366RB_SGCR_MAX_LENGTH(a)		((a) << 4)
34*4882a593Smuzhiyun #define RTL8366RB_SGCR_MAX_LENGTH_MASK		RTL8366RB_SGCR_MAX_LENGTH(0x3)
35*4882a593Smuzhiyun #define RTL8366RB_SGCR_MAX_LENGTH_1522		RTL8366RB_SGCR_MAX_LENGTH(0x0)
36*4882a593Smuzhiyun #define RTL8366RB_SGCR_MAX_LENGTH_1536		RTL8366RB_SGCR_MAX_LENGTH(0x1)
37*4882a593Smuzhiyun #define RTL8366RB_SGCR_MAX_LENGTH_1552		RTL8366RB_SGCR_MAX_LENGTH(0x2)
38*4882a593Smuzhiyun #define RTL8366RB_SGCR_MAX_LENGTH_16000		RTL8366RB_SGCR_MAX_LENGTH(0x3)
39*4882a593Smuzhiyun #define RTL8366RB_SGCR_EN_VLAN			BIT(13)
40*4882a593Smuzhiyun #define RTL8366RB_SGCR_EN_VLAN_4KTB		BIT(14)
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun /* Port Enable Control register */
43*4882a593Smuzhiyun #define RTL8366RB_PECR				0x0001
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun /* Switch Security Control registers */
46*4882a593Smuzhiyun #define RTL8366RB_SSCR0				0x0002
47*4882a593Smuzhiyun #define RTL8366RB_SSCR1				0x0003
48*4882a593Smuzhiyun #define RTL8366RB_SSCR2				0x0004
49*4882a593Smuzhiyun #define RTL8366RB_SSCR2_DROP_UNKNOWN_DA		BIT(0)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* Port Mode Control registers */
52*4882a593Smuzhiyun #define RTL8366RB_PMC0				0x0005
53*4882a593Smuzhiyun #define RTL8366RB_PMC0_SPI			BIT(0)
54*4882a593Smuzhiyun #define RTL8366RB_PMC0_EN_AUTOLOAD		BIT(1)
55*4882a593Smuzhiyun #define RTL8366RB_PMC0_PROBE			BIT(2)
56*4882a593Smuzhiyun #define RTL8366RB_PMC0_DIS_BISR			BIT(3)
57*4882a593Smuzhiyun #define RTL8366RB_PMC0_ADCTEST			BIT(4)
58*4882a593Smuzhiyun #define RTL8366RB_PMC0_SRAM_DIAG		BIT(5)
59*4882a593Smuzhiyun #define RTL8366RB_PMC0_EN_SCAN			BIT(6)
60*4882a593Smuzhiyun #define RTL8366RB_PMC0_P4_IOMODE_SHIFT		7
61*4882a593Smuzhiyun #define RTL8366RB_PMC0_P4_IOMODE_MASK		GENMASK(9, 7)
62*4882a593Smuzhiyun #define RTL8366RB_PMC0_P5_IOMODE_SHIFT		10
63*4882a593Smuzhiyun #define RTL8366RB_PMC0_P5_IOMODE_MASK		GENMASK(12, 10)
64*4882a593Smuzhiyun #define RTL8366RB_PMC0_SDSMODE_SHIFT		13
65*4882a593Smuzhiyun #define RTL8366RB_PMC0_SDSMODE_MASK		GENMASK(15, 13)
66*4882a593Smuzhiyun #define RTL8366RB_PMC1				0x0006
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /* Port Mirror Control Register */
69*4882a593Smuzhiyun #define RTL8366RB_PMCR				0x0007
70*4882a593Smuzhiyun #define RTL8366RB_PMCR_SOURCE_PORT(a)		(a)
71*4882a593Smuzhiyun #define RTL8366RB_PMCR_SOURCE_PORT_MASK		0x000f
72*4882a593Smuzhiyun #define RTL8366RB_PMCR_MONITOR_PORT(a)		((a) << 4)
73*4882a593Smuzhiyun #define RTL8366RB_PMCR_MONITOR_PORT_MASK	0x00f0
74*4882a593Smuzhiyun #define RTL8366RB_PMCR_MIRROR_RX		BIT(8)
75*4882a593Smuzhiyun #define RTL8366RB_PMCR_MIRROR_TX		BIT(9)
76*4882a593Smuzhiyun #define RTL8366RB_PMCR_MIRROR_SPC		BIT(10)
77*4882a593Smuzhiyun #define RTL8366RB_PMCR_MIRROR_ISO		BIT(11)
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* bits 0..7 = port 0, bits 8..15 = port 1 */
80*4882a593Smuzhiyun #define RTL8366RB_PAACR0		0x0010
81*4882a593Smuzhiyun /* bits 0..7 = port 2, bits 8..15 = port 3 */
82*4882a593Smuzhiyun #define RTL8366RB_PAACR1		0x0011
83*4882a593Smuzhiyun /* bits 0..7 = port 4, bits 8..15 = port 5 */
84*4882a593Smuzhiyun #define RTL8366RB_PAACR2		0x0012
85*4882a593Smuzhiyun #define RTL8366RB_PAACR_SPEED_10M	0
86*4882a593Smuzhiyun #define RTL8366RB_PAACR_SPEED_100M	1
87*4882a593Smuzhiyun #define RTL8366RB_PAACR_SPEED_1000M	2
88*4882a593Smuzhiyun #define RTL8366RB_PAACR_FULL_DUPLEX	BIT(2)
89*4882a593Smuzhiyun #define RTL8366RB_PAACR_LINK_UP		BIT(4)
90*4882a593Smuzhiyun #define RTL8366RB_PAACR_TX_PAUSE	BIT(5)
91*4882a593Smuzhiyun #define RTL8366RB_PAACR_RX_PAUSE	BIT(6)
92*4882a593Smuzhiyun #define RTL8366RB_PAACR_AN		BIT(7)
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun #define RTL8366RB_PAACR_CPU_PORT	(RTL8366RB_PAACR_SPEED_1000M | \
95*4882a593Smuzhiyun 					 RTL8366RB_PAACR_FULL_DUPLEX | \
96*4882a593Smuzhiyun 					 RTL8366RB_PAACR_LINK_UP | \
97*4882a593Smuzhiyun 					 RTL8366RB_PAACR_TX_PAUSE | \
98*4882a593Smuzhiyun 					 RTL8366RB_PAACR_RX_PAUSE)
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun /* bits 0..7 = port 0, bits 8..15 = port 1 */
101*4882a593Smuzhiyun #define RTL8366RB_PSTAT0		0x0014
102*4882a593Smuzhiyun /* bits 0..7 = port 2, bits 8..15 = port 3 */
103*4882a593Smuzhiyun #define RTL8366RB_PSTAT1		0x0015
104*4882a593Smuzhiyun /* bits 0..7 = port 4, bits 8..15 = port 5 */
105*4882a593Smuzhiyun #define RTL8366RB_PSTAT2		0x0016
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun #define RTL8366RB_POWER_SAVING_REG	0x0021
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /* CPU port control reg */
110*4882a593Smuzhiyun #define RTL8368RB_CPU_CTRL_REG		0x0061
111*4882a593Smuzhiyun #define RTL8368RB_CPU_PORTS_MSK		0x00FF
112*4882a593Smuzhiyun /* Disables inserting custom tag length/type 0x8899 */
113*4882a593Smuzhiyun #define RTL8368RB_CPU_NO_TAG		BIT(15)
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun #define RTL8366RB_SMAR0			0x0070 /* bits 0..15 */
116*4882a593Smuzhiyun #define RTL8366RB_SMAR1			0x0071 /* bits 16..31 */
117*4882a593Smuzhiyun #define RTL8366RB_SMAR2			0x0072 /* bits 32..47 */
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun #define RTL8366RB_RESET_CTRL_REG		0x0100
120*4882a593Smuzhiyun #define RTL8366RB_CHIP_CTRL_RESET_HW		BIT(0)
121*4882a593Smuzhiyun #define RTL8366RB_CHIP_CTRL_RESET_SW		BIT(1)
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun #define RTL8366RB_CHIP_ID_REG			0x0509
124*4882a593Smuzhiyun #define RTL8366RB_CHIP_ID_8366			0x5937
125*4882a593Smuzhiyun #define RTL8366RB_CHIP_VERSION_CTRL_REG		0x050A
126*4882a593Smuzhiyun #define RTL8366RB_CHIP_VERSION_MASK		0xf
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun /* PHY registers control */
129*4882a593Smuzhiyun #define RTL8366RB_PHY_ACCESS_CTRL_REG		0x8000
130*4882a593Smuzhiyun #define RTL8366RB_PHY_CTRL_READ			BIT(0)
131*4882a593Smuzhiyun #define RTL8366RB_PHY_CTRL_WRITE		0
132*4882a593Smuzhiyun #define RTL8366RB_PHY_ACCESS_BUSY_REG		0x8001
133*4882a593Smuzhiyun #define RTL8366RB_PHY_INT_BUSY			BIT(0)
134*4882a593Smuzhiyun #define RTL8366RB_PHY_EXT_BUSY			BIT(4)
135*4882a593Smuzhiyun #define RTL8366RB_PHY_ACCESS_DATA_REG		0x8002
136*4882a593Smuzhiyun #define RTL8366RB_PHY_EXT_CTRL_REG		0x8010
137*4882a593Smuzhiyun #define RTL8366RB_PHY_EXT_WRDATA_REG		0x8011
138*4882a593Smuzhiyun #define RTL8366RB_PHY_EXT_RDDATA_REG		0x8012
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun #define RTL8366RB_PHY_REG_MASK			0x1f
141*4882a593Smuzhiyun #define RTL8366RB_PHY_PAGE_OFFSET		5
142*4882a593Smuzhiyun #define RTL8366RB_PHY_PAGE_MASK			(0xf << 5)
143*4882a593Smuzhiyun #define RTL8366RB_PHY_NO_OFFSET			9
144*4882a593Smuzhiyun #define RTL8366RB_PHY_NO_MASK			(0x1f << 9)
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun #define RTL8366RB_VLAN_INGRESS_CTRL2_REG	0x037f
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun /* LED control registers */
149*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_REG		0x0430
150*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_MASK		0x0007
151*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_28MS		0x0000
152*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_56MS		0x0001
153*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_84MS		0x0002
154*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_111MS		0x0003
155*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_222MS		0x0004
156*4882a593Smuzhiyun #define RTL8366RB_LED_BLINKRATE_446MS		0x0005
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun #define RTL8366RB_LED_CTRL_REG			0x0431
159*4882a593Smuzhiyun #define RTL8366RB_LED_OFF			0x0
160*4882a593Smuzhiyun #define RTL8366RB_LED_DUP_COL			0x1
161*4882a593Smuzhiyun #define RTL8366RB_LED_LINK_ACT			0x2
162*4882a593Smuzhiyun #define RTL8366RB_LED_SPD1000			0x3
163*4882a593Smuzhiyun #define RTL8366RB_LED_SPD100			0x4
164*4882a593Smuzhiyun #define RTL8366RB_LED_SPD10			0x5
165*4882a593Smuzhiyun #define RTL8366RB_LED_SPD1000_ACT		0x6
166*4882a593Smuzhiyun #define RTL8366RB_LED_SPD100_ACT		0x7
167*4882a593Smuzhiyun #define RTL8366RB_LED_SPD10_ACT			0x8
168*4882a593Smuzhiyun #define RTL8366RB_LED_SPD100_10_ACT		0x9
169*4882a593Smuzhiyun #define RTL8366RB_LED_FIBER			0xa
170*4882a593Smuzhiyun #define RTL8366RB_LED_AN_FAULT			0xb
171*4882a593Smuzhiyun #define RTL8366RB_LED_LINK_RX			0xc
172*4882a593Smuzhiyun #define RTL8366RB_LED_LINK_TX			0xd
173*4882a593Smuzhiyun #define RTL8366RB_LED_MASTER			0xe
174*4882a593Smuzhiyun #define RTL8366RB_LED_FORCE			0xf
175*4882a593Smuzhiyun #define RTL8366RB_LED_0_1_CTRL_REG		0x0432
176*4882a593Smuzhiyun #define RTL8366RB_LED_1_OFFSET			6
177*4882a593Smuzhiyun #define RTL8366RB_LED_2_3_CTRL_REG		0x0433
178*4882a593Smuzhiyun #define RTL8366RB_LED_3_OFFSET			6
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun #define RTL8366RB_MIB_COUNT			33
181*4882a593Smuzhiyun #define RTL8366RB_GLOBAL_MIB_COUNT		1
182*4882a593Smuzhiyun #define RTL8366RB_MIB_COUNTER_PORT_OFFSET	0x0050
183*4882a593Smuzhiyun #define RTL8366RB_MIB_COUNTER_BASE		0x1000
184*4882a593Smuzhiyun #define RTL8366RB_MIB_CTRL_REG			0x13F0
185*4882a593Smuzhiyun #define RTL8366RB_MIB_CTRL_USER_MASK		0x0FFC
186*4882a593Smuzhiyun #define RTL8366RB_MIB_CTRL_BUSY_MASK		BIT(0)
187*4882a593Smuzhiyun #define RTL8366RB_MIB_CTRL_RESET_MASK		BIT(1)
188*4882a593Smuzhiyun #define RTL8366RB_MIB_CTRL_PORT_RESET(_p)	BIT(2 + (_p))
189*4882a593Smuzhiyun #define RTL8366RB_MIB_CTRL_GLOBAL_RESET		BIT(11)
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun #define RTL8366RB_PORT_VLAN_CTRL_BASE		0x0063
192*4882a593Smuzhiyun #define RTL8366RB_PORT_VLAN_CTRL_REG(_p)  \
193*4882a593Smuzhiyun 		(RTL8366RB_PORT_VLAN_CTRL_BASE + (_p) / 4)
194*4882a593Smuzhiyun #define RTL8366RB_PORT_VLAN_CTRL_MASK		0xf
195*4882a593Smuzhiyun #define RTL8366RB_PORT_VLAN_CTRL_SHIFT(_p)	(4 * ((_p) % 4))
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun #define RTL8366RB_VLAN_TABLE_READ_BASE		0x018C
198*4882a593Smuzhiyun #define RTL8366RB_VLAN_TABLE_WRITE_BASE		0x0185
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun #define RTL8366RB_TABLE_ACCESS_CTRL_REG		0x0180
201*4882a593Smuzhiyun #define RTL8366RB_TABLE_VLAN_READ_CTRL		0x0E01
202*4882a593Smuzhiyun #define RTL8366RB_TABLE_VLAN_WRITE_CTRL		0x0F01
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun #define RTL8366RB_VLAN_MC_BASE(_x)		(0x0020 + (_x) * 3)
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun #define RTL8366RB_PORT_LINK_STATUS_BASE		0x0014
207*4882a593Smuzhiyun #define RTL8366RB_PORT_STATUS_SPEED_MASK	0x0003
208*4882a593Smuzhiyun #define RTL8366RB_PORT_STATUS_DUPLEX_MASK	0x0004
209*4882a593Smuzhiyun #define RTL8366RB_PORT_STATUS_LINK_MASK		0x0010
210*4882a593Smuzhiyun #define RTL8366RB_PORT_STATUS_TXPAUSE_MASK	0x0020
211*4882a593Smuzhiyun #define RTL8366RB_PORT_STATUS_RXPAUSE_MASK	0x0040
212*4882a593Smuzhiyun #define RTL8366RB_PORT_STATUS_AN_MASK		0x0080
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun #define RTL8366RB_NUM_VLANS		16
215*4882a593Smuzhiyun #define RTL8366RB_NUM_LEDGROUPS		4
216*4882a593Smuzhiyun #define RTL8366RB_NUM_VIDS		4096
217*4882a593Smuzhiyun #define RTL8366RB_PRIORITYMAX		7
218*4882a593Smuzhiyun #define RTL8366RB_FIDMAX		7
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun #define RTL8366RB_PORT_1		BIT(0) /* In userspace port 0 */
221*4882a593Smuzhiyun #define RTL8366RB_PORT_2		BIT(1) /* In userspace port 1 */
222*4882a593Smuzhiyun #define RTL8366RB_PORT_3		BIT(2) /* In userspace port 2 */
223*4882a593Smuzhiyun #define RTL8366RB_PORT_4		BIT(3) /* In userspace port 3 */
224*4882a593Smuzhiyun #define RTL8366RB_PORT_5		BIT(4) /* In userspace port 4 */
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun #define RTL8366RB_PORT_CPU		BIT(5) /* CPU port */
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun #define RTL8366RB_PORT_ALL		(RTL8366RB_PORT_1 |	\
229*4882a593Smuzhiyun 					 RTL8366RB_PORT_2 |	\
230*4882a593Smuzhiyun 					 RTL8366RB_PORT_3 |	\
231*4882a593Smuzhiyun 					 RTL8366RB_PORT_4 |	\
232*4882a593Smuzhiyun 					 RTL8366RB_PORT_5 |	\
233*4882a593Smuzhiyun 					 RTL8366RB_PORT_CPU)
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun #define RTL8366RB_PORT_ALL_BUT_CPU	(RTL8366RB_PORT_1 |	\
236*4882a593Smuzhiyun 					 RTL8366RB_PORT_2 |	\
237*4882a593Smuzhiyun 					 RTL8366RB_PORT_3 |	\
238*4882a593Smuzhiyun 					 RTL8366RB_PORT_4 |	\
239*4882a593Smuzhiyun 					 RTL8366RB_PORT_5)
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun #define RTL8366RB_PORT_ALL_EXTERNAL	(RTL8366RB_PORT_1 |	\
242*4882a593Smuzhiyun 					 RTL8366RB_PORT_2 |	\
243*4882a593Smuzhiyun 					 RTL8366RB_PORT_3 |	\
244*4882a593Smuzhiyun 					 RTL8366RB_PORT_4)
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun #define RTL8366RB_PORT_ALL_INTERNAL	 RTL8366RB_PORT_CPU
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun /* First configuration word per member config, VID and prio */
249*4882a593Smuzhiyun #define RTL8366RB_VLAN_VID_MASK		0xfff
250*4882a593Smuzhiyun #define RTL8366RB_VLAN_PRIORITY_SHIFT	12
251*4882a593Smuzhiyun #define RTL8366RB_VLAN_PRIORITY_MASK	0x7
252*4882a593Smuzhiyun /* Second configuration word per member config, member and untagged */
253*4882a593Smuzhiyun #define RTL8366RB_VLAN_UNTAG_SHIFT	8
254*4882a593Smuzhiyun #define RTL8366RB_VLAN_UNTAG_MASK	0xff
255*4882a593Smuzhiyun #define RTL8366RB_VLAN_MEMBER_MASK	0xff
256*4882a593Smuzhiyun /* Third config word per member config, STAG currently unused */
257*4882a593Smuzhiyun #define RTL8366RB_VLAN_STAG_MBR_MASK	0xff
258*4882a593Smuzhiyun #define RTL8366RB_VLAN_STAG_MBR_SHIFT	8
259*4882a593Smuzhiyun #define RTL8366RB_VLAN_STAG_IDX_MASK	0x7
260*4882a593Smuzhiyun #define RTL8366RB_VLAN_STAG_IDX_SHIFT	5
261*4882a593Smuzhiyun #define RTL8366RB_VLAN_FID_MASK		0x7
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun /* Port ingress bandwidth control */
264*4882a593Smuzhiyun #define RTL8366RB_IB_BASE		0x0200
265*4882a593Smuzhiyun #define RTL8366RB_IB_REG(pnum)		(RTL8366RB_IB_BASE + (pnum))
266*4882a593Smuzhiyun #define RTL8366RB_IB_BDTH_MASK		0x3fff
267*4882a593Smuzhiyun #define RTL8366RB_IB_PREIFG		BIT(14)
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun /* Port egress bandwidth control */
270*4882a593Smuzhiyun #define RTL8366RB_EB_BASE		0x02d1
271*4882a593Smuzhiyun #define RTL8366RB_EB_REG(pnum)		(RTL8366RB_EB_BASE + (pnum))
272*4882a593Smuzhiyun #define RTL8366RB_EB_BDTH_MASK		0x3fff
273*4882a593Smuzhiyun #define RTL8366RB_EB_PREIFG_REG		0x02f8
274*4882a593Smuzhiyun #define RTL8366RB_EB_PREIFG		BIT(9)
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun #define RTL8366RB_BDTH_SW_MAX		1048512 /* 1048576? */
277*4882a593Smuzhiyun #define RTL8366RB_BDTH_UNIT		64
278*4882a593Smuzhiyun #define RTL8366RB_BDTH_REG_DEFAULT	16383
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun /* QOS */
281*4882a593Smuzhiyun #define RTL8366RB_QOS			BIT(15)
282*4882a593Smuzhiyun /* Include/Exclude Preamble and IFG (20 bytes). 0:Exclude, 1:Include. */
283*4882a593Smuzhiyun #define RTL8366RB_QOS_DEFAULT_PREIFG	1
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun /* Interrupt handling */
286*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_CONTROL_REG	0x0440
287*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_POLARITY	BIT(0)
288*4882a593Smuzhiyun #define RTL8366RB_P4_RGMII_LED		BIT(2)
289*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_MASK_REG	0x0441
290*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_LINK_CHGALL	GENMASK(11, 0)
291*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_ACLEXCEED	BIT(8)
292*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_STORMEXCEED	BIT(9)
293*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_P4_FIBER	BIT(12)
294*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_P4_UTP	BIT(13)
295*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_VALID	(RTL8366RB_INTERRUPT_LINK_CHGALL | \
296*4882a593Smuzhiyun 					 RTL8366RB_INTERRUPT_ACLEXCEED | \
297*4882a593Smuzhiyun 					 RTL8366RB_INTERRUPT_STORMEXCEED | \
298*4882a593Smuzhiyun 					 RTL8366RB_INTERRUPT_P4_FIBER | \
299*4882a593Smuzhiyun 					 RTL8366RB_INTERRUPT_P4_UTP)
300*4882a593Smuzhiyun #define RTL8366RB_INTERRUPT_STATUS_REG	0x0442
301*4882a593Smuzhiyun #define RTL8366RB_NUM_INTERRUPT		14 /* 0..13 */
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun /* bits 0..5 enable force when cleared */
304*4882a593Smuzhiyun #define RTL8366RB_MAC_FORCE_CTRL_REG	0x0F11
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun #define RTL8366RB_OAM_PARSER_REG	0x0F14
307*4882a593Smuzhiyun #define RTL8366RB_OAM_MULTIPLEXER_REG	0x0F15
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun #define RTL8366RB_GREEN_FEATURE_REG	0x0F51
310*4882a593Smuzhiyun #define RTL8366RB_GREEN_FEATURE_MSK	0x0007
311*4882a593Smuzhiyun #define RTL8366RB_GREEN_FEATURE_TX	BIT(0)
312*4882a593Smuzhiyun #define RTL8366RB_GREEN_FEATURE_RX	BIT(2)
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun /**
315*4882a593Smuzhiyun  * struct rtl8366rb - RTL8366RB-specific data
316*4882a593Smuzhiyun  * @max_mtu: per-port max MTU setting
317*4882a593Smuzhiyun  */
318*4882a593Smuzhiyun struct rtl8366rb {
319*4882a593Smuzhiyun 	unsigned int max_mtu[RTL8366RB_NUM_PORTS];
320*4882a593Smuzhiyun };
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = {
323*4882a593Smuzhiyun 	{ 0,  0, 4, "IfInOctets"				},
324*4882a593Smuzhiyun 	{ 0,  4, 4, "EtherStatsOctets"				},
325*4882a593Smuzhiyun 	{ 0,  8, 2, "EtherStatsUnderSizePkts"			},
326*4882a593Smuzhiyun 	{ 0, 10, 2, "EtherFragments"				},
327*4882a593Smuzhiyun 	{ 0, 12, 2, "EtherStatsPkts64Octets"			},
328*4882a593Smuzhiyun 	{ 0, 14, 2, "EtherStatsPkts65to127Octets"		},
329*4882a593Smuzhiyun 	{ 0, 16, 2, "EtherStatsPkts128to255Octets"		},
330*4882a593Smuzhiyun 	{ 0, 18, 2, "EtherStatsPkts256to511Octets"		},
331*4882a593Smuzhiyun 	{ 0, 20, 2, "EtherStatsPkts512to1023Octets"		},
332*4882a593Smuzhiyun 	{ 0, 22, 2, "EtherStatsPkts1024to1518Octets"		},
333*4882a593Smuzhiyun 	{ 0, 24, 2, "EtherOversizeStats"			},
334*4882a593Smuzhiyun 	{ 0, 26, 2, "EtherStatsJabbers"				},
335*4882a593Smuzhiyun 	{ 0, 28, 2, "IfInUcastPkts"				},
336*4882a593Smuzhiyun 	{ 0, 30, 2, "EtherStatsMulticastPkts"			},
337*4882a593Smuzhiyun 	{ 0, 32, 2, "EtherStatsBroadcastPkts"			},
338*4882a593Smuzhiyun 	{ 0, 34, 2, "EtherStatsDropEvents"			},
339*4882a593Smuzhiyun 	{ 0, 36, 2, "Dot3StatsFCSErrors"			},
340*4882a593Smuzhiyun 	{ 0, 38, 2, "Dot3StatsSymbolErrors"			},
341*4882a593Smuzhiyun 	{ 0, 40, 2, "Dot3InPauseFrames"				},
342*4882a593Smuzhiyun 	{ 0, 42, 2, "Dot3ControlInUnknownOpcodes"		},
343*4882a593Smuzhiyun 	{ 0, 44, 4, "IfOutOctets"				},
344*4882a593Smuzhiyun 	{ 0, 48, 2, "Dot3StatsSingleCollisionFrames"		},
345*4882a593Smuzhiyun 	{ 0, 50, 2, "Dot3StatMultipleCollisionFrames"		},
346*4882a593Smuzhiyun 	{ 0, 52, 2, "Dot3sDeferredTransmissions"		},
347*4882a593Smuzhiyun 	{ 0, 54, 2, "Dot3StatsLateCollisions"			},
348*4882a593Smuzhiyun 	{ 0, 56, 2, "EtherStatsCollisions"			},
349*4882a593Smuzhiyun 	{ 0, 58, 2, "Dot3StatsExcessiveCollisions"		},
350*4882a593Smuzhiyun 	{ 0, 60, 2, "Dot3OutPauseFrames"			},
351*4882a593Smuzhiyun 	{ 0, 62, 2, "Dot1dBasePortDelayExceededDiscards"	},
352*4882a593Smuzhiyun 	{ 0, 64, 2, "Dot1dTpPortInDiscards"			},
353*4882a593Smuzhiyun 	{ 0, 66, 2, "IfOutUcastPkts"				},
354*4882a593Smuzhiyun 	{ 0, 68, 2, "IfOutMulticastPkts"			},
355*4882a593Smuzhiyun 	{ 0, 70, 2, "IfOutBroadcastPkts"			},
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun 
rtl8366rb_get_mib_counter(struct realtek_smi * smi,int port,struct rtl8366_mib_counter * mib,u64 * mibvalue)358*4882a593Smuzhiyun static int rtl8366rb_get_mib_counter(struct realtek_smi *smi,
359*4882a593Smuzhiyun 				     int port,
360*4882a593Smuzhiyun 				     struct rtl8366_mib_counter *mib,
361*4882a593Smuzhiyun 				     u64 *mibvalue)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun 	u32 addr, val;
364*4882a593Smuzhiyun 	int ret;
365*4882a593Smuzhiyun 	int i;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	addr = RTL8366RB_MIB_COUNTER_BASE +
368*4882a593Smuzhiyun 		RTL8366RB_MIB_COUNTER_PORT_OFFSET * (port) +
369*4882a593Smuzhiyun 		mib->offset;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	/* Writing access counter address first
372*4882a593Smuzhiyun 	 * then ASIC will prepare 64bits counter wait for being retrived
373*4882a593Smuzhiyun 	 */
374*4882a593Smuzhiyun 	ret = regmap_write(smi->map, addr, 0); /* Write whatever */
375*4882a593Smuzhiyun 	if (ret)
376*4882a593Smuzhiyun 		return ret;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	/* Read MIB control register */
379*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_MIB_CTRL_REG, &val);
380*4882a593Smuzhiyun 	if (ret)
381*4882a593Smuzhiyun 		return -EIO;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (val & RTL8366RB_MIB_CTRL_BUSY_MASK)
384*4882a593Smuzhiyun 		return -EBUSY;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	if (val & RTL8366RB_MIB_CTRL_RESET_MASK)
387*4882a593Smuzhiyun 		return -EIO;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/* Read each individual MIB 16 bits at the time */
390*4882a593Smuzhiyun 	*mibvalue = 0;
391*4882a593Smuzhiyun 	for (i = mib->length; i > 0; i--) {
392*4882a593Smuzhiyun 		ret = regmap_read(smi->map, addr + (i - 1), &val);
393*4882a593Smuzhiyun 		if (ret)
394*4882a593Smuzhiyun 			return ret;
395*4882a593Smuzhiyun 		*mibvalue = (*mibvalue << 16) | (val & 0xFFFF);
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 	return 0;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
rtl8366rb_get_irqmask(struct irq_data * d)400*4882a593Smuzhiyun static u32 rtl8366rb_get_irqmask(struct irq_data *d)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	int line = irqd_to_hwirq(d);
403*4882a593Smuzhiyun 	u32 val;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	/* For line interrupts we combine link down in bits
406*4882a593Smuzhiyun 	 * 6..11 with link up in bits 0..5 into one interrupt.
407*4882a593Smuzhiyun 	 */
408*4882a593Smuzhiyun 	if (line < 12)
409*4882a593Smuzhiyun 		val = BIT(line) | BIT(line + 6);
410*4882a593Smuzhiyun 	else
411*4882a593Smuzhiyun 		val = BIT(line);
412*4882a593Smuzhiyun 	return val;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
rtl8366rb_mask_irq(struct irq_data * d)415*4882a593Smuzhiyun static void rtl8366rb_mask_irq(struct irq_data *d)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct realtek_smi *smi = irq_data_get_irq_chip_data(d);
418*4882a593Smuzhiyun 	int ret;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_MASK_REG,
421*4882a593Smuzhiyun 				 rtl8366rb_get_irqmask(d), 0);
422*4882a593Smuzhiyun 	if (ret)
423*4882a593Smuzhiyun 		dev_err(smi->dev, "could not mask IRQ\n");
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun 
rtl8366rb_unmask_irq(struct irq_data * d)426*4882a593Smuzhiyun static void rtl8366rb_unmask_irq(struct irq_data *d)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	struct realtek_smi *smi = irq_data_get_irq_chip_data(d);
429*4882a593Smuzhiyun 	int ret;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_MASK_REG,
432*4882a593Smuzhiyun 				 rtl8366rb_get_irqmask(d),
433*4882a593Smuzhiyun 				 rtl8366rb_get_irqmask(d));
434*4882a593Smuzhiyun 	if (ret)
435*4882a593Smuzhiyun 		dev_err(smi->dev, "could not unmask IRQ\n");
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun 
rtl8366rb_irq(int irq,void * data)438*4882a593Smuzhiyun static irqreturn_t rtl8366rb_irq(int irq, void *data)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun 	struct realtek_smi *smi = data;
441*4882a593Smuzhiyun 	u32 stat;
442*4882a593Smuzhiyun 	int ret;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	/* This clears the IRQ status register */
445*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_INTERRUPT_STATUS_REG,
446*4882a593Smuzhiyun 			  &stat);
447*4882a593Smuzhiyun 	if (ret) {
448*4882a593Smuzhiyun 		dev_err(smi->dev, "can't read interrupt status\n");
449*4882a593Smuzhiyun 		return IRQ_NONE;
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 	stat &= RTL8366RB_INTERRUPT_VALID;
452*4882a593Smuzhiyun 	if (!stat)
453*4882a593Smuzhiyun 		return IRQ_NONE;
454*4882a593Smuzhiyun 	while (stat) {
455*4882a593Smuzhiyun 		int line = __ffs(stat);
456*4882a593Smuzhiyun 		int child_irq;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 		stat &= ~BIT(line);
459*4882a593Smuzhiyun 		/* For line interrupts we combine link down in bits
460*4882a593Smuzhiyun 		 * 6..11 with link up in bits 0..5 into one interrupt.
461*4882a593Smuzhiyun 		 */
462*4882a593Smuzhiyun 		if (line < 12 && line > 5)
463*4882a593Smuzhiyun 			line -= 5;
464*4882a593Smuzhiyun 		child_irq = irq_find_mapping(smi->irqdomain, line);
465*4882a593Smuzhiyun 		handle_nested_irq(child_irq);
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 	return IRQ_HANDLED;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun static struct irq_chip rtl8366rb_irq_chip = {
471*4882a593Smuzhiyun 	.name = "RTL8366RB",
472*4882a593Smuzhiyun 	.irq_mask = rtl8366rb_mask_irq,
473*4882a593Smuzhiyun 	.irq_unmask = rtl8366rb_unmask_irq,
474*4882a593Smuzhiyun };
475*4882a593Smuzhiyun 
rtl8366rb_irq_map(struct irq_domain * domain,unsigned int irq,irq_hw_number_t hwirq)476*4882a593Smuzhiyun static int rtl8366rb_irq_map(struct irq_domain *domain, unsigned int irq,
477*4882a593Smuzhiyun 			     irq_hw_number_t hwirq)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun 	irq_set_chip_data(irq, domain->host_data);
480*4882a593Smuzhiyun 	irq_set_chip_and_handler(irq, &rtl8366rb_irq_chip, handle_simple_irq);
481*4882a593Smuzhiyun 	irq_set_nested_thread(irq, 1);
482*4882a593Smuzhiyun 	irq_set_noprobe(irq);
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	return 0;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
rtl8366rb_irq_unmap(struct irq_domain * d,unsigned int irq)487*4882a593Smuzhiyun static void rtl8366rb_irq_unmap(struct irq_domain *d, unsigned int irq)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun 	irq_set_nested_thread(irq, 0);
490*4882a593Smuzhiyun 	irq_set_chip_and_handler(irq, NULL, NULL);
491*4882a593Smuzhiyun 	irq_set_chip_data(irq, NULL);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun static const struct irq_domain_ops rtl8366rb_irqdomain_ops = {
495*4882a593Smuzhiyun 	.map = rtl8366rb_irq_map,
496*4882a593Smuzhiyun 	.unmap = rtl8366rb_irq_unmap,
497*4882a593Smuzhiyun 	.xlate  = irq_domain_xlate_onecell,
498*4882a593Smuzhiyun };
499*4882a593Smuzhiyun 
rtl8366rb_setup_cascaded_irq(struct realtek_smi * smi)500*4882a593Smuzhiyun static int rtl8366rb_setup_cascaded_irq(struct realtek_smi *smi)
501*4882a593Smuzhiyun {
502*4882a593Smuzhiyun 	struct device_node *intc;
503*4882a593Smuzhiyun 	unsigned long irq_trig;
504*4882a593Smuzhiyun 	int irq;
505*4882a593Smuzhiyun 	int ret;
506*4882a593Smuzhiyun 	u32 val;
507*4882a593Smuzhiyun 	int i;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	intc = of_get_child_by_name(smi->dev->of_node, "interrupt-controller");
510*4882a593Smuzhiyun 	if (!intc) {
511*4882a593Smuzhiyun 		dev_err(smi->dev, "missing child interrupt-controller node\n");
512*4882a593Smuzhiyun 		return -EINVAL;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 	/* RB8366RB IRQs cascade off this one */
515*4882a593Smuzhiyun 	irq = of_irq_get(intc, 0);
516*4882a593Smuzhiyun 	if (irq <= 0) {
517*4882a593Smuzhiyun 		dev_err(smi->dev, "failed to get parent IRQ\n");
518*4882a593Smuzhiyun 		ret = irq ? irq : -EINVAL;
519*4882a593Smuzhiyun 		goto out_put_node;
520*4882a593Smuzhiyun 	}
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	/* This clears the IRQ status register */
523*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_INTERRUPT_STATUS_REG,
524*4882a593Smuzhiyun 			  &val);
525*4882a593Smuzhiyun 	if (ret) {
526*4882a593Smuzhiyun 		dev_err(smi->dev, "can't read interrupt status\n");
527*4882a593Smuzhiyun 		goto out_put_node;
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	/* Fetch IRQ edge information from the descriptor */
531*4882a593Smuzhiyun 	irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
532*4882a593Smuzhiyun 	switch (irq_trig) {
533*4882a593Smuzhiyun 	case IRQF_TRIGGER_RISING:
534*4882a593Smuzhiyun 	case IRQF_TRIGGER_HIGH:
535*4882a593Smuzhiyun 		dev_info(smi->dev, "active high/rising IRQ\n");
536*4882a593Smuzhiyun 		val = 0;
537*4882a593Smuzhiyun 		break;
538*4882a593Smuzhiyun 	case IRQF_TRIGGER_FALLING:
539*4882a593Smuzhiyun 	case IRQF_TRIGGER_LOW:
540*4882a593Smuzhiyun 		dev_info(smi->dev, "active low/falling IRQ\n");
541*4882a593Smuzhiyun 		val = RTL8366RB_INTERRUPT_POLARITY;
542*4882a593Smuzhiyun 		break;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_INTERRUPT_CONTROL_REG,
545*4882a593Smuzhiyun 				 RTL8366RB_INTERRUPT_POLARITY,
546*4882a593Smuzhiyun 				 val);
547*4882a593Smuzhiyun 	if (ret) {
548*4882a593Smuzhiyun 		dev_err(smi->dev, "could not configure IRQ polarity\n");
549*4882a593Smuzhiyun 		goto out_put_node;
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(smi->dev, irq, NULL,
553*4882a593Smuzhiyun 					rtl8366rb_irq, IRQF_ONESHOT,
554*4882a593Smuzhiyun 					"RTL8366RB", smi);
555*4882a593Smuzhiyun 	if (ret) {
556*4882a593Smuzhiyun 		dev_err(smi->dev, "unable to request irq: %d\n", ret);
557*4882a593Smuzhiyun 		goto out_put_node;
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 	smi->irqdomain = irq_domain_add_linear(intc,
560*4882a593Smuzhiyun 					       RTL8366RB_NUM_INTERRUPT,
561*4882a593Smuzhiyun 					       &rtl8366rb_irqdomain_ops,
562*4882a593Smuzhiyun 					       smi);
563*4882a593Smuzhiyun 	if (!smi->irqdomain) {
564*4882a593Smuzhiyun 		dev_err(smi->dev, "failed to create IRQ domain\n");
565*4882a593Smuzhiyun 		ret = -EINVAL;
566*4882a593Smuzhiyun 		goto out_put_node;
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun 	for (i = 0; i < smi->num_ports; i++)
569*4882a593Smuzhiyun 		irq_set_parent(irq_create_mapping(smi->irqdomain, i), irq);
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun out_put_node:
572*4882a593Smuzhiyun 	of_node_put(intc);
573*4882a593Smuzhiyun 	return ret;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
rtl8366rb_set_addr(struct realtek_smi * smi)576*4882a593Smuzhiyun static int rtl8366rb_set_addr(struct realtek_smi *smi)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun 	u8 addr[ETH_ALEN];
579*4882a593Smuzhiyun 	u16 val;
580*4882a593Smuzhiyun 	int ret;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	eth_random_addr(addr);
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	dev_info(smi->dev, "set MAC: %02X:%02X:%02X:%02X:%02X:%02X\n",
585*4882a593Smuzhiyun 		 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
586*4882a593Smuzhiyun 	val = addr[0] << 8 | addr[1];
587*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_SMAR0, val);
588*4882a593Smuzhiyun 	if (ret)
589*4882a593Smuzhiyun 		return ret;
590*4882a593Smuzhiyun 	val = addr[2] << 8 | addr[3];
591*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_SMAR1, val);
592*4882a593Smuzhiyun 	if (ret)
593*4882a593Smuzhiyun 		return ret;
594*4882a593Smuzhiyun 	val = addr[4] << 8 | addr[5];
595*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_SMAR2, val);
596*4882a593Smuzhiyun 	if (ret)
597*4882a593Smuzhiyun 		return ret;
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	return 0;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun /* Found in a vendor driver */
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun /* For the "version 0" early silicon, appear in most source releases */
605*4882a593Smuzhiyun static const u16 rtl8366rb_init_jam_ver_0[] = {
606*4882a593Smuzhiyun 	0x000B, 0x0001, 0x03A6, 0x0100, 0x03A7, 0x0001, 0x02D1, 0x3FFF,
607*4882a593Smuzhiyun 	0x02D2, 0x3FFF, 0x02D3, 0x3FFF, 0x02D4, 0x3FFF, 0x02D5, 0x3FFF,
608*4882a593Smuzhiyun 	0x02D6, 0x3FFF, 0x02D7, 0x3FFF, 0x02D8, 0x3FFF, 0x022B, 0x0688,
609*4882a593Smuzhiyun 	0x022C, 0x0FAC, 0x03D0, 0x4688, 0x03D1, 0x01F5, 0x0000, 0x0830,
610*4882a593Smuzhiyun 	0x02F9, 0x0200, 0x02F7, 0x7FFF, 0x02F8, 0x03FF, 0x0080, 0x03E8,
611*4882a593Smuzhiyun 	0x0081, 0x00CE, 0x0082, 0x00DA, 0x0083, 0x0230, 0xBE0F, 0x2000,
612*4882a593Smuzhiyun 	0x0231, 0x422A, 0x0232, 0x422A, 0x0233, 0x422A, 0x0234, 0x422A,
613*4882a593Smuzhiyun 	0x0235, 0x422A, 0x0236, 0x422A, 0x0237, 0x422A, 0x0238, 0x422A,
614*4882a593Smuzhiyun 	0x0239, 0x422A, 0x023A, 0x422A, 0x023B, 0x422A, 0x023C, 0x422A,
615*4882a593Smuzhiyun 	0x023D, 0x422A, 0x023E, 0x422A, 0x023F, 0x422A, 0x0240, 0x422A,
616*4882a593Smuzhiyun 	0x0241, 0x422A, 0x0242, 0x422A, 0x0243, 0x422A, 0x0244, 0x422A,
617*4882a593Smuzhiyun 	0x0245, 0x422A, 0x0246, 0x422A, 0x0247, 0x422A, 0x0248, 0x422A,
618*4882a593Smuzhiyun 	0x0249, 0x0146, 0x024A, 0x0146, 0x024B, 0x0146, 0xBE03, 0xC961,
619*4882a593Smuzhiyun 	0x024D, 0x0146, 0x024E, 0x0146, 0x024F, 0x0146, 0x0250, 0x0146,
620*4882a593Smuzhiyun 	0xBE64, 0x0226, 0x0252, 0x0146, 0x0253, 0x0146, 0x024C, 0x0146,
621*4882a593Smuzhiyun 	0x0251, 0x0146, 0x0254, 0x0146, 0xBE62, 0x3FD0, 0x0084, 0x0320,
622*4882a593Smuzhiyun 	0x0255, 0x0146, 0x0256, 0x0146, 0x0257, 0x0146, 0x0258, 0x0146,
623*4882a593Smuzhiyun 	0x0259, 0x0146, 0x025A, 0x0146, 0x025B, 0x0146, 0x025C, 0x0146,
624*4882a593Smuzhiyun 	0x025D, 0x0146, 0x025E, 0x0146, 0x025F, 0x0146, 0x0260, 0x0146,
625*4882a593Smuzhiyun 	0x0261, 0xA23F, 0x0262, 0x0294, 0x0263, 0xA23F, 0x0264, 0x0294,
626*4882a593Smuzhiyun 	0x0265, 0xA23F, 0x0266, 0x0294, 0x0267, 0xA23F, 0x0268, 0x0294,
627*4882a593Smuzhiyun 	0x0269, 0xA23F, 0x026A, 0x0294, 0x026B, 0xA23F, 0x026C, 0x0294,
628*4882a593Smuzhiyun 	0x026D, 0xA23F, 0x026E, 0x0294, 0x026F, 0xA23F, 0x0270, 0x0294,
629*4882a593Smuzhiyun 	0x02F5, 0x0048, 0xBE09, 0x0E00, 0xBE1E, 0x0FA0, 0xBE14, 0x8448,
630*4882a593Smuzhiyun 	0xBE15, 0x1007, 0xBE4A, 0xA284, 0xC454, 0x3F0B, 0xC474, 0x3F0B,
631*4882a593Smuzhiyun 	0xBE48, 0x3672, 0xBE4B, 0x17A7, 0xBE4C, 0x0B15, 0xBE52, 0x0EDD,
632*4882a593Smuzhiyun 	0xBE49, 0x8C00, 0xBE5B, 0x785C, 0xBE5C, 0x785C, 0xBE5D, 0x785C,
633*4882a593Smuzhiyun 	0xBE61, 0x368A, 0xBE63, 0x9B84, 0xC456, 0xCC13, 0xC476, 0xCC13,
634*4882a593Smuzhiyun 	0xBE65, 0x307D, 0xBE6D, 0x0005, 0xBE6E, 0xE120, 0xBE2E, 0x7BAF,
635*4882a593Smuzhiyun };
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun /* This v1 init sequence is from Belkin F5D8235 U-Boot release */
638*4882a593Smuzhiyun static const u16 rtl8366rb_init_jam_ver_1[] = {
639*4882a593Smuzhiyun 	0x0000, 0x0830, 0x0001, 0x8000, 0x0400, 0x8130, 0xBE78, 0x3C3C,
640*4882a593Smuzhiyun 	0x0431, 0x5432, 0xBE37, 0x0CE4, 0x02FA, 0xFFDF, 0x02FB, 0xFFE0,
641*4882a593Smuzhiyun 	0xC44C, 0x1585, 0xC44C, 0x1185, 0xC44C, 0x1585, 0xC46C, 0x1585,
642*4882a593Smuzhiyun 	0xC46C, 0x1185, 0xC46C, 0x1585, 0xC451, 0x2135, 0xC471, 0x2135,
643*4882a593Smuzhiyun 	0xBE10, 0x8140, 0xBE15, 0x0007, 0xBE6E, 0xE120, 0xBE69, 0xD20F,
644*4882a593Smuzhiyun 	0xBE6B, 0x0320, 0xBE24, 0xB000, 0xBE23, 0xFF51, 0xBE22, 0xDF20,
645*4882a593Smuzhiyun 	0xBE21, 0x0140, 0xBE20, 0x00BB, 0xBE24, 0xB800, 0xBE24, 0x0000,
646*4882a593Smuzhiyun 	0xBE24, 0x7000, 0xBE23, 0xFF51, 0xBE22, 0xDF60, 0xBE21, 0x0140,
647*4882a593Smuzhiyun 	0xBE20, 0x0077, 0xBE24, 0x7800, 0xBE24, 0x0000, 0xBE2E, 0x7B7A,
648*4882a593Smuzhiyun 	0xBE36, 0x0CE4, 0x02F5, 0x0048, 0xBE77, 0x2940, 0x000A, 0x83E0,
649*4882a593Smuzhiyun 	0xBE79, 0x3C3C, 0xBE00, 0x1340,
650*4882a593Smuzhiyun };
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun /* This v2 init sequence is from Belkin F5D8235 U-Boot release */
653*4882a593Smuzhiyun static const u16 rtl8366rb_init_jam_ver_2[] = {
654*4882a593Smuzhiyun 	0x0450, 0x0000, 0x0400, 0x8130, 0x000A, 0x83ED, 0x0431, 0x5432,
655*4882a593Smuzhiyun 	0xC44F, 0x6250, 0xC46F, 0x6250, 0xC456, 0x0C14, 0xC476, 0x0C14,
656*4882a593Smuzhiyun 	0xC44C, 0x1C85, 0xC44C, 0x1885, 0xC44C, 0x1C85, 0xC46C, 0x1C85,
657*4882a593Smuzhiyun 	0xC46C, 0x1885, 0xC46C, 0x1C85, 0xC44C, 0x0885, 0xC44C, 0x0881,
658*4882a593Smuzhiyun 	0xC44C, 0x0885, 0xC46C, 0x0885, 0xC46C, 0x0881, 0xC46C, 0x0885,
659*4882a593Smuzhiyun 	0xBE2E, 0x7BA7, 0xBE36, 0x1000, 0xBE37, 0x1000, 0x8000, 0x0001,
660*4882a593Smuzhiyun 	0xBE69, 0xD50F, 0x8000, 0x0000, 0xBE69, 0xD50F, 0xBE6E, 0x0320,
661*4882a593Smuzhiyun 	0xBE77, 0x2940, 0xBE78, 0x3C3C, 0xBE79, 0x3C3C, 0xBE6E, 0xE120,
662*4882a593Smuzhiyun 	0x8000, 0x0001, 0xBE15, 0x1007, 0x8000, 0x0000, 0xBE15, 0x1007,
663*4882a593Smuzhiyun 	0xBE14, 0x0448, 0xBE1E, 0x00A0, 0xBE10, 0x8160, 0xBE10, 0x8140,
664*4882a593Smuzhiyun 	0xBE00, 0x1340, 0x0F51, 0x0010,
665*4882a593Smuzhiyun };
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun /* Appears in a DDWRT code dump */
668*4882a593Smuzhiyun static const u16 rtl8366rb_init_jam_ver_3[] = {
669*4882a593Smuzhiyun 	0x0000, 0x0830, 0x0400, 0x8130, 0x000A, 0x83ED, 0x0431, 0x5432,
670*4882a593Smuzhiyun 	0x0F51, 0x0017, 0x02F5, 0x0048, 0x02FA, 0xFFDF, 0x02FB, 0xFFE0,
671*4882a593Smuzhiyun 	0xC456, 0x0C14, 0xC476, 0x0C14, 0xC454, 0x3F8B, 0xC474, 0x3F8B,
672*4882a593Smuzhiyun 	0xC450, 0x2071, 0xC470, 0x2071, 0xC451, 0x226B, 0xC471, 0x226B,
673*4882a593Smuzhiyun 	0xC452, 0xA293, 0xC472, 0xA293, 0xC44C, 0x1585, 0xC44C, 0x1185,
674*4882a593Smuzhiyun 	0xC44C, 0x1585, 0xC46C, 0x1585, 0xC46C, 0x1185, 0xC46C, 0x1585,
675*4882a593Smuzhiyun 	0xC44C, 0x0185, 0xC44C, 0x0181, 0xC44C, 0x0185, 0xC46C, 0x0185,
676*4882a593Smuzhiyun 	0xC46C, 0x0181, 0xC46C, 0x0185, 0xBE24, 0xB000, 0xBE23, 0xFF51,
677*4882a593Smuzhiyun 	0xBE22, 0xDF20, 0xBE21, 0x0140, 0xBE20, 0x00BB, 0xBE24, 0xB800,
678*4882a593Smuzhiyun 	0xBE24, 0x0000, 0xBE24, 0x7000, 0xBE23, 0xFF51, 0xBE22, 0xDF60,
679*4882a593Smuzhiyun 	0xBE21, 0x0140, 0xBE20, 0x0077, 0xBE24, 0x7800, 0xBE24, 0x0000,
680*4882a593Smuzhiyun 	0xBE2E, 0x7BA7, 0xBE36, 0x1000, 0xBE37, 0x1000, 0x8000, 0x0001,
681*4882a593Smuzhiyun 	0xBE69, 0xD50F, 0x8000, 0x0000, 0xBE69, 0xD50F, 0xBE6B, 0x0320,
682*4882a593Smuzhiyun 	0xBE77, 0x2800, 0xBE78, 0x3C3C, 0xBE79, 0x3C3C, 0xBE6E, 0xE120,
683*4882a593Smuzhiyun 	0x8000, 0x0001, 0xBE10, 0x8140, 0x8000, 0x0000, 0xBE10, 0x8140,
684*4882a593Smuzhiyun 	0xBE15, 0x1007, 0xBE14, 0x0448, 0xBE1E, 0x00A0, 0xBE10, 0x8160,
685*4882a593Smuzhiyun 	0xBE10, 0x8140, 0xBE00, 0x1340, 0x0450, 0x0000, 0x0401, 0x0000,
686*4882a593Smuzhiyun };
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun /* Belkin F5D8235 v1, "belkin,f5d8235-v1" */
689*4882a593Smuzhiyun static const u16 rtl8366rb_init_jam_f5d8235[] = {
690*4882a593Smuzhiyun 	0x0242, 0x02BF, 0x0245, 0x02BF, 0x0248, 0x02BF, 0x024B, 0x02BF,
691*4882a593Smuzhiyun 	0x024E, 0x02BF, 0x0251, 0x02BF, 0x0254, 0x0A3F, 0x0256, 0x0A3F,
692*4882a593Smuzhiyun 	0x0258, 0x0A3F, 0x025A, 0x0A3F, 0x025C, 0x0A3F, 0x025E, 0x0A3F,
693*4882a593Smuzhiyun 	0x0263, 0x007C, 0x0100, 0x0004, 0xBE5B, 0x3500, 0x800E, 0x200F,
694*4882a593Smuzhiyun 	0xBE1D, 0x0F00, 0x8001, 0x5011, 0x800A, 0xA2F4, 0x800B, 0x17A3,
695*4882a593Smuzhiyun 	0xBE4B, 0x17A3, 0xBE41, 0x5011, 0xBE17, 0x2100, 0x8000, 0x8304,
696*4882a593Smuzhiyun 	0xBE40, 0x8304, 0xBE4A, 0xA2F4, 0x800C, 0xA8D5, 0x8014, 0x5500,
697*4882a593Smuzhiyun 	0x8015, 0x0004, 0xBE4C, 0xA8D5, 0xBE59, 0x0008, 0xBE09, 0x0E00,
698*4882a593Smuzhiyun 	0xBE36, 0x1036, 0xBE37, 0x1036, 0x800D, 0x00FF, 0xBE4D, 0x00FF,
699*4882a593Smuzhiyun };
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun /* DGN3500, "netgear,dgn3500", "netgear,dgn3500b" */
702*4882a593Smuzhiyun static const u16 rtl8366rb_init_jam_dgn3500[] = {
703*4882a593Smuzhiyun 	0x0000, 0x0830, 0x0400, 0x8130, 0x000A, 0x83ED, 0x0F51, 0x0017,
704*4882a593Smuzhiyun 	0x02F5, 0x0048, 0x02FA, 0xFFDF, 0x02FB, 0xFFE0, 0x0450, 0x0000,
705*4882a593Smuzhiyun 	0x0401, 0x0000, 0x0431, 0x0960,
706*4882a593Smuzhiyun };
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun /* This jam table activates "green ethernet", which means low power mode
709*4882a593Smuzhiyun  * and is claimed to detect the cable length and not use more power than
710*4882a593Smuzhiyun  * necessary, and the ports should enter power saving mode 10 seconds after
711*4882a593Smuzhiyun  * a cable is disconnected. Seems to always be the same.
712*4882a593Smuzhiyun  */
713*4882a593Smuzhiyun static const u16 rtl8366rb_green_jam[][2] = {
714*4882a593Smuzhiyun 	{0xBE78, 0x323C}, {0xBE77, 0x5000}, {0xBE2E, 0x7BA7},
715*4882a593Smuzhiyun 	{0xBE59, 0x3459}, {0xBE5A, 0x745A}, {0xBE5B, 0x785C},
716*4882a593Smuzhiyun 	{0xBE5C, 0x785C}, {0xBE6E, 0xE120}, {0xBE79, 0x323C},
717*4882a593Smuzhiyun };
718*4882a593Smuzhiyun 
rtl8366rb_setup(struct dsa_switch * ds)719*4882a593Smuzhiyun static int rtl8366rb_setup(struct dsa_switch *ds)
720*4882a593Smuzhiyun {
721*4882a593Smuzhiyun 	struct realtek_smi *smi = ds->priv;
722*4882a593Smuzhiyun 	const u16 *jam_table;
723*4882a593Smuzhiyun 	struct rtl8366rb *rb;
724*4882a593Smuzhiyun 	u32 chip_ver = 0;
725*4882a593Smuzhiyun 	u32 chip_id = 0;
726*4882a593Smuzhiyun 	int jam_size;
727*4882a593Smuzhiyun 	u32 val;
728*4882a593Smuzhiyun 	int ret;
729*4882a593Smuzhiyun 	int i;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	rb = smi->chip_data;
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_CHIP_ID_REG, &chip_id);
734*4882a593Smuzhiyun 	if (ret) {
735*4882a593Smuzhiyun 		dev_err(smi->dev, "unable to read chip id\n");
736*4882a593Smuzhiyun 		return ret;
737*4882a593Smuzhiyun 	}
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	switch (chip_id) {
740*4882a593Smuzhiyun 	case RTL8366RB_CHIP_ID_8366:
741*4882a593Smuzhiyun 		break;
742*4882a593Smuzhiyun 	default:
743*4882a593Smuzhiyun 		dev_err(smi->dev, "unknown chip id (%04x)\n", chip_id);
744*4882a593Smuzhiyun 		return -ENODEV;
745*4882a593Smuzhiyun 	}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_CHIP_VERSION_CTRL_REG,
748*4882a593Smuzhiyun 			  &chip_ver);
749*4882a593Smuzhiyun 	if (ret) {
750*4882a593Smuzhiyun 		dev_err(smi->dev, "unable to read chip version\n");
751*4882a593Smuzhiyun 		return ret;
752*4882a593Smuzhiyun 	}
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	dev_info(smi->dev, "RTL%04x ver %u chip found\n",
755*4882a593Smuzhiyun 		 chip_id, chip_ver & RTL8366RB_CHIP_VERSION_MASK);
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	/* Do the init dance using the right jam table */
758*4882a593Smuzhiyun 	switch (chip_ver) {
759*4882a593Smuzhiyun 	case 0:
760*4882a593Smuzhiyun 		jam_table = rtl8366rb_init_jam_ver_0;
761*4882a593Smuzhiyun 		jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_0);
762*4882a593Smuzhiyun 		break;
763*4882a593Smuzhiyun 	case 1:
764*4882a593Smuzhiyun 		jam_table = rtl8366rb_init_jam_ver_1;
765*4882a593Smuzhiyun 		jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_1);
766*4882a593Smuzhiyun 		break;
767*4882a593Smuzhiyun 	case 2:
768*4882a593Smuzhiyun 		jam_table = rtl8366rb_init_jam_ver_2;
769*4882a593Smuzhiyun 		jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_2);
770*4882a593Smuzhiyun 		break;
771*4882a593Smuzhiyun 	default:
772*4882a593Smuzhiyun 		jam_table = rtl8366rb_init_jam_ver_3;
773*4882a593Smuzhiyun 		jam_size = ARRAY_SIZE(rtl8366rb_init_jam_ver_3);
774*4882a593Smuzhiyun 		break;
775*4882a593Smuzhiyun 	}
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	/* Special jam tables for special routers
778*4882a593Smuzhiyun 	 * TODO: are these necessary? Maintainers, please test
779*4882a593Smuzhiyun 	 * without them, using just the off-the-shelf tables.
780*4882a593Smuzhiyun 	 */
781*4882a593Smuzhiyun 	if (of_machine_is_compatible("belkin,f5d8235-v1")) {
782*4882a593Smuzhiyun 		jam_table = rtl8366rb_init_jam_f5d8235;
783*4882a593Smuzhiyun 		jam_size = ARRAY_SIZE(rtl8366rb_init_jam_f5d8235);
784*4882a593Smuzhiyun 	}
785*4882a593Smuzhiyun 	if (of_machine_is_compatible("netgear,dgn3500") ||
786*4882a593Smuzhiyun 	    of_machine_is_compatible("netgear,dgn3500b")) {
787*4882a593Smuzhiyun 		jam_table = rtl8366rb_init_jam_dgn3500;
788*4882a593Smuzhiyun 		jam_size = ARRAY_SIZE(rtl8366rb_init_jam_dgn3500);
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	i = 0;
792*4882a593Smuzhiyun 	while (i < jam_size) {
793*4882a593Smuzhiyun 		if ((jam_table[i] & 0xBE00) == 0xBE00) {
794*4882a593Smuzhiyun 			ret = regmap_read(smi->map,
795*4882a593Smuzhiyun 					  RTL8366RB_PHY_ACCESS_BUSY_REG,
796*4882a593Smuzhiyun 					  &val);
797*4882a593Smuzhiyun 			if (ret)
798*4882a593Smuzhiyun 				return ret;
799*4882a593Smuzhiyun 			if (!(val & RTL8366RB_PHY_INT_BUSY)) {
800*4882a593Smuzhiyun 				ret = regmap_write(smi->map,
801*4882a593Smuzhiyun 						RTL8366RB_PHY_ACCESS_CTRL_REG,
802*4882a593Smuzhiyun 						RTL8366RB_PHY_CTRL_WRITE);
803*4882a593Smuzhiyun 				if (ret)
804*4882a593Smuzhiyun 					return ret;
805*4882a593Smuzhiyun 			}
806*4882a593Smuzhiyun 		}
807*4882a593Smuzhiyun 		dev_dbg(smi->dev, "jam %04x into register %04x\n",
808*4882a593Smuzhiyun 			jam_table[i + 1],
809*4882a593Smuzhiyun 			jam_table[i]);
810*4882a593Smuzhiyun 		ret = regmap_write(smi->map,
811*4882a593Smuzhiyun 				   jam_table[i],
812*4882a593Smuzhiyun 				   jam_table[i + 1]);
813*4882a593Smuzhiyun 		if (ret)
814*4882a593Smuzhiyun 			return ret;
815*4882a593Smuzhiyun 		i += 2;
816*4882a593Smuzhiyun 	}
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	/* Set up the "green ethernet" feature */
819*4882a593Smuzhiyun 	i = 0;
820*4882a593Smuzhiyun 	while (i < ARRAY_SIZE(rtl8366rb_green_jam)) {
821*4882a593Smuzhiyun 		ret = regmap_read(smi->map, RTL8366RB_PHY_ACCESS_BUSY_REG,
822*4882a593Smuzhiyun 				  &val);
823*4882a593Smuzhiyun 		if (ret)
824*4882a593Smuzhiyun 			return ret;
825*4882a593Smuzhiyun 		if (!(val & RTL8366RB_PHY_INT_BUSY)) {
826*4882a593Smuzhiyun 			ret = regmap_write(smi->map,
827*4882a593Smuzhiyun 					   RTL8366RB_PHY_ACCESS_CTRL_REG,
828*4882a593Smuzhiyun 					   RTL8366RB_PHY_CTRL_WRITE);
829*4882a593Smuzhiyun 			if (ret)
830*4882a593Smuzhiyun 				return ret;
831*4882a593Smuzhiyun 			ret = regmap_write(smi->map,
832*4882a593Smuzhiyun 					   rtl8366rb_green_jam[i][0],
833*4882a593Smuzhiyun 					   rtl8366rb_green_jam[i][1]);
834*4882a593Smuzhiyun 			if (ret)
835*4882a593Smuzhiyun 				return ret;
836*4882a593Smuzhiyun 			i++;
837*4882a593Smuzhiyun 		}
838*4882a593Smuzhiyun 	}
839*4882a593Smuzhiyun 	ret = regmap_write(smi->map,
840*4882a593Smuzhiyun 			   RTL8366RB_GREEN_FEATURE_REG,
841*4882a593Smuzhiyun 			   (chip_ver == 1) ? 0x0007 : 0x0003);
842*4882a593Smuzhiyun 	if (ret)
843*4882a593Smuzhiyun 		return ret;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	/* Vendor driver sets 0x240 in registers 0xc and 0xd (undocumented) */
846*4882a593Smuzhiyun 	ret = regmap_write(smi->map, 0x0c, 0x240);
847*4882a593Smuzhiyun 	if (ret)
848*4882a593Smuzhiyun 		return ret;
849*4882a593Smuzhiyun 	ret = regmap_write(smi->map, 0x0d, 0x240);
850*4882a593Smuzhiyun 	if (ret)
851*4882a593Smuzhiyun 		return ret;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	/* Set some random MAC address */
854*4882a593Smuzhiyun 	ret = rtl8366rb_set_addr(smi);
855*4882a593Smuzhiyun 	if (ret)
856*4882a593Smuzhiyun 		return ret;
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	/* Enable CPU port with custom DSA tag 8899.
859*4882a593Smuzhiyun 	 *
860*4882a593Smuzhiyun 	 * If you set RTL8368RB_CPU_NO_TAG (bit 15) in this registers
861*4882a593Smuzhiyun 	 * the custom tag is turned off.
862*4882a593Smuzhiyun 	 */
863*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8368RB_CPU_CTRL_REG,
864*4882a593Smuzhiyun 				 0xFFFF,
865*4882a593Smuzhiyun 				 BIT(smi->cpu_port));
866*4882a593Smuzhiyun 	if (ret)
867*4882a593Smuzhiyun 		return ret;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	/* Make sure we default-enable the fixed CPU port */
870*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PECR,
871*4882a593Smuzhiyun 				 BIT(smi->cpu_port),
872*4882a593Smuzhiyun 				 0);
873*4882a593Smuzhiyun 	if (ret)
874*4882a593Smuzhiyun 		return ret;
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun 	/* Set maximum packet length to 1536 bytes */
877*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_SGCR,
878*4882a593Smuzhiyun 				 RTL8366RB_SGCR_MAX_LENGTH_MASK,
879*4882a593Smuzhiyun 				 RTL8366RB_SGCR_MAX_LENGTH_1536);
880*4882a593Smuzhiyun 	if (ret)
881*4882a593Smuzhiyun 		return ret;
882*4882a593Smuzhiyun 	for (i = 0; i < RTL8366RB_NUM_PORTS; i++)
883*4882a593Smuzhiyun 		/* layer 2 size, see rtl8366rb_change_mtu() */
884*4882a593Smuzhiyun 		rb->max_mtu[i] = 1532;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	/* Enable learning for all ports */
887*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0);
888*4882a593Smuzhiyun 	if (ret)
889*4882a593Smuzhiyun 		return ret;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	/* Enable auto ageing for all ports */
892*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_SSCR1, 0);
893*4882a593Smuzhiyun 	if (ret)
894*4882a593Smuzhiyun 		return ret;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	/* Port 4 setup: this enables Port 4, usually the WAN port,
897*4882a593Smuzhiyun 	 * common PHY IO mode is apparently mode 0, and this is not what
898*4882a593Smuzhiyun 	 * the port is initialized to. There is no explanation of the
899*4882a593Smuzhiyun 	 * IO modes in the Realtek source code, if your WAN port is
900*4882a593Smuzhiyun 	 * connected to something exotic such as fiber, then this might
901*4882a593Smuzhiyun 	 * be worth experimenting with.
902*4882a593Smuzhiyun 	 */
903*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PMC0,
904*4882a593Smuzhiyun 				 RTL8366RB_PMC0_P4_IOMODE_MASK,
905*4882a593Smuzhiyun 				 0 << RTL8366RB_PMC0_P4_IOMODE_SHIFT);
906*4882a593Smuzhiyun 	if (ret)
907*4882a593Smuzhiyun 		return ret;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	/* Discard VLAN tagged packets if the port is not a member of
910*4882a593Smuzhiyun 	 * the VLAN with which the packets is associated.
911*4882a593Smuzhiyun 	 */
912*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG,
913*4882a593Smuzhiyun 			   RTL8366RB_PORT_ALL);
914*4882a593Smuzhiyun 	if (ret)
915*4882a593Smuzhiyun 		return ret;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	/* Don't drop packets whose DA has not been learned */
918*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_SSCR2,
919*4882a593Smuzhiyun 				 RTL8366RB_SSCR2_DROP_UNKNOWN_DA, 0);
920*4882a593Smuzhiyun 	if (ret)
921*4882a593Smuzhiyun 		return ret;
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	/* Set blinking, TODO: make this configurable */
924*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_LED_BLINKRATE_REG,
925*4882a593Smuzhiyun 				 RTL8366RB_LED_BLINKRATE_MASK,
926*4882a593Smuzhiyun 				 RTL8366RB_LED_BLINKRATE_56MS);
927*4882a593Smuzhiyun 	if (ret)
928*4882a593Smuzhiyun 		return ret;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	/* Set up LED activity:
931*4882a593Smuzhiyun 	 * Each port has 4 LEDs, we configure all ports to the same
932*4882a593Smuzhiyun 	 * behaviour (no individual config) but we can set up each
933*4882a593Smuzhiyun 	 * LED separately.
934*4882a593Smuzhiyun 	 */
935*4882a593Smuzhiyun 	if (smi->leds_disabled) {
936*4882a593Smuzhiyun 		/* Turn everything off */
937*4882a593Smuzhiyun 		regmap_update_bits(smi->map,
938*4882a593Smuzhiyun 				   RTL8366RB_LED_0_1_CTRL_REG,
939*4882a593Smuzhiyun 				   0x0FFF, 0);
940*4882a593Smuzhiyun 		regmap_update_bits(smi->map,
941*4882a593Smuzhiyun 				   RTL8366RB_LED_2_3_CTRL_REG,
942*4882a593Smuzhiyun 				   0x0FFF, 0);
943*4882a593Smuzhiyun 		regmap_update_bits(smi->map,
944*4882a593Smuzhiyun 				   RTL8366RB_INTERRUPT_CONTROL_REG,
945*4882a593Smuzhiyun 				   RTL8366RB_P4_RGMII_LED,
946*4882a593Smuzhiyun 				   0);
947*4882a593Smuzhiyun 		val = RTL8366RB_LED_OFF;
948*4882a593Smuzhiyun 	} else {
949*4882a593Smuzhiyun 		/* TODO: make this configurable per LED */
950*4882a593Smuzhiyun 		val = RTL8366RB_LED_FORCE;
951*4882a593Smuzhiyun 	}
952*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
953*4882a593Smuzhiyun 		ret = regmap_update_bits(smi->map,
954*4882a593Smuzhiyun 					 RTL8366RB_LED_CTRL_REG,
955*4882a593Smuzhiyun 					 0xf << (i * 4),
956*4882a593Smuzhiyun 					 val << (i * 4));
957*4882a593Smuzhiyun 		if (ret)
958*4882a593Smuzhiyun 			return ret;
959*4882a593Smuzhiyun 	}
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	ret = rtl8366_init_vlan(smi);
962*4882a593Smuzhiyun 	if (ret)
963*4882a593Smuzhiyun 		return ret;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	ret = rtl8366rb_setup_cascaded_irq(smi);
966*4882a593Smuzhiyun 	if (ret)
967*4882a593Smuzhiyun 		dev_info(smi->dev, "no interrupt support\n");
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	ret = realtek_smi_setup_mdio(smi);
970*4882a593Smuzhiyun 	if (ret) {
971*4882a593Smuzhiyun 		dev_info(smi->dev, "could not set up MDIO bus\n");
972*4882a593Smuzhiyun 		return -ENODEV;
973*4882a593Smuzhiyun 	}
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 	return 0;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun 
rtl8366_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol mp)978*4882a593Smuzhiyun static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds,
979*4882a593Smuzhiyun 						      int port,
980*4882a593Smuzhiyun 						      enum dsa_tag_protocol mp)
981*4882a593Smuzhiyun {
982*4882a593Smuzhiyun 	/* This switch uses the 4 byte protocol A Realtek DSA tag */
983*4882a593Smuzhiyun 	return DSA_TAG_PROTO_RTL4_A;
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun static void
rtl8366rb_mac_link_up(struct dsa_switch * ds,int port,unsigned int mode,phy_interface_t interface,struct phy_device * phydev,int speed,int duplex,bool tx_pause,bool rx_pause)987*4882a593Smuzhiyun rtl8366rb_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode,
988*4882a593Smuzhiyun 		      phy_interface_t interface, struct phy_device *phydev,
989*4882a593Smuzhiyun 		      int speed, int duplex, bool tx_pause, bool rx_pause)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun 	struct realtek_smi *smi = ds->priv;
992*4882a593Smuzhiyun 	int ret;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	if (port != smi->cpu_port)
995*4882a593Smuzhiyun 		return;
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	dev_dbg(smi->dev, "MAC link up on CPU port (%d)\n", port);
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	/* Force the fixed CPU port into 1Gbit mode, no autonegotiation */
1000*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_MAC_FORCE_CTRL_REG,
1001*4882a593Smuzhiyun 				 BIT(port), BIT(port));
1002*4882a593Smuzhiyun 	if (ret) {
1003*4882a593Smuzhiyun 		dev_err(smi->dev, "failed to force 1Gbit on CPU port\n");
1004*4882a593Smuzhiyun 		return;
1005*4882a593Smuzhiyun 	}
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PAACR2,
1008*4882a593Smuzhiyun 				 0xFF00U,
1009*4882a593Smuzhiyun 				 RTL8366RB_PAACR_CPU_PORT << 8);
1010*4882a593Smuzhiyun 	if (ret) {
1011*4882a593Smuzhiyun 		dev_err(smi->dev, "failed to set PAACR on CPU port\n");
1012*4882a593Smuzhiyun 		return;
1013*4882a593Smuzhiyun 	}
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	/* Enable the CPU port */
1016*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port),
1017*4882a593Smuzhiyun 				 0);
1018*4882a593Smuzhiyun 	if (ret) {
1019*4882a593Smuzhiyun 		dev_err(smi->dev, "failed to enable the CPU port\n");
1020*4882a593Smuzhiyun 		return;
1021*4882a593Smuzhiyun 	}
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun static void
rtl8366rb_mac_link_down(struct dsa_switch * ds,int port,unsigned int mode,phy_interface_t interface)1025*4882a593Smuzhiyun rtl8366rb_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
1026*4882a593Smuzhiyun 			phy_interface_t interface)
1027*4882a593Smuzhiyun {
1028*4882a593Smuzhiyun 	struct realtek_smi *smi = ds->priv;
1029*4882a593Smuzhiyun 	int ret;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	if (port != smi->cpu_port)
1032*4882a593Smuzhiyun 		return;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	dev_dbg(smi->dev, "MAC link down on CPU port (%d)\n", port);
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 	/* Disable the CPU port */
1037*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port),
1038*4882a593Smuzhiyun 				 BIT(port));
1039*4882a593Smuzhiyun 	if (ret) {
1040*4882a593Smuzhiyun 		dev_err(smi->dev, "failed to disable the CPU port\n");
1041*4882a593Smuzhiyun 		return;
1042*4882a593Smuzhiyun 	}
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun 
rb8366rb_set_port_led(struct realtek_smi * smi,int port,bool enable)1045*4882a593Smuzhiyun static void rb8366rb_set_port_led(struct realtek_smi *smi,
1046*4882a593Smuzhiyun 				  int port, bool enable)
1047*4882a593Smuzhiyun {
1048*4882a593Smuzhiyun 	u16 val = enable ? 0x3f : 0;
1049*4882a593Smuzhiyun 	int ret;
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 	if (smi->leds_disabled)
1052*4882a593Smuzhiyun 		return;
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	switch (port) {
1055*4882a593Smuzhiyun 	case 0:
1056*4882a593Smuzhiyun 		ret = regmap_update_bits(smi->map,
1057*4882a593Smuzhiyun 					 RTL8366RB_LED_0_1_CTRL_REG,
1058*4882a593Smuzhiyun 					 0x3F, val);
1059*4882a593Smuzhiyun 		break;
1060*4882a593Smuzhiyun 	case 1:
1061*4882a593Smuzhiyun 		ret = regmap_update_bits(smi->map,
1062*4882a593Smuzhiyun 					 RTL8366RB_LED_0_1_CTRL_REG,
1063*4882a593Smuzhiyun 					 0x3F << RTL8366RB_LED_1_OFFSET,
1064*4882a593Smuzhiyun 					 val << RTL8366RB_LED_1_OFFSET);
1065*4882a593Smuzhiyun 		break;
1066*4882a593Smuzhiyun 	case 2:
1067*4882a593Smuzhiyun 		ret = regmap_update_bits(smi->map,
1068*4882a593Smuzhiyun 					 RTL8366RB_LED_2_3_CTRL_REG,
1069*4882a593Smuzhiyun 					 0x3F, val);
1070*4882a593Smuzhiyun 		break;
1071*4882a593Smuzhiyun 	case 3:
1072*4882a593Smuzhiyun 		ret = regmap_update_bits(smi->map,
1073*4882a593Smuzhiyun 					 RTL8366RB_LED_2_3_CTRL_REG,
1074*4882a593Smuzhiyun 					 0x3F << RTL8366RB_LED_3_OFFSET,
1075*4882a593Smuzhiyun 					 val << RTL8366RB_LED_3_OFFSET);
1076*4882a593Smuzhiyun 		break;
1077*4882a593Smuzhiyun 	case 4:
1078*4882a593Smuzhiyun 		ret = regmap_update_bits(smi->map,
1079*4882a593Smuzhiyun 					 RTL8366RB_INTERRUPT_CONTROL_REG,
1080*4882a593Smuzhiyun 					 RTL8366RB_P4_RGMII_LED,
1081*4882a593Smuzhiyun 					 enable ? RTL8366RB_P4_RGMII_LED : 0);
1082*4882a593Smuzhiyun 		break;
1083*4882a593Smuzhiyun 	default:
1084*4882a593Smuzhiyun 		dev_err(smi->dev, "no LED for port %d\n", port);
1085*4882a593Smuzhiyun 		return;
1086*4882a593Smuzhiyun 	}
1087*4882a593Smuzhiyun 	if (ret)
1088*4882a593Smuzhiyun 		dev_err(smi->dev, "error updating LED on port %d\n", port);
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun static int
rtl8366rb_port_enable(struct dsa_switch * ds,int port,struct phy_device * phy)1092*4882a593Smuzhiyun rtl8366rb_port_enable(struct dsa_switch *ds, int port,
1093*4882a593Smuzhiyun 		      struct phy_device *phy)
1094*4882a593Smuzhiyun {
1095*4882a593Smuzhiyun 	struct realtek_smi *smi = ds->priv;
1096*4882a593Smuzhiyun 	int ret;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	dev_dbg(smi->dev, "enable port %d\n", port);
1099*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port),
1100*4882a593Smuzhiyun 				 0);
1101*4882a593Smuzhiyun 	if (ret)
1102*4882a593Smuzhiyun 		return ret;
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	rb8366rb_set_port_led(smi, port, true);
1105*4882a593Smuzhiyun 	return 0;
1106*4882a593Smuzhiyun }
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun static void
rtl8366rb_port_disable(struct dsa_switch * ds,int port)1109*4882a593Smuzhiyun rtl8366rb_port_disable(struct dsa_switch *ds, int port)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun 	struct realtek_smi *smi = ds->priv;
1112*4882a593Smuzhiyun 	int ret;
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun 	dev_dbg(smi->dev, "disable port %d\n", port);
1115*4882a593Smuzhiyun 	ret = regmap_update_bits(smi->map, RTL8366RB_PECR, BIT(port),
1116*4882a593Smuzhiyun 				 BIT(port));
1117*4882a593Smuzhiyun 	if (ret)
1118*4882a593Smuzhiyun 		return;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	rb8366rb_set_port_led(smi, port, false);
1121*4882a593Smuzhiyun }
1122*4882a593Smuzhiyun 
rtl8366rb_change_mtu(struct dsa_switch * ds,int port,int new_mtu)1123*4882a593Smuzhiyun static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
1124*4882a593Smuzhiyun {
1125*4882a593Smuzhiyun 	struct realtek_smi *smi = ds->priv;
1126*4882a593Smuzhiyun 	struct rtl8366rb *rb;
1127*4882a593Smuzhiyun 	unsigned int max_mtu;
1128*4882a593Smuzhiyun 	u32 len;
1129*4882a593Smuzhiyun 	int i;
1130*4882a593Smuzhiyun 
1131*4882a593Smuzhiyun 	/* Cache the per-port MTU setting */
1132*4882a593Smuzhiyun 	rb = smi->chip_data;
1133*4882a593Smuzhiyun 	rb->max_mtu[port] = new_mtu;
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	/* Roof out the MTU for the entire switch to the greatest
1136*4882a593Smuzhiyun 	 * common denominator: the biggest set for any one port will
1137*4882a593Smuzhiyun 	 * be the biggest MTU for the switch.
1138*4882a593Smuzhiyun 	 *
1139*4882a593Smuzhiyun 	 * The first setting, 1522 bytes, is max IP packet 1500 bytes,
1140*4882a593Smuzhiyun 	 * plus ethernet header, 1518 bytes, plus CPU tag, 4 bytes.
1141*4882a593Smuzhiyun 	 * This function should consider the parameter an SDU, so the
1142*4882a593Smuzhiyun 	 * MTU passed for this setting is 1518 bytes. The same logic
1143*4882a593Smuzhiyun 	 * of subtracting the DSA tag of 4 bytes apply to the other
1144*4882a593Smuzhiyun 	 * settings.
1145*4882a593Smuzhiyun 	 */
1146*4882a593Smuzhiyun 	max_mtu = 1518;
1147*4882a593Smuzhiyun 	for (i = 0; i < RTL8366RB_NUM_PORTS; i++) {
1148*4882a593Smuzhiyun 		if (rb->max_mtu[i] > max_mtu)
1149*4882a593Smuzhiyun 			max_mtu = rb->max_mtu[i];
1150*4882a593Smuzhiyun 	}
1151*4882a593Smuzhiyun 	if (max_mtu <= 1518)
1152*4882a593Smuzhiyun 		len = RTL8366RB_SGCR_MAX_LENGTH_1522;
1153*4882a593Smuzhiyun 	else if (max_mtu > 1518 && max_mtu <= 1532)
1154*4882a593Smuzhiyun 		len = RTL8366RB_SGCR_MAX_LENGTH_1536;
1155*4882a593Smuzhiyun 	else if (max_mtu > 1532 && max_mtu <= 1548)
1156*4882a593Smuzhiyun 		len = RTL8366RB_SGCR_MAX_LENGTH_1552;
1157*4882a593Smuzhiyun 	else
1158*4882a593Smuzhiyun 		len = RTL8366RB_SGCR_MAX_LENGTH_16000;
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	return regmap_update_bits(smi->map, RTL8366RB_SGCR,
1161*4882a593Smuzhiyun 				  RTL8366RB_SGCR_MAX_LENGTH_MASK,
1162*4882a593Smuzhiyun 				  len);
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun 
rtl8366rb_max_mtu(struct dsa_switch * ds,int port)1165*4882a593Smuzhiyun static int rtl8366rb_max_mtu(struct dsa_switch *ds, int port)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun 	/* The max MTU is 16000 bytes, so we subtract the CPU tag
1168*4882a593Smuzhiyun 	 * and the max presented to the system is 15996 bytes.
1169*4882a593Smuzhiyun 	 */
1170*4882a593Smuzhiyun 	return 15996;
1171*4882a593Smuzhiyun }
1172*4882a593Smuzhiyun 
rtl8366rb_get_vlan_4k(struct realtek_smi * smi,u32 vid,struct rtl8366_vlan_4k * vlan4k)1173*4882a593Smuzhiyun static int rtl8366rb_get_vlan_4k(struct realtek_smi *smi, u32 vid,
1174*4882a593Smuzhiyun 				 struct rtl8366_vlan_4k *vlan4k)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun 	u32 data[3];
1177*4882a593Smuzhiyun 	int ret;
1178*4882a593Smuzhiyun 	int i;
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k));
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	if (vid >= RTL8366RB_NUM_VIDS)
1183*4882a593Smuzhiyun 		return -EINVAL;
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	/* write VID */
1186*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_VLAN_TABLE_WRITE_BASE,
1187*4882a593Smuzhiyun 			   vid & RTL8366RB_VLAN_VID_MASK);
1188*4882a593Smuzhiyun 	if (ret)
1189*4882a593Smuzhiyun 		return ret;
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	/* write table access control word */
1192*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_TABLE_ACCESS_CTRL_REG,
1193*4882a593Smuzhiyun 			   RTL8366RB_TABLE_VLAN_READ_CTRL);
1194*4882a593Smuzhiyun 	if (ret)
1195*4882a593Smuzhiyun 		return ret;
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
1198*4882a593Smuzhiyun 		ret = regmap_read(smi->map,
1199*4882a593Smuzhiyun 				  RTL8366RB_VLAN_TABLE_READ_BASE + i,
1200*4882a593Smuzhiyun 				  &data[i]);
1201*4882a593Smuzhiyun 		if (ret)
1202*4882a593Smuzhiyun 			return ret;
1203*4882a593Smuzhiyun 	}
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	vlan4k->vid = vid;
1206*4882a593Smuzhiyun 	vlan4k->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) &
1207*4882a593Smuzhiyun 			RTL8366RB_VLAN_UNTAG_MASK;
1208*4882a593Smuzhiyun 	vlan4k->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK;
1209*4882a593Smuzhiyun 	vlan4k->fid = data[2] & RTL8366RB_VLAN_FID_MASK;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	return 0;
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun 
rtl8366rb_set_vlan_4k(struct realtek_smi * smi,const struct rtl8366_vlan_4k * vlan4k)1214*4882a593Smuzhiyun static int rtl8366rb_set_vlan_4k(struct realtek_smi *smi,
1215*4882a593Smuzhiyun 				 const struct rtl8366_vlan_4k *vlan4k)
1216*4882a593Smuzhiyun {
1217*4882a593Smuzhiyun 	u32 data[3];
1218*4882a593Smuzhiyun 	int ret;
1219*4882a593Smuzhiyun 	int i;
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	if (vlan4k->vid >= RTL8366RB_NUM_VIDS ||
1222*4882a593Smuzhiyun 	    vlan4k->member > RTL8366RB_VLAN_MEMBER_MASK ||
1223*4882a593Smuzhiyun 	    vlan4k->untag > RTL8366RB_VLAN_UNTAG_MASK ||
1224*4882a593Smuzhiyun 	    vlan4k->fid > RTL8366RB_FIDMAX)
1225*4882a593Smuzhiyun 		return -EINVAL;
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 	data[0] = vlan4k->vid & RTL8366RB_VLAN_VID_MASK;
1228*4882a593Smuzhiyun 	data[1] = (vlan4k->member & RTL8366RB_VLAN_MEMBER_MASK) |
1229*4882a593Smuzhiyun 		  ((vlan4k->untag & RTL8366RB_VLAN_UNTAG_MASK) <<
1230*4882a593Smuzhiyun 			RTL8366RB_VLAN_UNTAG_SHIFT);
1231*4882a593Smuzhiyun 	data[2] = vlan4k->fid & RTL8366RB_VLAN_FID_MASK;
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
1234*4882a593Smuzhiyun 		ret = regmap_write(smi->map,
1235*4882a593Smuzhiyun 				   RTL8366RB_VLAN_TABLE_WRITE_BASE + i,
1236*4882a593Smuzhiyun 				   data[i]);
1237*4882a593Smuzhiyun 		if (ret)
1238*4882a593Smuzhiyun 			return ret;
1239*4882a593Smuzhiyun 	}
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	/* write table access control word */
1242*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_TABLE_ACCESS_CTRL_REG,
1243*4882a593Smuzhiyun 			   RTL8366RB_TABLE_VLAN_WRITE_CTRL);
1244*4882a593Smuzhiyun 
1245*4882a593Smuzhiyun 	return ret;
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun 
rtl8366rb_get_vlan_mc(struct realtek_smi * smi,u32 index,struct rtl8366_vlan_mc * vlanmc)1248*4882a593Smuzhiyun static int rtl8366rb_get_vlan_mc(struct realtek_smi *smi, u32 index,
1249*4882a593Smuzhiyun 				 struct rtl8366_vlan_mc *vlanmc)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	u32 data[3];
1252*4882a593Smuzhiyun 	int ret;
1253*4882a593Smuzhiyun 	int i;
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc));
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	if (index >= RTL8366RB_NUM_VLANS)
1258*4882a593Smuzhiyun 		return -EINVAL;
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
1261*4882a593Smuzhiyun 		ret = regmap_read(smi->map,
1262*4882a593Smuzhiyun 				  RTL8366RB_VLAN_MC_BASE(index) + i,
1263*4882a593Smuzhiyun 				  &data[i]);
1264*4882a593Smuzhiyun 		if (ret)
1265*4882a593Smuzhiyun 			return ret;
1266*4882a593Smuzhiyun 	}
1267*4882a593Smuzhiyun 
1268*4882a593Smuzhiyun 	vlanmc->vid = data[0] & RTL8366RB_VLAN_VID_MASK;
1269*4882a593Smuzhiyun 	vlanmc->priority = (data[0] >> RTL8366RB_VLAN_PRIORITY_SHIFT) &
1270*4882a593Smuzhiyun 		RTL8366RB_VLAN_PRIORITY_MASK;
1271*4882a593Smuzhiyun 	vlanmc->untag = (data[1] >> RTL8366RB_VLAN_UNTAG_SHIFT) &
1272*4882a593Smuzhiyun 		RTL8366RB_VLAN_UNTAG_MASK;
1273*4882a593Smuzhiyun 	vlanmc->member = data[1] & RTL8366RB_VLAN_MEMBER_MASK;
1274*4882a593Smuzhiyun 	vlanmc->fid = data[2] & RTL8366RB_VLAN_FID_MASK;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	return 0;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun 
rtl8366rb_set_vlan_mc(struct realtek_smi * smi,u32 index,const struct rtl8366_vlan_mc * vlanmc)1279*4882a593Smuzhiyun static int rtl8366rb_set_vlan_mc(struct realtek_smi *smi, u32 index,
1280*4882a593Smuzhiyun 				 const struct rtl8366_vlan_mc *vlanmc)
1281*4882a593Smuzhiyun {
1282*4882a593Smuzhiyun 	u32 data[3];
1283*4882a593Smuzhiyun 	int ret;
1284*4882a593Smuzhiyun 	int i;
1285*4882a593Smuzhiyun 
1286*4882a593Smuzhiyun 	if (index >= RTL8366RB_NUM_VLANS ||
1287*4882a593Smuzhiyun 	    vlanmc->vid >= RTL8366RB_NUM_VIDS ||
1288*4882a593Smuzhiyun 	    vlanmc->priority > RTL8366RB_PRIORITYMAX ||
1289*4882a593Smuzhiyun 	    vlanmc->member > RTL8366RB_VLAN_MEMBER_MASK ||
1290*4882a593Smuzhiyun 	    vlanmc->untag > RTL8366RB_VLAN_UNTAG_MASK ||
1291*4882a593Smuzhiyun 	    vlanmc->fid > RTL8366RB_FIDMAX)
1292*4882a593Smuzhiyun 		return -EINVAL;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	data[0] = (vlanmc->vid & RTL8366RB_VLAN_VID_MASK) |
1295*4882a593Smuzhiyun 		  ((vlanmc->priority & RTL8366RB_VLAN_PRIORITY_MASK) <<
1296*4882a593Smuzhiyun 			RTL8366RB_VLAN_PRIORITY_SHIFT);
1297*4882a593Smuzhiyun 	data[1] = (vlanmc->member & RTL8366RB_VLAN_MEMBER_MASK) |
1298*4882a593Smuzhiyun 		  ((vlanmc->untag & RTL8366RB_VLAN_UNTAG_MASK) <<
1299*4882a593Smuzhiyun 			RTL8366RB_VLAN_UNTAG_SHIFT);
1300*4882a593Smuzhiyun 	data[2] = vlanmc->fid & RTL8366RB_VLAN_FID_MASK;
1301*4882a593Smuzhiyun 
1302*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
1303*4882a593Smuzhiyun 		ret = regmap_write(smi->map,
1304*4882a593Smuzhiyun 				   RTL8366RB_VLAN_MC_BASE(index) + i,
1305*4882a593Smuzhiyun 				   data[i]);
1306*4882a593Smuzhiyun 		if (ret)
1307*4882a593Smuzhiyun 			return ret;
1308*4882a593Smuzhiyun 	}
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	return 0;
1311*4882a593Smuzhiyun }
1312*4882a593Smuzhiyun 
rtl8366rb_get_mc_index(struct realtek_smi * smi,int port,int * val)1313*4882a593Smuzhiyun static int rtl8366rb_get_mc_index(struct realtek_smi *smi, int port, int *val)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun 	u32 data;
1316*4882a593Smuzhiyun 	int ret;
1317*4882a593Smuzhiyun 
1318*4882a593Smuzhiyun 	if (port >= smi->num_ports)
1319*4882a593Smuzhiyun 		return -EINVAL;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
1322*4882a593Smuzhiyun 			  &data);
1323*4882a593Smuzhiyun 	if (ret)
1324*4882a593Smuzhiyun 		return ret;
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun 	*val = (data >> RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)) &
1327*4882a593Smuzhiyun 		RTL8366RB_PORT_VLAN_CTRL_MASK;
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 	return 0;
1330*4882a593Smuzhiyun }
1331*4882a593Smuzhiyun 
rtl8366rb_set_mc_index(struct realtek_smi * smi,int port,int index)1332*4882a593Smuzhiyun static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int index)
1333*4882a593Smuzhiyun {
1334*4882a593Smuzhiyun 	if (port >= smi->num_ports || index >= RTL8366RB_NUM_VLANS)
1335*4882a593Smuzhiyun 		return -EINVAL;
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	return regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port),
1338*4882a593Smuzhiyun 				RTL8366RB_PORT_VLAN_CTRL_MASK <<
1339*4882a593Smuzhiyun 					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port),
1340*4882a593Smuzhiyun 				(index & RTL8366RB_PORT_VLAN_CTRL_MASK) <<
1341*4882a593Smuzhiyun 					RTL8366RB_PORT_VLAN_CTRL_SHIFT(port));
1342*4882a593Smuzhiyun }
1343*4882a593Smuzhiyun 
rtl8366rb_is_vlan_valid(struct realtek_smi * smi,unsigned int vlan)1344*4882a593Smuzhiyun static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun 	unsigned int max = RTL8366RB_NUM_VLANS - 1;
1347*4882a593Smuzhiyun 
1348*4882a593Smuzhiyun 	if (smi->vlan4k_enabled)
1349*4882a593Smuzhiyun 		max = RTL8366RB_NUM_VIDS - 1;
1350*4882a593Smuzhiyun 
1351*4882a593Smuzhiyun 	if (vlan == 0 || vlan > max)
1352*4882a593Smuzhiyun 		return false;
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun 	return true;
1355*4882a593Smuzhiyun }
1356*4882a593Smuzhiyun 
rtl8366rb_enable_vlan(struct realtek_smi * smi,bool enable)1357*4882a593Smuzhiyun static int rtl8366rb_enable_vlan(struct realtek_smi *smi, bool enable)
1358*4882a593Smuzhiyun {
1359*4882a593Smuzhiyun 	dev_dbg(smi->dev, "%s VLAN\n", enable ? "enable" : "disable");
1360*4882a593Smuzhiyun 	return regmap_update_bits(smi->map,
1361*4882a593Smuzhiyun 				  RTL8366RB_SGCR, RTL8366RB_SGCR_EN_VLAN,
1362*4882a593Smuzhiyun 				  enable ? RTL8366RB_SGCR_EN_VLAN : 0);
1363*4882a593Smuzhiyun }
1364*4882a593Smuzhiyun 
rtl8366rb_enable_vlan4k(struct realtek_smi * smi,bool enable)1365*4882a593Smuzhiyun static int rtl8366rb_enable_vlan4k(struct realtek_smi *smi, bool enable)
1366*4882a593Smuzhiyun {
1367*4882a593Smuzhiyun 	dev_dbg(smi->dev, "%s VLAN 4k\n", enable ? "enable" : "disable");
1368*4882a593Smuzhiyun 	return regmap_update_bits(smi->map, RTL8366RB_SGCR,
1369*4882a593Smuzhiyun 				  RTL8366RB_SGCR_EN_VLAN_4KTB,
1370*4882a593Smuzhiyun 				  enable ? RTL8366RB_SGCR_EN_VLAN_4KTB : 0);
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun 
rtl8366rb_phy_read(struct realtek_smi * smi,int phy,int regnum)1373*4882a593Smuzhiyun static int rtl8366rb_phy_read(struct realtek_smi *smi, int phy, int regnum)
1374*4882a593Smuzhiyun {
1375*4882a593Smuzhiyun 	u32 val;
1376*4882a593Smuzhiyun 	u32 reg;
1377*4882a593Smuzhiyun 	int ret;
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun 	if (phy > RTL8366RB_PHY_NO_MAX)
1380*4882a593Smuzhiyun 		return -EINVAL;
1381*4882a593Smuzhiyun 
1382*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_PHY_ACCESS_CTRL_REG,
1383*4882a593Smuzhiyun 			   RTL8366RB_PHY_CTRL_READ);
1384*4882a593Smuzhiyun 	if (ret)
1385*4882a593Smuzhiyun 		return ret;
1386*4882a593Smuzhiyun 
1387*4882a593Smuzhiyun 	reg = 0x8000 | (1 << (phy + RTL8366RB_PHY_NO_OFFSET)) | regnum;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	ret = regmap_write(smi->map, reg, 0);
1390*4882a593Smuzhiyun 	if (ret) {
1391*4882a593Smuzhiyun 		dev_err(smi->dev,
1392*4882a593Smuzhiyun 			"failed to write PHY%d reg %04x @ %04x, ret %d\n",
1393*4882a593Smuzhiyun 			phy, regnum, reg, ret);
1394*4882a593Smuzhiyun 		return ret;
1395*4882a593Smuzhiyun 	}
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 	ret = regmap_read(smi->map, RTL8366RB_PHY_ACCESS_DATA_REG, &val);
1398*4882a593Smuzhiyun 	if (ret)
1399*4882a593Smuzhiyun 		return ret;
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	dev_dbg(smi->dev, "read PHY%d register 0x%04x @ %08x, val <- %04x\n",
1402*4882a593Smuzhiyun 		phy, regnum, reg, val);
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	return val;
1405*4882a593Smuzhiyun }
1406*4882a593Smuzhiyun 
rtl8366rb_phy_write(struct realtek_smi * smi,int phy,int regnum,u16 val)1407*4882a593Smuzhiyun static int rtl8366rb_phy_write(struct realtek_smi *smi, int phy, int regnum,
1408*4882a593Smuzhiyun 			       u16 val)
1409*4882a593Smuzhiyun {
1410*4882a593Smuzhiyun 	u32 reg;
1411*4882a593Smuzhiyun 	int ret;
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	if (phy > RTL8366RB_PHY_NO_MAX)
1414*4882a593Smuzhiyun 		return -EINVAL;
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun 	ret = regmap_write(smi->map, RTL8366RB_PHY_ACCESS_CTRL_REG,
1417*4882a593Smuzhiyun 			   RTL8366RB_PHY_CTRL_WRITE);
1418*4882a593Smuzhiyun 	if (ret)
1419*4882a593Smuzhiyun 		return ret;
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	reg = 0x8000 | (1 << (phy + RTL8366RB_PHY_NO_OFFSET)) | regnum;
1422*4882a593Smuzhiyun 
1423*4882a593Smuzhiyun 	dev_dbg(smi->dev, "write PHY%d register 0x%04x @ %04x, val -> %04x\n",
1424*4882a593Smuzhiyun 		phy, regnum, reg, val);
1425*4882a593Smuzhiyun 
1426*4882a593Smuzhiyun 	ret = regmap_write(smi->map, reg, val);
1427*4882a593Smuzhiyun 	if (ret)
1428*4882a593Smuzhiyun 		return ret;
1429*4882a593Smuzhiyun 
1430*4882a593Smuzhiyun 	return 0;
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun 
rtl8366rb_reset_chip(struct realtek_smi * smi)1433*4882a593Smuzhiyun static int rtl8366rb_reset_chip(struct realtek_smi *smi)
1434*4882a593Smuzhiyun {
1435*4882a593Smuzhiyun 	int timeout = 10;
1436*4882a593Smuzhiyun 	u32 val;
1437*4882a593Smuzhiyun 	int ret;
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 	realtek_smi_write_reg_noack(smi, RTL8366RB_RESET_CTRL_REG,
1440*4882a593Smuzhiyun 				    RTL8366RB_CHIP_CTRL_RESET_HW);
1441*4882a593Smuzhiyun 	do {
1442*4882a593Smuzhiyun 		usleep_range(20000, 25000);
1443*4882a593Smuzhiyun 		ret = regmap_read(smi->map, RTL8366RB_RESET_CTRL_REG, &val);
1444*4882a593Smuzhiyun 		if (ret)
1445*4882a593Smuzhiyun 			return ret;
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun 		if (!(val & RTL8366RB_CHIP_CTRL_RESET_HW))
1448*4882a593Smuzhiyun 			break;
1449*4882a593Smuzhiyun 	} while (--timeout);
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun 	if (!timeout) {
1452*4882a593Smuzhiyun 		dev_err(smi->dev, "timeout waiting for the switch to reset\n");
1453*4882a593Smuzhiyun 		return -EIO;
1454*4882a593Smuzhiyun 	}
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun 	return 0;
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun 
rtl8366rb_detect(struct realtek_smi * smi)1459*4882a593Smuzhiyun static int rtl8366rb_detect(struct realtek_smi *smi)
1460*4882a593Smuzhiyun {
1461*4882a593Smuzhiyun 	struct device *dev = smi->dev;
1462*4882a593Smuzhiyun 	int ret;
1463*4882a593Smuzhiyun 	u32 val;
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 	/* Detect device */
1466*4882a593Smuzhiyun 	ret = regmap_read(smi->map, 0x5c, &val);
1467*4882a593Smuzhiyun 	if (ret) {
1468*4882a593Smuzhiyun 		dev_err(dev, "can't get chip ID (%d)\n", ret);
1469*4882a593Smuzhiyun 		return ret;
1470*4882a593Smuzhiyun 	}
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	switch (val) {
1473*4882a593Smuzhiyun 	case 0x6027:
1474*4882a593Smuzhiyun 		dev_info(dev, "found an RTL8366S switch\n");
1475*4882a593Smuzhiyun 		dev_err(dev, "this switch is not yet supported, submit patches!\n");
1476*4882a593Smuzhiyun 		return -ENODEV;
1477*4882a593Smuzhiyun 	case 0x5937:
1478*4882a593Smuzhiyun 		dev_info(dev, "found an RTL8366RB switch\n");
1479*4882a593Smuzhiyun 		smi->cpu_port = RTL8366RB_PORT_NUM_CPU;
1480*4882a593Smuzhiyun 		smi->num_ports = RTL8366RB_NUM_PORTS;
1481*4882a593Smuzhiyun 		smi->num_vlan_mc = RTL8366RB_NUM_VLANS;
1482*4882a593Smuzhiyun 		smi->mib_counters = rtl8366rb_mib_counters;
1483*4882a593Smuzhiyun 		smi->num_mib_counters = ARRAY_SIZE(rtl8366rb_mib_counters);
1484*4882a593Smuzhiyun 		break;
1485*4882a593Smuzhiyun 	default:
1486*4882a593Smuzhiyun 		dev_info(dev, "found an Unknown Realtek switch (id=0x%04x)\n",
1487*4882a593Smuzhiyun 			 val);
1488*4882a593Smuzhiyun 		break;
1489*4882a593Smuzhiyun 	}
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	ret = rtl8366rb_reset_chip(smi);
1492*4882a593Smuzhiyun 	if (ret)
1493*4882a593Smuzhiyun 		return ret;
1494*4882a593Smuzhiyun 
1495*4882a593Smuzhiyun 	return 0;
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun static const struct dsa_switch_ops rtl8366rb_switch_ops = {
1499*4882a593Smuzhiyun 	.get_tag_protocol = rtl8366_get_tag_protocol,
1500*4882a593Smuzhiyun 	.setup = rtl8366rb_setup,
1501*4882a593Smuzhiyun 	.phylink_mac_link_up = rtl8366rb_mac_link_up,
1502*4882a593Smuzhiyun 	.phylink_mac_link_down = rtl8366rb_mac_link_down,
1503*4882a593Smuzhiyun 	.get_strings = rtl8366_get_strings,
1504*4882a593Smuzhiyun 	.get_ethtool_stats = rtl8366_get_ethtool_stats,
1505*4882a593Smuzhiyun 	.get_sset_count = rtl8366_get_sset_count,
1506*4882a593Smuzhiyun 	.port_vlan_filtering = rtl8366_vlan_filtering,
1507*4882a593Smuzhiyun 	.port_vlan_prepare = rtl8366_vlan_prepare,
1508*4882a593Smuzhiyun 	.port_vlan_add = rtl8366_vlan_add,
1509*4882a593Smuzhiyun 	.port_vlan_del = rtl8366_vlan_del,
1510*4882a593Smuzhiyun 	.port_enable = rtl8366rb_port_enable,
1511*4882a593Smuzhiyun 	.port_disable = rtl8366rb_port_disable,
1512*4882a593Smuzhiyun 	.port_change_mtu = rtl8366rb_change_mtu,
1513*4882a593Smuzhiyun 	.port_max_mtu = rtl8366rb_max_mtu,
1514*4882a593Smuzhiyun };
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun static const struct realtek_smi_ops rtl8366rb_smi_ops = {
1517*4882a593Smuzhiyun 	.detect		= rtl8366rb_detect,
1518*4882a593Smuzhiyun 	.get_vlan_mc	= rtl8366rb_get_vlan_mc,
1519*4882a593Smuzhiyun 	.set_vlan_mc	= rtl8366rb_set_vlan_mc,
1520*4882a593Smuzhiyun 	.get_vlan_4k	= rtl8366rb_get_vlan_4k,
1521*4882a593Smuzhiyun 	.set_vlan_4k	= rtl8366rb_set_vlan_4k,
1522*4882a593Smuzhiyun 	.get_mc_index	= rtl8366rb_get_mc_index,
1523*4882a593Smuzhiyun 	.set_mc_index	= rtl8366rb_set_mc_index,
1524*4882a593Smuzhiyun 	.get_mib_counter = rtl8366rb_get_mib_counter,
1525*4882a593Smuzhiyun 	.is_vlan_valid	= rtl8366rb_is_vlan_valid,
1526*4882a593Smuzhiyun 	.enable_vlan	= rtl8366rb_enable_vlan,
1527*4882a593Smuzhiyun 	.enable_vlan4k	= rtl8366rb_enable_vlan4k,
1528*4882a593Smuzhiyun 	.phy_read	= rtl8366rb_phy_read,
1529*4882a593Smuzhiyun 	.phy_write	= rtl8366rb_phy_write,
1530*4882a593Smuzhiyun };
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun const struct realtek_smi_variant rtl8366rb_variant = {
1533*4882a593Smuzhiyun 	.ds_ops = &rtl8366rb_switch_ops,
1534*4882a593Smuzhiyun 	.ops = &rtl8366rb_smi_ops,
1535*4882a593Smuzhiyun 	.clk_delay = 10,
1536*4882a593Smuzhiyun 	.cmd_read = 0xa9,
1537*4882a593Smuzhiyun 	.cmd_write = 0xa8,
1538*4882a593Smuzhiyun 	.chip_data_sz = sizeof(struct rtl8366rb),
1539*4882a593Smuzhiyun };
1540*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(rtl8366rb_variant);
1541