mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-24 15:56:49 +00:00
401a6ccfaf
Backport lots upstream changes, many of them fixes, for the mt7530 DSA driver. Some of them may or may not find they way into Linux 6.1 stable, some certainly won't because they are fixes for backported commits which aren't even present in Linux 6.1 upstream. Apart from adding new patches, also remove mutated patch 723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch which should never have been added for Linux 6.1 -- it was applied already upstream but coincidentally would fuzzy-apply in the wrong place as well (for MT7530 instead of MT7531). While that didn't really hurt anyone it is just unneeded. The other deleted patch 795-mt7530-register-OF-node-for-internal-MDIO-bus.patch has been replaced by an equivalent commit with a more complete patch description by upstream maintainer Arınç Ünal. The remaining differences compared to the upstream driver are: * C22/C45 MDIO ops aren't split Upstream did that, backporting it would require making changes to *all* DSA drivers * 'slave' -> 'user', 'master' -> 'conduit' language change in DSA * support for selecting preferred CPU port on MT7531 Also this would require too many DSA framework changes potentially affecting other devices. If we ever really use Linux 6.1 in a release (I hope not) we can still reconsider to make the effort to backport that. In addition to some minor bug fixes and style improvements the switch should now behave more conformant when it comes to link-local frames, and we will again be able to cleanly pick patches from upstream. MAINTAIERS NOTE: Three patches are already part of Linux stable and should be removed with the next minor kernel version bump: 789-STABLE-01-net-dsa-mt7530-prevent-possible-incorrect-XTAL-frequ.patch 789-STABLE-02-net-dsa-mt7530-fix-link-local-frames-that-ingress-vl.patch 789-STABLE-03-net-dsa-mt7530-fix-handling-of-all-link-local-frames.patch Signed-off-by: Daniel Golle <daniel@makrotopia.org>
696 lines
18 KiB
Diff
696 lines
18 KiB
Diff
From 5313432ca1e1a0677ad7b4f17a7e0186473f47aa Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Mon, 3 Apr 2023 02:19:13 +0100
|
|
Subject: [PATCH 12/48] net: dsa: mt7530: introduce separate MDIO driver
|
|
|
|
Split MT7530 switch driver into a common part and a part specific
|
|
for MDIO connected switches and multi-chip modules.
|
|
Move MDIO-specific functions to newly introduced mt7530-mdio.c while
|
|
keeping the common parts in mt7530.c.
|
|
Introduce new Kconfig symbol CONFIG_NET_DSA_MT7530_MDIO which is
|
|
implied by CONFIG_NET_DSA_MT7530.
|
|
|
|
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
|
---
|
|
MAINTAINERS | 1 +
|
|
drivers/net/dsa/Kconfig | 18 ++-
|
|
drivers/net/dsa/Makefile | 1 +
|
|
drivers/net/dsa/mt7530-mdio.c | 271 ++++++++++++++++++++++++++++++++++
|
|
drivers/net/dsa/mt7530.c | 264 +--------------------------------
|
|
drivers/net/dsa/mt7530.h | 6 +
|
|
6 files changed, 302 insertions(+), 259 deletions(-)
|
|
create mode 100644 drivers/net/dsa/mt7530-mdio.c
|
|
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -13069,6 +13069,7 @@ M: Landen Chao <Landen.Chao@mediatek.com
|
|
M: DENG Qingfang <dqfext@gmail.com>
|
|
L: netdev@vger.kernel.org
|
|
S: Maintained
|
|
+F: drivers/net/dsa/mt7530-mdio.c
|
|
F: drivers/net/dsa/mt7530.*
|
|
F: net/dsa/tag_mtk.c
|
|
|
|
--- a/drivers/net/dsa/Kconfig
|
|
+++ b/drivers/net/dsa/Kconfig
|
|
@@ -34,13 +34,25 @@ config NET_DSA_LANTIQ_GSWIP
|
|
the xrx200 / VR9 SoC.
|
|
|
|
config NET_DSA_MT7530
|
|
- tristate "MediaTek MT753x and MT7621 Ethernet switch support"
|
|
+ tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
|
|
select NET_DSA_TAG_MTK
|
|
+ imply NET_DSA_MT7530_MDIO
|
|
+ help
|
|
+ This enables support for the MediaTek MT7530 and MT7531 Ethernet
|
|
+ switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
|
|
+ MT7621ST and MT7623AI SoCs, and built-in switch in MT7988 SoC are
|
|
+ supported as well.
|
|
+
|
|
+config NET_DSA_MT7530_MDIO
|
|
+ tristate "MediaTek MT7530 MDIO interface driver"
|
|
+ depends on NET_DSA_MT7530
|
|
select MEDIATEK_GE_PHY
|
|
select PCS_MTK_LYNXI
|
|
help
|
|
- This enables support for the MediaTek MT7530, MT7531, and MT7621
|
|
- Ethernet switch chips.
|
|
+ This enables support for the MediaTek MT7530 and MT7531 switch
|
|
+ chips which are connected via MDIO, as well as multi-chip
|
|
+ module MT7530 which can be found in the MT7621AT, MT7621DAT,
|
|
+ MT7621ST and MT7623AI SoCs.
|
|
|
|
config NET_DSA_MV88E6060
|
|
tristate "Marvell 88E6060 ethernet switch chip support"
|
|
--- a/drivers/net/dsa/Makefile
|
|
+++ b/drivers/net/dsa/Makefile
|
|
@@ -7,6 +7,7 @@ obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdi
|
|
endif
|
|
obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o
|
|
obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o
|
|
+obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o
|
|
obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
|
|
obj-$(CONFIG_NET_DSA_RZN1_A5PSW) += rzn1_a5psw.o
|
|
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/mt7530-mdio.c
|
|
@@ -0,0 +1,271 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+#include <linux/gpio/consumer.h>
|
|
+#include <linux/mdio.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/pcs/pcs-mtk-lynxi.h>
|
|
+#include <linux/of_irq.h>
|
|
+#include <linux/of_mdio.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/reset.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include <net/dsa.h>
|
|
+
|
|
+#include "mt7530.h"
|
|
+
|
|
+static int
|
|
+mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
|
|
+{
|
|
+ struct mii_bus *bus = context;
|
|
+ u16 page, r, lo, hi;
|
|
+ int ret;
|
|
+
|
|
+ page = (reg >> 6) & 0x3ff;
|
|
+ r = (reg >> 2) & 0xf;
|
|
+ lo = val & 0xffff;
|
|
+ hi = val >> 16;
|
|
+
|
|
+ /* MT7530 uses 31 as the pseudo port */
|
|
+ ret = bus->write(bus, 0x1f, 0x1f, page);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = bus->write(bus, 0x1f, r, lo);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = bus->write(bus, 0x1f, 0x10, hi);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
|
|
+{
|
|
+ struct mii_bus *bus = context;
|
|
+ u16 page, r, lo, hi;
|
|
+ int ret;
|
|
+
|
|
+ page = (reg >> 6) & 0x3ff;
|
|
+ r = (reg >> 2) & 0xf;
|
|
+
|
|
+ /* MT7530 uses 31 as the pseudo port */
|
|
+ ret = bus->write(bus, 0x1f, 0x1f, page);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ lo = bus->read(bus, 0x1f, r);
|
|
+ hi = bus->read(bus, 0x1f, 0x10);
|
|
+
|
|
+ *val = (hi << 16) | (lo & 0xffff);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void
|
|
+mt7530_mdio_regmap_lock(void *mdio_lock)
|
|
+{
|
|
+ mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
|
|
+}
|
|
+
|
|
+static void
|
|
+mt7530_mdio_regmap_unlock(void *mdio_lock)
|
|
+{
|
|
+ mutex_unlock(mdio_lock);
|
|
+}
|
|
+
|
|
+static const struct regmap_bus mt7530_regmap_bus = {
|
|
+ .reg_write = mt7530_regmap_write,
|
|
+ .reg_read = mt7530_regmap_read,
|
|
+};
|
|
+
|
|
+static int
|
|
+mt7531_create_sgmii(struct mt7530_priv *priv)
|
|
+{
|
|
+ struct regmap_config *mt7531_pcs_config[2];
|
|
+ struct phylink_pcs *pcs;
|
|
+ struct regmap *regmap;
|
|
+ int i, ret = 0;
|
|
+
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
|
|
+ sizeof(struct regmap_config),
|
|
+ GFP_KERNEL);
|
|
+ if (!mt7531_pcs_config[i]) {
|
|
+ ret = -ENOMEM;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ mt7531_pcs_config[i]->name = i ? "port6" : "port5";
|
|
+ mt7531_pcs_config[i]->reg_bits = 16;
|
|
+ mt7531_pcs_config[i]->val_bits = 32;
|
|
+ mt7531_pcs_config[i]->reg_stride = 4;
|
|
+ mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
|
|
+ mt7531_pcs_config[i]->max_register = 0x17c;
|
|
+ mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock;
|
|
+ mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
|
|
+ mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
|
|
+
|
|
+ regmap = devm_regmap_init(priv->dev,
|
|
+ &mt7530_regmap_bus, priv->bus,
|
|
+ mt7531_pcs_config[i]);
|
|
+ if (IS_ERR(regmap)) {
|
|
+ ret = PTR_ERR(regmap);
|
|
+ break;
|
|
+ }
|
|
+ pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
|
|
+ MT7531_PHYA_CTRL_SIGNAL3, 0);
|
|
+ if (!pcs) {
|
|
+ ret = -ENXIO;
|
|
+ break;
|
|
+ }
|
|
+ priv->ports[5 + i].sgmii_pcs = pcs;
|
|
+ }
|
|
+
|
|
+ if (ret && i)
|
|
+ mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct of_device_id mt7530_of_match[] = {
|
|
+ { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
|
|
+ { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
|
|
+ { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, mt7530_of_match);
|
|
+
|
|
+static int
|
|
+mt7530_probe(struct mdio_device *mdiodev)
|
|
+{
|
|
+ static struct regmap_config *regmap_config;
|
|
+ struct mt7530_priv *priv;
|
|
+ struct device_node *dn;
|
|
+ int ret;
|
|
+
|
|
+ dn = mdiodev->dev.of_node;
|
|
+
|
|
+ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ priv->bus = mdiodev->bus;
|
|
+ priv->dev = &mdiodev->dev;
|
|
+
|
|
+ ret = mt7530_probe_common(priv);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Use medatek,mcm property to distinguish hardware type that would
|
|
+ * cause a little bit differences on power-on sequence.
|
|
+ * Not MCM that indicates switch works as the remote standalone
|
|
+ * integrated circuit so the GPIO pin would be used to complete
|
|
+ * the reset, otherwise memory-mapped register accessing used
|
|
+ * through syscon provides in the case of MCM.
|
|
+ */
|
|
+ priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
|
|
+ if (priv->mcm) {
|
|
+ dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
|
|
+
|
|
+ priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
|
|
+ if (IS_ERR(priv->rstc)) {
|
|
+ dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
|
|
+ return PTR_ERR(priv->rstc);
|
|
+ }
|
|
+ } else {
|
|
+ priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
|
|
+ GPIOD_OUT_LOW);
|
|
+ if (IS_ERR(priv->reset)) {
|
|
+ dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
|
|
+ return PTR_ERR(priv->reset);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (priv->id == ID_MT7530) {
|
|
+ priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
|
|
+ if (IS_ERR(priv->core_pwr))
|
|
+ return PTR_ERR(priv->core_pwr);
|
|
+
|
|
+ priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
|
|
+ if (IS_ERR(priv->io_pwr))
|
|
+ return PTR_ERR(priv->io_pwr);
|
|
+ }
|
|
+
|
|
+ regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config),
|
|
+ GFP_KERNEL);
|
|
+ if (!regmap_config)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ regmap_config->reg_bits = 16;
|
|
+ regmap_config->val_bits = 32;
|
|
+ regmap_config->reg_stride = 4;
|
|
+ regmap_config->max_register = MT7530_CREV;
|
|
+ regmap_config->disable_locking = true;
|
|
+ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
|
|
+ priv->bus, regmap_config);
|
|
+ if (IS_ERR(priv->regmap))
|
|
+ return PTR_ERR(priv->regmap);
|
|
+
|
|
+ if (priv->id == ID_MT7531) {
|
|
+ ret = mt7531_create_sgmii(priv);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return dsa_register_switch(priv->ds);
|
|
+}
|
|
+
|
|
+static void
|
|
+mt7530_remove(struct mdio_device *mdiodev)
|
|
+{
|
|
+ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
|
|
+ int ret = 0, i;
|
|
+
|
|
+ if (!priv)
|
|
+ return;
|
|
+
|
|
+ ret = regulator_disable(priv->core_pwr);
|
|
+ if (ret < 0)
|
|
+ dev_err(priv->dev,
|
|
+ "Failed to disable core power: %d\n", ret);
|
|
+
|
|
+ ret = regulator_disable(priv->io_pwr);
|
|
+ if (ret < 0)
|
|
+ dev_err(priv->dev, "Failed to disable io pwr: %d\n",
|
|
+ ret);
|
|
+
|
|
+ mt7530_remove_common(priv);
|
|
+
|
|
+ for (i = 0; i < 2; ++i)
|
|
+ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
|
|
+}
|
|
+
|
|
+static void mt7530_shutdown(struct mdio_device *mdiodev)
|
|
+{
|
|
+ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
|
|
+
|
|
+ if (!priv)
|
|
+ return;
|
|
+
|
|
+ dsa_switch_shutdown(priv->ds);
|
|
+
|
|
+ dev_set_drvdata(&mdiodev->dev, NULL);
|
|
+}
|
|
+
|
|
+static struct mdio_driver mt7530_mdio_driver = {
|
|
+ .probe = mt7530_probe,
|
|
+ .remove = mt7530_remove,
|
|
+ .shutdown = mt7530_shutdown,
|
|
+ .mdiodrv.driver = {
|
|
+ .name = "mt7530-mdio",
|
|
+ .of_match_table = mt7530_of_match,
|
|
+ },
|
|
+};
|
|
+
|
|
+mdio_module_driver(mt7530_mdio_driver);
|
|
+
|
|
+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
|
|
+MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MDIO)");
|
|
+MODULE_LICENSE("GPL");
|
|
--- a/drivers/net/dsa/mt7530.c
|
|
+++ b/drivers/net/dsa/mt7530.c
|
|
@@ -14,7 +14,6 @@
|
|
#include <linux/of_mdio.h>
|
|
#include <linux/of_net.h>
|
|
#include <linux/of_platform.h>
|
|
-#include <linux/pcs/pcs-mtk-lynxi.h>
|
|
#include <linux/phylink.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/regulator/consumer.h>
|
|
@@ -192,31 +191,6 @@ core_clear(struct mt7530_priv *priv, u32
|
|
}
|
|
|
|
static int
|
|
-mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
|
|
-{
|
|
- struct mii_bus *bus = context;
|
|
- u16 page, r, lo, hi;
|
|
- int ret;
|
|
-
|
|
- page = (reg >> 6) & 0x3ff;
|
|
- r = (reg >> 2) & 0xf;
|
|
- lo = val & 0xffff;
|
|
- hi = val >> 16;
|
|
-
|
|
- /* MT7530 uses 31 as the pseudo port */
|
|
- ret = bus->write(bus, 0x1f, 0x1f, page);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- ret = bus->write(bus, 0x1f, r, lo);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- ret = bus->write(bus, 0x1f, 0x10, hi);
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static int
|
|
mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
|
|
{
|
|
int ret;
|
|
@@ -230,29 +204,6 @@ mt7530_mii_write(struct mt7530_priv *pri
|
|
return ret;
|
|
}
|
|
|
|
-static int
|
|
-mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
|
|
-{
|
|
- struct mii_bus *bus = context;
|
|
- u16 page, r, lo, hi;
|
|
- int ret;
|
|
-
|
|
- page = (reg >> 6) & 0x3ff;
|
|
- r = (reg >> 2) & 0xf;
|
|
-
|
|
- /* MT7530 uses 31 as the pseudo port */
|
|
- ret = bus->write(bus, 0x1f, 0x1f, page);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- lo = bus->read(bus, 0x1f, r);
|
|
- hi = bus->read(bus, 0x1f, 0x10);
|
|
-
|
|
- *val = (hi << 16) | (lo & 0xffff);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static u32
|
|
mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
|
|
{
|
|
@@ -3008,72 +2959,6 @@ static const struct phylink_pcs_ops mt75
|
|
.pcs_an_restart = mt7530_pcs_an_restart,
|
|
};
|
|
|
|
-static void
|
|
-mt7530_mdio_regmap_lock(void *mdio_lock)
|
|
-{
|
|
- mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
|
|
-}
|
|
-
|
|
-static void
|
|
-mt7530_mdio_regmap_unlock(void *mdio_lock)
|
|
-{
|
|
- mutex_unlock(mdio_lock);
|
|
-}
|
|
-
|
|
-static const struct regmap_bus mt7530_regmap_bus = {
|
|
- .reg_write = mt7530_regmap_write,
|
|
- .reg_read = mt7530_regmap_read,
|
|
-};
|
|
-
|
|
-static int
|
|
-mt7531_create_sgmii(struct mt7530_priv *priv)
|
|
-{
|
|
- struct regmap_config *mt7531_pcs_config[2];
|
|
- struct phylink_pcs *pcs;
|
|
- struct regmap *regmap;
|
|
- int i, ret = 0;
|
|
-
|
|
- for (i = 0; i < 2; i++) {
|
|
- mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
|
|
- sizeof(struct regmap_config),
|
|
- GFP_KERNEL);
|
|
- if (!mt7531_pcs_config[i]) {
|
|
- ret = -ENOMEM;
|
|
- break;
|
|
- }
|
|
-
|
|
- mt7531_pcs_config[i]->name = i ? "port6" : "port5";
|
|
- mt7531_pcs_config[i]->reg_bits = 16;
|
|
- mt7531_pcs_config[i]->val_bits = 32;
|
|
- mt7531_pcs_config[i]->reg_stride = 4;
|
|
- mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
|
|
- mt7531_pcs_config[i]->max_register = 0x17c;
|
|
- mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock;
|
|
- mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
|
|
- mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
|
|
-
|
|
- regmap = devm_regmap_init(priv->dev,
|
|
- &mt7530_regmap_bus, priv->bus,
|
|
- mt7531_pcs_config[i]);
|
|
- if (IS_ERR(regmap)) {
|
|
- ret = PTR_ERR(regmap);
|
|
- break;
|
|
- }
|
|
- pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
|
|
- MT7531_PHYA_CTRL_SIGNAL3, 0);
|
|
- if (!pcs) {
|
|
- ret = -ENXIO;
|
|
- break;
|
|
- }
|
|
- priv->ports[5 + i].sgmii_pcs = pcs;
|
|
- }
|
|
-
|
|
- if (ret && i)
|
|
- mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
static int
|
|
mt753x_setup(struct dsa_switch *ds)
|
|
{
|
|
@@ -3132,7 +3017,7 @@ static int mt753x_set_mac_eee(struct dsa
|
|
return 0;
|
|
}
|
|
|
|
-static const struct dsa_switch_ops mt7530_switch_ops = {
|
|
+const struct dsa_switch_ops mt7530_switch_ops = {
|
|
.get_tag_protocol = mtk_get_tag_protocol,
|
|
.setup = mt753x_setup,
|
|
.get_strings = mt7530_get_strings,
|
|
@@ -3166,8 +3051,9 @@ static const struct dsa_switch_ops mt753
|
|
.get_mac_eee = mt753x_get_mac_eee,
|
|
.set_mac_eee = mt753x_set_mac_eee,
|
|
};
|
|
+EXPORT_SYMBOL_GPL(mt7530_switch_ops);
|
|
|
|
-static const struct mt753x_info mt753x_table[] = {
|
|
+const struct mt753x_info mt753x_table[] = {
|
|
[ID_MT7621] = {
|
|
.id = ID_MT7621,
|
|
.pcs_ops = &mt7530_pcs_ops,
|
|
@@ -3200,16 +3086,9 @@ static const struct mt753x_info mt753x_t
|
|
.mac_port_config = mt7531_mac_config,
|
|
},
|
|
};
|
|
+EXPORT_SYMBOL_GPL(mt753x_table);
|
|
|
|
-static const struct of_device_id mt7530_of_match[] = {
|
|
- { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
|
|
- { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
|
|
- { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
|
|
- { /* sentinel */ },
|
|
-};
|
|
-MODULE_DEVICE_TABLE(of, mt7530_of_match);
|
|
-
|
|
-static int
|
|
+int
|
|
mt7530_probe_common(struct mt7530_priv *priv)
|
|
{
|
|
struct device *dev = priv->dev;
|
|
@@ -3246,88 +3125,9 @@ mt7530_probe_common(struct mt7530_priv *
|
|
|
|
return 0;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(mt7530_probe_common);
|
|
|
|
-static int
|
|
-mt7530_probe(struct mdio_device *mdiodev)
|
|
-{
|
|
- static struct regmap_config *regmap_config;
|
|
- struct mt7530_priv *priv;
|
|
- struct device_node *dn;
|
|
- int ret;
|
|
-
|
|
- dn = mdiodev->dev.of_node;
|
|
-
|
|
- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
|
|
- if (!priv)
|
|
- return -ENOMEM;
|
|
-
|
|
- priv->bus = mdiodev->bus;
|
|
- priv->dev = &mdiodev->dev;
|
|
-
|
|
- ret = mt7530_probe_common(priv);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Use medatek,mcm property to distinguish hardware type that would
|
|
- * cause a little bit differences on power-on sequence.
|
|
- * Not MCM that indicates switch works as the remote standalone
|
|
- * integrated circuit so the GPIO pin would be used to complete
|
|
- * the reset, otherwise memory-mapped register accessing used
|
|
- * through syscon provides in the case of MCM.
|
|
- */
|
|
- priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
|
|
- if (priv->mcm) {
|
|
- dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
|
|
-
|
|
- priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
|
|
- if (IS_ERR(priv->rstc)) {
|
|
- dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
|
|
- return PTR_ERR(priv->rstc);
|
|
- }
|
|
- } else {
|
|
- priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
|
|
- GPIOD_OUT_LOW);
|
|
- if (IS_ERR(priv->reset)) {
|
|
- dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
|
|
- return PTR_ERR(priv->reset);
|
|
- }
|
|
- }
|
|
-
|
|
- if (priv->id == ID_MT7530) {
|
|
- priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
|
|
- if (IS_ERR(priv->core_pwr))
|
|
- return PTR_ERR(priv->core_pwr);
|
|
-
|
|
- priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
|
|
- if (IS_ERR(priv->io_pwr))
|
|
- return PTR_ERR(priv->io_pwr);
|
|
- }
|
|
-
|
|
- regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config),
|
|
- GFP_KERNEL);
|
|
- if (!regmap_config)
|
|
- return -ENOMEM;
|
|
-
|
|
- regmap_config->reg_bits = 16;
|
|
- regmap_config->val_bits = 32;
|
|
- regmap_config->reg_stride = 4;
|
|
- regmap_config->max_register = MT7530_CREV;
|
|
- regmap_config->disable_locking = true;
|
|
- priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
|
|
- priv->bus, regmap_config);
|
|
- if (IS_ERR(priv->regmap))
|
|
- return PTR_ERR(priv->regmap);
|
|
-
|
|
- if (priv->id == ID_MT7531) {
|
|
- ret = mt7531_create_sgmii(priv);
|
|
- if (ret)
|
|
- return ret;
|
|
- }
|
|
-
|
|
- return dsa_register_switch(priv->ds);
|
|
-}
|
|
-
|
|
-static void
|
|
+void
|
|
mt7530_remove_common(struct mt7530_priv *priv)
|
|
{
|
|
if (priv->irq)
|
|
@@ -3337,55 +3137,7 @@ mt7530_remove_common(struct mt7530_priv
|
|
|
|
mutex_destroy(&priv->reg_mutex);
|
|
}
|
|
-
|
|
-static void
|
|
-mt7530_remove(struct mdio_device *mdiodev)
|
|
-{
|
|
- struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
|
|
- int ret = 0, i;
|
|
-
|
|
- if (!priv)
|
|
- return;
|
|
-
|
|
- ret = regulator_disable(priv->core_pwr);
|
|
- if (ret < 0)
|
|
- dev_err(priv->dev,
|
|
- "Failed to disable core power: %d\n", ret);
|
|
-
|
|
- ret = regulator_disable(priv->io_pwr);
|
|
- if (ret < 0)
|
|
- dev_err(priv->dev, "Failed to disable io pwr: %d\n",
|
|
- ret);
|
|
-
|
|
- mt7530_remove_common(priv);
|
|
-
|
|
- for (i = 0; i < 2; ++i)
|
|
- mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
|
|
-}
|
|
-
|
|
-static void mt7530_shutdown(struct mdio_device *mdiodev)
|
|
-{
|
|
- struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
|
|
-
|
|
- if (!priv)
|
|
- return;
|
|
-
|
|
- dsa_switch_shutdown(priv->ds);
|
|
-
|
|
- dev_set_drvdata(&mdiodev->dev, NULL);
|
|
-}
|
|
-
|
|
-static struct mdio_driver mt7530_mdio_driver = {
|
|
- .probe = mt7530_probe,
|
|
- .remove = mt7530_remove,
|
|
- .shutdown = mt7530_shutdown,
|
|
- .mdiodrv.driver = {
|
|
- .name = "mt7530",
|
|
- .of_match_table = mt7530_of_match,
|
|
- },
|
|
-};
|
|
-
|
|
-mdio_module_driver(mt7530_mdio_driver);
|
|
+EXPORT_SYMBOL_GPL(mt7530_remove_common);
|
|
|
|
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
|
|
MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
|
|
--- a/drivers/net/dsa/mt7530.h
|
|
+++ b/drivers/net/dsa/mt7530.h
|
|
@@ -834,4 +834,10 @@ static inline void INIT_MT7530_DUMMY_POL
|
|
p->reg = reg;
|
|
}
|
|
|
|
+int mt7530_probe_common(struct mt7530_priv *priv);
|
|
+void mt7530_remove_common(struct mt7530_priv *priv);
|
|
+
|
|
+extern const struct dsa_switch_ops mt7530_switch_ops;
|
|
+extern const struct mt753x_info mt753x_table[];
|
|
+
|
|
#endif /* __MT7530_H */
|