1
2
3
4
5
6
7
8
9#include <linux/module.h>
10#include <linux/device.h>
11#include <linux/netdevice.h>
12#include <linux/platform_device.h>
13#include <linux/interrupt.h>
14#include <linux/of.h>
15#include <linux/of_net.h>
16#include <linux/of_mdio.h>
17#include <net/switchdev.h>
18#include <linux/etherdevice.h>
19#include <linux/io.h>
20#include <linux/printk.h>
21#include <linux/iopoll.h>
22#include <linux/mfd/syscon.h>
23#include <linux/regmap.h>
24#include <linux/types.h>
25#include <linux/reset.h>
26
27#include "sparx5_main_regs.h"
28#include "sparx5_main.h"
29#include "sparx5_port.h"
30
31#define QLIM_WM(fraction) \
32 ((SPX5_BUFFER_MEMORY / SPX5_BUFFER_CELL_SZ - 100) * (fraction) / 100)
33#define IO_RANGES 3
34
35struct initial_port_config {
36 u32 portno;
37 struct device_node *node;
38 struct sparx5_port_config conf;
39 struct phy *serdes;
40};
41
42struct sparx5_ram_config {
43 void __iomem *init_reg;
44 u32 init_val;
45};
46
47struct sparx5_main_io_resource {
48 enum sparx5_target id;
49 phys_addr_t offset;
50 int range;
51};
52
53static const struct sparx5_main_io_resource sparx5_main_iomap[] = {
54 { TARGET_CPU, 0, 0 },
55 { TARGET_FDMA, 0x80000, 0 },
56 { TARGET_PCEP, 0x400000, 0 },
57 { TARGET_DEV2G5, 0x10004000, 1 },
58 { TARGET_DEV5G, 0x10008000, 1 },
59 { TARGET_PCS5G_BR, 0x1000c000, 1 },
60 { TARGET_DEV2G5 + 1, 0x10010000, 1 },
61 { TARGET_DEV5G + 1, 0x10014000, 1 },
62 { TARGET_PCS5G_BR + 1, 0x10018000, 1 },
63 { TARGET_DEV2G5 + 2, 0x1001c000, 1 },
64 { TARGET_DEV5G + 2, 0x10020000, 1 },
65 { TARGET_PCS5G_BR + 2, 0x10024000, 1 },
66 { TARGET_DEV2G5 + 6, 0x10028000, 1 },
67 { TARGET_DEV5G + 6, 0x1002c000, 1 },
68 { TARGET_PCS5G_BR + 6, 0x10030000, 1 },
69 { TARGET_DEV2G5 + 7, 0x10034000, 1 },
70 { TARGET_DEV5G + 7, 0x10038000, 1 },
71 { TARGET_PCS5G_BR + 7, 0x1003c000, 1 },
72 { TARGET_DEV2G5 + 8, 0x10040000, 1 },
73 { TARGET_DEV5G + 8, 0x10044000, 1 },
74 { TARGET_PCS5G_BR + 8, 0x10048000, 1 },
75 { TARGET_DEV2G5 + 9, 0x1004c000, 1 },
76 { TARGET_DEV5G + 9, 0x10050000, 1 },
77 { TARGET_PCS5G_BR + 9, 0x10054000, 1 },
78 { TARGET_DEV2G5 + 10, 0x10058000, 1 },
79 { TARGET_DEV5G + 10, 0x1005c000, 1 },
80 { TARGET_PCS5G_BR + 10, 0x10060000, 1 },
81 { TARGET_DEV2G5 + 11, 0x10064000, 1 },
82 { TARGET_DEV5G + 11, 0x10068000, 1 },
83 { TARGET_PCS5G_BR + 11, 0x1006c000, 1 },
84 { TARGET_DEV2G5 + 12, 0x10070000, 1 },
85 { TARGET_DEV10G, 0x10074000, 1 },
86 { TARGET_PCS10G_BR, 0x10078000, 1 },
87 { TARGET_DEV2G5 + 14, 0x1007c000, 1 },
88 { TARGET_DEV10G + 2, 0x10080000, 1 },
89 { TARGET_PCS10G_BR + 2, 0x10084000, 1 },
90 { TARGET_DEV2G5 + 15, 0x10088000, 1 },
91 { TARGET_DEV10G + 3, 0x1008c000, 1 },
92 { TARGET_PCS10G_BR + 3, 0x10090000, 1 },
93 { TARGET_DEV2G5 + 16, 0x10094000, 1 },
94 { TARGET_DEV2G5 + 17, 0x10098000, 1 },
95 { TARGET_DEV2G5 + 18, 0x1009c000, 1 },
96 { TARGET_DEV2G5 + 19, 0x100a0000, 1 },
97 { TARGET_DEV2G5 + 20, 0x100a4000, 1 },
98 { TARGET_DEV2G5 + 21, 0x100a8000, 1 },
99 { TARGET_DEV2G5 + 22, 0x100ac000, 1 },
100 { TARGET_DEV2G5 + 23, 0x100b0000, 1 },
101 { TARGET_DEV2G5 + 32, 0x100b4000, 1 },
102 { TARGET_DEV2G5 + 33, 0x100b8000, 1 },
103 { TARGET_DEV2G5 + 34, 0x100bc000, 1 },
104 { TARGET_DEV2G5 + 35, 0x100c0000, 1 },
105 { TARGET_DEV2G5 + 36, 0x100c4000, 1 },
106 { TARGET_DEV2G5 + 37, 0x100c8000, 1 },
107 { TARGET_DEV2G5 + 38, 0x100cc000, 1 },
108 { TARGET_DEV2G5 + 39, 0x100d0000, 1 },
109 { TARGET_DEV2G5 + 40, 0x100d4000, 1 },
110 { TARGET_DEV2G5 + 41, 0x100d8000, 1 },
111 { TARGET_DEV2G5 + 42, 0x100dc000, 1 },
112 { TARGET_DEV2G5 + 43, 0x100e0000, 1 },
113 { TARGET_DEV2G5 + 44, 0x100e4000, 1 },
114 { TARGET_DEV2G5 + 45, 0x100e8000, 1 },
115 { TARGET_DEV2G5 + 46, 0x100ec000, 1 },
116 { TARGET_DEV2G5 + 47, 0x100f0000, 1 },
117 { TARGET_DEV2G5 + 57, 0x100f4000, 1 },
118 { TARGET_DEV25G + 1, 0x100f8000, 1 },
119 { TARGET_PCS25G_BR + 1, 0x100fc000, 1 },
120 { TARGET_DEV2G5 + 59, 0x10104000, 1 },
121 { TARGET_DEV25G + 3, 0x10108000, 1 },
122 { TARGET_PCS25G_BR + 3, 0x1010c000, 1 },
123 { TARGET_DEV2G5 + 60, 0x10114000, 1 },
124 { TARGET_DEV25G + 4, 0x10118000, 1 },
125 { TARGET_PCS25G_BR + 4, 0x1011c000, 1 },
126 { TARGET_DEV2G5 + 64, 0x10124000, 1 },
127 { TARGET_DEV5G + 12, 0x10128000, 1 },
128 { TARGET_PCS5G_BR + 12, 0x1012c000, 1 },
129 { TARGET_PORT_CONF, 0x10130000, 1 },
130 { TARGET_DEV2G5 + 3, 0x10404000, 1 },
131 { TARGET_DEV5G + 3, 0x10408000, 1 },
132 { TARGET_PCS5G_BR + 3, 0x1040c000, 1 },
133 { TARGET_DEV2G5 + 4, 0x10410000, 1 },
134 { TARGET_DEV5G + 4, 0x10414000, 1 },
135 { TARGET_PCS5G_BR + 4, 0x10418000, 1 },
136 { TARGET_DEV2G5 + 5, 0x1041c000, 1 },
137 { TARGET_DEV5G + 5, 0x10420000, 1 },
138 { TARGET_PCS5G_BR + 5, 0x10424000, 1 },
139 { TARGET_DEV2G5 + 13, 0x10428000, 1 },
140 { TARGET_DEV10G + 1, 0x1042c000, 1 },
141 { TARGET_PCS10G_BR + 1, 0x10430000, 1 },
142 { TARGET_DEV2G5 + 24, 0x10434000, 1 },
143 { TARGET_DEV2G5 + 25, 0x10438000, 1 },
144 { TARGET_DEV2G5 + 26, 0x1043c000, 1 },
145 { TARGET_DEV2G5 + 27, 0x10440000, 1 },
146 { TARGET_DEV2G5 + 28, 0x10444000, 1 },
147 { TARGET_DEV2G5 + 29, 0x10448000, 1 },
148 { TARGET_DEV2G5 + 30, 0x1044c000, 1 },
149 { TARGET_DEV2G5 + 31, 0x10450000, 1 },
150 { TARGET_DEV2G5 + 48, 0x10454000, 1 },
151 { TARGET_DEV10G + 4, 0x10458000, 1 },
152 { TARGET_PCS10G_BR + 4, 0x1045c000, 1 },
153 { TARGET_DEV2G5 + 49, 0x10460000, 1 },
154 { TARGET_DEV10G + 5, 0x10464000, 1 },
155 { TARGET_PCS10G_BR + 5, 0x10468000, 1 },
156 { TARGET_DEV2G5 + 50, 0x1046c000, 1 },
157 { TARGET_DEV10G + 6, 0x10470000, 1 },
158 { TARGET_PCS10G_BR + 6, 0x10474000, 1 },
159 { TARGET_DEV2G5 + 51, 0x10478000, 1 },
160 { TARGET_DEV10G + 7, 0x1047c000, 1 },
161 { TARGET_PCS10G_BR + 7, 0x10480000, 1 },
162 { TARGET_DEV2G5 + 52, 0x10484000, 1 },
163 { TARGET_DEV10G + 8, 0x10488000, 1 },
164 { TARGET_PCS10G_BR + 8, 0x1048c000, 1 },
165 { TARGET_DEV2G5 + 53, 0x10490000, 1 },
166 { TARGET_DEV10G + 9, 0x10494000, 1 },
167 { TARGET_PCS10G_BR + 9, 0x10498000, 1 },
168 { TARGET_DEV2G5 + 54, 0x1049c000, 1 },
169 { TARGET_DEV10G + 10, 0x104a0000, 1 },
170 { TARGET_PCS10G_BR + 10, 0x104a4000, 1 },
171 { TARGET_DEV2G5 + 55, 0x104a8000, 1 },
172 { TARGET_DEV10G + 11, 0x104ac000, 1 },
173 { TARGET_PCS10G_BR + 11, 0x104b0000, 1 },
174 { TARGET_DEV2G5 + 56, 0x104b4000, 1 },
175 { TARGET_DEV25G, 0x104b8000, 1 },
176 { TARGET_PCS25G_BR, 0x104bc000, 1 },
177 { TARGET_DEV2G5 + 58, 0x104c4000, 1 },
178 { TARGET_DEV25G + 2, 0x104c8000, 1 },
179 { TARGET_PCS25G_BR + 2, 0x104cc000, 1 },
180 { TARGET_DEV2G5 + 61, 0x104d4000, 1 },
181 { TARGET_DEV25G + 5, 0x104d8000, 1 },
182 { TARGET_PCS25G_BR + 5, 0x104dc000, 1 },
183 { TARGET_DEV2G5 + 62, 0x104e4000, 1 },
184 { TARGET_DEV25G + 6, 0x104e8000, 1 },
185 { TARGET_PCS25G_BR + 6, 0x104ec000, 1 },
186 { TARGET_DEV2G5 + 63, 0x104f4000, 1 },
187 { TARGET_DEV25G + 7, 0x104f8000, 1 },
188 { TARGET_PCS25G_BR + 7, 0x104fc000, 1 },
189 { TARGET_DSM, 0x10504000, 1 },
190 { TARGET_ASM, 0x10600000, 1 },
191 { TARGET_GCB, 0x11010000, 2 },
192 { TARGET_QS, 0x11030000, 2 },
193 { TARGET_ANA_ACL, 0x11050000, 2 },
194 { TARGET_LRN, 0x11060000, 2 },
195 { TARGET_VCAP_SUPER, 0x11080000, 2 },
196 { TARGET_QSYS, 0x110a0000, 2 },
197 { TARGET_QFWD, 0x110b0000, 2 },
198 { TARGET_XQS, 0x110c0000, 2 },
199 { TARGET_CLKGEN, 0x11100000, 2 },
200 { TARGET_ANA_AC_POL, 0x11200000, 2 },
201 { TARGET_QRES, 0x11280000, 2 },
202 { TARGET_EACL, 0x112c0000, 2 },
203 { TARGET_ANA_CL, 0x11400000, 2 },
204 { TARGET_ANA_L3, 0x11480000, 2 },
205 { TARGET_HSCH, 0x11580000, 2 },
206 { TARGET_REW, 0x11600000, 2 },
207 { TARGET_ANA_L2, 0x11800000, 2 },
208 { TARGET_ANA_AC, 0x11900000, 2 },
209 { TARGET_VOP, 0x11a00000, 2 },
210};
211
212static int sparx5_create_targets(struct sparx5 *sparx5)
213{
214 struct resource *iores[IO_RANGES];
215 void __iomem *iomem[IO_RANGES];
216 void __iomem *begin[IO_RANGES];
217 int range_id[IO_RANGES];
218 int idx, jdx;
219
220 for (idx = 0, jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) {
221 const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx];
222
223 if (idx == iomap->range) {
224 range_id[idx] = jdx;
225 idx++;
226 }
227 }
228 for (idx = 0; idx < IO_RANGES; idx++) {
229 iores[idx] = platform_get_resource(sparx5->pdev, IORESOURCE_MEM,
230 idx);
231 if (!iores[idx]) {
232 dev_err(sparx5->dev, "Invalid resource\n");
233 return -EINVAL;
234 }
235 iomem[idx] = devm_ioremap(sparx5->dev,
236 iores[idx]->start,
237 iores[idx]->end - iores[idx]->start
238 + 1);
239 if (!iomem[idx]) {
240 dev_err(sparx5->dev, "Unable to get switch registers: %s\n",
241 iores[idx]->name);
242 return -ENOMEM;
243 }
244 begin[idx] = iomem[idx] - sparx5_main_iomap[range_id[idx]].offset;
245 }
246 for (jdx = 0; jdx < ARRAY_SIZE(sparx5_main_iomap); jdx++) {
247 const struct sparx5_main_io_resource *iomap = &sparx5_main_iomap[jdx];
248
249 sparx5->regs[iomap->id] = begin[iomap->range] + iomap->offset;
250 }
251 return 0;
252}
253
254static int sparx5_create_port(struct sparx5 *sparx5,
255 struct initial_port_config *config)
256{
257 struct sparx5_port *spx5_port;
258 struct net_device *ndev;
259 struct phylink *phylink;
260 int err;
261
262 ndev = sparx5_create_netdev(sparx5, config->portno);
263 if (IS_ERR(ndev)) {
264 dev_err(sparx5->dev, "Could not create net device: %02u\n",
265 config->portno);
266 return PTR_ERR(ndev);
267 }
268 spx5_port = netdev_priv(ndev);
269 spx5_port->of_node = config->node;
270 spx5_port->serdes = config->serdes;
271 spx5_port->pvid = NULL_VID;
272 spx5_port->signd_internal = true;
273 spx5_port->signd_active_high = true;
274 spx5_port->signd_enable = true;
275 spx5_port->max_vlan_tags = SPX5_PORT_MAX_TAGS_NONE;
276 spx5_port->vlan_type = SPX5_VLAN_PORT_TYPE_UNAWARE;
277 spx5_port->custom_etype = 0x8880;
278 spx5_port->phylink_pcs.poll = true;
279 spx5_port->phylink_pcs.ops = &sparx5_phylink_pcs_ops;
280 sparx5->ports[config->portno] = spx5_port;
281
282 err = sparx5_port_init(sparx5, spx5_port, &config->conf);
283 if (err) {
284 dev_err(sparx5->dev, "port init failed\n");
285 return err;
286 }
287 spx5_port->conf = config->conf;
288
289
290 sparx5_vlan_port_setup(sparx5, spx5_port->portno);
291
292
293 spx5_port->phylink_config.dev = &spx5_port->ndev->dev;
294 spx5_port->phylink_config.type = PHYLINK_NETDEV;
295 spx5_port->phylink_config.pcs_poll = true;
296
297 phylink = phylink_create(&spx5_port->phylink_config,
298 of_fwnode_handle(config->node),
299 config->conf.phy_mode,
300 &sparx5_phylink_mac_ops);
301 if (IS_ERR(phylink))
302 return PTR_ERR(phylink);
303
304 spx5_port->phylink = phylink;
305 phylink_set_pcs(phylink, &spx5_port->phylink_pcs);
306
307 return 0;
308}
309
310static int sparx5_init_ram(struct sparx5 *s5)
311{
312 const struct sparx5_ram_config spx5_ram_cfg[] = {
313 {spx5_reg_get(s5, ANA_AC_STAT_RESET), ANA_AC_STAT_RESET_RESET},
314 {spx5_reg_get(s5, ASM_STAT_CFG), ASM_STAT_CFG_STAT_CNT_CLR_SHOT},
315 {spx5_reg_get(s5, QSYS_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
316 {spx5_reg_get(s5, REW_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
317 {spx5_reg_get(s5, VOP_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
318 {spx5_reg_get(s5, ANA_AC_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
319 {spx5_reg_get(s5, ASM_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
320 {spx5_reg_get(s5, EACL_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
321 {spx5_reg_get(s5, VCAP_SUPER_RAM_INIT), QSYS_RAM_INIT_RAM_INIT},
322 {spx5_reg_get(s5, DSM_RAM_INIT), QSYS_RAM_INIT_RAM_INIT}
323 };
324 const struct sparx5_ram_config *cfg;
325 u32 value, pending, jdx, idx;
326
327 for (jdx = 0; jdx < 10; jdx++) {
328 pending = ARRAY_SIZE(spx5_ram_cfg);
329 for (idx = 0; idx < ARRAY_SIZE(spx5_ram_cfg); idx++) {
330 cfg = &spx5_ram_cfg[idx];
331 if (jdx == 0) {
332 writel(cfg->init_val, cfg->init_reg);
333 } else {
334 value = readl(cfg->init_reg);
335 if ((value & cfg->init_val) != cfg->init_val)
336 pending--;
337 }
338 }
339 if (!pending)
340 break;
341 usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
342 }
343
344 if (pending > 0) {
345
346
347
348 dev_err(s5->dev, "Memory initialization error\n");
349 return -EINVAL;
350 }
351 return 0;
352}
353
354static int sparx5_init_switchcore(struct sparx5 *sparx5)
355{
356 u32 value;
357 int err = 0;
358
359 spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(1),
360 EACL_POL_EACL_CFG_EACL_FORCE_INIT,
361 sparx5,
362 EACL_POL_EACL_CFG);
363
364 spx5_rmw(EACL_POL_EACL_CFG_EACL_FORCE_INIT_SET(0),
365 EACL_POL_EACL_CFG_EACL_FORCE_INIT,
366 sparx5,
367 EACL_POL_EACL_CFG);
368
369
370 value = spx5_rd(sparx5, HSCH_RESET_CFG);
371 if (!(value & HSCH_RESET_CFG_CORE_ENA)) {
372 err = sparx5_init_ram(sparx5);
373 if (err)
374 return err;
375 }
376
377
378 spx5_wr(ANA_AC_STAT_RESET_RESET_SET(1), sparx5, ANA_AC_STAT_RESET);
379 spx5_wr(ASM_STAT_CFG_STAT_CNT_CLR_SHOT_SET(1), sparx5, ASM_STAT_CFG);
380
381
382 spx5_wr(HSCH_RESET_CFG_CORE_ENA_SET(1), sparx5, HSCH_RESET_CFG);
383
384 return 0;
385}
386
387static int sparx5_init_coreclock(struct sparx5 *sparx5)
388{
389 enum sparx5_core_clockfreq freq = sparx5->coreclock;
390 u32 clk_div, clk_period, pol_upd_int, idx;
391
392
393
394
395
396 switch (sparx5->target_ct) {
397 case SPX5_TARGET_CT_7546:
398 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
399 freq = SPX5_CORE_CLOCK_250MHZ;
400 else if (sparx5->coreclock != SPX5_CORE_CLOCK_250MHZ)
401 freq = 0;
402 break;
403 case SPX5_TARGET_CT_7549:
404 case SPX5_TARGET_CT_7552:
405 case SPX5_TARGET_CT_7556:
406 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
407 freq = SPX5_CORE_CLOCK_500MHZ;
408 else if (sparx5->coreclock != SPX5_CORE_CLOCK_500MHZ)
409 freq = 0;
410 break;
411 case SPX5_TARGET_CT_7558:
412 case SPX5_TARGET_CT_7558TSN:
413 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
414 freq = SPX5_CORE_CLOCK_625MHZ;
415 else if (sparx5->coreclock != SPX5_CORE_CLOCK_625MHZ)
416 freq = 0;
417 break;
418 case SPX5_TARGET_CT_7546TSN:
419 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
420 freq = SPX5_CORE_CLOCK_625MHZ;
421 break;
422 case SPX5_TARGET_CT_7549TSN:
423 case SPX5_TARGET_CT_7552TSN:
424 case SPX5_TARGET_CT_7556TSN:
425 if (sparx5->coreclock == SPX5_CORE_CLOCK_DEFAULT)
426 freq = SPX5_CORE_CLOCK_625MHZ;
427 else if (sparx5->coreclock == SPX5_CORE_CLOCK_250MHZ)
428 freq = 0;
429 break;
430 default:
431 dev_err(sparx5->dev, "Target (%#04x) not supported\n",
432 sparx5->target_ct);
433 return -ENODEV;
434 }
435
436 switch (freq) {
437 case SPX5_CORE_CLOCK_250MHZ:
438 clk_div = 10;
439 pol_upd_int = 312;
440 break;
441 case SPX5_CORE_CLOCK_500MHZ:
442 clk_div = 5;
443 pol_upd_int = 624;
444 break;
445 case SPX5_CORE_CLOCK_625MHZ:
446 clk_div = 4;
447 pol_upd_int = 780;
448 break;
449 default:
450 dev_err(sparx5->dev, "%d coreclock not supported on (%#04x)\n",
451 sparx5->coreclock, sparx5->target_ct);
452 return -EINVAL;
453 }
454
455
456 sparx5->coreclock = freq;
457
458
459 spx5_rmw(CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV_SET(clk_div) |
460 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV_SET(0) |
461 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR_SET(0) |
462 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL_SET(0) |
463 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA_SET(0) |
464 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA_SET(1),
465 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_DIV |
466 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_PRE_DIV |
467 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_DIR |
468 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_SEL |
469 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_ROT_ENA |
470 CLKGEN_LCPLL1_CORE_CLK_CFG_CORE_CLK_ENA,
471 sparx5,
472 CLKGEN_LCPLL1_CORE_CLK_CFG);
473
474 clk_period = sparx5_clk_period(freq);
475
476 spx5_rmw(HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS_SET(clk_period / 100),
477 HSCH_SYS_CLK_PER_SYS_CLK_PER_100PS,
478 sparx5,
479 HSCH_SYS_CLK_PER);
480
481 spx5_rmw(ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
482 ANA_AC_POL_BDLB_DLB_CTRL_CLK_PERIOD_01NS,
483 sparx5,
484 ANA_AC_POL_BDLB_DLB_CTRL);
485
486 spx5_rmw(ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS_SET(clk_period / 100),
487 ANA_AC_POL_SLB_DLB_CTRL_CLK_PERIOD_01NS,
488 sparx5,
489 ANA_AC_POL_SLB_DLB_CTRL);
490
491 spx5_rmw(LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS_SET(clk_period / 100),
492 LRN_AUTOAGE_CFG_1_CLK_PERIOD_01NS,
493 sparx5,
494 LRN_AUTOAGE_CFG_1);
495
496 for (idx = 0; idx < 3; idx++)
497 spx5_rmw(GCB_SIO_CLOCK_SYS_CLK_PERIOD_SET(clk_period / 100),
498 GCB_SIO_CLOCK_SYS_CLK_PERIOD,
499 sparx5,
500 GCB_SIO_CLOCK(idx));
501
502 spx5_rmw(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_SET
503 ((256 * 1000) / clk_period),
504 HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY,
505 sparx5,
506 HSCH_TAS_STATEMACHINE_CFG);
507
508 spx5_rmw(ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT_SET(pol_upd_int),
509 ANA_AC_POL_POL_UPD_INT_CFG_POL_UPD_INT,
510 sparx5,
511 ANA_AC_POL_POL_UPD_INT_CFG);
512
513 return 0;
514}
515
516static int sparx5_qlim_set(struct sparx5 *sparx5)
517{
518 u32 res, dp, prio;
519
520 for (res = 0; res < 2; res++) {
521 for (prio = 0; prio < 8; prio++)
522 spx5_wr(0xFFF, sparx5,
523 QRES_RES_CFG(prio + 630 + res * 1024));
524
525 for (dp = 0; dp < 4; dp++)
526 spx5_wr(0xFFF, sparx5,
527 QRES_RES_CFG(dp + 638 + res * 1024));
528 }
529
530
531 spx5_wr(QLIM_WM(80), sparx5, XQS_QLIMIT_SHR_QLIM_CFG(0));
532 spx5_wr(QLIM_WM(90), sparx5, XQS_QLIMIT_SHR_CTOP_CFG(0));
533 spx5_wr(QLIM_WM(95), sparx5, XQS_QLIMIT_SHR_ATOP_CFG(0));
534 spx5_wr(QLIM_WM(100), sparx5, XQS_QLIMIT_SHR_TOP_CFG(0));
535
536 return 0;
537}
538
539
540
541
542static void sparx5_board_init(struct sparx5 *sparx5)
543{
544 int idx;
545
546 if (!sparx5->sd_sgpio_remapping)
547 return;
548
549
550 spx5_rmw(GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL,
551 GCB_HW_SGPIO_SD_CFG_SD_MAP_SEL,
552 sparx5,
553 GCB_HW_SGPIO_SD_CFG);
554
555
556 for (idx = 0; idx < SPX5_PORTS; idx++)
557 if (sparx5->ports[idx])
558 if (sparx5->ports[idx]->conf.sd_sgpio != ~0)
559 spx5_wr(sparx5->ports[idx]->conf.sd_sgpio,
560 sparx5,
561 GCB_HW_SGPIO_TO_SD_MAP_CFG(idx));
562}
563
564static int sparx5_start(struct sparx5 *sparx5)
565{
566 u8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
567 char queue_name[32];
568 u32 idx;
569 int err;
570
571
572 for (idx = 0; idx < 3; idx++) {
573 spx5_wr(idx, sparx5, ANA_AC_OWN_UPSID(idx));
574 spx5_wr(idx, sparx5, ANA_CL_OWN_UPSID(idx));
575 spx5_wr(idx, sparx5, ANA_L2_OWN_UPSID(idx));
576 spx5_wr(idx, sparx5, REW_OWN_UPSID(idx));
577 }
578
579
580 for (idx = SPX5_PORTS; idx < SPX5_PORTS_ALL; idx++)
581 spx5_rmw(QFWD_SWITCH_PORT_MODE_PORT_ENA_SET(1),
582 QFWD_SWITCH_PORT_MODE_PORT_ENA,
583 sparx5,
584 QFWD_SWITCH_PORT_MODE(idx));
585
586
587 sparx5_update_fwd(sparx5);
588
589
590 spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
591 sparx5, ANA_AC_PGID_MISC_CFG(PGID_CPU));
592 spx5_wr(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1),
593 sparx5, ANA_AC_PGID_MISC_CFG(PGID_BCAST));
594
595
596 for (idx = SPX5_PORT_CPU_0; idx <= SPX5_PORT_CPU_1; idx++)
597 spx5_rmw(ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA_SET(1),
598 ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA,
599 sparx5, ANA_CL_FILTER_CTRL(idx));
600
601
602 sparx5_mact_init(sparx5);
603
604
605 sparx5_vlan_init(sparx5);
606
607
608 sparx5_mact_learn(sparx5, PGID_CPU, broadcast, NULL_VID);
609
610
611 sparx5_qlim_set(sparx5);
612
613 err = sparx5_config_auto_calendar(sparx5);
614 if (err)
615 return err;
616
617 err = sparx5_config_dsm_calendar(sparx5);
618 if (err)
619 return err;
620
621
622 err = sparx_stats_init(sparx5);
623 if (err)
624 return err;
625
626
627 mutex_init(&sparx5->mact_lock);
628 INIT_LIST_HEAD(&sparx5->mact_entries);
629 snprintf(queue_name, sizeof(queue_name), "%s-mact",
630 dev_name(sparx5->dev));
631 sparx5->mact_queue = create_singlethread_workqueue(queue_name);
632 INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work);
633 queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work,
634 SPX5_MACT_PULL_DELAY);
635
636 err = sparx5_register_netdevs(sparx5);
637 if (err)
638 return err;
639
640 sparx5_board_init(sparx5);
641 err = sparx5_register_notifier_blocks(sparx5);
642
643
644 err = -ENXIO;
645 if (sparx5->fdma_irq >= 0) {
646 if (GCB_CHIP_ID_REV_ID_GET(sparx5->chip_id) > 0)
647 err = devm_request_threaded_irq(sparx5->dev,
648 sparx5->fdma_irq,
649 NULL,
650 sparx5_fdma_handler,
651 IRQF_ONESHOT,
652 "sparx5-fdma", sparx5);
653 if (!err)
654 err = sparx5_fdma_start(sparx5);
655 if (err)
656 sparx5->fdma_irq = -ENXIO;
657 } else {
658 sparx5->fdma_irq = -ENXIO;
659 }
660 if (err && sparx5->xtr_irq >= 0) {
661 err = devm_request_irq(sparx5->dev, sparx5->xtr_irq,
662 sparx5_xtr_handler, IRQF_SHARED,
663 "sparx5-xtr", sparx5);
664 if (!err)
665 err = sparx5_manual_injection_mode(sparx5);
666 if (err)
667 sparx5->xtr_irq = -ENXIO;
668 } else {
669 sparx5->xtr_irq = -ENXIO;
670 }
671 return err;
672}
673
674static void sparx5_cleanup_ports(struct sparx5 *sparx5)
675{
676 sparx5_unregister_netdevs(sparx5);
677 sparx5_destroy_netdevs(sparx5);
678}
679
680static int mchp_sparx5_probe(struct platform_device *pdev)
681{
682 struct initial_port_config *configs, *config;
683 struct device_node *np = pdev->dev.of_node;
684 struct device_node *ports, *portnp;
685 struct reset_control *reset;
686 struct sparx5 *sparx5;
687 int idx = 0, err = 0;
688
689 if (!np && !pdev->dev.platform_data)
690 return -ENODEV;
691
692 sparx5 = devm_kzalloc(&pdev->dev, sizeof(*sparx5), GFP_KERNEL);
693 if (!sparx5)
694 return -ENOMEM;
695
696 platform_set_drvdata(pdev, sparx5);
697 sparx5->pdev = pdev;
698 sparx5->dev = &pdev->dev;
699
700
701 reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch");
702 if (IS_ERR(reset))
703 return dev_err_probe(&pdev->dev, PTR_ERR(reset),
704 "Failed to get switch reset controller.\n");
705 reset_control_reset(reset);
706
707
708 sparx5->coreclock = SPX5_CORE_CLOCK_DEFAULT;
709
710 ports = of_get_child_by_name(np, "ethernet-ports");
711 if (!ports) {
712 dev_err(sparx5->dev, "no ethernet-ports child node found\n");
713 return -ENODEV;
714 }
715 sparx5->port_count = of_get_child_count(ports);
716
717 configs = kcalloc(sparx5->port_count,
718 sizeof(struct initial_port_config), GFP_KERNEL);
719 if (!configs) {
720 err = -ENOMEM;
721 goto cleanup_pnode;
722 }
723
724 for_each_available_child_of_node(ports, portnp) {
725 struct sparx5_port_config *conf;
726 struct phy *serdes;
727 u32 portno;
728
729 err = of_property_read_u32(portnp, "reg", &portno);
730 if (err) {
731 dev_err(sparx5->dev, "port reg property error\n");
732 continue;
733 }
734 config = &configs[idx];
735 conf = &config->conf;
736 conf->speed = SPEED_UNKNOWN;
737 conf->bandwidth = SPEED_UNKNOWN;
738 err = of_get_phy_mode(portnp, &conf->phy_mode);
739 if (err) {
740 dev_err(sparx5->dev, "port %u: missing phy-mode\n",
741 portno);
742 continue;
743 }
744 err = of_property_read_u32(portnp, "microchip,bandwidth",
745 &conf->bandwidth);
746 if (err) {
747 dev_err(sparx5->dev, "port %u: missing bandwidth\n",
748 portno);
749 continue;
750 }
751 err = of_property_read_u32(portnp, "microchip,sd-sgpio", &conf->sd_sgpio);
752 if (err)
753 conf->sd_sgpio = ~0;
754 else
755 sparx5->sd_sgpio_remapping = true;
756 serdes = devm_of_phy_get(sparx5->dev, portnp, NULL);
757 if (IS_ERR(serdes)) {
758 err = dev_err_probe(sparx5->dev, PTR_ERR(serdes),
759 "port %u: missing serdes\n",
760 portno);
761 of_node_put(portnp);
762 goto cleanup_config;
763 }
764 config->portno = portno;
765 config->node = portnp;
766 config->serdes = serdes;
767
768 conf->media = PHY_MEDIA_DAC;
769 conf->serdes_reset = true;
770 conf->portmode = conf->phy_mode;
771 conf->power_down = true;
772 idx++;
773 }
774
775 err = sparx5_create_targets(sparx5);
776 if (err)
777 goto cleanup_config;
778
779 if (!of_get_mac_address(np, sparx5->base_mac)) {
780 dev_info(sparx5->dev, "MAC addr was not set, use random MAC\n");
781 eth_random_addr(sparx5->base_mac);
782 sparx5->base_mac[5] = 0;
783 }
784
785 sparx5->fdma_irq = platform_get_irq_byname(sparx5->pdev, "fdma");
786 sparx5->xtr_irq = platform_get_irq_byname(sparx5->pdev, "xtr");
787
788
789 sparx5->chip_id = spx5_rd(sparx5, GCB_CHIP_ID);
790
791 sparx5->target_ct = (enum spx5_target_chiptype)
792 GCB_CHIP_ID_PART_ID_GET(sparx5->chip_id);
793
794
795 err = sparx5_init_switchcore(sparx5);
796 if (err) {
797 dev_err(sparx5->dev, "Switchcore initialization error\n");
798 goto cleanup_config;
799 }
800
801
802 err = sparx5_init_coreclock(sparx5);
803 if (err) {
804 dev_err(sparx5->dev, "LC-PLL initialization error\n");
805 goto cleanup_config;
806 }
807
808 for (idx = 0; idx < sparx5->port_count; ++idx) {
809 config = &configs[idx];
810 if (!config->node)
811 continue;
812
813 err = sparx5_create_port(sparx5, config);
814 if (err) {
815 dev_err(sparx5->dev, "port create error\n");
816 goto cleanup_ports;
817 }
818 }
819
820 err = sparx5_start(sparx5);
821 if (err) {
822 dev_err(sparx5->dev, "Start failed\n");
823 goto cleanup_ports;
824 }
825 goto cleanup_config;
826
827cleanup_ports:
828 sparx5_cleanup_ports(sparx5);
829cleanup_config:
830 kfree(configs);
831cleanup_pnode:
832 of_node_put(ports);
833 return err;
834}
835
836static int mchp_sparx5_remove(struct platform_device *pdev)
837{
838 struct sparx5 *sparx5 = platform_get_drvdata(pdev);
839
840 if (sparx5->xtr_irq) {
841 disable_irq(sparx5->xtr_irq);
842 sparx5->xtr_irq = -ENXIO;
843 }
844 if (sparx5->fdma_irq) {
845 disable_irq(sparx5->fdma_irq);
846 sparx5->fdma_irq = -ENXIO;
847 }
848 sparx5_fdma_stop(sparx5);
849 sparx5_cleanup_ports(sparx5);
850
851 sparx5_unregister_notifier_blocks(sparx5);
852
853 return 0;
854}
855
856static const struct of_device_id mchp_sparx5_match[] = {
857 { .compatible = "microchip,sparx5-switch" },
858 { }
859};
860MODULE_DEVICE_TABLE(of, mchp_sparx5_match);
861
862static struct platform_driver mchp_sparx5_driver = {
863 .probe = mchp_sparx5_probe,
864 .remove = mchp_sparx5_remove,
865 .driver = {
866 .name = "sparx5-switch",
867 .of_match_table = mchp_sparx5_match,
868 },
869};
870
871module_platform_driver(mchp_sparx5_driver);
872
873MODULE_DESCRIPTION("Microchip Sparx5 switch driver");
874MODULE_AUTHOR("Steen Hegelund <steen.hegelund@microchip.com>");
875MODULE_LICENSE("Dual MIT/GPL");
876