From 90508a46a0fd6416dcaad2c7f0ef25a5a421bf4f Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Fri, 2 Jun 2023 13:06:00 +0800
Subject: [PATCH] 
 [backport-networking-drivers][999-1706-net-dsa-support-mt7988.patch]

---
 drivers/net/dsa/mt7530.c | 191 ++++++++++++++++++++++++++++++++-------
 drivers/net/dsa/mt7530.h |  11 ++-
 2 files changed, 164 insertions(+), 38 deletions(-)

diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 63f8a632b..2cd5dae9c 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -19,6 +19,7 @@
 #include <linux/reset.h>
 #include <linux/gpio/consumer.h>
 #include <net/dsa.h>
+#include <linux/of_address.h>
 
 #include "mt7530.h"
 #include "mt7530_nl.h"
@@ -170,28 +171,44 @@ core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
 	core_rmw(priv, reg, val, 0);
 }
 
+static void
+mtk_w32(struct mt7530_priv *priv, u32 val, unsigned reg)
+{
+	__raw_writel(val, priv->base + reg);
+}
+
+static u32
+mtk_r32(struct mt7530_priv *priv, unsigned reg)
+{
+	return __raw_readl(priv->base + reg);
+}
+
 static int
 mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
 {
 	struct mii_bus *bus = priv->bus;
 	u16 page, r, lo, hi;
-	int ret;
+	int ret = 0;
 
-	page = (reg >> 6) & 0x3ff;
-	r  = (reg >> 2) & 0xf;
-	lo = val & 0xffff;
-	hi = val >> 16;
+	if (priv->direct_access){
+		mtk_w32(priv, val, reg);
+	} else {
+		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)
-		goto err;
+		/* MT7530 uses 31 as the pseudo port */
+		ret = bus->write(bus, 0x1f, 0x1f, page);
+		if (ret < 0)
+			goto err;
 
-	ret = bus->write(bus, 0x1f, r,  lo);
-	if (ret < 0)
-		goto err;
+		ret = bus->write(bus, 0x1f, r,  lo);
+		if (ret < 0)
+			goto err;
 
-	ret = bus->write(bus, 0x1f, 0x10, hi);
+		ret = bus->write(bus, 0x1f, 0x10, hi);
+	}
 err:
 	if (ret < 0)
 		dev_err(&bus->dev,
@@ -206,21 +223,25 @@ mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
 	u16 page, r, lo, hi;
 	int ret;
 
-	page = (reg >> 6) & 0x3ff;
-	r = (reg >> 2) & 0xf;
+	if (priv->direct_access){
+		return mtk_r32(priv, reg);
+	} else {
+		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) {
-		dev_err(&bus->dev,
-			"failed to read mt7530 register\n");
-		return ret;
-	}
+		/* MT7530 uses 31 as the pseudo port */
+		ret = bus->write(bus, 0x1f, 0x1f, page);
+		if (ret < 0) {
+			dev_err(&bus->dev,
+				"failed to read mt7530 register\n");
+			return ret;
+		}
 
-	lo = bus->read(bus, 0x1f, r);
-	hi = bus->read(bus, 0x1f, 0x10);
+		lo = bus->read(bus, 0x1f, r);
+		hi = bus->read(bus, 0x1f, 0x10);
 
-	return (hi << 16) | (lo & 0xffff);
+		return (hi << 16) | (lo & 0xffff);
+	}
 }
 
 void
