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