public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties
@ 2026-01-19  9:12 Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 1/5] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx" Vladimir Oltean
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Vladimir Oltean @ 2026-01-19  9:12 UTC (permalink / raw)
  To: netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Using the "rx-polarity" and "tx-polarity" device tree properties
introduced in linux-phy and merged into net-next in
https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=96a2d53f24787df907e8bab388cc3e8f180a2314
we convert here two existing networking use cases - the EN8811H Ethernet
PHY and the Mediatek LynxI PCS.

v3 at:
https://lore.kernel.org/netdev/20260111093940.975359-1-vladimir.oltean@nxp.com/
Changes since v3:
It was requested that v3 be resent with just the networking parts, there
is no change.

v2 at:
https://lore.kernel.org/netdev/20260103210403.438687-1-vladimir.oltean@nxp.com/
Changes since v2:
- fix bug with existing fwnode which is missing polarity properties.
  This is supposed to return the default value, not an error. (thanks to
  Bjørn Mork).
- fix inconsistency between PHY_COMMON_PROPS and GENERIC_PHY_COMMON_PROPS
  Kconfig options by using PHY_COMMON_PROPS everywhere (thanks to Bjørn
  Mork).

v1 at:
https://lore.kernel.org/netdev/20251122193341.332324-1-vladimir.oltean@nxp.com/
Changes since v1:
- API changes: split error code from returned value; introduce two new
  helpers for simple driver cases
- Add KUnit tests
- Bug fixes in core code and in drivers
- Defer XPCS patches for later (*)
- Convert Mediatek LynxI PCS
- Logical change: rx-polarity and tx-polarity refer to the currently
  described block, and not necessarily to device pins
- Apply Rob's feedback
- Drop the "joint maintainership" idea.

(*) To simplify the generic XPCS driver, I've decided to make
"tx-polarity" default to <PHY_POL_NORMAL>, rather than <PHY_POL_NORMAL>
OR <PHY_POL_INVERT> for SJA1105. But in order to avoid breakage, it
creates a hard dependency on this patch set being merged *first*:
https://lore.kernel.org/netdev/20251118190530.580267-1-vladimir.oltean@nxp.com/
so that the SJA1105 driver can provide an XPCS fwnode with the right
polarity specified. All patches in context can be seen at:
https://github.com/vladimiroltean/linux/tree/phy-polarity-inversion

Original cover letter:

Polarity inversion (described in patch 4/10) is a feature with at least
4 potential new users waiting for a generic description:
- Horatiu Vultur with the lan966x SerDes
- Daniel Golle with the MaxLinear GSW1xx switches
- Bjørn Mork with the AN8811HB Ethernet PHY
- Me with a custom SJA1105 board, switch which uses the DesignWare XPCS

I became interested in exploring the problem space because I was averse
to the idea of adding vendor-specific device tree properties to describe
a common need.

This set contains an implementation of a generic feature that should
cater to all known needs that were identified during my documentation
phase.

Apart from what is converted here, we also have the following, which I
did not touch:
- "st,px_rx_pol_inv" - its binding is a .txt file and I don't have time
  for such a large detour to convert it to dtschema.
- "st,pcie-tx-pol-inv" and "st,sata-tx-pol-inv" - these are defined in a
  .txt schema but are not implemented in any driver. My verdict would be
  "delete the properties" but again, I would prefer not introducing such
  dependency to this series.

Vladimir Oltean (5):
  dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and
    "airoha,pnswap-tx"
  net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and
    "airoha,pnswap-tx"
  dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap"
  net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS
  net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"

 .../bindings/net/airoha,en8811h.yaml          | 11 +++-
 .../bindings/net/pcs/mediatek,sgmiisys.yaml   |  7 ++-
 drivers/net/dsa/mt7530-mdio.c                 |  4 +-
 drivers/net/ethernet/mediatek/mtk_eth_soc.c   | 19 +++---
 drivers/net/pcs/Kconfig                       |  1 +
 drivers/net/pcs/pcs-mtk-lynxi.c               | 63 ++++++++++++++++---
 drivers/net/phy/Kconfig                       |  1 +
 drivers/net/phy/air_en8811h.c                 | 53 +++++++++++-----
 include/linux/pcs/pcs-mtk-lynxi.h             |  5 +-
 9 files changed, 121 insertions(+), 43 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v4 net-next 1/5] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
  2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
@ 2026-01-19  9:12 ` Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 2/5] net: phy: air_en8811h: " Vladimir Oltean
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 15+ messages in thread
From: Vladimir Oltean @ 2026-01-19  9:12 UTC (permalink / raw)
  To: netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Reference the common PHY properties, and update the example to use them.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
v1->v4: none

 .../devicetree/bindings/net/airoha,en8811h.yaml       | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/net/airoha,en8811h.yaml b/Documentation/devicetree/bindings/net/airoha,en8811h.yaml
index ecb5149ec6b0..0de6e9284fbc 100644
--- a/Documentation/devicetree/bindings/net/airoha,en8811h.yaml
+++ b/Documentation/devicetree/bindings/net/airoha,en8811h.yaml
@@ -16,6 +16,7 @@ description:
 
 allOf:
   - $ref: ethernet-phy.yaml#
+  - $ref: /schemas/phy/phy-common-props.yaml#
 
 properties:
   compatible:
@@ -30,12 +31,18 @@ properties:
     description:
       Reverse rx polarity of the SERDES. This is the receiving
       side of the lines from the MAC towards the EN881H.
+      This property is deprecated, for details please refer to
+      Documentation/devicetree/bindings/phy/phy-common-props.yaml
+    deprecated: true
 
   airoha,pnswap-tx:
     type: boolean
     description:
       Reverse tx polarity of SERDES. This is the transmitting
       side of the lines from EN8811H towards the MAC.
+      This property is deprecated, for details please refer to
+      Documentation/devicetree/bindings/phy/phy-common-props.yaml
+    deprecated: true
 
 required:
   - reg
@@ -44,6 +51,8 @@ unevaluatedProperties: false
 
 examples:
   - |
+    #include <dt-bindings/phy/phy.h>
+
     mdio {
         #address-cells = <1>;
         #size-cells = <0>;
@@ -51,6 +60,6 @@ examples:
         ethernet-phy@1 {
             compatible = "ethernet-phy-id03a2.a411";
             reg = <1>;
-            airoha,pnswap-rx;
+            rx-polarity = <PHY_POL_INVERT>;
         };
     };
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 net-next 2/5] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
  2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 1/5] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx" Vladimir Oltean
@ 2026-01-19  9:12 ` Vladimir Oltean
  2026-01-19 15:33   ` Maxime Chevallier
  2026-01-19  9:12 ` [PATCH v4 net-next 3/5] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap" Vladimir Oltean
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Vladimir Oltean @ 2026-01-19  9:12 UTC (permalink / raw)
  To: netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Prefer the new "rx-polarity" and "tx-polarity" properties, and use the
vendor specific ones as fallback if the standard description doesn't
exist.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v2->v4: none
v1->v2:
- adapt to API change: error code and returned value have been split
- bug fix: supported mask of polarities should be BIT(PHY_POL_NORMAL) |
  BIT(PHY_POL_INVERT) rather than PHY_POL_NORMAL | PHY_POL_INVERT.

 drivers/net/phy/Kconfig       |  1 +
 drivers/net/phy/air_en8811h.c | 53 +++++++++++++++++++++++++----------
 2 files changed, 39 insertions(+), 15 deletions(-)

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index a7ade7b95a2e..7b73332a13d9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -98,6 +98,7 @@ config AS21XXX_PHY
 
 config AIR_EN8811H_PHY
 	tristate "Airoha EN8811H 2.5 Gigabit PHY"
+	select PHY_COMMON_PROPS
 	help
 	  Currently supports the Airoha EN8811H PHY.
 
diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
index badd65f0ccee..e890bb2c0aa8 100644
--- a/drivers/net/phy/air_en8811h.c
+++ b/drivers/net/phy/air_en8811h.c
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/phy.h>
+#include <linux/phy/phy-common-props.h>
 #include <linux/firmware.h>
 #include <linux/property.h>
 #include <linux/wordpart.h>
@@ -966,11 +967,45 @@ static int en8811h_probe(struct phy_device *phydev)
 	return 0;
 }
 