@@ -1907,9 +1928,9 @@ mt7531_phy_supported(struct dsa_switch *ds, int port,
 		if (mt7531_is_rgmii_port(priv, port))
 			return phy_interface_mode_is_rgmii(state->interface);
 		fallthrough;
-	case 6: /* 1st cpu port supports sgmii/8023z only */
-		if (state->interface != PHY_INTERFACE_MODE_SGMII &&
-		    !phy_interface_mode_is_8023z(state->interface))
+	case 6: /* 1st cpu port supports sgmii/8023z/usxgmii/10gkr */
+		if (state->interface != PHY_INTERFACE_MODE_SGMII && state->interface != PHY_INTERFACE_MODE_USXGMII &&
+		    state->interface != PHY_INTERFACE_MODE_10GKR && !phy_interface_mode_is_8023z(state->interface))
 			goto unsupported;
 		break;
 	default:
@@ -2018,6 +2039,13 @@ static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port,
 		phylink_set(supported, 1000baseX_Full);
 		phylink_set(supported, 2500baseX_Full);
 		phylink_set(supported, 2500baseT_Full);
+		phylink_set(supported, 10000baseKR_Full);
+		phylink_set(supported, 10000baseT_Full);
+		phylink_set(supported, 10000baseCR_Full);
+		phylink_set(supported, 10000baseSR_Full);
+		phylink_set(supported, 10000baseLR_Full);
+		phylink_set(supported, 10000baseLRM_Full);
+		phylink_set(supported, 10000baseER_Full);
 	}
 }
 
@@ -2166,6 +2194,8 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
 	case PHY_INTERFACE_MODE_NA:
 	case PHY_INTERFACE_MODE_1000BASEX:
 	case PHY_INTERFACE_MODE_2500BASEX:
+	case PHY_INTERFACE_MODE_USXGMII:
+	case PHY_INTERFACE_MODE_10GKR:
 		if (phylink_autoneg_inband(mode))
 			return -EINVAL;
 
@@ -2303,8 +2333,8 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
 	/* MT753x MAC works in 1G full duplex mode for all up-clocked
 	 * variants.
 	 */
-	if (interface == PHY_INTERFACE_MODE_TRGMII ||
-	    (phy_interface_mode_is_8023z(interface))) {
+	if (interface == PHY_INTERFACE_MODE_TRGMII || interface == PHY_INTERFACE_MODE_USXGMII ||
+	    interface == PHY_INTERFACE_MODE_10GKR || (phy_interface_mode_is_8023z(interface))) {
 		speed = SPEED_1000;
 		duplex = DUPLEX_FULL;
 	}
@@ -2403,8 +2433,8 @@ mt753x_phylink_validate(struct dsa_switch *ds, int port,
 
 	phylink_set_port_modes(mask);
 
-	if (state->interface != PHY_INTERFACE_MODE_TRGMII ||
-	    !phy_interface_mode_is_8023z(state->interface)) {
+	if (state->interface != PHY_INTERFACE_MODE_TRGMII || state->interface != PHY_INTERFACE_MODE_USXGMII ||
+	    state->interface != PHY_INTERFACE_MODE_10GKR || !phy_interface_mode_is_8023z(state->interface)) {
 		phylink_set(mask, 10baseT_Half);
 		phylink_set(mask, 10baseT_Full);
 		phylink_set(mask, 100baseT_Half);
@@ -2608,6 +2638,66 @@ mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
 	return priv->info->phy_write(ds, port, regnum, val);
 }
 
+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;
+	u32 unused_pm = 0;
+	int ret, i;
+
+	/* Reset the switch through internal reset */
+	mt7530_write(priv, MT7530_SYS_CTRL,
+		     SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST);
+
+	/* BPDU to CPU port */
+	mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
+		   BIT(MT7530_CPU_PORT));
+	mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
+		   MT753X_BPDU_CPU_ONLY);
+
+	/* Enable and reset MIB counters */
+	mt7530_mib_reset(ds);
+
+	for (i = 0; i < MT7530_NUM_PORTS; i++) {
+		/* Disable forwarding by default on all ports */
+		mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
+			   PCR_MATRIX_CLR);
+
+		mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
+
+		if (dsa_is_unused_port(ds, i))
+			unused_pm |= BIT(i);
+		else if (dsa_is_cpu_port(ds, i))
+			mt753x_cpu_port_enable(ds, i);
+		else
+			mt7530_port_disable(ds, i);
+
+		/* Enable consistent egress tag */
+		mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
+			   PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+	}
+
+	mt7531_phy_setup(ds);
+
+	/* Group and enable unused ports as a standalone dumb switch. */
+	setup_unused_ports(ds, unused_pm);
+
+	ds->configure_vlan_while_not_filtering = true;
+
+	/* Flush the FDB table */
+	ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static const struct dsa_switch_ops mt7530_switch_ops = {
 	.get_tag_protocol	= mtk_get_tag_protocol,
 	.setup			= mt753x_setup,
@@ -2677,12 +2767,28 @@ static const struct mt753x_info mt753x_table[] = {
 		.mac_pcs_an_restart = mt7531_sgmii_restart_an,
 		.mac_pcs_link_up = mt7531_sgmii_link_up_force,
 	},
+	[ID_MT7988] = {
+		.id = ID_MT7988,
+		.sw_setup = mt7988_setup,
+		.phy_read = mt7531_ind_phy_read,
+		.phy_write = mt7531_ind_phy_write,
+		.pad_setup = mt7988_pad_setup,
+		.cpu_port_config = mt7531_cpu_port_config,
+		.phy_mode_supported = mt7531_phy_supported,
+		.mac_port_validate = mt7531_mac_port_validate,
+		.mac_port_get_state = mt7531_phylink_mac_link_state,
+		.mac_port_config = mt7531_mac_config,
+		.mac_pcs_an_restart = mt7531_sgmii_restart_an,
+		.mac_pcs_link_up = mt7531_sgmii_link_up_force,
+	},
+
 };
 
 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], },
+	{ .compatible = "mediatek,mt7988", .data = &mt753x_table[ID_MT7988], },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, mt7530_of_match);
@@ -2692,6 +2798,7 @@ mt7530_probe(struct mdio_device *mdiodev)
 {
 	struct mt7530_priv *priv;
 	struct device_node *dn;
+	struct device_node *switch_node = NULL;
 	int ret;
 
 	dn = mdiodev->dev.of_node;
@@ -2761,6 +2868,16 @@ mt7530_probe(struct mdio_device *mdiodev)
 		}
 	}
 
+	switch_node = of_find_node_by_name(NULL, "switch0");
+	if(switch_node) {
+		priv->base = of_iomap(switch_node, 0);
+		if(priv->base == NULL){
+			dev_err(&mdiodev->dev, "of_iomap failed\n");
+			return -ENOMEM;
+		}
+		priv->direct_access = 1;
+	}
+
 	priv->bus = mdiodev->bus;
 	priv->dev = &mdiodev->dev;
 	priv->ds->priv = priv;
@@ -2769,9 +2886,12 @@ mt7530_probe(struct mdio_device *mdiodev)
 	dev_set_drvdata(&mdiodev->dev, priv);
 
 	ret = dsa_register_switch(priv->ds);
-	if (ret)
-		return ret;
+	if (ret) {
+		if(priv->base)
+			iounmap(priv->base);
 
+		return ret;
+	}
 	mt7530_nl_init(&priv);
 
 	return 0;
@@ -2796,6 +2916,9 @@ mt7530_remove(struct mdio_device *mdiodev)
 	dsa_unregister_switch(priv->ds);
 	mutex_destroy(&priv->reg_mutex);
 
+	if(priv->base)
+		iounmap(priv->base);
+
 	mt7530_nl_exit();
 }
 
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 130d7e5ec..7b175c5f2 100644
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -16,6 +16,7 @@ enum mt753x_id {
 	ID_MT7530 = 0,
 	ID_MT7621 = 1,
 	ID_MT7531 = 2,
+	ID_MT7988 = 3,
 };
 
 #define	NUM_TRGMII_CTRL			5
@@ -51,11 +52,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*/
@@ -261,7 +262,7 @@ enum mt7530_vlan_port_attr {
 					 MT7531_FORCE_DPX | \
 					 MT7531_FORCE_RX_FC | \
 					 MT7531_FORCE_TX_FC)
-#define  PMCR_FORCE_MODE_ID(id)		(((id) == ID_MT7531) ? \
+#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 | \
@@ -733,6 +734,8 @@ struct mt7530_priv {
 	struct regulator	*core_pwr;
 	struct regulator	*io_pwr;
 	struct gpio_desc	*reset;
+	void  __iomem *base;
+	int   direct_access;
 	const struct mt753x_info *info;
 	unsigned int		id;
 	bool			mcm;
-- 
2.34.1

