Commit | Line | Data |
---|---|---|
a1292595 JB |
1 | /* |
2 | * Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | */ | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/gpio/consumer.h> | |
17 | #include <linux/regmap.h> | |
18 | #include <linux/mutex.h> | |
19 | #include <linux/mii.h> | |
20 | ||
21 | #include "lan9303.h" | |
22 | ||
a368ca53 EH |
23 | #define LAN9303_NUM_PORTS 3 |
24 | ||
ab78acb1 EH |
25 | /* 13.2 System Control and Status Registers |
26 | * Multiply register number by 4 to get address offset. | |
27 | */ | |
a1292595 JB |
28 | #define LAN9303_CHIP_REV 0x14 |
29 | # define LAN9303_CHIP_ID 0x9303 | |
30 | #define LAN9303_IRQ_CFG 0x15 | |
31 | # define LAN9303_IRQ_CFG_IRQ_ENABLE BIT(8) | |
32 | # define LAN9303_IRQ_CFG_IRQ_POL BIT(4) | |
33 | # define LAN9303_IRQ_CFG_IRQ_TYPE BIT(0) | |
34 | #define LAN9303_INT_STS 0x16 | |
35 | # define LAN9303_INT_STS_PHY_INT2 BIT(27) | |
36 | # define LAN9303_INT_STS_PHY_INT1 BIT(26) | |
37 | #define LAN9303_INT_EN 0x17 | |
38 | # define LAN9303_INT_EN_PHY_INT2_EN BIT(27) | |
39 | # define LAN9303_INT_EN_PHY_INT1_EN BIT(26) | |
40 | #define LAN9303_HW_CFG 0x1D | |
41 | # define LAN9303_HW_CFG_READY BIT(27) | |
42 | # define LAN9303_HW_CFG_AMDX_EN_PORT2 BIT(26) | |
43 | # define LAN9303_HW_CFG_AMDX_EN_PORT1 BIT(25) | |
44 | #define LAN9303_PMI_DATA 0x29 | |
45 | #define LAN9303_PMI_ACCESS 0x2A | |
46 | # define LAN9303_PMI_ACCESS_PHY_ADDR(x) (((x) & 0x1f) << 11) | |
47 | # define LAN9303_PMI_ACCESS_MIIRINDA(x) (((x) & 0x1f) << 6) | |
48 | # define LAN9303_PMI_ACCESS_MII_BUSY BIT(0) | |
49 | # define LAN9303_PMI_ACCESS_MII_WRITE BIT(1) | |
50 | #define LAN9303_MANUAL_FC_1 0x68 | |
51 | #define LAN9303_MANUAL_FC_2 0x69 | |
52 | #define LAN9303_MANUAL_FC_0 0x6a | |
53 | #define LAN9303_SWITCH_CSR_DATA 0x6b | |
54 | #define LAN9303_SWITCH_CSR_CMD 0x6c | |
55 | #define LAN9303_SWITCH_CSR_CMD_BUSY BIT(31) | |
56 | #define LAN9303_SWITCH_CSR_CMD_RW BIT(30) | |
57 | #define LAN9303_SWITCH_CSR_CMD_LANES (BIT(19) | BIT(18) | BIT(17) | BIT(16)) | |
58 | #define LAN9303_VIRT_PHY_BASE 0x70 | |
59 | #define LAN9303_VIRT_SPECIAL_CTRL 0x77 | |
60 | ||
ab78acb1 EH |
61 | /*13.4 Switch Fabric Control and Status Registers |
62 | * Accessed indirectly via SWITCH_CSR_CMD, SWITCH_CSR_DATA. | |
63 | */ | |
a1292595 JB |
64 | #define LAN9303_SW_DEV_ID 0x0000 |
65 | #define LAN9303_SW_RESET 0x0001 | |
66 | #define LAN9303_SW_RESET_RESET BIT(0) | |
67 | #define LAN9303_SW_IMR 0x0004 | |
68 | #define LAN9303_SW_IPR 0x0005 | |
69 | #define LAN9303_MAC_VER_ID_0 0x0400 | |
70 | #define LAN9303_MAC_RX_CFG_0 0x0401 | |
71 | # define LAN9303_MAC_RX_CFG_X_REJECT_MAC_TYPES BIT(1) | |
72 | # define LAN9303_MAC_RX_CFG_X_RX_ENABLE BIT(0) | |
73 | #define LAN9303_MAC_RX_UNDSZE_CNT_0 0x0410 | |
74 | #define LAN9303_MAC_RX_64_CNT_0 0x0411 | |
75 | #define LAN9303_MAC_RX_127_CNT_0 0x0412 | |
76 | #define LAN9303_MAC_RX_255_CNT_0 0x413 | |
77 | #define LAN9303_MAC_RX_511_CNT_0 0x0414 | |
78 | #define LAN9303_MAC_RX_1023_CNT_0 0x0415 | |
79 | #define LAN9303_MAC_RX_MAX_CNT_0 0x0416 | |
80 | #define LAN9303_MAC_RX_OVRSZE_CNT_0 0x0417 | |
81 | #define LAN9303_MAC_RX_PKTOK_CNT_0 0x0418 | |
82 | #define LAN9303_MAC_RX_CRCERR_CNT_0 0x0419 | |
83 | #define LAN9303_MAC_RX_MULCST_CNT_0 0x041a | |
84 | #define LAN9303_MAC_RX_BRDCST_CNT_0 0x041b | |
85 | #define LAN9303_MAC_RX_PAUSE_CNT_0 0x041c | |
86 | #define LAN9303_MAC_RX_FRAG_CNT_0 0x041d | |
87 | #define LAN9303_MAC_RX_JABB_CNT_0 0x041e | |
88 | #define LAN9303_MAC_RX_ALIGN_CNT_0 0x041f | |
89 | #define LAN9303_MAC_RX_PKTLEN_CNT_0 0x0420 | |
90 | #define LAN9303_MAC_RX_GOODPKTLEN_CNT_0 0x0421 | |
91 | #define LAN9303_MAC_RX_SYMBL_CNT_0 0x0422 | |
92 | #define LAN9303_MAC_RX_CTLFRM_CNT_0 0x0423 | |
93 | ||
94 | #define LAN9303_MAC_TX_CFG_0 0x0440 | |
95 | # define LAN9303_MAC_TX_CFG_X_TX_IFG_CONFIG_DEFAULT (21 << 2) | |
96 | # define LAN9303_MAC_TX_CFG_X_TX_PAD_ENABLE BIT(1) | |
97 | # define LAN9303_MAC_TX_CFG_X_TX_ENABLE BIT(0) | |
98 | #define LAN9303_MAC_TX_DEFER_CNT_0 0x0451 | |
99 | #define LAN9303_MAC_TX_PAUSE_CNT_0 0x0452 | |
100 | #define LAN9303_MAC_TX_PKTOK_CNT_0 0x0453 | |
101 | #define LAN9303_MAC_TX_64_CNT_0 0x0454 | |
102 | #define LAN9303_MAC_TX_127_CNT_0 0x0455 | |
103 | #define LAN9303_MAC_TX_255_CNT_0 0x0456 | |
104 | #define LAN9303_MAC_TX_511_CNT_0 0x0457 | |
105 | #define LAN9303_MAC_TX_1023_CNT_0 0x0458 | |
106 | #define LAN9303_MAC_TX_MAX_CNT_0 0x0459 | |
107 | #define LAN9303_MAC_TX_UNDSZE_CNT_0 0x045a | |
108 | #define LAN9303_MAC_TX_PKTLEN_CNT_0 0x045c | |
109 | #define LAN9303_MAC_TX_BRDCST_CNT_0 0x045d | |
110 | #define LAN9303_MAC_TX_MULCST_CNT_0 0x045e | |
111 | #define LAN9303_MAC_TX_LATECOL_0 0x045f | |
112 | #define LAN9303_MAC_TX_EXCOL_CNT_0 0x0460 | |
113 | #define LAN9303_MAC_TX_SNGLECOL_CNT_0 0x0461 | |
114 | #define LAN9303_MAC_TX_MULTICOL_CNT_0 0x0462 | |
115 | #define LAN9303_MAC_TX_TOTALCOL_CNT_0 0x0463 | |
116 | ||
117 | #define LAN9303_MAC_VER_ID_1 0x0800 | |
118 | #define LAN9303_MAC_RX_CFG_1 0x0801 | |
119 | #define LAN9303_MAC_TX_CFG_1 0x0840 | |
120 | #define LAN9303_MAC_VER_ID_2 0x0c00 | |
121 | #define LAN9303_MAC_RX_CFG_2 0x0c01 | |
122 | #define LAN9303_MAC_TX_CFG_2 0x0c40 | |
123 | #define LAN9303_SWE_ALR_CMD 0x1800 | |
124 | #define LAN9303_SWE_VLAN_CMD 0x180b | |
125 | # define LAN9303_SWE_VLAN_CMD_RNW BIT(5) | |
126 | # define LAN9303_SWE_VLAN_CMD_PVIDNVLAN BIT(4) | |
127 | #define LAN9303_SWE_VLAN_WR_DATA 0x180c | |
128 | #define LAN9303_SWE_VLAN_RD_DATA 0x180e | |
129 | # define LAN9303_SWE_VLAN_MEMBER_PORT2 BIT(17) | |
130 | # define LAN9303_SWE_VLAN_UNTAG_PORT2 BIT(16) | |
131 | # define LAN9303_SWE_VLAN_MEMBER_PORT1 BIT(15) | |
132 | # define LAN9303_SWE_VLAN_UNTAG_PORT1 BIT(14) | |
133 | # define LAN9303_SWE_VLAN_MEMBER_PORT0 BIT(13) | |
134 | # define LAN9303_SWE_VLAN_UNTAG_PORT0 BIT(12) | |
135 | #define LAN9303_SWE_VLAN_CMD_STS 0x1810 | |
136 | #define LAN9303_SWE_GLB_INGRESS_CFG 0x1840 | |
137 | #define LAN9303_SWE_PORT_STATE 0x1843 | |
138 | # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT2 (0) | |
139 | # define LAN9303_SWE_PORT_STATE_LEARNING_PORT2 BIT(5) | |
140 | # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT2 BIT(4) | |
141 | # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT1 (0) | |
142 | # define LAN9303_SWE_PORT_STATE_LEARNING_PORT1 BIT(3) | |
143 | # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT1 BIT(2) | |
144 | # define LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 (0) | |
145 | # define LAN9303_SWE_PORT_STATE_LEARNING_PORT0 BIT(1) | |
146 | # define LAN9303_SWE_PORT_STATE_BLOCKING_PORT0 BIT(0) | |
147 | #define LAN9303_SWE_PORT_MIRROR 0x1846 | |
148 | # define LAN9303_SWE_PORT_MIRROR_SNIFF_ALL BIT(8) | |
149 | # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT2 BIT(7) | |
150 | # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT1 BIT(6) | |
151 | # define LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT0 BIT(5) | |
152 | # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT2 BIT(4) | |
153 | # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT1 BIT(3) | |
154 | # define LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT0 BIT(2) | |
155 | # define LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING BIT(1) | |
156 | # define LAN9303_SWE_PORT_MIRROR_ENABLE_TX_MIRRORING BIT(0) | |
157 | #define LAN9303_SWE_INGRESS_PORT_TYPE 0x1847 | |
158 | #define LAN9303_BM_CFG 0x1c00 | |
159 | #define LAN9303_BM_EGRSS_PORT_TYPE 0x1c0c | |
160 | # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT2 (BIT(17) | BIT(16)) | |
161 | # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT1 (BIT(9) | BIT(8)) | |
162 | # define LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT0 (BIT(1) | BIT(0)) | |
163 | ||
451d3ca0 | 164 | #define LAN9303_SWITCH_PORT_REG(port, reg0) (0x400 * (port) + (reg0)) |
a1292595 JB |
165 | |
166 | /* the built-in PHYs are of type LAN911X */ | |
167 | #define MII_LAN911X_SPECIAL_MODES 0x12 | |
168 | #define MII_LAN911X_SPECIAL_CONTROL_STATUS 0x1f | |
169 | ||
170 | static const struct regmap_range lan9303_valid_regs[] = { | |
171 | regmap_reg_range(0x14, 0x17), /* misc, interrupt */ | |
172 | regmap_reg_range(0x19, 0x19), /* endian test */ | |
173 | regmap_reg_range(0x1d, 0x1d), /* hardware config */ | |
174 | regmap_reg_range(0x23, 0x24), /* general purpose timer */ | |
175 | regmap_reg_range(0x27, 0x27), /* counter */ | |
176 | regmap_reg_range(0x29, 0x2a), /* PMI index regs */ | |
177 | regmap_reg_range(0x68, 0x6a), /* flow control */ | |
178 | regmap_reg_range(0x6b, 0x6c), /* switch fabric indirect regs */ | |
179 | regmap_reg_range(0x6d, 0x6f), /* misc */ | |
180 | regmap_reg_range(0x70, 0x77), /* virtual phy */ | |
181 | regmap_reg_range(0x78, 0x7a), /* GPIO */ | |
182 | regmap_reg_range(0x7c, 0x7e), /* MAC & reset */ | |
183 | regmap_reg_range(0x80, 0xb7), /* switch fabric direct regs (wr only) */ | |
184 | }; | |
185 | ||
186 | static const struct regmap_range lan9303_reserved_ranges[] = { | |
187 | regmap_reg_range(0x00, 0x13), | |
188 | regmap_reg_range(0x18, 0x18), | |
189 | regmap_reg_range(0x1a, 0x1c), | |
190 | regmap_reg_range(0x1e, 0x22), | |
191 | regmap_reg_range(0x25, 0x26), | |
192 | regmap_reg_range(0x28, 0x28), | |
193 | regmap_reg_range(0x2b, 0x67), | |
194 | regmap_reg_range(0x7b, 0x7b), | |
195 | regmap_reg_range(0x7f, 0x7f), | |
196 | regmap_reg_range(0xb8, 0xff), | |
197 | }; | |
198 | ||
199 | const struct regmap_access_table lan9303_register_set = { | |
200 | .yes_ranges = lan9303_valid_regs, | |
201 | .n_yes_ranges = ARRAY_SIZE(lan9303_valid_regs), | |
202 | .no_ranges = lan9303_reserved_ranges, | |
203 | .n_no_ranges = ARRAY_SIZE(lan9303_reserved_ranges), | |
204 | }; | |
205 | EXPORT_SYMBOL(lan9303_register_set); | |
206 | ||
207 | static int lan9303_read(struct regmap *regmap, unsigned int offset, u32 *reg) | |
208 | { | |
209 | int ret, i; | |
210 | ||
211 | /* we can lose arbitration for the I2C case, because the device | |
212 | * tries to detect and read an external EEPROM after reset and acts as | |
213 | * a master on the shared I2C bus itself. This conflicts with our | |
214 | * attempts to access the device as a slave at the same moment. | |
215 | */ | |
216 | for (i = 0; i < 5; i++) { | |
217 | ret = regmap_read(regmap, offset, reg); | |
218 | if (!ret) | |
219 | return 0; | |
220 | if (ret != -EAGAIN) | |
221 | break; | |
222 | msleep(500); | |
223 | } | |
224 | ||
225 | return -EIO; | |
226 | } | |
227 | ||
228 | static int lan9303_virt_phy_reg_read(struct lan9303 *chip, int regnum) | |
229 | { | |
230 | int ret; | |
231 | u32 val; | |
232 | ||
233 | if (regnum > MII_EXPANSION) | |
234 | return -EINVAL; | |
235 | ||
236 | ret = lan9303_read(chip->regmap, LAN9303_VIRT_PHY_BASE + regnum, &val); | |
237 | if (ret) | |
238 | return ret; | |
239 | ||
240 | return val & 0xffff; | |
241 | } | |
242 | ||
243 | static int lan9303_virt_phy_reg_write(struct lan9303 *chip, int regnum, u16 val) | |
244 | { | |
245 | if (regnum > MII_EXPANSION) | |
246 | return -EINVAL; | |
247 | ||
248 | return regmap_write(chip->regmap, LAN9303_VIRT_PHY_BASE + regnum, val); | |
249 | } | |
250 | ||
9e866e5d | 251 | static int lan9303_indirect_phy_wait_for_completion(struct lan9303 *chip) |
a1292595 JB |
252 | { |
253 | int ret, i; | |
254 | u32 reg; | |
255 | ||
256 | for (i = 0; i < 25; i++) { | |
257 | ret = lan9303_read(chip->regmap, LAN9303_PMI_ACCESS, ®); | |
258 | if (ret) { | |
259 | dev_err(chip->dev, | |
260 | "Failed to read pmi access status: %d\n", ret); | |
261 | return ret; | |
262 | } | |
263 | if (!(reg & LAN9303_PMI_ACCESS_MII_BUSY)) | |
264 | return 0; | |
265 | msleep(1); | |
266 | } | |
267 | ||
268 | return -EIO; | |
269 | } | |
270 | ||
9e866e5d | 271 | static int lan9303_indirect_phy_read(struct lan9303 *chip, int addr, int regnum) |
a1292595 JB |
272 | { |
273 | int ret; | |
274 | u32 val; | |
275 | ||
276 | val = LAN9303_PMI_ACCESS_PHY_ADDR(addr); | |
277 | val |= LAN9303_PMI_ACCESS_MIIRINDA(regnum); | |
278 | ||
279 | mutex_lock(&chip->indirect_mutex); | |
280 | ||
9e866e5d | 281 | ret = lan9303_indirect_phy_wait_for_completion(chip); |
a1292595 JB |
282 | if (ret) |
283 | goto on_error; | |
284 | ||
285 | /* start the MII read cycle */ | |
286 | ret = regmap_write(chip->regmap, LAN9303_PMI_ACCESS, val); | |
287 | if (ret) | |
288 | goto on_error; | |
289 | ||
9e866e5d | 290 | ret = lan9303_indirect_phy_wait_for_completion(chip); |
a1292595 JB |
291 | if (ret) |
292 | goto on_error; | |
293 | ||
294 | /* read the result of this operation */ | |
295 | ret = lan9303_read(chip->regmap, LAN9303_PMI_DATA, &val); | |
296 | if (ret) | |
297 | goto on_error; | |
298 | ||
299 | mutex_unlock(&chip->indirect_mutex); | |
300 | ||
301 | return val & 0xffff; | |
302 | ||
303 | on_error: | |
304 | mutex_unlock(&chip->indirect_mutex); | |
305 | return ret; | |
306 | } | |
307 | ||
9e866e5d EH |
308 | static int lan9303_indirect_phy_write(struct lan9303 *chip, int addr, |
309 | int regnum, u16 val) | |
a1292595 JB |
310 | { |
311 | int ret; | |
312 | u32 reg; | |
313 | ||
314 | reg = LAN9303_PMI_ACCESS_PHY_ADDR(addr); | |
315 | reg |= LAN9303_PMI_ACCESS_MIIRINDA(regnum); | |
316 | reg |= LAN9303_PMI_ACCESS_MII_WRITE; | |
317 | ||
318 | mutex_lock(&chip->indirect_mutex); | |
319 | ||
9e866e5d | 320 | ret = lan9303_indirect_phy_wait_for_completion(chip); |
a1292595 JB |
321 | if (ret) |
322 | goto on_error; | |
323 | ||
324 | /* write the data first... */ | |
325 | ret = regmap_write(chip->regmap, LAN9303_PMI_DATA, val); | |
326 | if (ret) | |
327 | goto on_error; | |
328 | ||
329 | /* ...then start the MII write cycle */ | |
330 | ret = regmap_write(chip->regmap, LAN9303_PMI_ACCESS, reg); | |
331 | ||
332 | on_error: | |
333 | mutex_unlock(&chip->indirect_mutex); | |
334 | return ret; | |
335 | } | |
336 | ||
2c340898 EH |
337 | const struct lan9303_phy_ops lan9303_indirect_phy_ops = { |
338 | .phy_read = lan9303_indirect_phy_read, | |
339 | .phy_write = lan9303_indirect_phy_write, | |
340 | }; | |
341 | EXPORT_SYMBOL_GPL(lan9303_indirect_phy_ops); | |
342 | ||
a1292595 JB |
343 | static int lan9303_switch_wait_for_completion(struct lan9303 *chip) |
344 | { | |
345 | int ret, i; | |
346 | u32 reg; | |
347 | ||
348 | for (i = 0; i < 25; i++) { | |
349 | ret = lan9303_read(chip->regmap, LAN9303_SWITCH_CSR_CMD, ®); | |
350 | if (ret) { | |
351 | dev_err(chip->dev, | |
352 | "Failed to read csr command status: %d\n", ret); | |
353 | return ret; | |
354 | } | |
355 | if (!(reg & LAN9303_SWITCH_CSR_CMD_BUSY)) | |
356 | return 0; | |
357 | msleep(1); | |
358 | } | |
359 | ||
360 | return -EIO; | |
361 | } | |
362 | ||
363 | static int lan9303_write_switch_reg(struct lan9303 *chip, u16 regnum, u32 val) | |
364 | { | |
365 | u32 reg; | |
366 | int ret; | |
367 | ||
368 | reg = regnum; | |
369 | reg |= LAN9303_SWITCH_CSR_CMD_LANES; | |
370 | reg |= LAN9303_SWITCH_CSR_CMD_BUSY; | |
371 | ||
372 | mutex_lock(&chip->indirect_mutex); | |
373 | ||
374 | ret = lan9303_switch_wait_for_completion(chip); | |
375 | if (ret) | |
376 | goto on_error; | |
377 | ||
378 | ret = regmap_write(chip->regmap, LAN9303_SWITCH_CSR_DATA, val); | |
379 | if (ret) { | |
380 | dev_err(chip->dev, "Failed to write csr data reg: %d\n", ret); | |
381 | goto on_error; | |
382 | } | |
383 | ||
384 | /* trigger write */ | |
385 | ret = regmap_write(chip->regmap, LAN9303_SWITCH_CSR_CMD, reg); | |
386 | if (ret) | |
387 | dev_err(chip->dev, "Failed to write csr command reg: %d\n", | |
388 | ret); | |
389 | ||
390 | on_error: | |
391 | mutex_unlock(&chip->indirect_mutex); | |
392 | return ret; | |
393 | } | |
394 | ||
395 | static int lan9303_read_switch_reg(struct lan9303 *chip, u16 regnum, u32 *val) | |
396 | { | |
397 | u32 reg; | |
398 | int ret; | |
399 | ||
400 | reg = regnum; | |
401 | reg |= LAN9303_SWITCH_CSR_CMD_LANES; | |
402 | reg |= LAN9303_SWITCH_CSR_CMD_RW; | |
403 | reg |= LAN9303_SWITCH_CSR_CMD_BUSY; | |
404 | ||
405 | mutex_lock(&chip->indirect_mutex); | |
406 | ||
407 | ret = lan9303_switch_wait_for_completion(chip); | |
408 | if (ret) | |
409 | goto on_error; | |
410 | ||
411 | /* trigger read */ | |
412 | ret = regmap_write(chip->regmap, LAN9303_SWITCH_CSR_CMD, reg); | |
413 | if (ret) { | |
414 | dev_err(chip->dev, "Failed to write csr command reg: %d\n", | |
415 | ret); | |
416 | goto on_error; | |
417 | } | |
418 | ||
419 | ret = lan9303_switch_wait_for_completion(chip); | |
420 | if (ret) | |
421 | goto on_error; | |
422 | ||
423 | ret = lan9303_read(chip->regmap, LAN9303_SWITCH_CSR_DATA, val); | |
424 | if (ret) | |
425 | dev_err(chip->dev, "Failed to read csr data reg: %d\n", ret); | |
426 | on_error: | |
427 | mutex_unlock(&chip->indirect_mutex); | |
428 | return ret; | |
429 | } | |
430 | ||
451d3ca0 EH |
431 | static int lan9303_write_switch_port(struct lan9303 *chip, int port, |
432 | u16 regnum, u32 val) | |
433 | { | |
434 | return lan9303_write_switch_reg( | |
435 | chip, LAN9303_SWITCH_PORT_REG(port, regnum), val); | |
436 | } | |
437 | ||
a1292595 JB |
438 | static int lan9303_detect_phy_setup(struct lan9303 *chip) |
439 | { | |
440 | int reg; | |
441 | ||
442 | /* depending on the 'phy_addr_sel_strap' setting, the three phys are | |
443 | * using IDs 0-1-2 or IDs 1-2-3. We cannot read back the | |
444 | * 'phy_addr_sel_strap' setting directly, so we need a test, which | |
445 | * configuration is active: | |
446 | * Special reg 18 of phy 3 reads as 0x0000, if 'phy_addr_sel_strap' is 0 | |
447 | * and the IDs are 0-1-2, else it contains something different from | |
448 | * 0x0000, which means 'phy_addr_sel_strap' is 1 and the IDs are 1-2-3. | |
d329ac88 | 449 | * 0xffff is returned on MDIO read with no response. |
a1292595 | 450 | */ |
2c340898 | 451 | reg = chip->ops->phy_read(chip, 3, MII_LAN911X_SPECIAL_MODES); |
a1292595 JB |
452 | if (reg < 0) { |
453 | dev_err(chip->dev, "Failed to detect phy config: %d\n", reg); | |
454 | return reg; | |
455 | } | |
456 | ||
d329ac88 | 457 | if ((reg != 0) && (reg != 0xffff)) |
a1292595 JB |
458 | chip->phy_addr_sel_strap = 1; |
459 | else | |
460 | chip->phy_addr_sel_strap = 0; | |
461 | ||
462 | dev_dbg(chip->dev, "Phy setup '%s' detected\n", | |
463 | chip->phy_addr_sel_strap ? "1-2-3" : "0-1-2"); | |
464 | ||
465 | return 0; | |
466 | } | |
467 | ||
a1292595 JB |
468 | static int lan9303_disable_packet_processing(struct lan9303 *chip, |
469 | unsigned int port) | |
470 | { | |
471 | int ret; | |
472 | ||
473 | /* disable RX, but keep register reset default values else */ | |
451d3ca0 EH |
474 | ret = lan9303_write_switch_port(chip, port, LAN9303_MAC_RX_CFG_0, |
475 | LAN9303_MAC_RX_CFG_X_REJECT_MAC_TYPES); | |
a1292595 JB |
476 | if (ret) |
477 | return ret; | |
478 | ||
479 | /* disable TX, but keep register reset default values else */ | |
451d3ca0 | 480 | return lan9303_write_switch_port(chip, port, LAN9303_MAC_TX_CFG_0, |
a1292595 JB |
481 | LAN9303_MAC_TX_CFG_X_TX_IFG_CONFIG_DEFAULT | |
482 | LAN9303_MAC_TX_CFG_X_TX_PAD_ENABLE); | |
483 | } | |
484 | ||
485 | static int lan9303_enable_packet_processing(struct lan9303 *chip, | |
486 | unsigned int port) | |
487 | { | |
488 | int ret; | |
489 | ||
490 | /* enable RX and keep register reset default values else */ | |
451d3ca0 EH |
491 | ret = lan9303_write_switch_port(chip, port, LAN9303_MAC_RX_CFG_0, |
492 | LAN9303_MAC_RX_CFG_X_REJECT_MAC_TYPES | | |
493 | LAN9303_MAC_RX_CFG_X_RX_ENABLE); | |
a1292595 JB |
494 | if (ret) |
495 | return ret; | |
496 | ||
497 | /* enable TX and keep register reset default values else */ | |
451d3ca0 | 498 | return lan9303_write_switch_port(chip, port, LAN9303_MAC_TX_CFG_0, |
a1292595 JB |
499 | LAN9303_MAC_TX_CFG_X_TX_IFG_CONFIG_DEFAULT | |
500 | LAN9303_MAC_TX_CFG_X_TX_PAD_ENABLE | | |
501 | LAN9303_MAC_TX_CFG_X_TX_ENABLE); | |
502 | } | |
503 | ||
504 | /* We want a special working switch: | |
505 | * - do not forward packets between port 1 and 2 | |
506 | * - forward everything from port 1 to port 0 | |
507 | * - forward everything from port 2 to port 0 | |
508 | * - forward special tagged packets from port 0 to port 1 *or* port 2 | |
509 | */ | |
510 | static int lan9303_separate_ports(struct lan9303 *chip) | |
511 | { | |
512 | int ret; | |
513 | ||
514 | ret = lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_MIRROR, | |
515 | LAN9303_SWE_PORT_MIRROR_SNIFFER_PORT0 | | |
516 | LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT1 | | |
517 | LAN9303_SWE_PORT_MIRROR_MIRRORED_PORT2 | | |
518 | LAN9303_SWE_PORT_MIRROR_ENABLE_RX_MIRRORING | | |
519 | LAN9303_SWE_PORT_MIRROR_SNIFF_ALL); | |
520 | if (ret) | |
521 | return ret; | |
522 | ||
523 | /* enable defining the destination port via special VLAN tagging | |
524 | * for port 0 | |
525 | */ | |
526 | ret = lan9303_write_switch_reg(chip, LAN9303_SWE_INGRESS_PORT_TYPE, | |
527 | 0x03); | |
528 | if (ret) | |
529 | return ret; | |
530 | ||
531 | /* tag incoming packets at port 1 and 2 on their way to port 0 to be | |
532 | * able to discover their source port | |
533 | */ | |
534 | ret = lan9303_write_switch_reg(chip, LAN9303_BM_EGRSS_PORT_TYPE, | |
535 | LAN9303_BM_EGRSS_PORT_TYPE_SPECIAL_TAG_PORT0); | |
536 | if (ret) | |
537 | return ret; | |
538 | ||
539 | /* prevent port 1 and 2 from forwarding packets by their own */ | |
540 | return lan9303_write_switch_reg(chip, LAN9303_SWE_PORT_STATE, | |
541 | LAN9303_SWE_PORT_STATE_FORWARDING_PORT0 | | |
542 | LAN9303_SWE_PORT_STATE_BLOCKING_PORT1 | | |
543 | LAN9303_SWE_PORT_STATE_BLOCKING_PORT2); | |
544 | } | |
545 | ||
546 | static int lan9303_handle_reset(struct lan9303 *chip) | |
547 | { | |
548 | if (!chip->reset_gpio) | |
549 | return 0; | |
550 | ||
551 | if (chip->reset_duration != 0) | |
552 | msleep(chip->reset_duration); | |
553 | ||
554 | /* release (deassert) reset and activate the device */ | |
555 | gpiod_set_value_cansleep(chip->reset_gpio, 0); | |
556 | ||
557 | return 0; | |
558 | } | |
559 | ||
560 | /* stop processing packets for all ports */ | |
561 | static int lan9303_disable_processing(struct lan9303 *chip) | |
562 | { | |
b3d14a2b | 563 | int p; |
a1292595 | 564 | |
b3d14a2b EH |
565 | for (p = 0; p < LAN9303_NUM_PORTS; p++) { |
566 | int ret = lan9303_disable_packet_processing(chip, p); | |
567 | ||
568 | if (ret) | |
569 | return ret; | |
570 | } | |
571 | ||
572 | return 0; | |
a1292595 JB |
573 | } |
574 | ||
575 | static int lan9303_check_device(struct lan9303 *chip) | |
576 | { | |
577 | int ret; | |
578 | u32 reg; | |
579 | ||
580 | ret = lan9303_read(chip->regmap, LAN9303_CHIP_REV, ®); | |
581 | if (ret) { | |
582 | dev_err(chip->dev, "failed to read chip revision register: %d\n", | |
583 | ret); | |
584 | if (!chip->reset_gpio) { | |
585 | dev_dbg(chip->dev, | |
586 | "hint: maybe failed due to missing reset GPIO\n"); | |
587 | } | |
588 | return ret; | |
589 | } | |
590 | ||
591 | if ((reg >> 16) != LAN9303_CHIP_ID) { | |
592 | dev_err(chip->dev, "expecting LAN9303 chip, but found: %X\n", | |
593 | reg >> 16); | |
594 | return ret; | |
595 | } | |
596 | ||
597 | /* The default state of the LAN9303 device is to forward packets between | |
598 | * all ports (if not configured differently by an external EEPROM). | |
599 | * The initial state of a DSA device must be forwarding packets only | |
600 | * between the external and the internal ports and no forwarding | |
601 | * between the external ports. In preparation we stop packet handling | |
602 | * at all for now until the LAN9303 device is re-programmed accordingly. | |
603 | */ | |
604 | ret = lan9303_disable_processing(chip); | |
605 | if (ret) | |
606 | dev_warn(chip->dev, "failed to disable switching %d\n", ret); | |
607 | ||
608 | dev_info(chip->dev, "Found LAN9303 rev. %u\n", reg & 0xffff); | |
609 | ||
610 | ret = lan9303_detect_phy_setup(chip); | |
611 | if (ret) { | |
612 | dev_err(chip->dev, | |
613 | "failed to discover phy bootstrap setup: %d\n", ret); | |
614 | return ret; | |
615 | } | |
616 | ||
617 | return 0; | |
618 | } | |
619 | ||
620 | /* ---------------------------- DSA -----------------------------------*/ | |
621 | ||
622 | static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds) | |
623 | { | |
624 | return DSA_TAG_PROTO_LAN9303; | |
625 | } | |
626 | ||
627 | static int lan9303_setup(struct dsa_switch *ds) | |
628 | { | |
629 | struct lan9303 *chip = ds->priv; | |
630 | int ret; | |
631 | ||
632 | /* Make sure that port 0 is the cpu port */ | |
633 | if (!dsa_is_cpu_port(ds, 0)) { | |
634 | dev_err(chip->dev, "port 0 is not the CPU port\n"); | |
635 | return -EINVAL; | |
636 | } | |
637 | ||
638 | ret = lan9303_separate_ports(chip); | |
639 | if (ret) | |
640 | dev_err(chip->dev, "failed to separate ports %d\n", ret); | |
641 | ||
451d3ca0 | 642 | ret = lan9303_enable_packet_processing(chip, 0); |
a1292595 JB |
643 | if (ret) |
644 | dev_err(chip->dev, "failed to re-enable switching %d\n", ret); | |
645 | ||
646 | return 0; | |
647 | } | |
648 | ||
649 | struct lan9303_mib_desc { | |
650 | unsigned int offset; /* offset of first MAC */ | |
651 | const char *name; | |
652 | }; | |
653 | ||
654 | static const struct lan9303_mib_desc lan9303_mib[] = { | |
655 | { .offset = LAN9303_MAC_RX_BRDCST_CNT_0, .name = "RxBroad", }, | |
656 | { .offset = LAN9303_MAC_RX_PAUSE_CNT_0, .name = "RxPause", }, | |
657 | { .offset = LAN9303_MAC_RX_MULCST_CNT_0, .name = "RxMulti", }, | |
658 | { .offset = LAN9303_MAC_RX_PKTOK_CNT_0, .name = "RxOk", }, | |
659 | { .offset = LAN9303_MAC_RX_CRCERR_CNT_0, .name = "RxCrcErr", }, | |
660 | { .offset = LAN9303_MAC_RX_ALIGN_CNT_0, .name = "RxAlignErr", }, | |
661 | { .offset = LAN9303_MAC_RX_JABB_CNT_0, .name = "RxJabber", }, | |
662 | { .offset = LAN9303_MAC_RX_FRAG_CNT_0, .name = "RxFragment", }, | |
663 | { .offset = LAN9303_MAC_RX_64_CNT_0, .name = "Rx64Byte", }, | |
664 | { .offset = LAN9303_MAC_RX_127_CNT_0, .name = "Rx128Byte", }, | |
665 | { .offset = LAN9303_MAC_RX_255_CNT_0, .name = "Rx256Byte", }, | |
666 | { .offset = LAN9303_MAC_RX_511_CNT_0, .name = "Rx512Byte", }, | |
667 | { .offset = LAN9303_MAC_RX_1023_CNT_0, .name = "Rx1024Byte", }, | |
668 | { .offset = LAN9303_MAC_RX_MAX_CNT_0, .name = "RxMaxByte", }, | |
669 | { .offset = LAN9303_MAC_RX_PKTLEN_CNT_0, .name = "RxByteCnt", }, | |
670 | { .offset = LAN9303_MAC_RX_SYMBL_CNT_0, .name = "RxSymbolCnt", }, | |
671 | { .offset = LAN9303_MAC_RX_CTLFRM_CNT_0, .name = "RxCfs", }, | |
672 | { .offset = LAN9303_MAC_RX_OVRSZE_CNT_0, .name = "RxOverFlow", }, | |
673 | { .offset = LAN9303_MAC_TX_UNDSZE_CNT_0, .name = "TxShort", }, | |
674 | { .offset = LAN9303_MAC_TX_BRDCST_CNT_0, .name = "TxBroad", }, | |
675 | { .offset = LAN9303_MAC_TX_PAUSE_CNT_0, .name = "TxPause", }, | |
676 | { .offset = LAN9303_MAC_TX_MULCST_CNT_0, .name = "TxMulti", }, | |
677 | { .offset = LAN9303_MAC_RX_UNDSZE_CNT_0, .name = "TxUnderRun", }, | |
678 | { .offset = LAN9303_MAC_TX_64_CNT_0, .name = "Tx64Byte", }, | |
679 | { .offset = LAN9303_MAC_TX_127_CNT_0, .name = "Tx128Byte", }, | |
680 | { .offset = LAN9303_MAC_TX_255_CNT_0, .name = "Tx256Byte", }, | |
681 | { .offset = LAN9303_MAC_TX_511_CNT_0, .name = "Tx512Byte", }, | |
682 | { .offset = LAN9303_MAC_TX_1023_CNT_0, .name = "Tx1024Byte", }, | |
683 | { .offset = LAN9303_MAC_TX_MAX_CNT_0, .name = "TxMaxByte", }, | |
684 | { .offset = LAN9303_MAC_TX_PKTLEN_CNT_0, .name = "TxByteCnt", }, | |
685 | { .offset = LAN9303_MAC_TX_PKTOK_CNT_0, .name = "TxOk", }, | |
686 | { .offset = LAN9303_MAC_TX_TOTALCOL_CNT_0, .name = "TxCollision", }, | |
687 | { .offset = LAN9303_MAC_TX_MULTICOL_CNT_0, .name = "TxMultiCol", }, | |
688 | { .offset = LAN9303_MAC_TX_SNGLECOL_CNT_0, .name = "TxSingleCol", }, | |
689 | { .offset = LAN9303_MAC_TX_EXCOL_CNT_0, .name = "TxExcCol", }, | |
690 | { .offset = LAN9303_MAC_TX_DEFER_CNT_0, .name = "TxDefer", }, | |
691 | { .offset = LAN9303_MAC_TX_LATECOL_0, .name = "TxLateCol", }, | |
692 | }; | |
693 | ||
694 | static void lan9303_get_strings(struct dsa_switch *ds, int port, uint8_t *data) | |
695 | { | |
696 | unsigned int u; | |
697 | ||
698 | for (u = 0; u < ARRAY_SIZE(lan9303_mib); u++) { | |
699 | strncpy(data + u * ETH_GSTRING_LEN, lan9303_mib[u].name, | |
700 | ETH_GSTRING_LEN); | |
701 | } | |
702 | } | |
703 | ||
704 | static void lan9303_get_ethtool_stats(struct dsa_switch *ds, int port, | |
705 | uint64_t *data) | |
706 | { | |
707 | struct lan9303 *chip = ds->priv; | |
708 | u32 reg; | |
709 | unsigned int u, poff; | |
710 | int ret; | |
711 | ||
712 | poff = port * 0x400; | |
713 | ||
714 | for (u = 0; u < ARRAY_SIZE(lan9303_mib); u++) { | |
715 | ret = lan9303_read_switch_reg(chip, | |
716 | lan9303_mib[u].offset + poff, | |
717 | ®); | |
718 | if (ret) | |
719 | dev_warn(chip->dev, "Reading status reg %u failed\n", | |
720 | lan9303_mib[u].offset + poff); | |
721 | data[u] = reg; | |
722 | } | |
723 | } | |
724 | ||
725 | static int lan9303_get_sset_count(struct dsa_switch *ds) | |
726 | { | |
727 | return ARRAY_SIZE(lan9303_mib); | |
728 | } | |
729 | ||
730 | static int lan9303_phy_read(struct dsa_switch *ds, int phy, int regnum) | |
731 | { | |
732 | struct lan9303 *chip = ds->priv; | |
733 | int phy_base = chip->phy_addr_sel_strap; | |
734 | ||
735 | if (phy == phy_base) | |
736 | return lan9303_virt_phy_reg_read(chip, regnum); | |
737 | if (phy > phy_base + 2) | |
738 | return -ENODEV; | |
739 | ||
2c340898 | 740 | return chip->ops->phy_read(chip, phy, regnum); |
a1292595 JB |
741 | } |
742 | ||
743 | static int lan9303_phy_write(struct dsa_switch *ds, int phy, int regnum, | |
744 | u16 val) | |
745 | { | |
746 | struct lan9303 *chip = ds->priv; | |
747 | int phy_base = chip->phy_addr_sel_strap; | |
748 | ||
749 | if (phy == phy_base) | |
750 | return lan9303_virt_phy_reg_write(chip, regnum, val); | |
751 | if (phy > phy_base + 2) | |
752 | return -ENODEV; | |
753 | ||
2c340898 | 754 | return chip->ops->phy_write(chip, phy, regnum, val); |
a1292595 JB |
755 | } |
756 | ||
757 | static int lan9303_port_enable(struct dsa_switch *ds, int port, | |
758 | struct phy_device *phy) | |
759 | { | |
760 | struct lan9303 *chip = ds->priv; | |
761 | ||
762 | /* enable internal packet processing */ | |
763 | switch (port) { | |
764 | case 1: | |
a1292595 | 765 | case 2: |
451d3ca0 | 766 | return lan9303_enable_packet_processing(chip, port); |
a1292595 JB |
767 | default: |
768 | dev_dbg(chip->dev, | |
769 | "Error: request to power up invalid port %d\n", port); | |
770 | } | |
771 | ||
772 | return -ENODEV; | |
773 | } | |
774 | ||
775 | static void lan9303_port_disable(struct dsa_switch *ds, int port, | |
776 | struct phy_device *phy) | |
777 | { | |
778 | struct lan9303 *chip = ds->priv; | |
779 | ||
780 | /* disable internal packet processing */ | |
781 | switch (port) { | |
782 | case 1: | |
a1292595 | 783 | case 2: |
451d3ca0 | 784 | lan9303_disable_packet_processing(chip, port); |
b3d14a2b | 785 | lan9303_phy_write(ds, chip->phy_addr_sel_strap + port, |
2c340898 | 786 | MII_BMCR, BMCR_PDOWN); |
a1292595 JB |
787 | break; |
788 | default: | |
789 | dev_dbg(chip->dev, | |
790 | "Error: request to power down invalid port %d\n", port); | |
791 | } | |
792 | } | |
793 | ||
794 | static struct dsa_switch_ops lan9303_switch_ops = { | |
795 | .get_tag_protocol = lan9303_get_tag_protocol, | |
796 | .setup = lan9303_setup, | |
797 | .get_strings = lan9303_get_strings, | |
798 | .phy_read = lan9303_phy_read, | |
799 | .phy_write = lan9303_phy_write, | |
800 | .get_ethtool_stats = lan9303_get_ethtool_stats, | |
801 | .get_sset_count = lan9303_get_sset_count, | |
802 | .port_enable = lan9303_port_enable, | |
803 | .port_disable = lan9303_port_disable, | |
804 | }; | |
805 | ||
806 | static int lan9303_register_switch(struct lan9303 *chip) | |
807 | { | |
808 | chip->ds = dsa_switch_alloc(chip->dev, DSA_MAX_PORTS); | |
809 | if (!chip->ds) | |
810 | return -ENOMEM; | |
811 | ||
812 | chip->ds->priv = chip; | |
813 | chip->ds->ops = &lan9303_switch_ops; | |
814 | chip->ds->phys_mii_mask = chip->phy_addr_sel_strap ? 0xe : 0x7; | |
815 | ||
23c9ee49 | 816 | return dsa_register_switch(chip->ds); |
a1292595 JB |
817 | } |
818 | ||
819 | static void lan9303_probe_reset_gpio(struct lan9303 *chip, | |
820 | struct device_node *np) | |
821 | { | |
822 | chip->reset_gpio = devm_gpiod_get_optional(chip->dev, "reset", | |
823 | GPIOD_OUT_LOW); | |
824 | ||
825 | if (!chip->reset_gpio) { | |
826 | dev_dbg(chip->dev, "No reset GPIO defined\n"); | |
827 | return; | |
828 | } | |
829 | ||
830 | chip->reset_duration = 200; | |
831 | ||
832 | if (np) { | |
833 | of_property_read_u32(np, "reset-duration", | |
834 | &chip->reset_duration); | |
835 | } else { | |
836 | dev_dbg(chip->dev, "reset duration defaults to 200 ms\n"); | |
837 | } | |
838 | ||
839 | /* A sane reset duration should not be longer than 1s */ | |
840 | if (chip->reset_duration > 1000) | |
841 | chip->reset_duration = 1000; | |
842 | } | |
843 | ||
844 | int lan9303_probe(struct lan9303 *chip, struct device_node *np) | |
845 | { | |
846 | int ret; | |
847 | ||
848 | mutex_init(&chip->indirect_mutex); | |
849 | ||
850 | lan9303_probe_reset_gpio(chip, np); | |
851 | ||
852 | ret = lan9303_handle_reset(chip); | |
853 | if (ret) | |
854 | return ret; | |
855 | ||
856 | ret = lan9303_check_device(chip); | |
857 | if (ret) | |
858 | return ret; | |
859 | ||
860 | ret = lan9303_register_switch(chip); | |
861 | if (ret) { | |
862 | dev_dbg(chip->dev, "Failed to register switch: %d\n", ret); | |
863 | return ret; | |
864 | } | |
865 | ||
866 | return 0; | |
867 | } | |
868 | EXPORT_SYMBOL(lan9303_probe); | |
869 | ||
870 | int lan9303_remove(struct lan9303 *chip) | |
871 | { | |
872 | int rc; | |
873 | ||
874 | rc = lan9303_disable_processing(chip); | |
875 | if (rc != 0) | |
876 | dev_warn(chip->dev, "shutting down failed\n"); | |
877 | ||
878 | dsa_unregister_switch(chip->ds); | |
879 | ||
880 | /* assert reset to the whole device to prevent it from doing anything */ | |
881 | gpiod_set_value_cansleep(chip->reset_gpio, 1); | |
882 | gpiod_unexport(chip->reset_gpio); | |
883 | ||
884 | return 0; | |
885 | } | |
886 | EXPORT_SYMBOL(lan9303_remove); | |
887 | ||
888 | MODULE_AUTHOR("Juergen Borleis <kernel@pengutronix.de>"); | |
889 | MODULE_DESCRIPTION("Core driver for SMSC/Microchip LAN9303 three port ethernet switch"); | |
890 | MODULE_LICENSE("GPL v2"); |