+static int en8811h_config_serdes_polarity(struct phy_device *phydev)
+{
+	struct device *dev = &phydev->mdio.dev;
+	unsigned int pol, default_pol;
+	u32 pbus_value = 0;
+	int ret;
+
+	default_pol = PHY_POL_NORMAL;
+	if (device_property_read_bool(dev, "airoha,pnswap-rx"))
+		default_pol = PHY_POL_INVERT;
+
+	ret = phy_get_rx_polarity(dev_fwnode(dev), phy_modes(phydev->interface),
+				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+				  default_pol, &pol);
+	if (ret)
+		return ret;
+	if (pol == PHY_POL_INVERT)
+		pbus_value |= EN8811H_POLARITY_RX_REVERSE;
+
+	default_pol = PHY_POL_NORMAL;
+	if (device_property_read_bool(dev, "airoha,pnswap-tx"))
+		default_pol = PHY_POL_INVERT;
+
+	ret = phy_get_tx_polarity(dev_fwnode(dev), phy_modes(phydev->interface),
+				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+				  default_pol, &pol);
+	if (ret)
+		return ret;
+	if (pol == PHY_POL_NORMAL)
+		pbus_value |= EN8811H_POLARITY_TX_NORMAL;
+
+	return air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
+				       EN8811H_POLARITY_RX_REVERSE |
+				       EN8811H_POLARITY_TX_NORMAL, pbus_value);
+}
+
 static int en8811h_config_init(struct phy_device *phydev)
 {
 	struct en8811h_priv *priv = phydev->priv;
-	struct device *dev = &phydev->mdio.dev;
-	u32 pbus_value;
 	int ret;
 
 	/* If restart happened in .probe(), no need to restart now */
@@ -1003,19 +1038,7 @@ static int en8811h_config_init(struct phy_device *phydev)
 	if (ret < 0)
 		return ret;
 
-	/* Serdes polarity */
-	pbus_value = 0;
-	if (device_property_read_bool(dev, "airoha,pnswap-rx"))
-		pbus_value |=  EN8811H_POLARITY_RX_REVERSE;
-	else
-		pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
-	if (device_property_read_bool(dev, "airoha,pnswap-tx"))
-		pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
-	else
-		pbus_value |=  EN8811H_POLARITY_TX_NORMAL;
-	ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
-				      EN8811H_POLARITY_RX_REVERSE |
-				      EN8811H_POLARITY_TX_NORMAL, pbus_value);
+	ret = en8811h_config_serdes_polarity(phydev);
 	if (ret < 0)
 		return ret;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 net-next 3/5] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap"
  2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 1/5] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx" Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 2/5] net: phy: air_en8811h: " Vladimir Oltean
@ 2026-01-19  9:12 ` Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 4/5] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS Vladimir Oltean
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 15+ messages in thread
From: Vladimir Oltean @ 2026-01-19  9:12 UTC (permalink / raw)
  To: netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Reference the common PHY properties, and update the example to use them.
Note that a PCS subnode exists, and it seems a better container of the
polarity description than the SGMIISYS node that hosts "mediatek,pnswap".
So use that.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
---
v1->v4: none

 .../devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml     | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
index 1bacc0eeff75..b8478416f8ef 100644
--- a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
+++ b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
@@ -39,12 +39,17 @@ properties:
     const: 1
 
   mediatek,pnswap:
-    description: Invert polarity of the SGMII data lanes
+    description:
+      Invert polarity of the SGMII data lanes.
+      This property is deprecated, for details please refer to
+      Documentation/devicetree/bindings/phy/phy-common-props.yaml.
     type: boolean
+    deprecated: true
 
   pcs:
     type: object
     description: MediaTek LynxI HSGMII PCS
+    $ref: /schemas/phy/phy-common-props.yaml#
     properties:
       compatible:
         const: mediatek,mt7988-sgmii
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 net-next 4/5] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS
  2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
                   ` (2 preceding siblings ...)
  2026-01-19  9:12 ` [PATCH v4 net-next 3/5] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap" Vladimir Oltean
@ 2026-01-19  9:12 ` Vladimir Oltean
  2026-01-19  9:12 ` [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap" Vladimir Oltean
  2026-01-22  4:00 ` [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties patchwork-bot+netdevbpf
  5 siblings, 0 replies; 15+ messages in thread
From: Vladimir Oltean @ 2026-01-19  9:12 UTC (permalink / raw)
  To: netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

The Mediatek LynxI PCS is used from the MT7530 DSA driver (where it does
not have an OF presence) and from mtk_eth_soc, where it does
(Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
informs of a combined clock provider + SGMII PCS "SGMIISYS" syscon
block).

Currently, mtk_eth_soc parses the SGMIISYS OF node for the
"mediatek,pnswap" property and sets a bit in the "flags" argument of
mtk_pcs_lynxi_create() if set.

I'd like to deprecate "mediatek,pnswap" in favour of a property which
takes the current phy-mode into consideration. But this is only known at
mtk_pcs_lynxi_config() time, and not known at mtk_pcs_lynxi_create(),
when the SGMIISYS OF node is parsed.

To achieve that, we must pass the OF node of the PCS, if it exists, to
mtk_pcs_lynxi_create(), and let the PCS take a reference on it and
handle property parsing whenever it wants.

Use the fwnode API which is more general than OF (in case we ever need
to describe the PCS using some other format). This API should be NULL
tolerant, so add no particular tests for the mt7530 case.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v2->v4: none
v1->v2: patch is new

 drivers/net/dsa/mt7530-mdio.c               |  4 ++--
 drivers/net/ethernet/mediatek/mtk_eth_soc.c | 19 ++++++++-----------
 drivers/net/pcs/pcs-mtk-lynxi.c             | 15 ++++++++++-----
 include/linux/pcs/pcs-mtk-lynxi.h           |  5 ++---
 4 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c
index 0286a6cecb6f..11ea924a9f35 100644
--- a/drivers/net/dsa/mt7530-mdio.c
+++ b/drivers/net/dsa/mt7530-mdio.c
@@ -113,8 +113,8 @@ mt7531_create_sgmii(struct mt7530_priv *priv)
 			ret = PTR_ERR(regmap);
 			break;
 		}
-		pcs = mtk_pcs_lynxi_create(priv->dev, regmap,
-					   MT7531_PHYA_CTRL_SIGNAL3, 0);
+		pcs = mtk_pcs_lynxi_create(priv->dev, NULL, regmap,
+					   MT7531_PHYA_CTRL_SIGNAL3);
 		if (!pcs) {
 			ret = -ENXIO;
 			break;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 99abec2198d0..35fef28ee2f9 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -4994,7 +4994,6 @@ static int mtk_sgmii_init(struct mtk_eth *eth)
 {
 	struct device_node *np;
 	struct regmap *regmap;
-	u32 flags;
 	int i;
 
 	for (i = 0; i < MTK_MAX_DEVS; i++) {
@@ -5003,18 +5002,16 @@ static int mtk_sgmii_init(struct mtk_eth *eth)
 			break;
 
 		regmap = syscon_node_to_regmap(np);
-		flags = 0;
-		if (of_property_read_bool(np, "mediatek,pnswap"))
-			flags |= MTK_SGMII_FLAG_PN_SWAP;
-
-		of_node_put(np);
-
-		if (IS_ERR(regmap))
+		if (IS_ERR(regmap)) {
+			of_node_put(np);
 			return PTR_ERR(regmap);
+		}
 
-		eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev, regmap,
-							 eth->soc->ana_rgc3,
-							 flags);
+		eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev,
+							 of_fwnode_handle(np),
+							 regmap,
+							 eth->soc->ana_rgc3);
+		of_node_put(np);
 	}
 
 	return 0;
diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
index 149ddf51d785..7f719da5812e 100644
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -81,6 +81,7 @@ struct mtk_pcs_lynxi {
 	phy_interface_t		interface;
 	struct			phylink_pcs pcs;
 	u32			flags;
+	struct fwnode_handle	*fwnode;
 };
 
 static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
@@ -168,7 +169,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
 		regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
 				SGMII_SW_RESET);
 
-		if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP)
+		if (fwnode_property_read_bool(mpcs->fwnode, "mediatek,pnswap"))
 			regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
 					   SGMII_PN_SWAP_MASK,
 					   SGMII_PN_SWAP_TX_RX);
@@ -268,8 +269,8 @@ static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = {
 };
 
 struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
-					 struct regmap *regmap, u32 ana_rgc3,
-					 u32 flags)
+					 struct fwnode_handle *fwnode,
+					 struct regmap *regmap, u32 ana_rgc3)
 {
 	struct mtk_pcs_lynxi *mpcs;
 	u32 id, ver;
@@ -303,10 +304,10 @@ struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
 
 	mpcs->ana_rgc3 = ana_rgc3;
 	mpcs->regmap = regmap;
-	mpcs->flags = flags;
 	mpcs->pcs.ops = &mtk_pcs_lynxi_ops;
 	mpcs->pcs.poll = true;
 	mpcs->interface = PHY_INTERFACE_MODE_NA;
+	mpcs->fwnode = fwnode_handle_get(fwnode);
 
 	__set_bit(PHY_INTERFACE_MODE_SGMII, mpcs->pcs.supported_interfaces);
 	__set_bit(PHY_INTERFACE_MODE_1000BASEX, mpcs->pcs.supported_interfaces);
@@ -318,10 +319,14 @@ EXPORT_SYMBOL(mtk_pcs_lynxi_create);
 
 void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs)
 {
+	struct mtk_pcs_lynxi *mpcs;
+
 	if (!pcs)
 		return;
 
-	kfree(pcs_to_mtk_pcs_lynxi(pcs));
+	mpcs = pcs_to_mtk_pcs_lynxi(pcs);
+	fwnode_handle_put(mpcs->fwnode);
+	kfree(mpcs);
 }
 EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
 
