--- /dev/null
+From f13b2b33c7674fa0988dfaa9adb95d7d912b489f Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Wed, 10 Apr 2024 20:42:38 +0100
+Subject: [PATCH 1/2] net: dsa: introduce dsa_phylink_to_port()
+
+We convert from a phylink_config struct to a dsa_port struct in many
+places, let's provide a helper for this.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/E1rudqA-006K9B-85@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ include/net/dsa.h | 6 ++++++
+ net/dsa/port.c | 12 ++++++------
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -337,6 +337,12 @@ struct dsa_port {
+ struct list_head vlans;
+ };
+
++static inline struct dsa_port *
++dsa_phylink_to_port(struct phylink_config *config)
++{
++ return container_of(config, struct dsa_port, pl_config);
++}
++
+ /* TODO: ideally DSA ports would have a single dp->link_dp member,
+ * and no dst->rtable nor this struct dsa_link would be needed,
+ * but this would require some more complex tree walking,
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -1552,7 +1552,7 @@ static void dsa_port_phylink_validate(st
+ unsigned long *supported,
+ struct phylink_link_state *state)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+
+ if (!ds->ops->phylink_validate) {
+@@ -1567,7 +1567,7 @@ static void dsa_port_phylink_validate(st
+ static void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config,
+ struct phylink_link_state *state)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+ int err;
+
+@@ -1589,7 +1589,7 @@ static struct phylink_pcs *
+ dsa_port_phylink_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
+ struct dsa_switch *ds = dp->ds;
+
+@@ -1603,7 +1603,7 @@ static void dsa_port_phylink_mac_config(
+ unsigned int mode,
+ const struct phylink_link_state *state)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+
+ if (!ds->ops->phylink_mac_config)
+@@ -1614,7 +1614,7 @@ static void dsa_port_phylink_mac_config(
+
+ static void dsa_port_phylink_mac_an_restart(struct phylink_config *config)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+
+ if (!ds->ops->phylink_mac_an_restart)
+@@ -1627,7 +1627,7 @@ static void dsa_port_phylink_mac_link_do
+ unsigned int mode,
+ phy_interface_t interface)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct phy_device *phydev = NULL;
+ struct dsa_switch *ds = dp->ds;
+
+@@ -1650,7 +1650,7 @@ static void dsa_port_phylink_mac_link_up
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+
+ if (!ds->ops->phylink_mac_link_up) {
--- /dev/null
+From c22d8240fcd73a1c3ec8dcb055bd583fb970c375 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Wed, 10 Apr 2024 20:42:43 +0100
+Subject: [PATCH 2/2] net: dsa: allow DSA switch drivers to provide their own
+ phylink mac ops
+
+Rather than having a shim for each and every phylink MAC operation,
+allow DSA switch drivers to provide their own ops structure. When a
+DSA driver provides the phylink MAC operations, the shimmed ops must
+not be provided, so fail an attempt to register a switch with both
+the phylink_mac_ops in struct dsa_switch and the phylink_mac_*
+operations populated in dsa_switch_ops populated.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://lore.kernel.org/r/E1rudqF-006K9H-Cc@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ include/net/dsa.h | 5 +++++
+ net/dsa/dsa.c | 11 +++++++++++
+ net/dsa/port.c | 26 ++++++++++++++++++++------
+ 3 files changed, 36 insertions(+), 6 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -468,6 +468,11 @@ struct dsa_switch {
+ const struct dsa_switch_ops *ops;
+
+ /*
++ * Allow a DSA switch driver to override the phylink MAC ops
++ */
++ const struct phylink_mac_ops *phylink_mac_ops;
++
++ /*
+ * Slave mii_bus and devices for the individual ports.
+ */
+ u32 phys_mii_mask;
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -1675,6 +1675,7 @@ static const struct phylink_mac_ops dsa_
+
+ int dsa_port_phylink_create(struct dsa_port *dp)
+ {
++ const struct phylink_mac_ops *mac_ops;
+ struct dsa_switch *ds = dp->ds;
+ phy_interface_t mode;
+ struct phylink *pl;
+@@ -1694,8 +1695,12 @@ int dsa_port_phylink_create(struct dsa_p
+ if (ds->ops->phylink_get_caps)
+ ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config);
+
+- pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
+- mode, &dsa_port_phylink_mac_ops);
++ mac_ops = &dsa_port_phylink_mac_ops;
++ if (ds->phylink_mac_ops)
++ mac_ops = ds->phylink_mac_ops;
++
++ pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode,
++ mac_ops);
+ if (IS_ERR(pl)) {
+ pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));
+ return PTR_ERR(pl);
+@@ -1961,12 +1966,23 @@ static void dsa_shared_port_validate_of(
+ dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
+ }
+
++static void dsa_shared_port_link_down(struct dsa_port *dp)
++{
++ struct dsa_switch *ds = dp->ds;
++
++ if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down)
++ ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED,
++ PHY_INTERFACE_MODE_NA);
++ else if (ds->ops->phylink_mac_link_down)
++ ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED,
++ PHY_INTERFACE_MODE_NA);
++}
++
+ int dsa_shared_port_link_register_of(struct dsa_port *dp)
+ {
+ struct dsa_switch *ds = dp->ds;
+ bool missing_link_description;
+ bool missing_phy_mode;
+- int port = dp->index;
+
+ dsa_shared_port_validate_of(dp, &missing_phy_mode,
+ &missing_link_description);
+@@ -1982,9 +1998,7 @@ int dsa_shared_port_link_register_of(str
+ "Skipping phylink registration for %s port %d\n",
+ dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
+ } else {
+- if (ds->ops->phylink_mac_link_down)
+- ds->ops->phylink_mac_link_down(ds, port,
+- MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
++ dsa_shared_port_link_down(dp);
+
+ return dsa_shared_port_phylink_register(dp);
+ }
+--- a/net/dsa/dsa2.c
++++ b/net/dsa/dsa2.c
+@@ -1736,6 +1736,15 @@ static int dsa_switch_probe(struct dsa_s
+ if (!ds->num_ports)
+ return -EINVAL;
+
++ if (ds->phylink_mac_ops) {
++ if (ds->ops->phylink_mac_select_pcs ||
++ ds->ops->phylink_mac_config ||
++ ds->ops->phylink_mac_link_down ||
++ ds->ops->phylink_mac_link_up ||
++ ds->ops->adjust_link)
++ return -EINVAL;
++ }
++
+ if (np) {
+ err = dsa_switch_parse_of(ds, np);
+ if (err)
--- /dev/null
+From 5754b3bdcd872aa229881b8f07f84a8404c7d72a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 12 Apr 2024 16:15:34 +0100
+Subject: [PATCH 1/5] net: dsa: mt7530: provide own phylink MAC operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Convert mt753x to provide its own phylink MAC operations, thus avoiding
+the shim layer in DSA's port.c
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Tested-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/E1rvIco-006bQu-Fq@rmk-PC.armlinux.org.uk
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 46 +++++++++++++++++++++++++---------------
+ 1 file changed, 29 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2841,28 +2841,34 @@ mt7531_mac_config(struct dsa_switch *ds,
+ }
+
+ static struct phylink_pcs *
+-mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
++mt753x_phylink_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct mt7530_priv *priv = dp->ds->priv;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_TRGMII:
+- return &priv->pcs[port].pcs;
++ return &priv->pcs[dp->index].pcs;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+- return priv->ports[port].sgmii_pcs;
++ return priv->ports[dp->index].sgmii_pcs;
+ default:
+ return NULL;
+ }
+ }
+
+ static void
+-mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
++mt753x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct dsa_switch *ds = dp->ds;
++ struct mt7530_priv *priv;
++ int port = dp->index;
++
++ priv = ds->priv;
+
+ if ((port == 5 || port == 6) && priv->info->mac_port_config)
+ priv->info->mac_port_config(ds, port, mode, state->interface);
+@@ -2872,23 +2878,25 @@ mt753x_phylink_mac_config(struct dsa_swi
+ mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
+ }
+
+-static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
++static void mt753x_phylink_mac_link_down(struct phylink_config *config,
+ unsigned int mode,
+ phy_interface_t interface)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct mt7530_priv *priv = dp->ds->priv;
+
+- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
++ mt7530_clear(priv, MT7530_PMCR_P(dp->index), PMCR_LINK_SETTINGS_MASK);
+ }
+
+-static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
++static void mt753x_phylink_mac_link_up(struct phylink_config *config,
++ struct phy_device *phydev,
+ unsigned int mode,
+ phy_interface_t interface,
+- struct phy_device *phydev,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct mt7530_priv *priv = dp->ds->priv;
+ u32 mcr;
+
+ mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
+@@ -2923,7 +2931,7 @@ static void mt753x_phylink_mac_link_up(s
+ }
+ }
+
+- mt7530_set(priv, MT7530_PMCR_P(port), mcr);
++ mt7530_set(priv, MT7530_PMCR_P(dp->index), mcr);
+ }
+
+ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
+@@ -3148,16 +3156,19 @@ const struct dsa_switch_ops mt7530_switc
+ .port_mirror_add = mt753x_port_mirror_add,
+ .port_mirror_del = mt753x_port_mirror_del,
+ .phylink_get_caps = mt753x_phylink_get_caps,
+- .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs,
+- .phylink_mac_config = mt753x_phylink_mac_config,
+- .phylink_mac_link_down = mt753x_phylink_mac_link_down,
+- .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);
+
++static const struct phylink_mac_ops mt753x_phylink_mac_ops = {
++ .mac_select_pcs = mt753x_phylink_mac_select_pcs,
++ .mac_config = mt753x_phylink_mac_config,
++ .mac_link_down = mt753x_phylink_mac_link_down,
++ .mac_link_up = mt753x_phylink_mac_link_up,
++};
++
+ const struct mt753x_info mt753x_table[] = {
+ [ID_MT7621] = {
+ .id = ID_MT7621,
+@@ -3227,6 +3238,7 @@ mt7530_probe_common(struct mt7530_priv *
+ priv->dev = dev;
+ priv->ds->priv = priv;
+ priv->ds->ops = &mt7530_switch_ops;
++ priv->ds->phylink_mac_ops = &mt753x_phylink_mac_ops;
+ mutex_init(&priv->reg_mutex);
+ dev_set_drvdata(dev, priv);
+
--- /dev/null
+From d4097ddef078a113643a6dcde01e99741f852adb 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, 13 Apr 2024 16:01:39 +0300
+Subject: [PATCH 2/5] net: dsa: mt7530: fix mirroring frames received on local
+ port
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This switch intellectual property provides a bit on the ARL global control
+register which controls allowing mirroring frames which are received on the
+local port (monitor port). This bit is unset after reset.
+
+This ability must be enabled to fully support the port mirroring feature on
+this switch intellectual property.
+
+Therefore, this patch fixes the traffic not being reflected on a port,
+which would be configured like below:
+
+ tc qdisc add dev swp0 clsact
+
+ tc filter add dev swp0 ingress matchall skip_sw \
+ action mirred egress mirror dev swp0
+
+As a side note, this configuration provides the hairpinning feature for a
+single port.
+
+Fixes: 37feab6076aa ("net: dsa: mt7530: add support for port mirroring")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 6 ++++++
+ drivers/net/dsa/mt7530.h | 4 ++++
+ 2 files changed, 10 insertions(+)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2471,6 +2471,9 @@ mt7530_setup(struct dsa_switch *ds)
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ }
+
++ /* Allow mirroring frames received on the local port (monitor port). */
++ mt7530_set(priv, MT753X_AGC, LOCAL_EN);
++
+ /* Setup VLAN ID 0 for VLAN-unaware bridges */
+ ret = mt7530_setup_vlan0(priv);
+ if (ret)
+@@ -2582,6 +2585,9 @@ mt7531_setup_common(struct dsa_switch *d
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ }
+
++ /* Allow mirroring frames received on the local port (monitor port). */
++ mt7530_set(priv, MT753X_AGC, LOCAL_EN);
++
+ /* Flush the FDB table */
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
+ if (ret < 0)
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -32,6 +32,10 @@ enum mt753x_id {
+ #define SYSC_REG_RSTCTRL 0x34
+ #define RESET_MCM BIT(2)
+
++/* Register for ARL global control */
++#define MT753X_AGC 0xc
++#define LOCAL_EN BIT(7)
++
+ /* Registers to mac forward control for unknown frames */
+ #define MT7530_MFC 0x10
+ #define BC_FFP(x) (((x) & 0xff) << 24)
--- /dev/null
+From 019a17a5e76940ea86114838d1d638d4dc8d3750 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, 13 Apr 2024 16:01:40 +0300
+Subject: [PATCH 3/5] net: dsa: mt7530: fix port mirroring for MT7988 SoC
+ switch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version)
+v0.1" document shows bits 16 to 18 as the MIRROR_PORT field of the CPU
+forward control register. Currently, the MT7530 DSA subdriver configures
+bits 0 to 2 of the CPU forward control register which breaks the port
+mirroring feature for the MT7988 SoC switch.
+
+Fix this by using the MT7531_MIRROR_PORT_GET() and MT7531_MIRROR_PORT_SET()
+macros which utilise the correct bits.
+
+Fixes: 110c18bfed41 ("net: dsa: mt7530: introduce driver for MT7988 built-in switch")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1876,14 +1876,16 @@ mt7530_port_vlan_del(struct dsa_switch *
+
+ static int mt753x_mirror_port_get(unsigned int id, u32 val)
+ {
+- return (id == ID_MT7531) ? MT7531_MIRROR_PORT_GET(val) :
+- MIRROR_PORT(val);
++ return (id == ID_MT7531 || id == ID_MT7988) ?
++ MT7531_MIRROR_PORT_GET(val) :
++ MIRROR_PORT(val);
+ }
+
+ static int mt753x_mirror_port_set(unsigned int id, u32 val)
+ {
+- return (id == ID_MT7531) ? MT7531_MIRROR_PORT_SET(val) :
+- MIRROR_PORT(val);
++ return (id == ID_MT7531 || id == ID_MT7988) ?
++ MT7531_MIRROR_PORT_SET(val) :
++ MIRROR_PORT(val);
+ }
+
+ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
--- /dev/null
+From 5053a6cf1d50d785078562470d2a63695a9f3bf2 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, 18 Apr 2024 08:35:30 +0300
+Subject: [PATCH 4/5] net: dsa: mt7530-mdio: read PHY address of switch from
+ device tree
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Read the PHY address the switch listens on from the reg property of the
+switch node on the device tree. This change brings support for MT7530
+switches on boards with such bootstrapping configuration where the switch
+listens on a different PHY address than the hardcoded PHY address on the
+driver, 31.
+
+As described on the "MT7621 Programming Guide v0.4" document, the MT7530
+switch and its PHYs can be configured to listen on the range of 7-12,
+15-20, 23-28, and 31 and 0-4 PHY addresses.
+
+There are operations where the switch PHY registers are used. For the PHY
+address of the control PHY, transform the MT753X_CTRL_PHY_ADDR constant
+into a macro and use it. The PHY address for the control PHY is 0 when the
+switch listens on 31. In any other case, it is one greater than the PHY
+address the switch listens on.
+
+Reviewed-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530-mdio.c | 28 +++++++++++++-------------
+ drivers/net/dsa/mt7530.c | 37 +++++++++++++++++++++++------------
+ drivers/net/dsa/mt7530.h | 4 +++-
+ 3 files changed, 41 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/dsa/mt7530-mdio.c
++++ b/drivers/net/dsa/mt7530-mdio.c
+@@ -18,7 +18,8 @@
+ static int
+ mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
+ {
+- struct mii_bus *bus = context;
++ struct mt7530_priv *priv = context;
++ struct mii_bus *bus = priv->bus;
+ u16 page, r, lo, hi;
+ int ret;
+
+@@ -27,36 +28,35 @@ mt7530_regmap_write(void *context, unsig
+ lo = val & 0xffff;
+ hi = val >> 16;
+
+- /* MT7530 uses 31 as the pseudo port */
+- ret = bus->write(bus, 0x1f, 0x1f, page);
++ ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
+ if (ret < 0)
+ return ret;
+
+- ret = bus->write(bus, 0x1f, r, lo);
++ ret = bus->write(bus, priv->mdiodev->addr, r, lo);
+ if (ret < 0)
+ return ret;
+
+- ret = bus->write(bus, 0x1f, 0x10, hi);
++ ret = bus->write(bus, priv->mdiodev->addr, 0x10, hi);
+ return ret;
+ }
+
+ static int
+ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
+ {
+- struct mii_bus *bus = context;
++ struct mt7530_priv *priv = context;
++ struct mii_bus *bus = priv->bus;
+ 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);
++ ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
+ if (ret < 0)
+ return ret;
+
+- lo = bus->read(bus, 0x1f, r);
+- hi = bus->read(bus, 0x1f, 0x10);
++ lo = bus->read(bus, priv->mdiodev->addr, r);
++ hi = bus->read(bus, priv->mdiodev->addr, 0x10);
+
+ *val = (hi << 16) | (lo & 0xffff);
+
+@@ -107,8 +107,7 @@ mt7531_create_sgmii(struct mt7530_priv *
+ 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,
++ regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
+ mt7531_pcs_config[i]);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+@@ -153,6 +152,7 @@ mt7530_probe(struct mdio_device *mdiodev
+
+ priv->bus = mdiodev->bus;
+ priv->dev = &mdiodev->dev;
++ priv->mdiodev = mdiodev;
+
+ ret = mt7530_probe_common(priv);
+ if (ret)
+@@ -203,8 +203,8 @@ mt7530_probe(struct mdio_device *mdiodev
+ 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);
++ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
++ regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -86,22 +86,26 @@ core_read_mmd_indirect(struct mt7530_pri
+ int value, ret;
+
+ /* Write the desired MMD Devad */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+- ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, prtad);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
+ /* Read the content of the MMD's selected register */
+- value = bus->read(bus, 0, MII_MMD_DATA);
++ value = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA);
+
+ return value;
+ err:
+@@ -118,22 +122,26 @@ core_write_mmd_indirect(struct mt7530_pr
+ int ret;
+
+ /* Write the desired MMD Devad */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+- ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, prtad);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
+ /* Write the data into MMD's selected register */
+- ret = bus->write(bus, 0, MII_MMD_DATA, data);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, data);
+ err:
+ if (ret < 0)
+ dev_err(&bus->dev,
+@@ -2670,16 +2678,19 @@ mt7531_setup(struct dsa_switch *ds)
+ * phy_[read,write]_mmd_indirect is called, we provide our own
+ * mt7531_ind_mmd_phy_[read,write] to complete this function.
+ */
+- val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR,
++ val = mt7531_ind_c45_phy_read(priv,
++ MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+ MDIO_MMD_VEND2, CORE_PLL_GROUP4);
+ val |= MT7531_RG_SYSPLL_DMY2 | MT7531_PHY_PLL_BYPASS_MODE;
+ val &= ~MT7531_PHY_PLL_OFF;
+- mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
+- CORE_PLL_GROUP4, val);
++ mt7531_ind_c45_phy_write(priv,
++ MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MDIO_MMD_VEND2, CORE_PLL_GROUP4, val);
+
+ /* Disable EEE advertisement on the switch PHYs. */
+- for (i = MT753X_CTRL_PHY_ADDR;
+- i < MT753X_CTRL_PHY_ADDR + MT7530_NUM_PHYS; i++) {
++ for (i = MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr);
++ i < MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr) + MT7530_NUM_PHYS;
++ i++) {
+ mt7531_ind_c45_phy_write(priv, i, MDIO_MMD_AN, MDIO_AN_EEE_ADV,
+ 0);
+ }
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -629,7 +629,7 @@ enum mt7531_clk_skew {
+ #define MT7531_PHY_PLL_OFF BIT(5)
+ #define MT7531_PHY_PLL_BYPASS_MODE BIT(4)
+
+-#define MT753X_CTRL_PHY_ADDR 0
++#define MT753X_CTRL_PHY_ADDR(addr) ((addr + 1) & 0x1f)
+
+ #define CORE_PLL_GROUP5 0x404
+ #define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff)
+@@ -771,6 +771,7 @@ struct mt753x_info {
+ * @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
++ * @mdiodev: The pointer to the MDIO device structure
+ */
+ struct mt7530_priv {
+ struct device *dev;
+@@ -797,6 +798,7 @@ struct mt7530_priv {
+ u32 irq_enable;
+ int (*create_sgmii)(struct mt7530_priv *priv);
+ u8 active_cpu_ports;
++ struct mdio_device *mdiodev;
+ };
+
+ struct mt7530_hw_vlan_entry {
--- /dev/null
+From 9764a08b3d260f4e7799d34bbfe64463db940d74 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, 18 Apr 2024 08:35:31 +0300
+Subject: [PATCH 5/5] net: dsa: mt7530: simplify core operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The core_rmw() function calls core_read_mmd_indirect() to read the
+requested register, and then calls core_write_mmd_indirect() to write the
+requested value to the register. Because Clause 22 is used to access Clause
+45 registers, some operations on core_write_mmd_indirect() are
+unnecessarily run. Get rid of core_read_mmd_indirect() and
+core_write_mmd_indirect(), and run only the necessary operations on
+core_write() and core_rmw().
+
+Reviewed-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 108 ++++++++++++++++-----------------------
+ 1 file changed, 43 insertions(+), 65 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -74,116 +74,94 @@ static const struct mt7530_mib_desc mt75
+ MIB_DESC(1, 0xb8, "RxArlDrop"),
+ };
+
+-/* Since phy_device has not yet been created and
+- * phy_{read,write}_mmd_indirect is not available, we provide our own
+- * core_{read,write}_mmd_indirect with core_{clear,write,set} wrappers
+- * to complete this function.
+- */
+-static int
+-core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
++static void
++mt7530_mutex_lock(struct mt7530_priv *priv)
++{
++ if (priv->bus)
++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++}
++
++static void
++mt7530_mutex_unlock(struct mt7530_priv *priv)
++{
++ if (priv->bus)
++ mutex_unlock(&priv->bus->mdio_lock);
++}
++
++static void
++core_write(struct mt7530_priv *priv, u32 reg, u32 val)
+ {
+ struct mii_bus *bus = priv->bus;
+- int value, ret;
++ int ret;
++
++ mt7530_mutex_lock(priv);
+
+ /* Write the desired MMD Devad */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad);
++ MII_MMD_CTRL, MDIO_MMD_VEND2);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA, prtad);
++ MII_MMD_DATA, reg);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
++ MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
+- /* Read the content of the MMD's selected register */
+- value = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA);
+-
+- return value;
++ /* Write the data into MMD's selected register */
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, val);
+ err:
+- dev_err(&bus->dev, "failed to read mmd register\n");
++ if (ret < 0)
++ dev_err(&bus->dev, "failed to write mmd register\n");
+
+- return ret;
++ mt7530_mutex_unlock(priv);
+ }
+
+-static int
+-core_write_mmd_indirect(struct mt7530_priv *priv, int prtad,
+- int devad, u32 data)
++static void
++core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
+ {
+ struct mii_bus *bus = priv->bus;
++ u32 val;
+ int ret;
+
++ mt7530_mutex_lock(priv);
++
+ /* Write the desired MMD Devad */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad);
++ MII_MMD_CTRL, MDIO_MMD_VEND2);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA, prtad);
++ MII_MMD_DATA, reg);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
++ MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
++ /* Read the content of the MMD's selected register */
++ val = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA);
++ val &= ~mask;
++ val |= set;
+ /* Write the data into MMD's selected register */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA, data);
++ MII_MMD_DATA, val);
+ err:
+ if (ret < 0)
+- dev_err(&bus->dev,
+- "failed to write mmd register\n");
+- return ret;
+-}
+-
+-static void
+-mt7530_mutex_lock(struct mt7530_priv *priv)
+-{
+- if (priv->bus)
+- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+-}
+-
+-static void
+-mt7530_mutex_unlock(struct mt7530_priv *priv)
+-{
+- if (priv->bus)
+- 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);
+-
+- mt7530_mutex_unlock(priv);
+-}
+-
+-static void
+-core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
+-{
+- u32 val;
+-
+- 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);
++ dev_err(&bus->dev, "failed to write mmd register\n");
+
+ mt7530_mutex_unlock(priv);
+ }
--- /dev/null
+From f13b2b33c7674fa0988dfaa9adb95d7d912b489f Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Wed, 10 Apr 2024 20:42:38 +0100
+Subject: [PATCH 1/2] net: dsa: introduce dsa_phylink_to_port()
+
+We convert from a phylink_config struct to a dsa_port struct in many
+places, let's provide a helper for this.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Link: https://lore.kernel.org/r/E1rudqA-006K9B-85@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ include/net/dsa.h | 6 ++++++
+ net/dsa/port.c | 12 ++++++------
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -327,6 +327,12 @@ struct dsa_port {
+ };
+ };
+
++static inline struct dsa_port *
++dsa_phylink_to_port(struct phylink_config *config)
++{
++ return container_of(config, struct dsa_port, pl_config);
++}
++
+ /* TODO: ideally DSA ports would have a single dp->link_dp member,
+ * and no dst->rtable nor this struct dsa_link would be needed,
+ * but this would require some more complex tree walking,
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -1572,7 +1572,7 @@ static struct phylink_pcs *
+ dsa_port_phylink_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP);
+ struct dsa_switch *ds = dp->ds;
+
+@@ -1586,7 +1586,7 @@ static int dsa_port_phylink_mac_prepare(
+ unsigned int mode,
+ phy_interface_t interface)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+ int err = 0;
+
+@@ -1601,7 +1601,7 @@ static void dsa_port_phylink_mac_config(
+ unsigned int mode,
+ const struct phylink_link_state *state)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+
+ if (!ds->ops->phylink_mac_config)
+@@ -1614,7 +1614,7 @@ static int dsa_port_phylink_mac_finish(s
+ unsigned int mode,
+ phy_interface_t interface)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+ int err = 0;
+
+@@ -1629,7 +1629,7 @@ static void dsa_port_phylink_mac_link_do
+ unsigned int mode,
+ phy_interface_t interface)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct phy_device *phydev = NULL;
+ struct dsa_switch *ds = dp->ds;
+
+@@ -1652,7 +1652,7 @@ static void dsa_port_phylink_mac_link_up
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+ {
+- struct dsa_port *dp = container_of(config, struct dsa_port, pl_config);
++ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct dsa_switch *ds = dp->ds;
+
+ if (!ds->ops->phylink_mac_link_up) {
--- /dev/null
+From c22d8240fcd73a1c3ec8dcb055bd583fb970c375 Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Wed, 10 Apr 2024 20:42:43 +0100
+Subject: [PATCH 2/2] net: dsa: allow DSA switch drivers to provide their own
+ phylink mac ops
+
+Rather than having a shim for each and every phylink MAC operation,
+allow DSA switch drivers to provide their own ops structure. When a
+DSA driver provides the phylink MAC operations, the shimmed ops must
+not be provided, so fail an attempt to register a switch with both
+the phylink_mac_ops in struct dsa_switch and the phylink_mac_*
+operations populated in dsa_switch_ops populated.
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Link: https://lore.kernel.org/r/E1rudqF-006K9H-Cc@rmk-PC.armlinux.org.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+---
+ include/net/dsa.h | 5 +++++
+ net/dsa/dsa.c | 11 +++++++++++
+ net/dsa/port.c | 26 ++++++++++++++++++++------
+ 3 files changed, 36 insertions(+), 6 deletions(-)
+
+--- a/include/net/dsa.h
++++ b/include/net/dsa.h
+@@ -458,6 +458,11 @@ struct dsa_switch {
+ const struct dsa_switch_ops *ops;
+
+ /*
++ * Allow a DSA switch driver to override the phylink MAC ops
++ */
++ const struct phylink_mac_ops *phylink_mac_ops;
++
++ /*
+ * Slave mii_bus and devices for the individual ports.
+ */
+ u32 phys_mii_mask;
+--- a/net/dsa/dsa.c
++++ b/net/dsa/dsa.c
+@@ -1510,6 +1510,17 @@ static int dsa_switch_probe(struct dsa_s
+ if (!ds->num_ports)
+ return -EINVAL;
+
++ if (ds->phylink_mac_ops) {
++ if (ds->ops->phylink_mac_select_pcs ||
++ ds->ops->phylink_mac_prepare ||
++ ds->ops->phylink_mac_config ||
++ ds->ops->phylink_mac_finish ||
++ ds->ops->phylink_mac_link_down ||
++ ds->ops->phylink_mac_link_up ||
++ ds->ops->adjust_link)
++ return -EINVAL;
++ }
++
+ if (np) {
+ err = dsa_switch_parse_of(ds, np);
+ if (err)
+--- a/net/dsa/port.c
++++ b/net/dsa/port.c
+@@ -1677,6 +1677,7 @@ static const struct phylink_mac_ops dsa_
+
+ int dsa_port_phylink_create(struct dsa_port *dp)
+ {
++ const struct phylink_mac_ops *mac_ops;
+ struct dsa_switch *ds = dp->ds;
+ phy_interface_t mode;
+ struct phylink *pl;
+@@ -1700,8 +1701,12 @@ int dsa_port_phylink_create(struct dsa_p
+ }
+ }
+
+- pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
+- mode, &dsa_port_phylink_mac_ops);
++ mac_ops = &dsa_port_phylink_mac_ops;
++ if (ds->phylink_mac_ops)
++ mac_ops = ds->phylink_mac_ops;
++
++ pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), mode,
++ mac_ops);
+ if (IS_ERR(pl)) {
+ pr_err("error creating PHYLINK: %ld\n", PTR_ERR(pl));
+ return PTR_ERR(pl);
+@@ -1967,12 +1972,23 @@ static void dsa_shared_port_validate_of(
+ dn, dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
+ }
+
++static void dsa_shared_port_link_down(struct dsa_port *dp)
++{
++ struct dsa_switch *ds = dp->ds;
++
++ if (ds->phylink_mac_ops && ds->phylink_mac_ops->mac_link_down)
++ ds->phylink_mac_ops->mac_link_down(&dp->pl_config, MLO_AN_FIXED,
++ PHY_INTERFACE_MODE_NA);
++ else if (ds->ops->phylink_mac_link_down)
++ ds->ops->phylink_mac_link_down(ds, dp->index, MLO_AN_FIXED,
++ PHY_INTERFACE_MODE_NA);
++}
++
+ int dsa_shared_port_link_register_of(struct dsa_port *dp)
+ {
+ struct dsa_switch *ds = dp->ds;
+ bool missing_link_description;
+ bool missing_phy_mode;
+- int port = dp->index;
+
+ dsa_shared_port_validate_of(dp, &missing_phy_mode,
+ &missing_link_description);
+@@ -1988,9 +2004,7 @@ int dsa_shared_port_link_register_of(str
+ "Skipping phylink registration for %s port %d\n",
+ dsa_port_is_cpu(dp) ? "CPU" : "DSA", dp->index);
+ } else {
+- if (ds->ops->phylink_mac_link_down)
+- ds->ops->phylink_mac_link_down(ds, port,
+- MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
++ dsa_shared_port_link_down(dp);
+
+ return dsa_shared_port_phylink_register(dp);
+ }
--- /dev/null
+From 5754b3bdcd872aa229881b8f07f84a8404c7d72a Mon Sep 17 00:00:00 2001
+From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
+Date: Fri, 12 Apr 2024 16:15:34 +0100
+Subject: [PATCH 1/5] net: dsa: mt7530: provide own phylink MAC operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Convert mt753x to provide its own phylink MAC operations, thus avoiding
+the shim layer in DSA's port.c
+
+Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Tested-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Link: https://lore.kernel.org/r/E1rvIco-006bQu-Fq@rmk-PC.armlinux.org.uk
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 46 +++++++++++++++++++++++++---------------
+ 1 file changed, 29 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2850,28 +2850,34 @@ mt7531_mac_config(struct dsa_switch *ds,
+ }
+
+ static struct phylink_pcs *
+-mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
++mt753x_phylink_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct mt7530_priv *priv = dp->ds->priv;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_TRGMII:
+- return &priv->pcs[port].pcs;
++ return &priv->pcs[dp->index].pcs;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+- return priv->ports[port].sgmii_pcs;
++ return priv->ports[dp->index].sgmii_pcs;
+ default:
+ return NULL;
+ }
+ }
+
+ static void
+-mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
++mt753x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct dsa_switch *ds = dp->ds;
++ struct mt7530_priv *priv;
++ int port = dp->index;
++
++ priv = ds->priv;
+
+ if ((port == 5 || port == 6) && priv->info->mac_port_config)
+ priv->info->mac_port_config(ds, port, mode, state->interface);
+@@ -2881,23 +2887,25 @@ mt753x_phylink_mac_config(struct dsa_swi
+ mt7530_set(priv, MT7530_PMCR_P(port), PMCR_EXT_PHY);
+ }
+
+-static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
++static void mt753x_phylink_mac_link_down(struct phylink_config *config,
+ unsigned int mode,
+ phy_interface_t interface)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct mt7530_priv *priv = dp->ds->priv;
+
+- mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
++ mt7530_clear(priv, MT7530_PMCR_P(dp->index), PMCR_LINK_SETTINGS_MASK);
+ }
+
+-static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
++static void mt753x_phylink_mac_link_up(struct phylink_config *config,
++ struct phy_device *phydev,
+ unsigned int mode,
+ phy_interface_t interface,
+- struct phy_device *phydev,
+ int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+ {
+- struct mt7530_priv *priv = ds->priv;
++ struct dsa_port *dp = dsa_phylink_to_port(config);
++ struct mt7530_priv *priv = dp->ds->priv;
+ u32 mcr;
+
+ mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
+@@ -2932,7 +2940,7 @@ static void mt753x_phylink_mac_link_up(s
+ }
+ }
+
+- mt7530_set(priv, MT7530_PMCR_P(port), mcr);
++ mt7530_set(priv, MT7530_PMCR_P(dp->index), mcr);
+ }
+
+ static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
+@@ -3152,16 +3160,19 @@ const struct dsa_switch_ops mt7530_switc
+ .port_mirror_add = mt753x_port_mirror_add,
+ .port_mirror_del = mt753x_port_mirror_del,
+ .phylink_get_caps = mt753x_phylink_get_caps,
+- .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs,
+- .phylink_mac_config = mt753x_phylink_mac_config,
+- .phylink_mac_link_down = mt753x_phylink_mac_link_down,
+- .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);
+
++static const struct phylink_mac_ops mt753x_phylink_mac_ops = {
++ .mac_select_pcs = mt753x_phylink_mac_select_pcs,
++ .mac_config = mt753x_phylink_mac_config,
++ .mac_link_down = mt753x_phylink_mac_link_down,
++ .mac_link_up = mt753x_phylink_mac_link_up,
++};
++
+ const struct mt753x_info mt753x_table[] = {
+ [ID_MT7621] = {
+ .id = ID_MT7621,
+@@ -3239,6 +3250,7 @@ mt7530_probe_common(struct mt7530_priv *
+ priv->dev = dev;
+ priv->ds->priv = priv;
+ priv->ds->ops = &mt7530_switch_ops;
++ priv->ds->phylink_mac_ops = &mt753x_phylink_mac_ops;
+ mutex_init(&priv->reg_mutex);
+ dev_set_drvdata(dev, priv);
+
--- /dev/null
+From d4097ddef078a113643a6dcde01e99741f852adb 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, 13 Apr 2024 16:01:39 +0300
+Subject: [PATCH 2/5] net: dsa: mt7530: fix mirroring frames received on local
+ port
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This switch intellectual property provides a bit on the ARL global control
+register which controls allowing mirroring frames which are received on the
+local port (monitor port). This bit is unset after reset.
+
+This ability must be enabled to fully support the port mirroring feature on
+this switch intellectual property.
+
+Therefore, this patch fixes the traffic not being reflected on a port,
+which would be configured like below:
+
+ tc qdisc add dev swp0 clsact
+
+ tc filter add dev swp0 ingress matchall skip_sw \
+ action mirred egress mirror dev swp0
+
+As a side note, this configuration provides the hairpinning feature for a
+single port.
+
+Fixes: 37feab6076aa ("net: dsa: mt7530: add support for port mirroring")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 6 ++++++
+ drivers/net/dsa/mt7530.h | 4 ++++
+ 2 files changed, 10 insertions(+)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -2480,6 +2480,9 @@ mt7530_setup(struct dsa_switch *ds)
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ }
+
++ /* Allow mirroring frames received on the local port (monitor port). */
++ mt7530_set(priv, MT753X_AGC, LOCAL_EN);
++
+ /* Setup VLAN ID 0 for VLAN-unaware bridges */
+ ret = mt7530_setup_vlan0(priv);
+ if (ret)
+@@ -2591,6 +2594,9 @@ mt7531_setup_common(struct dsa_switch *d
+ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
+ }
+
++ /* Allow mirroring frames received on the local port (monitor port). */
++ mt7530_set(priv, MT753X_AGC, LOCAL_EN);
++
+ /* Flush the FDB table */
+ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
+ if (ret < 0)
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -32,6 +32,10 @@ enum mt753x_id {
+ #define SYSC_REG_RSTCTRL 0x34
+ #define RESET_MCM BIT(2)
+
++/* Register for ARL global control */
++#define MT753X_AGC 0xc
++#define LOCAL_EN BIT(7)
++
+ /* Registers to mac forward control for unknown frames */
+ #define MT7530_MFC 0x10
+ #define BC_FFP(x) (((x) & 0xff) << 24)
--- /dev/null
+From 019a17a5e76940ea86114838d1d638d4dc8d3750 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, 13 Apr 2024 16:01:40 +0300
+Subject: [PATCH 3/5] net: dsa: mt7530: fix port mirroring for MT7988 SoC
+ switch
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The "MT7988A Wi-Fi 7 Generation Router Platform: Datasheet (Open Version)
+v0.1" document shows bits 16 to 18 as the MIRROR_PORT field of the CPU
+forward control register. Currently, the MT7530 DSA subdriver configures
+bits 0 to 2 of the CPU forward control register which breaks the port
+mirroring feature for the MT7988 SoC switch.
+
+Fix this by using the MT7531_MIRROR_PORT_GET() and MT7531_MIRROR_PORT_SET()
+macros which utilise the correct bits.
+
+Fixes: 110c18bfed41 ("net: dsa: mt7530: introduce driver for MT7988 built-in switch")
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Acked-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/dsa/mt7530.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -1883,14 +1883,16 @@ mt7530_port_vlan_del(struct dsa_switch *
+
+ static int mt753x_mirror_port_get(unsigned int id, u32 val)
+ {
+- return (id == ID_MT7531) ? MT7531_MIRROR_PORT_GET(val) :
+- MIRROR_PORT(val);
++ return (id == ID_MT7531 || id == ID_MT7988) ?
++ MT7531_MIRROR_PORT_GET(val) :
++ MIRROR_PORT(val);
+ }
+
+ static int mt753x_mirror_port_set(unsigned int id, u32 val)
+ {
+- return (id == ID_MT7531) ? MT7531_MIRROR_PORT_SET(val) :
+- MIRROR_PORT(val);
++ return (id == ID_MT7531 || id == ID_MT7988) ?
++ MT7531_MIRROR_PORT_SET(val) :
++ MIRROR_PORT(val);
+ }
+
+ static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
--- /dev/null
+From 5053a6cf1d50d785078562470d2a63695a9f3bf2 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, 18 Apr 2024 08:35:30 +0300
+Subject: [PATCH 4/5] net: dsa: mt7530-mdio: read PHY address of switch from
+ device tree
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Read the PHY address the switch listens on from the reg property of the
+switch node on the device tree. This change brings support for MT7530
+switches on boards with such bootstrapping configuration where the switch
+listens on a different PHY address than the hardcoded PHY address on the
+driver, 31.
+
+As described on the "MT7621 Programming Guide v0.4" document, the MT7530
+switch and its PHYs can be configured to listen on the range of 7-12,
+15-20, 23-28, and 31 and 0-4 PHY addresses.
+
+There are operations where the switch PHY registers are used. For the PHY
+address of the control PHY, transform the MT753X_CTRL_PHY_ADDR constant
+into a macro and use it. The PHY address for the control PHY is 0 when the
+switch listens on 31. In any other case, it is one greater than the PHY
+address the switch listens on.
+
+Reviewed-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530-mdio.c | 28 +++++++++++++-------------
+ drivers/net/dsa/mt7530.c | 37 +++++++++++++++++++++++------------
+ drivers/net/dsa/mt7530.h | 4 +++-
+ 3 files changed, 41 insertions(+), 28 deletions(-)
+
+--- a/drivers/net/dsa/mt7530-mdio.c
++++ b/drivers/net/dsa/mt7530-mdio.c
+@@ -18,7 +18,8 @@
+ static int
+ mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
+ {
+- struct mii_bus *bus = context;
++ struct mt7530_priv *priv = context;
++ struct mii_bus *bus = priv->bus;
+ u16 page, r, lo, hi;
+ int ret;
+
+@@ -27,36 +28,35 @@ mt7530_regmap_write(void *context, unsig
+ lo = val & 0xffff;
+ hi = val >> 16;
+
+- /* MT7530 uses 31 as the pseudo port */
+- ret = bus->write(bus, 0x1f, 0x1f, page);
++ ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
+ if (ret < 0)
+ return ret;
+
+- ret = bus->write(bus, 0x1f, r, lo);
++ ret = bus->write(bus, priv->mdiodev->addr, r, lo);
+ if (ret < 0)
+ return ret;
+
+- ret = bus->write(bus, 0x1f, 0x10, hi);
++ ret = bus->write(bus, priv->mdiodev->addr, 0x10, hi);
+ return ret;
+ }
+
+ static int
+ mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
+ {
+- struct mii_bus *bus = context;
++ struct mt7530_priv *priv = context;
++ struct mii_bus *bus = priv->bus;
+ 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);
++ ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
+ if (ret < 0)
+ return ret;
+
+- lo = bus->read(bus, 0x1f, r);
+- hi = bus->read(bus, 0x1f, 0x10);
++ lo = bus->read(bus, priv->mdiodev->addr, r);
++ hi = bus->read(bus, priv->mdiodev->addr, 0x10);
+
+ *val = (hi << 16) | (lo & 0xffff);
+
+@@ -107,8 +107,7 @@ mt7531_create_sgmii(struct mt7530_priv *
+ 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,
++ regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
+ mt7531_pcs_config[i]);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+@@ -153,6 +152,7 @@ mt7530_probe(struct mdio_device *mdiodev
+
+ priv->bus = mdiodev->bus;
+ priv->dev = &mdiodev->dev;
++ priv->mdiodev = mdiodev;
+
+ ret = mt7530_probe_common(priv);
+ if (ret)
+@@ -203,8 +203,8 @@ mt7530_probe(struct mdio_device *mdiodev
+ 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);
++ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
++ regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -86,22 +86,26 @@ core_read_mmd_indirect(struct mt7530_pri
+ int value, ret;
+
+ /* Write the desired MMD Devad */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+- ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, prtad);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
+ /* Read the content of the MMD's selected register */
+- value = bus->read(bus, 0, MII_MMD_DATA);
++ value = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA);
+
+ return value;
+ err:
+@@ -118,22 +122,26 @@ core_write_mmd_indirect(struct mt7530_pr
+ int ret;
+
+ /* Write the desired MMD Devad */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, devad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+- ret = bus->write(bus, 0, MII_MMD_DATA, prtad);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, prtad);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+- ret = bus->write(bus, 0, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
+ /* Write the data into MMD's selected register */
+- ret = bus->write(bus, 0, MII_MMD_DATA, data);
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, data);
+ err:
+ if (ret < 0)
+ dev_err(&bus->dev,
+@@ -2679,16 +2687,19 @@ mt7531_setup(struct dsa_switch *ds)
+ * phy_[read,write]_mmd_indirect is called, we provide our own
+ * mt7531_ind_mmd_phy_[read,write] to complete this function.
+ */
+- val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR,
++ val = mt7531_ind_c45_phy_read(priv,
++ MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+ MDIO_MMD_VEND2, CORE_PLL_GROUP4);
+ val |= MT7531_RG_SYSPLL_DMY2 | MT7531_PHY_PLL_BYPASS_MODE;
+ val &= ~MT7531_PHY_PLL_OFF;
+- mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
+- CORE_PLL_GROUP4, val);
++ mt7531_ind_c45_phy_write(priv,
++ MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MDIO_MMD_VEND2, CORE_PLL_GROUP4, val);
+
+ /* Disable EEE advertisement on the switch PHYs. */
+- for (i = MT753X_CTRL_PHY_ADDR;
+- i < MT753X_CTRL_PHY_ADDR + MT7530_NUM_PHYS; i++) {
++ for (i = MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr);
++ i < MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr) + MT7530_NUM_PHYS;
++ i++) {
+ mt7531_ind_c45_phy_write(priv, i, MDIO_MMD_AN, MDIO_AN_EEE_ADV,
+ 0);
+ }
+--- a/drivers/net/dsa/mt7530.h
++++ b/drivers/net/dsa/mt7530.h
+@@ -629,7 +629,7 @@ enum mt7531_clk_skew {
+ #define MT7531_PHY_PLL_OFF BIT(5)
+ #define MT7531_PHY_PLL_BYPASS_MODE BIT(4)
+
+-#define MT753X_CTRL_PHY_ADDR 0
++#define MT753X_CTRL_PHY_ADDR(addr) ((addr + 1) & 0x1f)
+
+ #define CORE_PLL_GROUP5 0x404
+ #define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff)
+@@ -778,6 +778,7 @@ struct mt753x_info {
+ * @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
++ * @mdiodev: The pointer to the MDIO device structure
+ */
+ struct mt7530_priv {
+ struct device *dev;
+@@ -804,6 +805,7 @@ struct mt7530_priv {
+ u32 irq_enable;
+ int (*create_sgmii)(struct mt7530_priv *priv);
+ u8 active_cpu_ports;
++ struct mdio_device *mdiodev;
+ };
+
+ struct mt7530_hw_vlan_entry {
--- /dev/null
+From 9764a08b3d260f4e7799d34bbfe64463db940d74 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, 18 Apr 2024 08:35:31 +0300
+Subject: [PATCH 5/5] net: dsa: mt7530: simplify core operations
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The core_rmw() function calls core_read_mmd_indirect() to read the
+requested register, and then calls core_write_mmd_indirect() to write the
+requested value to the register. Because Clause 22 is used to access Clause
+45 registers, some operations on core_write_mmd_indirect() are
+unnecessarily run. Get rid of core_read_mmd_indirect() and
+core_write_mmd_indirect(), and run only the necessary operations on
+core_write() and core_rmw().
+
+Reviewed-by: Daniel Golle <daniel@makrotopia.org>
+Tested-by: Daniel Golle <daniel@makrotopia.org>
+Signed-off-by: Arınç ÜNAL <arinc.unal@arinc9.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+---
+ drivers/net/dsa/mt7530.c | 108 ++++++++++++++++-----------------------
+ 1 file changed, 43 insertions(+), 65 deletions(-)
+
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -74,116 +74,94 @@ static const struct mt7530_mib_desc mt75
+ MIB_DESC(1, 0xb8, "RxArlDrop"),
+ };
+
+-/* Since phy_device has not yet been created and
+- * phy_{read,write}_mmd_indirect is not available, we provide our own
+- * core_{read,write}_mmd_indirect with core_{clear,write,set} wrappers
+- * to complete this function.
+- */
+-static int
+-core_read_mmd_indirect(struct mt7530_priv *priv, int prtad, int devad)
++static void
++mt7530_mutex_lock(struct mt7530_priv *priv)
++{
++ if (priv->bus)
++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
++}
++
++static void
++mt7530_mutex_unlock(struct mt7530_priv *priv)
++{
++ if (priv->bus)
++ mutex_unlock(&priv->bus->mdio_lock);
++}
++
++static void
++core_write(struct mt7530_priv *priv, u32 reg, u32 val)
+ {
+ struct mii_bus *bus = priv->bus;
+- int value, ret;
++ int ret;
++
++ mt7530_mutex_lock(priv);
+
+ /* Write the desired MMD Devad */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad);
++ MII_MMD_CTRL, MDIO_MMD_VEND2);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA, prtad);
++ MII_MMD_DATA, reg);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
++ MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
+- /* Read the content of the MMD's selected register */
+- value = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA);
+-
+- return value;
++ /* Write the data into MMD's selected register */
++ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA, val);
+ err:
+- dev_err(&bus->dev, "failed to read mmd register\n");
++ if (ret < 0)
++ dev_err(&bus->dev, "failed to write mmd register\n");
+
+- return ret;
++ mt7530_mutex_unlock(priv);
+ }
+
+-static int
+-core_write_mmd_indirect(struct mt7530_priv *priv, int prtad,
+- int devad, u32 data)
++static void
++core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
+ {
+ struct mii_bus *bus = priv->bus;
++ u32 val;
+ int ret;
+
++ mt7530_mutex_lock(priv);
++
+ /* Write the desired MMD Devad */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad);
++ MII_MMD_CTRL, MDIO_MMD_VEND2);
+ if (ret < 0)
+ goto err;
+
+ /* Write the desired MMD register address */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA, prtad);
++ MII_MMD_DATA, reg);
+ if (ret < 0)
+ goto err;
+
+ /* Select the Function : DATA with no post increment */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
++ MII_MMD_CTRL, MDIO_MMD_VEND2 | MII_MMD_CTRL_NOINCR);
+ if (ret < 0)
+ goto err;
+
++ /* Read the content of the MMD's selected register */
++ val = bus->read(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
++ MII_MMD_DATA);
++ val &= ~mask;
++ val |= set;
+ /* Write the data into MMD's selected register */
+ ret = bus->write(bus, MT753X_CTRL_PHY_ADDR(priv->mdiodev->addr),
+- MII_MMD_DATA, data);
++ MII_MMD_DATA, val);
+ err:
+ if (ret < 0)
+- dev_err(&bus->dev,
+- "failed to write mmd register\n");
+- return ret;
+-}
+-
+-static void
+-mt7530_mutex_lock(struct mt7530_priv *priv)
+-{
+- if (priv->bus)
+- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
+-}
+-
+-static void
+-mt7530_mutex_unlock(struct mt7530_priv *priv)
+-{
+- if (priv->bus)
+- 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);
+-
+- mt7530_mutex_unlock(priv);
+-}
+-
+-static void
+-core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set)
+-{
+- u32 val;
+-
+- 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);
++ dev_err(&bus->dev, "failed to write mmd register\n");
+
+ mt7530_mutex_unlock(priv);
+ }