mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-20 06:08:08 +00:00
d1ac7230d0
Changelog: https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.1.50 All patches automatically rebased. Build system: x86/64 Build-tested: x86/64/AMD Cezanne, filogic/xiaomi_redmi-router-ax6000-ubootmod, ipq806x/R7800 Run-tested: x86/64/AMD Cezanne, filogic/xiaomi_redmi-router-ax6000-ubootmod, ipq806x/R7800 Signed-off-by: John Audia <therealgraysky@proton.me>
422 lines
12 KiB
Diff
422 lines
12 KiB
Diff
From b361015763fedea439f13b336b15ef7bdf1f7d4f Mon Sep 17 00:00:00 2001
|
|
From: Daniel Golle <daniel@makrotopia.org>
|
|
Date: Mon, 3 Apr 2023 02:19:40 +0100
|
|
Subject: [PATCH 12/13] 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
|
|
@@ -13058,9 +13058,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
|
|
@@ -38,6 +38,7 @@ config NET_DSA_MT7530
|
|
select NET_DSA_TAG_MTK
|
|
select MEDIATEK_GE_PHY
|
|
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
|
|
@@ -2005,6 +2005,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;
|
|
@@ -2038,8 +2079,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;
|
|
@@ -2538,6 +2586,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)
|
|
{
|
|
@@ -2614,6 +2681,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)
|
|
{
|
|
@@ -2683,7 +2761,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 */
|
|
@@ -2761,7 +2840,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;
|
|
@@ -2841,6 +2921,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)
|
|
{
|
|
@@ -2986,6 +3081,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,
|
|
@@ -3054,6 +3170,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*/
|
|
@@ -302,9 +303,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 | \
|