diff --git a/include/linux/pcs/pcs-mtk-lynxi.h b/include/linux/pcs/pcs-mtk-lynxi.h
index be3b4ab32f4a..1bd4a27a8898 100644
--- a/include/linux/pcs/pcs-mtk-lynxi.h
+++ b/include/linux/pcs/pcs-mtk-lynxi.h
@@ -5,9 +5,8 @@
 #include <linux/phylink.h>
 #include <linux/regmap.h>
 
-#define MTK_SGMII_FLAG_PN_SWAP BIT(0)
 struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
-					 struct regmap *regmap,
-					 u32 ana_rgc3, u32 flags);
+					 struct fwnode_handle *fwnode,
+					 struct regmap *regmap, u32 ana_rgc3);
 void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs);
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
                   ` (3 preceding siblings ...)
  2026-01-19  9:12 ` [PATCH v4 net-next 4/5] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS Vladimir Oltean
@ 2026-01-19  9:12 ` Vladimir Oltean
  2026-03-24  6:36   ` Frank Wunderlich
  2026-01-22  4:00 ` [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties patchwork-bot+netdevbpf
  5 siblings, 1 reply; 15+ messages in thread
From: Vladimir Oltean @ 2026-01-19  9:12 UTC (permalink / raw)
  To: netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Prefer the new "rx-polarity" and "tx-polarity" properties, which in this
case have the advantage that polarity inversion can be specified per
direction (and per protocol, although this isn't useful here).

We use the vendor specific ones as fallback if the standard description
doesn't exist.

Daniel, referring to the Mediatek SDK, clarifies that the combined
SGMII_PN_SWAP_TX_RX register field should be split like this: bit 0 is
TX and bit 1 is RX:
https://lore.kernel.org/linux-phy/aSW--slbJWpXK0nv@makrotopia.org/

Suggested-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v3->v4: none
v2->v3: s/GENERIC_PHY_COMMON_PROPS/PHY_COMMON_PROPS/
v1->v2: patch is new

 drivers/net/pcs/Kconfig         |  1 +
 drivers/net/pcs/pcs-mtk-lynxi.c | 50 +++++++++++++++++++++++++++++----
 2 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig
index ecbc3530e780..e417fd66f660 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -20,6 +20,7 @@ config PCS_LYNX
 
 config PCS_MTK_LYNXI
 	tristate
+	select PHY_COMMON_PROPS
 	select REGMAP
 	help
 	  This module provides helpers to phylink for managing the LynxI PCS
diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
index 7f719da5812e..74dbce205f71 100644
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -11,6 +11,7 @@
 #include <linux/mdio.h>
 #include <linux/of.h>
 #include <linux/pcs/pcs-mtk-lynxi.h>
+#include <linux/phy/phy-common-props.h>
 #include <linux/phylink.h>
 #include <linux/regmap.h>
 
@@ -62,8 +63,9 @@
 
 /* Register to QPHY wrapper control */
 #define SGMSYS_QPHY_WRAP_CTRL		0xec
-#define SGMII_PN_SWAP_MASK		GENMASK(1, 0)
-#define SGMII_PN_SWAP_TX_RX		(BIT(0) | BIT(1))
+#define SGMII_PN_SWAP_RX		BIT(1)
+#define SGMII_PN_SWAP_TX		BIT(0)
+
 
 /* struct mtk_pcs_lynxi -  This structure holds each sgmii regmap andassociated
  *                         data
@@ -121,6 +123,42 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
 					 FIELD_GET(SGMII_LPA, adv));
 }
 
+static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
+				   phy_interface_t interface)
+{
+	struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode;
+	unsigned int pol, default_pol = PHY_POL_NORMAL;
+	unsigned int val = 0;
+	int ret;
+
+	if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
+		default_pol = PHY_POL_INVERT;
+
+	pcs_fwnode = fwnode_get_named_child_node(fwnode, "pcs");
+
+	ret = phy_get_rx_polarity(pcs_fwnode, phy_modes(interface),
+				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+				  default_pol, &pol);
+	if (ret) {
+		fwnode_handle_put(pcs_fwnode);
+		return ret;
+	}
+	if (pol == PHY_POL_INVERT)
+		val |= SGMII_PN_SWAP_RX;
+
+	ret = phy_get_tx_polarity(pcs_fwnode, phy_modes(interface),
+				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+				  default_pol, &pol);
+	fwnode_handle_put(pcs_fwnode);
+	if (ret)
+		return ret;
+	if (pol == PHY_POL_INVERT)
+		val |= SGMII_PN_SWAP_TX;
+
+	return regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
+				  SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX, val);
+}
+
 static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
 				phy_interface_t interface,
 				const unsigned long *advertising,
@@ -130,6 +168,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
 	bool mode_changed = false, changed;
 	unsigned int rgc3, sgm_mode, bmcr;
 	int advertise, link_timer;
+	int ret;
 
 	advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
 							     advertising);
@@ -169,10 +208,9 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
 		regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
 				SGMII_SW_RESET);
 
-		if (fwnode_property_read_bool(mpcs->fwnode, "mediatek,pnswap"))
-			regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
-					   SGMII_PN_SWAP_MASK,
-					   SGMII_PN_SWAP_TX_RX);
+		ret = mtk_pcs_config_polarity(mpcs, interface);
+		if (ret)
+			return ret;
 
 		if (interface == PHY_INTERFACE_MODE_2500BASEX)
 			rgc3 = SGMII_PHY_SPEED_3_125G;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 2/5] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
  2026-01-19  9:12 ` [PATCH v4 net-next 2/5] net: phy: air_en8811h: " Vladimir Oltean
@ 2026-01-19 15:33   ` Maxime Chevallier
  0 siblings, 0 replies; 15+ messages in thread
From: Maxime Chevallier @ 2026-01-19 15:33 UTC (permalink / raw)
  To: Vladimir Oltean, netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Hi Vladimir,

On 19/01/2026 10:12, Vladimir Oltean wrote:
> Prefer the new "rx-polarity" and "tx-polarity" properties, and use the
> vendor specific ones as fallback if the standard description doesn't
> exist.
> 
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>

Thanks,

Maxime

> ---
> v2->v4: none
> v1->v2:
> - adapt to API change: error code and returned value have been split
> - bug fix: supported mask of polarities should be BIT(PHY_POL_NORMAL) |
>   BIT(PHY_POL_INVERT) rather than PHY_POL_NORMAL | PHY_POL_INVERT.
> 
>  drivers/net/phy/Kconfig       |  1 +
>  drivers/net/phy/air_en8811h.c | 53 +++++++++++++++++++++++++----------
>  2 files changed, 39 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index a7ade7b95a2e..7b73332a13d9 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -98,6 +98,7 @@ config AS21XXX_PHY
>  
>  config AIR_EN8811H_PHY
>  	tristate "Airoha EN8811H 2.5 Gigabit PHY"
> +	select PHY_COMMON_PROPS
>  	help
>  	  Currently supports the Airoha EN8811H PHY.
>  
> diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
> index badd65f0ccee..e890bb2c0aa8 100644
> --- a/drivers/net/phy/air_en8811h.c
> +++ b/drivers/net/phy/air_en8811h.c
> @@ -14,6 +14,7 @@
>  #include <linux/clk.h>
>  #include <linux/clk-provider.h>
>  #include <linux/phy.h>
> +#include <linux/phy/phy-common-props.h>
>  #include <linux/firmware.h>
>  #include <linux/property.h>
>  #include <linux/wordpart.h>
> @@ -966,11 +967,45 @@ static int en8811h_probe(struct phy_device *phydev)
>  	return 0;
>  }
>  
> +static int en8811h_config_serdes_polarity(struct phy_device *phydev)
> +{
> +	struct device *dev = &phydev->mdio.dev;
> +	unsigned int pol, default_pol;
> +	u32 pbus_value = 0;
> +	int ret;
> +
> +	default_pol = PHY_POL_NORMAL;
> +	if (device_property_read_bool(dev, "airoha,pnswap-rx"))
> +		default_pol = PHY_POL_INVERT;
> +
> +	ret = phy_get_rx_polarity(dev_fwnode(dev), phy_modes(phydev->interface),
> +				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
> +				  default_pol, &pol);
> +	if (ret)
> +		return ret;
> +	if (pol == PHY_POL_INVERT)
> +		pbus_value |= EN8811H_POLARITY_RX_REVERSE;
> +
> +	default_pol = PHY_POL_NORMAL;
> +	if (device_property_read_bool(dev, "airoha,pnswap-tx"))
> +		default_pol = PHY_POL_INVERT;
> +
> +	ret = phy_get_tx_polarity(dev_fwnode(dev), phy_modes(phydev->interface),
> +				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
> +				  default_pol, &pol);
> +	if (ret)
> +		return ret;
> +	if (pol == PHY_POL_NORMAL)
> +		pbus_value |= EN8811H_POLARITY_TX_NORMAL;
> +
> +	return air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
> +				       EN8811H_POLARITY_RX_REVERSE |
> +				       EN8811H_POLARITY_TX_NORMAL, pbus_value);
> +}
> +
>  static int en8811h_config_init(struct phy_device *phydev)
>  {
>  	struct en8811h_priv *priv = phydev->priv;
> -	struct device *dev = &phydev->mdio.dev;
> -	u32 pbus_value;
>  	int ret;
>  
>  	/* If restart happened in .probe(), no need to restart now */
> @@ -1003,19 +1038,7 @@ static int en8811h_config_init(struct phy_device *phydev)
>  	if (ret < 0)
>  		return ret;
>  
> -	/* Serdes polarity */
> -	pbus_value = 0;
> -	if (device_property_read_bool(dev, "airoha,pnswap-rx"))
> -		pbus_value |=  EN8811H_POLARITY_RX_REVERSE;
> -	else
> -		pbus_value &= ~EN8811H_POLARITY_RX_REVERSE;
> -	if (device_property_read_bool(dev, "airoha,pnswap-tx"))
> -		pbus_value &= ~EN8811H_POLARITY_TX_NORMAL;
> -	else
> -		pbus_value |=  EN8811H_POLARITY_TX_NORMAL;
> -	ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
> -				      EN8811H_POLARITY_RX_REVERSE |
> -				      EN8811H_POLARITY_TX_NORMAL, pbus_value);
> +	ret = en8811h_config_serdes_polarity(phydev);
>  	if (ret < 0)
>  		return ret;
>  


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties
  2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
                   ` (4 preceding siblings ...)
  2026-01-19  9:12 ` [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap" Vladimir Oltean
@ 2026-01-22  4:00 ` patchwork-bot+netdevbpf
  5 siblings, 0 replies; 15+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-01-22  4:00 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, daniel,
	horatiu.vultur, bjorn, andrew+netdev, hkallweit1, linux, davem,
	edumazet, kuba, pabeni, robh, krzk+dt, conor+dt, matthias.bgg,
	angelogioacchino.delregno, ericwouds, lynxis, chester.a.unal,
	dqfext, sean.wang, nbd

