* [PATCH v2 net-next 01/10] dt-bindings: phy: rename transmit-amplitude.yaml to phy-common-props.yaml
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
@ 2026-01-03 21:03 ` Vladimir Oltean
2026-01-03 21:03 ` [PATCH v2 net-next 02/10] dt-bindings: phy-common-props: create a reusable "protocol-names" definition Vladimir Oltean
` (8 subsequent siblings)
9 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:03 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
I would like to add more properties similar to tx-p2p-microvolt, and I
don't think it makes sense to create one schema for each such property
(transmit-amplitude.yaml, lane-polarity.yaml, transmit-equalization.yaml
etc).
Instead, let's rename to phy-common-props.yaml, which makes it a more
adequate host schema for all the above properties.
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
.../{transmit-amplitude.yaml => phy-common-props.yaml} | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
rename Documentation/devicetree/bindings/phy/{transmit-amplitude.yaml => phy-common-props.yaml} (90%)
diff --git a/Documentation/devicetree/bindings/phy/transmit-amplitude.yaml b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
similarity index 90%
rename from Documentation/devicetree/bindings/phy/transmit-amplitude.yaml
rename to Documentation/devicetree/bindings/phy/phy-common-props.yaml
index 617f3c0b3dfb..255205ac09cd 100644
--- a/Documentation/devicetree/bindings/phy/transmit-amplitude.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
@@ -1,14 +1,14 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/phy/transmit-amplitude.yaml#
+$id: http://devicetree.org/schemas/phy/phy-common-props.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Common PHY and network PCS transmit amplitude property
+title: Common PHY and network PCS properties
description:
- Binding describing the peak-to-peak transmit amplitude for common PHYs
- and network PCSes.
+ Common PHY and network PCS properties, such as peak-to-peak transmit
+ amplitude.
maintainers:
- Marek Behún <kabel@kernel.org>
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v2 net-next 02/10] dt-bindings: phy-common-props: create a reusable "protocol-names" definition
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
2026-01-03 21:03 ` [PATCH v2 net-next 01/10] dt-bindings: phy: rename transmit-amplitude.yaml to phy-common-props.yaml Vladimir Oltean
@ 2026-01-03 21:03 ` Vladimir Oltean
2026-01-06 18:23 ` Rob Herring (Arm)
2026-01-03 21:03 ` [PATCH v2 net-next 03/10] dt-bindings: phy-common-props: ensure protocol-names are unique Vladimir Oltean
` (7 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:03 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Other properties also need to be defined per protocol than just
tx-p2p-microvolt-names. Create a common definition to avoid copying a 55
line property.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: none
.../bindings/phy/phy-common-props.yaml | 34 +++++++++++--------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/phy-common-props.yaml b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
index 255205ac09cd..775f4dfe3cc3 100644
--- a/Documentation/devicetree/bindings/phy/phy-common-props.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
@@ -13,22 +13,12 @@ description:
maintainers:
- Marek Behún <kabel@kernel.org>
-properties:
- tx-p2p-microvolt:
+$defs:
+ protocol-names:
description:
- Transmit amplitude voltages in microvolts, peak-to-peak. If this property
- contains multiple values for various PHY modes, the
- 'tx-p2p-microvolt-names' property must be provided and contain
- corresponding mode names.
-
- tx-p2p-microvolt-names:
- description: |
- Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
- property. Required only if multiple voltages are provided.
-
- If a value of 'default' is provided, the system should use it for any PHY
- mode that is otherwise not defined here. If 'default' is not provided, the
- system should use manufacturer default value.
+ Names of the PHY modes. If a value of 'default' is provided, the system
+ should use it for any PHY mode that is otherwise not defined here. If
+ 'default' is not provided, the system should use manufacturer default value.
minItems: 1
maxItems: 16
items:
@@ -89,6 +79,20 @@ properties:
- mipi-dphy-univ
- mipi-dphy-v2.5-univ
+properties:
+ tx-p2p-microvolt:
+ description:
+ Transmit amplitude voltages in microvolts, peak-to-peak. If this property
+ contains multiple values for various PHY modes, the
+ 'tx-p2p-microvolt-names' property must be provided and contain
+ corresponding mode names.
+
+ tx-p2p-microvolt-names:
+ description:
+ Names of the modes corresponding to voltages in the 'tx-p2p-microvolt'
+ property. Required only if multiple voltages are provided.
+ $ref: "#/$defs/protocol-names"
+
dependencies:
tx-p2p-microvolt-names: [ tx-p2p-microvolt ]
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v2 net-next 02/10] dt-bindings: phy-common-props: create a reusable "protocol-names" definition
2026-01-03 21:03 ` [PATCH v2 net-next 02/10] dt-bindings: phy-common-props: create a reusable "protocol-names" definition Vladimir Oltean
@ 2026-01-06 18:23 ` Rob Herring (Arm)
0 siblings, 0 replies; 21+ messages in thread
From: Rob Herring (Arm) @ 2026-01-06 18:23 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Daniel Golle, Matthias Brugger, Bjørn Mork,
AngeloGioacchino Del Regno, Krzysztof Kozlowski, Eric Woudstra,
Lee Jones, devicetree, Eric Dumazet, linux-mediatek,
Marek Behún, Russell King, Vinod Koul, linux-phy,
Neil Armstrong, linux-kernel, Conor Dooley, David S. Miller,
Paolo Abeni, Horatiu Vultur, Patrice Chotard, Heiner Kallweit,
Andrew Lunn, netdev, Jakub Kicinski, linux-arm-kernel
On Sat, 03 Jan 2026 23:03:55 +0200, Vladimir Oltean wrote:
> Other properties also need to be defined per protocol than just
> tx-p2p-microvolt-names. Create a common definition to avoid copying a 55
> line property.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> v1->v2: none
>
> .../bindings/phy/phy-common-props.yaml | 34 +++++++++++--------
> 1 file changed, 19 insertions(+), 15 deletions(-)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 net-next 03/10] dt-bindings: phy-common-props: ensure protocol-names are unique
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
2026-01-03 21:03 ` [PATCH v2 net-next 01/10] dt-bindings: phy: rename transmit-amplitude.yaml to phy-common-props.yaml Vladimir Oltean
2026-01-03 21:03 ` [PATCH v2 net-next 02/10] dt-bindings: phy-common-props: create a reusable "protocol-names" definition Vladimir Oltean
@ 2026-01-03 21:03 ` Vladimir Oltean
2026-01-06 18:22 ` Rob Herring (Arm)
2026-01-03 21:03 ` [PATCH v2 net-next 04/10] dt-bindings: phy-common-props: RX and TX lane polarity inversion Vladimir Oltean
` (6 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:03 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Rob Herring points out that "The default for .*-names is the entries
don't have to be unique.":
https://lore.kernel.org/linux-phy/20251204155219.GA1533839-robh@kernel.org/
Let's use uniqueItems: true to make sure the schema enforces this. It
doesn't make sense in this case to have duplicate properties for the
same SerDes protocol.
Note that this can only be done with the $defs + $ref pattern as
established by the previous commit. When the tx-p2p-microvolt-names
constraints were expressed directly under "properties", it would have
been validated by the string-array meta-schema, which does not support
the 'uniqueItems' keyword as can be seen below.
properties:tx-p2p-microvolt-names: Additional properties are not allowed ('uniqueItems' was unexpected)
from schema $id: http://devicetree.org/meta-schemas/string-array.yaml
Suggested-by: Rob Herring <robh@kernel.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: patch is new
Documentation/devicetree/bindings/phy/phy-common-props.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/phy/phy-common-props.yaml b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
index 775f4dfe3cc3..31bf1382262a 100644
--- a/Documentation/devicetree/bindings/phy/phy-common-props.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
@@ -21,6 +21,7 @@ $defs:
'default' is not provided, the system should use manufacturer default value.
minItems: 1
maxItems: 16
+ uniqueItems: true
items:
enum:
- default
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v2 net-next 03/10] dt-bindings: phy-common-props: ensure protocol-names are unique
2026-01-03 21:03 ` [PATCH v2 net-next 03/10] dt-bindings: phy-common-props: ensure protocol-names are unique Vladimir Oltean
@ 2026-01-06 18:22 ` Rob Herring (Arm)
0 siblings, 0 replies; 21+ messages in thread
From: Rob Herring (Arm) @ 2026-01-06 18:22 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Conor Dooley, Eric Dumazet, Russell King, netdev, linux-phy,
linux-mediatek, AngeloGioacchino Del Regno, David S. Miller,
linux-kernel, Eric Woudstra, devicetree, Neil Armstrong,
Lee Jones, Vinod Koul, Daniel Golle, Jakub Kicinski,
Bjørn Mork, linux-arm-kernel, Patrice Chotard,
Marek Behún, Matthias Brugger, Paolo Abeni,
Krzysztof Kozlowski, Horatiu Vultur, Heiner Kallweit, Andrew Lunn
On Sat, 03 Jan 2026 23:03:56 +0200, Vladimir Oltean wrote:
> Rob Herring points out that "The default for .*-names is the entries
> don't have to be unique.":
> https://lore.kernel.org/linux-phy/20251204155219.GA1533839-robh@kernel.org/
>
> Let's use uniqueItems: true to make sure the schema enforces this. It
> doesn't make sense in this case to have duplicate properties for the
> same SerDes protocol.
>
> Note that this can only be done with the $defs + $ref pattern as
> established by the previous commit. When the tx-p2p-microvolt-names
> constraints were expressed directly under "properties", it would have
> been validated by the string-array meta-schema, which does not support
> the 'uniqueItems' keyword as can be seen below.
>
> properties:tx-p2p-microvolt-names: Additional properties are not allowed ('uniqueItems' was unexpected)
> from schema $id: http://devicetree.org/meta-schemas/string-array.yaml
>
> Suggested-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> ---
> v1->v2: patch is new
>
> Documentation/devicetree/bindings/phy/phy-common-props.yaml | 1 +
> 1 file changed, 1 insertion(+)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 net-next 04/10] dt-bindings: phy-common-props: RX and TX lane polarity inversion
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (2 preceding siblings ...)
2026-01-03 21:03 ` [PATCH v2 net-next 03/10] dt-bindings: phy-common-props: ensure protocol-names are unique Vladimir Oltean
@ 2026-01-03 21:03 ` Vladimir Oltean
2026-01-03 21:03 ` [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity() Vladimir Oltean
` (5 subsequent siblings)
9 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:03 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Differential signaling is a technique for high-speed protocols to be
more resilient to noise. At the transmit side we have a positive and a
negative signal which are mirror images of each other. At the receiver,
if we subtract the negative signal (say of amplitude -A) from the
positive signal (say +A), we recover the original single-ended signal at
twice its original amplitude. But any noise, like one coming from EMI
from outside sources, is supposed to have an almost equal impact upon
the positive (A + E, E being for "error") and negative signal (-A + E).
So (A + E) - (-A + E) eliminates this noise, and this is what makes
differential signaling useful.
Except that in order to work, there must be strict requirements observed
during PCB design and layout, like the signal traces needing to have the
same length and be physically close to each other, and many others.
Sometimes it is not easy to fulfill all these requirements, a simple
case to understand is when on chip A's pins, the positive pin is on the
left and the negative is on the right, but on the chip B's pins (with
which A tries to communicate), positive is on the right and negative on
the left. The signals would need to cross, using vias and other ugly
stuff that affects signal integrity (introduces impedance
discontinuities which cause reflections, etc).
So sometimes, board designers intentionally connect differential lanes
the wrong way, and expect somebody else to invert that signal to recover
useful data. This is where RX and TX polarity inversion comes in as a
generic concept that applies to any high-speed serial protocol as long
as it uses differential signaling.
I've stopped two attempts to introduce more vendor-specific descriptions
of this only in the past month:
https://lore.kernel.org/linux-phy/20251110110536.2596490-1-horatiu.vultur@microchip.com/
https://lore.kernel.org/netdev/20251028000959.3kiac5kwo5pcl4ft@skbuf/
and in the kernel we already have merged:
- "st,px_rx_pol_inv"
- "st,pcie-tx-pol-inv"
- "st,sata-tx-pol-inv"
- "mediatek,pnswap"
- "airoha,pnswap-rx"
- "airoha,pnswap-tx"
and maybe more. So it is pretty general.
One additional element of complexity is introduced by the fact that for
some protocols, receivers can automatically detect and correct for an
inverted lane polarity (example: the PCIe LTSSM does this in the
Polling.Configuration state; the USB 3.1 Link Layer Test Specification
says that the detection and correction of the lane polarity inversion in
SuperSpeed operation shall be enabled in Polling.RxEQ.). Whereas for
other protocols (SGMII, SATA, 10GBase-R, etc etc), the polarity is all
manual and there is no detection mechanism mandated by their respective
standards.
So why would one even describe rx-polarity and tx-polarity for protocols
like PCIe, if it had to always be PHY_POL_AUTO?
Related question: why would we define the polarity as an array per
protocol? Isn't the physical PCB layout protocol-agnostic, and aren't we
describing the same physical reality from the lens of different protocols?
The answer to both questions is because multi-protocol PHYs exist
(supporting e.g. USB2 and USB3, or SATA and PCIe, or PCIe and Ethernet
over the same lane), one would need to manually set the polarity for
SATA/Ethernet, while leaving it at auto for PCIe/USB 3.0+.
I also investigated from another angle: what if polarity inversion in
the PHY is one layer, and then the PCIe/USB3 LTSSM polarity detection is
another layer on top? Then rx-polarity = <PHY_POL_AUTO> doesn't make
sense, it can still be rx-polarity = <PHY_POL_NORMAL> or <PHY_POL_INVERT>,
and the link training state machine figures things out on top of that.
This would radically simplify the design, as the elimination of
PHY_POL_AUTO inherently means that the need for a property array per
protocol also goes away.
I don't know how things are in the general case, but at least in the 10G
and 28G Lynx SerDes blocks from NXP Layerscape devices, this isn't the
case, and there's only a single level of RX polarity inversion: in the
SerDes lane. In the case of PCIe, the controller is in charge of driving
the RDAT_INV bit autonomously, and it is read-only to software.
So the existence of this kind of SerDes lane proves the need for
PHY_POL_AUTO to be a third state.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2:
- logical change: the bindings refer to the described block's I/O
signals, not necessarily device pins. This means that a PCS that needs
to internall invert a polarity to work around an inverting PMA in
order to achieve normal polarity at the pin needs to be described as
PHY_POL_INVERT now.
- clarify that default values are undefined.
- fix a checkpatch issue: duplicated "the the" in rx-polarity description
.../bindings/phy/phy-common-props.yaml | 49 +++++++++++++++++++
include/dt-bindings/phy/phy.h | 4 ++
2 files changed, 53 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/phy-common-props.yaml b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
index 31bf1382262a..b2c709cc1b0d 100644
--- a/Documentation/devicetree/bindings/phy/phy-common-props.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-common-props.yaml
@@ -94,15 +94,64 @@ properties:
property. Required only if multiple voltages are provided.
$ref: "#/$defs/protocol-names"
+ rx-polarity:
+ description:
+ An array of values indicating whether the differential receiver's
+ polarity is inverted. Each value can be one of
+ PHY_POL_NORMAL (0) which means the negative signal is decoded from the
+ RXN input, and the positive signal from the RXP input;
+ PHY_POL_INVERT (1) which means the negative signal is decoded from the
+ RXP input, and the positive signal from the RXN input;
+ PHY_POL_AUTO (2) which means the receiver performs automatic polarity
+ detection and correction, which is a mandatory part of link training for
+ some protocols (PCIe, USB SS).
+
+ The values are defined in <dt-bindings/phy/phy.h>. If the property is
+ absent, the default value is undefined.
+
+ Note that the RXP and RXN inputs refer to the block that this property is
+ under, and do not necessarily directly translate to external pins.
+
+ If this property contains multiple values for various protocols, the
+ 'rx-polarity-names' property must be provided.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ maxItems: 16
+ items:
+ enum: [0, 1, 2]
+
+ rx-polarity-names:
+ $ref: '#/$defs/protocol-names'
+
+ tx-polarity:
+ description:
+ Like 'rx-polarity', except it applies to differential transmitters,
+ and only the values of PHY_POL_NORMAL and PHY_POL_INVERT are possible.
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ maxItems: 16
+ items:
+ enum: [0, 1]
+
+ tx-polarity-names:
+ $ref: '#/$defs/protocol-names'
+
dependencies:
tx-p2p-microvolt-names: [ tx-p2p-microvolt ]
+ rx-polarity-names: [ rx-polarity ]
+ tx-polarity-names: [ tx-polarity ]
additionalProperties: true
examples:
- |
+ #include <dt-bindings/phy/phy.h>
+
phy: phy {
#phy-cells = <1>;
tx-p2p-microvolt = <915000>, <1100000>, <1200000>;
tx-p2p-microvolt-names = "2500base-x", "usb-hs", "usb-ss";
+ rx-polarity = <PHY_POL_AUTO>, <PHY_POL_NORMAL>;
+ rx-polarity-names = "usb-ss", "default";
+ tx-polarity = <PHY_POL_INVERT>;
};
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 6b901b342348..f8d4094f0880 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -24,4 +24,8 @@
#define PHY_TYPE_CPHY 11
#define PHY_TYPE_USXGMII 12
+#define PHY_POL_NORMAL 0
+#define PHY_POL_INVERT 1
+#define PHY_POL_AUTO 2
+
#endif /* _DT_BINDINGS_PHY */
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread* [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity()
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (3 preceding siblings ...)
2026-01-03 21:03 ` [PATCH v2 net-next 04/10] dt-bindings: phy-common-props: RX and TX lane polarity inversion Vladimir Oltean
@ 2026-01-03 21:03 ` Vladimir Oltean
2026-01-07 8:12 ` Bjørn Mork
2026-01-03 21:03 ` [PATCH v2 net-next 06/10] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx" Vladimir Oltean
` (4 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:03 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Add helpers in the generic PHY folder which can be used using 'select
GENERIC_PHY_COMMON_PROPS' from Kconfig, without otherwise needing to
enable GENERIC_PHY.
These helpers need to deal with the slight messiness of the fact that
the polarity properties are arrays per protocol, and with the fact that
there is no default value mandated by the standard properties, all
default values depend on driver and protocol (PHY_POL_NORMAL may be a
good default for SGMII, whereas PHY_POL_AUTO may be a good default for
PCIe).
Push the supported mask of polarities to these helpers, to simplify
drivers such that they don't need to validate what's in the device tree
(or other firmware description).
Add a KUnit test suite to make sure that the API produces the expected
results. The fact that we use fwnode structures means we can validate
with software nodes, and as opposed to the device_property API, we can
bypass the need to have a device structure.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2:
- add KUnit test suite
- replace joint maintainership model with linux-phy being the only tree.
- split the combined return code (if negative, error, if positive, valid
return value) into a single "error or zero" return code and an
unsigned int pointer argument to the returned polarity
- add __must_check to ensure that callers are forced to test for errors
- add a reusable fwnode_get_u32_prop_for_name() helper for further
property parsing
- remove support for looking up polarity of a NULL PHY mode
- introduce phy_get_manual_rx_polarity() and
phy_get_manual_tx_polarity() helpers to reduce boilerplate in simple
drivers
- bug fix: a polarity defined as a single value rather than an array was
not validated against the supported mask
- bug fix: the default polarity was not validated against the supported
mask
- bug fix: wrong error message if the polarity value is unsupported
MAINTAINERS | 10 +
drivers/phy/Kconfig | 22 ++
drivers/phy/Makefile | 2 +
drivers/phy/phy-common-props-test.c | 380 +++++++++++++++++++++++++++
drivers/phy/phy-common-props.c | 216 +++++++++++++++
include/linux/phy/phy-common-props.h | 32 +++
6 files changed, 662 insertions(+)
create mode 100644 drivers/phy/phy-common-props-test.c
create mode 100644 drivers/phy/phy-common-props.c
create mode 100644 include/linux/phy/phy-common-props.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 765ad2daa218..24965eec37c9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10561,6 +10561,16 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
F: include/asm-generic/
F: include/uapi/asm-generic/
+GENERIC PHY COMMON PROPERTIES
+M: Vladimir Oltean <vladimir.oltean@nxp.com>
+L: netdev@vger.kernel.org
+S: Maintained
+Q: https://patchwork.kernel.org/project/netdevbpf/list/
+F: Documentation/devicetree/bindings/phy/phy-common-props.yaml
+F: drivers/phy/phy-common-props-test.c
+F: drivers/phy/phy-common-props.c
+F: include/linux/phy/phy-common-props.h
+
GENERIC PHY FRAMEWORK
M: Vinod Koul <vkoul@kernel.org>
R: Neil Armstrong <neil.armstrong@linaro.org>
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 678dd0452f0a..f082680e1262 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -16,6 +16,28 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this
framework should select this config.
+config GENERIC_PHY_COMMON_PROPS
+ bool
+ help
+ Generic PHY common property parsing.
+
+ Select this from consumer drivers to gain access to helpers for
+ parsing properties from the
+ Documentation/devicetree/bindings/phy/phy-common-props.yaml schema.
+
+config GENERIC_PHY_COMMON_PROPS_TEST
+ tristate "KUnit tests for generic PHY common props" if !KUNIT_ALL_TESTS
+ select GENERIC_PHY_COMMON_PROPS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This builds KUnit tests for the generic PHY common property API.
+
+ For more information on KUnit and unit tests in general,
+ please refer to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+ When in doubt, say N.
+
config GENERIC_PHY_MIPI_DPHY
bool
select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index bfb27fb5a494..4e8ac966064b 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -4,6 +4,8 @@
#
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
+obj-$(CONFIG_GENERIC_PHY_COMMON_PROPS) += phy-common-props.o
+obj-$(CONFIG_GENERIC_PHY_COMMON_PROPS_TEST) += phy-common-props-test.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
diff --git a/drivers/phy/phy-common-props-test.c b/drivers/phy/phy-common-props-test.c
new file mode 100644
index 000000000000..269353891add
--- /dev/null
+++ b/drivers/phy/phy-common-props-test.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-common-props-test.c -- Unit tests for PHY common properties API
+ *
+ * Copyright 2025-2026 NXP
+ */
+#include <kunit/test.h>
+#include <linux/property.h>
+#include <linux/phy/phy-common-props.h>
+#include <dt-bindings/phy/phy.h>
+
+/* Test: rx-polarity has more values than rx-polarity-names */
+static void phy_test_rx_polarity_more_values_than_names(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL };
+ static const char * const rx_pol_names[] = { "sgmii", "2500base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: rx-polarity has 1 value and rx-polarity-names does not exist */
+static void phy_test_rx_polarity_single_value_no_names(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_INVERT };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: rx-polarity-names has more values than rx-polarity */
+static void phy_test_rx_polarity_more_names_than_values(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT };
+ static const char * const rx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: rx-polarity and rx-polarity-names have same length, find the name */
+static void phy_test_rx_polarity_find_by_name(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_AUTO };
+ static const char * const rx_pol_names[] = { "sgmii", "2500base-x", "usb-ss" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL);
+
+ ret = phy_get_manual_rx_polarity(node, "2500base-x", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT);
+
+ ret = phy_get_rx_polarity(node, "usb-ss", BIT(PHY_POL_AUTO),
+ PHY_POL_AUTO, &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_AUTO);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: same length, name not found, no "default" - error */
+static void phy_test_rx_polarity_name_not_found_no_default(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT };
+ static const char * const rx_pol_names[] = { "2500base-x", "1000base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: same length, name not found, but "default" exists */
+static void phy_test_rx_polarity_name_not_found_with_default(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT };
+ static const char * const rx_pol_names[] = { "2500base-x", "default" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: polarity found but value is unsupported */
+static void phy_test_rx_polarity_unsupported_value(struct kunit *test)
+{
+ static const u32 rx_pol[] = { PHY_POL_AUTO };
+ static const char * const rx_pol_names[] = { "sgmii" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_rx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: tx-polarity has more values than tx-polarity-names */
+static void phy_test_tx_polarity_more_values_than_names(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL };
+ static const char * const tx_pol_names[] = { "sgmii", "2500base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: tx-polarity has 1 value and tx-polarity-names does not exist */
+static void phy_test_tx_polarity_single_value_no_names(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_INVERT };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: tx-polarity-names has more values than tx-polarity */
+static void phy_test_tx_polarity_more_names_than_values(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT };
+ static const char * const tx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: tx-polarity and tx-polarity-names have same length, find the name */
+static void phy_test_tx_polarity_find_by_name(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL };
+ static const char * const tx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL);
+
+ ret = phy_get_manual_tx_polarity(node, "2500base-x", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT);
+
+ ret = phy_get_manual_tx_polarity(node, "1000base-x", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: same length, name not found, no "default" - error */
+static void phy_test_tx_polarity_name_not_found_no_default(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT };
+ static const char * const tx_pol_names[] = { "2500base-x", "1000base-x" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EINVAL);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: same length, name not found, but "default" exists */
+static void phy_test_tx_polarity_name_not_found_with_default(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT };
+ static const char * const tx_pol_names[] = { "2500base-x", "default" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT);
+
+ fwnode_remove_software_node(node);
+}
+
+/* Test: polarity found but value is unsupported (AUTO for TX) */
+static void phy_test_tx_polarity_unsupported_value(struct kunit *test)
+{
+ static const u32 tx_pol[] = { PHY_POL_AUTO };
+ static const char * const tx_pol_names[] = { "sgmii" };
+ static const struct property_entry entries[] = {
+ PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol),
+ PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names),
+ {}
+ };
+ struct fwnode_handle *node;
+ unsigned int val;
+ int ret;
+
+ node = fwnode_create_software_node(entries, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
+
+ ret = phy_get_manual_tx_polarity(node, "sgmii", &val);
+ KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP);
+
+ fwnode_remove_software_node(node);
+}
+
+static struct kunit_case phy_common_props_test_cases[] = {
+ KUNIT_CASE(phy_test_rx_polarity_more_values_than_names),
+ KUNIT_CASE(phy_test_rx_polarity_single_value_no_names),
+ KUNIT_CASE(phy_test_rx_polarity_more_names_than_values),
+ KUNIT_CASE(phy_test_rx_polarity_find_by_name),
+ KUNIT_CASE(phy_test_rx_polarity_name_not_found_no_default),
+ KUNIT_CASE(phy_test_rx_polarity_name_not_found_with_default),
+ KUNIT_CASE(phy_test_rx_polarity_unsupported_value),
+ KUNIT_CASE(phy_test_tx_polarity_more_values_than_names),
+ KUNIT_CASE(phy_test_tx_polarity_single_value_no_names),
+ KUNIT_CASE(phy_test_tx_polarity_more_names_than_values),
+ KUNIT_CASE(phy_test_tx_polarity_find_by_name),
+ KUNIT_CASE(phy_test_tx_polarity_name_not_found_no_default),
+ KUNIT_CASE(phy_test_tx_polarity_name_not_found_with_default),
+ KUNIT_CASE(phy_test_tx_polarity_unsupported_value),
+ {}
+};
+
+static struct kunit_suite phy_common_props_test_suite = {
+ .name = "phy-common-props",
+ .test_cases = phy_common_props_test_cases,
+};
+
+kunit_test_suite(phy_common_props_test_suite);
+
+MODULE_DESCRIPTION("Test module for PHY common properties API");
+MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/phy-common-props.c b/drivers/phy/phy-common-props.c
new file mode 100644
index 000000000000..120b5562ade5
--- /dev/null
+++ b/drivers/phy/phy-common-props.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * phy-common-props.c -- Common PHY properties
+ *
+ * Copyright 2025-2026 NXP
+ */
+#include <linux/export.h>
+#include <linux/fwnode.h>
+#include <linux/phy/phy-common-props.h>
+#include <linux/printk.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+/**
+ * fwnode_get_u32_prop_for_name - Find u32 property by name, or default value
+ * @fwnode: Pointer to firmware node, or NULL to use @default_val
+ * @name: Property name used as lookup key in @names_title (must not be NULL)
+ * @props_title: Name of u32 array property holding values
+ * @names_title: Name of string array property holding lookup keys
+ * @default_val: Default value if @fwnode is NULL or @props_title is empty
+ * @val: Pointer to store the returned value
+ *
+ * This function retrieves a u32 value from @props_title based on a name lookup
+ * in @names_title. The value stored in @val is determined as follows:
+ *
+ * - If @fwnode is NULL or @props_title is empty: @default_val is used
+ * - If @props_title has exactly one element and @names_title is empty:
+ * that element is used
+ * - Otherwise: @val is set to the element at the same index where @name is
+ * found in @names_title.
+ * - If @name is not found, the function looks for a "default" entry in
+ * @names_title and uses the corresponding value from @props_title
+ *
+ * When both @props_title and @names_title are present, they must have the
+ * same number of elements (except when @props_title has exactly one element).
+ *
+ * Return: zero on success, negative error on failure.
+ */
+static int fwnode_get_u32_prop_for_name(struct fwnode_handle *fwnode,
+ const char *name,
+ const char *props_title,
+ const char *names_title,
+ unsigned int default_val,
+ unsigned int *val)
+{
+ int err, n_props, n_names, idx = -1;
+ u32 *props;
+
+ if (!name) {
+ pr_err("Lookup key inside \"%s\" is mandatory\n", names_title);
+ return -EINVAL;
+ }
+
+ if (!fwnode) {
+ *val = default_val;
+ return 0;
+ }
+
+ err = fwnode_property_count_u32(fwnode, props_title);
+ if (err < 0)
+ return err;
+ if (err == 0) {
+ *val = default_val;
+ return 0;
+ }
+ n_props = err;
+
+ n_names = fwnode_property_string_array_count(fwnode, names_title);
+ if (n_names >= 0 && n_props != n_names) {
+ pr_err("%pfw mismatch between \"%s\" and \"%s\" property count (%d vs %d)\n",
+ fwnode, props_title, names_title, n_props, n_names);
+ return -EINVAL;
+ }
+
+ idx = fwnode_property_match_string(fwnode, names_title, name);
+ if (idx < 0)
+ idx = fwnode_property_match_string(fwnode, names_title, "default");
+ /*
+ * If the mode name is missing, it can only mean the specified property
+ * is the default one for all modes, so reject any other property count
+ * than 1.
+ */
+ if (idx < 0 && n_props != 1) {
+ pr_err("%pfw \"%s \" property has %d elements, but cannot find \"%s\" in \"%s\" and there is no default value\n",
+ fwnode, props_title, n_props, name, names_title);
+ return -EINVAL;
+ }
+
+ if (n_props == 1) {
+ err = fwnode_property_read_u32(fwnode, props_title, val);
+ if (err)
+ return err;
+
+ return 0;
+ }
+
+ /* We implicitly know idx >= 0 here */
+ props = kcalloc(n_props, sizeof(*props), GFP_KERNEL);
+ if (!props)
+ return -ENOMEM;
+
+ err = fwnode_property_read_u32_array(fwnode, props_title, props, n_props);
+ if (err >= 0)
+ *val = props[idx];
+
+ kfree(props);
+
+ return err;
+}
+
+static int phy_get_polarity_for_mode(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int supported,
+ unsigned int default_val,
+ const char *polarity_prop,
+ const char *names_prop,
+ unsigned int *val)
+{
+ int err;
+
+ err = fwnode_get_u32_prop_for_name(fwnode, mode_name, polarity_prop,
+ names_prop, default_val, val);
+ if (err)
+ return err;
+
+ if (!(supported & BIT(*val))) {
+ pr_err("%d is not a supported value for %pfw '%s' element '%s'\n",
+ *val, fwnode, polarity_prop, mode_name);
+ err = -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+/**
+ * phy_get_rx_polarity - Get RX polarity for PHY differential lane
+ * @fwnode: Pointer to the PHY's firmware node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO
+ * @default_val: Default polarity value if property is missing
+ * @val: Pointer to returned polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int __must_check phy_get_rx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int supported,
+ unsigned int default_val,
+ unsigned int *val)
+{
+ return phy_get_polarity_for_mode(fwnode, mode_name, supported,
+ default_val, "rx-polarity",
+ "rx-polarity-names", val);
+}
+EXPORT_SYMBOL_GPL(phy_get_rx_polarity);
+
+/**
+ * phy_get_tx_polarity - Get TX polarity for PHY differential lane
+ * @fwnode: Pointer to the PHY's firmware node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @supported: Bit mask of PHY_POL_NORMAL and PHY_POL_INVERT
+ * @default_val: Default polarity value if property is missing
+ * @val: Pointer to returned polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int __must_check phy_get_tx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name, unsigned int supported,
+ unsigned int default_val, unsigned int *val)
+{
+ return phy_get_polarity_for_mode(fwnode, mode_name, supported,
+ default_val, "tx-polarity",
+ "tx-polarity-names", val);
+}
+EXPORT_SYMBOL_GPL(phy_get_tx_polarity);
+
+/**
+ * phy_get_manual_rx_polarity - Get manual RX polarity for PHY differential lane
+ * @fwnode: Pointer to the PHY's firmware node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @val: Pointer to returned polarity.
+ *
+ * Helper for PHYs which do not support protocols with automatic RX polarity
+ * detection and correction.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int __must_check phy_get_manual_rx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int *val)
+{
+ return phy_get_rx_polarity(fwnode, mode_name,
+ BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+ PHY_POL_NORMAL, val);
+}
+EXPORT_SYMBOL_GPL(phy_get_manual_rx_polarity);
+
+/**
+ * phy_get_manual_tx_polarity - Get manual TX polarity for PHY differential lane
+ * @fwnode: Pointer to the PHY's firmware node.
+ * @mode_name: The name of the PHY mode to look up.
+ * @val: Pointer to returned polarity.
+ *
+ * Helper for PHYs without any custom default value for the TX polarity.
+ *
+ * Return: zero on success, negative error on failure.
+ */
+int __must_check phy_get_manual_tx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int *val)
+{
+ return phy_get_tx_polarity(fwnode, mode_name,
+ BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT),
+ PHY_POL_NORMAL, val);
+}
+EXPORT_SYMBOL_GPL(phy_get_manual_tx_polarity);
diff --git a/include/linux/phy/phy-common-props.h b/include/linux/phy/phy-common-props.h
new file mode 100644
index 000000000000..680e13de4558
--- /dev/null
+++ b/include/linux/phy/phy-common-props.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * phy-common-props.h -- Common properties for generic PHYs
+ *
+ * Copyright 2025 NXP
+ */
+
+#ifndef __PHY_COMMON_PROPS_H
+#define __PHY_COMMON_PROPS_H
+
+#include <dt-bindings/phy/phy.h>
+
+struct fwnode_handle;
+
+int __must_check phy_get_rx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int supported,
+ unsigned int default_val,
+ unsigned int *val);
+int __must_check phy_get_tx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int supported,
+ unsigned int default_val,
+ unsigned int *val);
+int __must_check phy_get_manual_rx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int *val);
+int __must_check phy_get_manual_tx_polarity(struct fwnode_handle *fwnode,
+ const char *mode_name,
+ unsigned int *val);
+
+#endif /* __PHY_COMMON_PROPS_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity()
2026-01-03 21:03 ` [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity() Vladimir Oltean
@ 2026-01-07 8:12 ` Bjørn Mork
2026-01-10 18:04 ` Vladimir Oltean
0 siblings, 1 reply; 21+ messages in thread
From: Bjørn Mork @ 2026-01-07 8:12 UTC (permalink / raw)
To: Vladimir Oltean
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Vladimir Oltean <vladimir.oltean@nxp.com> writes:
> +static int fwnode_get_u32_prop_for_name(struct fwnode_handle *fwnode,
> + const char *name,
> + const char *props_title,
> + const char *names_title,
> + unsigned int default_val,
> + unsigned int *val)
> +{
> + int err, n_props, n_names, idx = -1;
> + u32 *props;
> +
> + if (!name) {
> + pr_err("Lookup key inside \"%s\" is mandatory\n", names_title);
> + return -EINVAL;
> + }
> +
> + if (!fwnode) {
> + *val = default_val;
> + return 0;
> + }
> +
> + err = fwnode_property_count_u32(fwnode, props_title);
> + if (err < 0)
> + return err;
> + if (err == 0) {
> + *val = default_val;
> + return 0;
> + }
> + n_props = err;
I tried using this in the air_en8811h driver and started wondering if I
have misunderstood something.
The problem I have is that fwnode_property_count_u32() returns -EINVAL
if props_title is missing. So if you have a node with the legacy
"airoha,pnswap-rx" property instead of "rx-polarity", or more common: no
polariy property at all, then we see -EINVAL returned from
phy_get_rx_polarity(). Which is propagated back to config_init() and
the phy fails to attach. That can't be the intention?
The behaviour I expected is described by this test:
/* Test: tx-polarity property is missing */
static void phy_test_tx_polarity_is_missing(struct kunit *test)
{
static const struct property_entry entries[] = {
{}
};
struct fwnode_handle *node;
unsigned int val;
int ret;
node = fwnode_create_software_node(entries, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
ret = phy_get_manual_tx_polarity(node, "sgmi", &val);
KUNIT_EXPECT_EQ(test, ret, 0);
KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL);
fwnode_remove_software_node(node);
}
Bjørn
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity()
2026-01-07 8:12 ` Bjørn Mork
@ 2026-01-10 18:04 ` Vladimir Oltean
2026-01-10 18:08 ` Bjørn Mork
0 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-10 18:04 UTC (permalink / raw)
To: Bjørn Mork
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Hi Bjørn,
On Wed, Jan 07, 2026 at 09:12:28AM +0100, Bjørn Mork wrote:
> Vladimir Oltean <vladimir.oltean@nxp.com> writes:
>
> > +static int fwnode_get_u32_prop_for_name(struct fwnode_handle *fwnode,
> > + const char *name,
> > + const char *props_title,
> > + const char *names_title,
> > + unsigned int default_val,
> > + unsigned int *val)
> > +{
> > + int err, n_props, n_names, idx = -1;
> > + u32 *props;
> > +
> > + if (!name) {
> > + pr_err("Lookup key inside \"%s\" is mandatory\n", names_title);
> > + return -EINVAL;
> > + }
> > +
> > + if (!fwnode) {
> > + *val = default_val;
> > + return 0;
> > + }
> > +
> > + err = fwnode_property_count_u32(fwnode, props_title);
> > + if (err < 0)
> > + return err;
> > + if (err == 0) {
> > + *val = default_val;
> > + return 0;
> > + }
> > + n_props = err;
>
> I tried using this in the air_en8811h driver and started wondering if I
> have misunderstood something.
>
> The problem I have is that fwnode_property_count_u32() returns -EINVAL
> if props_title is missing. So if you have a node with the legacy
> "airoha,pnswap-rx" property instead of "rx-polarity", or more common: no
> polariy property at all, then we see -EINVAL returned from
> phy_get_rx_polarity(). Which is propagated back to config_init() and
> the phy fails to attach. That can't be the intention?
>
> The behaviour I expected is described by this test:
>
>
> /* Test: tx-polarity property is missing */
> static void phy_test_tx_polarity_is_missing(struct kunit *test)
> {
> static const struct property_entry entries[] = {
> {}
> };
> struct fwnode_handle *node;
> unsigned int val;
> int ret;
>
> node = fwnode_create_software_node(entries, NULL);
> KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
>
> ret = phy_get_manual_tx_polarity(node, "sgmi", &val);
> KUNIT_EXPECT_EQ(test, ret, 0);
> KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL);
>
> fwnode_remove_software_node(node);
> }
Thanks for debugging and for the test! This is a regression from v1,
where I just checked the fwnode_property_count_u32() return code for
being <= 0.
I've integrated your test and added one more for RX. Do you have any
further comments, or shall I send an updated v3?
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity()
2026-01-10 18:04 ` Vladimir Oltean
@ 2026-01-10 18:08 ` Bjørn Mork
2026-01-10 18:19 ` Vladimir Oltean
0 siblings, 1 reply; 21+ messages in thread
From: Bjørn Mork @ 2026-01-10 18:08 UTC (permalink / raw)
To: Vladimir Oltean
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Vladimir Oltean <vladimir.oltean@nxp.com> writes:
> I've integrated your test and added one more for RX. Do you have any
> further comments, or shall I send an updated v3?
That was everything I've found.
Bjørn
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity()
2026-01-10 18:08 ` Bjørn Mork
@ 2026-01-10 18:19 ` Vladimir Oltean
0 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-10 18:19 UTC (permalink / raw)
To: Bjørn Mork
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
On Sat, Jan 10, 2026 at 07:08:30PM +0100, Bjørn Mork wrote:
> Vladimir Oltean <vladimir.oltean@nxp.com> writes:
>
> > I've integrated your test and added one more for RX. Do you have any
> > further comments, or shall I send an updated v3?
>
> That was everything I've found.
>
>
> Bjørn
Ok. I'll add your Co-developed-by and Signed-off-by tags for the tests,
if you don't mind. I'll also do some build testing, so I'm not sure if
I'll manage to send v3 today.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 net-next 06/10] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (4 preceding siblings ...)
2026-01-03 21:03 ` [PATCH v2 net-next 05/10] phy: add phy_get_rx_polarity() and phy_get_tx_polarity() Vladimir Oltean
@ 2026-01-03 21:03 ` Vladimir Oltean
2026-01-03 21:04 ` [PATCH v2 net-next 07/10] net: phy: air_en8811h: " Vladimir Oltean
` (3 subsequent siblings)
9 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:03 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Reference the common PHY properties, and update the example to use them.
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
v1->v2: 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] 21+ messages in thread* [PATCH v2 net-next 07/10] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (5 preceding siblings ...)
2026-01-03 21:03 ` [PATCH v2 net-next 06/10] dt-bindings: net: airoha,en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx" Vladimir Oltean
@ 2026-01-03 21:04 ` Vladimir Oltean
2026-01-06 19:03 ` Bjørn Mork
2026-01-03 21:04 ` [PATCH v2 net-next 08/10] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap" Vladimir Oltean
` (2 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:04 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
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>
---
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] 21+ messages in thread* Re: [PATCH v2 net-next 07/10] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
2026-01-03 21:04 ` [PATCH v2 net-next 07/10] net: phy: air_en8811h: " Vladimir Oltean
@ 2026-01-06 19:03 ` Bjørn Mork
2026-01-06 22:16 ` Vladimir Oltean
2026-01-10 18:41 ` Vladimir Oltean
0 siblings, 2 replies; 21+ messages in thread
From: Bjørn Mork @ 2026-01-06 19:03 UTC (permalink / raw)
To: Vladimir Oltean
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
Vladimir Oltean <vladimir.oltean@nxp.com> writes:
> 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
GENERIC_PHY_COMMON_PROPS maybe?
Bjørn
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 net-next 07/10] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
2026-01-06 19:03 ` Bjørn Mork
@ 2026-01-06 22:16 ` Vladimir Oltean
2026-01-10 18:41 ` Vladimir Oltean
1 sibling, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-06 22:16 UTC (permalink / raw)
To: Bjørn Mork
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
On Tue, Jan 06, 2026 at 08:03:50PM +0100, Bjørn Mork wrote:
> Vladimir Oltean <vladimir.oltean@nxp.com> writes:
>
> > 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
>
> GENERIC_PHY_COMMON_PROPS maybe?
Thanks for pointing out the inconsistency with patch 05/10.
Yes, this should have been GENERIC_PHY_COMMON_PROPS.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v2 net-next 07/10] net: phy: air_en8811h: deprecate "airoha,pnswap-rx" and "airoha,pnswap-tx"
2026-01-06 19:03 ` Bjørn Mork
2026-01-06 22:16 ` Vladimir Oltean
@ 2026-01-10 18:41 ` Vladimir Oltean
1 sibling, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-10 18:41 UTC (permalink / raw)
To: Bjørn Mork
Cc: netdev, devicetree, linux-phy, linux-kernel, linux-arm-kernel,
linux-mediatek, Daniel Golle, Horatiu Vultur, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
On Tue, Jan 06, 2026 at 08:03:50PM +0100, Bjørn Mork wrote:
> Vladimir Oltean <vladimir.oltean@nxp.com> writes:
>
> > 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
>
> GENERIC_PHY_COMMON_PROPS maybe?
FWIW, I'm renaming this to PHY_COMMON_PROPS across the board. The
properties are common between generic PHY and Ethernet PHY/PCS, hence
calling them "generic PHY common properties" is a bit incorrect.
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 net-next 08/10] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap"
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (6 preceding siblings ...)
2026-01-03 21:04 ` [PATCH v2 net-next 07/10] net: phy: air_en8811h: " Vladimir Oltean
@ 2026-01-03 21:04 ` Vladimir Oltean
2026-01-06 18:24 ` Rob Herring (Arm)
2026-01-03 21:04 ` [PATCH v2 net-next 09/10] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS Vladimir Oltean
2026-01-03 21:04 ` [PATCH v2 net-next 10/10] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap" Vladimir Oltean
9 siblings, 1 reply; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:04 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
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>
---
v1->v2: 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] 21+ messages in thread* Re: [PATCH v2 net-next 08/10] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap"
2026-01-03 21:04 ` [PATCH v2 net-next 08/10] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap" Vladimir Oltean
@ 2026-01-06 18:24 ` Rob Herring (Arm)
0 siblings, 0 replies; 21+ messages in thread
From: Rob Herring (Arm) @ 2026-01-06 18:24 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Marek Behún, Daniel Golle, Matthias Brugger, linux-kernel,
Paolo Abeni, Vinod Koul, Eric Woudstra, David S. Miller,
Heiner Kallweit, Andrew Lunn, Patrice Chotard,
Krzysztof Kozlowski, netdev, devicetree, Conor Dooley,
linux-arm-kernel, Russell King, linux-mediatek, Horatiu Vultur,
Neil Armstrong, Jakub Kicinski, Lee Jones,
AngeloGioacchino Del Regno, linux-phy, Eric Dumazet,
Bjørn Mork
On Sat, 03 Jan 2026 23:04:01 +0200, Vladimir Oltean wrote:
> 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>
> ---
> v1->v2: none
>
> .../devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v2 net-next 09/10] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (7 preceding siblings ...)
2026-01-03 21:04 ` [PATCH v2 net-next 08/10] dt-bindings: net: pcs: mediatek,sgmiisys: deprecate "mediatek,pnswap" Vladimir Oltean
@ 2026-01-03 21:04 ` Vladimir Oltean
2026-01-03 21:04 ` [PATCH v2 net-next 10/10] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap" Vladimir Oltean
9 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:04 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
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>
---
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 e68997a29191..8534579b8470 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -4991,7 +4991,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++) {
@@ -5000,18 +4999,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] 21+ messages in thread* [PATCH v2 net-next 10/10] net: pcs: pcs-mtk-lynxi: deprecate "mediatek,pnswap"
2026-01-03 21:03 [PATCH v2 net-next 00/10] PHY polarity inversion via generic device tree properties Vladimir Oltean
` (8 preceding siblings ...)
2026-01-03 21:04 ` [PATCH v2 net-next 09/10] net: pcs: pcs-mtk-lynxi: pass SGMIISYS OF node to PCS Vladimir Oltean
@ 2026-01-03 21:04 ` Vladimir Oltean
9 siblings, 0 replies; 21+ messages in thread
From: Vladimir Oltean @ 2026-01-03 21:04 UTC (permalink / raw)
To: netdev, devicetree, linux-phy
Cc: linux-kernel, linux-arm-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,
Vinod Koul, Neil Armstrong, Matthias Brugger,
AngeloGioacchino Del Regno, Eric Woudstra, Marek Behún,
Lee Jones, Patrice Chotard
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>
---
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..5f94a11f6332 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -20,6 +20,7 @@ config PCS_LYNX
config PCS_MTK_LYNXI
tristate
+ select GENERIC_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] 21+ messages in thread