1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /*
3 * Microsemi Ocelot Switch driver
4 *
5 * Copyright (c) 2017 Microsemi Corporation
6 */
7 #include <linux/dsa/ocelot.h>
8 #include <linux/interrupt.h>
9 #include <linux/module.h>
10 #include <linux/of_net.h>
11 #include <linux/netdevice.h>
12 #include <linux/phylink.h>
13 #include <linux/of_mdio.h>
14 #include <linux/of_platform.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/skbuff.h>
17 #include <net/switchdev.h>
18
19 #include <soc/mscc/ocelot.h>
20 #include <soc/mscc/ocelot_vcap.h>
21 #include <soc/mscc/ocelot_hsio.h>
22 #include <soc/mscc/vsc7514_regs.h>
23 #include "ocelot_fdma.h"
24 #include "ocelot.h"
25
26 #define VSC7514_VCAP_POLICER_BASE 128
27 #define VSC7514_VCAP_POLICER_MAX 191
28
ocelot_pll5_init(struct ocelot * ocelot)29 static void ocelot_pll5_init(struct ocelot *ocelot)
30 {
31 /* Configure PLL5. This will need a proper CCF driver
32 * The values are coming from the VTSS API for Ocelot
33 */
34 regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG4,
35 HSIO_PLL5G_CFG4_IB_CTRL(0x7600) |
36 HSIO_PLL5G_CFG4_IB_BIAS_CTRL(0x8));
37 regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG0,
38 HSIO_PLL5G_CFG0_CORE_CLK_DIV(0x11) |
39 HSIO_PLL5G_CFG0_CPU_CLK_DIV(2) |
40 HSIO_PLL5G_CFG0_ENA_BIAS |
41 HSIO_PLL5G_CFG0_ENA_VCO_BUF |
42 HSIO_PLL5G_CFG0_ENA_CP1 |
43 HSIO_PLL5G_CFG0_SELCPI(2) |
44 HSIO_PLL5G_CFG0_LOOP_BW_RES(0xe) |
45 HSIO_PLL5G_CFG0_SELBGV820(4) |
46 HSIO_PLL5G_CFG0_DIV4 |
47 HSIO_PLL5G_CFG0_ENA_CLKTREE |
48 HSIO_PLL5G_CFG0_ENA_LANE);
49 regmap_write(ocelot->targets[HSIO], HSIO_PLL5G_CFG2,
50 HSIO_PLL5G_CFG2_EN_RESET_FRQ_DET |
51 HSIO_PLL5G_CFG2_EN_RESET_OVERRUN |
52 HSIO_PLL5G_CFG2_GAIN_TEST(0x8) |
53 HSIO_PLL5G_CFG2_ENA_AMPCTRL |
54 HSIO_PLL5G_CFG2_PWD_AMPCTRL_N |
55 HSIO_PLL5G_CFG2_AMPC_SEL(0x10));
56 }
57
ocelot_chip_init(struct ocelot * ocelot,const struct ocelot_ops * ops)58 static int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops)
59 {
60 int ret;
61
62 ocelot->map = vsc7514_regmap;
63 ocelot->num_mact_rows = 1024;
64 ocelot->ops = ops;
65
66 ret = ocelot_regfields_init(ocelot, vsc7514_regfields);
67 if (ret)
68 return ret;
69
70 ocelot_pll5_init(ocelot);
71
72 eth_random_addr(ocelot->base_mac);
73 ocelot->base_mac[5] &= 0xf0;
74
75 return 0;
76 }
77
ocelot_xtr_irq_handler(int irq,void * arg)78 static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg)
79 {
80 struct ocelot *ocelot = arg;
81 int grp = 0, err;
82
83 while (ocelot_read(ocelot, QS_XTR_DATA_PRESENT) & BIT(grp)) {
84 struct sk_buff *skb;
85
86 err = ocelot_xtr_poll_frame(ocelot, grp, &skb);
87 if (err)
88 goto out;
89
90 skb->dev->stats.rx_bytes += skb->len;
91 skb->dev->stats.rx_packets++;
92
93 if (!skb_defer_rx_timestamp(skb))
94 netif_rx(skb);
95 }
96
97 out:
98 if (err < 0)
99 ocelot_drain_cpu_queue(ocelot, 0);
100
101 return IRQ_HANDLED;
102 }
103
ocelot_ptp_rdy_irq_handler(int irq,void * arg)104 static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg)
105 {
106 struct ocelot *ocelot = arg;
107
108 ocelot_get_txtstamp(ocelot);
109
110 return IRQ_HANDLED;
111 }
112
113 static const struct of_device_id mscc_ocelot_match[] = {
114 { .compatible = "mscc,vsc7514-switch" },
115 { }
116 };
117 MODULE_DEVICE_TABLE(of, mscc_ocelot_match);
118
119 static const struct ocelot_ops ocelot_ops = {
120 .reset = ocelot_reset,
121 .wm_enc = ocelot_wm_enc,
122 .wm_dec = ocelot_wm_dec,
123 .wm_stat = ocelot_wm_stat,
124 .port_to_netdev = ocelot_port_to_netdev,
125 .netdev_to_port = ocelot_netdev_to_port,
126 };
127
128 static struct ptp_clock_info ocelot_ptp_clock_info = {
129 .owner = THIS_MODULE,
130 .name = "ocelot ptp",
131 .max_adj = 0x7fffffff,
132 .n_alarm = 0,
133 .n_ext_ts = 0,
134 .n_per_out = OCELOT_PTP_PINS_NUM,
135 .n_pins = OCELOT_PTP_PINS_NUM,
136 .pps = 0,
137 .gettime64 = ocelot_ptp_gettime64,
138 .settime64 = ocelot_ptp_settime64,
139 .adjtime = ocelot_ptp_adjtime,
140 .adjfine = ocelot_ptp_adjfine,
141 .verify = ocelot_ptp_verify,
142 .enable = ocelot_ptp_enable,
143 };
144
mscc_ocelot_teardown_devlink_ports(struct ocelot * ocelot)145 static void mscc_ocelot_teardown_devlink_ports(struct ocelot *ocelot)
146 {
147 int port;
148
149 for (port = 0; port < ocelot->num_phys_ports; port++)
150 ocelot_port_devlink_teardown(ocelot, port);
151 }
152
mscc_ocelot_release_ports(struct ocelot * ocelot)153 static void mscc_ocelot_release_ports(struct ocelot *ocelot)
154 {
155 int port;
156
157 for (port = 0; port < ocelot->num_phys_ports; port++) {
158 struct ocelot_port *ocelot_port;
159
160 ocelot_port = ocelot->ports[port];
161 if (!ocelot_port)
162 continue;
163
164 ocelot_deinit_port(ocelot, port);
165 ocelot_release_port(ocelot_port);
166 }
167 }
168
mscc_ocelot_init_ports(struct platform_device * pdev,struct device_node * ports)169 static int mscc_ocelot_init_ports(struct platform_device *pdev,
170 struct device_node *ports)
171 {
172 struct ocelot *ocelot = platform_get_drvdata(pdev);
173 u32 devlink_ports_registered = 0;
174 struct device_node *portnp;
175 int port, err;
176 u32 reg;
177
178 ocelot->ports = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports,
179 sizeof(struct ocelot_port *), GFP_KERNEL);
180 if (!ocelot->ports)
181 return -ENOMEM;
182
183 ocelot->devlink_ports = devm_kcalloc(ocelot->dev,
184 ocelot->num_phys_ports,
185 sizeof(*ocelot->devlink_ports),
186 GFP_KERNEL);
187 if (!ocelot->devlink_ports)
188 return -ENOMEM;
189
190 for_each_available_child_of_node(ports, portnp) {
191 struct regmap *target;
192 struct resource *res;
193 char res_name[8];
194
195 if (of_property_read_u32(portnp, "reg", ®))
196 continue;
197
198 port = reg;
199 if (port < 0 || port >= ocelot->num_phys_ports) {
200 dev_err(ocelot->dev,
201 "invalid port number: %d >= %d\n", port,
202 ocelot->num_phys_ports);
203 continue;
204 }
205
206 snprintf(res_name, sizeof(res_name), "port%d", port);
207
208 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
209 res_name);
210 target = ocelot_regmap_init(ocelot, res);
211 if (IS_ERR(target)) {
212 err = PTR_ERR(target);
213 of_node_put(portnp);
214 goto out_teardown;
215 }
216
217 err = ocelot_port_devlink_init(ocelot, port,
218 DEVLINK_PORT_FLAVOUR_PHYSICAL);
219 if (err) {
220 of_node_put(portnp);
221 goto out_teardown;
222 }
223
224 err = ocelot_probe_port(ocelot, port, target, portnp);
225 if (err) {
226 ocelot_port_devlink_teardown(ocelot, port);
227 continue;
228 }
229
230 devlink_ports_registered |= BIT(port);
231 }
232
233 /* Initialize unused devlink ports at the end */
234 for (port = 0; port < ocelot->num_phys_ports; port++) {
235 if (devlink_ports_registered & BIT(port))
236 continue;
237
238 err = ocelot_port_devlink_init(ocelot, port,
239 DEVLINK_PORT_FLAVOUR_UNUSED);
240 if (err)
241 goto out_teardown;
242
243 devlink_ports_registered |= BIT(port);
244 }
245
246 return 0;
247
248 out_teardown:
249 /* Unregister the network interfaces */
250 mscc_ocelot_release_ports(ocelot);
251 /* Tear down devlink ports for the registered network interfaces */
252 for (port = 0; port < ocelot->num_phys_ports; port++) {
253 if (devlink_ports_registered & BIT(port))
254 ocelot_port_devlink_teardown(ocelot, port);
255 }
256 return err;
257 }
258
mscc_ocelot_probe(struct platform_device * pdev)259 static int mscc_ocelot_probe(struct platform_device *pdev)
260 {
261 struct device_node *np = pdev->dev.of_node;
262 int err, irq_xtr, irq_ptp_rdy;
263 struct device_node *ports;
264 struct devlink *devlink;
265 struct ocelot *ocelot;
266 struct regmap *hsio;
267 unsigned int i;
268
269 struct {
270 enum ocelot_target id;
271 char *name;
272 u8 optional:1;
273 } io_target[] = {
274 { SYS, "sys" },
275 { REW, "rew" },
276 { QSYS, "qsys" },
277 { ANA, "ana" },
278 { QS, "qs" },
279 { S0, "s0" },
280 { S1, "s1" },
281 { S2, "s2" },
282 { PTP, "ptp", 1 },
283 { FDMA, "fdma", 1 },
284 };
285
286 if (!np && !pdev->dev.platform_data)
287 return -ENODEV;
288
289 devlink =
290 devlink_alloc(&ocelot_devlink_ops, sizeof(*ocelot), &pdev->dev);
291 if (!devlink)
292 return -ENOMEM;
293
294 ocelot = devlink_priv(devlink);
295 ocelot->devlink = priv_to_devlink(ocelot);
296 platform_set_drvdata(pdev, ocelot);
297 ocelot->dev = &pdev->dev;
298
299 for (i = 0; i < ARRAY_SIZE(io_target); i++) {
300 struct regmap *target;
301 struct resource *res;
302
303 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
304 io_target[i].name);
305
306 target = ocelot_regmap_init(ocelot, res);
307 if (IS_ERR(target)) {
308 if (io_target[i].optional) {
309 ocelot->targets[io_target[i].id] = NULL;
310 continue;
311 }
312 err = PTR_ERR(target);
313 goto out_free_devlink;
314 }
315
316 ocelot->targets[io_target[i].id] = target;
317 }
318
319 if (ocelot->targets[FDMA])
320 ocelot_fdma_init(pdev, ocelot);
321
322 hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio");
323 if (IS_ERR(hsio)) {
324 dev_err(&pdev->dev, "missing hsio syscon\n");
325 err = PTR_ERR(hsio);
326 goto out_free_devlink;
327 }
328
329 ocelot->targets[HSIO] = hsio;
330
331 err = ocelot_chip_init(ocelot, &ocelot_ops);
332 if (err)
333 goto out_free_devlink;
334
335 irq_xtr = platform_get_irq_byname(pdev, "xtr");
336 if (irq_xtr < 0) {
337 err = irq_xtr;
338 goto out_free_devlink;
339 }
340
341 err = devm_request_threaded_irq(&pdev->dev, irq_xtr, NULL,
342 ocelot_xtr_irq_handler, IRQF_ONESHOT,
343 "frame extraction", ocelot);
344 if (err)
345 goto out_free_devlink;
346
347 irq_ptp_rdy = platform_get_irq_byname(pdev, "ptp_rdy");
348 if (irq_ptp_rdy > 0 && ocelot->targets[PTP]) {
349 err = devm_request_threaded_irq(&pdev->dev, irq_ptp_rdy, NULL,
350 ocelot_ptp_rdy_irq_handler,
351 IRQF_ONESHOT, "ptp ready",
352 ocelot);
353 if (err)
354 goto out_free_devlink;
355
356 /* Both the PTP interrupt and the PTP bank are available */
357 ocelot->ptp = 1;
358 }
359
360 ports = of_get_child_by_name(np, "ethernet-ports");
361 if (!ports) {
362 dev_err(ocelot->dev, "no ethernet-ports child node found\n");
363 err = -ENODEV;
364 goto out_free_devlink;
365 }
366
367 ocelot->num_phys_ports = of_get_child_count(ports);
368 ocelot->num_flooding_pgids = 1;
369
370 ocelot->vcap = vsc7514_vcap_props;
371
372 ocelot->vcap_pol.base = VSC7514_VCAP_POLICER_BASE;
373 ocelot->vcap_pol.max = VSC7514_VCAP_POLICER_MAX;
374
375 ocelot->npi = -1;
376
377 err = ocelot_init(ocelot);
378 if (err)
379 goto out_put_ports;
380
381 err = mscc_ocelot_init_ports(pdev, ports);
382 if (err)
383 goto out_ocelot_devlink_unregister;
384
385 if (ocelot->fdma)
386 ocelot_fdma_start(ocelot);
387
388 err = ocelot_devlink_sb_register(ocelot);
389 if (err)
390 goto out_ocelot_release_ports;
391
392 if (ocelot->ptp) {
393 err = ocelot_init_timestamp(ocelot, &ocelot_ptp_clock_info);
394 if (err) {
395 dev_err(ocelot->dev,
396 "Timestamp initialization failed\n");
397 ocelot->ptp = 0;
398 }
399 }
400
401 register_netdevice_notifier(&ocelot_netdevice_nb);
402 register_switchdev_notifier(&ocelot_switchdev_nb);
403 register_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
404
405 of_node_put(ports);
406 devlink_register(devlink);
407
408 dev_info(&pdev->dev, "Ocelot switch probed\n");
409
410 return 0;
411
412 out_ocelot_release_ports:
413 mscc_ocelot_release_ports(ocelot);
414 mscc_ocelot_teardown_devlink_ports(ocelot);
415 out_ocelot_devlink_unregister:
416 ocelot_deinit(ocelot);
417 out_put_ports:
418 of_node_put(ports);
419 out_free_devlink:
420 devlink_free(devlink);
421 return err;
422 }
423
mscc_ocelot_remove(struct platform_device * pdev)424 static int mscc_ocelot_remove(struct platform_device *pdev)
425 {
426 struct ocelot *ocelot = platform_get_drvdata(pdev);
427
428 if (ocelot->fdma)
429 ocelot_fdma_deinit(ocelot);
430 devlink_unregister(ocelot->devlink);
431 ocelot_deinit_timestamp(ocelot);
432 ocelot_devlink_sb_unregister(ocelot);
433 mscc_ocelot_release_ports(ocelot);
434 mscc_ocelot_teardown_devlink_ports(ocelot);
435 ocelot_deinit(ocelot);
436 unregister_switchdev_blocking_notifier(&ocelot_switchdev_blocking_nb);
437 unregister_switchdev_notifier(&ocelot_switchdev_nb);
438 unregister_netdevice_notifier(&ocelot_netdevice_nb);
439 devlink_free(ocelot->devlink);
440
441 return 0;
442 }
443
444 static struct platform_driver mscc_ocelot_driver = {
445 .probe = mscc_ocelot_probe,
446 .remove = mscc_ocelot_remove,
447 .driver = {
448 .name = "ocelot-switch",
449 .of_match_table = mscc_ocelot_match,
450 },
451 };
452
453 module_platform_driver(mscc_ocelot_driver);
454
455 MODULE_DESCRIPTION("Microsemi Ocelot switch driver");
456 MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
457 MODULE_LICENSE("Dual MIT/GPL");
458