Hello:

This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Mon, 19 Jan 2026 11:12:15 +0200 you wrote:
> Using the "rx-polarity" and "tx-polarity" device tree properties
> introduced in linux-phy and merged into net-next in
> https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=96a2d53f24787df907e8bab388cc3e8f180a2314
> we convert here two existing networking use cases - the EN8811H Ethernet
> PHY and the Mediatek LynxI PCS.
> 
> v3 at:
> https://lore.kernel.org/netdev/20260111093940.975359-1-vladimir.oltean@nxp.com/
> Changes since v3:
> It was requested that v3 be resent with just the networking parts, there
> is no change.
> 
> [...]

Here is the summary with links:
  - [v4,net-next,1/5] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
    https://git.kernel.org/netdev/net-next/c/44f62aa1b120
  - [v4,net-next,2/5] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
    https://git.kernel.org/netdev/net-next/c/66d8a334b57e
  - [v4,net-next,3/5] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap"
    https://git.kernel.org/netdev/net-next/c/9f841922ebd0
  - [v4,net-next,4/5] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS
    https://git.kernel.org/netdev/net-next/c/bde1ae2d52ab
  - [v4,net-next,5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
    https://git.kernel.org/netdev/net-next/c/8871389da151

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-01-19  9:12 ` [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap" Vladimir Oltean
@ 2026-03-24  6:36   ` Frank Wunderlich
  2026-03-26 21:54     ` Vladimir Oltean
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Wunderlich @ 2026-03-24  6:36 UTC (permalink / raw)
  To: Vladimir Oltean, netdev, devicetree
  Cc: linux-kernel, linux-mediatek, Daniel Golle, Horatiu Vultur,
	Bjørn Mork, Andrew Lunn, Heiner Kallweit, Russell King,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Eric Woudstra, Alexander Couzens,
	Chester A. Unal, DENG Qingfang, Sean Wang, Felix Fietkau

Hi,

looks like this patch breaks BPI-R3 serdes between mt7986 SoC and mt7531 switch in 7.0 (6.19 is ok).
in ethtool i see only tx on mac but no rx. if i revert this patch i can ping through dsa-ports again.

i did not completely understanding the code with the default-pol as it is now splitted between rx and tx.

mt7986 and this board does not have mediatek,pnswap set, so the final  regmap_update_bits writes val=0,
before there was only write to this register on invert mode...but i guess this should not break. Maybe some
kind of timing issue between mac and switch?

maybe reverting this patch skips changes made here:
bde1ae2d52ab 2026-01-19 net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS

I resend as last try was sending as html (option "always send as text" in webmailer seems to be ignored
somehow, had to choose "unformatted" in this response too).

regards Frank

Am 19. Januar 2026 um 10:12 schrieb "Vladimir Oltean" <vladimir.oltean@nxp.com mailto:vladimir.oltean@nxp.com?to=%22Vladimir%20Oltean%22%20%3Cvladimir.oltean%40nxp.com%3E >:
> 
> Prefer the new "rx-polarity" and "tx-polarity" properties, which in this
> case have the advantage that polarity inversion can be specified per
> direction (and per protocol, although this isn't useful here).
> 
> We use the vendor specific ones as fallback if the standard description
> doesn't exist.
> 
> Daniel, referring to the Mediatek SDK, clarifies that the combined
> SGMII_PN_SWAP_TX_RX register field should be split like this: bit 0 is
> TX and bit 1 is RX:
> https://lore.kernel.org/linux-phy/aSW--slbJWpXK0nv@makrotopia.org/
> 
> Suggested-by: Daniel Golle <daniel@makrotopia.org>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> v3->v4: none
> v2->v3: s/GENERIC_PHY_COMMON_PROPS/PHY_COMMON_PROPS/
> v1->v2: patch is new
> 
>  drivers/net/pcs/Kconfig | 1 +
>  drivers/net/pcs/pcs-mtk-lynxi.c | 50 +++++++++++++++++++++++++++++----
>  2 files changed, 45 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig
> index ecbc3530e780..e417fd66f660 100644
> --- a/drivers/net/pcs/Kconfig
> +++ b/drivers/net/pcs/Kconfig
> @@ -20,6 +20,7 @@ config PCS_LYNX
>  
>  config PCS_MTK_LYNXI
>  tristate
> + select PHY_COMMON_PROPS
>  select REGMAP
>  help
>  This module provides helpers to phylink for managing the LynxI PCS
> diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
> index 7f719da5812e..74dbce205f71 100644
> --- a/drivers/net/pcs/pcs-mtk-lynxi.c
> +++ b/drivers/net/pcs/pcs-mtk-lynxi.c
> @@ -11,6 +11,7 @@
>  #include <linux/mdio.h>
>  #include <linux/of.h>
>  #include <linux/pcs/pcs-mtk-lynxi.h>
> +#include <linux/phy/phy-common-props.h>
>  #include <linux/phylink.h>
>  #include <linux/regmap.h>
>  
> @@ -62,8 +63,9 @@
>  
>  /* Register to QPHY wrapper control */
>  #define SGMSYS_QPHY_WRAP_CTRL 0xec
> -#define SGMII_PN_SWAP_MASK GENMASK(1, 0)
> -#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1))
> +#define SGMII_PN_SWAP_RX BIT(1)
> +#define SGMII_PN_SWAP_TX BIT(0)
> +
>  
>  /* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated
>  * data
> @@ -121,6 +123,42 @@ static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs,
>  FIELD_GET(SGMII_LPA, adv));
>  }
>  
> +static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
> + phy_interface_t interface)
> +{
> + struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode;
> + unsigned int pol, default_pol = PHY_POL_NORMAL;
> + unsigned int val = 0;
> + int ret;
> +
> + if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
> + default_pol = PHY_POL_INVERT;
> +
> + pcs_fwnode = fwnode_get_named_child_node(fwnode, "pcs");
> +
> + ret = phy_get_rx_polarity(pcs_fwnode, phy_modes(interface),
> + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
> + default_pol, &pol);
> + if (ret) {
> + fwnode_handle_put(pcs_fwnode);
> + return ret;
> + }
> + if (pol == PHY_POL_INVERT)
> + val |= SGMII_PN_SWAP_RX;
> +
> + ret = phy_get_tx_polarity(pcs_fwnode, phy_modes(interface),
> + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
> + default_pol, &pol);
> + fwnode_handle_put(pcs_fwnode);
> + if (ret)
> + return ret;
> + if (pol == PHY_POL_INVERT)
> + val |= SGMII_PN_SWAP_TX;
> +
> + return regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
> + SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX, val);
> +}
> +
>  static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
>  phy_interface_t interface,
>  const unsigned long *advertising,
> @@ -130,6 +168,7 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
>  bool mode_changed = false, changed;
>  unsigned int rgc3, sgm_mode, bmcr;
>  int advertise, link_timer;
> + int ret;
>  
>  advertise = phylink_mii_c22_pcs_encode_advertisement(interface,
>  advertising);
> @@ -169,10 +208,9 @@ static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
>  regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
>  SGMII_SW_RESET);
>  
> - if (fwnode_property_read_bool(mpcs->fwnode, "mediatek,pnswap"))
> - regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
> - SGMII_PN_SWAP_MASK,
> - SGMII_PN_SWAP_TX_RX);
> + ret = mtk_pcs_config_polarity(mpcs, interface);
> + if (ret)
> + return ret;
>  
>  if (interface == PHY_INTERFACE_MODE_2500BASEX)
>  rgc3 = SGMII_PHY_SPEED_3_125G;
> -- 
> 2.34.1
> 

regards Frank

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-03-24  6:36   ` Frank Wunderlich
@ 2026-03-26 21:54     ` Vladimir Oltean
  2026-03-30 17:52       ` Frank Wunderlich
  0 siblings, 1 reply; 15+ messages in thread
From: Vladimir Oltean @ 2026-03-26 21:54 UTC (permalink / raw)
  To: Frank Wunderlich
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
	Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
	Sean Wang, Felix Fietkau

Hi Frank,

On Tue, Mar 24, 2026 at 06:36:44AM +0000, Frank Wunderlich wrote:
> Hi,
> 
> looks like this patch breaks BPI-R3 serdes between mt7986 SoC and mt7531 switch in 7.0 (6.19 is ok).
> in ethtool i see only tx on mac but no rx. if i revert this patch i can ping through dsa-ports again.
> 
> i did not completely understanding the code with the default-pol as it is now splitted between rx and tx.
> 
> mt7986 and this board does not have mediatek,pnswap set, so the final  regmap_update_bits writes val=0,
> before there was only write to this register on invert mode...but i guess this should not break. Maybe some
> kind of timing issue between mac and switch?
> 
> maybe reverting this patch skips changes made here:
> bde1ae2d52ab 2026-01-19 net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS
> 
> I resend as last try was sending as html (option "always send as text" in webmailer seems to be ignored
> somehow, had to choose "unformatted" in this response too).
> 
> regards Frank

Sorry for the delay.

If writing val=0 breaks the link, I'm curious
(a) whether it still breaks if we don't write anything at all
(b) what was the register value originally

Could you please test the patch below and let me know what it prints,
and whether traffic passes with it applied?

-- >8 --
diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
index c12f8087af9b..5c5f45b93b82 100644
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -126,7 +126,7 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
 {
 	struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode;
 	unsigned int pol, default_pol = PHY_POL_NORMAL;
-	unsigned int val = 0;
+	unsigned int val = 0, tmp;
 	int ret;
 
 	if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
@@ -153,8 +153,14 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
 	if (pol == PHY_POL_INVERT)
 		val |= SGMII_PN_SWAP_TX;
 
-	return regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
-				  SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX, val);
+	ret = regmap_read(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, &tmp);
+	if (ret)
+		return ret;
+
+	pr_err("SGMSYS_QPHY_WRAP_CTRL = 0x%x, intending to write 0x%lx\n",
+	       tmp, (tmp & ~(SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX)) | val);
+
+	return 0;
 }
 
 static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
