1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Driver for MaxLinear MxL862xx switch family
4 *
5 * Copyright (C) 2024 MaxLinear Inc.
6 * Copyright (C) 2025 John Crispin <john@phrozen.org>
7 * Copyright (C) 2025 Daniel Golle <daniel@makrotopia.org>
8 */
9
10 #include <linux/module.h>
11 #include <linux/delay.h>
12 #include <linux/of_device.h>
13 #include <linux/of_mdio.h>
14 #include <linux/phy.h>
15 #include <linux/phylink.h>
16 #include <net/dsa.h>
17
18 #include "mxl862xx.h"
19 #include "mxl862xx-api.h"
20 #include "mxl862xx-cmd.h"
21 #include "mxl862xx-host.h"
22
23 #define MXL862XX_API_WRITE(dev, cmd, data) \
24 mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), false, false)
25 #define MXL862XX_API_READ(dev, cmd, data) \
26 mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), true, false)
27 #define MXL862XX_API_READ_QUIET(dev, cmd, data) \
28 mxl862xx_api_wrap(dev, cmd, &(data), sizeof((data)), true, true)
29
30 #define MXL862XX_SDMA_PCTRLP(p) (0xbc0 + ((p) * 0x6))
31 #define MXL862XX_SDMA_PCTRL_EN BIT(0)
32
33 #define MXL862XX_FDMA_PCTRLP(p) (0xa80 + ((p) * 0x6))
34 #define MXL862XX_FDMA_PCTRL_EN BIT(0)
35
36 #define MXL862XX_READY_TIMEOUT_MS 10000
37 #define MXL862XX_READY_POLL_MS 100
38
mxl862xx_get_tag_protocol(struct dsa_switch * ds,int port,enum dsa_tag_protocol m)39 static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds,
40 int port,
41 enum dsa_tag_protocol m)
42 {
43 return DSA_TAG_PROTO_MXL862;
44 }
45
46 /* PHY access via firmware relay */
mxl862xx_phy_read_mmd(struct mxl862xx_priv * priv,int port,int devadd,int reg)47 static int mxl862xx_phy_read_mmd(struct mxl862xx_priv *priv, int port,
48 int devadd, int reg)
49 {
50 struct mdio_relay_data param = {
51 .phy = port,
52 .mmd = devadd,
53 .reg = cpu_to_le16(reg),
54 };
55 int ret;
56
57 ret = MXL862XX_API_READ(priv, INT_GPHY_READ, param);
58 if (ret)
59 return ret;
60
61 return le16_to_cpu(param.data);
62 }
63
mxl862xx_phy_write_mmd(struct mxl862xx_priv * priv,int port,int devadd,int reg,u16 data)64 static int mxl862xx_phy_write_mmd(struct mxl862xx_priv *priv, int port,
65 int devadd, int reg, u16 data)
66 {
67 struct mdio_relay_data param = {
68 .phy = port,
69 .mmd = devadd,
70 .reg = cpu_to_le16(reg),
71 .data = cpu_to_le16(data),
72 };
73
74 return MXL862XX_API_WRITE(priv, INT_GPHY_WRITE, param);
75 }
76
mxl862xx_phy_read_mii_bus(struct mii_bus * bus,int port,int regnum)77 static int mxl862xx_phy_read_mii_bus(struct mii_bus *bus, int port, int regnum)
78 {
79 return mxl862xx_phy_read_mmd(bus->priv, port, 0, regnum);
80 }
81
mxl862xx_phy_write_mii_bus(struct mii_bus * bus,int port,int regnum,u16 val)82 static int mxl862xx_phy_write_mii_bus(struct mii_bus *bus, int port,
83 int regnum, u16 val)
84 {
85 return mxl862xx_phy_write_mmd(bus->priv, port, 0, regnum, val);
86 }
87
mxl862xx_phy_read_c45_mii_bus(struct mii_bus * bus,int port,int devadd,int regnum)88 static int mxl862xx_phy_read_c45_mii_bus(struct mii_bus *bus, int port,
89 int devadd, int regnum)
90 {
91 return mxl862xx_phy_read_mmd(bus->priv, port, devadd, regnum);
92 }
93
mxl862xx_phy_write_c45_mii_bus(struct mii_bus * bus,int port,int devadd,int regnum,u16 val)94 static int mxl862xx_phy_write_c45_mii_bus(struct mii_bus *bus, int port,
95 int devadd, int regnum, u16 val)
96 {
97 return mxl862xx_phy_write_mmd(bus->priv, port, devadd, regnum, val);
98 }
99
mxl862xx_wait_ready(struct dsa_switch * ds)100 static int mxl862xx_wait_ready(struct dsa_switch *ds)
101 {
102 struct mxl862xx_sys_fw_image_version ver = {};
103 unsigned long start = jiffies, timeout;
104 struct mxl862xx_priv *priv = ds->priv;
105 struct mxl862xx_cfg cfg = {};
106 int ret;
107
108 timeout = start + msecs_to_jiffies(MXL862XX_READY_TIMEOUT_MS);
109 msleep(2000); /* it always takes at least 2 seconds */
110 do {
111 ret = MXL862XX_API_READ_QUIET(priv, SYS_MISC_FW_VERSION, ver);
112 if (ret || !ver.iv_major)
113 goto not_ready_yet;
114
115 /* being able to perform CFGGET indicates that
116 * the firmware is ready
117 */
118 ret = MXL862XX_API_READ_QUIET(priv,
119 MXL862XX_COMMON_CFGGET,
120 cfg);
121 if (ret)
122 goto not_ready_yet;
123
124 dev_info(ds->dev, "switch ready after %ums, firmware %u.%u.%u (build %u)\n",
125 jiffies_to_msecs(jiffies - start),
126 ver.iv_major, ver.iv_minor,
127 le16_to_cpu(ver.iv_revision),
128 le32_to_cpu(ver.iv_build_num));
129 return 0;
130
131 not_ready_yet:
132 msleep(MXL862XX_READY_POLL_MS);
133 } while (time_before(jiffies, timeout));
134
135 dev_err(ds->dev, "switch not responding after reset\n");
136 return -ETIMEDOUT;
137 }
138
mxl862xx_setup_mdio(struct dsa_switch * ds)139 static int mxl862xx_setup_mdio(struct dsa_switch *ds)
140 {
141 struct mxl862xx_priv *priv = ds->priv;
142 struct device *dev = ds->dev;
143 struct device_node *mdio_np;
144 struct mii_bus *bus;
145 int ret;
146
147 bus = devm_mdiobus_alloc(dev);
148 if (!bus)
149 return -ENOMEM;
150
151 bus->priv = priv;
152 bus->name = KBUILD_MODNAME "-mii";
153 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(dev));
154 bus->read_c45 = mxl862xx_phy_read_c45_mii_bus;
155 bus->write_c45 = mxl862xx_phy_write_c45_mii_bus;
156 bus->read = mxl862xx_phy_read_mii_bus;
157 bus->write = mxl862xx_phy_write_mii_bus;
158 bus->parent = dev;
159 bus->phy_mask = ~ds->phys_mii_mask;
160
161 mdio_np = of_get_child_by_name(dev->of_node, "mdio");
162 if (!mdio_np)
163 return -ENODEV;
164
165 ret = devm_of_mdiobus_register(dev, bus, mdio_np);
166 of_node_put(mdio_np);
167
168 return ret;
169 }
170
mxl862xx_setup(struct dsa_switch * ds)171 static int mxl862xx_setup(struct dsa_switch *ds)
172 {
173 struct mxl862xx_priv *priv = ds->priv;
174 int ret;
175
176 ret = mxl862xx_reset(priv);
177 if (ret)
178 return ret;
179
180 ret = mxl862xx_wait_ready(ds);
181 if (ret)
182 return ret;
183
184 return mxl862xx_setup_mdio(ds);
185 }
186
mxl862xx_port_state(struct dsa_switch * ds,int port,bool enable)187 static int mxl862xx_port_state(struct dsa_switch *ds, int port, bool enable)
188 {
189 struct mxl862xx_register_mod sdma = {
190 .addr = cpu_to_le16(MXL862XX_SDMA_PCTRLP(port)),
191 .data = cpu_to_le16(enable ? MXL862XX_SDMA_PCTRL_EN : 0),
192 .mask = cpu_to_le16(MXL862XX_SDMA_PCTRL_EN),
193 };
194 struct mxl862xx_register_mod fdma = {
195 .addr = cpu_to_le16(MXL862XX_FDMA_PCTRLP(port)),
196 .data = cpu_to_le16(enable ? MXL862XX_FDMA_PCTRL_EN : 0),
197 .mask = cpu_to_le16(MXL862XX_FDMA_PCTRL_EN),
198 };
199 int ret;
200
201 ret = MXL862XX_API_WRITE(ds->priv, MXL862XX_COMMON_REGISTERMOD, sdma);
202 if (ret)
203 return ret;
204
205 return MXL862XX_API_WRITE(ds->priv, MXL862XX_COMMON_REGISTERMOD, fdma);
206 }
207
mxl862xx_port_enable(struct dsa_switch * ds,int port,struct phy_device * phydev)208 static int mxl862xx_port_enable(struct dsa_switch *ds, int port,
209 struct phy_device *phydev)
210 {
211 return mxl862xx_port_state(ds, port, true);
212 }
213
mxl862xx_port_disable(struct dsa_switch * ds,int port)214 static void mxl862xx_port_disable(struct dsa_switch *ds, int port)
215 {
216 if (mxl862xx_port_state(ds, port, false))
217 dev_err(ds->dev, "failed to disable port %d\n", port);
218 }
219
mxl862xx_port_fast_age(struct dsa_switch * ds,int port)220 static void mxl862xx_port_fast_age(struct dsa_switch *ds, int port)
221 {
222 struct mxl862xx_mac_table_clear param = {
223 .type = MXL862XX_MAC_CLEAR_PHY_PORT,
224 .port_id = port,
225 };
226
227 if (MXL862XX_API_WRITE(ds->priv, MXL862XX_MAC_TABLECLEARCOND, param))
228 dev_err(ds->dev, "failed to clear fdb on port %d\n", port);
229 }
230
mxl862xx_configure_ctp_port(struct dsa_switch * ds,int port,u16 first_ctp_port_id,u16 number_of_ctp_ports)231 static int mxl862xx_configure_ctp_port(struct dsa_switch *ds, int port,
232 u16 first_ctp_port_id,
233 u16 number_of_ctp_ports)
234 {
235 struct mxl862xx_ctp_port_assignment ctp_assign = {
236 .logical_port_id = port,
237 .first_ctp_port_id = cpu_to_le16(first_ctp_port_id),
238 .number_of_ctp_port = cpu_to_le16(number_of_ctp_ports),
239 .mode = cpu_to_le32(MXL862XX_LOGICAL_PORT_ETHERNET),
240 };
241
242 return MXL862XX_API_WRITE(ds->priv, MXL862XX_CTP_PORTASSIGNMENTSET,
243 ctp_assign);
244 }
245
mxl862xx_configure_sp_tag_proto(struct dsa_switch * ds,int port,bool enable)246 static int mxl862xx_configure_sp_tag_proto(struct dsa_switch *ds, int port,
247 bool enable)
248 {
249 struct mxl862xx_ss_sp_tag tag = {
250 .pid = port,
251 .mask = MXL862XX_SS_SP_TAG_MASK_RX | MXL862XX_SS_SP_TAG_MASK_TX,
252 .rx = enable ? MXL862XX_SS_SP_TAG_RX_TAG_NO_INSERT :
253 MXL862XX_SS_SP_TAG_RX_NO_TAG_INSERT,
254 .tx = enable ? MXL862XX_SS_SP_TAG_TX_TAG_NO_REMOVE :
255 MXL862XX_SS_SP_TAG_TX_TAG_REMOVE,
256 };
257
258 return MXL862XX_API_WRITE(ds->priv, MXL862XX_SS_SPTAG_SET, tag);
259 }
260
mxl862xx_setup_cpu_bridge(struct dsa_switch * ds,int port)261 static int mxl862xx_setup_cpu_bridge(struct dsa_switch *ds, int port)
262 {
263 struct mxl862xx_bridge_port_config br_port_cfg = {};
264 struct mxl862xx_priv *priv = ds->priv;
265 u16 bridge_port_map = 0;
266 struct dsa_port *dp;
267
268 /* CPU port bridge setup */
269 br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
270 MXL862XX_BRIDGE_PORT_CONFIG_MASK_MC_SRC_MAC_LEARNING |
271 MXL862XX_BRIDGE_PORT_CONFIG_MASK_VLAN_BASED_MAC_LEARNING);
272
273 br_port_cfg.bridge_port_id = cpu_to_le16(port);
274 br_port_cfg.src_mac_learning_disable = false;
275 br_port_cfg.vlan_src_mac_vid_enable = true;
276 br_port_cfg.vlan_dst_mac_vid_enable = true;
277
278 /* include all assigned user ports in the CPU portmap */
279 dsa_switch_for_each_user_port(dp, ds) {
280 /* it's safe to rely on cpu_dp being valid for user ports */
281 if (dp->cpu_dp->index != port)
282 continue;
283
284 bridge_port_map |= BIT(dp->index);
285 }
286 br_port_cfg.bridge_port_map[0] |= cpu_to_le16(bridge_port_map);
287
288 return MXL862XX_API_WRITE(priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
289 }
290
mxl862xx_add_single_port_bridge(struct dsa_switch * ds,int port)291 static int mxl862xx_add_single_port_bridge(struct dsa_switch *ds, int port)
292 {
293 struct mxl862xx_bridge_port_config br_port_cfg = {};
294 struct dsa_port *dp = dsa_to_port(ds, port);
295 struct mxl862xx_bridge_alloc br_alloc = {};
296 int ret;
297
298 ret = MXL862XX_API_READ(ds->priv, MXL862XX_BRIDGE_ALLOC, br_alloc);
299 if (ret) {
300 dev_err(ds->dev, "failed to allocate a bridge for port %d\n", port);
301 return ret;
302 }
303
304 br_port_cfg.bridge_id = br_alloc.bridge_id;
305 br_port_cfg.bridge_port_id = cpu_to_le16(port);
306 br_port_cfg.mask = cpu_to_le32(MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_ID |
307 MXL862XX_BRIDGE_PORT_CONFIG_MASK_BRIDGE_PORT_MAP |
308 MXL862XX_BRIDGE_PORT_CONFIG_MASK_MC_SRC_MAC_LEARNING |
309 MXL862XX_BRIDGE_PORT_CONFIG_MASK_VLAN_BASED_MAC_LEARNING);
310 br_port_cfg.src_mac_learning_disable = true;
311 br_port_cfg.vlan_src_mac_vid_enable = false;
312 br_port_cfg.vlan_dst_mac_vid_enable = false;
313 /* As this function is only called for user ports it is safe to rely on
314 * cpu_dp being valid
315 */
316 br_port_cfg.bridge_port_map[0] = cpu_to_le16(BIT(dp->cpu_dp->index));
317
318 return MXL862XX_API_WRITE(ds->priv, MXL862XX_BRIDGEPORT_CONFIGSET, br_port_cfg);
319 }
320
mxl862xx_port_setup(struct dsa_switch * ds,int port)321 static int mxl862xx_port_setup(struct dsa_switch *ds, int port)
322 {
323 struct dsa_port *dp = dsa_to_port(ds, port);
324 bool is_cpu_port = dsa_port_is_cpu(dp);
325 int ret;
326
327 /* disable port and flush MAC entries */
328 ret = mxl862xx_port_state(ds, port, false);
329 if (ret)
330 return ret;
331
332 mxl862xx_port_fast_age(ds, port);
333
334 /* skip setup for unused and DSA ports */
335 if (dsa_port_is_unused(dp) ||
336 dsa_port_is_dsa(dp))
337 return 0;
338
339 /* configure tag protocol */
340 ret = mxl862xx_configure_sp_tag_proto(ds, port, is_cpu_port);
341 if (ret)
342 return ret;
343
344 /* assign CTP port IDs */
345 ret = mxl862xx_configure_ctp_port(ds, port, port,
346 is_cpu_port ? 32 - port : 1);
347 if (ret)
348 return ret;
349
350 if (is_cpu_port)
351 /* assign user ports to CPU port bridge */
352 return mxl862xx_setup_cpu_bridge(ds, port);
353
354 /* setup single-port bridge for user ports */
355 return mxl862xx_add_single_port_bridge(ds, port);
356 }
357
mxl862xx_phylink_get_caps(struct dsa_switch * ds,int port,struct phylink_config * config)358 static void mxl862xx_phylink_get_caps(struct dsa_switch *ds, int port,
359 struct phylink_config *config)
360 {
361 config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 |
362 MAC_100 | MAC_1000 | MAC_2500FD;
363
364 __set_bit(PHY_INTERFACE_MODE_INTERNAL,
365 config->supported_interfaces);
366 }
367
368 static const struct dsa_switch_ops mxl862xx_switch_ops = {
369 .get_tag_protocol = mxl862xx_get_tag_protocol,
370 .setup = mxl862xx_setup,
371 .port_setup = mxl862xx_port_setup,
372 .phylink_get_caps = mxl862xx_phylink_get_caps,
373 .port_enable = mxl862xx_port_enable,
374 .port_disable = mxl862xx_port_disable,
375 .port_fast_age = mxl862xx_port_fast_age,
376 };
377
mxl862xx_phylink_mac_config(struct phylink_config * config,unsigned int mode,const struct phylink_link_state * state)378 static void mxl862xx_phylink_mac_config(struct phylink_config *config,
379 unsigned int mode,
380 const struct phylink_link_state *state)
381 {
382 }
383
mxl862xx_phylink_mac_link_down(struct phylink_config * config,unsigned int mode,phy_interface_t interface)384 static void mxl862xx_phylink_mac_link_down(struct phylink_config *config,
385 unsigned int mode,
386 phy_interface_t interface)
387 {
388 }
389
mxl862xx_phylink_mac_link_up(struct phylink_config * config,struct phy_device * phydev,unsigned int mode,phy_interface_t interface,int speed,int duplex,bool tx_pause,bool rx_pause)390 static void mxl862xx_phylink_mac_link_up(struct phylink_config *config,
391 struct phy_device *phydev,
392 unsigned int mode,
393 phy_interface_t interface,
394 int speed, int duplex,
395 bool tx_pause, bool rx_pause)
396 {
397 }
398
399 static const struct phylink_mac_ops mxl862xx_phylink_mac_ops = {
400 .mac_config = mxl862xx_phylink_mac_config,
401 .mac_link_down = mxl862xx_phylink_mac_link_down,
402 .mac_link_up = mxl862xx_phylink_mac_link_up,
403 };
404
mxl862xx_probe(struct mdio_device * mdiodev)405 static int mxl862xx_probe(struct mdio_device *mdiodev)
406 {
407 struct device *dev = &mdiodev->dev;
408 struct mxl862xx_priv *priv;
409 struct dsa_switch *ds;
410
411 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
412 if (!priv)
413 return -ENOMEM;
414
415 priv->mdiodev = mdiodev;
416
417 ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
418 if (!ds)
419 return -ENOMEM;
420
421 priv->ds = ds;
422 ds->dev = dev;
423 ds->priv = priv;
424 ds->ops = &mxl862xx_switch_ops;
425 ds->phylink_mac_ops = &mxl862xx_phylink_mac_ops;
426 ds->num_ports = MXL862XX_MAX_PORTS;
427
428 dev_set_drvdata(dev, ds);
429
430 return dsa_register_switch(ds);
431 }
432
mxl862xx_remove(struct mdio_device * mdiodev)433 static void mxl862xx_remove(struct mdio_device *mdiodev)
434 {
435 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
436
437 if (!ds)
438 return;
439
440 dsa_unregister_switch(ds);
441 }
442
mxl862xx_shutdown(struct mdio_device * mdiodev)443 static void mxl862xx_shutdown(struct mdio_device *mdiodev)
444 {
445 struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
446
447 if (!ds)
448 return;
449
450 dsa_switch_shutdown(ds);
451
452 dev_set_drvdata(&mdiodev->dev, NULL);
453 }
454
455 static const struct of_device_id mxl862xx_of_match[] = {
456 { .compatible = "maxlinear,mxl86282" },
457 { .compatible = "maxlinear,mxl86252" },
458 { /* sentinel */ }
459 };
460 MODULE_DEVICE_TABLE(of, mxl862xx_of_match);
461
462 static struct mdio_driver mxl862xx_driver = {
463 .probe = mxl862xx_probe,
464 .remove = mxl862xx_remove,
465 .shutdown = mxl862xx_shutdown,
466 .mdiodrv.driver = {
467 .name = "mxl862xx",
468 .of_match_table = mxl862xx_of_match,
469 },
470 };
471
472 mdio_module_driver(mxl862xx_driver);
473
474 MODULE_DESCRIPTION("Driver for MaxLinear MxL862xx switch family");
475 MODULE_LICENSE("GPL");
476