+++ /dev/null
-From patchwork Thu Mar 9 10:57:44 2023
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 8bit
-X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
-X-Patchwork-Id: 13167235
-X-Patchwork-Delegate: kuba@kernel.org
-Return-Path: <netdev-owner@vger.kernel.org>
-Date: Thu, 9 Mar 2023 10:57:44 +0000
-From: Daniel Golle <daniel@makrotopia.org>
-To: netdev@vger.kernel.org, linux-mediatek@lists.infradead.org,
- linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org,
- Russell King <linux@armlinux.org.uk>,
- Heiner Kallweit <hkallweit1@gmail.com>,
- Lorenzo Bianconi <lorenzo@kernel.org>,
- Mark Lee <Mark-MC.Lee@mediatek.com>,
- John Crispin <john@phrozen.org>, Felix Fietkau <nbd@nbd.name>,
- AngeloGioacchino Del Regno
- <angelogioacchino.delregno@collabora.com>,
- Matthias Brugger <matthias.bgg@gmail.com>,
- DENG Qingfang <dqfext@gmail.com>,
- Landen Chao <Landen.Chao@mediatek.com>,
- Sean Wang <sean.wang@mediatek.com>,
- Paolo Abeni <pabeni@redhat.com>,
- Jakub Kicinski <kuba@kernel.org>,
- Eric Dumazet <edumazet@google.com>,
- "David S. Miller" <davem@davemloft.net>,
- Vladimir Oltean <olteanv@gmail.com>,
- Florian Fainelli <f.fainelli@gmail.com>,
- Andrew Lunn <andrew@lunn.ch>,
- Vladimir Oltean <vladimir.oltean@nxp.com>
-Cc: =?iso-8859-1?q?Bj=F8rn?= Mork <bjorn@mork.no>,
- Frank Wunderlich <frank-w@public-files.de>,
- Alexander Couzens <lynxis@fe80.eu>
-Subject: [PATCH net-next v13 11/16] net: dsa: mt7530: use external PCS driver
-Message-ID:
- <2ac2ee40d3b0e705461b50613fda6a7edfdbc4b3.1678357225.git.daniel@makrotopia.org>
-References: <cover.1678357225.git.daniel@makrotopia.org>
-MIME-Version: 1.0
-Content-Disposition: inline
-In-Reply-To: <cover.1678357225.git.daniel@makrotopia.org>
-Precedence: bulk
-List-ID: <netdev.vger.kernel.org>
-X-Mailing-List: netdev@vger.kernel.org
-X-Patchwork-Delegate: kuba@kernel.org
-
-Implement regmap access wrappers, for now only to be used by the
-pcs-mtk driver.
-Make use of external PCS driver and drop the reduntant implementation
-in mt7530.c.
-As a nice side effect the SGMII registers can now also more easily be
-inspected for debugging via /sys/kernel/debug/regmap.
-
-Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-Tested-by: Bjørn Mork <bjorn@mork.no>
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Tested-by: Frank Wunderlich <frank-w@public-files.de>
----
- drivers/net/dsa/Kconfig | 1 +
- drivers/net/dsa/mt7530.c | 277 ++++++++++-----------------------------
- drivers/net/dsa/mt7530.h | 47 +------
- 3 files changed, 71 insertions(+), 254 deletions(-)
-
---- a/drivers/net/dsa/Kconfig
-+++ b/drivers/net/dsa/Kconfig
-@@ -37,6 +37,7 @@ config NET_DSA_MT7530
- tristate "MediaTek MT753x and MT7621 Ethernet switch support"
- select NET_DSA_TAG_MTK
- select MEDIATEK_GE_PHY
-+ select PCS_MTK_LYNXI
- help
- This enables support for the MediaTek MT7530, MT7531, and MT7621
- Ethernet switch chips.
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -14,6 +14,7 @@
- #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>
-@@ -2615,128 +2616,11 @@ static int mt7531_rgmii_setup(struct mt7
- return 0;
- }
-
--static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
-- phy_interface_t interface, int speed, int duplex)
--{
-- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
-- int port = pcs_to_mt753x_pcs(pcs)->port;
-- unsigned int val;
--
-- /* For adjusting speed and duplex of SGMII force mode. */
-- if (interface != PHY_INTERFACE_MODE_SGMII ||
-- phylink_autoneg_inband(mode))
-- return;
--
-- /* SGMII force mode setting */
-- val = mt7530_read(priv, MT7531_SGMII_MODE(port));
-- val &= ~MT7531_SGMII_IF_MODE_MASK;
--
-- switch (speed) {
-- case SPEED_10:
-- val |= MT7531_SGMII_FORCE_SPEED_10;
-- break;
-- case SPEED_100:
-- val |= MT7531_SGMII_FORCE_SPEED_100;
-- break;
-- case SPEED_1000:
-- val |= MT7531_SGMII_FORCE_SPEED_1000;
-- break;
-- }
--
-- /* MT7531 SGMII 1G force mode can only work in full duplex mode,
-- * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
-- *
-- * The speed check is unnecessary as the MAC capabilities apply
-- * this restriction. --rmk
-- */
-- if ((speed == SPEED_10 || speed == SPEED_100) &&
-- duplex != DUPLEX_FULL)
-- val |= MT7531_SGMII_FORCE_HALF_DUPLEX;
--
-- mt7530_write(priv, MT7531_SGMII_MODE(port), val);
--}
--
- static bool mt753x_is_mac_port(u32 port)
- {
- return (port == 5 || port == 6);
- }
-
--static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port,
-- phy_interface_t interface)
--{
-- u32 val;
--
-- if (!mt753x_is_mac_port(port))
-- return -EINVAL;
--
-- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
-- MT7531_SGMII_PHYA_PWD);
--
-- val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port));
-- val &= ~MT7531_RG_TPHY_SPEED_MASK;
-- /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B
-- * encoding.
-- */
-- val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ?
-- MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G;
-- mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val);
--
-- mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
--
-- /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex
-- * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
-- */
-- mt7530_rmw(priv, MT7531_SGMII_MODE(port),
-- MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS,
-- MT7531_SGMII_FORCE_SPEED_1000);
--
-- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
--
-- return 0;
--}
--
--static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port,
-- phy_interface_t interface)
--{
-- if (!mt753x_is_mac_port(port))
-- return -EINVAL;
--
-- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
-- MT7531_SGMII_PHYA_PWD);
--
-- mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
-- MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G);
--
-- mt7530_set(priv, MT7531_SGMII_MODE(port),
-- MT7531_SGMII_REMOTE_FAULT_DIS |
-- MT7531_SGMII_SPEED_DUPLEX_AN);
--
-- mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port),
-- MT7531_SGMII_TX_CONFIG_MASK, 1);
--
-- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
--
-- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART);
--
-- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
--
-- return 0;
--}
--
--static void mt7531_pcs_an_restart(struct phylink_pcs *pcs)
--{
-- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
-- int port = pcs_to_mt753x_pcs(pcs)->port;
-- u32 val;
--
-- /* Only restart AN when AN is enabled */
-- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
-- if (val & MT7531_SGMII_AN_ENABLE) {
-- val |= MT7531_SGMII_AN_RESTART;
-- mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val);
-- }
--}
--
- static int
- mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
- phy_interface_t interface)
-@@ -2759,11 +2643,11 @@ mt7531_mac_config(struct dsa_switch *ds,
- phydev = dp->slave->phydev;
- return mt7531_rgmii_setup(priv, port, interface, phydev);
- case PHY_INTERFACE_MODE_SGMII:
-- return mt7531_sgmii_setup_mode_an(priv, port, interface);
- case PHY_INTERFACE_MODE_NA:
- case PHY_INTERFACE_MODE_1000BASEX:
- case PHY_INTERFACE_MODE_2500BASEX:
-- return mt7531_sgmii_setup_mode_force(priv, port, interface);
-+ /* handled in SGMII PCS driver */
-+ return 0;
- default:
- return -EINVAL;
- }
-@@ -2788,11 +2672,11 @@ mt753x_phylink_mac_select_pcs(struct dsa
-
- switch (interface) {
- case PHY_INTERFACE_MODE_TRGMII:
-+ return &priv->pcs[port].pcs;
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- case PHY_INTERFACE_MODE_2500BASEX:
-- return &priv->pcs[port].pcs;
--
-+ return priv->ports[port].sgmii_pcs;
- default:
- return NULL;
- }
-@@ -3033,86 +2917,6 @@ static void mt7530_pcs_get_state(struct
- state->pause |= MLO_PAUSE_TX;
- }
-
--static int
--mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port,
-- struct phylink_link_state *state)
--{
-- u32 status, val;
-- u16 config_reg;
--
-- status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
-- state->link = !!(status & MT7531_SGMII_LINK_STATUS);
-- state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE);
-- if (state->interface == PHY_INTERFACE_MODE_SGMII &&
-- (status & MT7531_SGMII_AN_ENABLE)) {
-- val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
-- config_reg = val >> 16;
--
-- switch (config_reg & LPA_SGMII_SPD_MASK) {
-- case LPA_SGMII_1000:
-- state->speed = SPEED_1000;
-- break;
-- case LPA_SGMII_100:
-- state->speed = SPEED_100;
-- break;
-- case LPA_SGMII_10:
-- state->speed = SPEED_10;
-- break;
-- default:
-- dev_err(priv->dev, "invalid sgmii PHY speed\n");
-- state->link = false;
-- return -EINVAL;
-- }
--
-- if (config_reg & LPA_SGMII_FULL_DUPLEX)
-- state->duplex = DUPLEX_FULL;
-- else
-- state->duplex = DUPLEX_HALF;
-- }
--
-- return 0;
--}
--
--static void
--mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port,
-- struct phylink_link_state *state)
--{
-- unsigned int val;
--
-- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
-- state->link = !!(val & MT7531_SGMII_LINK_STATUS);
-- if (!state->link)
-- return;
--
-- state->an_complete = state->link;
--
-- if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
-- state->speed = SPEED_2500;
-- else
-- state->speed = SPEED_1000;
--
-- state->duplex = DUPLEX_FULL;
-- state->pause = MLO_PAUSE_NONE;
--}
--
--static void mt7531_pcs_get_state(struct phylink_pcs *pcs,
-- struct phylink_link_state *state)
--{
-- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
-- int port = pcs_to_mt753x_pcs(pcs)->port;
--
-- if (state->interface == PHY_INTERFACE_MODE_SGMII) {
-- mt7531_sgmii_pcs_get_state_an(priv, port, state);
-- return;
-- } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) ||
-- (state->interface == PHY_INTERFACE_MODE_2500BASEX)) {
-- mt7531_sgmii_pcs_get_state_inband(priv, port, state);
-- return;
-- }
--
-- state->link = false;
--}
--
- static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
- phy_interface_t interface,
- const unsigned long *advertising,
-@@ -3132,18 +2936,57 @@ static const struct phylink_pcs_ops mt75
- .pcs_an_restart = mt7530_pcs_an_restart,
- };
-
--static const struct phylink_pcs_ops mt7531_pcs_ops = {
-- .pcs_validate = mt753x_pcs_validate,
-- .pcs_get_state = mt7531_pcs_get_state,
-- .pcs_config = mt753x_pcs_config,
-- .pcs_an_restart = mt7531_pcs_an_restart,
-- .pcs_link_up = mt7531_pcs_link_up,
-+static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
-+{
-+ struct mt7530_priv *priv = context;
-+
-+ *val = mt7530_read(priv, reg);
-+ return 0;
-+};
-+
-+static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
-+{
-+ struct mt7530_priv *priv = context;
-+
-+ mt7530_write(priv, reg, val);
-+ return 0;
-+};
-+
-+static int mt7530_regmap_update_bits(void *context, unsigned int reg,
-+ unsigned int mask, unsigned int val)
-+{
-+ struct mt7530_priv *priv = context;
-+
-+ mt7530_rmw(priv, reg, mask, val);
-+ return 0;
-+};
-+
-+static const struct regmap_bus mt7531_regmap_bus = {
-+ .reg_write = mt7530_regmap_write,
-+ .reg_read = mt7530_regmap_read,
-+ .reg_update_bits = mt7530_regmap_update_bits,
-+};
-+
-+#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \
-+ { \
-+ .name = _name, \
-+ .reg_bits = 16, \
-+ .val_bits = 32, \
-+ .reg_stride = 4, \
-+ .reg_base = _reg_base, \
-+ .max_register = 0x17c, \
-+ }
-+
-+static const struct regmap_config mt7531_pcs_config[] = {
-+ MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)),
-+ MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)),
- };
-
- static int
- mt753x_setup(struct dsa_switch *ds)
- {
- struct mt7530_priv *priv = ds->priv;
-+ struct regmap *regmap;
- int i, ret;
-
- /* Initialise the PCS devices */
-@@ -3151,8 +2994,6 @@ mt753x_setup(struct dsa_switch *ds)
- priv->pcs[i].pcs.ops = priv->info->pcs_ops;
- priv->pcs[i].priv = priv;
- priv->pcs[i].port = i;
-- if (mt753x_is_mac_port(i))
-- priv->pcs[i].pcs.poll = 1;
- }
-
- ret = priv->info->sw_setup(ds);
-@@ -3167,6 +3008,16 @@ mt753x_setup(struct dsa_switch *ds)
- if (ret && priv->irq)
- mt7530_free_irq_common(priv);
-
-+ if (priv->id == ID_MT7531)
-+ for (i = 0; i < 2; i++) {
-+ regmap = devm_regmap_init(ds->dev,
-+ &mt7531_regmap_bus, priv,
-+ &mt7531_pcs_config[i]);
-+ priv->ports[5 + i].sgmii_pcs =
-+ mtk_pcs_lynxi_create(ds->dev, regmap,
-+ MT7531_PHYA_CTRL_SIGNAL3, 0);
-+ }
-+
- return ret;
- }
-
-@@ -3258,7 +3109,7 @@ static const struct mt753x_info mt753x_t
- },
- [ID_MT7531] = {
- .id = ID_MT7531,
-- .pcs_ops = &mt7531_pcs_ops,
-+ .pcs_ops = &mt7530_pcs_ops,
- .sw_setup = mt7531_setup,
- .phy_read = mt7531_ind_phy_read,
- .phy_write = mt7531_ind_phy_write,
-@@ -3366,7 +3217,7 @@ static void
- mt7530_remove(struct mdio_device *mdiodev)
- {
- struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
-- int ret = 0;
-+ int ret = 0, i;
-
- if (!priv)
- return;
-@@ -3385,6 +3236,10 @@ mt7530_remove(struct mdio_device *mdiode
- mt7530_free_irq(priv);
-
- dsa_unregister_switch(priv->ds);
-+
-+ for (i = 0; i < 2; ++i)
-+ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
-+
- mutex_destroy(&priv->reg_mutex);
- }
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -371,47 +371,8 @@ enum mt7530_vlan_port_acc_frm {
- CCR_TX_OCT_CNT_BAD)
-
- /* MT7531 SGMII register group */
--#define MT7531_SGMII_REG_BASE 0x5000
--#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \
-- ((p) - 5) * 0x1000 + (r))
--
--/* Register forSGMII PCS_CONTROL_1 */
--#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00)
--#define MT7531_SGMII_LINK_STATUS BIT(18)
--#define MT7531_SGMII_AN_ENABLE BIT(12)
--#define MT7531_SGMII_AN_RESTART BIT(9)
--#define MT7531_SGMII_AN_COMPLETE BIT(21)
--
--/* Register for SGMII PCS_SPPED_ABILITY */
--#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08)
--#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0)
--#define MT7531_SGMII_TX_CONFIG BIT(0)
--
--/* Register for SGMII_MODE */
--#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20)
--#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8)
--#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1)
--#define MT7531_SGMII_FORCE_DUPLEX BIT(4)
--#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2)
--#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3)
--#define MT7531_SGMII_FORCE_SPEED_100 BIT(2)
--#define MT7531_SGMII_FORCE_SPEED_10 0
--#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1)
--
--enum mt7531_sgmii_force_duplex {
-- MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
-- MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
--};
--
--/* Fields of QPHY_PWR_STATE_CTRL */
--#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8)
--#define MT7531_SGMII_PHYA_PWD BIT(4)
--
--/* Values of SGMII SPEED */
--#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128)
--#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3))
--#define MT7531_RG_TPHY_SPEED_1_25G 0x0
--#define MT7531_RG_TPHY_SPEED_3_125G BIT(2)
-+#define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000)
-+#define MT7531_PHYA_CTRL_SIGNAL3 0x128
-
- /* Register for system reset */
- #define MT7530_SYS_CTRL 0x7000
-@@ -710,13 +671,13 @@ struct mt7530_fdb {
- * @pm: The matrix used to show all connections with the port.
- * @pvid: The VLAN specified is to be considered a PVID at ingress. Any
- * untagged frames will be assigned to the related VLAN.
-- * @vlan_filtering: The flags indicating whether the port that can recognize
-- * VLAN-tagged frames.
-+ * @sgmii_pcs: Pointer to PCS instance for SerDes ports
- */
- struct mt7530_port {
- bool enable;
- u32 pm;
- u16 pvid;
-+ struct phylink_pcs *sgmii_pcs;
- };
-
- /* Port 5 interface select definitions */
--- /dev/null
+From be4512b9ac6fc53e1ca8daccbda84f643215c547 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Thu, 14 Mar 2024 12:28:35 +0300
+Subject: [PATCH 1/3] net: dsa: mt7530: prevent possible incorrect XTAL
+ frequency selection
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[ Upstream commit f490c492e946d8ffbe65ad4efc66de3c5ede30a4 ]
+
+On MT7530, the HT_XTAL_FSEL field of the HWTRAP register stores a 2-bit
+value that represents the frequency of the crystal oscillator connected to
+the switch IC. The field is populated by the state of the ESW_P4_LED_0 and
+ESW_P4_LED_0 pins, which is done right after reset is deasserted.
+
+ ESW_P4_LED_0 ESW_P3_LED_0 Frequency
+ -----------------------------------------
+ 0 0 Reserved
+ 0 1 20MHz
+ 1 0 40MHz
+ 1 1 25MHz
+
+On MT7531, the XTAL25 bit of the STRAP register stores this. The LAN0LED0
+pin is used to populate the bit. 25MHz when the pin is high, 40MHz when
+it's low.
+
+These pins are also used with LEDs, therefore, their state can be set to
+something other than the bootstrapping configuration. For example, a link
+may be established on port 3 before the DSA subdriver takes control of the
+switch which would set ESW_P3_LED_0 to high.
+
+Currently on mt7530_setup() and mt7531_setup(), 1000 - 1100 usec delay is
+described between reset assertion and deassertion. Some switch ICs in real
+life conditions cannot always have these pins set back to the bootstrapping
+configuration before reset deassertion in this amount of delay. This causes
+wrong crystal frequency to be selected which puts the switch in a
+nonfunctional state after reset deassertion.
+
+The tests below are conducted on an MT7530 with a 40MHz crystal oscillator
+by Justin Swartz.
+
+With a cable from an active peer connected to port 3 before reset, an
+incorrect crystal frequency (0b11 = 25MHz) is selected:
+
+ [1] [3] [5]
+ : : :
+ _____________________________ __________________
+ESW_P4_LED_0 |_______|
+ _____________________________
+ESW_P3_LED_0 |__________________________
+
+ : : : :
+ : : [4]...:
+ : :
+ [2]................:
+
+[1] Reset is asserted.
+[2] Period of 1000 - 1100 usec.
+[3] Reset is deasserted.
+[4] Period of 315 usec. HWTRAP register is populated with incorrect
+ XTAL frequency.
+[5] Signals reflect the bootstrapped configuration.
+
+Increase the delay between reset_control_assert() and
+reset_control_deassert(), and gpiod_set_value_cansleep(priv->reset, 0) and
+gpiod_set_value_cansleep(priv->reset, 1) to 5000 - 5100 usec. This amount
+ensures a higher possibility that the switch IC will have these pins back
+to the bootstrapping configuration before reset deassertion.
+
+With a cable from an active peer connected to port 3 before reset, the
+correct crystal frequency (0b10 = 40MHz) is selected:
+
+ [1] [2-1] [3] [5]
+ : : : :
+ _____________________________ __________________
+ESW_P4_LED_0 |_______|
+ ___________________ _______
+ESW_P3_LED_0 |_________| |__________________
+
+ : : : : :
+ : [2-2]...: [4]...:
+ [2]................:
+
+[1] Reset is asserted.
+[2] Period of 5000 - 5100 usec.
+[2-1] ESW_P3_LED_0 goes low.
+[2-2] Remaining period of 5000 - 5100 usec.
+[3] Reset is deasserted.
+[4] Period of 310 usec. HWTRAP register is populated with bootstrapped
+ XTAL frequency.
+[5] Signals reflect the bootstrapped configuration.
+
+ESW_P3_LED_0 low period before reset deassertion:
+
+ 5000 usec
+ - 5100 usec
+ TEST RESET HOLD
+ # (usec)
+ ---------------------
+ 1 5410
+ 2 5440
+ 3 4375
+ 4 5490
+ 5 5475
+ 6 4335
+ 7 4370
+ 8 5435
+ 9 4205
+ 10 4335
+ 11 3750
+ 12 3170
+ 13 4395
+ 14 4375
+ 15 3515
+ 16 4335
+ 17 4220
+ 18 4175
+ 19 4175
+ 20 4350
+
+ Min 3170
+ Max 5490
+
+ Median 4342.500
+ Avg 4466.500
+
+Revert commit 2920dd92b980 ("net: dsa: mt7530: disable LEDs before reset").
+Changing the state of pins via reset assertion is simpler and more
+efficient than doing so by setting the LED controller off.
+
+Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
+Fixes: c288575f7810 ("net: dsa: mt7530: Add the support of MT7531 switch")
+Co-developed-by: Justin Swartz <justin.swartz@risingedge.co.za>
+Signed-off-by: Justin Swartz <justin.swartz@risingedge.co.za>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2187,11 +2187,11 @@ mt7530_setup(struct dsa_switch *ds)
+ */
+ if (priv->mcm) {
+ reset_control_assert(priv->rstc);
+- usleep_range(1000, 1100);
++ usleep_range(5000, 5100);
+ reset_control_deassert(priv->rstc);
+ } else {
+ gpiod_set_value_cansleep(priv->reset, 0);
+- usleep_range(1000, 1100);
++ usleep_range(5000, 5100);
+ gpiod_set_value_cansleep(priv->reset, 1);
+ }
+
+@@ -2401,11 +2401,11 @@ mt7531_setup(struct dsa_switch *ds)
+ */
+ if (priv->mcm) {
+ reset_control_assert(priv->rstc);
+- usleep_range(1000, 1100);
++ usleep_range(5000, 5100);
+ reset_control_deassert(priv->rstc);
+ } else {
+ gpiod_set_value_cansleep(priv->reset, 0);
+- usleep_range(1000, 1100);
++ usleep_range(5000, 5100);
+ gpiod_set_value_cansleep(priv->reset, 1);
+ }
+
--- /dev/null
+From f1fa919ea59655f73cb3972264e157b8831ba546 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Thu, 14 Mar 2024 12:33:41 +0300
+Subject: [PATCH 2/3] net: dsa: mt7530: fix link-local frames that ingress vlan
+ filtering ports
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[ Upstream commit e8bf353577f382c7066c661fed41b2adc0fc7c40 ]
+
+Whether VLAN-aware or not, on every VID VLAN table entry that has the CPU
+port as a member of it, frames are set to egress the CPU port with the VLAN
+tag stacked. This is so that VLAN tags can be appended after hardware
+special tag (called DSA tag in the context of Linux drivers).
+
+For user ports on a VLAN-unaware bridge, frame ingressing the user port
+egresses CPU port with only the special tag.
+
+For user ports on a VLAN-aware bridge, frame ingressing the user port
+egresses CPU port with the special tag and the VLAN tag.
+
+This causes issues with link-local frames, specifically BPDUs, because the
+software expects to receive them VLAN-untagged.
+
+There are two options to make link-local frames egress untagged. Setting
+CONSISTENT or UNTAGGED on the EG_TAG bits on the relevant register.
+CONSISTENT means frames egress exactly as they ingress. That means
+egressing with the VLAN tag they had at ingress or egressing untagged if
+they ingressed untagged. Although link-local frames are not supposed to be
+transmitted VLAN-tagged, if they are done so, when egressing through a CPU
+port, the special tag field will be broken.
+
+BPDU egresses CPU port with VLAN tag egressing stacked, received on
+software:
+
+00:01:25.104821 AF Unknown (382365846), length 106:
+ | STAG | | VLAN |
+ 0x0000: 0000 6c27 614d 4143 0001 0000 8100 0001 ..l'aMAC........
+ 0x0010: 0026 4242 0300 0000 0000 0000 6c27 614d .&BB........l'aM
+ 0x0020: 4143 0000 0000 0000 6c27 614d 4143 0000 AC......l'aMAC..
+ 0x0030: 0000 1400 0200 0f00 0000 0000 0000 0000 ................
+
+BPDU egresses CPU port with VLAN tag egressing untagged, received on
+software:
+
+00:23:56.628708 AF Unknown (25215488), length 64:
+ | STAG |
+ 0x0000: 0000 6c27 614d 4143 0001 0000 0026 4242 ..l'aMAC.....&BB
+ 0x0010: 0300 0000 0000 0000 6c27 614d 4143 0000 ........l'aMAC..
+ 0x0020: 0000 0000 6c27 614d 4143 0000 0000 1400 ....l'aMAC......
+ 0x0030: 0200 0f00 0000 0000 0000 0000 ............
+
+BPDU egresses CPU port with VLAN tag egressing tagged, received on
+software:
+
+00:01:34.311963 AF Unknown (25215488), length 64:
+ | Mess |
+ 0x0000: 0000 6c27 614d 4143 0001 0001 0026 4242 ..l'aMAC.....&BB
+ 0x0010: 0300 0000 0000 0000 6c27 614d 4143 0000 ........l'aMAC..
+ 0x0020: 0000 0000 6c27 614d 4143 0000 0000 1400 ....l'aMAC......
+ 0x0030: 0200 0f00 0000 0000 0000 0000 ............
+
+To prevent confusing the software, force the frame to egress UNTAGGED
+instead of CONSISTENT. This way, frames can't possibly be received TAGGED
+by software which would have the special tag field broken.
+
+VLAN Tag Egress Procedure
+
+ For all frames, one of these options set the earliest in this order will
+ apply to the frame:
+
+ - EG_TAG in certain registers for certain frames.
+ This will apply to frame with matching MAC DA or EtherType.
+
+ - EG_TAG in the address table.
+ This will apply to frame at its incoming port.
+
+ - EG_TAG in the PVC register.
+ This will apply to frame at its incoming port.
+
+ - EG_CON and [EG_TAG per port] in the VLAN table.
+ This will apply to frame at its outgoing port.
+
+ - EG_TAG in the PCR register.
+ This will apply to frame at its outgoing port.
+
+ EG_TAG in certain registers for certain frames:
+
+ PPPoE Discovery_ARP/RARP: PPP_EG_TAG and ARP_EG_TAG in the APC register.
+ IGMP_MLD: IGMP_EG_TAG and MLD_EG_TAG in the IMC register.
+ BPDU and PAE: BPDU_EG_TAG and PAE_EG_TAG in the BPC register.
+ REV_01 and REV_02: R01_EG_TAG and R02_EG_TAG in the RGAC1 register.
+ REV_03 and REV_0E: R03_EG_TAG and R0E_EG_TAG in the RGAC2 register.
+ REV_10 and REV_20: R10_EG_TAG and R20_EG_TAG in the RGAC3 register.
+ REV_21 and REV_UN: R21_EG_TAG and RUN_EG_TAG in the RGAC4 register.
+
+With this change, it can be observed that a bridge interface with stp_state
+and vlan_filtering enabled will properly block ports now.
+
+Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 23 +++++++++++++++--------
+ drivers/net/dsa/mt7530.h | 9 ++++++++-
+ 2 files changed, 23 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1001,16 +1001,23 @@ unlock_exit:
+ static void
+ mt753x_trap_frames(struct mt7530_priv *priv)
+ {
+- /* Trap BPDUs to the CPU port(s) */
+- mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
++ /* Trap 802.1X PAE frames and BPDUs to the CPU port(s) and egress them
++ * VLAN-untagged.
++ */
++ mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_EG_TAG_MASK |
++ MT753X_PAE_PORT_FW_MASK | MT753X_BPDU_EG_TAG_MASK |
++ MT753X_BPDU_PORT_FW_MASK,
++ MT753X_PAE_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
++ MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY) |
++ MT753X_BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+ MT753X_BPDU_CPU_ONLY);
+
+- /* Trap 802.1X PAE frames to the CPU port(s) */
+- mt7530_rmw(priv, MT753X_BPC, MT753X_PAE_PORT_FW_MASK,
+- MT753X_PAE_PORT_FW(MT753X_BPDU_CPU_ONLY));
+-
+- /* Trap LLDP frames with :0E MAC DA to the CPU port(s) */
+- mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_PORT_FW_MASK,
++ /* Trap LLDP frames with :0E MAC DA to the CPU port(s) and egress them
++ * VLAN-untagged.
++ */
++ mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_EG_TAG_MASK |
++ MT753X_R0E_PORT_FW_MASK,
++ MT753X_R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+ MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY));
+ }
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -63,12 +63,18 @@ enum mt753x_id {
+
+ /* Registers for BPDU and PAE frame control*/
+ #define MT753X_BPC 0x24
+-#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
++#define MT753X_PAE_EG_TAG_MASK GENMASK(24, 22)
++#define MT753X_PAE_EG_TAG(x) FIELD_PREP(MT753X_PAE_EG_TAG_MASK, x)
+ #define MT753X_PAE_PORT_FW_MASK GENMASK(18, 16)
+ #define MT753X_PAE_PORT_FW(x) FIELD_PREP(MT753X_PAE_PORT_FW_MASK, x)
++#define MT753X_BPDU_EG_TAG_MASK GENMASK(8, 6)
++#define MT753X_BPDU_EG_TAG(x) FIELD_PREP(MT753X_BPDU_EG_TAG_MASK, x)
++#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
+
+ /* Register for :03 and :0E MAC DA frame control */
+ #define MT753X_RGAC2 0x2c
++#define MT753X_R0E_EG_TAG_MASK GENMASK(24, 22)
++#define MT753X_R0E_EG_TAG(x) FIELD_PREP(MT753X_R0E_EG_TAG_MASK, x)
+ #define MT753X_R0E_PORT_FW_MASK GENMASK(18, 16)
+ #define MT753X_R0E_PORT_FW(x) FIELD_PREP(MT753X_R0E_PORT_FW_MASK, x)
+
+@@ -251,6 +257,7 @@ enum mt7530_port_mode {
+ enum mt7530_vlan_port_eg_tag {
+ MT7530_VLAN_EG_DISABLED = 0,
+ MT7530_VLAN_EG_CONSISTENT = 1,
++ MT7530_VLAN_EG_UNTAGGED = 4,
+ };
+
+ enum mt7530_vlan_port_attr {
--- /dev/null
+From 86c0c154a759f2af9612a04bdf29110f02dce956 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Thu, 14 Mar 2024 12:33:42 +0300
+Subject: [PATCH 3/3] net: dsa: mt7530: fix handling of all link-local frames
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[ Upstream commit 69ddba9d170bdaee1dc0eb4ced38d7e4bb7b92af ]
+
+Currently, the MT753X switches treat frames with :01-0D and :0F MAC DAs as
+regular multicast frames, therefore flooding them to user ports.
+
+On page 205, section "8.6.3 Frame filtering" of the active standard, IEEE
+Std 802.1Q™-2022, it is stated that frames with 01:80:C2:00:00:00-0F as MAC
+DA must only be propagated to C-VLAN and MAC Bridge components. That means
+VLAN-aware and VLAN-unaware bridges. On the switch designs with CPU ports,
+these frames are supposed to be processed by the CPU (software). So we make
+the switch only forward them to the CPU port. And if received from a CPU
+port, forward to a single port. The software is responsible of making the
+switch conform to the latter by setting a single port as destination port
+on the special tag.
+
+This switch intellectual property cannot conform to this part of the
+standard fully. Whilst the REV_UN frame tag covers the remaining :04-0D and
+:0F MAC DAs, it also includes :22-FF which the scope of propagation is not
+supposed to be restricted for these MAC DAs.
+
+Set frames with :01-03 MAC DAs to be trapped to the CPU port(s). Add a
+comment for the remaining MAC DAs.
+
+Note that the ingress port must have a PVID assigned to it for the switch
+to forward untagged frames. A PVID is set by default on VLAN-aware and
+VLAN-unaware ports. However, when the network interface that pertains to
+the ingress port is attached to a vlan_filtering enabled bridge, the user
+can remove the PVID assignment from it which would prevent the link-local
+frames from being trapped to the CPU port. I am yet to see a way to forward
+link-local frames while preventing other untagged frames from being
+forwarded too.
+
+Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 37 +++++++++++++++++++++++++++++++++----
+ drivers/net/dsa/mt7530.h | 13 +++++++++++++
+ 2 files changed, 46 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -998,6 +998,21 @@ unlock_exit:
+ mutex_unlock(&priv->reg_mutex);
+ }
+
++/* On page 205, section "8.6.3 Frame filtering" of the active standard, IEEE Std
++ * 802.1Q™-2022, it is stated that frames with 01:80:C2:00:00:00-0F as MAC DA
++ * must only be propagated to C-VLAN and MAC Bridge components. That means
++ * VLAN-aware and VLAN-unaware bridges. On the switch designs with CPU ports,
++ * these frames are supposed to be processed by the CPU (software). So we make
++ * the switch only forward them to the CPU port. And if received from a CPU
++ * port, forward to a single port. The software is responsible of making the
++ * switch conform to the latter by setting a single port as destination port on
++ * the special tag.
++ *
++ * This switch intellectual property cannot conform to this part of the standard
++ * fully. Whilst the REV_UN frame tag covers the remaining :04-0D and :0F MAC
++ * DAs, it also includes :22-FF which the scope of propagation is not supposed
++ * to be restricted for these MAC DAs.
++ */
+ static void
+ mt753x_trap_frames(struct mt7530_priv *priv)
+ {
+@@ -1012,13 +1027,27 @@ mt753x_trap_frames(struct mt7530_priv *p
+ MT753X_BPDU_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+ MT753X_BPDU_CPU_ONLY);
+
+- /* Trap LLDP frames with :0E MAC DA to the CPU port(s) and egress them
+- * VLAN-untagged.
++ /* Trap frames with :01 and :02 MAC DAs to the CPU port(s) and egress
++ * them VLAN-untagged.
++ */
++ mt7530_rmw(priv, MT753X_RGAC1, MT753X_R02_EG_TAG_MASK |
++ MT753X_R02_PORT_FW_MASK | MT753X_R01_EG_TAG_MASK |
++ MT753X_R01_PORT_FW_MASK,
++ MT753X_R02_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
++ MT753X_R02_PORT_FW(MT753X_BPDU_CPU_ONLY) |
++ MT753X_R01_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
++ MT753X_BPDU_CPU_ONLY);
++
++ /* Trap frames with :03 and :0E MAC DAs to the CPU port(s) and egress
++ * them VLAN-untagged.
+ */
+ mt7530_rmw(priv, MT753X_RGAC2, MT753X_R0E_EG_TAG_MASK |
+- MT753X_R0E_PORT_FW_MASK,
++ MT753X_R0E_PORT_FW_MASK | MT753X_R03_EG_TAG_MASK |
++ MT753X_R03_PORT_FW_MASK,
+ MT753X_R0E_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
+- MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY));
++ MT753X_R0E_PORT_FW(MT753X_BPDU_CPU_ONLY) |
++ MT753X_R03_EG_TAG(MT7530_VLAN_EG_UNTAGGED) |
++ MT753X_BPDU_CPU_ONLY);
+ }
+
+ static int
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -71,12 +71,25 @@ enum mt753x_id {
+ #define MT753X_BPDU_EG_TAG(x) FIELD_PREP(MT753X_BPDU_EG_TAG_MASK, x)
+ #define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
+
++/* Register for :01 and :02 MAC DA frame control */
++#define MT753X_RGAC1 0x28
++#define MT753X_R02_EG_TAG_MASK GENMASK(24, 22)
++#define MT753X_R02_EG_TAG(x) FIELD_PREP(MT753X_R02_EG_TAG_MASK, x)
++#define MT753X_R02_PORT_FW_MASK GENMASK(18, 16)
++#define MT753X_R02_PORT_FW(x) FIELD_PREP(MT753X_R02_PORT_FW_MASK, x)
++#define MT753X_R01_EG_TAG_MASK GENMASK(8, 6)
++#define MT753X_R01_EG_TAG(x) FIELD_PREP(MT753X_R01_EG_TAG_MASK, x)
++#define MT753X_R01_PORT_FW_MASK GENMASK(2, 0)
++
+ /* Register for :03 and :0E MAC DA frame control */
+ #define MT753X_RGAC2 0x2c
+ #define MT753X_R0E_EG_TAG_MASK GENMASK(24, 22)
+ #define MT753X_R0E_EG_TAG(x) FIELD_PREP(MT753X_R0E_EG_TAG_MASK, x)
+ #define MT753X_R0E_PORT_FW_MASK GENMASK(18, 16)
+ #define MT753X_R0E_PORT_FW(x) FIELD_PREP(MT753X_R0E_PORT_FW_MASK, x)
++#define MT753X_R03_EG_TAG_MASK GENMASK(8, 6)
++#define MT753X_R03_EG_TAG(x) FIELD_PREP(MT753X_R03_EG_TAG_MASK, x)
++#define MT753X_R03_PORT_FW_MASK GENMASK(2, 0)
+
+ enum mt753x_bpdu_port_fw {
+ MT753X_BPDU_FOLLOW_MFC,
--- /dev/null
+From 27b692012840f658c84a3102c0aeca2676f03132 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 15 Dec 2022 03:47:59 +0000
+Subject: [PATCH 01/48] net: dsa: mt7530: remove redundant assignment
+
+Russell King correctly pointed out that the MAC_2500FD capability is
+already added for port 5 (if not in RGMII mode) and port 6 (which only
+supports SGMII) by mt7531_mac_port_get_caps. Remove the reduntant
+setting of this capability flag which was added by a previous commit.
+
+Fixes: e19de30d2080 ("net: dsa: mt7530: add support for in-band link status")
+Reported-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Link: https://lore.kernel.org/r/Y5qY7x6la5TxZxzX@makrotopia.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3010,9 +3010,6 @@ static void mt753x_phylink_get_caps(stru
+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+ MAC_10 | MAC_100 | MAC_1000FD;
+
+- if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port))
+- config->mac_capabilities |= MAC_2500FD;
+-
+ /* This driver does not make use of the speed, duplex, pause or the
+ * advertisement in its mac_config, so it is safe to mark this driver
+ * as non-legacy.
--- /dev/null
+From 05dc5ea089f947a69a5db092ef4cad6a0f3c96ce Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 19 Mar 2023 12:58:43 +0000
+Subject: [PATCH 02/48] net: dsa: mt7530: use external PCS driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Implement regmap access wrappers, for now only to be used by the
+pcs-mtk-lynxi driver.
+Make use of this external PCS driver and drop the now reduntant
+implementation in mt7530.c.
+As a nice side effect the SGMII registers can now also more easily be
+inspected for debugging via /sys/kernel/debug/regmap.
+
+Tested-by: Bjørn Mork <bjorn@mork.no>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Frank Wunderlich <frank-w@public-files.de>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/Kconfig | 1 +
+ drivers/net/dsa/mt7530.c | 277 ++++++++++-----------------------------
+ drivers/net/dsa/mt7530.h | 47 +------
+ 3 files changed, 71 insertions(+), 254 deletions(-)
+
+--- a/drivers/net/dsa/Kconfig
++++ b/drivers/net/dsa/Kconfig
+@@ -37,6 +37,7 @@ config NET_DSA_MT7530
+ tristate "MediaTek MT753x and MT7621 Ethernet switch support"
+ select NET_DSA_TAG_MTK
+ select MEDIATEK_GE_PHY
++ select PCS_MTK_LYNXI
+ help
+ This enables support for the MediaTek MT7530, MT7531, and MT7621
+ Ethernet switch chips.
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -14,6 +14,7 @@
+ #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>
+@@ -2651,128 +2652,11 @@ static int mt7531_rgmii_setup(struct mt7
+ return 0;
+ }
+
+-static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
+- phy_interface_t interface, int speed, int duplex)
+-{
+- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
+- int port = pcs_to_mt753x_pcs(pcs)->port;
+- unsigned int val;
+-
+- /* For adjusting speed and duplex of SGMII force mode. */
+- if (interface != PHY_INTERFACE_MODE_SGMII ||
+- phylink_autoneg_inband(mode))
+- return;
+-
+- /* SGMII force mode setting */
+- val = mt7530_read(priv, MT7531_SGMII_MODE(port));
+- val &= ~MT7531_SGMII_IF_MODE_MASK;
+-
+- switch (speed) {
+- case SPEED_10:
+- val |= MT7531_SGMII_FORCE_SPEED_10;
+- break;
+- case SPEED_100:
+- val |= MT7531_SGMII_FORCE_SPEED_100;
+- break;
+- case SPEED_1000:
+- val |= MT7531_SGMII_FORCE_SPEED_1000;
+- break;
+- }
+-
+- /* MT7531 SGMII 1G force mode can only work in full duplex mode,
+- * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
+- *
+- * The speed check is unnecessary as the MAC capabilities apply
+- * this restriction. --rmk
+- */
+- if ((speed == SPEED_10 || speed == SPEED_100) &&
+- duplex != DUPLEX_FULL)
+- val |= MT7531_SGMII_FORCE_HALF_DUPLEX;
+-
+- mt7530_write(priv, MT7531_SGMII_MODE(port), val);
+-}
+-
+ static bool mt753x_is_mac_port(u32 port)
+ {
+ return (port == 5 || port == 6);
+ }
+
+-static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port,
+- phy_interface_t interface)
+-{
+- u32 val;
+-
+- if (!mt753x_is_mac_port(port))
+- return -EINVAL;
+-
+- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
+- MT7531_SGMII_PHYA_PWD);
+-
+- val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port));
+- val &= ~MT7531_RG_TPHY_SPEED_MASK;
+- /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B
+- * encoding.
+- */
+- val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ?
+- MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G;
+- mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val);
+-
+- mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
+-
+- /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex
+- * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
+- */
+- mt7530_rmw(priv, MT7531_SGMII_MODE(port),
+- MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS,
+- MT7531_SGMII_FORCE_SPEED_1000);
+-
+- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
+-
+- return 0;
+-}
+-
+-static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port,
+- phy_interface_t interface)
+-{
+- if (!mt753x_is_mac_port(port))
+- return -EINVAL;
+-
+- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
+- MT7531_SGMII_PHYA_PWD);
+-
+- mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
+- MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G);
+-
+- mt7530_set(priv, MT7531_SGMII_MODE(port),
+- MT7531_SGMII_REMOTE_FAULT_DIS |
+- MT7531_SGMII_SPEED_DUPLEX_AN);
+-
+- mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port),
+- MT7531_SGMII_TX_CONFIG_MASK, 1);
+-
+- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
+-
+- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART);
+-
+- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
+-
+- return 0;
+-}
+-
+-static void mt7531_pcs_an_restart(struct phylink_pcs *pcs)
+-{
+- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
+- int port = pcs_to_mt753x_pcs(pcs)->port;
+- u32 val;
+-
+- /* Only restart AN when AN is enabled */
+- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
+- if (val & MT7531_SGMII_AN_ENABLE) {
+- val |= MT7531_SGMII_AN_RESTART;
+- mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val);
+- }
+-}
+-
+ static int
+ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ phy_interface_t interface)
+@@ -2795,11 +2679,11 @@ mt7531_mac_config(struct dsa_switch *ds,
+ phydev = dp->slave->phydev;
+ return mt7531_rgmii_setup(priv, port, interface, phydev);
+ case PHY_INTERFACE_MODE_SGMII:
+- return mt7531_sgmii_setup_mode_an(priv, port, interface);
+ case PHY_INTERFACE_MODE_NA:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+- return mt7531_sgmii_setup_mode_force(priv, port, interface);
++ /* handled in SGMII PCS driver */
++ return 0;
+ default:
+ return -EINVAL;
+ }
+@@ -2824,11 +2708,11 @@ mt753x_phylink_mac_select_pcs(struct dsa
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_TRGMII:
++ return &priv->pcs[port].pcs;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+- return &priv->pcs[port].pcs;
+-
++ return priv->ports[port].sgmii_pcs;
+ default:
+ return NULL;
+ }
+@@ -3066,86 +2950,6 @@ static void mt7530_pcs_get_state(struct
+ state->pause |= MLO_PAUSE_TX;
+ }
+
+-static int
+-mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port,
+- struct phylink_link_state *state)
+-{
+- u32 status, val;
+- u16 config_reg;
+-
+- status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
+- state->link = !!(status & MT7531_SGMII_LINK_STATUS);
+- state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE);
+- if (state->interface == PHY_INTERFACE_MODE_SGMII &&
+- (status & MT7531_SGMII_AN_ENABLE)) {
+- val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
+- config_reg = val >> 16;
+-
+- switch (config_reg & LPA_SGMII_SPD_MASK) {
+- case LPA_SGMII_1000:
+- state->speed = SPEED_1000;
+- break;
+- case LPA_SGMII_100:
+- state->speed = SPEED_100;
+- break;
+- case LPA_SGMII_10:
+- state->speed = SPEED_10;
+- break;
+- default:
+- dev_err(priv->dev, "invalid sgmii PHY speed\n");
+- state->link = false;
+- return -EINVAL;
+- }
+-
+- if (config_reg & LPA_SGMII_FULL_DUPLEX)
+- state->duplex = DUPLEX_FULL;
+- else
+- state->duplex = DUPLEX_HALF;
+- }
+-
+- return 0;
+-}
+-
+-static void
+-mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port,
+- struct phylink_link_state *state)
+-{
+- unsigned int val;
+-
+- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
+- state->link = !!(val & MT7531_SGMII_LINK_STATUS);
+- if (!state->link)
+- return;
+-
+- state->an_complete = state->link;
+-
+- if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
+- state->speed = SPEED_2500;
+- else
+- state->speed = SPEED_1000;
+-
+- state->duplex = DUPLEX_FULL;
+- state->pause = MLO_PAUSE_NONE;
+-}
+-
+-static void mt7531_pcs_get_state(struct phylink_pcs *pcs,
+- struct phylink_link_state *state)
+-{
+- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
+- int port = pcs_to_mt753x_pcs(pcs)->port;
+-
+- if (state->interface == PHY_INTERFACE_MODE_SGMII) {
+- mt7531_sgmii_pcs_get_state_an(priv, port, state);
+- return;
+- } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) ||
+- (state->interface == PHY_INTERFACE_MODE_2500BASEX)) {
+- mt7531_sgmii_pcs_get_state_inband(priv, port, state);
+- return;
+- }
+-
+- state->link = false;
+-}
+-
+ static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+@@ -3165,18 +2969,57 @@ static const struct phylink_pcs_ops mt75
+ .pcs_an_restart = mt7530_pcs_an_restart,
+ };
+
+-static const struct phylink_pcs_ops mt7531_pcs_ops = {
+- .pcs_validate = mt753x_pcs_validate,
+- .pcs_get_state = mt7531_pcs_get_state,
+- .pcs_config = mt753x_pcs_config,
+- .pcs_an_restart = mt7531_pcs_an_restart,
+- .pcs_link_up = mt7531_pcs_link_up,
++static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
++{
++ struct mt7530_priv *priv = context;
++
++ *val = mt7530_read(priv, reg);
++ return 0;
++};
++
++static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
++{
++ struct mt7530_priv *priv = context;
++
++ mt7530_write(priv, reg, val);
++ return 0;
++};
++
++static int mt7530_regmap_update_bits(void *context, unsigned int reg,
++ unsigned int mask, unsigned int val)
++{
++ struct mt7530_priv *priv = context;
++
++ mt7530_rmw(priv, reg, mask, val);
++ return 0;
++};
++
++static const struct regmap_bus mt7531_regmap_bus = {
++ .reg_write = mt7530_regmap_write,
++ .reg_read = mt7530_regmap_read,
++ .reg_update_bits = mt7530_regmap_update_bits,
++};
++
++#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \
++ { \
++ .name = _name, \
++ .reg_bits = 16, \
++ .val_bits = 32, \
++ .reg_stride = 4, \
++ .reg_base = _reg_base, \
++ .max_register = 0x17c, \
++ }
++
++static const struct regmap_config mt7531_pcs_config[] = {
++ MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)),
++ MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)),
+ };
+
+ static int
+ mt753x_setup(struct dsa_switch *ds)
+ {
+ struct mt7530_priv *priv = ds->priv;
++ struct regmap *regmap;
+ int i, ret;
+
+ /* Initialise the PCS devices */
+@@ -3184,8 +3027,6 @@ mt753x_setup(struct dsa_switch *ds)
+ priv->pcs[i].pcs.ops = priv->info->pcs_ops;
+ priv->pcs[i].priv = priv;
+ priv->pcs[i].port = i;
+- if (mt753x_is_mac_port(i))
+- priv->pcs[i].pcs.poll = 1;
+ }
+
+ ret = priv->info->sw_setup(ds);
+@@ -3200,6 +3041,16 @@ mt753x_setup(struct dsa_switch *ds)
+ if (ret && priv->irq)
+ mt7530_free_irq_common(priv);
+
++ if (priv->id == ID_MT7531)
++ for (i = 0; i < 2; i++) {
++ regmap = devm_regmap_init(ds->dev,
++ &mt7531_regmap_bus, priv,
++ &mt7531_pcs_config[i]);
++ priv->ports[5 + i].sgmii_pcs =
++ mtk_pcs_lynxi_create(ds->dev, regmap,
++ MT7531_PHYA_CTRL_SIGNAL3, 0);
++ }
++
+ return ret;
+ }
+
+@@ -3291,7 +3142,7 @@ static const struct mt753x_info mt753x_t
+ },
+ [ID_MT7531] = {
+ .id = ID_MT7531,
+- .pcs_ops = &mt7531_pcs_ops,
++ .pcs_ops = &mt7530_pcs_ops,
+ .sw_setup = mt7531_setup,
+ .phy_read = mt7531_ind_phy_read,
+ .phy_write = mt7531_ind_phy_write,
+@@ -3399,7 +3250,7 @@ static void
+ mt7530_remove(struct mdio_device *mdiodev)
+ {
+ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
+- int ret = 0;
++ int ret = 0, i;
+
+ if (!priv)
+ return;
+@@ -3418,6 +3269,10 @@ mt7530_remove(struct mdio_device *mdiode
+ mt7530_free_irq(priv);
+
+ dsa_unregister_switch(priv->ds);
++
++ for (i = 0; i < 2; ++i)
++ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
++
+ mutex_destroy(&priv->reg_mutex);
+ }
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -391,47 +391,8 @@ enum mt7530_vlan_port_acc_frm {
+ CCR_TX_OCT_CNT_BAD)
+
+ /* MT7531 SGMII register group */
+-#define MT7531_SGMII_REG_BASE 0x5000
+-#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \
+- ((p) - 5) * 0x1000 + (r))
+-
+-/* Register forSGMII PCS_CONTROL_1 */
+-#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00)
+-#define MT7531_SGMII_LINK_STATUS BIT(18)
+-#define MT7531_SGMII_AN_ENABLE BIT(12)
+-#define MT7531_SGMII_AN_RESTART BIT(9)
+-#define MT7531_SGMII_AN_COMPLETE BIT(21)
+-
+-/* Register for SGMII PCS_SPPED_ABILITY */
+-#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08)
+-#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0)
+-#define MT7531_SGMII_TX_CONFIG BIT(0)
+-
+-/* Register for SGMII_MODE */
+-#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20)
+-#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8)
+-#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1)
+-#define MT7531_SGMII_FORCE_DUPLEX BIT(4)
+-#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2)
+-#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3)
+-#define MT7531_SGMII_FORCE_SPEED_100 BIT(2)
+-#define MT7531_SGMII_FORCE_SPEED_10 0
+-#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1)
+-
+-enum mt7531_sgmii_force_duplex {
+- MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
+- MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
+-};
+-
+-/* Fields of QPHY_PWR_STATE_CTRL */
+-#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8)
+-#define MT7531_SGMII_PHYA_PWD BIT(4)
+-
+-/* Values of SGMII SPEED */
+-#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128)
+-#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3))
+-#define MT7531_RG_TPHY_SPEED_1_25G 0x0
+-#define MT7531_RG_TPHY_SPEED_3_125G BIT(2)
++#define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000)
++#define MT7531_PHYA_CTRL_SIGNAL3 0x128
+
+ /* Register for system reset */
+ #define MT7530_SYS_CTRL 0x7000
+@@ -730,13 +691,13 @@ struct mt7530_fdb {
+ * @pm: The matrix used to show all connections with the port.
+ * @pvid: The VLAN specified is to be considered a PVID at ingress. Any
+ * untagged frames will be assigned to the related VLAN.
+- * @vlan_filtering: The flags indicating whether the port that can recognize
+- * VLAN-tagged frames.
++ * @sgmii_pcs: Pointer to PCS instance for SerDes ports
+ */
+ struct mt7530_port {
+ bool enable;
+ u32 pm;
+ u16 pvid;
++ struct phylink_pcs *sgmii_pcs;
+ };
+
+ /* Port 5 interface select definitions */
--- /dev/null
+From cafbb70e148e7a4e318dcc1e36a96643815b6245 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:17:19 +0100
+Subject: [PATCH 03/48] net: dsa: mt7530: make some noise if register read
+ fails
+
+Simply returning the negative error value instead of the read value
+doesn't seem like a good idea. Return 0 instead and add WARN_ON_ONCE(1)
+so this kind of error will not go unnoticed.
+
+Suggested-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -224,9 +224,10 @@ mt7530_mii_read(struct mt7530_priv *priv
+ /* MT7530 uses 31 as the pseudo port */
+ ret = bus->write(bus, 0x1f, 0x1f, page);
+ if (ret < 0) {
++ WARN_ON_ONCE(1);
+ dev_err(&bus->dev,
+ "failed to read mt7530 register\n");
+- return ret;
++ return 0;
+ }
+
+ lo = bus->read(bus, 0x1f, r);
--- /dev/null
+From 8f83ad87e2df26ddf9b8afd4d2873644a872d929 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:17:30 +0100
+Subject: [PATCH 04/48] net: dsa: mt7530: refactor SGMII PCS creation
+
+Instead of macro templates use a dedidated function and allocated
+regmap_config when creating the regmaps for the pcs-mtk-lynxi
+instances.
+This is in preparation to switching to use unlocked regmap accessors
+and have regmap's locking API handle locking for us.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 74 +++++++++++++++++++++++++++-------------
+ 1 file changed, 50 insertions(+), 24 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3001,26 +3001,56 @@ static const struct regmap_bus mt7531_re
+ .reg_update_bits = mt7530_regmap_update_bits,
+ };
+
+-#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \
+- { \
+- .name = _name, \
+- .reg_bits = 16, \
+- .val_bits = 32, \
+- .reg_stride = 4, \
+- .reg_base = _reg_base, \
+- .max_register = 0x17c, \
++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;
++
++ regmap = devm_regmap_init(priv->dev,
++ &mt7531_regmap_bus, priv,
++ 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;
+ }
+
+-static const struct regmap_config mt7531_pcs_config[] = {
+- MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)),
+- MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)),
+-};
++ if (ret && i)
++ mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
++
++ return ret;
++}
+
+ static int
+ mt753x_setup(struct dsa_switch *ds)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- struct regmap *regmap;
+ int i, ret;
+
+ /* Initialise the PCS devices */
+@@ -3042,15 +3072,11 @@ mt753x_setup(struct dsa_switch *ds)
+ if (ret && priv->irq)
+ mt7530_free_irq_common(priv);
+
+- if (priv->id == ID_MT7531)
+- for (i = 0; i < 2; i++) {
+- regmap = devm_regmap_init(ds->dev,
+- &mt7531_regmap_bus, priv,
+- &mt7531_pcs_config[i]);
+- priv->ports[5 + i].sgmii_pcs =
+- mtk_pcs_lynxi_create(ds->dev, regmap,
+- MT7531_PHYA_CTRL_SIGNAL3, 0);
+- }
++ if (priv->id == ID_MT7531) {
++ ret = mt7531_create_sgmii(priv);
++ if (ret && priv->irq)
++ mt7530_free_irq_common(priv);
++ }
+
+ return ret;
+ }
--- /dev/null
+From efb41b8e9b7bbb08ace1930373bff63d4f5cc6e2 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:17:40 +0100
+Subject: [PATCH 05/48] net: dsa: mt7530: use unlocked regmap accessors
+
+Instead of wrapping the locked register accessor functions, use the
+unlocked variants and add locking wrapper functions to let regmap
+handle the locking.
+
+This is a preparation towards being able to always use regmap to
+access switch registers instead of open-coded accessor functions.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2974,7 +2974,7 @@ static int mt7530_regmap_read(void *cont
+ {
+ struct mt7530_priv *priv = context;
+
+- *val = mt7530_read(priv, reg);
++ *val = mt7530_mii_read(priv, reg);
+ return 0;
+ };
+
+@@ -2982,23 +2982,25 @@ static int mt7530_regmap_write(void *con
+ {
+ struct mt7530_priv *priv = context;
+
+- mt7530_write(priv, reg, val);
++ mt7530_mii_write(priv, reg, val);
+ return 0;
+ };
+
+-static int mt7530_regmap_update_bits(void *context, unsigned int reg,
+- unsigned int mask, unsigned int val)
++static void
++mt7530_mdio_regmap_lock(void *mdio_lock)
+ {
+- struct mt7530_priv *priv = context;
++ mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
++}
+
+- mt7530_rmw(priv, reg, mask, val);
+- return 0;
+-};
++static void
++mt7530_mdio_regmap_unlock(void *mdio_lock)
++{
++ mutex_unlock(mdio_lock);
++}
+
+ static const struct regmap_bus mt7531_regmap_bus = {
+ .reg_write = mt7530_regmap_write,
+ .reg_read = mt7530_regmap_read,
+- .reg_update_bits = mt7530_regmap_update_bits,
+ };
+
+ static int
+@@ -3024,6 +3026,9 @@ mt7531_create_sgmii(struct mt7530_priv *
+ 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,
+ &mt7531_regmap_bus, priv,
--- /dev/null
+From c7945d11a060797c31b3f47d9c9e515b0bf2082f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:17:52 +0100
+Subject: [PATCH 06/48] net: dsa: mt7530: use regmap to access switch register
+ space
+
+Use regmap API to access the switch register space.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 99 ++++++++++++++++++++++++----------------
+ drivers/net/dsa/mt7530.h | 2 +
+ 2 files changed, 62 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -183,9 +183,9 @@ core_clear(struct mt7530_priv *priv, u32
+ }
+
+ static int
+-mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
++mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
+ {
+- struct mii_bus *bus = priv->bus;
++ struct mii_bus *bus = context;
+ u16 page, r, lo, hi;
+ int ret;
+
+@@ -197,24 +197,34 @@ mt7530_mii_write(struct mt7530_priv *pri
+ /* MT7530 uses 31 as the pseudo port */
+ ret = bus->write(bus, 0x1f, 0x1f, page);
+ if (ret < 0)
+- goto err;
++ return ret;
+
+ ret = bus->write(bus, 0x1f, r, lo);
+ if (ret < 0)
+- goto err;
++ return ret;
+
+ ret = bus->write(bus, 0x1f, 0x10, hi);
+-err:
++ return ret;
++}
++
++static int
++mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++ int ret;
++
++ ret = regmap_write(priv->regmap, reg, val);
++
+ if (ret < 0)
+- dev_err(&bus->dev,
++ dev_err(priv->dev,
+ "failed to write mt7530 register\n");
++
+ return ret;
+ }
+
+-static u32
+-mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
++static int
++mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
+ {
+- struct mii_bus *bus = priv->bus;
++ struct mii_bus *bus = context;
+ u16 page, r, lo, hi;
+ int ret;
+
+@@ -223,17 +233,32 @@ mt7530_mii_read(struct mt7530_priv *priv
+
+ /* MT7530 uses 31 as the pseudo port */
+ ret = bus->write(bus, 0x1f, 0x1f, page);
+- if (ret < 0) {
++ 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)
++{
++ int ret;
++ u32 val;
++
++ ret = regmap_read(priv->regmap, reg, &val);
++ if (ret) {
+ WARN_ON_ONCE(1);
+- dev_err(&bus->dev,
++ dev_err(priv->dev,
+ "failed to read mt7530 register\n");
+ return 0;
+ }
+
+- lo = bus->read(bus, 0x1f, r);
+- hi = bus->read(bus, 0x1f, 0x10);
+-
+- return (hi << 16) | (lo & 0xffff);
++ return val;
+ }
+
+ static void
+@@ -283,14 +308,10 @@ mt7530_rmw(struct mt7530_priv *priv, u32
+ u32 mask, u32 set)
+ {
+ struct mii_bus *bus = priv->bus;
+- u32 val;
+
+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
+
+- val = mt7530_mii_read(priv, reg);
+- val &= ~mask;
+- val |= set;
+- mt7530_mii_write(priv, reg, val);
++ regmap_update_bits(priv->regmap, reg, mask, set);
+
+ mutex_unlock(&bus->mdio_lock);
+ }
+@@ -298,7 +319,7 @@ mt7530_rmw(struct mt7530_priv *priv, u32
+ static void
+ mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)
+ {
+- mt7530_rmw(priv, reg, 0, val);
++ mt7530_rmw(priv, reg, val, val);
+ }
+
+ static void
+@@ -2970,22 +2991,6 @@ static const struct phylink_pcs_ops mt75
+ .pcs_an_restart = mt7530_pcs_an_restart,
+ };
+
+-static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
+-{
+- struct mt7530_priv *priv = context;
+-
+- *val = mt7530_mii_read(priv, reg);
+- return 0;
+-};
+-
+-static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
+-{
+- struct mt7530_priv *priv = context;
+-
+- mt7530_mii_write(priv, reg, val);
+- return 0;
+-};
+-
+ static void
+ mt7530_mdio_regmap_lock(void *mdio_lock)
+ {
+@@ -2998,7 +3003,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc
+ mutex_unlock(mdio_lock);
+ }
+
+-static const struct regmap_bus mt7531_regmap_bus = {
++static const struct regmap_bus mt7530_regmap_bus = {
+ .reg_write = mt7530_regmap_write,
+ .reg_read = mt7530_regmap_read,
+ };
+@@ -3031,7 +3036,7 @@ mt7531_create_sgmii(struct mt7530_priv *
+ mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
+
+ regmap = devm_regmap_init(priv->dev,
+- &mt7531_regmap_bus, priv,
++ &mt7530_regmap_bus, priv->bus,
+ mt7531_pcs_config[i]);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+@@ -3196,6 +3201,7 @@ 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;
+
+@@ -3275,6 +3281,21 @@ mt7530_probe(struct mdio_device *mdiodev
+ mutex_init(&priv->reg_mutex);
+ dev_set_drvdata(&mdiodev->dev, priv);
+
++ 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);
++
+ return dsa_register_switch(priv->ds);
+ }
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -774,6 +774,7 @@ struct mt753x_info {
+ * @dev: The device pointer
+ * @ds: The pointer to the dsa core structure
+ * @bus: The bus used for the device and built-in PHY
++ * @regmap: The regmap instance representing all switch registers
+ * @rstc: The pointer to reset control used by MCM
+ * @core_pwr: The power supplied into the core
+ * @io_pwr: The power supplied into the I/O
+@@ -794,6 +795,7 @@ struct mt7530_priv {
+ struct device *dev;
+ struct dsa_switch *ds;
+ struct mii_bus *bus;
++ struct regmap *regmap;
+ struct reset_control *rstc;
+ struct regulator *core_pwr;
+ struct regulator *io_pwr;
--- /dev/null
+From 6b64b5bc3045a7e1ee5278df4f4ff315cd43d88a Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:18:04 +0100
+Subject: [PATCH 07/48] net: dsa: mt7530: move SGMII PCS creation to
+ mt7530_probe function
+
+Move creating the SGMII PCS from mt753x_setup() to the more appropriate
+mt7530_probe() function.
+This is done also in preparation of moving all functions related to
+MDIO-connected MT753x switches to a separate module.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3082,12 +3082,6 @@ mt753x_setup(struct dsa_switch *ds)
+ if (ret && priv->irq)
+ mt7530_free_irq_common(priv);
+
+- if (priv->id == ID_MT7531) {
+- ret = mt7531_create_sgmii(priv);
+- if (ret && priv->irq)
+- mt7530_free_irq_common(priv);
+- }
+-
+ return ret;
+ }
+
+@@ -3204,6 +3198,7 @@ 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;
+
+@@ -3296,6 +3291,12 @@ mt7530_probe(struct mdio_device *mdiodev
+ 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);
+ }
+
--- /dev/null
+From 504d39cbda402df3e6fd123d040520393b6a6297 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:18:16 +0100
+Subject: [PATCH 08/48] net: dsa: mt7530: introduce mutex helpers
+
+As the MDIO bus lock only needs to be involved if actually operating
+on an MDIO-connected switch we will need to skip locking for built-in
+switches which are accessed via MMIO.
+Create helper functions which simplify that upcoming change.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 73 ++++++++++++++++++++--------------------
+ 1 file changed, 36 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -143,31 +143,40 @@ err:
+ }
+
+ static void
+-core_write(struct mt7530_priv *priv, u32 reg, u32 val)
++mt7530_mutex_lock(struct mt7530_priv *priv)
+ {
+- struct mii_bus *bus = priv->bus;
++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++}
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++static void
++mt7530_mutex_unlock(struct mt7530_priv *priv)
++{
++ mutex_unlock(&priv->bus->mdio_lock);
++}
++
++static void
++core_write(struct mt7530_priv *priv, u32 reg, u32 val)
++{
++ mt7530_mutex_lock(priv);
+
+ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
+
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+ }
+
+ static void
+ core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
+ {
+- struct mii_bus *bus = priv->bus;
+ u32 val;
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);
+ val &= ~mask;
+ val |= set;
+ core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
+
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+ }
+
+ static void
+@@ -264,13 +273,11 @@ mt7530_mii_read(struct mt7530_priv *priv
+ static void
+ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
+ {
+- struct mii_bus *bus = priv->bus;
+-
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ mt7530_mii_write(priv, reg, val);
+
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+ }
+
+ static u32
+@@ -282,14 +289,13 @@ _mt7530_unlocked_read(struct mt7530_dumm
+ static u32
+ _mt7530_read(struct mt7530_dummy_poll *p)
+ {
+- struct mii_bus *bus = p->priv->bus;
+ u32 val;
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(p->priv);
+
+ val = mt7530_mii_read(p->priv, p->reg);
+
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(p->priv);
+
+ return val;
+ }
+@@ -307,13 +313,11 @@ static void
+ mt7530_rmw(struct mt7530_priv *priv, u32 reg,
+ u32 mask, u32 set)
+ {
+- struct mii_bus *bus = priv->bus;
+-
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ regmap_update_bits(priv->regmap, reg, mask, set);
+
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+ }
+
+ static void
+@@ -645,14 +649,13 @@ static int
+ mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
+ int regnum)
+ {
+- struct mii_bus *bus = priv->bus;
+ struct mt7530_dummy_poll p;
+ u32 reg, val;
+ int ret;
+
+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
+@@ -685,7 +688,7 @@ mt7531_ind_c45_phy_read(struct mt7530_pr
+
+ ret = val & MT7531_MDIO_RW_DATA_MASK;
+ out:
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+
+ return ret;
+ }
+@@ -694,14 +697,13 @@ static int
+ mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
+ int regnum, u32 data)
+ {
+- struct mii_bus *bus = priv->bus;
+ struct mt7530_dummy_poll p;
+ u32 val, reg;
+ int ret;
+
+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
+@@ -733,7 +735,7 @@ mt7531_ind_c45_phy_write(struct mt7530_p
+ }
+
+ out:
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+
+ return ret;
+ }
+@@ -741,14 +743,13 @@ out:
+ static int
+ mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
+ {
+- struct mii_bus *bus = priv->bus;
+ struct mt7530_dummy_poll p;
+ int ret;
+ u32 val;
+
+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
+ !(val & MT7531_PHY_ACS_ST), 20, 100000);
+@@ -771,7 +772,7 @@ mt7531_ind_c22_phy_read(struct mt7530_pr
+
+ ret = val & MT7531_MDIO_RW_DATA_MASK;
+ out:
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+
+ return ret;
+ }
+@@ -780,14 +781,13 @@ static int
+ mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
+ u16 data)
+ {
+- struct mii_bus *bus = priv->bus;
+ struct mt7530_dummy_poll p;
+ int ret;
+ u32 reg;
+
+ INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
+ !(reg & MT7531_PHY_ACS_ST), 20, 100000);
+@@ -809,7 +809,7 @@ mt7531_ind_c22_phy_write(struct mt7530_p
+ }
+
+ out:
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+
+ return ret;
+ }
+@@ -1161,7 +1161,6 @@ static int
+ mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- struct mii_bus *bus = priv->bus;
+ int length;
+ u32 val;
+
+@@ -1172,7 +1171,7 @@ mt7530_port_change_mtu(struct dsa_switch
+ if (!dsa_is_cpu_port(ds, port))
+ return 0;
+
+- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+
+ val = mt7530_mii_read(priv, MT7530_GMACCR);
+ val &= ~MAX_RX_PKT_LEN_MASK;
+@@ -1193,7 +1192,7 @@ mt7530_port_change_mtu(struct dsa_switch
+
+ mt7530_mii_write(priv, MT7530_GMACCR, val);
+
+- mutex_unlock(&bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+
+ return 0;
+ }
+@@ -1994,10 +1993,10 @@ mt7530_irq_thread_fn(int irq, void *dev_
+ u32 val;
+ int p;
+
+- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+ val = mt7530_mii_read(priv, MT7530_SYS_INT_STS);
+ mt7530_mii_write(priv, MT7530_SYS_INT_STS, val);
+- mutex_unlock(&priv->bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+
+ for (p = 0; p < MT7530_NUM_PHYS; p++) {
+ if (BIT(p) & val) {
+@@ -2033,7 +2032,7 @@ mt7530_irq_bus_lock(struct irq_data *d)
+ {
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++ mt7530_mutex_lock(priv);
+ }
+
+ static void
+@@ -2042,7 +2041,7 @@ mt7530_irq_bus_sync_unlock(struct irq_da
+ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+ mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
+- mutex_unlock(&priv->bus->mdio_lock);
++ mt7530_mutex_unlock(priv);
+ }
+
+ static struct irq_chip mt7530_irq_chip = {
--- /dev/null
+From dbef24b66807eef7498740fa8b8441bee64a96c4 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:18:28 +0100
+Subject: [PATCH 09/48] net: dsa: mt7530: move p5_intf_modes() function to
+ mt7530.c
+
+In preparation of splitting mt7530.c into a driver for MDIO-connected
+as well as MDIO-accessed built-in switches on one hand and MMIO-accessed
+built-in switches move the p5_inft_modes() function from mt7530.h to
+mt7530.c. The function is only needed there and will trigger a compiler
+warning about a defined but unused function otherwise when including
+mt7530.h in the to-be-introduced bus-specific drivers.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 18 ++++++++++++++++++
+ drivers/net/dsa/mt7530.h | 18 ------------------
+ 2 files changed, 18 insertions(+), 18 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -950,6 +950,24 @@ mt7530_set_ageing_time(struct dsa_switch
+ return 0;
+ }
+
++static const char *p5_intf_modes(unsigned int p5_interface)
++{
++ switch (p5_interface) {
++ case P5_DISABLED:
++ return "DISABLED";
++ case P5_INTF_SEL_PHY_P0:
++ return "PHY P0";
++ case P5_INTF_SEL_PHY_P4:
++ return "PHY P4";
++ case P5_INTF_SEL_GMAC5:
++ return "GMAC5";
++ case P5_INTF_SEL_GMAC5_SGMII:
++ return "GMAC5_SGMII";
++ default:
++ return "unknown";
++ }
++}
++
+ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
+ {
+ struct mt7530_priv *priv = ds->priv;
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -709,24 +709,6 @@ enum p5_interface_select {
+ P5_INTF_SEL_GMAC5_SGMII,
+ };
+
+-static const char *p5_intf_modes(unsigned int p5_interface)
+-{
+- switch (p5_interface) {
+- case P5_DISABLED:
+- return "DISABLED";
+- case P5_INTF_SEL_PHY_P0:
+- return "PHY P0";
+- case P5_INTF_SEL_PHY_P4:
+- return "PHY P4";
+- case P5_INTF_SEL_GMAC5:
+- return "GMAC5";
+- case P5_INTF_SEL_GMAC5_SGMII:
+- return "GMAC5_SGMII";
+- default:
+- return "unknown";
+- }
+-}
+-
+ struct mt7530_priv;
+
+ struct mt753x_pcs {
--- /dev/null
+From a0c6527a38d518ff175c1b6ce248e9b06cc98d3b Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:18:39 +0100
+Subject: [PATCH 10/48] net: dsa: mt7530: introduce mt7530_probe_common helper
+ function
+
+Move commonly used parts from mt7530_probe into new mt7530_probe_common
+helper function which will be used by both, mt7530_probe and the
+to-be-introduced mt7988_probe.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 98 ++++++++++++++++++++++------------------
+ 1 file changed, 54 insertions(+), 44 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3210,44 +3210,21 @@ static const struct of_device_id mt7530_
+ MODULE_DEVICE_TABLE(of, mt7530_of_match);
+
+ static int
+-mt7530_probe(struct mdio_device *mdiodev)
++mt7530_probe_common(struct mt7530_priv *priv)
+ {
+- static struct regmap_config *regmap_config;
+- struct mt7530_priv *priv;
+- struct device_node *dn;
+- int ret;
++ struct device *dev = priv->dev;
+
+- dn = mdiodev->dev.of_node;
+-
+- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
+- if (!priv)
+- return -ENOMEM;
+-
+- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
++ priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
+ if (!priv->ds)
+ return -ENOMEM;
+
+- priv->ds->dev = &mdiodev->dev;
++ priv->ds->dev = dev;
+ priv->ds->num_ports = MT7530_NUM_PORTS;
+
+- /* Use medatek,mcm property to distinguish hardware type that would
+- * casues a little bit differences on power-on sequence.
+- */
+- 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);
+- }
+- }
+-
+ /* Get the hardware identifier from the devicetree node.
+ * We will need it for some of the clock and regulator setup.
+ */
+- priv->info = of_device_get_match_data(&mdiodev->dev);
++ priv->info = of_device_get_match_data(dev);
+ if (!priv->info)
+ return -EINVAL;
+
+@@ -3261,23 +3238,53 @@ mt7530_probe(struct mdio_device *mdiodev
+ return -EINVAL;
+
+ priv->id = priv->info->id;
++ priv->dev = dev;
++ priv->ds->priv = priv;
++ priv->ds->ops = &mt7530_switch_ops;
++ mutex_init(&priv->reg_mutex);
++ dev_set_drvdata(dev, priv);
+
+- 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);
++ return 0;
++}
+
+- priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
+- if (IS_ERR(priv->io_pwr))
+- return PTR_ERR(priv->io_pwr);
+- }
++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;
+
+- /* Not MCM that indicates switch works as the remote standalone
++ 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.
+ */
+- if (!priv->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)) {
+@@ -3286,12 +3293,15 @@ mt7530_probe(struct mdio_device *mdiodev
+ }
+ }
+
+- priv->bus = mdiodev->bus;
+- priv->dev = &mdiodev->dev;
+- priv->ds->priv = priv;
+- priv->ds->ops = &mt7530_switch_ops;
+- mutex_init(&priv->reg_mutex);
+- dev_set_drvdata(&mdiodev->dev, priv);
++ 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);
--- /dev/null
+From a7783b0b6f3b38abd34cecf515811691714dee57 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:18:50 +0100
+Subject: [PATCH 11/48] net: dsa: mt7530: introduce mt7530_remove_common helper
+ function
+
+Move commonly used parts from mt7530_remove into new
+mt7530_remove_common helper function which will be used by both,
+mt7530_remove and the to-be-introduced mt7988_remove.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3328,6 +3328,17 @@ mt7530_probe(struct mdio_device *mdiodev
+ }
+
+ static void
++mt7530_remove_common(struct mt7530_priv *priv)
++{
++ if (priv->irq)
++ mt7530_free_irq(priv);
++
++ dsa_unregister_switch(priv->ds);
++
++ mutex_destroy(&priv->reg_mutex);
++}
++
++static void
+ mt7530_remove(struct mdio_device *mdiodev)
+ {
+ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
+@@ -3346,15 +3357,10 @@ mt7530_remove(struct mdio_device *mdiode
+ dev_err(priv->dev, "Failed to disable io pwr: %d\n",
+ ret);
+
+- if (priv->irq)
+- mt7530_free_irq(priv);
+-
+- dsa_unregister_switch(priv->ds);
++ mt7530_remove_common(priv);
+
+ for (i = 0; i < 2; ++i)
+ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
+-
+- mutex_destroy(&priv->reg_mutex);
+ }
+
+ static void mt7530_shutdown(struct mdio_device *mdiodev)
--- /dev/null
+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 */
--- /dev/null
+From 86e1168a214b7ab0883acf1e7a6885a7a949e3e7 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 3 Apr 2023 02:19:28 +0100
+Subject: [PATCH 13/48] net: dsa: mt7530: skip locking if MDIO bus isn't
+ present
+
+As MT7530 and MT7531 internally use 32-bit wide registers, each access
+to any register of the switch requires several operations on the MDIO
+bus. Hence if there is congruent access, e.g. due to PCS or PHY
+polling, this can mess up and interfere with another ongoing register
+access sequence.
+
+However, the MDIO bus mutex is only relevant for MDIO-connected
+switches. Prepare switches which have there registers directly mapped
+into the SoCs register space via MMIO which do not require such
+locking. There we can simply use regmap's default locking mechanism.
+
+Hence guard mutex operations to only be performed in case of MDIO
+connected switches.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -144,13 +144,15 @@ err:
+ static void
+ mt7530_mutex_lock(struct mt7530_priv *priv)
+ {
+- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++ if (priv->bus)
++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+ }
+
+ static void
+ mt7530_mutex_unlock(struct mt7530_priv *priv)
+ {
+- mutex_unlock(&priv->bus->mdio_lock);
++ if (priv->bus)
++ mutex_unlock(&priv->bus->mdio_lock);
+ }
+
+ static void
--- /dev/null
+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 | \
--- /dev/null
+From ed01748319b25456c5226ed0cb5e49e970da0e4f Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sun, 16 Apr 2023 13:08:14 +0100
+Subject: [PATCH 15/48] net: dsa: mt7530: fix support for MT7531BE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are two variants of the MT7531 switch IC which got different
+features (and pins) regarding port 5:
+ * MT7531AE: SGMII/1000Base-X/2500Base-X SerDes PCS
+ * MT7531BE: RGMII
+
+Moving the creation of the SerDes PCS from mt753x_setup to mt7530_probe
+with commit 6de285229773 ("net: dsa: mt7530: move SGMII PCS creation
+to mt7530_probe function") works fine for MT7531AE which got two
+instances of mtk-pcs-lynxi, however, MT7531BE requires mt7531_pll_setup
+to setup clocks before the single PCS on port 6 (usually used as CPU
+port) starts to work and hence the PCS creation failed on MT7531BE.
+
+Fix this by introducing a pointer to mt7531_create_sgmii function in
+struct mt7530_priv and call it again at the end of mt753x_setup like it
+was before commit 6de285229773 ("net: dsa: mt7530: move SGMII PCS
+creation to mt7530_probe function").
+
+Fixes: 6de285229773 ("net: dsa: mt7530: move SGMII PCS creation to mt7530_probe function")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Acked-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/ZDvlLhhqheobUvOK@makrotopia.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530-mdio.c | 16 ++++++++--------
+ drivers/net/dsa/mt7530.c | 6 ++++++
+ drivers/net/dsa/mt7530.h | 4 ++--
+ 3 files changed, 16 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/dsa/mt7530-mdio.c
++++ b/drivers/net/dsa/mt7530-mdio.c
+@@ -81,14 +81,17 @@ static const struct regmap_bus mt7530_re
+ };
+
+ static int
+-mt7531_create_sgmii(struct mt7530_priv *priv)
++mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii)
+ {
+- struct regmap_config *mt7531_pcs_config[2];
++ struct regmap_config *mt7531_pcs_config[2] = {};
+ struct phylink_pcs *pcs;
+ struct regmap *regmap;
+ int i, ret = 0;
+
+- for (i = 0; i < 2; i++) {
++ /* MT7531AE has two SGMII units for port 5 and port 6
++ * MT7531BE has only one SGMII unit for port 6
++ */
++ for (i = dual_sgmii ? 0 : 1; i < 2; i++) {
+ mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
+ sizeof(struct regmap_config),
+ GFP_KERNEL);
+@@ -208,11 +211,8 @@ mt7530_probe(struct mdio_device *mdiodev
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+- if (priv->id == ID_MT7531) {
+- ret = mt7531_create_sgmii(priv);
+- if (ret)
+- return ret;
+- }
++ if (priv->id == ID_MT7531)
++ priv->create_sgmii = mt7531_create_sgmii;
+
+ return dsa_register_switch(priv->ds);
+ }
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3081,6 +3081,12 @@ mt753x_setup(struct dsa_switch *ds)
+ if (ret && priv->irq)
+ mt7530_free_irq_common(priv);
+
++ if (priv->create_sgmii) {
++ ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv));
++ if (ret && priv->irq)
++ mt7530_free_irq(priv);
++ }
++
+ return ret;
+ }
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -768,10 +768,10 @@ struct mt753x_info {
+ * registers
+ * @p6_interface Holding the current port 6 interface
+ * @p5_intf_sel: Holding the current port 5 interface select
+- *
+ * @irq: IRQ number of the switch
+ * @irq_domain: IRQ domain of the switch irq_chip
+ * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
++ * @create_sgmii: Pointer to function creating SGMII PCS instance(s)
+ */
+ struct mt7530_priv {
+ struct device *dev;
+@@ -790,7 +790,6 @@ struct mt7530_priv {
+ unsigned int p5_intf_sel;
+ u8 mirror_rx;
+ u8 mirror_tx;
+-
+ struct mt7530_port ports[MT7530_NUM_PORTS];
+ struct mt753x_pcs pcs[MT7530_NUM_PORTS];
+ /* protect among processes for registers access*/
+@@ -798,6 +797,7 @@ struct mt7530_priv {
+ int irq;
+ struct irq_domain *irq_domain;
+ u32 irq_enable;
++ int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii);
+ };
+
+ struct mt7530_hw_vlan_entry {
--- /dev/null
+From 4b11e3eb0eb7245a0d22a5dc4161c54eea42910c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Sat, 17 Jun 2023 09:26:44 +0300
+Subject: [PATCH 16/48] net: dsa: mt7530: set all CPU ports in MT7531_CPU_PMAP
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+MT7531_CPU_PMAP represents the destination port mask for trapped-to-CPU
+frames (further restricted by PCR_MATRIX).
+
+Currently the driver sets the first CPU port as the single port in this bit
+mask, which works fine regardless of whether the device tree defines port
+5, 6 or 5+6 as CPU ports. This is because the logic coincides with DSA's
+logic of picking the first CPU port as the CPU port that all user ports are
+affine to, by default.
+
+An upcoming change would like to influence DSA's selection of the default
+CPU port to no longer be the first one, and in that case, this logic needs
+adaptation.
+
+Since there is no observed leakage or duplication of frames if all CPU
+ports are defined in this bit mask, simply include them all.
+
+Suggested-by: Russell King (Oracle) <linux@armlinux.org.uk>
+Suggested-by: Vladimir Oltean <olteanv@gmail.com>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 15 +++++++--------
+ drivers/net/dsa/mt7530.h | 1 +
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1069,6 +1069,13 @@ mt753x_cpu_port_enable(struct dsa_switch
+ if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
+ mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
+
++ /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
++ * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
++ * is affine to the inbound user port.
++ */
++ if (priv->id == ID_MT7531 || priv->id == ID_MT7988)
++ mt7530_set(priv, MT7531_CFC, MT7531_CPU_PMAP(BIT(port)));
++
+ /* CPU port gets connected to all user ports of
+ * the switch.
+ */
+@@ -2411,16 +2418,8 @@ static int
+ mt7531_setup_common(struct dsa_switch *ds)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- struct dsa_port *cpu_dp;
+ int ret, i;
+
+- /* BPDU to CPU port */
+- dsa_switch_for_each_cpu_port(cpu_dp, ds) {
+- mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
+- BIT(cpu_dp->index));
+- break;
+- }
+-
+ mt753x_trap_frames(priv);
+
+ /* Enable and reset MIB counters */
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -54,6 +54,7 @@ enum mt753x_id {
+ #define MT7531_MIRROR_PORT_GET(x) (((x) >> 16) & MIRROR_MASK)
+ #define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16)
+ #define MT7531_CPU_PMAP_MASK GENMASK(7, 0)
++#define MT7531_CPU_PMAP(x) FIELD_PREP(MT7531_CPU_PMAP_MASK, x)
+
+ #define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \
+ MT7531_CFC : MT7530_MFC)
--- /dev/null
+From fb6858e2c3b931433ea4d25871c272ee4c01bd99 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 16 Jun 2023 13:07:29 +0100
+Subject: [PATCH 17/48] net: dsa: mt7530: update PCS driver to use neg_mode
+
+Update mt7530's embedded PCS driver to use neg_mode, even though it
+makes no use of it or the "mode" argument. This makes the driver
+consistent with converted drivers.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/r/E1qA8Ej-00EaGR-Fk@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -3036,7 +3036,7 @@ static void mt7530_pcs_get_state(struct
+ state->pause |= MLO_PAUSE_TX;
+ }
+
+-static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
++static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+@@ -3064,6 +3064,7 @@ mt753x_setup(struct dsa_switch *ds)
+ /* Initialise the PCS devices */
+ for (i = 0; i < priv->ds->num_ports; i++) {
+ priv->pcs[i].pcs.ops = priv->info->pcs_ops;
++ priv->pcs[i].pcs.neg_mode = true;
+ priv->pcs[i].priv = priv;
+ priv->pcs[i].port = i;
+ }
--- /dev/null
+From 03ede98ecc29b59fb364f735d6de0e6a4c1735fc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Mon, 18 Sep 2023 21:19:12 +0200
+Subject: [PATCH 18/48] net: dsa: mt7530: Convert to platform remove callback
+ returning void
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is ignored (apart
+from emitting a warning) and this typically results in resource leaks.
+To improve here there is a quest to make the remove callback return
+void. In the first step of this quest all drivers are converted to
+.remove_new() which already returns void. Eventually after all drivers
+are converted, .remove_new() is renamed to .remove().
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530-mmio.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/dsa/mt7530-mmio.c
++++ b/drivers/net/dsa/mt7530-mmio.c
+@@ -62,15 +62,12 @@ mt7988_probe(struct platform_device *pde
+ return dsa_register_switch(priv->ds);
+ }
+
+-static int
+-mt7988_remove(struct platform_device *pdev)
++static void 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)
+@@ -87,7 +84,7 @@ static void mt7988_shutdown(struct platf
+
+ static struct platform_driver mt7988_platform_driver = {
+ .probe = mt7988_probe,
+- .remove = mt7988_remove,
++ .remove_new = mt7988_remove,
+ .shutdown = mt7988_shutdown,
+ .driver = {
+ .name = "mt7530-mmio",
--- /dev/null
+From 1a1a723d47c046d6c251651c9ade589040dafacf Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Wed, 27 Sep 2023 13:13:56 +0100
+Subject: [PATCH 19/48] net: dsa: mt753x: remove mt753x_phylink_pcs_link_up()
+
+Remove the mt753x_phylink_pcs_link_up() function for two reasons:
+
+1) priv->pcs[i].pcs.neg_mode is set true, meaning it doesn't take a
+ MLO_AN_FIXED anymore, but one of PHYLINK_PCS_NEG_*. However, this
+ is inconsequential due to...
+2) priv->pcs[port].pcs.ops is always initialised to point at
+ mt7530_pcs_ops, which does not have a pcs_link_up() member.
+
+So, let's remove mt753x_phylink_pcs_link_up() entirely.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://lore.kernel.org/r/E1qlTQS-008BWe-Va@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 11 -----------
+ 1 file changed, 11 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2851,15 +2851,6 @@ static void mt753x_phylink_mac_link_down
+ mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+ }
+
+-static void mt753x_phylink_pcs_link_up(struct phylink_pcs *pcs,
+- unsigned int mode,
+- phy_interface_t interface,
+- int speed, int duplex)
+-{
+- if (pcs->ops->pcs_link_up)
+- pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex);
+-}
+-
+ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
+ unsigned int mode,
+ phy_interface_t interface,
+@@ -2948,8 +2939,6 @@ mt7531_cpu_port_config(struct dsa_switch
+ return ret;
+ mt7530_write(priv, MT7530_PMCR_P(port),
+ PMCR_CPU_PORT_SETTING(priv->id));
+- mt753x_phylink_pcs_link_up(&priv->pcs[port].pcs, MLO_AN_FIXED,
+- interface, speed, DUPLEX_FULL);
+ mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
+ speed, DUPLEX_FULL, true, true);
+
--- /dev/null
+From 51e9c79a4d40fa3a64c0fbdab1ebbebf7cce2dba Mon Sep 17 00:00:00 2001
+From: Justin Stitt <justinstitt@google.com>
+Date: Mon, 9 Oct 2023 18:29:19 +0000
+Subject: [PATCH 20/48] net: dsa: mt7530: replace deprecated strncpy with
+ ethtool_sprintf
+
+`strncpy` is deprecated for use on NUL-terminated destination strings
+[1] and as such we should prefer more robust and less ambiguous string
+interfaces.
+
+ethtool_sprintf() is designed specifically for get_strings() usage.
+Let's replace strncpy in favor of this more robust and easier to
+understand interface.
+
+Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1]
+Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2]
+Link: https://github.com/KSPP/linux/issues/90
+Signed-off-by: Justin Stitt <justinstitt@google.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+Link: https://lore.kernel.org/r/20231009-strncpy-drivers-net-dsa-mt7530-c-v1-1-ec6677a6436a@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -829,8 +829,7 @@ mt7530_get_strings(struct dsa_switch *ds
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(mt7530_mib); i++)
+- strncpy(data + i * ETH_GSTRING_LEN, mt7530_mib[i].name,
+- ETH_GSTRING_LEN);
++ ethtool_sprintf(&data, "%s", mt7530_mib[i].name);
+ }
+
+ static void
--- /dev/null
+From 38be6fdf7e93431e91aac3884837b22236325f68 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:34:31 +0300
+Subject: [PATCH 21/48] net: dsa: mt7530: support OF-based registration of
+ switch MDIO bus
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Currently the MDIO bus of the switches the MT7530 DSA subdriver controls
+can only be registered as non-OF-based. Bring support for registering the
+bus OF-based.
+
+The subdrivers that control switches [with MDIO bus] probed on OF must
+follow this logic to support all cases properly:
+
+No switch MDIO bus defined: Populate ds->user_mii_bus, register the MDIO
+bus, set the interrupts for PHYs if "interrupt-controller" is defined at
+the switch node. This case should only be covered for the switches which
+their dt-bindings documentation didn't document the MDIO bus from the
+start. This is to keep supporting the device trees that do not describe the
+MDIO bus on the device tree but the MDIO bus is being used nonetheless.
+
+Switch MDIO bus defined: Don't populate ds->user_mii_bus, register the MDIO
+bus, set the interrupts for PHYs if ["interrupt-controller" is defined at
+the switch node and "interrupts" is defined at the PHY nodes under the
+switch MDIO bus node].
+
+Switch MDIO bus defined but explicitly disabled: If the device tree says
+status = "disabled" for the MDIO bus, we shouldn't need an MDIO bus at all.
+Instead, just exit as early as possible and do not call any MDIO API.
+
+The use of ds->user_mii_bus is inappropriate when the MDIO bus of the
+switch is described on the device tree [1], which is why we don't populate
+ds->user_mii_bus in that case.
+
+Link: https://lore.kernel.org/netdev/20231213120656.x46fyad6ls7sqyzv@skbuf/ [1]
+Suggested-by: David Bauer <mail@david-bauer.net>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122053431.7751-1-arinc.unal@arinc9.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 34 ++++++++++++++++++++++++++--------
+ 1 file changed, 26 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2175,24 +2175,40 @@ mt7530_free_irq_common(struct mt7530_pri
+ static void
+ mt7530_free_irq(struct mt7530_priv *priv)
+ {
+- mt7530_free_mdio_irq(priv);
++ struct device_node *mnp, *np = priv->dev->of_node;
++
++ mnp = of_get_child_by_name(np, "mdio");
++ if (!mnp)
++ mt7530_free_mdio_irq(priv);
++ of_node_put(mnp);
++
+ mt7530_free_irq_common(priv);
+ }
+
+ static int
+ mt7530_setup_mdio(struct mt7530_priv *priv)
+ {
++ struct device_node *mnp, *np = priv->dev->of_node;
+ struct dsa_switch *ds = priv->ds;
+ struct device *dev = priv->dev;
+ struct mii_bus *bus;
+ static int idx;
+- int ret;
++ int ret = 0;
++
++ mnp = of_get_child_by_name(np, "mdio");
++
++ if (mnp && !of_device_is_available(mnp))
++ goto out;
+
+ bus = devm_mdiobus_alloc(dev);
+- if (!bus)
+- return -ENOMEM;
++ if (!bus) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ if (!mnp)
++ ds->slave_mii_bus = bus;
+
+- ds->slave_mii_bus = bus;
+ bus->priv = priv;
+ bus->name = KBUILD_MODNAME "-mii";
+ snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++);
+@@ -2201,16 +2217,18 @@ mt7530_setup_mdio(struct mt7530_priv *pr
+ bus->parent = dev;
+ bus->phy_mask = ~ds->phys_mii_mask;
+
+- if (priv->irq)
++ if (priv->irq && !mnp)
+ mt7530_setup_mdio_irq(priv);
+
+- ret = devm_mdiobus_register(dev, bus);
++ ret = devm_of_mdiobus_register(dev, bus, mnp);
+ if (ret) {
+ dev_err(dev, "failed to register MDIO bus: %d\n", ret);
+- if (priv->irq)
++ if (priv->irq && !mnp)
+ mt7530_free_mdio_irq(priv);
+ }
+
++out:
++ of_node_put(mnp);
+ return ret;
+ }
+
--- /dev/null
+From 022a254fafce88367914dfc8168fe687fc528cdb Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Wed, 24 Jan 2024 05:17:25 +0000
+Subject: [PATCH 22/48] net: dsa: mt7530: fix 10M/100M speed on MT7988 switch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Setup PMCR port register for actual speed and duplex on internally
+connected PHYs of the MT7988 built-in switch. This fixes links with
+speeds other than 1000M.
+
+Fixes: 110c18bfed41 ("net: dsa: mt7530: introduce driver for MT7988 built-in switch")
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Acked-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/a5b04dfa8256d8302f402545a51ac4c626fdba25.1706071272.git.daniel@makrotopia.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2883,8 +2883,7 @@ 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_INTERNAL ||
+- interface == PHY_INTERFACE_MODE_TRGMII ||
++ if (interface == PHY_INTERFACE_MODE_TRGMII ||
+ (phy_interface_mode_is_8023z(interface))) {
+ speed = SPEED_1000;
+ duplex = DUPLEX_FULL;
--- /dev/null
+From a385398f77fad9eabe7cdc253e1a356484acc316 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:52 +0300
+Subject: [PATCH 23/48] net: dsa: mt7530: always trap frames to active CPU port
+ on MT7530
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On the MT7530 switch, the CPU_PORT field indicates which CPU port to trap
+frames to, regardless of the affinity of the inbound user port.
+
+When multiple CPU ports are in use, if the DSA conduit interface is down,
+trapped frames won't be passed to the conduit interface.
+
+To make trapping frames work including this case, implement
+ds->ops->conduit_state_change() on this subdriver and set the CPU_PORT
+field to the numerically smallest CPU port whose conduit interface is up.
+Introduce the active_cpu_ports field to store the information of the active
+CPU ports. Correct the macros, CPU_PORT is bits 4 through 6 of the
+register.
+
+Add a comment to explain frame trapping for this switch.
+
+Currently, the driver doesn't support the use of multiple CPU ports so this
+is not necessarily a bug fix.
+
+Suggested-by: Vladimir Oltean <olteanv@gmail.com>
+Suggested-by: Russell King (Oracle) <linux@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-1-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 35 +++++++++++++++++++++++++++++++----
+ drivers/net/dsa/mt7530.h | 6 ++++--
+ 2 files changed, 35 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1064,10 +1064,6 @@ mt753x_cpu_port_enable(struct dsa_switch
+ mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) |
+ UNU_FFP(BIT(port)));
+
+- /* Set CPU port number */
+- if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
+- mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
+-
+ /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on
+ * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that
+ * is affine to the inbound user port.
+@@ -3125,6 +3121,36 @@ static int mt753x_set_mac_eee(struct dsa
+ return 0;
+ }
+
++static void
++mt753x_conduit_state_change(struct dsa_switch *ds,
++ const struct net_device *conduit,
++ bool operational)
++{
++ struct dsa_port *cpu_dp = conduit->dsa_ptr;
++ struct mt7530_priv *priv = ds->priv;
++ int val = 0;
++ u8 mask;
++
++ /* Set the CPU port to trap frames to for MT7530. Trapped frames will be
++ * forwarded to the numerically smallest CPU port whose conduit
++ * interface is up.
++ */
++ if (priv->id != ID_MT7530 && priv->id != ID_MT7621)
++ return;
++
++ mask = BIT(cpu_dp->index);
++
++ if (operational)
++ priv->active_cpu_ports |= mask;
++ else
++ priv->active_cpu_ports &= ~mask;
++
++ if (priv->active_cpu_ports)
++ val = CPU_EN | CPU_PORT(__ffs(priv->active_cpu_ports));
++
++ mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val);
++}
++
+ static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+ {
+ return 0;
+@@ -3179,6 +3205,7 @@ const struct dsa_switch_ops mt7530_switc
+ .phylink_mac_link_up = mt753x_phylink_mac_link_up,
+ .get_mac_eee = mt753x_get_mac_eee,
+ .set_mac_eee = mt753x_set_mac_eee,
++ .master_state_change = mt753x_conduit_state_change,
+ };
+ EXPORT_SYMBOL_GPL(mt7530_switch_ops);
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -41,8 +41,8 @@ enum mt753x_id {
+ #define UNU_FFP(x) (((x) & 0xff) << 8)
+ #define UNU_FFP_MASK UNU_FFP(~0)
+ #define CPU_EN BIT(7)
+-#define CPU_PORT(x) ((x) << 4)
+-#define CPU_MASK (0xf << 4)
++#define CPU_PORT_MASK GENMASK(6, 4)
++#define CPU_PORT(x) FIELD_PREP(CPU_PORT_MASK, x)
+ #define MIRROR_EN BIT(3)
+ #define MIRROR_PORT(x) ((x) & 0x7)
+ #define MIRROR_MASK 0x7
+@@ -773,6 +773,7 @@ struct mt753x_info {
+ * @irq_domain: IRQ domain of the switch irq_chip
+ * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
+ * @create_sgmii: Pointer to function creating SGMII PCS instance(s)
++ * @active_cpu_ports: Holding the active CPU ports
+ */
+ struct mt7530_priv {
+ struct device *dev;
+@@ -799,6 +800,7 @@ struct mt7530_priv {
+ struct irq_domain *irq_domain;
+ u32 irq_enable;
+ int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii);
++ u8 active_cpu_ports;
+ };
+
+ struct mt7530_hw_vlan_entry {
--- /dev/null
+From e3c8f69af69e6c4022094309445c009faf5e8cef Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:53 +0300
+Subject: [PATCH 24/48] net: dsa: mt7530: use p5_interface_select as data type
+ for p5_intf_sel
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Use the p5_interface_select enumeration as the data type for the
+p5_intf_sel field. This ensures p5_intf_sel can only take the values
+defined in the p5_interface_select enumeration.
+
+Remove the explicit assignment of 0 to P5_DISABLED as the first enum item
+is automatically assigned 0.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-2-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -703,7 +703,7 @@ struct mt7530_port {
+
+ /* Port 5 interface select definitions */
+ enum p5_interface_select {
+- P5_DISABLED = 0,
++ P5_DISABLED,
+ P5_INTF_SEL_PHY_P0,
+ P5_INTF_SEL_PHY_P4,
+ P5_INTF_SEL_GMAC5,
+@@ -789,7 +789,7 @@ struct mt7530_priv {
+ bool mcm;
+ phy_interface_t p6_interface;
+ phy_interface_t p5_interface;
+- unsigned int p5_intf_sel;
++ enum p5_interface_select p5_intf_sel;
+ u8 mirror_rx;
+ u8 mirror_tx;
+ struct mt7530_port ports[MT7530_NUM_PORTS];
--- /dev/null
+From b0d590a5cdd95ed863717b279751d6166083889f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:54 +0300
+Subject: [PATCH 25/48] net: dsa: mt7530: store port 5 SGMII capability of
+ MT7531
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Introduce the p5_sgmii field to store the information for whether port 5
+has got SGMII or not. Instead of reading the MT7531_TOP_SIG_SR register
+multiple times, the register will be read once and the value will be
+stored on the p5_sgmii field. This saves unnecessary reads of the
+register.
+
+Move the comment about MT7531AE and MT7531BE to mt7531_setup(), where the
+switch is identified.
+
+Get rid of mt7531_dual_sgmii_supported() now that priv->p5_sgmii stores the
+information. Address the code where mt7531_dual_sgmii_supported() is used.
+
+Get rid of mt7531_is_rgmii_port() which just prints the opposite of
+priv->p5_sgmii.
+
+Instead of calling mt7531_pll_setup() then returning, do not call it if
+port 5 is SGMII.
+
+Remove P5_INTF_SEL_GMAC5_SGMII. The p5_interface_select enum is supposed to
+represent the mode that port 5 is being used in, not the hardware
+information of port 5. Set p5_intf_sel to P5_INTF_SEL_GMAC5 instead, if
+port 5 is not dsa_is_unused_port().
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-3-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530-mdio.c | 7 ++---
+ drivers/net/dsa/mt7530.c | 48 ++++++++++++-----------------------
+ drivers/net/dsa/mt7530.h | 6 +++--
+ 3 files changed, 22 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/dsa/mt7530-mdio.c
++++ b/drivers/net/dsa/mt7530-mdio.c
+@@ -81,17 +81,14 @@ static const struct regmap_bus mt7530_re
+ };
+
+ static int
+-mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii)
++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;
+
+- /* MT7531AE has two SGMII units for port 5 and port 6
+- * MT7531BE has only one SGMII unit for port 6
+- */
+- for (i = dual_sgmii ? 0 : 1; i < 2; i++) {
++ for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) {
+ mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
+ sizeof(struct regmap_config),
+ GFP_KERNEL);
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -473,15 +473,6 @@ mt7530_pad_clk_setup(struct dsa_switch *
+ return 0;
+ }
+
+-static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv)
+-{
+- u32 val;
+-
+- val = mt7530_read(priv, MT7531_TOP_SIG_SR);
+-
+- return (val & PAD_DUAL_SGMII_EN) != 0;
+-}
+-
+ static int
+ mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+ {
+@@ -496,9 +487,6 @@ mt7531_pll_setup(struct mt7530_priv *pri
+ u32 xtal;
+ u32 val;
+
+- if (mt7531_dual_sgmii_supported(priv))
+- return;
+-
+ val = mt7530_read(priv, MT7531_CREV);
+ top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
+ hwstrap = mt7530_read(priv, MT7531_HWTRAP);
+@@ -913,8 +901,6 @@ static const char *p5_intf_modes(unsigne
+ return "PHY P4";
+ case P5_INTF_SEL_GMAC5:
+ return "GMAC5";
+- case P5_INTF_SEL_GMAC5_SGMII:
+- return "GMAC5_SGMII";
+ default:
+ return "unknown";
+ }
+@@ -2515,6 +2501,12 @@ mt7531_setup(struct dsa_switch *ds)
+ return -ENODEV;
+ }
+
++ /* MT7531AE has got two SGMII units. One for port 5, one for port 6.
++ * MT7531BE has got only one SGMII unit which is for port 6.
++ */
++ val = mt7530_read(priv, MT7531_TOP_SIG_SR);
++ priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
++
+ /* all MACs must be forced link-down before sw reset */
+ for (i = 0; i < MT7530_NUM_PORTS; i++)
+ mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
+@@ -2524,21 +2516,18 @@ mt7531_setup(struct dsa_switch *ds)
+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+ SYS_CTRL_REG_RST);
+
+- mt7531_pll_setup(priv);
+-
+- if (mt7531_dual_sgmii_supported(priv)) {
+- priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
+-
++ if (!priv->p5_sgmii) {
++ mt7531_pll_setup(priv);
++ } else {
+ /* Let ds->slave_mii_bus be able to access external phy. */
+ mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
+ MT7531_EXT_P_MDC_11);
+ mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
+ MT7531_EXT_P_MDIO_12);
+- } else {
+- priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
+ }
+- dev_dbg(ds->dev, "P5 support %s interface\n",
+- p5_intf_modes(priv->p5_intf_sel));
++
++ if (!dsa_is_unused_port(ds, 5))
++ priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
+
+ mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
+ MT7531_GPIO0_INTERRUPT);
+@@ -2598,11 +2587,6 @@ static void mt7530_mac_port_get_caps(str
+ }
+ }
+
+-static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port)
+-{
+- return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
+-}
+-
+ static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port,
+ struct phylink_config *config)
+ {
+@@ -2615,7 +2599,7 @@ static void mt7531_mac_port_get_caps(str
+ break;
+
+ case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
+- if (mt7531_is_rgmii_port(priv, port)) {
++ if (!priv->p5_sgmii) {
+ phy_interface_set_rgmii(config->supported_interfaces);
+ break;
+ }
+@@ -2682,7 +2666,7 @@ static int mt7531_rgmii_setup(struct mt7
+ {
+ u32 val;
+
+- if (!mt7531_is_rgmii_port(priv, port)) {
++ if (priv->p5_sgmii) {
+ dev_err(priv->dev, "RGMII mode is not available for port %d\n",
+ port);
+ return -EINVAL;
+@@ -2925,7 +2909,7 @@ mt7531_cpu_port_config(struct dsa_switch
+
+ switch (port) {
+ case 5:
+- if (mt7531_is_rgmii_port(priv, port))
++ if (!priv->p5_sgmii)
+ interface = PHY_INTERFACE_MODE_RGMII;
+ else
+ interface = PHY_INTERFACE_MODE_2500BASEX;
+@@ -3083,7 +3067,7 @@ mt753x_setup(struct dsa_switch *ds)
+ mt7530_free_irq_common(priv);
+
+ if (priv->create_sgmii) {
+- ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv));
++ ret = priv->create_sgmii(priv);
+ if (ret && priv->irq)
+ mt7530_free_irq(priv);
+ }
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -707,7 +707,6 @@ enum p5_interface_select {
+ P5_INTF_SEL_PHY_P0,
+ P5_INTF_SEL_PHY_P4,
+ P5_INTF_SEL_GMAC5,
+- P5_INTF_SEL_GMAC5_SGMII,
+ };
+
+ struct mt7530_priv;
+@@ -769,6 +768,8 @@ struct mt753x_info {
+ * registers
+ * @p6_interface Holding the current port 6 interface
+ * @p5_intf_sel: Holding the current port 5 interface select
++ * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch
++ * has got SGMII
+ * @irq: IRQ number of the switch
+ * @irq_domain: IRQ domain of the switch irq_chip
+ * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
+@@ -790,6 +791,7 @@ struct mt7530_priv {
+ phy_interface_t p6_interface;
+ phy_interface_t p5_interface;
+ enum p5_interface_select p5_intf_sel;
++ bool p5_sgmii;
+ u8 mirror_rx;
+ u8 mirror_tx;
+ struct mt7530_port ports[MT7530_NUM_PORTS];
+@@ -799,7 +801,7 @@ struct mt7530_priv {
+ int irq;
+ struct irq_domain *irq_domain;
+ u32 irq_enable;
+- int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii);
++ int (*create_sgmii)(struct mt7530_priv *priv);
+ u8 active_cpu_ports;
+ };
+
--- /dev/null
+From 0dcde4c1e7c47822a6b00d6f96b7f19e51536026 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:55 +0300
+Subject: [PATCH 26/48] net: dsa: mt7530: improve comments regarding switch
+ ports
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There's no logic to numerically order the CPU ports. Just state the port
+number instead.
+
+Remove the irrelevant PHY muxing information from
+mt7530_mac_port_get_caps(). Explain the supported MII modes instead.
+
+Remove the out of place PHY muxing information from
+mt753x_phylink_mac_config(). The function is for MT7530, MT7531, and the
+switch on the MT7988 SoC but there's no PHY muxing on MT7531 or the switch
+on the MT7988 SoC.
+
+These comments were gradually introduced with the commits below.
+commit ca366d6c889b ("net: dsa: mt7530: Convert to PHYLINK API")
+commit 38f790a80560 ("net: dsa: mt7530: Add support for port 5")
+commit 88bdef8be9f6 ("net: dsa: mt7530: Extend device data ready for adding
+a new hardware")
+commit c288575f7810 ("net: dsa: mt7530: Add the support of MT7531 switch")
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-4-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2565,12 +2565,14 @@ static void mt7530_mac_port_get_caps(str
+ struct phylink_config *config)
+ {
+ switch (port) {
+- case 0 ... 4: /* Internal phy */
++ /* Ports which are connected to switch PHYs. There is no MII pinout. */
++ case 0 ... 4:
+ __set_bit(PHY_INTERFACE_MODE_GMII,
+ config->supported_interfaces);
+ break;
+
+- case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
++ /* Port 5 supports rgmii with delays, mii, and gmii. */
++ case 5:
+ phy_interface_set_rgmii(config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_MII,
+ config->supported_interfaces);
+@@ -2578,7 +2580,8 @@ static void mt7530_mac_port_get_caps(str
+ config->supported_interfaces);
+ break;
+
+- case 6: /* 1st cpu port */
++ /* Port 6 supports rgmii and trgmii. */
++ case 6:
+ __set_bit(PHY_INTERFACE_MODE_RGMII,
+ config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_TRGMII,
+@@ -2593,19 +2596,24 @@ static void mt7531_mac_port_get_caps(str
+ struct mt7530_priv *priv = ds->priv;
+
+ switch (port) {
+- case 0 ... 4: /* Internal phy */
++ /* Ports which are connected to switch PHYs. There is no MII pinout. */
++ case 0 ... 4:
+ __set_bit(PHY_INTERFACE_MODE_GMII,
+ config->supported_interfaces);
+ break;
+
+- case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
++ /* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on
++ * MT7531AE.
++ */
++ case 5:
+ if (!priv->p5_sgmii) {
+ phy_interface_set_rgmii(config->supported_interfaces);
+ break;
+ }
+ fallthrough;
+
+- case 6: /* 1st cpu port supports sgmii/8023z only */
++ /* Port 6 supports sgmii/802.3z. */
++ case 6:
+ __set_bit(PHY_INTERFACE_MODE_SGMII,
+ config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+@@ -2624,11 +2632,13 @@ static void mt7988_mac_port_get_caps(str
+ phy_interface_zero(config->supported_interfaces);
+
+ switch (port) {
+- case 0 ... 4: /* Internal phy */
++ /* Ports which are connected to switch PHYs. There is no MII pinout. */
++ case 0 ... 4:
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+ break;
+
++ /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */
+ case 6:
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+@@ -2792,12 +2802,12 @@ mt753x_phylink_mac_config(struct dsa_swi
+ u32 mcr_cur, mcr_new;
+
+ switch (port) {
+- case 0 ... 4: /* Internal phy */
++ case 0 ... 4:
+ 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 */
++ case 5:
+ if (priv->p5_interface == state->interface)
+ break;
+
+@@ -2807,7 +2817,7 @@ mt753x_phylink_mac_config(struct dsa_swi
+ if (priv->p5_intf_sel != P5_DISABLED)
+ priv->p5_interface = state->interface;
+ break;
+- case 6: /* 1st cpu port */
++ case 6:
+ if (priv->p6_interface == state->interface)
+ break;
+
--- /dev/null
+From 0f03d9bfa1da1d26cb950e4b35b1ff7b9be1828f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:56 +0300
+Subject: [PATCH 27/48] net: dsa: mt7530: improve code path for setting up port
+ 5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There're two code paths for setting up port 5:
+
+mt7530_setup()
+-> mt7530_setup_port5()
+
+mt753x_phylink_mac_config()
+-> mt753x_mac_config()
+ -> mt7530_mac_config()
+ -> mt7530_setup_port5()
+
+Currently mt7530_setup_port5() from mt7530_setup() always runs. If port 5
+is used as a CPU, DSA, or user port, mt7530_setup_port5() from
+mt753x_phylink_mac_config() won't run. That is because priv->p5_interface
+set on mt7530_setup_port5() will match state->interface on
+mt753x_phylink_mac_config() which will stop running mt7530_setup_port5()
+again.
+
+Therefore, mt7530_setup_port5() will never run from
+mt753x_phylink_mac_config().
+
+Address this by not running mt7530_setup_port5() from mt7530_setup() if
+port 5 is used as a CPU, DSA, or user port. This driver isn't in the
+dsa_switches_apply_workarounds[] array so phylink will always be present.
+
+To keep the cases where port 5 isn't controlled by phylink working as
+before, preserve the mt7530_setup_port5() call from mt7530_setup().
+
+Do not set priv->p5_intf_sel to P5_DISABLED. It is already set to that when
+"priv" is allocated.
+
+Move setting the interface to a more specific location. It's supposed to be
+overwritten if PHY muxing is detected.
+
+Improve the comment which explains the process.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-5-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2353,16 +2353,15 @@ mt7530_setup(struct dsa_switch *ds)
+ return ret;
+
+ /* Setup port 5 */
+- priv->p5_intf_sel = P5_DISABLED;
+- interface = PHY_INTERFACE_MODE_NA;
+-
+ if (!dsa_is_unused_port(ds, 5)) {
+ priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
+- ret = of_get_phy_mode(dsa_to_port(ds, 5)->dn, &interface);
+- if (ret && ret != -ENODEV)
+- return ret;
+ } else {
+- /* Scan the ethernet nodes. look for GMAC1, lookup used phy */
++ /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY.
++ * Set priv->p5_intf_sel to the appropriate value if PHY muxing
++ * is detected.
++ */
++ interface = PHY_INTERFACE_MODE_NA;
++
+ for_each_child_of_node(dn, mac_np) {
+ if (!of_device_is_compatible(mac_np,
+ "mediatek,eth-mac"))
+@@ -2393,6 +2392,8 @@ mt7530_setup(struct dsa_switch *ds)
+ of_node_put(phy_node);
+ break;
+ }
++
++ mt7530_setup_port5(ds, interface);
+ }
+
+ #ifdef CONFIG_GPIOLIB
+@@ -2403,8 +2404,6 @@ mt7530_setup(struct dsa_switch *ds)
+ }
+ #endif /* CONFIG_GPIOLIB */
+
+- mt7530_setup_port5(ds, interface);
+-
+ /* Flush the FDB table */
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
+ if (ret < 0)
--- /dev/null
+From 120581c81ad19704a9325505c83a82b7e760e96e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:57 +0300
+Subject: [PATCH 28/48] net: dsa: mt7530: do not set priv->p5_interface on
+ mt7530_setup_port5()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Running mt7530_setup_port5() from mt7530_setup() used to handle all cases
+of configuring port 5, including phylink.
+
+Setting priv->p5_interface under mt7530_setup_port5() makes sure that
+mt7530_setup_port5() from mt753x_phylink_mac_config() won't run.
+
+The commit ("net: dsa: mt7530: improve code path for setting up port 5")
+makes so that mt7530_setup_port5() from mt7530_setup() runs only on
+non-phylink cases.
+
+Get rid of unnecessarily setting priv->p5_interface under
+mt7530_setup_port5() as port 5 phylink configuration will be done by
+running mt7530_setup_port5() from mt753x_phylink_mac_config() now.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-6-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -971,8 +971,6 @@ static void mt7530_setup_port5(struct ds
+ dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
+ val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
+
+- priv->p5_interface = interface;
+-
+ unlock_exit:
+ mutex_unlock(&priv->reg_mutex);
+ }
--- /dev/null
+From 3b423061eb3a62e59b57939ae1e1234756a0f6a1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Mon, 22 Jan 2024 08:35:58 +0300
+Subject: [PATCH 29/48] net: dsa: mt7530: do not run mt7530_setup_port5() if
+ port 5 is disabled
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There's no need to run all the code on mt7530_setup_port5() if port 5 is
+disabled. The only case for calling mt7530_setup_port5() from
+mt7530_setup() is when PHY muxing is enabled. That is because port 5 is not
+defined as a port on the devicetree, therefore, it cannot be controlled by
+phylink.
+
+Because of this, run mt7530_setup_port5() if priv->p5_intf_sel is
+P5_INTF_SEL_PHY_P0 or P5_INTF_SEL_PHY_P4. Remove the P5_DISABLED case from
+mt7530_setup_port5().
+
+Stop initialising the interface variable as the remaining cases will always
+call mt7530_setup_port5() with it initialised.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240122-for-netnext-mt7530-improvements-1-v3-7-042401f2b279@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -935,9 +935,6 @@ static void mt7530_setup_port5(struct ds
+ /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */
+ val &= ~MHWTRAP_P5_DIS;
+ break;
+- case P5_DISABLED:
+- interface = PHY_INTERFACE_MODE_NA;
+- break;
+ default:
+ dev_err(ds->dev, "Unsupported p5_intf_sel %d\n",
+ priv->p5_intf_sel);
+@@ -2358,8 +2355,6 @@ mt7530_setup(struct dsa_switch *ds)
+ * Set priv->p5_intf_sel to the appropriate value if PHY muxing
+ * is detected.
+ */
+- interface = PHY_INTERFACE_MODE_NA;
+-
+ for_each_child_of_node(dn, mac_np) {
+ if (!of_device_is_compatible(mac_np,
+ "mediatek,eth-mac"))
+@@ -2391,7 +2386,9 @@ mt7530_setup(struct dsa_switch *ds)
+ break;
+ }
+
+- mt7530_setup_port5(ds, interface);
++ if (priv->p5_intf_sel == P5_INTF_SEL_PHY_P0 ||
++ priv->p5_intf_sel == P5_INTF_SEL_PHY_P4)
++ mt7530_setup_port5(ds, interface);
+ }
+
+ #ifdef CONFIG_GPIOLIB
--- /dev/null
+From 959f4ac4940bebb84bdd25ac61470b3965e1e475 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:02 +0300
+Subject: [PATCH 30/48] net: dsa: mt7530: empty default case on
+ mt7530_setup_port5()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There're two code paths for setting up port 5:
+
+mt7530_setup()
+-> mt7530_setup_port5()
+
+mt753x_phylink_mac_config()
+-> mt753x_mac_config()
+ -> mt7530_mac_config()
+ -> mt7530_setup_port5()
+
+On the first code path, priv->p5_intf_sel is either set to
+P5_INTF_SEL_PHY_P0 or P5_INTF_SEL_PHY_P4 when mt7530_setup_port5() is run.
+
+On the second code path, priv->p5_intf_sel is set to P5_INTF_SEL_GMAC5 when
+mt7530_setup_port5() is run.
+
+Empty the default case which will never run but is needed nonetheless to
+handle all the remaining enumeration values.
+
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-1-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -936,9 +936,7 @@ static void mt7530_setup_port5(struct ds
+ val &= ~MHWTRAP_P5_DIS;
+ break;
+ default:
+- dev_err(ds->dev, "Unsupported p5_intf_sel %d\n",
+- priv->p5_intf_sel);
+- goto unlock_exit;
++ break;
+ }
+
+ /* Setup RGMII settings */
+@@ -968,7 +966,6 @@ static void mt7530_setup_port5(struct ds
+ dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n",
+ val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface));
+
+-unlock_exit:
+ mutex_unlock(&priv->reg_mutex);
+ }
+
--- /dev/null
+From 9ec0a800c8e0850e1358b7402d6af557af81cb38 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:03 +0300
+Subject: [PATCH 31/48] net: dsa: mt7530: move XTAL check to mt7530_setup()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The crystal frequency concerns the switch core. The frequency should be
+checked when the switch is being set up so the driver can reject the
+unsupported hardware earlier and without requiring port 6 to be used.
+
+Move it to mt7530_setup(). Drop the unnecessary function printing.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-2-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -408,13 +408,6 @@ mt7530_pad_clk_setup(struct dsa_switch *
+
+ xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
+
+- if (xtal == HWTRAP_XTAL_20MHZ) {
+- dev_err(priv->dev,
+- "%s: MT7530 with a 20MHz XTAL is not supported!\n",
+- __func__);
+- return -EINVAL;
+- }
+-
+ switch (interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ trgint = 0;
+@@ -2286,6 +2279,12 @@ mt7530_setup(struct dsa_switch *ds)
+ return -ENODEV;
+ }
+
++ if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_20MHZ) {
++ dev_err(priv->dev,
++ "MT7530 with a 20MHz XTAL is not supported!\n");
++ return -EINVAL;
++ }
++
+ /* Reset the switch through internal reset */
+ mt7530_write(priv, MT7530_SYS_CTRL,
+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
--- /dev/null
+From 7199c736aa8cd9c69ae681a9c733408372c2ce76 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:04 +0300
+Subject: [PATCH 32/48] net: dsa: mt7530: simplify mt7530_pad_clk_setup()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This code is from before this driver was converted to phylink API. Phylink
+deals with the unsupported interface cases before mt7530_pad_clk_setup() is
+run. Therefore, the default case would never run. However, it must be
+defined nonetheless to handle all the remaining enumeration values, the
+phy-modes.
+
+Switch to if statement for RGMII and return which simplifies the code and
+saves an indent.
+
+Set P6_INTF_MODE, which is the three least significant bits of the
+MT7530_P6ECR register, to 0 for RGMII even though it will already be 0
+after reset. This is to keep supporting dynamic reconfiguration of the port
+in the case the interface changes from TRGMII to RGMII.
+
+Disable the TRGMII clocks for all cases. They will be enabled if TRGMII is
+being used.
+
+Read XTAL after checking for RGMII as it's only needed for the TRGMII
+interface mode.
+
+Reviewed-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-3-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 91 ++++++++++++++++++----------------------
+ 1 file changed, 40 insertions(+), 51 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -404,65 +404,54 @@ static int
+ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- u32 ncpo1, ssc_delta, trgint, xtal;
++ u32 ncpo1, ssc_delta, xtal;
+
+- xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
++ /* Disable the MT7530 TRGMII clocks */
++ core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
+
+- switch (interface) {
+- case PHY_INTERFACE_MODE_RGMII:
+- trgint = 0;
+- break;
+- case PHY_INTERFACE_MODE_TRGMII:
+- trgint = 1;
+- if (xtal == HWTRAP_XTAL_25MHZ)
+- ssc_delta = 0x57;
+- else
+- ssc_delta = 0x87;
+- if (priv->id == ID_MT7621) {
+- /* PLL frequency: 125MHz: 1.0GBit */
+- if (xtal == HWTRAP_XTAL_40MHZ)
+- ncpo1 = 0x0640;
+- if (xtal == HWTRAP_XTAL_25MHZ)
+- ncpo1 = 0x0a00;
+- } else { /* PLL frequency: 250MHz: 2.0Gbit */
+- if (xtal == HWTRAP_XTAL_40MHZ)
+- ncpo1 = 0x0c80;
+- if (xtal == HWTRAP_XTAL_25MHZ)
+- ncpo1 = 0x1400;
+- }
+- break;
+- default:
+- dev_err(priv->dev, "xMII interface %d not supported\n",
+- interface);
+- return -EINVAL;
++ if (interface == PHY_INTERFACE_MODE_RGMII) {
++ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
++ P6_INTF_MODE(0));
++ return 0;
+ }
+
+- mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
+- P6_INTF_MODE(trgint));
++ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
+
+- if (trgint) {
+- /* Disable the MT7530 TRGMII clocks */
+- core_clear(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
+-
+- /* Setup the MT7530 TRGMII Tx Clock */
+- core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
+- core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
+- core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
+- core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
+- core_write(priv, CORE_PLL_GROUP4,
+- RG_SYSPLL_DDSFBK_EN | RG_SYSPLL_BIAS_EN |
+- RG_SYSPLL_BIAS_LPF_EN);
+- core_write(priv, CORE_PLL_GROUP2,
+- RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
+- RG_SYSPLL_POSDIV(1));
+- core_write(priv, CORE_PLL_GROUP7,
+- RG_LCDDS_PCW_NCPO_CHG | RG_LCCDS_C(3) |
+- RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
++ xtal = mt7530_read(priv, MT7530_MHWTRAP) & HWTRAP_XTAL_MASK;
+
+- /* Enable the MT7530 TRGMII clocks */
+- core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
++ if (xtal == HWTRAP_XTAL_25MHZ)
++ ssc_delta = 0x57;
++ else
++ ssc_delta = 0x87;
++
++ if (priv->id == ID_MT7621) {
++ /* PLL frequency: 125MHz: 1.0GBit */
++ if (xtal == HWTRAP_XTAL_40MHZ)
++ ncpo1 = 0x0640;
++ if (xtal == HWTRAP_XTAL_25MHZ)
++ ncpo1 = 0x0a00;
++ } else { /* PLL frequency: 250MHz: 2.0Gbit */
++ if (xtal == HWTRAP_XTAL_40MHZ)
++ ncpo1 = 0x0c80;
++ if (xtal == HWTRAP_XTAL_25MHZ)
++ ncpo1 = 0x1400;
+ }
+
++ /* Setup the MT7530 TRGMII Tx Clock */
++ core_write(priv, CORE_PLL_GROUP5, RG_LCDDS_PCW_NCPO1(ncpo1));
++ core_write(priv, CORE_PLL_GROUP6, RG_LCDDS_PCW_NCPO0(0));
++ core_write(priv, CORE_PLL_GROUP10, RG_LCDDS_SSC_DELTA(ssc_delta));
++ core_write(priv, CORE_PLL_GROUP11, RG_LCDDS_SSC_DELTA1(ssc_delta));
++ core_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
++ RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
++ core_write(priv, CORE_PLL_GROUP2, RG_SYSPLL_EN_NORMAL |
++ RG_SYSPLL_VODEN | RG_SYSPLL_POSDIV(1));
++ core_write(priv, CORE_PLL_GROUP7, RG_LCDDS_PCW_NCPO_CHG |
++ RG_LCCDS_C(3) | RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
++
++ /* Enable the MT7530 TRGMII clocks */
++ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
++
+ return 0;
+ }
+
--- /dev/null
+From 921a7deee767aa157b5372863a4c1cac53e5c53a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:05 +0300
+Subject: [PATCH 33/48] net: dsa: mt7530: call port 6 setup from
+ mt7530_mac_config()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+mt7530_pad_clk_setup() is called if port 6 is enabled. It used to do more
+things than setting up port 6. That part was moved to more appropriate
+locations, mt7530_setup() and mt7530_pll_setup().
+
+Now that all it does is set up port 6, rename it to mt7530_setup_port6(),
+and move it to a more appropriate location, under mt7530_mac_config().
+
+Change mt7530_setup_port6() to void as there're no error cases.
+
+Leave an empty mt7530_pad_clk_setup() to satisfy the pad_setup function
+pointer.
+
+This is the code path for setting up the ports before:
+
+dsa_switch_ops :: phylink_mac_config() -> mt753x_phylink_mac_config()
+-> mt753x_mac_config()
+ -> mt753x_info :: mac_port_config() -> mt7530_mac_config()
+ -> mt7530_setup_port5()
+-> mt753x_pad_setup()
+ -> mt753x_info :: pad_setup() -> mt7530_pad_clk_setup()
+
+This is after:
+
+dsa_switch_ops :: phylink_mac_config() -> mt753x_phylink_mac_config()
+-> mt753x_mac_config()
+ -> mt753x_info :: mac_port_config() -> mt7530_mac_config()
+ -> mt7530_setup_port5()
+ -> mt7530_setup_port6()
+
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-4-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -400,8 +400,8 @@ static void mt7530_pll_setup(struct mt75
+ }
+
+ /* Setup port 6 interface mode and TRGMII TX circuit */
+-static int
+-mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
++static void
++mt7530_setup_port6(struct dsa_switch *ds, phy_interface_t interface)
+ {
+ struct mt7530_priv *priv = ds->priv;
+ u32 ncpo1, ssc_delta, xtal;
+@@ -412,7 +412,7 @@ mt7530_pad_clk_setup(struct dsa_switch *
+ if (interface == PHY_INTERFACE_MODE_RGMII) {
+ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK,
+ P6_INTF_MODE(0));
+- return 0;
++ return;
+ }
+
+ mt7530_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_MASK, P6_INTF_MODE(1));
+@@ -451,7 +451,11 @@ mt7530_pad_clk_setup(struct dsa_switch *
+
+ /* Enable the MT7530 TRGMII clocks */
+ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
++}
+
++static int
++mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
++{
+ return 0;
+ }
+
+@@ -2640,11 +2644,10 @@ mt7530_mac_config(struct dsa_switch *ds,
+ {
+ struct mt7530_priv *priv = ds->priv;
+
+- /* Only need to setup port5. */
+- if (port != 5)
+- return 0;
+-
+- mt7530_setup_port5(priv->ds, interface);
++ if (port == 5)
++ mt7530_setup_port5(priv->ds, interface);
++ else if (port == 6)
++ mt7530_setup_port6(priv->ds, interface);
+
+ return 0;
+ }
--- /dev/null
+From fcbc5d900fa53f79963fe4626069739ee5567b4b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:06 +0300
+Subject: [PATCH 34/48] net: dsa: mt7530: remove pad_setup function pointer
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The pad_setup function pointer was introduced with 88bdef8be9f6 ("net: dsa:
+mt7530: Extend device data ready for adding a new hardware"). It was being
+used to set up the core clock and port 6 of the MT7530 switch, and pll of
+the MT7531 switch.
+
+All of these were moved to more appropriate locations, and it was never
+used for the switch on the MT7988 SoC. Therefore, this function pointer
+hasn't got a use anymore. Remove it.
+
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-5-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 36 ++----------------------------------
+ drivers/net/dsa/mt7530.h | 3 ---
+ 2 files changed, 2 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -453,18 +453,6 @@ mt7530_setup_port6(struct dsa_switch *ds
+ core_set(priv, CORE_TRGMII_GSW_CLK_CG, REG_TRGMIICK_EN);
+ }
+
+-static int
+-mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
+-{
+- return 0;
+-}
+-
+-static int
+-mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+-{
+- return 0;
+-}
+-
+ static void
+ mt7531_pll_setup(struct mt7530_priv *priv)
+ {
+@@ -2631,14 +2619,6 @@ static void mt7988_mac_port_get_caps(str
+ }
+
+ static int
+-mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
+-{
+- struct mt7530_priv *priv = ds->priv;
+-
+- return priv->info->pad_setup(ds, state->interface);
+-}
+-
+-static int
+ mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ phy_interface_t interface)
+ {
+@@ -2803,8 +2783,6 @@ mt753x_phylink_mac_config(struct dsa_swi
+ if (priv->p6_interface == state->interface)
+ break;
+
+- mt753x_pad_setup(ds, state);
+-
+ if (mt753x_mac_config(ds, port, mode, state) < 0)
+ goto unsupported;
+
+@@ -3127,11 +3105,6 @@ mt753x_conduit_state_change(struct dsa_s
+ mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, 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;
+@@ -3192,7 +3165,6 @@ const struct mt753x_info mt753x_table[]
+ .sw_setup = mt7530_setup,
+ .phy_read = mt7530_phy_read,
+ .phy_write = mt7530_phy_write,
+- .pad_setup = mt7530_pad_clk_setup,
+ .mac_port_get_caps = mt7530_mac_port_get_caps,
+ .mac_port_config = mt7530_mac_config,
+ },
+@@ -3202,7 +3174,6 @@ const struct mt753x_info mt753x_table[]
+ .sw_setup = mt7530_setup,
+ .phy_read = mt7530_phy_read,
+ .phy_write = mt7530_phy_write,
+- .pad_setup = mt7530_pad_clk_setup,
+ .mac_port_get_caps = mt7530_mac_port_get_caps,
+ .mac_port_config = mt7530_mac_config,
+ },
+@@ -3212,7 +3183,6 @@ const struct mt753x_info mt753x_table[]
+ .sw_setup = mt7531_setup,
+ .phy_read = mt7531_ind_phy_read,
+ .phy_write = mt7531_ind_phy_write,
+- .pad_setup = mt7531_pad_setup,
+ .cpu_port_config = mt7531_cpu_port_config,
+ .mac_port_get_caps = mt7531_mac_port_get_caps,
+ .mac_port_config = mt7531_mac_config,
+@@ -3223,7 +3193,6 @@ const struct mt753x_info mt753x_table[]
+ .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,
+@@ -3253,9 +3222,8 @@ mt7530_probe_common(struct mt7530_priv *
+ /* Sanity check if these required device operations are filled
+ * properly.
+ */
+- if (!priv->info->sw_setup || !priv->info->pad_setup ||
+- !priv->info->phy_read || !priv->info->phy_write ||
+- !priv->info->mac_port_get_caps ||
++ if (!priv->info->sw_setup || !priv->info->phy_read ||
++ !priv->info->phy_write || !priv->info->mac_port_get_caps ||
+ !priv->info->mac_port_config)
+ return -EINVAL;
+
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -722,8 +722,6 @@ struct mt753x_pcs {
+ * @sw_setup: Holding the handler to a device initialization
+ * @phy_read: Holding the way reading PHY port
+ * @phy_write: Holding the way writing PHY port
+- * @pad_setup: Holding the way setting up the bus pad for a certain
+- * MAC port
+ * @phy_mode_supported: Check if the PHY type is being supported on a certain
+ * port
+ * @mac_port_validate: Holding the way to set addition validate type for a
+@@ -739,7 +737,6 @@ struct mt753x_info {
+ int (*sw_setup)(struct dsa_switch *ds);
+ int (*phy_read)(struct mt7530_priv *priv, int port, int regnum);
+ int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val);
+- int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
+ int (*cpu_port_config)(struct dsa_switch *ds, int port);
+ void (*mac_port_get_caps)(struct dsa_switch *ds, int port,
+ struct phylink_config *config);
--- /dev/null
+From 58a94eb63233bb2ede13b183b6a6a03aa0a2dfc3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:07 +0300
+Subject: [PATCH 35/48] net: dsa: mt7530: correct port capabilities of MT7988
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+On the switch on the MT7988 SoC, as shown in Block Diagram 8.1.1.3 on page
+125 of "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open
+Version) v0.1", there are only 4 PHYs. That's port 0 to 3. Set the case for
+ports which connect to switch PHYs to '0 ... 3'.
+
+Port 4 and 5 are not used at all in this design.
+
+Link: https://wiki.banana-pi.org/Banana_Pi_BPI-R4#Documents [1]
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-6-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2604,7 +2604,7 @@ static void mt7988_mac_port_get_caps(str
+
+ switch (port) {
+ /* Ports which are connected to switch PHYs. There is no MII pinout. */
+- case 0 ... 4:
++ case 0 ... 3:
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+ break;
--- /dev/null
+From 4440ce33074be6bd55d1a0c8b5f4b6d433ae2c74 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Tue, 6 Feb 2024 01:08:08 +0300
+Subject: [PATCH 36/48] net: dsa: mt7530: do not clear
+ config->supported_interfaces
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There's no need to clear the config->supported_interfaces bitmap before
+reporting the supported interfaces as all bits in the bitmap will already
+be initialized to zero when the phylink_config structure is allocated. The
+"config" pointer points to &dp->phylink_config, and "dp" is allocated by
+dsa_port_touch() with kzalloc(), so all its fields are filled with zeroes.
+
+There's no code that would change the bitmap beforehand. Remove it.
+
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240206-for-netnext-mt7530-improvements-2-v5-7-d7d92a185cb1@arinc9.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ drivers/net/dsa/mt7530.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2600,8 +2600,6 @@ 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) {
+ /* Ports which are connected to switch PHYs. There is no MII pinout. */
+ case 0 ... 3:
--- /dev/null
+From 2f507aaeb1a12044f2376a255c2afff1f7432b0b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:42:57 +0200
+Subject: [PATCH 37/48] net: dsa: mt7530: remove .mac_port_config for MT7988
+ and make it optional
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+For the switch on the MT7988 SoC, the mac_port_config member for ID_MT7988
+in mt753x_table is not needed as the interfaces of all MACs are already
+handled on mt7988_mac_port_get_caps().
+
+Therefore, remove the mac_port_config member from ID_MT7988 in
+mt753x_table. Before calling priv->info->mac_port_config(), if there's no
+mac_port_config member in mt753x_table, exit mt753x_mac_config()
+successfully.
+
+Remove calling priv->info->mac_port_config() from the sanity check as the
+sanity check requires a pointer to a mac_port_config function to be
+non-NULL. This will fail for MT7988 as mac_port_config won't be a member of
+its info table.
+
+Co-developed-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 18 ++++--------------
+ 1 file changed, 4 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2683,17 +2683,6 @@ 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)
+ {
+@@ -2733,6 +2722,9 @@ mt753x_mac_config(struct dsa_switch *ds,
+ {
+ struct mt7530_priv *priv = ds->priv;
+
++ if (!priv->info->mac_port_config)
++ return 0;
++
+ return priv->info->mac_port_config(ds, port, mode, state->interface);
+ }
+
+@@ -3193,7 +3185,6 @@ const struct mt753x_info mt753x_table[]
+ .phy_write = mt7531_ind_phy_write,
+ .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);
+@@ -3221,8 +3212,7 @@ mt7530_probe_common(struct mt7530_priv *
+ * properly.
+ */
+ if (!priv->info->sw_setup || !priv->info->phy_read ||
+- !priv->info->phy_write || !priv->info->mac_port_get_caps ||
+- !priv->info->mac_port_config)
++ !priv->info->phy_write || !priv->info->mac_port_get_caps)
+ return -EINVAL;
+
+ priv->id = priv->info->id;
--- /dev/null
+From 0e297b1c662825f7dcd97272323c81f502987e0f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:42:58 +0200
+Subject: [PATCH 38/48] net: dsa: mt7530: set interrupt register only for
+ MT7530
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Setting this register related to interrupts is only needed for the MT7530
+switch. Make an exclusive check to ensure this.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2084,7 +2084,7 @@ mt7530_setup_irq(struct mt7530_priv *pri
+ }
+
+ /* This register must be set for MT7530 to properly fire interrupts */
+- if (priv->id != ID_MT7531)
++ if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
+ mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
+
+ ret = request_threaded_irq(priv->irq, NULL, mt7530_irq_thread_fn,
--- /dev/null
+From 0eb6bc551371070325b6606cc3bed6734ecad87d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:42:59 +0200
+Subject: [PATCH 39/48] net: dsa: mt7530: do not use SW_PHY_RST to reset MT7531
+ switch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+According to the document MT7531 Reference Manual for Development Board
+v1.0, the SW_PHY_RST bit on the SYS_CTRL register doesn't exist for
+MT7531. This is likely why forcing link down on all ports is necessary for
+MT7531.
+
+Therefore, do not set SW_PHY_RST on mt7531_setup().
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2478,14 +2478,12 @@ mt7531_setup(struct dsa_switch *ds)
+ val = mt7530_read(priv, MT7531_TOP_SIG_SR);
+ priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
+
+- /* all MACs must be forced link-down before sw reset */
++ /* Force link down on all ports before internal reset */
+ for (i = 0; i < MT7530_NUM_PORTS; i++)
+ mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
+
+ /* Reset the switch through internal reset */
+- mt7530_write(priv, MT7530_SYS_CTRL,
+- SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+- SYS_CTRL_REG_RST);
++ mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_SW_RST | SYS_CTRL_REG_RST);
+
+ if (!priv->p5_sgmii) {
+ mt7531_pll_setup(priv);
--- /dev/null
+From bb20b1b4d832de4eb98ec7c22906db7c04e3f7c5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:43:00 +0200
+Subject: [PATCH 40/48] net: dsa: mt7530: get rid of useless error returns on
+ phylink code path
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Remove error returns on the cases where they are already handled with the
+function the mac_port_get_caps member in mt753x_table points to.
+
+mt7531_mac_config() is also called from mt7531_cpu_port_config() outside of
+phylink but the port and interface modes are already handled there.
+
+Change the functions and the mac_port_config function pointer to void now
+that there're no error returns anymore.
+
+Remove mt753x_is_mac_port() that used to help the said error returns.
+
+On mt7531_mac_config(), switch to if statements to simplify the code.
+
+Remove internal phy cases from mt753x_phylink_mac_config(), there is no
+need to check the interface mode as that's already handled with the
+function the mac_port_get_caps member in mt753x_table points to.
+
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 81 ++++++++--------------------------------
+ drivers/net/dsa/mt7530.h | 6 +--
+ 2 files changed, 19 insertions(+), 68 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2614,7 +2614,7 @@ static void mt7988_mac_port_get_caps(str
+ }
+ }
+
+-static int
++static void
+ mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ phy_interface_t interface)
+ {
+@@ -2624,22 +2624,14 @@ mt7530_mac_config(struct dsa_switch *ds,
+ mt7530_setup_port5(priv->ds, interface);
+ else if (port == 6)
+ mt7530_setup_port6(priv->ds, interface);
+-
+- return 0;
+ }
+
+-static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
+- phy_interface_t interface,
+- struct phy_device *phydev)
++static void mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
++ phy_interface_t interface,
++ struct phy_device *phydev)
+ {
+ u32 val;
+
+- if (priv->p5_sgmii) {
+- dev_err(priv->dev, "RGMII mode is not available for port %d\n",
+- port);
+- return -EINVAL;
+- }
+-
+ val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
+ val |= GP_CLK_EN;
+ val &= ~GP_MODE_MASK;
+@@ -2667,20 +2659,14 @@ static int mt7531_rgmii_setup(struct mt7
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ break;
+ default:
+- return -EINVAL;
++ break;
+ }
+ }
+- mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
+
+- return 0;
+-}
+-
+-static bool mt753x_is_mac_port(u32 port)
+-{
+- return (port == 5 || port == 6);
++ mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
+ }
+
+-static int
++static void
+ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ phy_interface_t interface)
+ {
+@@ -2688,42 +2674,21 @@ mt7531_mac_config(struct dsa_switch *ds,
+ struct phy_device *phydev;
+ struct dsa_port *dp;
+
+- if (!mt753x_is_mac_port(port)) {
+- dev_err(priv->dev, "port %d is not a MAC port\n", port);
+- return -EINVAL;
+- }
+-
+- switch (interface) {
+- case PHY_INTERFACE_MODE_RGMII:
+- case PHY_INTERFACE_MODE_RGMII_ID:
+- case PHY_INTERFACE_MODE_RGMII_RXID:
+- case PHY_INTERFACE_MODE_RGMII_TXID:
++ if (phy_interface_mode_is_rgmii(interface)) {
+ dp = dsa_to_port(ds, port);
+ phydev = dp->slave->phydev;
+- return mt7531_rgmii_setup(priv, port, interface, phydev);
+- case PHY_INTERFACE_MODE_SGMII:
+- case PHY_INTERFACE_MODE_NA:
+- case PHY_INTERFACE_MODE_1000BASEX:
+- case PHY_INTERFACE_MODE_2500BASEX:
+- /* handled in SGMII PCS driver */
+- return 0;
+- default:
+- return -EINVAL;
++ mt7531_rgmii_setup(priv, port, interface, phydev);
+ }
+-
+- return -EINVAL;
+ }
+
+-static int
++static void
+ mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+ const struct phylink_link_state *state)
+ {
+ struct mt7530_priv *priv = ds->priv;
+
+- if (!priv->info->mac_port_config)
+- return 0;
+-
+- return priv->info->mac_port_config(ds, port, mode, state->interface);
++ if (priv->info->mac_port_config)
++ priv->info->mac_port_config(ds, port, mode, state->interface);
+ }
+
+ static struct phylink_pcs *
+@@ -2752,17 +2717,11 @@ mt753x_phylink_mac_config(struct dsa_swi
+ u32 mcr_cur, mcr_new;
+
+ switch (port) {
+- case 0 ... 4:
+- if (state->interface != PHY_INTERFACE_MODE_GMII &&
+- state->interface != PHY_INTERFACE_MODE_INTERNAL)
+- goto unsupported;
+- break;
+ case 5:
+ if (priv->p5_interface == state->interface)
+ break;
+
+- if (mt753x_mac_config(ds, port, mode, state) < 0)
+- goto unsupported;
++ mt753x_mac_config(ds, port, mode, state);
+
+ if (priv->p5_intf_sel != P5_DISABLED)
+ priv->p5_interface = state->interface;
+@@ -2771,16 +2730,10 @@ mt753x_phylink_mac_config(struct dsa_swi
+ if (priv->p6_interface == state->interface)
+ break;
+
+- if (mt753x_mac_config(ds, port, mode, state) < 0)
+- goto unsupported;
++ mt753x_mac_config(ds, port, mode, state);
+
+ priv->p6_interface = state->interface;
+ break;
+- default:
+-unsupported:
+- dev_err(ds->dev, "%s: unsupported %s port: %i\n",
+- __func__, phy_modes(state->interface), port);
+- return;
+ }
+
+ mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
+@@ -2863,7 +2816,6 @@ mt7531_cpu_port_config(struct dsa_switch
+ struct mt7530_priv *priv = ds->priv;
+ phy_interface_t interface;
+ int speed;
+- int ret;
+
+ switch (port) {
+ case 5:
+@@ -2888,9 +2840,8 @@ mt7531_cpu_port_config(struct dsa_switch
+ else
+ speed = SPEED_1000;
+
+- ret = mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
+- if (ret)
+- return ret;
++ mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
++
+ mt7530_write(priv, MT7530_PMCR_P(port),
+ PMCR_CPU_PORT_SETTING(priv->id));
+ mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -743,9 +743,9 @@ struct mt753x_info {
+ void (*mac_port_validate)(struct dsa_switch *ds, int port,
+ phy_interface_t interface,
+ unsigned long *supported);
+- int (*mac_port_config)(struct dsa_switch *ds, int port,
+- unsigned int mode,
+- phy_interface_t interface);
++ void (*mac_port_config)(struct dsa_switch *ds, int port,
++ unsigned int mode,
++ phy_interface_t interface);
+ };
+
+ /* struct mt7530_priv - This is the main data structure for holding the state
--- /dev/null
+From 8554f6a7914d28b179671540f527897d85c88809 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:43:01 +0200
+Subject: [PATCH 41/48] net: dsa: mt7530: get rid of
+ priv->info->cpu_port_config()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+priv->info->cpu_port_config() is used for MT7531 and the switch on the
+MT7988 SoC. It sets up the ports described as a CPU port earlier than the
+phylink code path would do.
+
+This function is useless as:
+- Configuring the MACs can be done from the phylink_mac_config code path
+ instead.
+- All the link configuration it does on the CPU ports are later undone with
+ the port_enable, phylink_mac_config, and then phylink_mac_link_up code
+ path [1].
+
+priv->p5_interface and priv->p6_interface were being used to prevent
+configuring the MACs from the phylink_mac_config code path. Remove them now
+that they hold no purpose.
+
+Remove priv->info->cpu_port_config(). On mt753x_phylink_mac_config, switch
+to if statements to simplify the code.
+
+Remove the overwriting of the speed and duplex interfaces for certain
+interface modes. Phylink already provides the speed and duplex variables
+with proper values. Phylink already sets the max speed of TRGMII to
+SPEED_1000. Add SPEED_2500 for PHY_INTERFACE_MODE_2500BASEX to where the
+speed and EEE bits are set instead.
+
+On the switch on the MT7988 SoC, PHY_INTERFACE_MODE_INTERNAL is being used
+to describe the interface mode of the 10G MAC, which is of port 6. On
+mt7988_cpu_port_config() PMCR_FORCE_SPEED_1000 was set via the
+PMCR_CPU_PORT_SETTING() mask. Add SPEED_10000 case to where the speed bits
+are set to cover this. No need to add it to where the EEE bits are set as
+the "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version)
+v0.1" document shows that these bits don't exist on the MT7530_PMCR_P(6)
+register.
+
+Remove the definition of PMCR_CPU_PORT_SETTING() now that it holds no
+purpose.
+
+Change mt753x_cpu_port_enable() to void now that there're no error cases
+left.
+
+Link: https://lore.kernel.org/netdev/ZHy2jQLesdYFMQtO@shell.armlinux.org.uk/ [1]
+Suggested-by: Russell King (Oracle) <linux@armlinux.org.uk>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 114 +++------------------------------------
+ drivers/net/dsa/mt7530.h | 11 ----
+ 2 files changed, 7 insertions(+), 118 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -995,18 +995,10 @@ mt753x_trap_frames(struct mt7530_priv *p
+ MT753X_BPDU_CPU_ONLY);
+ }
+
+-static int
++static void
+ mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- int ret;
+-
+- /* Setup max capability of CPU port at first */
+- if (priv->info->cpu_port_config) {
+- ret = priv->info->cpu_port_config(ds, port);
+- if (ret)
+- return ret;
+- }
+
+ /* Enable Mediatek header mode on the cpu port */
+ mt7530_write(priv, MT7530_PVC_P(port),
+@@ -1032,8 +1024,6 @@ mt753x_cpu_port_enable(struct dsa_switch
+ /* Set to fallback mode for independent VLAN learning */
+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
+ MT7530_PORT_FALLBACK_MODE);
+-
+- return 0;
+ }
+
+ static int
+@@ -2288,8 +2278,6 @@ mt7530_setup(struct dsa_switch *ds)
+ val |= MHWTRAP_MANUAL;
+ mt7530_write(priv, MT7530_MHWTRAP, val);
+
+- priv->p6_interface = PHY_INTERFACE_MODE_NA;
+-
+ mt753x_trap_frames(priv);
+
+ /* Enable and reset MIB counters */
+@@ -2304,9 +2292,7 @@ mt7530_setup(struct dsa_switch *ds)
+ mt7530_set(priv, MT7530_PSC_P(i), SA_DIS);
+
+ if (dsa_is_cpu_port(ds, i)) {
+- ret = mt753x_cpu_port_enable(ds, i);
+- if (ret)
+- return ret;
++ mt753x_cpu_port_enable(ds, i);
+ } else {
+ mt7530_port_disable(ds, i);
+
+@@ -2410,9 +2396,7 @@ mt7531_setup_common(struct dsa_switch *d
+ mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
+
+ if (dsa_is_cpu_port(ds, i)) {
+- ret = mt753x_cpu_port_enable(ds, i);
+- if (ret)
+- return ret;
++ mt753x_cpu_port_enable(ds, i);
+ } else {
+ mt7530_port_disable(ds, i);
+
+@@ -2501,10 +2485,6 @@ mt7531_setup(struct dsa_switch *ds)
+ mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
+ MT7531_GPIO0_INTERRUPT);
+
+- /* Let phylink decide the interface later. */
+- priv->p5_interface = PHY_INTERFACE_MODE_NA;
+- priv->p6_interface = PHY_INTERFACE_MODE_NA;
+-
+ /* Enable PHY core PLL, since phy_device has not yet been created
+ * provided for phy_[read,write]_mmd_indirect is called, we provide
+ * our own mt7531_ind_mmd_phy_[read,write] to complete this
+@@ -2716,26 +2696,9 @@ mt753x_phylink_mac_config(struct dsa_swi
+ struct mt7530_priv *priv = ds->priv;
+ u32 mcr_cur, mcr_new;
+
+- switch (port) {
+- case 5:
+- if (priv->p5_interface == state->interface)
+- break;
+-
++ if (port == 5 || port == 6)
+ mt753x_mac_config(ds, port, mode, state);
+
+- if (priv->p5_intf_sel != P5_DISABLED)
+- priv->p5_interface = state->interface;
+- break;
+- case 6:
+- if (priv->p6_interface == state->interface)
+- break;
+-
+- mt753x_mac_config(ds, port, mode, state);
+-
+- priv->p6_interface = state->interface;
+- break;
+- }
+-
+ mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
+ mcr_new = mcr_cur;
+ mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
+@@ -2771,17 +2734,10 @@ static void mt753x_phylink_mac_link_up(s
+
+ mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
+
+- /* 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))) {
+- speed = SPEED_1000;
+- duplex = DUPLEX_FULL;
+- }
+-
+ switch (speed) {
+ case SPEED_1000:
++ case SPEED_2500:
++ case SPEED_10000:
+ mcr |= PMCR_FORCE_SPEED_1000;
+ break;
+ case SPEED_100:
+@@ -2799,6 +2755,7 @@ static void mt753x_phylink_mac_link_up(s
+ if (mode == MLO_AN_PHY && phydev && phy_init_eee(phydev, false) >= 0) {
+ switch (speed) {
+ case SPEED_1000:
++ case SPEED_2500:
+ mcr |= PMCR_FORCE_EEE1G;
+ break;
+ case SPEED_100:
+@@ -2810,61 +2767,6 @@ static void mt753x_phylink_mac_link_up(s
+ mt7530_set(priv, MT7530_PMCR_P(port), mcr);
+ }
+
+-static int
+-mt7531_cpu_port_config(struct dsa_switch *ds, int port)
+-{
+- struct mt7530_priv *priv = ds->priv;
+- phy_interface_t interface;
+- int speed;
+-
+- switch (port) {
+- case 5:
+- if (!priv->p5_sgmii)
+- interface = PHY_INTERFACE_MODE_RGMII;
+- else
+- interface = PHY_INTERFACE_MODE_2500BASEX;
+-
+- priv->p5_interface = interface;
+- break;
+- case 6:
+- interface = PHY_INTERFACE_MODE_2500BASEX;
+-
+- priv->p6_interface = interface;
+- break;
+- default:
+- return -EINVAL;
+- }
+-
+- if (interface == PHY_INTERFACE_MODE_2500BASEX)
+- speed = SPEED_2500;
+- else
+- speed = SPEED_1000;
+-
+- mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
+-
+- mt7530_write(priv, MT7530_PMCR_P(port),
+- PMCR_CPU_PORT_SETTING(priv->id));
+- mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
+- speed, DUPLEX_FULL, true, true);
+-
+- 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)
+ {
+@@ -3122,7 +3024,6 @@ const struct mt753x_info mt753x_table[]
+ .sw_setup = mt7531_setup,
+ .phy_read = mt7531_ind_phy_read,
+ .phy_write = mt7531_ind_phy_write,
+- .cpu_port_config = mt7531_cpu_port_config,
+ .mac_port_get_caps = mt7531_mac_port_get_caps,
+ .mac_port_config = mt7531_mac_config,
+ },
+@@ -3132,7 +3033,6 @@ const struct mt753x_info mt753x_table[]
+ .sw_setup = mt7988_setup,
+ .phy_read = mt7531_ind_phy_read,
+ .phy_write = mt7531_ind_phy_write,
+- .cpu_port_config = mt7988_cpu_port_config,
+ .mac_port_get_caps = mt7988_mac_port_get_caps,
+ },
+ };
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -331,13 +331,6 @@ enum mt7530_vlan_port_acc_frm {
+ PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+ PMCR_FORCE_FDX | PMCR_FORCE_LNK | \
+ PMCR_FORCE_EEE1G | PMCR_FORCE_EEE100)
+-#define PMCR_CPU_PORT_SETTING(id) (PMCR_FORCE_MODE_ID((id)) | \
+- PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
+- PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
+- PMCR_TX_EN | PMCR_RX_EN | \
+- PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
+- PMCR_FORCE_SPEED_1000 | \
+- PMCR_FORCE_FDX | PMCR_FORCE_LNK)
+
+ #define MT7530_PMEEECR_P(x) (0x3004 + (x) * 0x100)
+ #define WAKEUP_TIME_1000(x) (((x) & 0xFF) << 24)
+@@ -737,7 +730,6 @@ struct mt753x_info {
+ int (*sw_setup)(struct dsa_switch *ds);
+ int (*phy_read)(struct mt7530_priv *priv, int port, int regnum);
+ int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val);
+- int (*cpu_port_config)(struct dsa_switch *ds, int port);
+ void (*mac_port_get_caps)(struct dsa_switch *ds, int port,
+ struct phylink_config *config);
+ void (*mac_port_validate)(struct dsa_switch *ds, int port,
+@@ -763,7 +755,6 @@ struct mt753x_info {
+ * @ports: Holding the state among ports
+ * @reg_mutex: The lock for protecting among process accessing
+ * registers
+- * @p6_interface Holding the current port 6 interface
+ * @p5_intf_sel: Holding the current port 5 interface select
+ * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch
+ * has got SGMII
+@@ -785,8 +776,6 @@ struct mt7530_priv {
+ const struct mt753x_info *info;
+ unsigned int id;
+ bool mcm;
+- phy_interface_t p6_interface;
+- phy_interface_t p5_interface;
+ enum p5_interface_select p5_intf_sel;
+ bool p5_sgmii;
+ u8 mirror_rx;
--- /dev/null
+From 0c282205ef8c6dd6d2c145fac1fb6aba3e65c02d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:43:02 +0200
+Subject: [PATCH 42/48] net: dsa: mt7530: get rid of mt753x_mac_config()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There is no need for a separate function to call
+priv->info->mac_port_config(). Call it from mt753x_phylink_mac_config()
+instead and remove mt753x_mac_config().
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 14 ++------------
+ 1 file changed, 2 insertions(+), 12 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2661,16 +2661,6 @@ mt7531_mac_config(struct dsa_switch *ds,
+ }
+ }
+
+-static void
+-mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+- const struct phylink_link_state *state)
+-{
+- struct mt7530_priv *priv = ds->priv;
+-
+- if (priv->info->mac_port_config)
+- priv->info->mac_port_config(ds, port, mode, state->interface);
+-}
+-
+ static struct phylink_pcs *
+ mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
+ phy_interface_t interface)
+@@ -2696,8 +2686,8 @@ mt753x_phylink_mac_config(struct dsa_swi
+ struct mt7530_priv *priv = ds->priv;
+ u32 mcr_cur, mcr_new;
+
+- if (port == 5 || port == 6)
+- mt753x_mac_config(ds, port, mode, state);
++ if ((port == 5 || port == 6) && priv->info->mac_port_config)
++ priv->info->mac_port_config(ds, port, mode, state->interface);
+
+ mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
+ mcr_new = mcr_cur;
--- /dev/null
+From d55c300aa1fe240aa3eba18550ba6c4e2c4bd157 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:43:03 +0200
+Subject: [PATCH 43/48] net: dsa: mt7530: put initialising PCS devices code
+ back to original order
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The commit fae463084032 ("net: dsa: mt753x: fix pcs conversion regression")
+fixes regression caused by cpu_port_config manually calling phylink
+operations. cpu_port_config was deemed useless and was removed. Therefore,
+put initialising PCS devices code back to its original order.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 20 ++++++++++----------
+ 1 file changed, 10 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2845,17 +2845,9 @@ static int
+ mt753x_setup(struct dsa_switch *ds)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- int i, ret;
++ int ret = priv->info->sw_setup(ds);
++ int i;
+
+- /* Initialise the PCS devices */
+- for (i = 0; i < priv->ds->num_ports; i++) {
+- priv->pcs[i].pcs.ops = priv->info->pcs_ops;
+- priv->pcs[i].pcs.neg_mode = true;
+- priv->pcs[i].priv = priv;
+- priv->pcs[i].port = i;
+- }
+-
+- ret = priv->info->sw_setup(ds);
+ if (ret)
+ return ret;
+
+@@ -2867,6 +2859,14 @@ mt753x_setup(struct dsa_switch *ds)
+ if (ret && priv->irq)
+ mt7530_free_irq_common(priv);
+
++ /* Initialise the PCS devices */
++ for (i = 0; i < priv->ds->num_ports; i++) {
++ priv->pcs[i].pcs.ops = priv->info->pcs_ops;
++ priv->pcs[i].pcs.neg_mode = true;
++ priv->pcs[i].priv = priv;
++ priv->pcs[i].port = i;
++ }
++
+ if (priv->create_sgmii) {
+ ret = priv->create_sgmii(priv);
+ if (ret && priv->irq)
--- /dev/null
+From a9544caa482a7ed215117a902f04185216997831 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:43:04 +0200
+Subject: [PATCH 44/48] net: dsa: mt7530: sort link settings ops and force link
+ down on all ports
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+port_enable and port_disable clears the link settings. Move that to
+mt7530_setup() and mt7531_setup_common() which set up the switches. This
+way, the link settings are cleared on all ports at setup, and then only
+once with phylink_mac_link_down() when a link goes down.
+
+Enable force mode at setup to apply the force part of the link settings.
+This ensures that disabled ports will have their link down.
+
+Suggested-by: Vladimir Oltean <olteanv@gmail.com>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1047,7 +1047,6 @@ mt7530_port_enable(struct dsa_switch *ds
+ priv->ports[port].enable = true;
+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ priv->ports[port].pm);
+- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+
+ mutex_unlock(&priv->reg_mutex);
+
+@@ -1067,7 +1066,6 @@ mt7530_port_disable(struct dsa_switch *d
+ priv->ports[port].enable = false;
+ mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
+ PCR_MATRIX_CLR);
+- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
+
+ mutex_unlock(&priv->reg_mutex);
+ }
+@@ -2284,6 +2282,12 @@ mt7530_setup(struct dsa_switch *ds)
+ mt7530_mib_reset(ds);
+
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
++ /* Clear link settings and enable force mode to force link down
++ * on all ports until they're enabled later.
++ */
++ mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
++ PMCR_FORCE_MODE, PMCR_FORCE_MODE);
++
+ /* Disable forwarding by default on all ports */
+ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
+ PCR_MATRIX_CLR);
+@@ -2386,6 +2390,12 @@ mt7531_setup_common(struct dsa_switch *d
+ UNU_FFP_MASK);
+
+ for (i = 0; i < MT7530_NUM_PORTS; i++) {
++ /* Clear link settings and enable force mode to force link down
++ * on all ports until they're enabled later.
++ */
++ mt7530_rmw(priv, MT7530_PMCR_P(i), PMCR_LINK_SETTINGS_MASK |
++ MT7531_FORCE_MODE, MT7531_FORCE_MODE);
++
+ /* Disable forwarding by default on all ports */
+ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
+ PCR_MATRIX_CLR);
--- /dev/null
+From 89017cac5f6fbaab23955818c31b3c7f1eb26f4a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Fri, 1 Mar 2024 12:43:05 +0200
+Subject: [PATCH 45/48] net: dsa: mt7530: simplify link operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The "MT7621 Giga Switch Programming Guide v0.3", "MT7531 Reference Manual
+for Development Board v1.0", and "MT7988A Wi-Fi 7 Generation Router
+Platform: Datasheet (Open Version) v0.1" documents show that these bits are
+enabled at reset:
+
+PMCR_IFG_XMIT(1) (not part of PMCR_LINK_SETTINGS_MASK)
+PMCR_MAC_MODE (not part of PMCR_LINK_SETTINGS_MASK)
+PMCR_TX_EN
+PMCR_RX_EN
+PMCR_BACKOFF_EN (not part of PMCR_LINK_SETTINGS_MASK)
+PMCR_BACKPR_EN (not part of PMCR_LINK_SETTINGS_MASK)
+PMCR_TX_FC_EN
+PMCR_RX_FC_EN
+
+These bits also don't exist on the MT7530_PMCR_P(6) register of the switch
+on the MT7988 SoC:
+
+PMCR_IFG_XMIT()
+PMCR_MAC_MODE
+PMCR_BACKOFF_EN
+PMCR_BACKPR_EN
+
+Remove the setting of the bits not part of PMCR_LINK_SETTINGS_MASK on
+phylink_mac_config as they're already set.
+
+The bit for setting the port on force mode is already done on
+mt7530_setup() and mt7531_setup_common(). So get rid of
+PMCR_FORCE_MODE_ID() which helped determine which bit to use for the switch
+model.
+
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 12 +-----------
+ drivers/net/dsa/mt7530.h | 2 --
+ 2 files changed, 1 insertion(+), 13 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2694,23 +2694,13 @@ mt753x_phylink_mac_config(struct dsa_swi
+ const struct phylink_link_state *state)
+ {
+ struct mt7530_priv *priv = ds->priv;
+- u32 mcr_cur, mcr_new;
+
+ if ((port == 5 || port == 6) && priv->info->mac_port_config)
+ priv->info->mac_port_config(ds, port, mode, state->interface);
+
+- mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
+- mcr_new = mcr_cur;
+- mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
+- mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
+- PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id);
+-
+ /* Are we connected to external phy */
+ if (port == 5 && dsa_is_user_port(ds, 5))
+- mcr_new |= PMCR_EXT_PHY;
+-
+- if (mcr_new != mcr_cur)
+- mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
++ mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
+ }
+
+ static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -324,8 +324,6 @@ 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) || ((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 | \
--- /dev/null
+From cfa7c85f92cd3814ad9748eb1ab25658c7f7cc67 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= <arinc.unal@arinc9.com>
+Date: Wed, 20 Mar 2024 23:45:30 +0300
+Subject: [PATCH 48/48] net: dsa: mt7530: fix improper frames on all 25MHz and
+ 40MHz XTAL MT7530
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The MT7530 switch after reset initialises with a core clock frequency that
+works with a 25MHz XTAL connected to it. For 40MHz XTAL, the core clock
+frequency must be set to 500MHz.
+
+The mt7530_pll_setup() function is responsible of setting the core clock
+frequency. Currently, it runs on MT7530 with 25MHz and 40MHz XTAL. This
+causes MT7530 switch with 25MHz XTAL to egress and ingress frames
+improperly.
+
+Introduce a check to run it only on MT7530 with 40MHz XTAL.
+
+The core clock frequency is set by writing to a switch PHY's register.
+Access to the PHY's register is done via the MDIO bus the switch is also
+on. Therefore, it works only when the switch makes switch PHYs listen on
+the MDIO bus the switch is on. This is controlled either by the state of
+the ESW_P1_LED_1 pin after reset deassertion or modifying bit 5 of the
+modifiable trap register.
+
+When ESW_P1_LED_1 is pulled high, PHY indirect access is used. That means
+accessing PHY registers via the PHY indirect access control register of the
+switch.
+
+When ESW_P1_LED_1 is pulled low, PHY direct access is used. That means
+accessing PHY registers via the MDIO bus the switch is on.
+
+For MT7530 switch with 40MHz XTAL on a board with ESW_P1_LED_1 pulled high,
+the core clock frequency won't be set to 500MHz, causing the switch to
+egress and ingress frames improperly.
+
+Run mt7530_pll_setup() after PHY direct access is set on the modifiable
+trap register.
+
+With these two changes, all MT7530 switches with 25MHz and 40MHz, and
+P1_LED_1 pulled high or low, will egress and ingress frames properly.
+
+Link: https://github.com/BPI-SINOVOIP/BPI-R2-bsp/blob/4a5dd143f2172ec97a2872fa29c7c4cd520f45b5/linux-mt/drivers/net/ethernet/mediatek/gsw_mt7623.c#L1039
+Fixes: b8f126a8d543 ("net-next: dsa: add dsa support for Mediatek MT7530 switch")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/20240320-for-net-mt7530-fix-25mhz-xtal-with-direct-phy-access-v1-1-d92f605f1160@arinc9.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2259,8 +2259,6 @@ mt7530_setup(struct dsa_switch *ds)
+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+ SYS_CTRL_REG_RST);
+
+- mt7530_pll_setup(priv);
+-
+ /* Lower Tx driving for TRGMII path */
+ for (i = 0; i < NUM_TRGMII_CTRL; i++)
+ mt7530_write(priv, MT7530_TRGMII_TD_ODT(i),
+@@ -2276,6 +2274,9 @@ mt7530_setup(struct dsa_switch *ds)
+ val |= MHWTRAP_MANUAL;
+ mt7530_write(priv, MT7530_MHWTRAP, val);
+
++ if ((val & HWTRAP_XTAL_MASK) == HWTRAP_XTAL_40MHZ)
++ mt7530_pll_setup(priv);
++
+ mt753x_trap_frames(priv);
+
+ /* Enable and reset MIB counters */
+++ /dev/null
-From c3552d3f85f06cf4b4818bd84c4fcc09d8d45165 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:17:19 +0100
-Subject: [PATCH 01/13] net: dsa: mt7530: make some noise if register read
- fails
-
-Simply returning the negative error value instead of the read value
-doesn't seem like a good idea. Return 0 instead and add WARN_ON_ONCE(1)
-so this kind of error will not go unnoticed.
-
-Suggested-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -224,9 +224,10 @@ mt7530_mii_read(struct mt7530_priv *priv
- /* MT7530 uses 31 as the pseudo port */
- ret = bus->write(bus, 0x1f, 0x1f, page);
- if (ret < 0) {
-+ WARN_ON_ONCE(1);
- dev_err(&bus->dev,
- "failed to read mt7530 register\n");
-- return ret;
-+ return 0;
- }
-
- lo = bus->read(bus, 0x1f, r);
+++ /dev/null
-From b896355fc4988216d4f38582d07add9252a795ae Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:17:30 +0100
-Subject: [PATCH 02/13] net: dsa: mt7530: refactor SGMII PCS creation
-
-Instead of macro templates use a dedidated function and allocated
-regmap_config when creating the regmaps for the pcs-mtk-lynxi
-instances.
-This is in preparation to switching to use unlocked regmap accessors
-and have regmap's locking API handle locking for us.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 74 +++++++++++++++++++++++++++-------------
- 1 file changed, 50 insertions(+), 24 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2968,26 +2968,56 @@ static const struct regmap_bus mt7531_re
- .reg_update_bits = mt7530_regmap_update_bits,
- };
-
--#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \
-- { \
-- .name = _name, \
-- .reg_bits = 16, \
-- .val_bits = 32, \
-- .reg_stride = 4, \
-- .reg_base = _reg_base, \
-- .max_register = 0x17c, \
-+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;
-+
-+ regmap = devm_regmap_init(priv->dev,
-+ &mt7531_regmap_bus, priv,
-+ 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;
- }
-
--static const struct regmap_config mt7531_pcs_config[] = {
-- MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)),
-- MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)),
--};
-+ if (ret && i)
-+ mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
-+
-+ return ret;
-+}
-
- static int
- mt753x_setup(struct dsa_switch *ds)
- {
- struct mt7530_priv *priv = ds->priv;
-- struct regmap *regmap;
- int i, ret;
-
- /* Initialise the PCS devices */
-@@ -3009,15 +3039,11 @@ mt753x_setup(struct dsa_switch *ds)
- if (ret && priv->irq)
- mt7530_free_irq_common(priv);
-
-- if (priv->id == ID_MT7531)
-- for (i = 0; i < 2; i++) {
-- regmap = devm_regmap_init(ds->dev,
-- &mt7531_regmap_bus, priv,
-- &mt7531_pcs_config[i]);
-- priv->ports[5 + i].sgmii_pcs =
-- mtk_pcs_lynxi_create(ds->dev, regmap,
-- MT7531_PHYA_CTRL_SIGNAL3, 0);
-- }
-+ if (priv->id == ID_MT7531) {
-+ ret = mt7531_create_sgmii(priv);
-+ if (ret && priv->irq)
-+ mt7530_free_irq_common(priv);
-+ }
-
- return ret;
- }
+++ /dev/null
-From 33396408776385f3d2f6069646169a6b5b28e3b3 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:17:40 +0100
-Subject: [PATCH 03/13] net: dsa: mt7530: use unlocked regmap accessors
-
-Instead of wrapping the locked register accessor functions, use the
-unlocked variants and add locking wrapper functions to let regmap
-handle the locking.
-
-This is a preparation towards being able to always use regmap to
-access switch registers instead of open-coded accessor functions.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 23 ++++++++++++++---------
- 1 file changed, 14 insertions(+), 9 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2941,7 +2941,7 @@ static int mt7530_regmap_read(void *cont
- {
- struct mt7530_priv *priv = context;
-
-- *val = mt7530_read(priv, reg);
-+ *val = mt7530_mii_read(priv, reg);
- return 0;
- };
-
-@@ -2949,23 +2949,25 @@ static int mt7530_regmap_write(void *con
- {
- struct mt7530_priv *priv = context;
-
-- mt7530_write(priv, reg, val);
-+ mt7530_mii_write(priv, reg, val);
- return 0;
- };
-
--static int mt7530_regmap_update_bits(void *context, unsigned int reg,
-- unsigned int mask, unsigned int val)
-+static void
-+mt7530_mdio_regmap_lock(void *mdio_lock)
- {
-- struct mt7530_priv *priv = context;
-+ mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
-+}
-
-- mt7530_rmw(priv, reg, mask, val);
-- return 0;
--};
-+static void
-+mt7530_mdio_regmap_unlock(void *mdio_lock)
-+{
-+ mutex_unlock(mdio_lock);
-+}
-
- static const struct regmap_bus mt7531_regmap_bus = {
- .reg_write = mt7530_regmap_write,
- .reg_read = mt7530_regmap_read,
-- .reg_update_bits = mt7530_regmap_update_bits,
- };
-
- static int
-@@ -2991,6 +2993,9 @@ mt7531_create_sgmii(struct mt7530_priv *
- 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,
- &mt7531_regmap_bus, priv,
+++ /dev/null
-From 743cba4345cb366248f9d375c6a9e50243dc0677 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:17:52 +0100
-Subject: [PATCH 04/13] net: dsa: mt7530: use regmap to access switch register
- space
-
-Use regmap API to access the switch register space.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 99 ++++++++++++++++++++++++----------------
- drivers/net/dsa/mt7530.h | 2 +
- 2 files changed, 62 insertions(+), 39 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -183,9 +183,9 @@ core_clear(struct mt7530_priv *priv, u32
- }
-
- static int
--mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
- {
-- struct mii_bus *bus = priv->bus;
-+ struct mii_bus *bus = context;
- u16 page, r, lo, hi;
- int ret;
-
-@@ -197,24 +197,34 @@ mt7530_mii_write(struct mt7530_priv *pri
- /* MT7530 uses 31 as the pseudo port */
- ret = bus->write(bus, 0x1f, 0x1f, page);
- if (ret < 0)
-- goto err;
-+ return ret;
-
- ret = bus->write(bus, 0x1f, r, lo);
- if (ret < 0)
-- goto err;
-+ return ret;
-
- ret = bus->write(bus, 0x1f, 0x10, hi);
--err:
-+ return ret;
-+}
-+
-+static int
-+mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+ int ret;
-+
-+ ret = regmap_write(priv->regmap, reg, val);
-+
- if (ret < 0)
-- dev_err(&bus->dev,
-+ dev_err(priv->dev,
- "failed to write mt7530 register\n");
-+
- return ret;
- }
-
--static u32
--mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
-+static int
-+mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
- {
-- struct mii_bus *bus = priv->bus;
-+ struct mii_bus *bus = context;
- u16 page, r, lo, hi;
- int ret;
-
-@@ -223,17 +233,32 @@ mt7530_mii_read(struct mt7530_priv *priv
-
- /* MT7530 uses 31 as the pseudo port */
- ret = bus->write(bus, 0x1f, 0x1f, page);
-- if (ret < 0) {
-+ 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)
-+{
-+ int ret;
-+ u32 val;
-+
-+ ret = regmap_read(priv->regmap, reg, &val);
-+ if (ret) {
- WARN_ON_ONCE(1);
-- dev_err(&bus->dev,
-+ dev_err(priv->dev,
- "failed to read mt7530 register\n");
- return 0;
- }
-
-- lo = bus->read(bus, 0x1f, r);
-- hi = bus->read(bus, 0x1f, 0x10);
--
-- return (hi << 16) | (lo & 0xffff);
-+ return val;
- }
-
- static void
-@@ -283,14 +308,10 @@ mt7530_rmw(struct mt7530_priv *priv, u32
- u32 mask, u32 set)
- {
- struct mii_bus *bus = priv->bus;
-- u32 val;
-
- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-
-- val = mt7530_mii_read(priv, reg);
-- val &= ~mask;
-- val |= set;
-- mt7530_mii_write(priv, reg, val);
-+ regmap_update_bits(priv->regmap, reg, mask, set);
-
- mutex_unlock(&bus->mdio_lock);
- }
-@@ -298,7 +319,7 @@ mt7530_rmw(struct mt7530_priv *priv, u32
- static void
- mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val)
- {
-- mt7530_rmw(priv, reg, 0, val);
-+ mt7530_rmw(priv, reg, val, val);
- }
-
- static void
-@@ -2937,22 +2958,6 @@ static const struct phylink_pcs_ops mt75
- .pcs_an_restart = mt7530_pcs_an_restart,
- };
-
--static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
--{
-- struct mt7530_priv *priv = context;
--
-- *val = mt7530_mii_read(priv, reg);
-- return 0;
--};
--
--static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
--{
-- struct mt7530_priv *priv = context;
--
-- mt7530_mii_write(priv, reg, val);
-- return 0;
--};
--
- static void
- mt7530_mdio_regmap_lock(void *mdio_lock)
- {
-@@ -2965,7 +2970,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc
- mutex_unlock(mdio_lock);
- }
-
--static const struct regmap_bus mt7531_regmap_bus = {
-+static const struct regmap_bus mt7530_regmap_bus = {
- .reg_write = mt7530_regmap_write,
- .reg_read = mt7530_regmap_read,
- };
-@@ -2998,7 +3003,7 @@ mt7531_create_sgmii(struct mt7530_priv *
- mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
-
- regmap = devm_regmap_init(priv->dev,
-- &mt7531_regmap_bus, priv,
-+ &mt7530_regmap_bus, priv->bus,
- mt7531_pcs_config[i]);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
-@@ -3163,6 +3168,7 @@ 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;
-
-@@ -3242,6 +3248,21 @@ mt7530_probe(struct mdio_device *mdiodev
- mutex_init(&priv->reg_mutex);
- dev_set_drvdata(&mdiodev->dev, priv);
-
-+ 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);
-+
- return dsa_register_switch(priv->ds);
- }
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -754,6 +754,7 @@ struct mt753x_info {
- * @dev: The device pointer
- * @ds: The pointer to the dsa core structure
- * @bus: The bus used for the device and built-in PHY
-+ * @regmap: The regmap instance representing all switch registers
- * @rstc: The pointer to reset control used by MCM
- * @core_pwr: The power supplied into the core
- * @io_pwr: The power supplied into the I/O
-@@ -774,6 +775,7 @@ struct mt7530_priv {
- struct device *dev;
- struct dsa_switch *ds;
- struct mii_bus *bus;
-+ struct regmap *regmap;
- struct reset_control *rstc;
- struct regulator *core_pwr;
- struct regulator *io_pwr;
+++ /dev/null
-From f3cf1d06e2aef644b426c23b4bb570780b1f8d47 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:18:04 +0100
-Subject: [PATCH 05/13] net: dsa: mt7530: move SGMII PCS creation to
- mt7530_probe function
-
-Move creating the SGMII PCS from mt753x_setup() to the more appropriate
-mt7530_probe() function.
-This is done also in preparation of moving all functions related to
-MDIO-connected MT753x switches to a separate module.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 13 +++++++------
- 1 file changed, 7 insertions(+), 6 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3049,12 +3049,6 @@ mt753x_setup(struct dsa_switch *ds)
- if (ret && priv->irq)
- mt7530_free_irq_common(priv);
-
-- if (priv->id == ID_MT7531) {
-- ret = mt7531_create_sgmii(priv);
-- if (ret && priv->irq)
-- mt7530_free_irq_common(priv);
-- }
--
- return ret;
- }
-
-@@ -3171,6 +3165,7 @@ 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;
-
-@@ -3263,6 +3258,12 @@ mt7530_probe(struct mdio_device *mdiodev
- 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);
- }
-
+++ /dev/null
-From e4729ae7c095c0c87794bff47ea43e35d69de986 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:18:16 +0100
-Subject: [PATCH 06/13] net: dsa: mt7530: introduce mutex helpers
-
-As the MDIO bus lock only needs to be involved if actually operating
-on an MDIO-connected switch we will need to skip locking for built-in
-switches which are accessed via MMIO.
-Create helper functions which simplify that upcoming change.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 73 ++++++++++++++++++++--------------------
- 1 file changed, 36 insertions(+), 37 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -143,31 +143,40 @@ err:
- }
-
- static void
--core_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+mt7530_mutex_lock(struct mt7530_priv *priv)
- {
-- struct mii_bus *bus = priv->bus;
-+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+}
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+static void
-+mt7530_mutex_unlock(struct mt7530_priv *priv)
-+{
-+ mutex_unlock(&priv->bus->mdio_lock);
-+}
-+
-+static void
-+core_write(struct mt7530_priv *priv, u32 reg, u32 val)
-+{
-+ mt7530_mutex_lock(priv);
-
- core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
-
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
- }
-
- static void
- core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
- {
-- struct mii_bus *bus = priv->bus;
- u32 val;
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2);
- val &= ~mask;
- val |= set;
- core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val);
-
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
- }
-
- static void
-@@ -264,13 +273,11 @@ mt7530_mii_read(struct mt7530_priv *priv
- static void
- mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
- {
-- struct mii_bus *bus = priv->bus;
--
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- mt7530_mii_write(priv, reg, val);
-
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
- }
-
- static u32
-@@ -282,14 +289,13 @@ _mt7530_unlocked_read(struct mt7530_dumm
- static u32
- _mt7530_read(struct mt7530_dummy_poll *p)
- {
-- struct mii_bus *bus = p->priv->bus;
- u32 val;
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(p->priv);
-
- val = mt7530_mii_read(p->priv, p->reg);
-
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(p->priv);
-
- return val;
- }
-@@ -307,13 +313,11 @@ static void
- mt7530_rmw(struct mt7530_priv *priv, u32 reg,
- u32 mask, u32 set)
- {
-- struct mii_bus *bus = priv->bus;
--
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- regmap_update_bits(priv->regmap, reg, mask, set);
-
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
- }
-
- static void
-@@ -645,14 +649,13 @@ static int
- mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
- int regnum)
- {
-- struct mii_bus *bus = priv->bus;
- struct mt7530_dummy_poll p;
- u32 reg, val;
- int ret;
-
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
-@@ -685,7 +688,7 @@ mt7531_ind_c45_phy_read(struct mt7530_pr
-
- ret = val & MT7531_MDIO_RW_DATA_MASK;
- out:
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
-
- return ret;
- }
-@@ -694,14 +697,13 @@ static int
- mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
- int regnum, u32 data)
- {
-- struct mii_bus *bus = priv->bus;
- struct mt7530_dummy_poll p;
- u32 val, reg;
- int ret;
-
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
-@@ -733,7 +735,7 @@ mt7531_ind_c45_phy_write(struct mt7530_p
- }
-
- out:
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
-
- return ret;
- }
-@@ -741,14 +743,13 @@ out:
- static int
- mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
- {
-- struct mii_bus *bus = priv->bus;
- struct mt7530_dummy_poll p;
- int ret;
- u32 val;
-
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
- !(val & MT7531_PHY_ACS_ST), 20, 100000);
-@@ -771,7 +772,7 @@ mt7531_ind_c22_phy_read(struct mt7530_pr
-
- ret = val & MT7531_MDIO_RW_DATA_MASK;
- out:
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
-
- return ret;
- }
-@@ -780,14 +781,13 @@ static int
- mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
- u16 data)
- {
-- struct mii_bus *bus = priv->bus;
- struct mt7530_dummy_poll p;
- int ret;
- u32 reg;
-
- INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
- !(reg & MT7531_PHY_ACS_ST), 20, 100000);
-@@ -809,7 +809,7 @@ mt7531_ind_c22_phy_write(struct mt7530_p
- }
-
- out:
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
-
- return ret;
- }
-@@ -1125,7 +1125,6 @@ static int
- mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
- {
- struct mt7530_priv *priv = ds->priv;
-- struct mii_bus *bus = priv->bus;
- int length;
- u32 val;
-
-@@ -1136,7 +1135,7 @@ mt7530_port_change_mtu(struct dsa_switch
- if (!dsa_is_cpu_port(ds, port))
- return 0;
-
-- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
-
- val = mt7530_mii_read(priv, MT7530_GMACCR);
- val &= ~MAX_RX_PKT_LEN_MASK;
-@@ -1157,7 +1156,7 @@ mt7530_port_change_mtu(struct dsa_switch
-
- mt7530_mii_write(priv, MT7530_GMACCR, val);
-
-- mutex_unlock(&bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
-
- return 0;
- }
-@@ -1958,10 +1957,10 @@ mt7530_irq_thread_fn(int irq, void *dev_
- u32 val;
- int p;
-
-- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
- val = mt7530_mii_read(priv, MT7530_SYS_INT_STS);
- mt7530_mii_write(priv, MT7530_SYS_INT_STS, val);
-- mutex_unlock(&priv->bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
-
- for (p = 0; p < MT7530_NUM_PHYS; p++) {
- if (BIT(p) & val) {
-@@ -1997,7 +1996,7 @@ mt7530_irq_bus_lock(struct irq_data *d)
- {
- struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
-
-- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ mt7530_mutex_lock(priv);
- }
-
- static void
-@@ -2006,7 +2005,7 @@ mt7530_irq_bus_sync_unlock(struct irq_da
- struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
-
- mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
-- mutex_unlock(&priv->bus->mdio_lock);
-+ mt7530_mutex_unlock(priv);
- }
-
- static struct irq_chip mt7530_irq_chip = {
+++ /dev/null
-From 0d7ae94a0c581f86939bebec0b6ccd66e640d1d8 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:18:28 +0100
-Subject: [PATCH 07/13] net: dsa: mt7530: move p5_intf_modes() function to
- mt7530.c
-
-In preparation of splitting mt7530.c into a driver for MDIO-connected
-as well as MDIO-accessed built-in switches on one hand and MMIO-accessed
-built-in switches move the p5_inft_modes() function from mt7530.h to
-mt7530.c. The function is only needed there and will trigger a compiler
-warning about a defined but unused function otherwise when including
-mt7530.h in the to-be-introduced bus-specific drivers.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 18 ++++++++++++++++++
- drivers/net/dsa/mt7530.h | 18 ------------------
- 2 files changed, 18 insertions(+), 18 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -950,6 +950,24 @@ mt7530_set_ageing_time(struct dsa_switch
- return 0;
- }
-
-+static const char *p5_intf_modes(unsigned int p5_interface)
-+{
-+ switch (p5_interface) {
-+ case P5_DISABLED:
-+ return "DISABLED";
-+ case P5_INTF_SEL_PHY_P0:
-+ return "PHY P0";
-+ case P5_INTF_SEL_PHY_P4:
-+ return "PHY P4";
-+ case P5_INTF_SEL_GMAC5:
-+ return "GMAC5";
-+ case P5_INTF_SEL_GMAC5_SGMII:
-+ return "GMAC5_SGMII";
-+ default:
-+ return "unknown";
-+ }
-+}
-+
- static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
- {
- struct mt7530_priv *priv = ds->priv;
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -689,24 +689,6 @@ enum p5_interface_select {
- P5_INTF_SEL_GMAC5_SGMII,
- };
-
--static const char *p5_intf_modes(unsigned int p5_interface)
--{
-- switch (p5_interface) {
-- case P5_DISABLED:
-- return "DISABLED";
-- case P5_INTF_SEL_PHY_P0:
-- return "PHY P0";
-- case P5_INTF_SEL_PHY_P4:
-- return "PHY P4";
-- case P5_INTF_SEL_GMAC5:
-- return "GMAC5";
-- case P5_INTF_SEL_GMAC5_SGMII:
-- return "GMAC5_SGMII";
-- default:
-- return "unknown";
-- }
--}
--
- struct mt7530_priv;
-
- struct mt753x_pcs {
+++ /dev/null
-From 4d632005c90e253c000d0db73b7cdb9d8dc2e2dd Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:18:39 +0100
-Subject: [PATCH 08/13] net: dsa: mt7530: introduce mt7530_probe_common helper
- function
-
-Move commonly used parts from mt7530_probe into new mt7530_probe_common
-helper function which will be used by both, mt7530_probe and the
-to-be-introduced mt7988_probe.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 98 ++++++++++++++++++++++------------------
- 1 file changed, 54 insertions(+), 44 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3177,44 +3177,21 @@ static const struct of_device_id mt7530_
- MODULE_DEVICE_TABLE(of, mt7530_of_match);
-
- static int
--mt7530_probe(struct mdio_device *mdiodev)
-+mt7530_probe_common(struct mt7530_priv *priv)
- {
-- static struct regmap_config *regmap_config;
-- struct mt7530_priv *priv;
-- struct device_node *dn;
-- int ret;
-+ struct device *dev = priv->dev;
-
-- dn = mdiodev->dev.of_node;
--
-- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
-- if (!priv)
-- return -ENOMEM;
--
-- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL);
-+ priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
- if (!priv->ds)
- return -ENOMEM;
-
-- priv->ds->dev = &mdiodev->dev;
-+ priv->ds->dev = dev;
- priv->ds->num_ports = MT7530_NUM_PORTS;
-
-- /* Use medatek,mcm property to distinguish hardware type that would
-- * casues a little bit differences on power-on sequence.
-- */
-- 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);
-- }
-- }
--
- /* Get the hardware identifier from the devicetree node.
- * We will need it for some of the clock and regulator setup.
- */
-- priv->info = of_device_get_match_data(&mdiodev->dev);
-+ priv->info = of_device_get_match_data(dev);
- if (!priv->info)
- return -EINVAL;
-
-@@ -3228,23 +3205,53 @@ mt7530_probe(struct mdio_device *mdiodev
- return -EINVAL;
-
- priv->id = priv->info->id;
-+ priv->dev = dev;
-+ priv->ds->priv = priv;
-+ priv->ds->ops = &mt7530_switch_ops;
-+ mutex_init(&priv->reg_mutex);
-+ dev_set_drvdata(dev, priv);
-
-- 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);
-+ return 0;
-+}
-
-- priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
-- if (IS_ERR(priv->io_pwr))
-- return PTR_ERR(priv->io_pwr);
-- }
-+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;
-
-- /* Not MCM that indicates switch works as the remote standalone
-+ 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.
- */
-- if (!priv->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)) {
-@@ -3253,12 +3260,15 @@ mt7530_probe(struct mdio_device *mdiodev
- }
- }
-
-- priv->bus = mdiodev->bus;
-- priv->dev = &mdiodev->dev;
-- priv->ds->priv = priv;
-- priv->ds->ops = &mt7530_switch_ops;
-- mutex_init(&priv->reg_mutex);
-- dev_set_drvdata(&mdiodev->dev, priv);
-+ 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);
+++ /dev/null
-From 69b838d2629e6b82bcd9e0ab3c1c03f46e5e01d3 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:18:50 +0100
-Subject: [PATCH 09/13] net: dsa: mt7530: introduce mt7530_remove_common helper
- function
-
-Move commonly used parts from mt7530_remove into new
-mt7530_remove_common helper function which will be used by both,
-mt7530_remove and the to-be-introduced mt7988_remove.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 18 ++++++++++++------
- 1 file changed, 12 insertions(+), 6 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3295,6 +3295,17 @@ mt7530_probe(struct mdio_device *mdiodev
- }
-
- static void
-+mt7530_remove_common(struct mt7530_priv *priv)
-+{
-+ if (priv->irq)
-+ mt7530_free_irq(priv);
-+
-+ dsa_unregister_switch(priv->ds);
-+
-+ mutex_destroy(&priv->reg_mutex);
-+}
-+
-+static void
- mt7530_remove(struct mdio_device *mdiodev)
- {
- struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
-@@ -3313,15 +3324,10 @@ mt7530_remove(struct mdio_device *mdiode
- dev_err(priv->dev, "Failed to disable io pwr: %d\n",
- ret);
-
-- if (priv->irq)
-- mt7530_free_irq(priv);
--
-- dsa_unregister_switch(priv->ds);
-+ mt7530_remove_common(priv);
-
- for (i = 0; i < 2; ++i)
- mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
--
-- mutex_destroy(&priv->reg_mutex);
- }
-
- static void mt7530_shutdown(struct mdio_device *mdiodev)
+++ /dev/null
-From 8eceed6dbd74067dbf4d8e39f14734f4d2f35176 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:19:13 +0100
-Subject: [PATCH 10/13] 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 | 16 +-
- 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, 301 insertions(+), 258 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
-@@ -37,10 +37,22 @@ config NET_DSA_MT7530
- tristate "MediaTek MT753x and MT7621 Ethernet switch support"
- select NET_DSA_TAG_MTK
- select MEDIATEK_GE_PHY
-+ 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 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)
- {
-@@ -2975,72 +2926,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)
- {
-@@ -3099,7 +2984,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,
-@@ -3133,8 +3018,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,
-@@ -3167,16 +3053,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;
-@@ -3213,88 +3092,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)
-@@ -3304,55 +3104,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
-@@ -814,4 +814,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 */
+++ /dev/null
-From a52cadbf76593f8fcb2f4f62cb006e3f2a22ad06 Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Mon, 3 Apr 2023 02:19:28 +0100
-Subject: [PATCH 11/13] net: dsa: mt7530: skip locking if MDIO bus isn't
- present
-
-As MT7530 and MT7531 internally use 32-bit wide registers, each access
-to any register of the switch requires several operations on the MDIO
-bus. Hence if there is congruent access, e.g. due to PCS or PHY
-polling, this can mess up and interfere with another ongoing register
-access sequence.
-
-However, the MDIO bus mutex is only relevant for MDIO-connected
-switches. Prepare switches which have there registers directly mapped
-into the SoCs register space via MMIO which do not require such
-locking. There we can simply use regmap's default locking mechanism.
-
-Hence guard mutex operations to only be performed in case of MDIO
-connected switches.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Reviewed-by: Andrew Lunn <andrew@lunn.ch>
-Signed-off-by: David S. Miller <davem@davemloft.net>
----
- drivers/net/dsa/mt7530.c | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -144,13 +144,15 @@ err:
- static void
- mt7530_mutex_lock(struct mt7530_priv *priv)
- {
-- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
-+ if (priv->bus)
-+ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
- }
-
- static void
- mt7530_mutex_unlock(struct mt7530_priv *priv)
- {
-- mutex_unlock(&priv->bus->mdio_lock);
-+ if (priv->bus)
-+ mutex_unlock(&priv->bus->mdio_lock);
- }
-
- static void
+++ /dev/null
-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
-@@ -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
-@@ -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 | \
+++ /dev/null
-From eb1dd407b4be7ca38166a38c56c8edf52c6a399f Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Sun, 16 Apr 2023 13:08:14 +0100
-Subject: [PATCH 13/13] net: dsa: mt7530: fix support for MT7531BE
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-There are two variants of the MT7531 switch IC which got different
-features (and pins) regarding port 5:
- * MT7531AE: SGMII/1000Base-X/2500Base-X SerDes PCS
- * MT7531BE: RGMII
-
-Moving the creation of the SerDes PCS from mt753x_setup to mt7530_probe
-with commit 6de285229773 ("net: dsa: mt7530: move SGMII PCS creation
-to mt7530_probe function") works fine for MT7531AE which got two
-instances of mtk-pcs-lynxi, however, MT7531BE requires mt7531_pll_setup
-to setup clocks before the single PCS on port 6 (usually used as CPU
-port) starts to work and hence the PCS creation failed on MT7531BE.
-
-Fix this by introducing a pointer to mt7531_create_sgmii function in
-struct mt7530_priv and call it again at the end of mt753x_setup like it
-was before commit 6de285229773 ("net: dsa: mt7530: move SGMII PCS
-creation to mt7530_probe function").
-
-Fixes: 6de285229773 ("net: dsa: mt7530: move SGMII PCS creation to mt7530_probe function")
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
-Acked-by: Arınç ÜNAL <arinc.unal@arinc9.com>
-Link: https://lore.kernel.org/r/ZDvlLhhqheobUvOK@makrotopia.org
-Signed-off-by: Jakub Kicinski <kuba@kernel.org>
----
- drivers/net/dsa/mt7530-mdio.c | 16 ++++++++--------
- drivers/net/dsa/mt7530.c | 6 ++++++
- drivers/net/dsa/mt7530.h | 4 ++--
- 3 files changed, 16 insertions(+), 10 deletions(-)
-
---- a/drivers/net/dsa/mt7530-mdio.c
-+++ b/drivers/net/dsa/mt7530-mdio.c
-@@ -81,14 +81,17 @@ static const struct regmap_bus mt7530_re
- };
-
- static int
--mt7531_create_sgmii(struct mt7530_priv *priv)
-+mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii)
- {
-- struct regmap_config *mt7531_pcs_config[2];
-+ struct regmap_config *mt7531_pcs_config[2] = {};
- struct phylink_pcs *pcs;
- struct regmap *regmap;
- int i, ret = 0;
-
-- for (i = 0; i < 2; i++) {
-+ /* MT7531AE has two SGMII units for port 5 and port 6
-+ * MT7531BE has only one SGMII unit for port 6
-+ */
-+ for (i = dual_sgmii ? 0 : 1; i < 2; i++) {
- mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
- sizeof(struct regmap_config),
- GFP_KERNEL);
-@@ -208,11 +211,8 @@ mt7530_probe(struct mdio_device *mdiodev
- if (IS_ERR(priv->regmap))
- return PTR_ERR(priv->regmap);
-
-- if (priv->id == ID_MT7531) {
-- ret = mt7531_create_sgmii(priv);
-- if (ret)
-- return ret;
-- }
-+ if (priv->id == ID_MT7531)
-+ priv->create_sgmii = mt7531_create_sgmii;
-
- return dsa_register_switch(priv->ds);
- }
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -3048,6 +3048,12 @@ mt753x_setup(struct dsa_switch *ds)
- if (ret && priv->irq)
- mt7530_free_irq_common(priv);
-
-+ if (priv->create_sgmii) {
-+ ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv));
-+ if (ret && priv->irq)
-+ mt7530_free_irq(priv);
-+ }
-+
- return ret;
- }
-
---- a/drivers/net/dsa/mt7530.h
-+++ b/drivers/net/dsa/mt7530.h
-@@ -748,10 +748,10 @@ struct mt753x_info {
- * registers
- * @p6_interface Holding the current port 6 interface
- * @p5_intf_sel: Holding the current port 5 interface select
-- *
- * @irq: IRQ number of the switch
- * @irq_domain: IRQ domain of the switch irq_chip
- * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
-+ * @create_sgmii: Pointer to function creating SGMII PCS instance(s)
- */
- struct mt7530_priv {
- struct device *dev;
-@@ -770,7 +770,6 @@ struct mt7530_priv {
- unsigned int p5_intf_sel;
- u8 mirror_rx;
- u8 mirror_tx;
--
- struct mt7530_port ports[MT7530_NUM_PORTS];
- struct mt753x_pcs pcs[MT7530_NUM_PORTS];
- /* protect among processes for registers access*/
-@@ -778,6 +777,7 @@ struct mt7530_priv {
- int irq;
- struct irq_domain *irq_domain;
- u32 irq_enable;
-+ int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii);
- };
-
- struct mt7530_hw_vlan_entry {
+++ /dev/null
-From 3fb8841513c4ec3a2e5d366df86230c45f239a57 Mon Sep 17 00:00:00 2001
-From: Alexander Couzens <lynxis@fe80.eu>
-Date: Sat, 13 Aug 2022 13:08:22 +0200
-Subject: [PATCH 03/10] net: mt7531: ensure all MACs are powered down before
- reset
-
-The datasheet [1] explicit describes it as requirement for a reset.
-
-[1] MT7531 Reference Manual for Development Board rev 1.0, page 735
-
-Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
----
- drivers/net/dsa/mt7530.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2252,6 +2252,10 @@ mt7530_setup(struct dsa_switch *ds)
- return -ENODEV;
- }
-
-+ /* all MACs must be forced link-down before sw reset */
-+ for (i = 0; i < MT7530_NUM_PORTS; i++)
-+ mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK);
-+
- /* Reset the switch through internal reset */
- mt7530_write(priv, MT7530_SYS_CTRL,
- SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
+++ /dev/null
-From 1d81e51d6d79d9098013b2e8cdd677bae998c5d8 Mon Sep 17 00:00:00 2001
-From: David Bauer <mail@david-bauer.net>
-Date: Fri, 28 Apr 2023 02:22:59 +0200
-Subject: [PATCH 1/2] mt7530: register OF node for internal MDIO bus
-
-The MT753x switches provide a switch-internal MDIO bus for the embedded
-PHYs.
-
-Register a OF sub-node on the switch OF-node for this internal MDIO bus.
-This allows to configure the embedded PHYs using device-tree.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
----
- drivers/net/dsa/mt7530.c | 7 ++++++-
- 1 file changed, 6 insertions(+), 1 deletion(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2142,10 +2142,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr
- {
- struct dsa_switch *ds = priv->ds;
- struct device *dev = priv->dev;
-+ struct device_node *np, *mnp;
- struct mii_bus *bus;
- static int idx;
- int ret;
-
-+ np = priv->dev->of_node;
-+
- bus = devm_mdiobus_alloc(dev);
- if (!bus)
- return -ENOMEM;
-@@ -2162,7 +2165,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr
- if (priv->irq)
- mt7530_setup_mdio_irq(priv);
-
-- ret = devm_mdiobus_register(dev, bus);
-+ mnp = of_get_child_by_name(np, "mdio");
-+ ret = devm_of_mdiobus_register(dev, bus, mnp);
-+ of_node_put(mnp);
- if (ret) {
- dev_err(dev, "failed to register MDIO bus: %d\n", ret);
- if (priv->irq)
+++ /dev/null
-From a444877c10a665cd8a869e6d37facdb89fd95f79 Mon Sep 17 00:00:00 2001
-Message-ID: <a444877c10a665cd8a869e6d37facdb89fd95f79.1706070008.git.daniel@makrotopia.org>
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Wed, 24 Jan 2024 04:17:11 +0000
-Subject: [PATCH net] net: dsa: mt7530: fix 10M/100M speed on MT7988 switch
-To: Arınç ÜNAL <arinc.unal@arinc9.com>,
- Daniel Golle <daniel@makrotopia.org>,
- DENG Qingfang <dqfext@gmail.com>,
- Sean Wang <sean.wang@mediatek.com>,
- Andrew Lunn <andrew@lunn.ch>,
- Florian Fainelli <f.fainelli@gmail.com>,
- Vladimir Oltean <olteanv@gmail.com>,
- David S. Miller <davem@davemloft.net>,
- Eric Dumazet <edumazet@google.com>,
- Jakub Kicinski <kuba@kernel.org>,
- Paolo Abeni <pabeni@redhat.com>,
- Matthias Brugger <matthias.bgg@gmail.com>,
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>,
- netdev@vger.kernel.org,
- linux-kernel@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org,
- linux-mediatek@lists.infradead.org
-
-Setup PMCR port register for actual speed and duplex on internally
-connected PHYs of the MT7988 built-in switch. This fixes links with
-speeds other than 1000M.
-
-Fixes: ("110c18bfed414 net: dsa: mt7530: introduce driver for MT7988 built-in switch")
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/net/dsa/mt7530.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
---- a/drivers/net/dsa/mt7530.c
-+++ b/drivers/net/dsa/mt7530.c
-@@ -2849,8 +2849,7 @@ 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_INTERNAL ||
-- interface == PHY_INTERFACE_MODE_TRGMII ||
-+ if (interface == PHY_INTERFACE_MODE_TRGMII ||
- (phy_interface_mode_is_8023z(interface))) {
- speed = SPEED_1000;
- duplex = DUPLEX_FULL;