-- >8 --

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-03-26 21:54     ` Vladimir Oltean
@ 2026-03-30 17:52       ` Frank Wunderlich
  2026-03-30 19:04         ` Vladimir Oltean
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Wunderlich @ 2026-03-30 17:52 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
	Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
	Sean Wang, Felix Fietkau

Hi Vladimir

Thanks for the patch and sorry for my delay...i was away this weekend so i was not able to test.

traffic works again (but there is only read now) and this is the result of your debug prints:

root@bpi-r3:~# dmesg | grep SGMSYS_QPHY_WRAP_CTRL
[    2.706963] SGMSYS_QPHY_WRAP_CTRL = 0x501, intending to write 0x500
[    9.134081] SGMSYS_QPHY_WRAP_CTRL = 0x500, intending to write 0x500

R3/mt7986 has 2 MAC, and switch is on the first, so value will change, not sure why this is different.

i have not found SGMSYS_QPHY_WRAP_CTRL or something related with polarity in ethernet/mac- 
(drivers/net/ethernet/mediatek/mtk_eth_soc.c) or switch-driver (drivers/net/dsa/mt7530{,-mdio}.c)
in case they manipulate this register too (of course they should not). Also looked into the pcs-handling
in both drivers, but see nothing related to polarity. And looked for possible duplicate register const
definition (other name for 0xec).

regards Frank

Am 26. März 2026 um 22:54 schrieb "Vladimir Oltean" <vladimir.oltean@nxp.com>:
> 
> Hi Frank,
> 
> On Tue, Mar 24, 2026 at 06:36:44AM +0000, Frank Wunderlich wrote:
> 
> > 
> > Hi,
> >  
> >  looks like this patch breaks BPI-R3 serdes between mt7986 SoC and mt7531 switch in 7.0 (6.19 is ok).
> >  in ethtool i see only tx on mac but no rx. if i revert this patch i can ping through dsa-ports again.
> >  
> >  i did not completely understanding the code with the default-pol as it is now splitted between rx and tx.
> >  
> >  mt7986 and this board does not have mediatek,pnswap set, so the final regmap_update_bits writes val=0,
> >  before there was only write to this register on invert mode...but i guess this should not break. Maybe some
> >  kind of timing issue between mac and switch?
> >  
> >  maybe reverting this patch skips changes made here:
> >  bde1ae2d52ab 2026-01-19 net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS
> >  
> >  I resend as last try was sending as html (option "always send as text" in webmailer seems to be ignored
> >  somehow, had to choose "unformatted" in this response too).
> >  
> >  regards Frank
> > 
> Sorry for the delay.
> 
> If writing val=0 breaks the link, I'm curious
> (a) whether it still breaks if we don't write anything at all
> (b) what was the register value originally
> 
> Could you please test the patch below and let me know what it prints,
> and whether traffic passes with it applied?
> 
> -- >8 --
> diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
> index c12f8087af9b..5c5f45b93b82 100644
> --- a/drivers/net/pcs/pcs-mtk-lynxi.c
> +++ b/drivers/net/pcs/pcs-mtk-lynxi.c
> @@ -126,7 +126,7 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
>  {
>  struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode;
>  unsigned int pol, default_pol = PHY_POL_NORMAL;
> - unsigned int val = 0;
> + unsigned int val = 0, tmp;
>  int ret;
>  
>  if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
> @@ -153,8 +153,14 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
>  if (pol == PHY_POL_INVERT)
>  val |= SGMII_PN_SWAP_TX;
>  
> - return regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL,
> - SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX, val);
> + ret = regmap_read(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, &tmp);
> + if (ret)
> + return ret;
> +
> + pr_err("SGMSYS_QPHY_WRAP_CTRL = 0x%x, intending to write 0x%lx\n",
> + tmp, (tmp & ~(SGMII_PN_SWAP_RX | SGMII_PN_SWAP_TX)) | val);
> +
> + return 0;
>  }
>  
>  static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
> -- >8 --
> 

regards Frank

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-03-30 17:52       ` Frank Wunderlich
@ 2026-03-30 19:04         ` Vladimir Oltean
  2026-04-02  5:50           ` Frank Wunderlich
  0 siblings, 1 reply; 15+ messages in thread
From: Vladimir Oltean @ 2026-03-30 19:04 UTC (permalink / raw)
  To: Frank Wunderlich
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
	Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
	Sean Wang, Felix Fietkau

