* [PATCH RFC v3 01/12] dt-bindings: phy: Add NXP S32G SerDes subsystem
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 02/12] dt-bindings: net: nxp,s32-dwmac: Document pcs-handle Jan Petrous via B4 Relay
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
The S32G SerDes subsystem multiplexes two lanes between a PCIe PHY and
two DesignWare XPCS instances. Describe it with one node per SerDes and
one child node per lane.
Compared to the previous revision, the vendor nxp,sys-mode property is
removed: the SS_RW_REG_0[SUBSYS_MODE] value is fully derivable from the
child-node lane mux and the XPCS instance routing (nxp,xpcs-instance).
Each working mode described here has a unique lane mux, so the mode is
a pure function of the child nodes. The reference-clock rate is
validated against the derived mode; it is not used to select it.
The 3.125 Gbit/s working modes are deliberately not described yet.
Distinguishing them from the 1.25 Gbit/s dual-XPCS mode requires a
per-lane 2500BASE-X capability that this binding does not express, and
the reference clock does not distinguish them either - both accept 100
or 125 MHz. They are added by the 2500BASE-X follow-up.
Only the PCIe lane child gets '#phy-cells'. An XPCS lane is not a
generic PHY provider; the Ethernet controller references it through the
standard pcs-handle property instead.
S32G2 and S32G3 use distinct compatibles without fallback because the
full reference-manual mode tables differ per SoC and per SerDes
instance.
Co-developed-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
.../devicetree/bindings/phy/nxp,s32g-serdes.yaml | 258 +++++++++++++++++++++
1 file changed, 258 insertions(+)
diff --git a/Documentation/devicetree/bindings/phy/nxp,s32g-serdes.yaml b/Documentation/devicetree/bindings/phy/nxp,s32g-serdes.yaml
new file mode 100644
index 000000000000..6343d01bfde4
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/nxp,s32g-serdes.yaml
@@ -0,0 +1,258 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/nxp,s32g-serdes.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP S32G2xxx/S32G3xxx SerDes PHY subsystem
+
+maintainers:
+ - Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
+ - Jan Petrous <jan.petrous@oss.nxp.com>
+
+description: |
+ The SerDes subsystem multiplexes two SerDes lanes between one PCIe
+ controller PHY and two Synopsys DesignWare XPCS (Ethernet PCS) instances,
+ behind a shared 2-lane combo PHY. The active routing is selected by the
+ SS_RW_REG_0[SUBSYS_MODE] field.
+
+ Reference-manual working modes described by this binding:
+
+ Mode Lane0 Lane1 PHY refclk (MHz) Description
+ ------------------------------------------------------------
+ 0 PCIe PCIe 100 PCIe x2
+ 1 PCIe XPCS0 100 PCIe x1 + SGMII
+ 2 PCIe XPCS1 100 PCIe x1 + SGMII
+ 3 XPCS0 XPCS1 100 or 125 dual SGMII, 1.25 Gbit/s
+
+ Which Ethernet MAC an XPCS instance feeds is fixed by the SoC integration
+ and differs per SoC and per SerDes instance - on S32G3 SerDes_0, XPCS0
+ feeds GMAC0 and XPCS1 feeds PFE_MAC2, while on SerDes_1 the same two
+ instances feed PFE_MAC0 and PFE_MAC1. That mapping is a property of the
+ SoC, not of this binding, and is resolved by the driver.
+
+ The 3.125 Gbit/s working modes are not described here yet. Distinguishing
+ them from mode 3 requires a per-lane 2500BASE-X capability, which this
+ binding does not express; the reference clock does not distinguish them
+ either, as both accept 100 or 125 MHz. They are added by a follow-up.
+
+ SUBSYS_MODE is not encoded in the devicetree. It is derived at probe from
+ information already present in standard form:
+ - the lane mux, from the per-lane child nodes below;
+ - the XPCS instance a lane feeds, from nxp,xpcs-instance (this is what
+ distinguishes modes 1 and 2).
+ Each mode above has a unique lane mux, so the mode is a pure function of
+ the child nodes. The reference-clock rate is validated against the
+ derived mode; it is never used to select it.
+
+ Both lanes must always be described, even a lane the board does not wire
+ out to a connector. The lane mux is a property of the hardware
+ SUBSYS_MODE, not of the board routing: in mode 1, for example, the
+ subsystem internally routes lane 1 to XPCS0 whether or not the board
+ connects that lane to anything. The child nodes describe that fixed
+ hardware mux, so both must be present; omitting a lane leaves the mode
+ underivable and the probe fails with -EINVAL. Which of those lanes is
+ actually used by a given board is expressed elsewhere (the consumer's
+ phys / pcs-handle reference), not by leaving the lane out here.
+
+ The full reference-manual mode tables differ per SoC, which is why S32G2
+ and S32G3 use distinct compatibles without a fallback between them.
+
+ They also differ between the two SerDes instances of one SoC, so each
+ instance additionally carries a compatible naming it, with the per-SoC
+ string as fallback:
+
+ serdes0: compatible = "nxp,s32g3-serdes0", "nxp,s32g3-serdes";
+ serdes1: compatible = "nxp,s32g3-serdes1", "nxp,s32g3-serdes";
+
+ For the modes described here the two instances behave identically and a
+ driver need only match the fallback. They diverge outside this scope:
+ on S32G3 the 3.125 Gbit/s dual-XPCS mode 4 exists on SerDes_1 only, and
+ on S32G2 only SerDes_1 reaches 3.125 Gbit/s at all. Recording the
+ instance now means the follow-up that adds those modes is purely
+ additive - it matches the specific strings and needs no devicetree
+ change.
+
+ The same mechanism covers SoCs whose instances differ in kind rather
+ than in degree: on S32R47 one SerDes has no PCIe controller at all, so
+ its compatible must be distinguishable in order to reject a PCIe lane
+ child in schema rather than at probe time.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - nxp,s32g2-serdes0
+ - nxp,s32g2-serdes1
+ - const: nxp,s32g2-serdes
+ - items:
+ - enum:
+ - nxp,s32g3-serdes0
+ - nxp,s32g3-serdes1
+ - const: nxp,s32g3-serdes
+
+ reg:
+ maxItems: 4
+
+ reg-names:
+ items:
+ - const: ss-pcie
+ - const: pcie-phy
+ - const: xpcs0
+ - const: xpcs1
+
+ clocks:
+ minItems: 4
+ maxItems: 5
+
+ clock-names:
+ minItems: 4
+ items:
+ - const: axi
+ - const: aux
+ - const: apb
+ - const: ref
+ - const: ext
+ description:
+ The combo PHY reference can be taken from the internal reference
+ clock ("ref") or from the external reference pad ("ext"). A board
+ that routes the external pad lists both; the external reference is
+ then the one used.
+
+ resets:
+ maxItems: 2
+
+ reset-names:
+ items:
+ - const: serdes
+ - const: pcie
+
+ '#address-cells':
+ const: 1
+
+ '#size-cells':
+ const: 0
+
+patternProperties:
+ '^phy@[01]$':
+ description: One SerDes lane. The unit address is the physical lane index.
+ type: object
+ additionalProperties: false
+
+ properties:
+ reg:
+ description: Physical lane index.
+ maximum: 1
+
+ compatible:
+ enum:
+ - nxp,s32g-serdes-pcie-phy
+ - nxp,s32g-serdes-xpcs
+
+ '#phy-cells':
+ const: 0
+
+ nxp,xpcs-instance:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1]
+ description:
+ DesignWare XPCS instance this lane is routed to. Required for, and
+ only valid on, XPCS lanes. Distinguishes modes 1 and 2; for the
+ dual-XPCS mode the instance equals the lane index.
+
+ required:
+ - reg
+ - compatible
+
+ allOf:
+ - if:
+ properties:
+ compatible:
+ const: nxp,s32g-serdes-xpcs
+ required:
+ - compatible
+ then:
+ # An XPCS lane is not a generic PHY provider. It is referenced by
+ # the Ethernet controller through pcs-handle, not through phys.
+ required:
+ - nxp,xpcs-instance
+ properties:
+ '#phy-cells': false
+ else:
+ required:
+ - '#phy-cells'
+ properties:
+ nxp,xpcs-instance: false
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - '#address-cells'
+ - '#size-cells'
+
+additionalProperties: false
+
+examples:
+ # PCIe x1 on lane 0 + 1G SGMII on lane 1 via XPCS0 (derived mode 1).
+ - |
+ serdes@40480000 {
+ compatible = "nxp,s32g3-serdes0", "nxp,s32g3-serdes";
+ reg = <0x40480000 0x108>,
+ <0x40483008 0x10>,
+ <0x40482000 0x800>,
+ <0x40482800 0x800>;
+ reg-names = "ss-pcie", "pcie-phy", "xpcs0", "xpcs1";
+ clocks = <&clks 1>, <&clks 2>, <&clks 3>, <&clks 4>;
+ clock-names = "axi", "aux", "apb", "ref";
+ resets = <&scmi_reset 1>, <&scmi_reset 0>;
+ reset-names = "serdes", "pcie";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy@0 {
+ reg = <0>;
+ compatible = "nxp,s32g-serdes-pcie-phy";
+ #phy-cells = <0>;
+ };
+
+ phy@1 {
+ reg = <1>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <0>;
+ };
+ };
+
+ # Dual 1G SGMII (derived mode 3).
+ - |
+ serdes@44180000 {
+ compatible = "nxp,s32g3-serdes1", "nxp,s32g3-serdes";
+ reg = <0x44180000 0x108>,
+ <0x44183008 0x10>,
+ <0x44182000 0x800>,
+ <0x44182800 0x800>;
+ reg-names = "ss-pcie", "pcie-phy", "xpcs0", "xpcs1";
+ clocks = <&clks 1>, <&clks 2>, <&clks 3>, <&clks 4>;
+ clock-names = "axi", "aux", "apb", "ref";
+ resets = <&scmi_reset 11>, <&scmi_reset 10>;
+ reset-names = "serdes", "pcie";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ phy@0 {
+ reg = <0>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <0>;
+ };
+
+ phy@1 {
+ reg = <1>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <1>;
+ };
+ };
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 02/12] dt-bindings: net: nxp,s32-dwmac: Document pcs-handle
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
2026-09-19 6:54 ` [PATCH RFC v3 01/12] dt-bindings: phy: Add NXP S32G SerDes subsystem Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 03/12] dt-bindings: PCI: nxp,s32g-pcie: Fix SerDes PHY phandle in example Jan Petrous via B4 Relay
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
When the MAC output is routed to the embedded SerDes for SGMII, the PCS
is one of the SerDes XPCS instances. Document that it is referenced
through the standard pcs-handle property defined by
ethernet-controller.yaml, pointing at the SerDes XPCS lane child node.
The type already comes from the ethernet-controller.yaml reference in
the schema chain; this only records the intent, the same way
renesas,rzn1-gmac.yaml does.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml b/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml
index 753a04941659..b168decb540c 100644
--- a/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/nxp,s32-dwmac.yaml
@@ -15,7 +15,8 @@ description:
The SoC series S32G2xx and S32G3xx feature one DWMAC instance,
the SoC S32R45 has two instances. The devices can use RGMII/RMII/MII
interface over Pinctrl device or the output can be routed
- to the embedded SerDes for SGMII connectivity.
+ to the embedded SerDes for SGMII connectivity, in which case the
+ SerDes XPCS lane acting as the PCS is referenced via pcs-handle.
The DWMAC instances have connected all RX/TX queues interrupts,
enabling load balancing of data traffic across all CPU cores.
@@ -81,6 +82,14 @@ properties:
- const: rx
- const: ptp_ref
+ pcs-handle:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ maxItems: 1
+ description:
+ phandle pointing to the SerDes XPCS lane child node that provides
+ the SGMII PCS for this MAC. See
+ Documentation/devicetree/bindings/phy/nxp,s32g-serdes.yaml.
+
required:
- clocks
- clock-names
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 03/12] dt-bindings: PCI: nxp,s32g-pcie: Fix SerDes PHY phandle in example
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
2026-09-19 6:54 ` [PATCH RFC v3 01/12] dt-bindings: phy: Add NXP S32G SerDes subsystem Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 02/12] dt-bindings: net: nxp,s32-dwmac: Document pcs-handle Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core Jan Petrous via B4 Relay
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
The example references the SerDes PHY as
phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
i.e. the SerDes node itself with three PHY cells. That does not match
the SerDes binding: the per-lane child node is the generic PHY
provider and carries '#phy-cells = <0>', while the SerDes node itself
has no '#phy-cells' at all.
Point the example at the PCIe lane child instead, which is also what
the S32G3 board device trees use. The dt-bindings/phy/phy.h include is
dropped along with the now-unused PHY_TYPE_PCIE constant.
The schema itself is unchanged; 'phys: maxItems: 1' already describes
the corrected form.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
index 66a050028278..29323e50bd8b 100644
--- a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
@@ -82,7 +82,6 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
- #include <dt-bindings/phy/phy.h>
bus {
#address-cells = <2>;
@@ -124,7 +123,7 @@ examples:
ranges;
device_type = "pci";
- phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
+ phys = <&serdes0_pcie0>;
};
};
};
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (2 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 03/12] dt-bindings: PCI: nxp,s32g-pcie: Fix SerDes PHY phandle in example Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 15:31 ` Maxime Chevallier
2026-09-20 18:39 ` Andrew Lunn
2026-09-19 6:54 ` [PATCH RFC v3 07/12] net: stmmac: dwmac-s32: Add SGMII support Jan Petrous via B4 Relay
` (6 subsequent siblings)
10 siblings, 2 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: Clark Wang <xiaoning.wang@nxp.com>
The SerDes subsystems found on NXP S32G and i.MX SoCs integrate a
Synopsys DesignWare Ethernet XPCS and an Ethernet PHY (PMA) with an
identical register layout. Only the register transport differs: indirect
memory mapped access on S32G, Clause 45 MDIO on i.MX.
Add a transport agnostic phylink PCS core which operates on regmaps
provided by the platform glue. It implements the phylink PCS operations,
the Clause 37 SGMII / 2500BASE-X / USXGMII / 10GBASE-R configuration and
link state handling, soft reset and polling helpers, and the common
feature sets. The platform specific register sequences, compatibility
tables and quirks are supplied through a per revision descriptor by the
platform drivers selecting this core.
The register sequences and the feature lists are derived from the
Synopsys pcs-xpcs driver, so its copyright is retained. A separate driver
is needed because struct dw_xpcs is built around an mdio_device and owns
the transport, the reset and the identification of a standalone PCS,
while here the PMA can be shared with a PCIe controller, the bring-up is
sequenced across both XPCS instances by the SerDes PHY driver, and the
transport is not always MDIO.
Tested on an S32G3-VNP-RDB3 board through the S32G platform glue added
by the next patch, in both SerDes working modes this series describes:
mode 1 (PCIe x1 + 1G SGMII) and mode 3 (dual SGMII). GMAC0 links at 1G
over XPCS0 and passes traffic in both.
Signed-off-by: Clark Wang <xiaoning.wang@nxp.com>
[jan.petrous: report in-band SGMII link down until BMSR_ANEGCOMPLETE]
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
drivers/net/pcs/Kconfig | 11 +
drivers/net/pcs/Makefile | 1 +
drivers/net/pcs/pcs-nxp-serdes-xpcs.c | 853 ++++++++++++++++++++++++++++++++
include/linux/pcs/pcs-nxp-serdes-xpcs.h | 100 ++++
4 files changed, 965 insertions(+)
diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig
index e417fd66f660..ec4af294003f 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -12,6 +12,17 @@ config PCS_XPCS
This module provides a driver and helper functions for Synopsys
DesignWare XPCS controllers.
+config PCS_NXP_SERDES_XPCS
+ tristate "NXP SerDes XPCS shared core"
+ select PHYLINK
+ select REGMAP
+ help
+ Transport agnostic phylink PCS core for the Synopsys DesignWare
+ Ethernet XPCS and Ethernet PHY of the SerDes subsystems found on
+ NXP S32G and i.MX SoCs. The platform specific register transport
+ (indirect MMIO on S32G, Clause 45 MDIO on i.MX) is implemented as
+ regmap callbacks by the platform drivers selecting this core.
+
config PCS_LYNX
tristate
help
diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index 4f7920618b90..bbf063b18f1f 100644
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -5,6 +5,7 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-plat.o \
pcs-xpcs-nxp.o pcs-xpcs-wx.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
+obj-$(CONFIG_PCS_NXP_SERDES_XPCS) += pcs-nxp-serdes-xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o
obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
diff --git a/drivers/net/pcs/pcs-nxp-serdes-xpcs.c b/drivers/net/pcs/pcs-nxp-serdes-xpcs.c
new file mode 100644
index 000000000000..cc739914496e
--- /dev/null
+++ b/drivers/net/pcs/pcs-nxp-serdes-xpcs.c
@@ -0,0 +1,853 @@
+// SPDX-License-Identifier: GPL-2.0
+/* NXP SerDes XPCS / XPCS-PHY shared core
+ *
+ * Transport agnostic phylink PCS driver for the Ethernet XPCS and Ethernet
+ * PHY (XPCS-PHY) of the SerDes subsystems found on NXP S32G and i.MX SoCs.
+ * The platform glue provides the regmaps and a per revision descriptor
+ * with the compatibility table, quirks and PMA programming sequences.
+ *
+ * The XPCS is a Synopsys DesignWare core, so the Clause 37 / 2500BASE-X /
+ * USXGMII / 10GBASE-R register sequences below are shared with the Synopsys
+ * pcs-xpcs driver and were derived from it. This is a separate driver rather
+ * than an extension of pcs-xpcs because struct dw_xpcs is built around an
+ * mdio_device: it owns the transport, the reset and the identification of a
+ * standalone PCS. That model does not fit these SerDes subsystems, where the
+ * PMA belongs to a combo PHY shared with a PCIe controller, the bring-up is
+ * sequenced across both XPCS instances by the PHY driver, and the register
+ * transport is either indirect MMIO or Clause 45 MDIO. What is left here is
+ * the phylink PCS layer on top of a regmap.
+ *
+ * Keep the register sequences in sync with drivers/net/pcs/pcs-xpcs.c when
+ * fixes apply to both.
+ *
+ * Copyright 2023-2026 NXP
+ * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
+ */
+
+#include <linux/device.h>
+#include <linux/ethtool.h>
+#include <linux/iopoll.h>
+#include <linux/mdio.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/pcs/pcs-nxp-serdes-xpcs.h>
+#include <linux/phylink.h>
+
+/* SR_MII USXGMII speed selection */
+#define DW_USXGMII_RST BIT(10)
+#define DW_USXGMII_EN BIT(9)
+#define DW_USXGMII_FULL BIT(8)
+#define DW_USXGMII_SS_MASK (BIT(13) | BIT(6) | BIT(5))
+#define DW_USXGMII_10000 (BIT(13) | BIT(6))
+#define DW_USXGMII_5000 (BIT(13) | BIT(5))
+#define DW_USXGMII_2500 (BIT(5))
+#define DW_USXGMII_1000 (BIT(6))
+#define DW_USXGMII_100 (BIT(13))
+#define DW_USXGMII_10 (0)
+
+/* VR MII MMD registers offsets */
+#define DW_VR_MII_DIG_CTRL1 0x8000
+#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW BIT(9)
+#define DW_VR_MII_DIG_CTRL1_2G5_EN BIT(2)
+
+#define DW_VR_MII_AN_CTRL 0x8001
+#define DW_VR_MII_TX_CONFIG_MASK BIT(3)
+#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII 0x0
+#define DW_VR_MII_PCS_MODE_MASK GENMASK(2, 1)
+#define DW_VR_MII_PCS_MODE_C37_SGMII 0x2
+#define DW_VR_MII_AN_INTR_EN BIT(0)
+
+#define DW_VR_MII_AN_INTR_STS 0x8002
+#define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR BIT(0)
+#define DW_VR_MII_AN_STS_C37_ANSGM_FD BIT(1)
+#define DW_VR_MII_AN_STS_C37_ANSGM_SP GENMASK(3, 2)
+#define DW_VR_MII_C37_ANSGM_SP_10 0x0
+#define DW_VR_MII_C37_ANSGM_SP_100 0x1
+#define DW_VR_MII_C37_ANSGM_SP_1000 0x2
+#define DW_VR_MII_C37_ANSGM_SP_LNKSTS BIT(4)
+#define DW_VR_MII_USX_AN_STS_MASK GENMASK(14, 8)
+
+#define DW_VR_MII_EEE_MCTRL0 0x8006
+#define DW_VR_MII_EEE_LTX_EN BIT(0) /* LPI Tx Enable */
+#define DW_VR_MII_EEE_LRX_EN BIT(1) /* LPI Rx Enable */
+#define DW_VR_MII_EEE_TX_QUIET_EN BIT(2) /* Tx Quiet Enable */
+#define DW_VR_MII_EEE_RX_QUIET_EN BIT(3) /* Rx Quiet Enable */
+#define DW_VR_MII_EEE_TX_EN_CTRL BIT(4) /* Tx Control Enable */
+#define DW_VR_MII_EEE_RX_EN_CTRL BIT(7) /* Rx Control Enable */
+#define DW_VR_MII_EEE_MULT_FACT_100NS GENMASK(11, 8)
+
+#define DW_VR_MII_EEE_MCTRL1 0x800b
+#define DW_VR_MII_EEE_TRN_LPI BIT(0) /* Transparent Mode Enable */
+
+const int nxp_serdes_xpcs_usxgmii_features[] = {
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_usxgmii_features);
+
+const int nxp_serdes_xpcs_2500basex_features[] = {
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_2500basex_features);
+
+const int nxp_serdes_xpcs_sgmii_features[] = {
+ ETHTOOL_LINK_MODE_Pause_BIT,
+ ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+};
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_sgmii_features);
+
+static const struct nxp_serdes_xpcs_compat *
+nxp_serdes_xpcs_find_compat(struct nxp_serdes_xpcs *xpcs,
+ phy_interface_t interface)
+{
+ const struct nxp_serdes_xpcs_compat *compat;
+
+ for (compat = xpcs->desc->compat; compat->supported; compat++)
+ if (compat->interface == interface)
+ return compat;
+
+ return NULL;
+}
+
+static void nxp_serdes_xpcs_get_interfaces(struct nxp_serdes_xpcs *xpcs,
+ unsigned long *interfaces)
+{
+ const struct nxp_serdes_xpcs_compat *compat;
+
+ for (compat = xpcs->desc->compat; compat->supported; compat++)
+ __set_bit(compat->interface, interfaces);
+}
+
+int nxp_serdes_xpcs_read(struct nxp_serdes_xpcs *xpcs, u8 devad, u32 reg)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(xpcs->xpcs_regmap, (devad << 16) | (reg & 0xffff),
+ &val);
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_read);
+
+int nxp_serdes_xpcs_write(struct nxp_serdes_xpcs *xpcs, u8 devad, u32 reg,
+ u16 val)
+{
+ return regmap_write(xpcs->xpcs_regmap, (devad << 16) | (reg & 0xffff),
+ val);
+}
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_write);
+
+int nxp_serdes_xpcs_modify(struct nxp_serdes_xpcs *xpcs, u8 devad, u32 reg,
+ u16 mask, u16 set)
+{
+ return regmap_update_bits(xpcs->xpcs_regmap,
+ (devad << 16) | (reg & 0xffff), mask, set);
+}
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_modify);
+
+static int nxp_serdes_xpcs_poll_reset(struct nxp_serdes_xpcs *xpcs, int dev)
+{
+ int ret, val;
+
+ ret = read_poll_timeout(nxp_serdes_xpcs_read, val,
+ val < 0 || !(val & BMCR_RESET),
+ 50000, 600000, true, xpcs, dev, MII_BMCR);
+ if (val < 0)
+ ret = val;
+
+ return ret;
+}
+
+static int nxp_serdes_xpcs_soft_reset(struct nxp_serdes_xpcs *xpcs,
+ const struct nxp_serdes_xpcs_compat *compat)
+{
+ int ret, dev;
+
+ switch (compat->an_mode) {
+ case NXP_SERDES_10GBASER:
+ dev = MDIO_MMD_PCS;
+ break;
+ case NXP_SERDES_AN_C37_SGMII:
+ case NXP_SERDES_AN_C37_USXGMII:
+ case NXP_SERDES_2500BASEX:
+ dev = MDIO_MMD_VEND2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = nxp_serdes_xpcs_write(xpcs, dev, MII_BMCR, BMCR_RESET);
+ if (ret < 0)
+ return ret;
+
+ return nxp_serdes_xpcs_poll_reset(xpcs, dev);
+}
+
+static int nxp_serdes_xpcs_validate(struct phylink_pcs *pcs,
+ unsigned long *supported,
+ const struct phylink_link_state *state)
+{
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };
+ const struct nxp_serdes_xpcs_compat *compat;
+ struct nxp_serdes_xpcs *xpcs;
+ int i;
+
+ xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+ compat = nxp_serdes_xpcs_find_compat(xpcs, state->interface);
+ if (!compat)
+ return -EINVAL;
+
+ for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
+ set_bit(compat->supported[i], xpcs_supported);
+
+ linkmode_and(supported, supported, xpcs_supported);
+
+ return 0;
+}
+
+static unsigned int nxp_serdes_xpcs_inband_caps(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+ const struct nxp_serdes_xpcs_compat *compat;
+
+ compat = nxp_serdes_xpcs_find_compat(xpcs, interface);
+ if (!compat)
+ return 0;
+
+ switch (compat->an_mode) {
+ case NXP_SERDES_AN_C37_USXGMII:
+ return LINK_INBAND_ENABLE;
+
+ case NXP_SERDES_AN_C37_SGMII:
+ return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+
+ case NXP_SERDES_10GBASER:
+ case NXP_SERDES_2500BASEX:
+ return LINK_INBAND_DISABLE;
+
+ default:
+ return 0;
+ }
+}
+
+static void nxp_serdes_xpcs_disable(struct phylink_pcs *pcs)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+
+ if (xpcs->desc->reset)
+ xpcs->desc->reset(xpcs);
+}
+
+static void nxp_serdes_xpcs_pre_config(struct phylink_pcs *pcs,
+ phy_interface_t interface)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+ const struct nxp_serdes_xpcs_compat *compat;
+ int ret;
+
+ if (xpcs->interface != interface) {
+ if (interface == PHY_INTERFACE_MODE_SGMII)
+ xpcs->need_reset = true;
+ xpcs->interface = interface;
+ }
+
+ if (xpcs->desc->quirks & NXP_SERDES_QUIRK_NO_POLL)
+ xpcs->pcs.poll = false;
+
+ if (xpcs->desc->quirks & NXP_SERDES_QUIRK_NO_SOFT_RESET)
+ xpcs->need_reset = false;
+
+ if (!xpcs->need_reset)
+ return;
+
+ compat = nxp_serdes_xpcs_find_compat(xpcs, interface);
+ if (!compat) {
+ dev_err(xpcs->dev, "unsupported interface %s\n",
+ phy_modes(interface));
+ return;
+ }
+
+ ret = nxp_serdes_xpcs_soft_reset(xpcs, compat);
+ if (ret)
+ dev_err(xpcs->dev, "soft reset failed: %pe\n", ERR_PTR(ret));
+
+ xpcs->need_reset = false;
+}
+
+static int nxp_serdes_xpcs_config_aneg_c37_sgmii(struct nxp_serdes_xpcs *xpcs,
+ unsigned int neg_mode)
+{
+ int ret, mdio_ctrl;
+ u16 mask, val;
+
+ /* Disable AN while PCS_MODE and TX_CONFIG are switched to C37 SGMII on
+ * the MAC side, then re-enable it for in-band mode. MAC_AUTO_SW lets
+ * the hardware apply the negotiated speed and duplex.
+ */
+ mdio_ctrl = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
+ if (mdio_ctrl < 0)
+ return mdio_ctrl;
+
+ if (mdio_ctrl & BMCR_ANENABLE) {
+ ret = nxp_serdes_xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+ mdio_ctrl & ~BMCR_ANENABLE);
+ if (ret < 0)
+ return ret;
+ }
+
+ mask = DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK;
+ val = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK,
+ DW_VR_MII_PCS_MODE_C37_SGMII);
+ val |= FIELD_PREP(DW_VR_MII_TX_CONFIG_MASK,
+ DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII);
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL,
+ mask, val);
+ if (ret < 0)
+ return ret;
+
+ val = 0;
+ mask = DW_VR_MII_DIG_CTRL1_2G5_EN | DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+ val = DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
+ mask, val);
+ if (ret < 0)
+ return ret;
+
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+ ret = nxp_serdes_xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+ mdio_ctrl | BMCR_ANENABLE);
+
+ return ret;
+}
+
+static int nxp_serdes_xpcs_config_2500basex(struct nxp_serdes_xpcs *xpcs)
+{
+ int ret;
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
+ DW_VR_MII_DIG_CTRL1_2G5_EN |
+ DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW,
+ DW_VR_MII_DIG_CTRL1_2G5_EN);
+ if (ret < 0)
+ return ret;
+
+ return nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+ BMCR_ANENABLE | BMCR_SPEED1000 |
+ BMCR_SPEED100, BMCR_SPEED1000);
+}
+
+static int nxp_serdes_xpcs_config_10gbaser(struct nxp_serdes_xpcs *xpcs)
+{
+ return nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
+ DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW, 0);
+}
+
+static int nxp_serdes_xpcs_do_config(struct nxp_serdes_xpcs *xpcs,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ unsigned int neg_mode)
+{
+ const struct nxp_serdes_xpcs_compat *compat;
+ int ret;
+
+ compat = nxp_serdes_xpcs_find_compat(xpcs, interface);
+ if (!compat)
+ return -ENODEV;
+
+ switch (compat->an_mode) {
+ case NXP_SERDES_10GBASER:
+ ret = nxp_serdes_xpcs_config_10gbaser(xpcs);
+ if (ret)
+ return ret;
+ break;
+ case NXP_SERDES_AN_C37_USXGMII:
+ break;
+ case NXP_SERDES_AN_C37_SGMII:
+ ret = nxp_serdes_xpcs_config_aneg_c37_sgmii(xpcs, neg_mode);
+ if (ret)
+ return ret;
+ break;
+ case NXP_SERDES_2500BASEX:
+ ret = nxp_serdes_xpcs_config_2500basex(xpcs);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (compat->pma_config) {
+ ret = compat->pma_config(xpcs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int nxp_serdes_xpcs_config(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+
+ return nxp_serdes_xpcs_do_config(xpcs, interface, advertising, neg_mode);
+}
+
+static int nxp_serdes_xpcs_get_state_c37_sgmii(struct nxp_serdes_xpcs *xpcs,
+ unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ int ret;
+
+ state->link = false;
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ state->pause = 0;
+
+ /* Until AN completes, the status still holds the previous SGMII word */
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
+ ret = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR);
+ if (ret < 0)
+ return ret;
+
+ if (!(ret & BMSR_ANEGCOMPLETE))
+ return 0;
+ }
+
+ ret = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
+ if (ret < 0)
+ return ret;
+
+ state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
+
+ if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
+ int speed_value;
+
+ state->link = true;
+
+ speed_value = FIELD_GET(DW_VR_MII_AN_STS_C37_ANSGM_SP, ret);
+ if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000)
+ state->speed = SPEED_1000;
+ else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100)
+ state->speed = SPEED_100;
+ else
+ state->speed = SPEED_10;
+
+ if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD)
+ state->duplex = DUPLEX_FULL;
+ else
+ state->duplex = DUPLEX_HALF;
+ } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+ int speed, duplex;
+
+ state->link = true;
+
+ speed = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
+ if (speed < 0)
+ return speed;
+
+ speed &= BMCR_SPEED100 | BMCR_SPEED1000;
+ if (speed == BMCR_SPEED1000)
+ state->speed = SPEED_1000;
+ else if (speed == BMCR_SPEED100)
+ state->speed = SPEED_100;
+ else if (speed == 0)
+ state->speed = SPEED_10;
+
+ duplex = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2,
+ MII_ADVERTISE);
+ if (duplex < 0)
+ return duplex;
+
+ if (duplex & ADVERTISE_1000XFULL)
+ state->duplex = DUPLEX_FULL;
+ else if (duplex & ADVERTISE_1000XHALF)
+ state->duplex = DUPLEX_HALF;
+
+ nxp_serdes_xpcs_write(xpcs, MDIO_MMD_VEND2,
+ DW_VR_MII_AN_INTR_STS, 0);
+ }
+
+ return 0;
+}
+
+static int nxp_serdes_xpcs_get_state_2500basex(struct nxp_serdes_xpcs *xpcs,
+ struct phylink_link_state *state)
+{
+ int ret;
+
+ ret = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR);
+ if (ret < 0) {
+ state->link = 0;
+ return ret;
+ }
+
+ state->link = !!(ret & BMSR_LSTATUS);
+ if (!state->link)
+ return 0;
+
+ state->speed = SPEED_2500;
+ state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX;
+ state->duplex = DUPLEX_FULL;
+
+ return 0;
+}
+
+static int nxp_serdes_xpcs_get_state_c37_usxgmii(struct nxp_serdes_xpcs *xpcs,
+ struct phylink_link_state *state)
+{
+ u16 usxg_an_status;
+ int ret;
+
+ state->link = false;
+ state->speed = SPEED_UNKNOWN;
+ state->duplex = DUPLEX_UNKNOWN;
+ state->pause = 0;
+
+ ret = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
+ if (ret < 0)
+ return ret;
+
+ usxg_an_status = FIELD_GET(DW_VR_MII_USX_AN_STS_MASK, ret);
+ if (!(usxg_an_status & BIT(6)))
+ return 0;
+
+ state->link = true;
+ state->an_complete = true;
+ phylink_decode_usxgmii_word(state, usxg_an_status << 7);
+
+ return 0;
+}
+
+static void nxp_serdes_xpcs_get_state(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+ const struct nxp_serdes_xpcs_compat *compat;
+ int stat1;
+ int ret;
+
+ compat = nxp_serdes_xpcs_find_compat(xpcs, state->interface);
+ if (!compat)
+ return;
+
+ switch (compat->an_mode) {
+ case NXP_SERDES_10GBASER:
+ stat1 = nxp_serdes_xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
+ if (stat1 < 0) {
+ state->link = false;
+ break;
+ }
+
+ if (stat1 & MDIO_STAT1_FAULT)
+ nxp_serdes_xpcs_do_config(xpcs, state->interface, NULL,
+ PHYLINK_PCS_NEG_NONE);
+
+ state->link = !!(stat1 & MDIO_STAT1_LSTATUS);
+ if (state->link &&
+ state->interface == PHY_INTERFACE_MODE_10GBASER) {
+ state->speed = SPEED_10000;
+ state->duplex = DUPLEX_FULL;
+ }
+ break;
+ case NXP_SERDES_AN_C37_USXGMII:
+ ret = nxp_serdes_xpcs_get_state_c37_usxgmii(xpcs, state);
+ if (ret)
+ dev_err(xpcs->dev, "%s returned %pe\n",
+ "nxp_serdes_xpcs_get_state_c37_usxgmii",
+ ERR_PTR(ret));
+ break;
+ case NXP_SERDES_AN_C37_SGMII:
+ ret = nxp_serdes_xpcs_get_state_c37_sgmii(xpcs, neg_mode, state);
+ if (ret)
+ dev_err(xpcs->dev, "%s returned %pe\n",
+ "nxp_serdes_xpcs_get_state_c37_sgmii",
+ ERR_PTR(ret));
+ break;
+ case NXP_SERDES_2500BASEX:
+ ret = nxp_serdes_xpcs_get_state_2500basex(xpcs, state);
+ if (ret)
+ dev_err(xpcs->dev, "%s returned %pe\n",
+ "nxp_serdes_xpcs_get_state_2500basex",
+ ERR_PTR(ret));
+ break;
+ default:
+ return;
+ }
+}
+
+static void nxp_serdes_xpcs_link_up_sgmii_1000basex(struct nxp_serdes_xpcs *xpcs,
+ unsigned int neg_mode,
+ phy_interface_t interface,
+ int speed, int duplex)
+{
+ int ret;
+
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+ return;
+
+ if (interface == PHY_INTERFACE_MODE_1000BASEX) {
+ if (speed != SPEED_1000) {
+ dev_err(xpcs->dev, "%s: speed %dMbps not supported\n",
+ __func__, speed);
+ return;
+ }
+
+ if (duplex != DUPLEX_FULL)
+ dev_err(xpcs->dev, "%s: half duplex not supported\n",
+ __func__);
+ }
+
+ ret = nxp_serdes_xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+ mii_bmcr_encode_fixed(speed, duplex));
+ if (ret)
+ dev_err(xpcs->dev, "%s: write returned %pe\n",
+ __func__, ERR_PTR(ret));
+}
+
+static void nxp_serdes_xpcs_link_up_usxgmii(struct nxp_serdes_xpcs *xpcs,
+ int speed)
+{
+ int ret, speed_sel;
+
+ switch (speed) {
+ case SPEED_10:
+ speed_sel = DW_USXGMII_10;
+ break;
+ case SPEED_100:
+ speed_sel = DW_USXGMII_100;
+ break;
+ case SPEED_1000:
+ speed_sel = DW_USXGMII_1000;
+ break;
+ case SPEED_2500:
+ speed_sel = DW_USXGMII_2500;
+ break;
+ case SPEED_5000:
+ speed_sel = DW_USXGMII_5000;
+ break;
+ case SPEED_10000:
+ speed_sel = DW_USXGMII_10000;
+ break;
+ default:
+ return;
+ }
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_PCS, BIT(15) | MDIO_CTRL1,
+ DW_USXGMII_EN, DW_USXGMII_EN);
+ if (ret < 0)
+ goto out;
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+ DW_USXGMII_SS_MASK,
+ speed_sel | DW_USXGMII_FULL);
+ if (ret < 0)
+ goto out;
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_PCS, BIT(15) | MDIO_CTRL1,
+ DW_USXGMII_RST, DW_USXGMII_RST);
+ if (ret < 0)
+ goto out;
+
+ return;
+
+out:
+ dev_err(xpcs->dev, "%s: XPCS access returned %pe\n",
+ __func__, ERR_PTR(ret));
+}
+
+static void nxp_serdes_xpcs_link_up(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ phy_interface_t interface, int speed,
+ int duplex)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+ const struct nxp_serdes_xpcs_compat *compat;
+ int ret;
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_USXGMII:
+ nxp_serdes_xpcs_link_up_usxgmii(xpcs, speed);
+ break;
+
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ nxp_serdes_xpcs_link_up_sgmii_1000basex(xpcs, neg_mode,
+ interface, speed,
+ duplex);
+ break;
+
+ default:
+ break;
+ }
+
+ compat = nxp_serdes_xpcs_find_compat(xpcs, interface);
+ if (compat && compat->pma_link_up) {
+ ret = compat->pma_link_up(xpcs, speed, duplex);
+ if (ret)
+ dev_err(xpcs->dev, "%s: pma_link_up returned %pe\n",
+ __func__, ERR_PTR(ret));
+ }
+}
+
+static void nxp_serdes_xpcs_an_restart(struct phylink_pcs *pcs)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+
+ nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART,
+ BMCR_ANRESTART);
+}
+
+static int nxp_serdes_xpcs_config_eee(struct nxp_serdes_xpcs *xpcs,
+ bool enable)
+{
+ u16 mask, val;
+ int ret;
+
+ mask = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+ DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+ DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+ DW_VR_MII_EEE_MULT_FACT_100NS;
+
+ if (enable)
+ val = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
+ DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
+ DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
+ /* No platform needs a non-default multiply factor */
+ FIELD_PREP(DW_VR_MII_EEE_MULT_FACT_100NS, 0);
+ else
+ val = 0;
+
+ ret = nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2,
+ DW_VR_MII_EEE_MCTRL0, mask, val);
+ if (ret < 0)
+ return ret;
+
+ return nxp_serdes_xpcs_modify(xpcs, MDIO_MMD_VEND2,
+ DW_VR_MII_EEE_MCTRL1,
+ DW_VR_MII_EEE_TRN_LPI,
+ enable ? DW_VR_MII_EEE_TRN_LPI : 0);
+}
+
+static void nxp_serdes_xpcs_disable_eee(struct phylink_pcs *pcs)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+
+ if (xpcs->desc->quirks & NXP_SERDES_QUIRK_NO_EEE)
+ return;
+
+ nxp_serdes_xpcs_config_eee(xpcs, false);
+}
+
+static void nxp_serdes_xpcs_enable_eee(struct phylink_pcs *pcs)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+
+ if (xpcs->desc->quirks & NXP_SERDES_QUIRK_NO_EEE)
+ return;
+
+ nxp_serdes_xpcs_config_eee(xpcs, true);
+}
+
+static const struct phylink_pcs_ops nxp_serdes_xpcs_phylink_ops = {
+ .pcs_validate = nxp_serdes_xpcs_validate,
+ .pcs_inband_caps = nxp_serdes_xpcs_inband_caps,
+ .pcs_pre_config = nxp_serdes_xpcs_pre_config,
+ .pcs_disable = nxp_serdes_xpcs_disable,
+ .pcs_config = nxp_serdes_xpcs_config,
+ .pcs_get_state = nxp_serdes_xpcs_get_state,
+ .pcs_an_restart = nxp_serdes_xpcs_an_restart,
+ .pcs_link_up = nxp_serdes_xpcs_link_up,
+ .pcs_disable_eee = nxp_serdes_xpcs_disable_eee,
+ .pcs_enable_eee = nxp_serdes_xpcs_enable_eee,
+};
+
+/**
+ * nxp_serdes_xpcs_create() - create a NXP SerDes XPCS phylink PCS
+ * @dev: device the PCS belongs to, used for error reporting
+ * @xpcs_regmap: regmap of the XPCS registers
+ * @phy_regmap: regmap of the XPCS-PHY registers, may be NULL
+ * @desc: revision descriptor, see &struct nxp_serdes_xpcs_desc
+ * @portid: index of the XPCS port, used to select the shared MPLL
+ * @interface: PHY interface mode used for the link
+ *
+ * The regmaps must stay valid until nxp_serdes_xpcs_destroy() has been called.
+ *
+ * Return: a pointer to a &struct phylink_pcs, or an ERR_PTR() on failure.
+ */
+struct phylink_pcs *nxp_serdes_xpcs_create(struct device *dev,
+ struct regmap *xpcs_regmap,
+ struct regmap *phy_regmap,
+ const struct nxp_serdes_xpcs_desc *desc,
+ u8 portid, phy_interface_t interface)
+{
+ struct nxp_serdes_xpcs *xpcs;
+
+ if (!desc || !desc->compat)
+ return ERR_PTR(-EINVAL);
+
+ xpcs = kzalloc_obj(struct nxp_serdes_xpcs, GFP_KERNEL);
+ if (!xpcs)
+ return ERR_PTR(-ENOMEM);
+
+ xpcs->dev = dev;
+ xpcs->xpcs_regmap = xpcs_regmap;
+ xpcs->phy_regmap = phy_regmap;
+ xpcs->desc = desc;
+ xpcs->pma_id = desc->pma_id;
+ xpcs->portid = portid;
+ xpcs->interface = interface;
+ xpcs->pcs.ops = &nxp_serdes_xpcs_phylink_ops;
+ xpcs->pcs.poll = true;
+ nxp_serdes_xpcs_get_interfaces(xpcs, xpcs->pcs.supported_interfaces);
+ xpcs->need_reset = true;
+
+ return &xpcs->pcs;
+}
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_create);
+
+void nxp_serdes_xpcs_destroy(struct phylink_pcs *pcs)
+{
+ struct nxp_serdes_xpcs *xpcs = phylink_pcs_to_nxp_serdes_xpcs(pcs);
+
+ if (!xpcs)
+ return;
+
+ kfree(xpcs);
+}
+EXPORT_SYMBOL_GPL(nxp_serdes_xpcs_destroy);
+
+MODULE_DESCRIPTION("NXP SerDes XPCS shared core");
+MODULE_AUTHOR("Clark Wang <xiaoning.wang@nxp.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/pcs/pcs-nxp-serdes-xpcs.h b/include/linux/pcs/pcs-nxp-serdes-xpcs.h
new file mode 100644
index 000000000000..2579c6b14a61
--- /dev/null
+++ b/include/linux/pcs/pcs-nxp-serdes-xpcs.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * NXP SerDes XPCS shared core
+ * Copyright 2026 NXP
+ */
+
+#ifndef __LINUX_PCS_NXP_SERDES_XPCS_H
+#define __LINUX_PCS_NXP_SERDES_XPCS_H
+
+#include <linux/phy.h>
+#include <linux/phylink.h>
+#include <linux/regmap.h>
+
+/* AN mode values as defined by the DesignWare XPCS */
+enum nxp_serdes_an_mode {
+ NXP_SERDES_AN_C37_SGMII = 2,
+ NXP_SERDES_2500BASEX = 3,
+ NXP_SERDES_10GBASER = 5,
+ NXP_SERDES_AN_C37_USXGMII = 6,
+};
+
+/* The revision runs its own reset sequence, skip the soft reset */
+#define NXP_SERDES_QUIRK_NO_SOFT_RESET BIT(0)
+/* The revision reports the link state to the MAC, do not poll the PCS */
+#define NXP_SERDES_QUIRK_NO_POLL BIT(1)
+/* The revision does not implement the VR_MII_EEE_MCTRL0/1 registers */
+#define NXP_SERDES_QUIRK_NO_EEE BIT(2)
+
+struct nxp_serdes_xpcs;
+
+struct nxp_serdes_xpcs_compat {
+ phy_interface_t interface;
+ const int *supported;
+ enum nxp_serdes_an_mode an_mode;
+ int (*pma_config)(struct nxp_serdes_xpcs *xpcs);
+ int (*pma_link_up)(struct nxp_serdes_xpcs *xpcs, int speed,
+ int duplex);
+};
+
+/* Description of one SerDes revision, provided by the platform glue */
+struct nxp_serdes_xpcs_desc {
+ const char *name;
+ u32 pma_id;
+ const struct nxp_serdes_xpcs_compat *compat;
+ unsigned int quirks;
+ void (*reset)(struct nxp_serdes_xpcs *xpcs);
+};
+
+struct nxp_serdes_xpcs {
+ struct device *dev;
+ struct regmap *xpcs_regmap;
+ struct regmap *phy_regmap;
+ const struct nxp_serdes_xpcs_desc *desc;
+ struct phylink_pcs pcs;
+ phy_interface_t interface;
+ u32 pma_id;
+ u8 portid;
+ bool need_reset;
+ bool sgmii_internal_ref_clk;
+ void *priv;
+};
+
+#define phylink_pcs_to_nxp_serdes_xpcs(pl_pcs) \
+ container_of((pl_pcs), struct nxp_serdes_xpcs, pcs)
+
+static inline void nxp_serdes_xpcs_set_drvdata(struct nxp_serdes_xpcs *xpcs,
+ void *priv)
+{
+ xpcs->priv = priv;
+}
+
+static inline void *nxp_serdes_xpcs_get_drvdata(struct nxp_serdes_xpcs *xpcs)
+{
+ return xpcs->priv;
+}
+
+/* Feature sets for struct nxp_serdes_xpcs_compat::supported */
+extern const int nxp_serdes_xpcs_usxgmii_features[];
+extern const int nxp_serdes_xpcs_2500basex_features[];
+extern const int nxp_serdes_xpcs_sgmii_features[];
+
+struct phylink_pcs *nxp_serdes_xpcs_create(struct device *dev,
+ struct regmap *xpcs_regmap,
+ struct regmap *phy_regmap,
+ const struct nxp_serdes_xpcs_desc *desc,
+ u8 portid,
+ phy_interface_t interface);
+void nxp_serdes_xpcs_destroy(struct phylink_pcs *pcs);
+
+/* Register accesses are encoded in the regmap as "(devad << 16) | reg", with
+ * "devad" the Clause 45 device address and "reg" the 16-bit register address.
+ * Decoding both fields is up to the regmap of the platform glue.
+ */
+int nxp_serdes_xpcs_read(struct nxp_serdes_xpcs *xpcs, u8 devad, u32 reg);
+int nxp_serdes_xpcs_write(struct nxp_serdes_xpcs *xpcs, u8 devad, u32 reg,
+ u16 val);
+int nxp_serdes_xpcs_modify(struct nxp_serdes_xpcs *xpcs, u8 devad, u32 reg,
+ u16 mask, u16 set);
+
+#endif /* __LINUX_PCS_NXP_SERDES_XPCS_H */
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 07/12] net: stmmac: dwmac-s32: Add SGMII support
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (3 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 12:04 ` Maxime Chevallier
2026-09-19 6:54 ` [PATCH RFC v3 08/12] MAINTAINERS: Add NXP S32G SerDes and SerDes xPCS core entries Jan Petrous via B4 Relay
` (5 subsequent siblings)
10 siblings, 1 reply; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
Wire the NXP S32G SerDes XPCS PCS into the dwmac-s32 glue layer so the
MAC can run SGMII over a SerDes lane.
Changes:
- s32_gmac_write_phy_intf_select: replace the hard-coded RGMII selector
with a switch on phy_interface so SGMII (0x01), RGMII, RMII and MII
all programme the SoC control register correctly.
- Add s32_gmac_pcs_init: obtain the phylink_pcs handle from the SerDes
subsystem via s32g_serdes_pcs_create(), keyed by the standard
pcs-handle property on the GMAC node pointing at the SerDes XPCS lane
child. Propagates -EPROBE_DEFER if the SerDes driver has not probed
yet. There is no matching exit hook: the device link created by
s32g_serdes_pcs_create() covers the lifetime.
- Add s32_gmac_select_pcs: return the stored PCS handle when the
negotiated interface is SGMII.
- Hook pcs_init and select_pcs into plat_stmmacenet_data.
Note that installing a select_pcs callback suppresses the core's
integrated_pcs fallback, because stmmac treats a NULL return from
select_pcs as "no PCS" rather than "fall through". This matches what
dwmac-rzn1 and dwmac-intel already do.
Both negotiation modes are supported by the PCS. The board device
trees added later in this series describe the MAC-side link as fixed,
so they exercise the out-of-band path.
The XPCS header guards its s32g_serdes_pcs_create() declaration with
IS_REACHABLE(CONFIG_PHY_S32G_SERDES) and provides a static-inline stub
returning -ENODEV otherwise. IS_REACHABLE is false both when the SerDes
driver is disabled and in the built-in-consumer / modular-provider case
(DWMAC_S32=y with PHY_S32G_SERDES=m), so this driver links in all four
combinations of the two symbols.
Linking is not sufficient on its own, though. In the DWMAC_S32=y with
PHY_S32G_SERDES=m case the stub makes s32_gmac_pcs_init() return
-ENODEV, and stmmac treats a failing plat->pcs_init() as fatal, so a
built-in MAC would refuse to probe on any device tree describing
pcs-handle. Add a Kconfig dependency forbidding that combination
rather than letting it build into a MAC that cannot probe.
Tested on an S32G3-VNP-RDB3 board: GMAC0 links at 1G over SGMII and
passes traffic, both in SerDes mode 1 (alongside two active PCIe root
complexes) and in mode 3.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 6 ++
drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c | 74 ++++++++++++++++++++++++-
2 files changed, 78 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index e3dd5adda5ac..1443ff4149b4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -192,6 +192,12 @@ config DWMAC_S32
tristate "NXP S32G/S32R GMAC support"
default ARCH_S32
depends on OF && (ARCH_S32 || COMPILE_TEST)
+ # SGMII needs the PCS from the SerDes driver. The header falls back
+ # to a stub returning -ENODEV when that driver is not reachable, and
+ # stmmac makes a failing plat->pcs_init() fatal, so a built-in MAC
+ # with a modular SerDes would refuse to probe on any DT describing
+ # pcs-handle. Forbid that combination instead.
+ depends on PHY_S32G_SERDES || PHY_S32G_SERDES=n
help
Support for ethernet controller on NXP S32CC SOCs.
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
index 024d8e10e918..a3a56b21181a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
@@ -16,12 +16,14 @@
#include <linux/of_mdio.h>
#include <linux/of_address.h>
#include <linux/phy.h>
+#include <linux/phy/nxp-s32g-serdes.h>
#include <linux/phylink.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/stmmac.h>
#include "stmmac_platform.h"
+#include "stmmac.h"
#define GMAC_INTF_RATE_125M 125000000 /* 125MHz */
@@ -40,23 +42,89 @@ struct s32_priv_data {
phy_interface_t *intf_mode;
struct clk *tx_clk;
struct clk *rx_clk;
+ /* SGMII PCS provided by the SerDes subsystem (NULL if not SGMII) */
+ struct phylink_pcs *pcs;
};
static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
{
+ u32 intf_sel;
int ret = 0;
+ switch (*gmac->intf_mode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ intf_sel = S32_PHY_INTF_SEL_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ intf_sel = S32_PHY_INTF_SEL_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ intf_sel = S32_PHY_INTF_SEL_RMII;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ intf_sel = S32_PHY_INTF_SEL_MII;
+ break;
+ default:
+ dev_err(gmac->dev, "Unsupported phy interface mode: %s\n",
+ phy_modes(*gmac->intf_mode));
+ return -EINVAL;
+ }
+
if (gmac->ctrl_sts)
- writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
+ writel(intf_sel, gmac->ctrl_sts);
else
ret = regmap_write(gmac->sts_regmap, gmac->sts_offset,
- S32_PHY_INTF_SEL_RGMII);
+ intf_sel);
dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));
return ret;
}
+static int s32_gmac_pcs_init(struct stmmac_priv *priv)
+{
+ struct s32_priv_data *gmac = priv->plat->bsp_priv;
+ struct device_node *pcs_node;
+
+ /*
+ * pcs-handle points at the SerDes XPCS lane child node; its
+ * nxp,xpcs-instance property is what identifies the XPCS instance.
+ */
+ pcs_node = of_parse_phandle(gmac->dev->of_node, "pcs-handle", 0);
+ if (!pcs_node) {
+ dev_dbg(gmac->dev, "no 'pcs-handle' property, SGMII PCS unavailable\n");
+ return 0;
+ }
+
+ gmac->pcs = s32g_serdes_pcs_create(gmac->dev, pcs_node);
+ of_node_put(pcs_node);
+
+ if (IS_ERR(gmac->pcs)) {
+ int err = PTR_ERR(gmac->pcs);
+
+ gmac->pcs = NULL;
+ /* SerDes may not be probed yet - defer probe. */
+ return err;
+ }
+
+ dev_dbg(gmac->dev, "SGMII PCS created via SerDes XPCS\n");
+ return 0;
+}
+
+static struct phylink_pcs *s32_gmac_select_pcs(struct stmmac_priv *priv,
+ phy_interface_t interface)
+{
+ struct s32_priv_data *gmac = priv->plat->bsp_priv;
+
+ if (interface == PHY_INTERFACE_MODE_SGMII && gmac->pcs)
+ return gmac->pcs;
+
+ return NULL;
+}
+
static int s32_gmac_init(struct device *dev, void *priv)
{
struct s32_priv_data *gmac = priv;
@@ -204,6 +272,8 @@ static int s32_dwmac_probe(struct platform_device *pdev)
plat->init = s32_gmac_init;
plat->exit = s32_gmac_exit;
+ plat->pcs_init = s32_gmac_pcs_init;
+ plat->select_pcs = s32_gmac_select_pcs;
plat->clk_tx_i = gmac->tx_clk;
plat->set_clk_tx_rate = stmmac_set_clk_tx_rate;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 08/12] MAINTAINERS: Add NXP S32G SerDes and SerDes xPCS core entries
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (4 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 07/12] net: stmmac: dwmac-s32: Add SGMII support Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 09/12] arm64: dts: s32g: Add SCMI reset controller Jan Petrous via B4 Relay
` (4 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: Vincent Guittot <vincent.guittot@linaro.org>
Add two entries.
ARM/NXP S32G SERDES DRIVER covers the S32G specific parts: the SerDes
PHY driver, the S32G XPCS platform glue, their headers and the SerDes
devicetree binding. The R: and name forms match the adjacent ARM/NXP
S32G/S32R DWMAC ETHERNET DRIVER entry, and netdev is listed because the
PCS glue lives under drivers/net/pcs/.
NXP SERDES XPCS SHARED CORE covers the transport agnostic core on its
own. The core is not S32G specific - it is shared with i.MX9, whose
glue is a separate driver - so keeping it in the S32G entry would make
the S32G maintainers the default contact for i.MX transport work and
vice versa. This follows how drivers/net/pcs/ is already organised:
SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER carries the shared pcs-xpcs
core, while each vendor glue (pcs-xpcs-nxp.c, pcs-xpcs-wx.c,
pcs-rzn1-miic.c) is listed under its own vendor entry. Only netdev is
listed for the core, so i.MX changes to it do not reach the ARM lists.
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
MAINTAINERS | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 3b2eb2a7a89a..38c6b5e1af0d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3371,6 +3371,20 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
F: drivers/pci/controller/dwc/pcie-nxp-s32g*
+ARM/NXP S32G SERDES DRIVER
+M: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
+M: Jan Petrous <jan.petrous@oss.nxp.com>
+R: NXP S32 Linux Team <s32@nxp.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-phy@lists.infradead.org
+L: netdev@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/phy/nxp,s32g-serdes.yaml
+F: drivers/net/pcs/pcs-nxp-s32g-xpcs.c
+F: drivers/phy/freescale/phy-nxp-s32g-serdes.c
+F: include/linux/pcs/pcs-nxp-s32g-xpcs.h
+F: include/linux/phy/nxp-s32g-serdes.h
+
ARM/NXP S32G/S32R DWMAC ETHERNET DRIVER
M: Jan Petrous <jan.petrous@oss.nxp.com>
R: s32@nxp.com
@@ -19788,6 +19802,15 @@ S: Maintained
F: Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml
F: drivers/extcon/extcon-ptn5150.c
+NXP SERDES XPCS SHARED CORE
+M: Jan Petrous <jan.petrous@oss.nxp.com>
+M: Clark Wang <xiaoning.wang@nxp.com>
+R: NXP S32 Linux Team <s32@nxp.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/pcs/pcs-nxp-serdes-xpcs.c
+F: include/linux/pcs/pcs-nxp-serdes-xpcs.h
+
NXP SGTL5000 DRIVER
M: Fabio Estevam <festevam@gmail.com>
L: linux-sound@vger.kernel.org
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 09/12] arm64: dts: s32g: Add SCMI reset controller
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (5 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 08/12] MAINTAINERS: Add NXP S32G SerDes and SerDes xPCS core entries Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 10/12] arm64: dts: s32g: Add SerDes controller nodes Jan Petrous via B4 Relay
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
Add the SCMI reset domain protocol (protocol@16) node under the SCMI
firmware node for both S32G2 and S32G3, so that on-SoC controllers can
request resets through the SCMI reset controller.
The node is labelled scmi_reset rather than reset: a label that
generic in a SoC .dtsi invites collisions and reads poorly at the use
sites, and the sibling clock protocol node already uses the shortened
clks form.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32g2.dtsi | 5 +++++
arch/arm64/boot/dts/freescale/s32g3.dtsi | 5 +++++
2 files changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 996494e34593..6a2774d53747 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -100,6 +100,11 @@ clks: protocol@14 {
reg = <0x14>;
#clock-cells = <1>;
};
+
+ scmi_reset: protocol@16 {
+ reg = <0x16>;
+ #reset-cells = <1>;
+ };
};
psci {
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index 31f7aad00b76..da3915b7e915 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -139,6 +139,11 @@ clks: protocol@14 {
reg = <0x14>;
#clock-cells = <1>;
};
+
+ scmi_reset: protocol@16 {
+ reg = <0x16>;
+ #reset-cells = <1>;
+ };
};
psci: psci {
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 10/12] arm64: dts: s32g: Add SerDes controller nodes
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (6 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 09/12] arm64: dts: s32g: Add SCMI reset controller Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 11/12] arm64: dts: s32g: Add PCIe " Jan Petrous via B4 Relay
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
Add the SerDes/PCIe combo-PHY controller nodes for S32G2 and S32G3 in
the disabled state. Each SoC integrates two SerDes instances (SerDes_0
and SerDes_1) with identical register layout; every instance exposes
the PCIe PHY and the two XPCS instances used for SGMII. Board device
trees enable the required instance and add the lane PHY child nodes
matching the wanted SerDes subsystem mode.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32g2.dtsi | 32 ++++++++++++++++++++++++++++++++
arch/arm64/boot/dts/freescale/s32g3.dtsi | 32 ++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 6a2774d53747..404913b208fb 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -877,6 +877,38 @@ gmac0mdio: mdio {
};
};
+ serdes0: serdes@40480000 {
+ compatible = "nxp,s32g2-serdes0", "nxp,s32g2-serdes";
+ reg = <0x40480000 0x108>,
+ <0x40483008 0x10>,
+ <0x40482000 0x800>,
+ <0x40482800 0x800>;
+ reg-names = "ss-pcie", "pcie-phy", "xpcs0", "xpcs1";
+ clocks = <&clks 1>, <&clks 2>, <&clks 3>, <&clks 4>;
+ clock-names = "axi", "aux", "apb", "ref";
+ resets = <&scmi_reset 9>, <&scmi_reset 8>;
+ reset-names = "serdes", "pcie";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ serdes1: serdes@44180000 {
+ compatible = "nxp,s32g2-serdes1", "nxp,s32g2-serdes";
+ reg = <0x44180000 0x108>,
+ <0x44183008 0x10>,
+ <0x44182000 0x800>,
+ <0x44182800 0x800>;
+ reg-names = "ss-pcie", "pcie-phy", "xpcs0", "xpcs1";
+ clocks = <&clks 1>, <&clks 2>, <&clks 3>, <&clks 4>;
+ clock-names = "axi", "aux", "apb", "ref";
+ resets = <&scmi_reset 11>, <&scmi_reset 10>;
+ reset-names = "serdes", "pcie";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@50800000 {
compatible = "arm,gic-v3";
reg = <0x50800000 0x10000>,
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index da3915b7e915..0d001b2895c6 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -956,6 +956,38 @@ gmac0mdio: mdio {
};
};
+ serdes0: serdes@40480000 {
+ compatible = "nxp,s32g3-serdes0", "nxp,s32g3-serdes";
+ reg = <0x40480000 0x108>,
+ <0x40483008 0x10>,
+ <0x40482000 0x800>,
+ <0x40482800 0x800>;
+ reg-names = "ss-pcie", "pcie-phy", "xpcs0", "xpcs1";
+ clocks = <&clks 1>, <&clks 2>, <&clks 3>, <&clks 4>;
+ clock-names = "axi", "aux", "apb", "ref";
+ resets = <&scmi_reset 9>, <&scmi_reset 8>;
+ reset-names = "serdes", "pcie";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ serdes1: serdes@44180000 {
+ compatible = "nxp,s32g3-serdes1", "nxp,s32g3-serdes";
+ reg = <0x44180000 0x108>,
+ <0x44183008 0x10>,
+ <0x44182000 0x800>,
+ <0x44182800 0x800>;
+ reg-names = "ss-pcie", "pcie-phy", "xpcs0", "xpcs1";
+ clocks = <&clks 1>, <&clks 2>, <&clks 3>, <&clks 4>;
+ clock-names = "axi", "aux", "apb", "ref";
+ resets = <&scmi_reset 11>, <&scmi_reset 10>;
+ reset-names = "serdes", "pcie";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
swt8: watchdog@40500000 {
compatible = "nxp,s32g3-swt", "nxp,s32g2-swt";
reg = <0x40500000 0x1000>;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 11/12] arm64: dts: s32g: Add PCIe controller nodes
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (7 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 10/12] arm64: dts: s32g: Add SerDes controller nodes Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 12/12] arm64: dts: s32g: Add S32G3-RDB3 SerDes routing variants Jan Petrous via B4 Relay
[not found] ` <20260919-s32g_serdes-v3-5-9d68868c1e89@oss.nxp.com>
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
Add the two PCIe controllers of the S32G2 and S32G3, disabled. Each is
the root complex half of one SerDes subsystem: PCIe_0 pairs with
SerDes_0 and PCIe_1 with SerDes_1. A board device tree that routes a
SerDes lane to PCIe enables the controller and points the root port at
the lane PHY child node of the matching SerDes.
Both SoCs integrate the controllers identically - same register layout
and same GIC SPI assignment - so the nodes differ only in the
compatible: S32G3 adds "nxp,s32g3-pcie" ahead of the "nxp,s32g2-pcie"
base, as the binding describes. The S32G3-VNP-RDB3 and the
S32G2-VNP-RDB2 wire the same two root complexes to the M.2 slots and
the PCIe card slot.
Their configuration space (0x5f_ffffe000 and 0x4f_ffffe000) lies above
the 32-bit window mapped by soc@0, so the controllers are described at
the device tree root rather than under soc@0.
The root ports are labelled (pcie0_rp, pcie1_rp) so board device trees
can extend them by label. An overlay that instead re-declares a pcie@0
child inside the controller node makes dtc emit a unit_address_vs_reg
warning, because the overlay alone carries no reg for that node.
The GIC nodes gain '#address-cells = <0>'. The PCIe interrupt-map
entries name the GIC as their interrupt parent, and without it dtc
warns on every entry and falls back to zero.
Only the S32G3-VNP-RDB3 board device trees in this series enable a
controller; the S32G2 nodes stay disabled until a board enables them.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32g2.dtsi | 81 ++++++++++++++++++++++++++++++++
arch/arm64/boot/dts/freescale/s32g3.dtsi | 81 ++++++++++++++++++++++++++++++++
2 files changed, 162 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 404913b208fb..539840340318 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -918,7 +918,88 @@ gic: interrupt-controller@50800000 {
<0x50420000 0x2000>;
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
+ #address-cells = <0>;
#interrupt-cells = <3>;
};
};
+
+ /*
+ * PCIe controllers. Their config space (0x5f_ffffe000 / 0x4f_ffffe000)
+ * lies above the 32-bit window mapped by soc@0, so the root complexes
+ * are described at the device tree root. Disabled here; a board file
+ * that wires a lane to PCIe enables the controller and adds the phys.
+ */
+ pcie0: pcie@40400000 {
+ compatible = "nxp,s32g2-pcie";
+ reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi */
+ <0x00 0x40420000 0x0 0x00001000>, /* dbi2 */
+ <0x00 0x40460000 0x0 0x00001000>, /* atu */
+ <0x00 0x40470000 0x0 0x00001000>, /* dma */
+ <0x00 0x40481000 0x0 0x000000f8>, /* ctrl */
+ <0x5f 0xffffe000 0x0 0x00002000>; /* config */
+ reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
+ dma-coherent;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x01000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
+ <0x02000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
+ <0x02000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
+ bus-range = <0x0 0xff>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi", "dma";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+
+ pcie0_rp: pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ device_type = "pci";
+ };
+ };
+
+ pcie1: pcie@44100000 {
+ compatible = "nxp,s32g2-pcie";
+ reg = <0x00 0x44100000 0x0 0x00001000>, /* dbi */
+ <0x00 0x44120000 0x0 0x00001000>, /* dbi2 */
+ <0x00 0x44160000 0x0 0x00001000>, /* atu */
+ <0x00 0x44170000 0x0 0x00001000>, /* dma */
+ <0x00 0x44181000 0x0 0x000000f8>, /* ctrl */
+ <0x4f 0xffffe000 0x0 0x00002000>; /* config */
+ reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
+ dma-coherent;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x01000000 0x0 0x00000000 0x4f 0xfffe0000 0x0 0x00010000>,
+ <0x02000000 0x0 0x00000000 0x48 0x00000000 0x0 0x80000000>,
+ <0x02000000 0x1 0x00000000 0x49 0x00000000 0x6 0xfffe0000>;
+ bus-range = <0x0 0xff>;
+ interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi", "dma";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+
+ pcie1_rp: pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ device_type = "pci";
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index 0d001b2895c6..fdf086363c02 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -1058,6 +1058,7 @@ stm11: timer@4052c000 {
gic: interrupt-controller@50800000 {
compatible = "arm,gic-v3";
+ #address-cells = <0>;
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x50800000 0x10000>,
@@ -1069,6 +1070,86 @@ gic: interrupt-controller@50800000 {
};
};
+ /*
+ * PCIe controllers. Their config space (0x5f_ffffe000 / 0x4f_ffffe000)
+ * lies above the 32-bit window mapped by soc@0, so the root complexes
+ * are described at the device tree root. Disabled here; a board file
+ * that wires a lane to PCIe enables the controller and adds the phys.
+ */
+ pcie0: pcie@40400000 {
+ compatible = "nxp,s32g3-pcie", "nxp,s32g2-pcie";
+ reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi */
+ <0x00 0x40420000 0x0 0x00001000>, /* dbi2 */
+ <0x00 0x40460000 0x0 0x00001000>, /* atu */
+ <0x00 0x40470000 0x0 0x00001000>, /* dma */
+ <0x00 0x40481000 0x0 0x000000f8>, /* ctrl */
+ <0x5f 0xffffe000 0x0 0x00002000>; /* config */
+ reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
+ dma-coherent;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x01000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
+ <0x02000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
+ <0x02000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
+ bus-range = <0x0 0xff>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi", "dma";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+
+ pcie0_rp: pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ device_type = "pci";
+ };
+ };
+
+ pcie1: pcie@44100000 {
+ compatible = "nxp,s32g3-pcie", "nxp,s32g2-pcie";
+ reg = <0x00 0x44100000 0x0 0x00001000>, /* dbi */
+ <0x00 0x44120000 0x0 0x00001000>, /* dbi2 */
+ <0x00 0x44160000 0x0 0x00001000>, /* atu */
+ <0x00 0x44170000 0x0 0x00001000>, /* dma */
+ <0x00 0x44181000 0x0 0x000000f8>, /* ctrl */
+ <0x4f 0xffffe000 0x0 0x00002000>; /* config */
+ reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
+ dma-coherent;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x01000000 0x0 0x00000000 0x4f 0xfffe0000 0x0 0x00010000>,
+ <0x02000000 0x0 0x00000000 0x48 0x00000000 0x0 0x80000000>,
+ <0x02000000 0x1 0x00000000 0x49 0x00000000 0x6 0xfffe0000>;
+ bus-range = <0x0 0xff>;
+ interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 214 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi", "dma";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+
+ pcie1_rp: pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ device_type = "pci";
+ };
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupt-parent = <&gic>;
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH RFC v3 12/12] arm64: dts: s32g: Add S32G3-RDB3 SerDes routing variants
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
` (8 preceding siblings ...)
2026-09-19 6:54 ` [PATCH RFC v3 11/12] arm64: dts: s32g: Add PCIe " Jan Petrous via B4 Relay
@ 2026-09-19 6:54 ` Jan Petrous via B4 Relay
[not found] ` <20260919-s32g_serdes-v3-5-9d68868c1e89@oss.nxp.com>
10 siblings, 0 replies; 15+ messages in thread
From: Jan Petrous via B4 Relay @ 2026-09-19 6:54 UTC (permalink / raw)
To: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Jan Petrous (OSS)
From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
The S32G3-VNP-RDB3 board wires GMAC0 to an on-board KSZ9031 RGMII PHY by
default. Add two device tree variants that reroute GMAC0 over the
SerDes_0 XPCS lane for SGMII, matching the two SerDes lane layouts:
- Mode 1: PCIe x1 root complex on lane 0 plus 1G SGMII via GMAC0
(XPCS0) on lane 1.
- Mode 3: dual SGMII, GMAC0 (XPCS0) on lane 0 and PFE_EMAC_2 (XPCS1)
on lane 1.
The SerDes SUBSYS_MODE is derived from the lane child nodes present, so
each layout requires its own board device tree. The Mode 1 variant
enables both PCIe root complexes and extends their root ports by label
(pcie0_rp, pcie1_rp), matching the RDB3 wiring: PCIe_0 reaches the M.2
slots when board switch SW17-2 is ON, PCIe_1 the PCIe card slot.
The GMAC references its PCS with the standard pcs-handle property. On
this board the SGMII lane runs back-to-back to the on-board SJA1110
switch, so there is no PHY on the segment and nothing for phy-handle to
point at - the link partner is a switch port. The MAC-side link is
therefore described as a fixed 1G link and phylink uses out-of-band
negotiation. The SJA1110 itself is not described by these overlays.
Verified on the board:
- Mode 3: GMAC0 links at 1G and passes traffic.
- Mode 1: GMAC0 SGMII path up, and both PCIe root complexes come up -
PCIe_1 enumerates the card-slot NIC and passes traffic at full line
rate, PCIe_0 enumerates the M.2 slot with SW17-2 ON.
Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/Makefile | 6 ++
.../dts/freescale/s32g399a-rdb3-serdes-mode1.dtso | 111 +++++++++++++++++++++
.../dts/freescale/s32g399a-rdb3-serdes-mode3.dtso | 60 +++++++++++
3 files changed, 177 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 95ae85ab4adf..3f68f36ac2be 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -786,5 +786,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-phygate-tauri-l-rs232-rs485.dtb
dtb-$(CONFIG_ARCH_S32) += s32g274a-evb.dtb
dtb-$(CONFIG_ARCH_S32) += s32g274a-rdb2.dtb
dtb-$(CONFIG_ARCH_S32) += s32g399a-rdb3.dtb
+dtb-$(CONFIG_ARCH_S32) += s32g399a-rdb3-serdes-mode1.dtb
+dtb-$(CONFIG_ARCH_S32) += s32g399a-rdb3-serdes-mode3.dtb
+s32g399a-rdb3-serdes-mode1-dtbs := s32g399a-rdb3.dtb s32g399a-rdb3-serdes-mode1.dtbo
+s32g399a-rdb3-serdes-mode3-dtbs := s32g399a-rdb3.dtb s32g399a-rdb3-serdes-mode3.dtbo
+dtb-$(CONFIG_ARCH_S32) += s32g399a-rdb3-serdes-mode1.dtbo
+dtb-$(CONFIG_ARCH_S32) += s32g399a-rdb3-serdes-mode3.dtbo
dtb-$(CONFIG_ARCH_S32) += s32n79-rdb.dtb
dtb-$(CONFIG_ARCH_S32) += s32v234-evb.dtb
diff --git a/arch/arm64/boot/dts/freescale/s32g399a-rdb3-serdes-mode1.dtso b/arch/arm64/boot/dts/freescale/s32g399a-rdb3-serdes-mode1.dtso
new file mode 100644
index 000000000000..43219d9bb6eb
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/s32g399a-rdb3-serdes-mode1.dtso
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2021-2026 NXP
+ *
+ * NXP S32G3 Reference Design Board 3 (S32G-VNP-RDB3),
+ * SerDes_0 Mode 1: PCIe x1 (lane 0) + 1G SGMII via GMAC0 (XPCS0, lane 1).
+ *
+ * Overlay applied on top of s32g399a-rdb3.dtb. It reroutes GMAC0 from the
+ * on-board RGMII PHY to the SerDes_0 XPCS0 lane and brings up the PCIe
+ * controllers as root complexes. The lane layout present here selects
+ * SerDes SUBSYS_MODE 1.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&serdes0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ /* Mode 1 lane layout: PCIe on lane 0, GMAC SGMII (XPCS0) on lane 1. */
+ serdes0_pcie0: phy@0 {
+ reg = <0>;
+ compatible = "nxp,s32g-serdes-pcie-phy";
+ #phy-cells = <0>;
+ };
+
+ serdes0_xpcs0: phy@1 {
+ reg = <1>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <0>;
+ };
+};
+
+&serdes1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ /*
+ * SerDes_1 Mode 1 lane layout: PCIe on lane 0, SGMII (PFE_MAC0
+ * via XPCS0) on lane 1.
+ *
+ * Both lanes must be described: the SerDes driver derives the
+ * SUBSYS_MODE from the full lane mux, so lane 1 has to be present
+ * as XPCS instance 0 (PFE_MAC0) for the mode-1 match to succeed.
+ * PFE is not modeled as a MAC consumer in this upstreaming device
+ * tree, so the XPCS lane is only brought up by the SerDes driver
+ * and left without a pcs-handle user.
+ */
+ serdes1_pcie0: phy@0 {
+ reg = <0>;
+ compatible = "nxp,s32g-serdes-pcie-phy";
+ #phy-cells = <0>;
+ };
+
+ serdes1_xpcs0: phy@1 {
+ reg = <1>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <0>;
+ };
+};
+
+/*
+ * Both PCIe root complexes are wired on the RDB3:
+ * - PCIe_0 reaches the M.2 slots (M-key or E-key) when board switch
+ * SW17-2 is set to ON. It consumes SerDes_0 lane-0 PCIe phy.
+ * - PCIe_1 reaches the PCIe card slot. It consumes SerDes_1 lane-0 PCIe phy.
+ */
+&pcie0 {
+ status = "okay";
+};
+
+&pcie0_rp {
+ num-lanes = <1>;
+ phys = <&serdes0_pcie0>;
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&pcie1_rp {
+ num-lanes = <1>;
+ phys = <&serdes1_pcie0>;
+};
+
+&gmac0 {
+ /delete-property/ phy-handle;
+ clocks = <&clks 24>, <&clks 17>, <&clks 16>, <&clks 15>;
+ clock-names = "stmmaceth", "tx", "rx", "ptp_ref";
+ phy-mode = "sgmii";
+ pcs-handle = <&serdes0_xpcs0>;
+ status = "okay";
+
+ /*
+ * GMAC0 is wired back-to-back to the on-board SJA1110 switch over
+ * this SGMII lane. There is no PHY on the segment, so there is
+ * nothing to reference with phy-handle: the link partner is a
+ * switch port. Describe it as a fixed 1G link; phylink then uses
+ * out-of-band negotiation. The switch itself is not described by
+ * this overlay. The PCS also supports in-band negotiation, for
+ * boards whose link partner is described.
+ */
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ pause;
+ };
+};
diff --git a/arch/arm64/boot/dts/freescale/s32g399a-rdb3-serdes-mode3.dtso b/arch/arm64/boot/dts/freescale/s32g399a-rdb3-serdes-mode3.dtso
new file mode 100644
index 000000000000..195c8043c18a
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/s32g399a-rdb3-serdes-mode3.dtso
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Copyright 2021-2026 NXP
+ *
+ * NXP S32G3 Reference Design Board 3 (S32G-VNP-RDB3),
+ * SerDes_0 Mode 3: dual SGMII, GMAC0 (XPCS0, lane 0) + PFE_EMAC_2
+ * (XPCS1, lane 1), both 1G.
+ *
+ * Overlay applied on top of s32g399a-rdb3.dtb. It reroutes GMAC0 from the
+ * on-board RGMII PHY to the SerDes_0 XPCS0 lane. The lane-1 XPCS1
+ * (PFE_EMAC_2) is described so the mode is derivable and both XPCS
+ * instances are initialised; it has no upstream MAC consumer in this
+ * device tree. The lane layout present here selects SerDes SUBSYS_MODE 3.
+ */
+
+/dts-v1/;
+/plugin/;
+
+&serdes0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ /* Mode 3 lane layout: GMAC SGMII (XPCS0) on lane 0, PFE2 (XPCS1) on lane 1. */
+ serdes0_xpcs0: phy@0 {
+ reg = <0>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <0>;
+ };
+
+ serdes0_xpcs1: phy@1 {
+ reg = <1>;
+ compatible = "nxp,s32g-serdes-xpcs";
+ nxp,xpcs-instance = <1>;
+ };
+};
+
+&gmac0 {
+ /delete-property/ phy-handle;
+ clocks = <&clks 24>, <&clks 17>, <&clks 16>, <&clks 15>;
+ clock-names = "stmmaceth", "tx", "rx", "ptp_ref";
+ phy-mode = "sgmii";
+ pcs-handle = <&serdes0_xpcs0>;
+ status = "okay";
+
+ /*
+ * GMAC0 is wired back-to-back to the on-board SJA1110 switch over
+ * this SGMII lane. There is no PHY on the segment, so there is
+ * nothing to reference with phy-handle: the link partner is a
+ * switch port. Describe it as a fixed 1G link; phylink then uses
+ * out-of-band negotiation. The switch itself is not described by
+ * this overlay. The PCS also supports in-band negotiation, for
+ * boards whose link partner is described.
+ */
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ pause;
+ };
+};
--
2.55.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH RFC v3 07/12] net: stmmac: dwmac-s32: Add SGMII support
2026-09-19 6:54 ` [PATCH RFC v3 07/12] net: stmmac: dwmac-s32: Add SGMII support Jan Petrous via B4 Relay
@ 2026-09-19 12:04 ` Maxime Chevallier
0 siblings, 0 replies; 15+ messages in thread
From: Maxime Chevallier @ 2026-09-19 12:04 UTC (permalink / raw)
To: jan.petrous, Ciprian Marian Costea, NXP S32 Linux Team,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Coquelin, Alexandre Torgue,
Chester Lin, Matthias Brugger, Ghennadi Procopciuc, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Richard Cochran
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot
Hi Jan,
On 9/19/26 08:54, Jan Petrous via B4 Relay wrote:
> From: "Jan Petrous (OSS)" <jan.petrous@oss.nxp.com>
>
> Wire the NXP S32G SerDes XPCS PCS into the dwmac-s32 glue layer so the
> MAC can run SGMII over a SerDes lane.
>
> Changes:
> - s32_gmac_write_phy_intf_select: replace the hard-coded RGMII selector
> with a switch on phy_interface so SGMII (0x01), RGMII, RMII and MII
> all programme the SoC control register correctly.
> - Add s32_gmac_pcs_init: obtain the phylink_pcs handle from the SerDes
> subsystem via s32g_serdes_pcs_create(), keyed by the standard
> pcs-handle property on the GMAC node pointing at the SerDes XPCS lane
> child. Propagates -EPROBE_DEFER if the SerDes driver has not probed
> yet. There is no matching exit hook: the device link created by
> s32g_serdes_pcs_create() covers the lifetime.
> - Add s32_gmac_select_pcs: return the stored PCS handle when the
> negotiated interface is SGMII.
> - Hook pcs_init and select_pcs into plat_stmmacenet_data.
>
> Note that installing a select_pcs callback suppresses the core's
> integrated_pcs fallback, because stmmac treats a NULL return from
> select_pcs as "no PCS" rather than "fall through". This matches what
> dwmac-rzn1 and dwmac-intel already do.
>
> Both negotiation modes are supported by the PCS. The board device
> trees added later in this series describe the MAC-side link as fixed,
> so they exercise the out-of-band path.
>
> The XPCS header guards its s32g_serdes_pcs_create() declaration with
> IS_REACHABLE(CONFIG_PHY_S32G_SERDES) and provides a static-inline stub
> returning -ENODEV otherwise. IS_REACHABLE is false both when the SerDes
> driver is disabled and in the built-in-consumer / modular-provider case
> (DWMAC_S32=y with PHY_S32G_SERDES=m), so this driver links in all four
> combinations of the two symbols.
>
> Linking is not sufficient on its own, though. In the DWMAC_S32=y with
> PHY_S32G_SERDES=m case the stub makes s32_gmac_pcs_init() return
> -ENODEV, and stmmac treats a failing plat->pcs_init() as fatal, so a
> built-in MAC would refuse to probe on any device tree describing
> pcs-handle. Add a Kconfig dependency forbidding that combination
> rather than letting it build into a MAC that cannot probe.
>
> Tested on an S32G3-VNP-RDB3 board: GMAC0 links at 1G over SGMII and
> passes traffic, both in SerDes mode 1 (alongside two active PCIe root
> complexes) and in mode 3.
>
> Signed-off-by: Jan Petrous (OSS) <jan.petrous@oss.nxp.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/Kconfig | 6 ++
> drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c | 74 ++++++++++++++++++++++++-
> 2 files changed, 78 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> index e3dd5adda5ac..1443ff4149b4 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
> +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> @@ -192,6 +192,12 @@ config DWMAC_S32
> tristate "NXP S32G/S32R GMAC support"
> default ARCH_S32
> depends on OF && (ARCH_S32 || COMPILE_TEST)
> + # SGMII needs the PCS from the SerDes driver. The header falls back
> + # to a stub returning -ENODEV when that driver is not reachable, and
> + # stmmac makes a failing plat->pcs_init() fatal, so a built-in MAC
> + # with a modular SerDes would refuse to probe on any DT describing
> + # pcs-handle. Forbid that combination instead.
> + depends on PHY_S32G_SERDES || PHY_S32G_SERDES=n
select PHY_S32G_SERDES ? This is what other glues that require PCS do,
or there's a catch that prevents using it ?
> help
> Support for ethernet controller on NXP S32CC SOCs.
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> index 024d8e10e918..a3a56b21181a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c
> @@ -16,12 +16,14 @@
> #include <linux/of_mdio.h>
> #include <linux/of_address.h>
> #include <linux/phy.h>
> +#include <linux/phy/nxp-s32g-serdes.h>
> #include <linux/phylink.h>
> #include <linux/platform_device.h>
> #include <linux/regmap.h>
> #include <linux/stmmac.h>
>
> #include "stmmac_platform.h"
> +#include "stmmac.h"
>
> #define GMAC_INTF_RATE_125M 125000000 /* 125MHz */
>
> @@ -40,23 +42,89 @@ struct s32_priv_data {
> phy_interface_t *intf_mode;
> struct clk *tx_clk;
> struct clk *rx_clk;
> + /* SGMII PCS provided by the SerDes subsystem (NULL if not SGMII) */
> + struct phylink_pcs *pcs;
There's already a phylink_pcs pointer in priv->hw, you shouldn't have to
store your own here.
> };
>
> static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac)
> {
> + u32 intf_sel;
> int ret = 0;
>
> + switch (*gmac->intf_mode) {
> + case PHY_INTERFACE_MODE_SGMII:
> + intf_sel = S32_PHY_INTF_SEL_SGMII;
> + break;
> + case PHY_INTERFACE_MODE_RGMII:
> + case PHY_INTERFACE_MODE_RGMII_ID:
> + case PHY_INTERFACE_MODE_RGMII_RXID:
> + case PHY_INTERFACE_MODE_RGMII_TXID:
> + intf_sel = S32_PHY_INTF_SEL_RGMII;
> + break;
> + case PHY_INTERFACE_MODE_RMII:
> + intf_sel = S32_PHY_INTF_SEL_RMII;
> + break;
> + case PHY_INTERFACE_MODE_MII:
> + intf_sel = S32_PHY_INTF_SEL_MII;
> + break;
> + default:
> + dev_err(gmac->dev, "Unsupported phy interface mode: %s\n",
> + phy_modes(*gmac->intf_mode));
> + return -EINVAL;
> + }
We go from supporting RGMII only to RGMII + RMII + MII + SGMII.
Are RMII and MII actually supported on that platform ? if so, can you split
that into 2 commits : one for proper inft_sel support with RMII + MII added,
the another one for SGMII ?
> +
> if (gmac->ctrl_sts)
> - writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts);
> + writel(intf_sel, gmac->ctrl_sts);
> else
> ret = regmap_write(gmac->sts_regmap, gmac->sts_offset,
> - S32_PHY_INTF_SEL_RGMII);
> + intf_sel);
>
> dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode));
>
> return ret;
> }
>
> +static int s32_gmac_pcs_init(struct stmmac_priv *priv)
> +{
> + struct s32_priv_data *gmac = priv->plat->bsp_priv;
> + struct device_node *pcs_node;
> +
> + /*
> + * pcs-handle points at the SerDes XPCS lane child node; its
> + * nxp,xpcs-instance property is what identifies the XPCS instance.
> + */
> + pcs_node = of_parse_phandle(gmac->dev->of_node, "pcs-handle", 0);
> + if (!pcs_node) {
> + dev_dbg(gmac->dev, "no 'pcs-handle' property, SGMII PCS unavailable\n");
> + return 0;
> + }
> +
> + gmac->pcs = s32g_serdes_pcs_create(gmac->dev, pcs_node);
> + of_node_put(pcs_node);
> +
> + if (IS_ERR(gmac->pcs)) {
> + int err = PTR_ERR(gmac->pcs);
> +
> + gmac->pcs = NULL;
> + /* SerDes may not be probed yet - defer probe. */
> + return err;
> + }
> +
> + dev_dbg(gmac->dev, "SGMII PCS created via SerDes XPCS\n");
> + return 0;
> +}
> +
> +static struct phylink_pcs *s32_gmac_select_pcs(struct stmmac_priv *priv,
> + phy_interface_t interface)
> +{
> + struct s32_priv_data *gmac = priv->plat->bsp_priv;
> +
> + if (interface == PHY_INTERFACE_MODE_SGMII && gmac->pcs)
> + return gmac->pcs;
No need for the && gmac->pcs here, if it's NULL we return NULL anyway so you
can return priv->hw->phylink_pcs
> +
> + return NULL;
> +}
> +
> static int s32_gmac_init(struct device *dev, void *priv)
> {
> struct s32_priv_data *gmac = priv;
> @@ -204,6 +272,8 @@ static int s32_dwmac_probe(struct platform_device *pdev)
>
> plat->init = s32_gmac_init;
> plat->exit = s32_gmac_exit;
> + plat->pcs_init = s32_gmac_pcs_init;
> + plat->select_pcs = s32_gmac_select_pcs;
>
> plat->clk_tx_i = gmac->tx_clk;
> plat->set_clk_tx_rate = stmmac_set_clk_tx_rate;
>
Thanks,
Maxime
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core
2026-09-19 6:54 ` [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core Jan Petrous via B4 Relay
@ 2026-09-19 15:31 ` Maxime Chevallier
2026-09-19 16:31 ` Coia Prant
2026-09-20 18:39 ` Andrew Lunn
1 sibling, 1 reply; 15+ messages in thread
From: Maxime Chevallier @ 2026-09-19 15:31 UTC (permalink / raw)
To: jan.petrous, Ciprian Marian Costea, NXP S32 Linux Team,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Coquelin, Alexandre Torgue,
Chester Lin, Matthias Brugger, Ghennadi Procopciuc, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Richard Cochran, Coia Prant
Cc: linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot
Hi Jan,
On 9/19/26 08:54, Jan Petrous via B4 Relay wrote:
> From: Clark Wang <xiaoning.wang@nxp.com>
>
> The SerDes subsystems found on NXP S32G and i.MX SoCs integrate a
> Synopsys DesignWare Ethernet XPCS and an Ethernet PHY (PMA) with an
> identical register layout. Only the register transport differs: indirect
> memory mapped access on S32G, Clause 45 MDIO on i.MX.
>
> Add a transport agnostic phylink PCS core which operates on regmaps
> provided by the platform glue. It implements the phylink PCS operations,
> the Clause 37 SGMII / 2500BASE-X / USXGMII / 10GBASE-R configuration and
> link state handling, soft reset and polling helpers, and the common
> feature sets. The platform specific register sequences, compatibility
> tables and quirks are supplied through a per revision descriptor by the
> platform drivers selecting this core.
>
> The register sequences and the feature lists are derived from the
> Synopsys pcs-xpcs driver, so its copyright is retained. A separate driver
> is needed because struct dw_xpcs is built around an mdio_device and owns
> the transport, the reset and the identification of a standalone PCS,
> while here the PMA can be shared with a PCIe controller, the bring-up is
> sequenced across both XPCS instances by the SerDes PHY driver, and the
> transport is not always MDIO.
Is there a way to avoid code duplication by wrapping the accesses into
a mii_bus ?
This is what the Rockchip submission does :
https://lore.kernel.org/r/20260919125119.2107089-8-coiaprant@gmail.com
Maxime
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core
2026-09-19 15:31 ` Maxime Chevallier
@ 2026-09-19 16:31 ` Coia Prant
0 siblings, 0 replies; 15+ messages in thread
From: Coia Prant @ 2026-09-19 16:31 UTC (permalink / raw)
To: Maxime Chevallier
Cc: jan.petrous, Ciprian Marian Costea, NXP S32 Linux Team,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Andrew Lunn, Heiner Kallweit, Russell King,
Clark Wang, Philipp Zabel, Maxime Coquelin, Alexandre Torgue,
Chester Lin, Matthias Brugger, Ghennadi Procopciuc, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Richard Cochran, linux-arm-kernel, linux-phy, netdev, devicetree,
linux-kernel, linux-renesas-soc, imx, linux-pci, linux-stm32,
Vincent Guittot
Maxime Chevallier <maxime.chevallier@bootlin.com> 于2026年9月19日周六 23:31写道:
>
> Hi Jan,
>
> On 9/19/26 08:54, Jan Petrous via B4 Relay wrote:
> > From: Clark Wang <xiaoning.wang@nxp.com>
> >
> > The SerDes subsystems found on NXP S32G and i.MX SoCs integrate a
> > Synopsys DesignWare Ethernet XPCS and an Ethernet PHY (PMA) with an
> > identical register layout. Only the register transport differs: indirect
> > memory mapped access on S32G, Clause 45 MDIO on i.MX.
> >
> > Add a transport agnostic phylink PCS core which operates on regmaps
> > provided by the platform glue. It implements the phylink PCS operations,
> > the Clause 37 SGMII / 2500BASE-X / USXGMII / 10GBASE-R configuration and
> > link state handling, soft reset and polling helpers, and the common
> > feature sets. The platform specific register sequences, compatibility
> > tables and quirks are supplied through a per revision descriptor by the
> > platform drivers selecting this core.
> >
> > The register sequences and the feature lists are derived from the
> > Synopsys pcs-xpcs driver, so its copyright is retained. A separate driver
> > is needed because struct dw_xpcs is built around an mdio_device and owns
> > the transport, the reset and the identification of a standalone PCS,
> > while here the PMA can be shared with a PCIe controller, the bring-up is
> > sequenced across both XPCS instances by the SerDes PHY driver, and the
> > transport is not always MDIO.
>
> Is there a way to avoid code duplication by wrapping the accesses into
> a mii_bus ?
>
> This is what the Rockchip submission does :
>
> https://lore.kernel.org/r/20260919125119.2107089-8-coiaprant@gmail.com
>
> Maxime
Hi Maxime,
The Rockchip approach (wrapping MMIO into a virtual mii_bus and reusing
pcs-xpcs.c) is indeed relevant here. Alex Elder's pcs-xpcs-regmap does
exactly that for the TC956x: it registers the XPCS through a regmap and
creates the virtual MDIO bus internally, with both direct and indirect
(page viewport) access modes.
https://lore.kernel.org/all/20260605010022.968612-4-elder@riscstar.com/
The indirect mode is very close to what S32G needs. For i.MX the C45
MDIO transport is different, but the bus wrapper could still be shared.
That said, I think there is a broader gap in pcs-xpcs.c: it hardcodes
behaviors that vary between integrations. RK3568 cannot use out-of-band
SGMII (fixed 125 MHz MAC clock), so its in-band caps should be
LINK_INBAND_ENABLE only. Today that means editing xpcs_inband_caps() or
duplicating it. NXP is hitting the same kind of problem with soft reset,
poll and EEE quirks.
A callback in dw_xpcs would let platform glues express those differences without
copying the register sequences. That's the same pattern stmmac uses with
plat->pcs_init/pcs_exit.
Once that callback mechanism lands, I'll send a separate patch to wire
it up in pcs-xpcs-rk.c. Since the Rockchip driver is not even merged
yet, there is nothing to change there for now.
Coia
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH RFC v3 05/12] net: pcs: Add NXP S32G XPCS driver
[not found] ` <20260919-s32g_serdes-v3-5-9d68868c1e89@oss.nxp.com>
@ 2026-09-20 17:07 ` Andrew Lunn
0 siblings, 0 replies; 15+ messages in thread
From: Andrew Lunn @ 2026-09-20 17:07 UTC (permalink / raw)
To: jan.petrous
Cc: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Heiner Kallweit, Russell King, Clark Wang,
Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran,
linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot,
Alexandru-Catalin Ionita, Bogdan Roman
> +#define SR_MII_CTRL 0x1f0000
This is 0x1f0000 + MII_BMCR
> +#define SS13 BIT(13)
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
> +#define AN_ENABLE BIT(12)
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
> +#define RESTART_AN BIT(9)
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
> +#define DUPLEX_MODE BIT(8)
#define BMCR_FULLDPLX 0x0100 /* Full duplex */
> +#define SS6 BIT(6)
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
> +#define SR_MII_STS 0x1f0001
This is 0x1f0000 + MII_BMSR
> +#define LINK_STS BIT(2)
#define BMSR_LSTATUS 0x0004 /* Link status */
Please go through all these register definitions and throw out all the
ones which follow 801.3 and use the values from include/uapi/linux/mii.h
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core
2026-09-19 6:54 ` [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core Jan Petrous via B4 Relay
2026-09-19 15:31 ` Maxime Chevallier
@ 2026-09-20 18:39 ` Andrew Lunn
1 sibling, 0 replies; 15+ messages in thread
From: Andrew Lunn @ 2026-09-20 18:39 UTC (permalink / raw)
To: jan.petrous
Cc: Ciprian Marian Costea, NXP S32 Linux Team, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Ghennadi Procopciuc,
Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Geert Uytterhoeven, Magnus Damm, Lorenzo Pieralisi,
Krzysztof Wilczyński, Bjorn Helgaas, Bogdan Hamciuc,
Ionut Vicovan, Heiner Kallweit, Russell King, Clark Wang,
Philipp Zabel, Maxime Chevallier, Maxime Coquelin,
Alexandre Torgue, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Richard Cochran,
linux-arm-kernel, linux-phy, netdev, devicetree, linux-kernel,
linux-renesas-soc, imx, linux-pci, linux-stm32, Vincent Guittot
On Sat, Sep 19, 2026 at 08:54:32AM +0200, Jan Petrous via B4 Relay wrote:
> From: Clark Wang <xiaoning.wang@nxp.com>
>
> The SerDes subsystems found on NXP S32G and i.MX SoCs integrate a
> Synopsys DesignWare Ethernet XPCS and an Ethernet PHY (PMA) with an
> identical register layout. Only the register transport differs: indirect
> memory mapped access on S32G, Clause 45 MDIO on i.MX.
>
> Add a transport agnostic phylink PCS core which operates on regmaps
> provided by the platform glue.
What is not transport agnostic with the current code.
Think carefully about that, before you answer.
Andrew
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-09-20 18:39 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com>
2026-09-19 6:54 ` [PATCH RFC v3 01/12] dt-bindings: phy: Add NXP S32G SerDes subsystem Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 02/12] dt-bindings: net: nxp,s32-dwmac: Document pcs-handle Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 03/12] dt-bindings: PCI: nxp,s32g-pcie: Fix SerDes PHY phandle in example Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 04/12] net: pcs: add NXP SerDes XPCS shared core Jan Petrous via B4 Relay
2026-09-19 15:31 ` Maxime Chevallier
2026-09-19 16:31 ` Coia Prant
2026-09-20 18:39 ` Andrew Lunn
2026-09-19 6:54 ` [PATCH RFC v3 07/12] net: stmmac: dwmac-s32: Add SGMII support Jan Petrous via B4 Relay
2026-09-19 12:04 ` Maxime Chevallier
2026-09-19 6:54 ` [PATCH RFC v3 08/12] MAINTAINERS: Add NXP S32G SerDes and SerDes xPCS core entries Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 09/12] arm64: dts: s32g: Add SCMI reset controller Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 10/12] arm64: dts: s32g: Add SerDes controller nodes Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 11/12] arm64: dts: s32g: Add PCIe " Jan Petrous via B4 Relay
2026-09-19 6:54 ` [PATCH RFC v3 12/12] arm64: dts: s32g: Add S32G3-RDB3 SerDes routing variants Jan Petrous via B4 Relay
[not found] ` <20260919-s32g_serdes-v3-5-9d68868c1e89@oss.nxp.com>
2026-09-20 17:07 ` [PATCH RFC v3 05/12] net: pcs: Add NXP S32G XPCS driver Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox