mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-21 06:33:41 +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>
422 lines
12 KiB
Diff
422 lines
12 KiB
Diff
From a1b87b6322db9186c8689710fe3e98f59e540949 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Mon, 3 Apr 2023 02:19:40 +0100
|
|
Subject: [PATCH 14/48] net: dsa: mt7530: introduce driver for MT7988 built-in
|
|
switch
|
|
|
|
Add driver for the built-in Gigabit Ethernet switch which can be found
|
|
in the MediaTek MT7988 SoC.
|
|
|
|
The switch shares most of its design with MT7530 and MT7531, but has
|
|
it's registers mapped into the SoCs register space rather than being
|
|
connected externally or internally via MDIO.
|
|
|
|
Introduce a new platform driver to support that.
|
|
|
|
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 | 2 +
|
|
drivers/net/dsa/Kconfig | 12 +++
|
|
drivers/net/dsa/Makefile | 1 +
|
|
drivers/net/dsa/mt7530-mmio.c | 101 +++++++++++++++++++++++++
|
|
drivers/net/dsa/mt7530.c | 135 +++++++++++++++++++++++++++++++++-
|
|
drivers/net/dsa/mt7530.h | 12 +--
|
|
6 files changed, 253 insertions(+), 10 deletions(-)
|
|
create mode 100644 drivers/net/dsa/mt7530-mmio.c
|
|
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -13067,9 +13067,11 @@ MEDIATEK SWITCH DRIVER
|
|
M: Sean Wang <sean.wang@mediatek.com>
|
|
M: Landen Chao <Landen.Chao@mediatek.com>
|
|
M: DENG Qingfang <dqfext@gmail.com>
|
|
+M: Daniel Golle <daniel@makrotopia.org>
|
|
L: netdev@vger.kernel.org
|
|
S: Maintained
|
|
F: drivers/net/dsa/mt7530-mdio.c
|
|
+F: drivers/net/dsa/mt7530-mmio.c
|
|
F: drivers/net/dsa/mt7530.*
|
|
F: net/dsa/tag_mtk.c
|
|
|
|
--- a/drivers/net/dsa/Kconfig
|
|
+++ b/drivers/net/dsa/Kconfig
|
|
@@ -37,6 +37,7 @@ config NET_DSA_MT7530
|
|
tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
|
|
select NET_DSA_TAG_MTK
|
|
imply NET_DSA_MT7530_MDIO
|
|
+ imply NET_DSA_MT7530_MMIO
|
|
help
|
|
This enables support for the MediaTek MT7530 and MT7531 Ethernet
|
|
switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
|
|
@@ -54,6 +55,17 @@ config NET_DSA_MT7530_MDIO
|
|
module MT7530 which can be found in the MT7621AT, MT7621DAT,
|
|
MT7621ST and MT7623AI SoCs.
|
|
|
|
+config NET_DSA_MT7530_MMIO
|
|
+ tristate "MediaTek MT7530 MMIO interface driver"
|
|
+ depends on NET_DSA_MT7530
|
|
+ depends on HAS_IOMEM
|
|
+ help
|
|
+ This enables support for the built-in Ethernet switch found
|
|
+ in the MediaTek MT7988 SoC.
|
|
+ The switch is a similar design as MT7531, but the switch registers
|
|
+ are directly mapped into the SoCs register space rather than being
|
|
+ accessible via MDIO.
|
|
+
|
|
config NET_DSA_MV88E6060
|
|
tristate "Marvell 88E6060 ethernet switch chip support"
|
|
select NET_DSA_TAG_TRAILER
|
|
--- a/drivers/net/dsa/Makefile
|
|
+++ b/drivers/net/dsa/Makefile
|
|
@@ -8,6 +8,7 @@ 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_MT7530_MMIO) += mt7530-mmio.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-mmio.c
|
|
@@ -0,0 +1,101 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include <linux/reset.h>
|
|
+#include <net/dsa.h>
|
|
+
|
|
+#include "mt7530.h"
|
|
+
|
|
+static const struct of_device_id mt7988_of_match[] = {
|
|
+ { .compatible = "mediatek,mt7988-switch", .data = &mt753x_table[ID_MT7988], },
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, mt7988_of_match);
|
|
+
|
|
+static int
|
|
+mt7988_probe(struct platform_device *pdev)
|
|
+{
|
|
+ static struct regmap_config *sw_regmap_config;
|
|
+ struct mt7530_priv *priv;
|
|
+ void __iomem *base_addr;
|
|
+ int ret;
|
|
+
|
|
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ priv->bus = NULL;
|
|
+ priv->dev = &pdev->dev;
|
|
+
|
|
+ ret = mt7530_probe_common(priv);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
|
|
+ if (IS_ERR(priv->rstc)) {
|
|
+ dev_err(&pdev->dev, "Couldn't get our reset line\n");
|
|
+ return PTR_ERR(priv->rstc);
|
|
+ }
|
|
+
|
|
+ base_addr = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(base_addr)) {
|
|
+ dev_err(&pdev->dev, "cannot request I/O memory space\n");
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
+ sw_regmap_config = devm_kzalloc(&pdev->dev, sizeof(*sw_regmap_config), GFP_KERNEL);
|
|
+ if (!sw_regmap_config)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ sw_regmap_config->name = "switch";
|
|
+ sw_regmap_config->reg_bits = 16;
|
|
+ sw_regmap_config->val_bits = 32;
|
|
+ sw_regmap_config->reg_stride = 4;
|
|
+ sw_regmap_config->max_register = MT7530_CREV;
|
|
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base_addr, sw_regmap_config);
|
|
+ if (IS_ERR(priv->regmap))
|
|
+ return PTR_ERR(priv->regmap);
|
|
+
|
|
+ return dsa_register_switch(priv->ds);
|
|
+}
|
|
+
|
|
+static int
|
|
+mt7988_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct mt7530_priv *priv = platform_get_drvdata(pdev);
|
|
+
|
|
+ if (priv)
|
|
+ mt7530_remove_common(priv);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mt7988_shutdown(struct platform_device *pdev)
|
|
+{
|
|
+ struct mt7530_priv *priv = platform_get_drvdata(pdev);
|
|
+
|
|
+ if (!priv)
|
|
+ return;
|
|
+
|
|
+ dsa_switch_shutdown(priv->ds);
|
|
+
|
|
+ dev_set_drvdata(&pdev->dev, NULL);
|
|
+}
|
|
+
|
|
+static struct platform_driver mt7988_platform_driver = {
|
|
+ .probe = mt7988_probe,
|
|
+ .remove = mt7988_remove,
|
|
+ .shutdown = mt7988_shutdown,
|
|
+ .driver = {
|
|
+ .name = "mt7530-mmio",
|
|
+ .of_match_table = mt7988_of_match,
|
|
+ },
|
|
+};
|
|
+module_platform_driver(mt7988_platform_driver);
|
|
+
|
|
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
|
+MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MMIO)");
|
|
+MODULE_LICENSE("GPL");
|
|
--- a/drivers/net/dsa/mt7530.c
|
|
+++ b/drivers/net/dsa/mt7530.c
|
|
@@ -2041,6 +2041,47 @@ static const struct irq_domain_ops mt753
|
|
};
|
|
|
|
static void
|
|
+mt7988_irq_mask(struct irq_data *d)
|
|
+{
|
|
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
|
|
+
|
|
+ priv->irq_enable &= ~BIT(d->hwirq);
|
|
+ mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
|
|
+}
|
|
+
|
|
+static void
|
|
+mt7988_irq_unmask(struct irq_data *d)
|
|
+{
|
|
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
|
|
+
|
|
+ priv->irq_enable |= BIT(d->hwirq);
|
|
+ mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
|
|
+}
|
|
+
|
|
+static struct irq_chip mt7988_irq_chip = {
|
|
+ .name = KBUILD_MODNAME,
|
|
+ .irq_mask = mt7988_irq_mask,
|
|
+ .irq_unmask = mt7988_irq_unmask,
|
|
+};
|
|
+
|
|
+static int
|
|
+mt7988_irq_map(struct irq_domain *domain, unsigned int irq,
|
|
+ irq_hw_number_t hwirq)
|
|
+{
|
|
+ irq_set_chip_data(irq, domain->host_data);
|
|
+ irq_set_chip_and_handler(irq, &mt7988_irq_chip, handle_simple_irq);
|
|
+ irq_set_nested_thread(irq, true);
|
|
+ irq_set_noprobe(irq);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct irq_domain_ops mt7988_irq_domain_ops = {
|
|
+ .map = mt7988_irq_map,
|
|
+ .xlate = irq_domain_xlate_onecell,
|
|
+};
|
|
+
|
|
+static void
|
|
mt7530_setup_mdio_irq(struct mt7530_priv *priv)
|
|
{
|
|
struct dsa_switch *ds = priv->ds;
|
|
@@ -2074,8 +2115,15 @@ mt7530_setup_irq(struct mt7530_priv *pri
|
|
return priv->irq ? : -EINVAL;
|
|
}
|
|
|
|
- priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
|
|
- &mt7530_irq_domain_ops, priv);
|
|
+ if (priv->id == ID_MT7988)
|
|
+ priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
|
|
+ &mt7988_irq_domain_ops,
|
|
+ priv);
|
|
+ else
|
|
+ priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
|
|
+ &mt7530_irq_domain_ops,
|
|
+ priv);
|
|
+
|
|
if (!priv->irq_domain) {
|
|
dev_err(dev, "failed to create IRQ domain\n");
|
|
return -ENOMEM;
|
|
@@ -2574,6 +2622,25 @@ static void mt7531_mac_port_get_caps(str
|
|
}
|
|
}
|
|
|
|
+static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port,
|
|
+ struct phylink_config *config)
|
|
+{
|
|
+ phy_interface_zero(config->supported_interfaces);
|
|
+
|
|
+ switch (port) {
|
|
+ case 0 ... 4: /* Internal phy */
|
|
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
|
|
+ config->supported_interfaces);
|
|
+ break;
|
|
+
|
|
+ case 6:
|
|
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
|
|
+ config->supported_interfaces);
|
|
+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
|
|
+ MAC_10000FD;
|
|
+ }
|
|
+}
|
|
+
|
|
static int
|
|
mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
|
|
{
|
|
@@ -2650,6 +2717,17 @@ static bool mt753x_is_mac_port(u32 port)
|
|
}
|
|
|
|
static int
|
|
+mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
|
|
+ phy_interface_t interface)
|
|
+{
|
|
+ if (dsa_is_cpu_port(ds, port) &&
|
|
+ interface == PHY_INTERFACE_MODE_INTERNAL)
|
|
+ return 0;
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static int
|
|
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
|
|
phy_interface_t interface)
|
|
{
|
|
@@ -2719,7 +2797,8 @@ mt753x_phylink_mac_config(struct dsa_swi
|
|
|
|
switch (port) {
|
|
case 0 ... 4: /* Internal phy */
|
|
- if (state->interface != PHY_INTERFACE_MODE_GMII)
|
|
+ if (state->interface != PHY_INTERFACE_MODE_GMII &&
|
|
+ state->interface != PHY_INTERFACE_MODE_INTERNAL)
|
|
goto unsupported;
|
|
break;
|
|
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
|
|
@@ -2797,7 +2876,8 @@ static void mt753x_phylink_mac_link_up(s
|
|
/* MT753x MAC works in 1G full duplex mode for all up-clocked
|
|
* variants.
|
|
*/
|
|
- if (interface == PHY_INTERFACE_MODE_TRGMII ||
|
|
+ if (interface == PHY_INTERFACE_MODE_INTERNAL ||
|
|
+ interface == PHY_INTERFACE_MODE_TRGMII ||
|
|
(phy_interface_mode_is_8023z(interface))) {
|
|
speed = SPEED_1000;
|
|
duplex = DUPLEX_FULL;
|
|
@@ -2877,6 +2957,21 @@ mt7531_cpu_port_config(struct dsa_switch
|
|
return 0;
|
|
}
|
|
|
|
+static int
|
|
+mt7988_cpu_port_config(struct dsa_switch *ds, int port)
|
|
+{
|
|
+ struct mt7530_priv *priv = ds->priv;
|
|
+
|
|
+ mt7530_write(priv, MT7530_PMCR_P(port),
|
|
+ PMCR_CPU_PORT_SETTING(priv->id));
|
|
+
|
|
+ mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED,
|
|
+ PHY_INTERFACE_MODE_INTERNAL, NULL,
|
|
+ SPEED_10000, DUPLEX_FULL, true, true);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
|
|
struct phylink_config *config)
|
|
{
|
|
@@ -3019,6 +3114,27 @@ static int mt753x_set_mac_eee(struct dsa
|
|
return 0;
|
|
}
|
|
|
|
+static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt7988_setup(struct dsa_switch *ds)
|
|
+{
|
|
+ struct mt7530_priv *priv = ds->priv;
|
|
+
|
|
+ /* Reset the switch */
|
|
+ reset_control_assert(priv->rstc);
|
|
+ usleep_range(20, 50);
|
|
+ reset_control_deassert(priv->rstc);
|
|
+ usleep_range(20, 50);
|
|
+
|
|
+ /* Reset the switch PHYs */
|
|
+ mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST);
|
|
+
|
|
+ return mt7531_setup_common(ds);
|
|
+}
|
|
+
|
|
const struct dsa_switch_ops mt7530_switch_ops = {
|
|
.get_tag_protocol = mtk_get_tag_protocol,
|
|
.setup = mt753x_setup,
|
|
@@ -3087,6 +3203,17 @@ const struct mt753x_info mt753x_table[]
|
|
.mac_port_get_caps = mt7531_mac_port_get_caps,
|
|
.mac_port_config = mt7531_mac_config,
|
|
},
|
|
+ [ID_MT7988] = {
|
|
+ .id = ID_MT7988,
|
|
+ .pcs_ops = &mt7530_pcs_ops,
|
|
+ .sw_setup = mt7988_setup,
|
|
+ .phy_read = mt7531_ind_phy_read,
|
|
+ .phy_write = mt7531_ind_phy_write,
|
|
+ .pad_setup = mt7988_pad_setup,
|
|
+ .cpu_port_config = mt7988_cpu_port_config,
|
|
+ .mac_port_get_caps = mt7988_mac_port_get_caps,
|
|
+ .mac_port_config = mt7988_mac_config,
|
|
+ },
|
|
};
|
|
EXPORT_SYMBOL_GPL(mt753x_table);
|
|
|
|
--- a/drivers/net/dsa/mt7530.h
|
|
+++ b/drivers/net/dsa/mt7530.h
|
|
@@ -18,6 +18,7 @@ enum mt753x_id {
|
|
ID_MT7530 = 0,
|
|
ID_MT7621 = 1,
|
|
ID_MT7531 = 2,
|
|
+ ID_MT7988 = 3,
|
|
};
|
|
|
|
#define NUM_TRGMII_CTRL 5
|
|
@@ -54,11 +55,11 @@ enum mt753x_id {
|
|
#define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16)
|
|
#define MT7531_CPU_PMAP_MASK GENMASK(7, 0)
|
|
|
|
-#define MT753X_MIRROR_REG(id) (((id) == ID_MT7531) ? \
|
|
+#define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
|
|
MT7531_CFC : MT7530_MFC)
|
|
-#define MT753X_MIRROR_EN(id) (((id) == ID_MT7531) ? \
|
|
+#define MT753X_MIRROR_EN(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
|
|
MT7531_MIRROR_EN : MIRROR_EN)
|
|
-#define MT753X_MIRROR_MASK(id) (((id) == ID_MT7531) ? \
|
|
+#define MT753X_MIRROR_MASK(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
|
|
MT7531_MIRROR_MASK : MIRROR_MASK)
|
|
|
|
/* Registers for BPDU and PAE frame control*/
|
|
@@ -322,9 +323,8 @@ enum mt7530_vlan_port_acc_frm {
|
|
MT7531_FORCE_DPX | \
|
|
MT7531_FORCE_RX_FC | \
|
|
MT7531_FORCE_TX_FC)
|
|
-#define PMCR_FORCE_MODE_ID(id) (((id) == ID_MT7531) ? \
|
|
- MT7531_FORCE_MODE : \
|
|
- PMCR_FORCE_MODE)
|
|
+#define PMCR_FORCE_MODE_ID(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
|
|
+ MT7531_FORCE_MODE : PMCR_FORCE_MODE)
|
|
#define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
|
|
PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
|
|
PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
|