[-- Attachment #1: Type: text/plain, Size: 2089 bytes --]

Hi Frank,

On Mon, Mar 30, 2026 at 05:52:17PM +0000, Frank Wunderlich wrote:
> Hi Vladimir
> 
> Thanks for the patch and sorry for my delay...i was away this weekend so i was not able to test.
> 
> traffic works again (but there is only read now) and this is the result of your debug prints:
> 
> root@bpi-r3:~# dmesg | grep SGMSYS_QPHY_WRAP_CTRL
> [    2.706963] SGMSYS_QPHY_WRAP_CTRL = 0x501, intending to write 0x500
> [    9.134081] SGMSYS_QPHY_WRAP_CTRL = 0x500, intending to write 0x500
> 
> R3/mt7986 has 2 MAC, and switch is on the first, so value will change, not sure why this is different.
> 
> i have not found SGMSYS_QPHY_WRAP_CTRL or something related with polarity in ethernet/mac-
> (drivers/net/ethernet/mediatek/mtk_eth_soc.c) or switch-driver (drivers/net/dsa/mt7530{,-mdio}.c)
> in case they manipulate this register too (of course they should not). Also looked into the pcs-handling
> in both drivers, but see nothing related to polarity. And looked for possible duplicate register const
> definition (other name for 0xec).

This result means that your default QPHY_WRAP_CTRL register value has
the SGMII_PN_SWAP_TX bit set. Whether that comes from U-Boot or hardware
default or otherwise, it doesn't really matter. Curious that the
SGMII_SW_RESET doesn't clear TX inversion, though. I guess you wouldn't
have documentation that would suggest this setting is sticky?

In Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml,
it is not specified what happens when the "mediatek,pnswap" property is
missing. I thought the most logical thing would be for the lane
polarities to not be swapped - because how would you describe normal
lane polarities otherwise? My bad for thinking the original vendor
bindings were more sane than they were.

The only way to describe the polarities that this SGMSYS block needs on
a particular board is to use the newly introduced 'rx-polarity =
<PHY_POL_NORMAL>' and 'tx-polarity = <PHY_POL_INVERT>'. Which I strongly
recommend you to do, even if the attached patch should restore
functionality with your current device tree.

[-- Attachment #2: 0001-net-pcs-pcs-mtk-lynxi-preserve-lane-polarities-when-.patch --]
[-- Type: text/x-diff, Size: 3080 bytes --]

From 6b5fe06ec16e8a1e752fc871c135d2f12a37ce33 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Thu, 26 Mar 2026 23:46:46 +0200
Subject: [PATCH] net: pcs: pcs-mtk-lynxi: preserve lane polarities when not
 described in fwnode

Frank Wunderlich reports that the BPI-R3 board has a default
SGMSYS_QPHY_WRAP_CTRL = 0x501, aka TX inverted and RX not inverted.
At the same time, neither rx-polarity/tx-polarity nor mediatek,pnswap
are present in the device tree.

The original driver logic was to enable both TX inversion and RX
inversion when finding mediatek,pnswap in the device tree, and leave
SGMSYS_QPHY_WRAP_CTRL to its default value otherwise.

The blamed commit has broken that by assuming that a missing
mediatek,pnswap would mean non-inverting polarity.

Restore the original behaviour by reading the SGMSYS_QPHY_WRAP_CTRL
value and using it as a default polarity if mediatek,pnswap and the new
rx-polarity/tx-polarity are all unset.

Fixes: 8871389da151 ("net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"")
Reported-by: Frank Wunderlich <frank.wunderlich@linux.dev>
Closes: https://lore.kernel.org/netdev/e0ad52862d34cf4e0169c9850a7f164f127d0093@linux.dev/
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
 drivers/net/pcs/pcs-mtk-lynxi.c | 27 +++++++++++++++++++++++++--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c
index c12f8087af9b..7518c98fa98a 100644
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -126,11 +126,24 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
 {
 	struct fwnode_handle *fwnode = mpcs->fwnode, *pcs_fwnode;
 	unsigned int pol, default_pol = PHY_POL_NORMAL;
-	unsigned int val = 0;
+	unsigned int val = 0, orig;
+	bool has_legacy_prop;
 	int ret;
 
-	if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
+	ret = regmap_read(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, &orig);
+	if (ret)
+		return ret;
+
+	/* RX polarity:
+	 * - if standard 'rx-polarity' exists in 'pcs' subnode, follow that
+	 * - if 'mediatek,pnswap' is set, invert RX polarity
+	 * - otherwise, leave unchanged
+	 */
+	has_legacy_prop = fwnode_property_read_bool(fwnode, "mediatek,pnswap");
+	if (has_legacy_prop || FIELD_GET(SGMII_PN_SWAP_RX, orig))
 		default_pol = PHY_POL_INVERT;
+	else
+		default_pol = PHY_POL_NORMAL;
 
 	pcs_fwnode = fwnode_get_named_child_node(fwnode, "pcs");
 
@@ -144,6 +157,16 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
 	if (pol == PHY_POL_INVERT)
 		val |= SGMII_PN_SWAP_RX;
 
+	/* And TX polarity:
+	 * - if standard 'tx-polarity' exists in 'pcs' subnode, follow that
+	 * - if 'mediatek,pnswap' is set, invert TX polarity
+	 * - otherwise, leave unchanged
+	 */
+	if (has_legacy_prop || FIELD_GET(SGMII_PN_SWAP_TX, orig))
+		default_pol = PHY_POL_INVERT;
+	else
+		default_pol = PHY_POL_NORMAL;
+
 	ret = phy_get_tx_polarity(pcs_fwnode, phy_modes(interface),
 				  BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
 				  default_pol, &pol);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-03-30 19:04         ` Vladimir Oltean
@ 2026-04-02  5:50           ` Frank Wunderlich
  2026-04-02  9:53             ` Vladimir Oltean
  0 siblings, 1 reply; 15+ messages in thread
From: Frank Wunderlich @ 2026-04-02  5:50 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
	Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
	Sean Wang, Felix Fietkau

Hi,

i tried using these properties in sgmiisys0 node (which should be mapped to mac0 and the mt7530 switch) without success [1].

it looks like these properties are not read somewhere.

the flow is

mtk_probe (eth driver)

if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
	err = mtk_sgmii_init(eth);

and there calling mtk_pcs_lynxi_create with the sgmiisys-node (for each mac, so imho mac0=sgmiisys0)
but handling the sgmiisys only as syscon, not a "real" pcs node [2].

but your new code calls phy_get_tx_polarity and should read out this properties, but from subnode "pcs", so next try was

&sgmiisys0 {
	pcs {
		rx-polarity = <PHY_POL_NORMAL>;
		tx-polarity = <PHY_POL_INVERT>;
	};
};

which results in completely strange behaviour (looks like sgmiisys1 is mapped to mac0, but based on code in mtk_sgmii_init 0=0 should be right):

[    2.765218] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
[    9.143849] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x501

but nevertheless i tried changing sgmiisys0 to sgmiisys1 and got the dame result as before

[    2.713644] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
[    9.061509] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x500

i can only change the second serdes with sgmiisys0, but not the first.

mapping between mac and sgmiisys in dts in mt7986a.dtsi [3] are like this:

eth: ethernet@15100000 {
	compatible = "mediatek,mt7986-eth";
	mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
	...
};

&eth {
	status = "okay";

	gmac0: mac@0 {
		compatible = "mediatek,eth-mac";
	...
	};

	gmac1: mac@1 {
		compatible = "mediatek,eth-mac";
	...
	};
};

maybe it is time to revive the PCS framework discussion ([4]-[6])?

[1] https://github.com/frank-w/BPI-Router-Linux/commit/4846a7bb352fe5911136cba33813f099bac035fd
[2] https://elixir.bootlin.com/linux/v7.0-rc4/source/drivers/net/ethernet/mediatek/mtk_eth_soc.c#L5001
[3] https://elixir.bootlin.com/linux/v7.0-rc4/source/arch/arm64/boot/dts/mediatek/mt7986a.dtsi#L528

[4] * https://patchwork.kernel.org/project/netdevbpf/patch/20250610233134.3588011-4-sean.anderson@linux.dev/ (v6)
> pcs-framework itself had not yet got a response from netdev maintainer (only other parts)
[5] * https://patchwork.kernel.org/project/netdevbpf/patch/20250511201250.3789083-4-ansuelsmth@gmail.com/ (v4)
> discussion: https://lore.kernel.org/netdev/20250511201250.3789083-1-ansuelsmth@gmail.com/
[6] * https://patchwork.kernel.org/project/netdevbpf/patch/ba4e359584a6b3bc4b3470822c42186d5b0856f9.1721910728.git.daniel@makrotopia.org/
> discussion: https://patchwork.kernel.org/project/netdevbpf/patch/8aa905080bdb6760875d62cb3b2b41258837f80e.1702352117.git.daniel@makrotopia.org/

Am 30. März 2026 um 21:04 schrieb "Vladimir Oltean" <vladimir.oltean@nxp.com mailto:vladimir.oltean@nxp.com?to=%22Vladimir%20Oltean%22%20%3Cvladimir.oltean%40nxp.com%3E >:
> 
> Hi Frank,
> 
> On Mon, Mar 30, 2026 at 05:52:17PM +0000, Frank Wunderlich wrote:
> 
> > 
> > Hi Vladimir
> >  
> >  Thanks for the patch and sorry for my delay...i was away this weekend so i was not able to test.
> >  
> >  traffic works again (but there is only read now) and this is the result of your debug prints:
> >  
> >  root@bpi-r3:~# mailto:root@bpi-r3:~#  dmesg | grep SGMSYS_QPHY_WRAP_CTRL
> >  [ 2.706963] SGMSYS_QPHY_WRAP_CTRL = 0x501, intending to write 0x500
> >  [ 9.134081] SGMSYS_QPHY_WRAP_CTRL = 0x500, intending to write 0x500
> >  
> >  R3/mt7986 has 2 MAC, and switch is on the first, so value will change, not sure why this is different.
> >  
> >  i have not found SGMSYS_QPHY_WRAP_CTRL or something related with polarity in ethernet/mac-
> >  (drivers/net/ethernet/mediatek/mtk_eth_soc.c) or switch-driver (drivers/net/dsa/mt7530{,-mdio}.c)
> >  in case they manipulate this register too (of course they should not). Also looked into the pcs-handling
> >  in both drivers, but see nothing related to polarity. And looked for possible duplicate register const
> >  definition (other name for 0xec).
> > 
> This result means that your default QPHY_WRAP_CTRL register value has
> the SGMII_PN_SWAP_TX bit set. Whether that comes from U-Boot or hardware
> default or otherwise, it doesn't really matter. Curious that the
> SGMII_SW_RESET doesn't clear TX inversion, though. I guess you wouldn't
> have documentation that would suggest this setting is sticky?
> 
> In Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml,
> it is not specified what happens when the "mediatek,pnswap" property is
> missing. I thought the most logical thing would be for the lane
> polarities to not be swapped - because how would you describe normal
> lane polarities otherwise? My bad for thinking the original vendor
> bindings were more sane than they were.
> 
> The only way to describe the polarities that this SGMSYS block needs on
> a particular board is to use the newly introduced 'rx-polarity =
> <PHY_POL_NORMAL>' and 'tx-polarity = <PHY_POL_INVERT>'. Which I strongly
> recommend you to do, even if the attached patch should restore
> functionality with your current device tree.
> 

regards Frank

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-04-02  5:50           ` Frank Wunderlich
@ 2026-04-02  9:53             ` Vladimir Oltean
  2026-04-03  8:23               ` Frank Wunderlich
  0 siblings, 1 reply; 15+ messages in thread
From: Vladimir Oltean @ 2026-04-02  9:53 UTC (permalink / raw)
  To: Frank Wunderlich
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
	Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
	Sean Wang, Felix Fietkau

On Thu, Apr 02, 2026 at 05:50:33AM +0000, Frank Wunderlich wrote:
> Hi,

Hi,

Please don't top-post :(

> i tried using these properties in sgmiisys0 node (which should be mapped to mac0 and the mt7530 switch) without success [1].
> 
> it looks like these properties are not read somewhere.

Can you please clarify whether your problem is with the SerDes connected
to a switch port or to a GMAC?

Because if to a switch port, mt7531_create_sgmii() doesn't have any
phandle to the SGMIISYS. That was from existing code.

		pcs = mtk_pcs_lynxi_create(priv->dev, NULL, regmap,
					   MT7531_PHYA_CTRL_SIGNAL3);

The LynxI PCS will be instantiated without a fwnode and only the
defaults will apply.

> the flow is
> 
> mtk_probe (eth driver)
> 
> if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
> 	err = mtk_sgmii_init(eth);
> 
> and there calling mtk_pcs_lynxi_create with the sgmiisys-node (for each mac, so imho mac0=sgmiisys0)
> but handling the sgmiisys only as syscon, not a "real" pcs node [2].
> 
> but your new code calls phy_get_tx_polarity and should read out this properties, but from subnode "pcs", so next try was
> 
> &sgmiisys0 {
> 	pcs {
> 		rx-polarity = <PHY_POL_NORMAL>;
> 		tx-polarity = <PHY_POL_INVERT>;
> 	};
> };
> 
> which results in completely strange behaviour (looks like sgmiisys1 is mapped to mac0, but based on code in mtk_sgmii_init 0=0 should be right):
> 
> [    2.765218] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
> [    9.143849] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x501
> 
> but nevertheless i tried changing sgmiisys0 to sgmiisys1 and got the dame result as before
> 
> [    2.713644] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
> [    9.061509] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x500
> 
> i can only change the second serdes with sgmiisys0, but not the first.

I assume the second SerDes is mapped to a GMAC port which does
instantiate the LynxI PCS with a fwnode, right? If so, the behaviour is
consistent with the code. Only mtk-soc-eth uses mediatek,sgmiisys AFAICS.

> mapping between mac and sgmiisys in dts in mt7986a.dtsi [3] are like this:
> 
> eth: ethernet@15100000 {
> 	compatible = "mediatek,mt7986-eth";
> 	mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
> 	...
> };
> 
> &eth {
> 	status = "okay";
> 
> 	gmac0: mac@0 {
> 		compatible = "mediatek,eth-mac";
> 	...
> 	};
> 
> 	gmac1: mac@1 {
> 		compatible = "mediatek,eth-mac";
> 	...
> 	};
> };
> 
> maybe it is time to revive the PCS framework discussion ([4]-[6])?
> 
> [1] https://github.com/frank-w/BPI-Router-Linux/commit/4846a7bb352fe5911136cba33813f099bac035fd
> [2] https://elixir.bootlin.com/linux/v7.0-rc4/source/drivers/net/ethernet/mediatek/mtk_eth_soc.c#L5001
> [3] https://elixir.bootlin.com/linux/v7.0-rc4/source/arch/arm64/boot/dts/mediatek/mt7986a.dtsi#L528
> 
> [4] * https://patchwork.kernel.org/project/netdevbpf/patch/20250610233134.3588011-4-sean.anderson@linux.dev/ (v6)
> > pcs-framework itself had not yet got a response from netdev maintainer (only other parts)
> [5] * https://patchwork.kernel.org/project/netdevbpf/patch/20250511201250.3789083-4-ansuelsmth@gmail.com/ (v4)
> > discussion: https://lore.kernel.org/netdev/20250511201250.3789083-1-ansuelsmth@gmail.com/
> [6] * https://patchwork.kernel.org/project/netdevbpf/patch/ba4e359584a6b3bc4b3470822c42186d5b0856f9.1721910728.git.daniel@makrotopia.org/
> > discussion: https://patchwork.kernel.org/project/netdevbpf/patch/8aa905080bdb6760875d62cb3b2b41258837f80e.1702352117.git.daniel@makrotopia.org/

I'm not exactly sure how device+driver for the PCS devices would help in
this case though? Because the LynxI PCS driver would just retrieve the
fwnode on its own, rather than it being passed by the mtk_pcs_lynxi_create()
caller?

We need to have a very good model of what happens when the PCS provider
goes away, especially in multi-port scenarios. It is a similar issue as
to what happens when a phy_device goes away.
https://lore.kernel.org/netdev/20260311153421.u454m3e4blkstymt@skbuf/

I'm not saying "let's not do that", but we'd effectively introducing an
issue that currently does not exist, with the PCS lifetime being managed
by the consumer.

Do you have any better idea by now why SGMSYS_QPHY_WRAP_CTRL is 0x501
for SGMIISYS #0? Is that its out-of-reset value?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
  2026-04-02  9:53             ` Vladimir Oltean
@ 2026-04-03  8:23               ` Frank Wunderlich
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wunderlich @ 2026-04-03  8:23 UTC (permalink / raw)
  To: Vladimir Oltean
  Cc: netdev, devicetree, linux-kernel, linux-mediatek, Daniel Golle,
	Horatiu Vultur, Bj√∏rn Mork, Andrew Lunn,
	Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Matthias Brugger, AngeloGioacchino Del Regno,
	Eric Woudstra, Alexander Couzens, Chester A. Unal, DENG Qingfang,
	Sean Wang, Felix Fietkau



Am 2. April 2026 11:53:00 MESZ schrieb Vladimir Oltean <vladimir.oltean@nxp.com>:
>On Thu, Apr 02, 2026 at 05:50:33AM +0000, Frank Wunderlich wrote:
>> Hi,
>
>Hi,
>
>Please don't top-post :(

Sorry about that. Try to do better future :)

I keep context for now (not removing my findings from early mail),i hope it is ok.

Maybe daniel or mtk can respond if my understanding is wrong.

>> i tried using these properties in sgmiisys0 node (which should be mapped to mac0 and the mt7530 switch) without success [1].
>> 
>> it looks like these properties are not read somewhere.
>
>Can you please clarify whether your problem is with the SerDes connected
>to a switch port or to a GMAC?

From my tests it looks like the issue is on switch side.

>Because if to a switch port, mt7531_create_sgmii() doesn't have any
>phandle to the SGMIISYS. That was from existing code.
>
>		pcs = mtk_pcs_lynxi_create(priv->dev, NULL, regmap,
>					   MT7531_PHYA_CTRL_SIGNAL3);
>
>The LynxI PCS will be instantiated without a fwnode and only the
>defaults will apply.

This was a good hint, i had only seen the pcs call for mac.

>> the flow is
>> 
>> mtk_probe (eth driver)
>> 
>> if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
>> 	err = mtk_sgmii_init(eth);
>> 
>> and there calling mtk_pcs_lynxi_create with the sgmiisys-node (for each mac, so imho mac0=sgmiisys0)
>> but handling the sgmiisys only as syscon, not a "real" pcs node [2].
>> 
>> but your new code calls phy_get_tx_polarity and should read out this properties, but from subnode "pcs", so next try was
>> 
>> &sgmiisys0 {
>> 	pcs {
>> 		rx-polarity = <PHY_POL_NORMAL>;
>> 		tx-polarity = <PHY_POL_INVERT>;
>> 	};
>> };
>> 
>> which results in completely strange behaviour (looks like sgmiisys1 is mapped to mac0, but based on code in mtk_sgmii_init 0=0 should be right):
>> 
>> [    2.765218] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
>> [    9.143849] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x501
>> 
>> but nevertheless i tried changing sgmiisys0 to sgmiisys1 and got the dame result as before
>> 
>> [    2.713644] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x500
>> [    9.061509] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x500
>> 
>> i can only change the second serdes with sgmiisys0, but not the first.
>
>I assume the second SerDes is mapped to a GMAC port which does
>instantiate the LynxI PCS with a fwnode, right? If so, the behaviour is
>consistent with the code. Only mtk-soc-eth uses mediatek,sgmiisys AFAICS.
>
>> mapping between mac and sgmiisys in dts in mt7986a.dtsi [3] are like this:
>> 
>> eth: ethernet@15100000 {
>> 	compatible = "mediatek,mt7986-eth";
>> 	mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
>> 	...
>> };
>> 
>> &eth {
>> 	status = "okay";
>> 
>> 	gmac0: mac@0 {
>> 		compatible = "mediatek,eth-mac";
>> 	...
>> 	};
>> 
>> 	gmac1: mac@1 {
>> 		compatible = "mediatek,eth-mac";
>> 	...
>> 	};
>> };
>> 
>> maybe it is time to revive the PCS framework discussion ([4]-[6])?
>> 
>> [1] https://github.com/frank-w/BPI-Router-Linux/commit/4846a7bb352fe5911136cba33813f099bac035fd
>> [2] https://elixir.bootlin.com/linux/v7.0-rc4/source/drivers/net/ethernet/mediatek/mtk_eth_soc.c#L5001
>> [3] https://elixir.bootlin.com/linux/v7.0-rc4/source/arch/arm64/boot/dts/mediatek/mt7986a.dtsi#L528
>> 
>> [4] * https://patchwork.kernel.org/project/netdevbpf/patch/20250610233134.3588011-4-sean.anderson@linux.dev/ (v6)
>> > pcs-framework itself had not yet got a response from netdev maintainer (only other parts)
>> [5] * https://patchwork.kernel.org/project/netdevbpf/patch/20250511201250.3789083-4-ansuelsmth@gmail.com/ (v4)
>> > discussion: https://lore.kernel.org/netdev/20250511201250.3789083-1-ansuelsmth@gmail.com/
>> [6] * https://patchwork.kernel.org/project/netdevbpf/patch/ba4e359584a6b3bc4b3470822c42186d5b0856f9.1721910728.git.daniel@makrotopia.org/
>> > discussion: https://patchwork.kernel.org/project/netdevbpf/patch/8aa905080bdb6760875d62cb3b2b41258837f80e.1702352117.git.daniel@makrotopia.org/
>
>I'm not exactly sure how device+driver for the PCS devices would help in
>this case though? Because the LynxI PCS driver would just retrieve the
>fwnode on its own, rather than it being passed by the mtk_pcs_lynxi_create()
>caller?

Imho it could be more general and cleaner than calling "external" function in code. If pcs acts
as own device i would see which dtnode is assigned to it...here i guessed both calls were
from mac,but one was from mac and one from switch.
I tried adding prints before the lynxi call,but this does not make it clean from where it comes (i guess because of threading)...but this could be understanding issue on my side.

It looked like this:

root@bpi-r3:~# dmesg | grep 'SGMSYS_QPHY_WRAP_CTRL\|pcs'
[    2.155221] mtk_soc_eth 15100000.ethernet: create sgmii pcs for mac #0
[    2.168308] mtk_soc_eth 15100000.ethernet: create sgmii pcs for mac #1
[    2.699744] mt7530-mdio mdio-bus:1f: add lynxi pcs for switch (port5)
[    2.706773] mt7530-mdio mdio-bus:1f: add lynxi pcs for switch (port6)
[    2.707881] SGMSYS_QPHY_WRAP_CTRL = 0x501, will write 0x501
[    9.081259] SGMSYS_QPHY_WRAP_CTRL = 0x500, will write 0x500

>We need to have a very good model of what happens when the PCS provider
>goes away, especially in multi-port scenarios. It is a similar issue as
>to what happens when a phy_device goes away.
>https://lore.kernel.org/netdev/20260311153421.u454m3e4blkstymt@skbuf/
>
>I'm not saying "let's not do that", but we'd effectively introducing an
>issue that currently does not exist, with the PCS lifetime being managed
>by the consumer.
>
>Do you have any better idea by now why SGMSYS_QPHY_WRAP_CTRL is 0x501
>for SGMIISYS #0? Is that its out-of-reset value?

We guess that switch takes this value somehow from an efuse or similar.

I have 2 ways to fix this broken state:

1) to keep dts backward compatibility and due to undocumented behaviour i prefer this patch:

--- a/drivers/net/pcs/pcs-mtk-lynxi.c
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
@@ -129,6 +129,9 @@ static int mtk_pcs_config_polarity(struct mtk_pcs_lynxi *mpcs,
 	unsigned int val = 0, tmp;
 	int ret;
 
+	if (!fwnode)
+		return 0;
+
 	if (fwnode_property_read_bool(fwnode, "mediatek,pnswap"))
 		default_pol = PHY_POL_INVERT;

2) document pcs polarity (i'm still unsure if this is really correct as i cannot measure in hardware,just from software debugging...but not sure if the SGMSYS_QPHY_WRAP_CTRL offset is valid on switch regmap too) - it looks for me that by default is different between mac and switch side:

<https://github.com/frank-w/BPI-Router-Linux/commit/f693e2ed24287ce1e125d7f6202e14e263cc564d>

And add dts nodes like this:
<https://github.com/frank-w/BPI-Router-Linux/commit/4f7bce943dda614d24431d63adad65f1117a7f6d>

If i set same polarity to mac it is broken (thats why sgmiisys0 is disabled). I guess the pnswap property means "invert the default behaviour" and not "use inverted polarity compared to standard" and mac and switch use the same polarity with different values of the corresponding registers.

Based on my register documentation of mt7531 ("MT7531_Reference_Manual_for_Development_Board.pdf" page 729) i see

000050EC = QPHY_WRAP_CTRL
Bit 0
1'b1 : inversed TX_BIT_POLARITY TX bit polarity control (TX default inversed in MT7531)

Where bit 1 is only defined as "RX bit polarity control"

So my guess is that tx is inverted in hardware,but tx-bit is set in efuse to get the POL_NORMAL.

I did not find the register in my mt7986 register documentation...seems complete networking part is missing.

I do not expect that board changes polarity in hardware...

Regards Frank

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-04-03  8:23 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-19  9:12 [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties Vladimir Oltean
2026-01-19  9:12 ` [PATCH v4 net-next 1/5] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx" Vladimir Oltean
2026-01-19  9:12 ` [PATCH v4 net-next 2/5] net: phy: air_en8811h: " Vladimir Oltean
2026-01-19 15:33   ` Maxime Chevallier
2026-01-19  9:12 ` [PATCH v4 net-next 3/5] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap" Vladimir Oltean
2026-01-19  9:12 ` [PATCH v4 net-next 4/5] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS Vladimir Oltean
2026-01-19  9:12 ` [PATCH v4 net-next 5/5] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap" Vladimir Oltean
2026-03-24  6:36   ` Frank Wunderlich
2026-03-26 21:54     ` Vladimir Oltean
2026-03-30 17:52       ` Frank Wunderlich
2026-03-30 19:04         ` Vladimir Oltean
2026-04-02  5:50           ` Frank Wunderlich
2026-04-02  9:53             ` Vladimir Oltean
2026-04-03  8:23               ` Frank Wunderlich
2026-01-22  4:00 ` [PATCH v4 net-next 0/5] PHY polarity inversion via generic device tree properties patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox