1 From 5313432ca1e1a0677ad7b4f17a7e0186473f47aa Mon Sep 17 00:00:00 2001
2 From: Daniel Golle <daniel@makrotopia.org>
3 Date: Mon, 3 Apr 2023 02:19:13 +0100
4 Subject: [PATCH 12/48] net: dsa: mt7530: introduce separate MDIO driver
6 Split MT7530 switch driver into a common part and a part specific
7 for MDIO connected switches and multi-chip modules.
8 Move MDIO-specific functions to newly introduced mt7530-mdio.c while
9 keeping the common parts in mt7530.c.
10 Introduce new Kconfig symbol CONFIG_NET_DSA_MT7530_MDIO which is
11 implied by CONFIG_NET_DSA_MT7530.
13 Signed-off-by: Daniel Golle <daniel@makrotopia.org>
14 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
15 Signed-off-by: David S. Miller <davem@davemloft.net>
18 drivers/net/dsa/Kconfig | 18 ++-
19 drivers/net/dsa/Makefile | 1 +
20 drivers/net/dsa/mt7530-mdio.c | 271 ++++++++++++++++++++++++++++++++++
21 drivers/net/dsa/mt7530.c | 264 +--------------------------------
22 drivers/net/dsa/mt7530.h | 6 +
23 6 files changed, 302 insertions(+), 259 deletions(-)
24 create mode 100644 drivers/net/dsa/mt7530-mdio.c
28 @@ -13069,6 +13069,7 @@ M: Landen Chao <Landen.Chao@mediatek.com
29 M: DENG Qingfang <dqfext@gmail.com>
30 L: netdev@vger.kernel.org
32 +F: drivers/net/dsa/mt7530-mdio.c
33 F: drivers/net/dsa/mt7530.*
36 --- a/drivers/net/dsa/Kconfig
37 +++ b/drivers/net/dsa/Kconfig
38 @@ -34,13 +34,25 @@ config NET_DSA_LANTIQ_GSWIP
42 - tristate "MediaTek MT753x and MT7621 Ethernet switch support"
43 + tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
44 select NET_DSA_TAG_MTK
45 + imply NET_DSA_MT7530_MDIO
47 + This enables support for the MediaTek MT7530 and MT7531 Ethernet
48 + switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
49 + MT7621ST and MT7623AI SoCs, and built-in switch in MT7988 SoC are
52 +config NET_DSA_MT7530_MDIO
53 + tristate "MediaTek MT7530 MDIO interface driver"
54 + depends on NET_DSA_MT7530
55 select MEDIATEK_GE_PHY
58 - This enables support for the MediaTek MT7530, MT7531, and MT7621
59 - Ethernet switch chips.
60 + This enables support for the MediaTek MT7530 and MT7531 switch
61 + chips which are connected via MDIO, as well as multi-chip
62 + module MT7530 which can be found in the MT7621AT, MT7621DAT,
63 + MT7621ST and MT7623AI SoCs.
65 config NET_DSA_MV88E6060
66 tristate "Marvell 88E6060 ethernet switch chip support"
67 --- a/drivers/net/dsa/Makefile
68 +++ b/drivers/net/dsa/Makefile
69 @@ -7,6 +7,7 @@ obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdi
71 obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
72 obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
73 +obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o
74 obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
75 obj-$(CONFIG_NET_DSA_RZN1_A5PSW) += rzn1_a5psw.o
76 obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
78 +++ b/drivers/net/dsa/mt7530-mdio.c
80 +// SPDX-License-Identifier: GPL-2.0-only
82 +#include <linux/gpio/consumer.h>
83 +#include <linux/mdio.h>
84 +#include <linux/module.h>
85 +#include <linux/pcs/pcs-mtk-lynxi.h>
86 +#include <linux/of_irq.h>
87 +#include <linux/of_mdio.h>
88 +#include <linux/of_net.h>
89 +#include <linux/of_platform.h>
90 +#include <linux/regmap.h>
91 +#include <linux/reset.h>
92 +#include <linux/regulator/consumer.h>
98 +mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
100 + struct mii_bus *bus = context;
101 + u16 page, r, lo, hi;
104 + page = (reg >> 6) & 0x3ff;
105 + r = (reg >> 2) & 0xf;
109 + /* MT7530 uses 31 as the pseudo port */
110 + ret = bus->write(bus, 0x1f, 0x1f, page);
114 + ret = bus->write(bus, 0x1f, r, lo);
118 + ret = bus->write(bus, 0x1f, 0x10, hi);
123 +mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
125 + struct mii_bus *bus = context;
126 + u16 page, r, lo, hi;
129 + page = (reg >> 6) & 0x3ff;
130 + r = (reg >> 2) & 0xf;
132 + /* MT7530 uses 31 as the pseudo port */
133 + ret = bus->write(bus, 0x1f, 0x1f, page);
137 + lo = bus->read(bus, 0x1f, r);
138 + hi = bus->read(bus, 0x1f, 0x10);
140 + *val = (hi << 16) | (lo & 0xffff);
146 +mt7530_mdio_regmap_lock(void *mdio_lock)
148 + mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
152 +mt7530_mdio_regmap_unlock(void *mdio_lock)
154 + mutex_unlock(mdio_lock);
157 +static const struct regmap_bus mt7530_regmap_bus = {
158 + .reg_write = mt7530_regmap_write,
159 + .reg_read = mt7530_regmap_read,
163 +mt7531_create_sgmii(struct mt7530_priv *priv)
165 + struct regmap_config *mt7531_pcs_config[2];
166 + struct phylink_pcs *pcs;
167 + struct regmap *regmap;
170 + for (i = 0; i < 2; i++) {
171 + mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
172 + sizeof(struct regmap_config),
174 + if (!mt7531_pcs_config[i]) {
179 + mt7531_pcs_config[i]->name = i ? "port6" : "port5";
180 + mt7531_pcs_config[i]->reg_bits = 16;
181 + mt7531_pcs_config[i]->val_bits = 32;
182 + mt7531_pcs_config[i]->reg_stride = 4;
183 + mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
184 + mt7531_pcs_config[i]->max_register = 0x17c;
185 + mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock;
186 + mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
187 + mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
189 + regmap = devm_regmap_init(priv->dev,
190 + &mt7530_regmap_bus, priv->bus,
191 + mt7531_pcs_config[i]);
192 + if (IS_ERR(regmap)) {
193 + ret = PTR_ERR(regmap);
196 + pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
197 + MT7531_PHYA_CTRL_SIGNAL3, 0);
202 + priv->ports[5 + i].sgmii_pcs = pcs;
206 + mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
211 +static const struct of_device_id mt7530_of_match[] = {
212 + { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
213 + { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
214 + { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
215 + { /* sentinel */ },
217 +MODULE_DEVICE_TABLE(of, mt7530_of_match);
220 +mt7530_probe(struct mdio_device *mdiodev)
222 + static struct regmap_config *regmap_config;
223 + struct mt7530_priv *priv;
224 + struct device_node *dn;
227 + dn = mdiodev->dev.of_node;
229 + priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
233 + priv->bus = mdiodev->bus;
234 + priv->dev = &mdiodev->dev;
236 + ret = mt7530_probe_common(priv);
240 + /* Use medatek,mcm property to distinguish hardware type that would
241 + * cause a little bit differences on power-on sequence.
242 + * Not MCM that indicates switch works as the remote standalone
243 + * integrated circuit so the GPIO pin would be used to complete
244 + * the reset, otherwise memory-mapped register accessing used
245 + * through syscon provides in the case of MCM.
247 + priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
249 + dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
251 + priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
252 + if (IS_ERR(priv->rstc)) {
253 + dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
254 + return PTR_ERR(priv->rstc);
257 + priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
259 + if (IS_ERR(priv->reset)) {
260 + dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
261 + return PTR_ERR(priv->reset);
265 + if (priv->id == ID_MT7530) {
266 + priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
267 + if (IS_ERR(priv->core_pwr))
268 + return PTR_ERR(priv->core_pwr);
270 + priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
271 + if (IS_ERR(priv->io_pwr))
272 + return PTR_ERR(priv->io_pwr);
275 + regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config),
277 + if (!regmap_config)
280 + regmap_config->reg_bits = 16;
281 + regmap_config->val_bits = 32;
282 + regmap_config->reg_stride = 4;
283 + regmap_config->max_register = MT7530_CREV;
284 + regmap_config->disable_locking = true;
285 + priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
286 + priv->bus, regmap_config);
287 + if (IS_ERR(priv->regmap))
288 + return PTR_ERR(priv->regmap);
290 + if (priv->id == ID_MT7531) {
291 + ret = mt7531_create_sgmii(priv);
296 + return dsa_register_switch(priv->ds);
300 +mt7530_remove(struct mdio_device *mdiodev)
302 + struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
308 + ret = regulator_disable(priv->core_pwr);
311 + "Failed to disable core power: %d\n", ret);
313 + ret = regulator_disable(priv->io_pwr);
315 + dev_err(priv->dev, "Failed to disable io pwr: %d\n",
318 + mt7530_remove_common(priv);
320 + for (i = 0; i < 2; ++i)
321 + mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
324 +static void mt7530_shutdown(struct mdio_device *mdiodev)
326 + struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
331 + dsa_switch_shutdown(priv->ds);
333 + dev_set_drvdata(&mdiodev->dev, NULL);
336 +static struct mdio_driver mt7530_mdio_driver = {
337 + .probe = mt7530_probe,
338 + .remove = mt7530_remove,
339 + .shutdown = mt7530_shutdown,
340 + .mdiodrv.driver = {
341 + .name = "mt7530-mdio",
342 + .of_match_table = mt7530_of_match,
346 +mdio_module_driver(mt7530_mdio_driver);
348 +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
349 +MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MDIO)");
350 +MODULE_LICENSE("GPL");
351 --- a/drivers/net/dsa/mt7530.c
352 +++ b/drivers/net/dsa/mt7530.c
354 #include <linux/of_mdio.h>
355 #include <linux/of_net.h>
356 #include <linux/of_platform.h>
357 -#include <linux/pcs/pcs-mtk-lynxi.h>
358 #include <linux/phylink.h>
359 #include <linux/regmap.h>
360 #include <linux/regulator/consumer.h>
361 @@ -192,31 +191,6 @@ core_clear(struct mt7530_priv *priv, u32
365 -mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
367 - struct mii_bus *bus = context;
368 - u16 page, r, lo, hi;
371 - page = (reg >> 6) & 0x3ff;
372 - r = (reg >> 2) & 0xf;
376 - /* MT7530 uses 31 as the pseudo port */
377 - ret = bus->write(bus, 0x1f, 0x1f, page);
381 - ret = bus->write(bus, 0x1f, r, lo);
385 - ret = bus->write(bus, 0x1f, 0x10, hi);
390 mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
393 @@ -230,29 +204,6 @@ mt7530_mii_write(struct mt7530_priv *pri
398 -mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
400 - struct mii_bus *bus = context;
401 - u16 page, r, lo, hi;
404 - page = (reg >> 6) & 0x3ff;
405 - r = (reg >> 2) & 0xf;
407 - /* MT7530 uses 31 as the pseudo port */
408 - ret = bus->write(bus, 0x1f, 0x1f, page);
412 - lo = bus->read(bus, 0x1f, r);
413 - hi = bus->read(bus, 0x1f, 0x10);
415 - *val = (hi << 16) | (lo & 0xffff);
421 mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
423 @@ -3008,72 +2959,6 @@ static const struct phylink_pcs_ops mt75
424 .pcs_an_restart = mt7530_pcs_an_restart,
428 -mt7530_mdio_regmap_lock(void *mdio_lock)
430 - mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
434 -mt7530_mdio_regmap_unlock(void *mdio_lock)
436 - mutex_unlock(mdio_lock);
439 -static const struct regmap_bus mt7530_regmap_bus = {
440 - .reg_write = mt7530_regmap_write,
441 - .reg_read = mt7530_regmap_read,
445 -mt7531_create_sgmii(struct mt7530_priv *priv)
447 - struct regmap_config *mt7531_pcs_config[2];
448 - struct phylink_pcs *pcs;
449 - struct regmap *regmap;
452 - for (i = 0; i < 2; i++) {
453 - mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
454 - sizeof(struct regmap_config),
456 - if (!mt7531_pcs_config[i]) {
461 - mt7531_pcs_config[i]->name = i ? "port6" : "port5";
462 - mt7531_pcs_config[i]->reg_bits = 16;
463 - mt7531_pcs_config[i]->val_bits = 32;
464 - mt7531_pcs_config[i]->reg_stride = 4;
465 - mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
466 - mt7531_pcs_config[i]->max_register = 0x17c;
467 - mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock;
468 - mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
469 - mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
471 - regmap = devm_regmap_init(priv->dev,
472 - &mt7530_regmap_bus, priv->bus,
473 - mt7531_pcs_config[i]);
474 - if (IS_ERR(regmap)) {
475 - ret = PTR_ERR(regmap);
478 - pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
479 - MT7531_PHYA_CTRL_SIGNAL3, 0);
484 - priv->ports[5 + i].sgmii_pcs = pcs;
488 - mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
494 mt753x_setup(struct dsa_switch *ds)
496 @@ -3132,7 +3017,7 @@ static int mt753x_set_mac_eee(struct dsa
500 -static const struct dsa_switch_ops mt7530_switch_ops = {
501 +const struct dsa_switch_ops mt7530_switch_ops = {
502 .get_tag_protocol = mtk_get_tag_protocol,
503 .setup = mt753x_setup,
504 .get_strings = mt7530_get_strings,
505 @@ -3166,8 +3051,9 @@ static const struct dsa_switch_ops mt753
506 .get_mac_eee = mt753x_get_mac_eee,
507 .set_mac_eee = mt753x_set_mac_eee,
509 +EXPORT_SYMBOL_GPL(mt7530_switch_ops);
511 -static const struct mt753x_info mt753x_table[] = {
512 +const struct mt753x_info mt753x_table[] = {
515 .pcs_ops = &mt7530_pcs_ops,
516 @@ -3200,16 +3086,9 @@ static const struct mt753x_info mt753x_t
517 .mac_port_config = mt7531_mac_config,
520 +EXPORT_SYMBOL_GPL(mt753x_table);
522 -static const struct of_device_id mt7530_of_match[] = {
523 - { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
524 - { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
525 - { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
526 - { /* sentinel */ },
528 -MODULE_DEVICE_TABLE(of, mt7530_of_match);
532 mt7530_probe_common(struct mt7530_priv *priv)
534 struct device *dev = priv->dev;
535 @@ -3246,88 +3125,9 @@ mt7530_probe_common(struct mt7530_priv *
539 +EXPORT_SYMBOL_GPL(mt7530_probe_common);
542 -mt7530_probe(struct mdio_device *mdiodev)
544 - static struct regmap_config *regmap_config;
545 - struct mt7530_priv *priv;
546 - struct device_node *dn;
549 - dn = mdiodev->dev.of_node;
551 - priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
555 - priv->bus = mdiodev->bus;
556 - priv->dev = &mdiodev->dev;
558 - ret = mt7530_probe_common(priv);
562 - /* Use medatek,mcm property to distinguish hardware type that would
563 - * cause a little bit differences on power-on sequence.
564 - * Not MCM that indicates switch works as the remote standalone
565 - * integrated circuit so the GPIO pin would be used to complete
566 - * the reset, otherwise memory-mapped register accessing used
567 - * through syscon provides in the case of MCM.
569 - priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
571 - dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
573 - priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
574 - if (IS_ERR(priv->rstc)) {
575 - dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
576 - return PTR_ERR(priv->rstc);
579 - priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
581 - if (IS_ERR(priv->reset)) {
582 - dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
583 - return PTR_ERR(priv->reset);
587 - if (priv->id == ID_MT7530) {
588 - priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
589 - if (IS_ERR(priv->core_pwr))
590 - return PTR_ERR(priv->core_pwr);
592 - priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
593 - if (IS_ERR(priv->io_pwr))
594 - return PTR_ERR(priv->io_pwr);
597 - regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config),
599 - if (!regmap_config)
602 - regmap_config->reg_bits = 16;
603 - regmap_config->val_bits = 32;
604 - regmap_config->reg_stride = 4;
605 - regmap_config->max_register = MT7530_CREV;
606 - regmap_config->disable_locking = true;
607 - priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
608 - priv->bus, regmap_config);
609 - if (IS_ERR(priv->regmap))
610 - return PTR_ERR(priv->regmap);
612 - if (priv->id == ID_MT7531) {
613 - ret = mt7531_create_sgmii(priv);
618 - return dsa_register_switch(priv->ds);
623 mt7530_remove_common(struct mt7530_priv *priv)
626 @@ -3337,55 +3137,7 @@ mt7530_remove_common(struct mt7530_priv
628 mutex_destroy(&priv->reg_mutex);
632 -mt7530_remove(struct mdio_device *mdiodev)
634 - struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
640 - ret = regulator_disable(priv->core_pwr);
643 - "Failed to disable core power: %d\n", ret);
645 - ret = regulator_disable(priv->io_pwr);
647 - dev_err(priv->dev, "Failed to disable io pwr: %d\n",
650 - mt7530_remove_common(priv);
652 - for (i = 0; i < 2; ++i)
653 - mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
656 -static void mt7530_shutdown(struct mdio_device *mdiodev)
658 - struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
663 - dsa_switch_shutdown(priv->ds);
665 - dev_set_drvdata(&mdiodev->dev, NULL);
668 -static struct mdio_driver mt7530_mdio_driver = {
669 - .probe = mt7530_probe,
670 - .remove = mt7530_remove,
671 - .shutdown = mt7530_shutdown,
672 - .mdiodrv.driver = {
674 - .of_match_table = mt7530_of_match,
678 -mdio_module_driver(mt7530_mdio_driver);
679 +EXPORT_SYMBOL_GPL(mt7530_remove_common);
681 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
682 MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
683 --- a/drivers/net/dsa/mt7530.h
684 +++ b/drivers/net/dsa/mt7530.h
685 @@ -834,4 +834,10 @@ static inline void INIT_MT7530_DUMMY_POL
689 +int mt7530_probe_common(struct mt7530_priv *priv);
690 +void mt7530_remove_common(struct mt7530_priv *priv);
692 +extern const struct dsa_switch_ops mt7530_switch_ops;
693 +extern const struct mt753x_info mt753x_table[];
695 #endif /* __MT7530_H */