Devicetree
 help / color / mirror / Atom feed
* [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
@ 2026-09-23  1:07 Mohd Ayaan Anwar
  2026-09-23  1:07 ` [PATCH RFC net-next 1/9] dt-bindings: net: pcs: add Qualcomm Nord XPCS Mohd Ayaan Anwar
                   ` (10 more replies)
  0 siblings, 11 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Hi,

This is an early RFC which adds the XPCS and ETHQOS plumbing required
to enable 10 Gigabit Ethernet on the Qualcomm Nord SoC. This is the
first time USXGMII together with an external PCS is being supported by
the dwmac-qcom-ethqos driver.

This platform was somewhat tricky to work on, with several new pieces
having to come together across the MAC, XPCS and SerDes layers. Any
feedback would be appreciated, particularly around the XPCS modelling
and the generic stmmac register-layout changes.

The overall hardware path looks like this:

  +------------------+      +------------------+      +------------------+      +------------------+
  |    DW25GMAC      | ---> |  Synopsys XPCS   | ---> | QCOM SGMII PHY   | ===> | Ext PHY / Switch |
  | + QCOM ETHQOS    |      | + QCOM wrapper   |      |    (SerDes)      |      | USX/10GBASE-R    |
  +------------------+      +------------------+      +------------------+      +------------------+

The series can be broadly divided into two areas:

1. Qualcomm XPCS support

Nord integrates a Synopsys DesignWare XPCS, but exposes the PCS,
PMA/PMD and MII MMD register regions through separate direct-MMIO
windows instead of the standard contiguous or indirect XPCS mappings.
Patches 1 through 5 add the binding, generic platform register-access
hooks, the Qualcomm MMD-to-MMIO translation, and the runtime-PM handling
needed for the CSR clock.

The XPCS also uses Clause 37 control and status for USXGMII, while the
generic XPCS support currently handles USXGMII using Clause 73. Patch 2
adds the required Clause 37 USXGMII configuration and link-state path.

Using a small Qualcomm-specific access layer around the existing XPCS
core was the most straightforward way I could find to model this IP.
The core already uses synthetic IDs for the NXP integrations and has
vendor-specific hooks for other XPCS implementations, so this series
follows a similar approach. I am very much open to suggestions if there
is a cleaner way to represent the non-standard register mapping.

2. DW25GMAC and Qualcomm ETHQOS support

Patches 6 through 9 add the Nord ETHQOS binding and driver support. The
Nord integration has sparse, platform-specific MTL queue and DMA channel
addresses, as well as a relocated timestamp register bank. The series
therefore adds optional XGMAC register-layout data while preserving the
standard layout for existing platforms.

The ETHQOS driver then selects the XPCS provided through pcs-handle and
adds the Nord wrapper programming required for USXGMII, including the
EEE clock vote needed for PCS link-up and the platform-specific SerDes
loopback control.

This series has an obvious dependency on Jitendra Vegiraju's DW25GMAC
work:
https://lore.kernel.org/netdev/20260402213629.1996133-1-jitendra.vegiraju@broadcom.com/

I understand that a v10 of that series is planned. While bringing up
Nord, I also needed a few fixes on top of the DW25GMAC series. Those are
not included here; I will share them separately with Jitendra in case
they are useful for the next revision.

Testing:
Initial testing was done on the Nord Ride SX platform, where both
Ethernet ports connect to the on-board MV-Q6223 switch using fixed-link
USXGMII at 10 Gbps. The testing tree included the DW25GMAC dependency
and the additional fixups mentioned above.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
Mohd Ayaan Anwar (9):
      dt-bindings: net: pcs: add Qualcomm Nord XPCS
      net: pcs: xpcs: add USXGMII Clause 37 autoneg support
      net: pcs: xpcs: add custom platform register accessors
      net: pcs: xpcs: add Qualcomm Nord platform support
      net: pcs: xpcs: initialize runtime PM as suspended
      dt-bindings: net: qcom,ethqos: add Qualcomm Nord
      net: stmmac: support custom XGMAC register layouts
      net: stmmac: qcom-ethqos: support external PCS
      net: stmmac: qcom-ethqos: add Qualcomm Nord support

 .../devicetree/bindings/net/pcs/snps,dw-xpcs.yaml  |  17 +++
 .../devicetree/bindings/net/qcom,ethqos.yaml       |  57 ++++++--
 .../devicetree/bindings/net/snps,dwmac.yaml        |   2 +
 drivers/net/ethernet/stmicro/stmmac/common.h       |   1 +
 .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c    | 162 ++++++++++++++++++++-
 .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c    |   2 +-
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h     |  94 ++++++++----
 .../net/ethernet/stmicro/stmmac/dwxgmac2_core.c    |  34 +++--
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 128 +++++++++-------
 drivers/net/ethernet/stmicro/stmmac/hwif.c         |   5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |   5 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c   |  15 +-
 drivers/net/pcs/Makefile                           |   3 +-
 drivers/net/pcs/pcs-xpcs-plat.c                    |  47 +++++-
 drivers/net/pcs/pcs-xpcs-qcom.c                    |  86 +++++++++++
 drivers/net/pcs/pcs-xpcs-qcom.h                    |  16 ++
 drivers/net/pcs/pcs-xpcs.c                         | 126 ++++++++++++++++
 drivers/net/pcs/pcs-xpcs.h                         |  15 ++
 include/linux/pcs/pcs-xpcs.h                       |   2 +
 include/linux/stmmac.h                             |  11 ++
 20 files changed, 707 insertions(+), 121 deletions(-)
---
base-commit: 6598456d72e48d779445bfec8f72114747f8b8d7
change-id: 20260923-qcom_xpcs_nord_emac-bf296eb48e4b

Best regards,
-- 
Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>


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

* [PATCH RFC net-next 1/9] dt-bindings: net: pcs: add Qualcomm Nord XPCS
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-23  1:07 ` [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support Mohd Ayaan Anwar
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Document the Qualcomm Nord integrated DesignWare XPCS compatible. The
XPCS resides in an Ethernet power domain and requires its CSR clock for
register access, so require the clock and power-domain resources for
this compatible.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 .../devicetree/bindings/net/pcs/snps,dw-xpcs.yaml       | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml b/Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml
index e77eec9ac9ee08d2e11a28975f61f8c36b4e0a95..68bb941cbb290d29bbd94d7280b89d2ad0f38e7a 100644
--- a/Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml
+++ b/Documentation/devicetree/bindings/net/pcs/snps,dw-xpcs.yaml
@@ -22,6 +22,17 @@ description:
   by means of the APB3/MCI interfaces. In the later case the XPCS can be mapped
   right to the system IO memory space.
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          const: qcom,nord-dw-xpcs
+    then:
+      required:
+        - clocks
+        - clock-names
+        - power-domains
+
 properties:
   compatible:
     oneOf:
@@ -41,6 +52,8 @@ properties:
         const: snps,dw-xpcs-gen5-10g
       - description: Synopsys DesignWare XPCS with Consumer Gen5 12G PMA
         const: snps,dw-xpcs-gen5-12g
+      - description: Qualcomm Nord integrated DesignWare XPCS
+        const: qcom,nord-dw-xpcs
 
   reg:
     items:
@@ -98,6 +111,10 @@ properties:
           - enum: [core, pad]
           - const: pad
 
+  power-domains:
+    description: Power domain containing the integrated PCS registers
+    maxItems: 1
+
 required:
   - compatible
   - reg

-- 
2.34.1


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

* [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
  2026-09-23  1:07 ` [PATCH RFC net-next 1/9] dt-bindings: net: pcs: add Qualcomm Nord XPCS Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-23 13:31   ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  2026-09-23  1:07 ` [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors Mohd Ayaan Anwar
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

The generic DesignWare XPCS support currently associates USXGMII with
Clause 73 auto-negotiation. The XPCS integration on Qualcomm Nord
instead uses the vendor MII register block and Clause 37 control and
status for USXGMII.

Add a separate Clause 37 USXGMII mode which configures the PCS for
BASE-R, enables single-port 10G-SXGMII operation and enables
PHY-side Clause 37 auto-negotiation.

Also decode the negotiated link, speed and duplex from the vendor
Clause 37 status register. This supports 10 Mbps through 10 Gbps link
rates exposed by the USXGMII status fields.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 drivers/net/pcs/pcs-xpcs.c   | 113 +++++++++++++++++++++++++++++++++++++++++++
 drivers/net/pcs/pcs-xpcs.h   |  15 ++++++
 include/linux/pcs/pcs-xpcs.h |   1 +
 3 files changed, 129 insertions(+)

diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 0337e2bcc01258e102a649e3b7fce41c65a3dd05..7f5c7a275630f2b064e4b9abdd6c3619e9346cec 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -283,6 +283,7 @@ static int xpcs_soft_reset(struct dw_xpcs *xpcs,
 	switch (compat->an_mode) {
 	case DW_AN_C73:
 	case DW_10GBASER:
+	case DW_AN_C37_USXGMII:
 		dev = MDIO_MMD_PCS;
 		break;
 	case DW_AN_C37_SGMII:
@@ -355,6 +356,54 @@ static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
 	return 0;
 }
 
+static int xpcs_config_aneg_c37_usxgmii(struct dw_xpcs *xpcs)
+{
+	u16 mask, val;
+	int ret;
+
+	/* Select BASE-R PCS mode. */
+	ret = xpcs_modify(xpcs, MDIO_MMD_PCS, MDIO_CTRL2,
+			  DW_PCS_TYPE_SEL, MDIO_PCS_CTRL2_10GBR);
+	if (ret < 0)
+		return ret;
+
+	/* Enable USXGMII before accessing the MII MMD registers. */
+	ret = xpcs_modify_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1,
+			       DW_USXGMII_EN, DW_USXGMII_EN);
+	if (ret < 0)
+		return ret;
+
+	/* Select single-port 10G-SXGMII mode. */
+	ret = xpcs_modify_vpcs(xpcs, DW_VR_XS_PCS_KR_CTRL,
+			       DW_USXG_MODE_SEL,
+			       FIELD_PREP(DW_USXG_MODE_SEL,
+					  DW_USXG_MODE_10G_SXGMII));
+	if (ret < 0)
+		return ret;
+
+	/* Disable Clause 37 AN before changing its configuration. */
+	ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+			  BMCR_ANENABLE, 0);
+	if (ret < 0)
+		return ret;
+
+	/* Configure USXGMII per XPCS databook section 7.6. */
+	mask = DW_VR_MII_AN_CTRL_8BIT | DW_VR_MII_SGMII_LINK_STS |
+	       DW_VR_MII_TX_CONFIG_MASK | DW_VR_MII_PCS_MODE_MASK |
+	       DW_VR_MII_AN_INTR_EN;
+	val = FIELD_PREP(DW_VR_MII_TX_CONFIG_MASK,
+			 DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII) |
+	      DW_VR_MII_SGMII_LINK_STS;
+
+	ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL,
+			  mask, val);
+	if (ret < 0)
+		return ret;
+
+	return xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR,
+			   BMCR_ANENABLE, BMCR_ANENABLE);
+}
+
 static void xpcs_link_up_usxgmii(struct dw_xpcs *xpcs, int speed)
 {
 	int ret, speed_sel;
@@ -687,6 +736,7 @@ static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
 
 	case DW_10GBASER:
 	case DW_2500BASEX:
+	case DW_AN_C37_USXGMII:
 		return LINK_INBAND_DISABLE;
 
 	default:
@@ -950,6 +1000,11 @@ static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
 		if (ret)
 			return ret;
 		break;
+	case DW_AN_C37_USXGMII:
+		ret = xpcs_config_aneg_c37_usxgmii(xpcs);
+		if (ret)
+			return ret;
+		break;
 	case DW_2500BASEX:
 		ret = xpcs_config_2500basex(xpcs);
 		if (ret)
@@ -1158,6 +1213,58 @@ static int xpcs_get_state_2500basex(struct dw_xpcs *xpcs,
 	return 0;
 }
 
+static int xpcs_get_state_c37_usxgmii(struct dw_xpcs *xpcs,
+				      struct phylink_link_state *state)
+{
+	u16 speed;
+	int ret;
+
+	state->link = false;
+	state->an_complete = false;
+	state->speed = SPEED_UNKNOWN;
+	state->duplex = DUPLEX_UNKNOWN;
+	state->pause = 0;
+
+	ret = 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);
+	state->link = !!(ret & DW_VR_MII_USXG_LINK);
+	if (!state->link)
+		return 0;
+
+	speed = FIELD_GET(DW_VR_MII_USXG_SPEED, ret);
+	switch (speed) {
+	case DW_VR_MII_USXG_SPEED_10:
+		state->speed = SPEED_10;
+		break;
+	case DW_VR_MII_USXG_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case DW_VR_MII_USXG_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	case DW_VR_MII_USXG_SPEED_10000:
+		state->speed = SPEED_10000;
+		break;
+	case DW_VR_MII_USXG_SPEED_2500:
+		state->speed = SPEED_2500;
+		break;
+	case DW_VR_MII_USXG_SPEED_5000:
+		state->speed = SPEED_5000;
+		break;
+	default:
+		state->link = false;
+		return 0;
+	}
+
+	state->duplex = ret & DW_VR_MII_USXG_FULL ?
+			DUPLEX_FULL : DUPLEX_HALF;
+
+	return 0;
+}
+
 static void xpcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
 			   struct phylink_link_state *state)
 {
@@ -1191,6 +1298,12 @@ static void xpcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
 			dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n",
 				"xpcs_get_state_c37_1000basex", ERR_PTR(ret));
 		break;
+	case DW_AN_C37_USXGMII:
+		ret = xpcs_get_state_c37_usxgmii(xpcs, state);
+		if (ret)
+			dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n",
+				"xpcs_get_state_c37_usxgmii", ERR_PTR(ret));
+		break;
 	case DW_2500BASEX:
 		ret = xpcs_get_state_2500basex(xpcs, state);
 		if (ret)
diff --git a/drivers/net/pcs/pcs-xpcs.h b/drivers/net/pcs/pcs-xpcs.h
index 929fa238445ed550677850b9b89149e952ac9fd6..cbf583ff55ba0884efb9c8b63a07154628ee5ea2 100644
--- a/drivers/net/pcs/pcs-xpcs.h
+++ b/drivers/net/pcs/pcs-xpcs.h
@@ -13,6 +13,7 @@
 #define DW_VENDOR			BIT(15)
 
 /* VR_XS_PCS */
+#define DW_PCS_TYPE_SEL			GENMASK(3, 0)
 #define DW_USXGMII_RST			BIT(10)
 #define DW_USXGMII_EN			BIT(9)
 #define DW_VR_XS_PCS_DIG_CTRL1		0x0000
@@ -20,6 +21,9 @@
 #define DW_EN_VSMMD1			BIT(13)
 #define DW_CL37_BP			BIT(12)
 #define DW_VR_XS_PCS_DIG_STS		0x0010
+#define DW_VR_XS_PCS_KR_CTRL		0x0007
+#define DW_USXG_MODE_SEL		GENMASK(12, 10)
+#define DW_USXG_MODE_10G_SXGMII		0
 #define DW_RXFIFO_ERR			GENMASK(6, 5)
 #define DW_PSEQ_ST			GENMASK(4, 2)
 #define DW_PSEQ_ST_GOOD			FIELD_PREP(GENMASK(4, 2), 0x4)
@@ -68,6 +72,7 @@
 #define DW_VR_MII_PCS_MODE_C37_1000BASEX	0x0
 #define DW_VR_MII_PCS_MODE_C37_SGMII		0x2
 #define DW_VR_MII_AN_INTR_EN			BIT(0)
+#define DW_VR_MII_SGMII_LINK_STS		BIT(4)
 
 #define DW_VR_MII_AN_INTR_STS		0x8002
 #define DW_VR_MII_AN_STS_C37_ANCMPLT_INTR	BIT(0)
@@ -78,6 +83,16 @@
 #define DW_VR_MII_C37_ANSGM_SP_1000		0x2
 #define DW_VR_MII_C37_ANSGM_SP_LNKSTS		BIT(4)
 
+#define DW_VR_MII_USXG_LINK		BIT(14)
+#define DW_VR_MII_USXG_FULL		BIT(13)
+#define DW_VR_MII_USXG_SPEED		GENMASK(12, 10)
+#define DW_VR_MII_USXG_SPEED_10		0
+#define DW_VR_MII_USXG_SPEED_100	1
+#define DW_VR_MII_USXG_SPEED_1000	2
+#define DW_VR_MII_USXG_SPEED_10000	3
+#define DW_VR_MII_USXG_SPEED_2500	4
+#define DW_VR_MII_USXG_SPEED_5000	5
+
 #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 */
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index 36073f7b6bb40e02c523112f79b3c55838a778e2..4ea995b70150e33e1e1a47cc7aa324c53742fbdc 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -20,6 +20,7 @@
 #define DW_2500BASEX			3
 #define DW_AN_C37_1000BASEX		4
 #define DW_10GBASER			5
+#define DW_AN_C37_USXGMII		6
 
 enum dw_xpcs_pcs_id {
 	DW_XPCS_ID_NATIVE = 0,

-- 
2.34.1


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

* [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
  2026-09-23  1:07 ` [PATCH RFC net-next 1/9] dt-bindings: net: pcs: add Qualcomm Nord XPCS Mohd Ayaan Anwar
  2026-09-23  1:07 ` [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-23 12:18   ` Andrew Lunn
  2026-09-25 10:18   ` Lorenzo Bianconi
  2026-09-23  1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
                   ` (7 subsequent siblings)
  10 siblings, 2 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Some XPCS integrations do not expose the standard direct or indirect
register layout. Allow the platform driver to use optional register read
and write callbacks for both Clause 22 and Clause 45 accesses, while
retaining the existing access paths when no callbacks are supplied.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 drivers/net/pcs/pcs-xpcs-plat.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index e669a7b248ac4677aeb5cd1874108f5c87f837d2..e78a233fb198d940951064a71e8597c6c666bc9d 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -24,8 +24,16 @@
 /* Page select register for the indirect MMIO CSRs access */
 #define DW_VR_CSR_VIEWPORT		0xff
 
+struct dw_xpcs_plat_ops {
+	int (*reg_read)(struct platform_device *pdev, void __iomem *reg_base,
+			int dev, int reg);
+	int (*reg_write)(struct platform_device *pdev, void __iomem *reg_base,
+			 int dev, int reg, u16 val);
+};
+
 struct dw_xpcs_plat {
 	struct platform_device *pdev;
+	const struct dw_xpcs_plat_ops *ops;
 	struct mii_bus *bus;
 	bool reg_indir;
 	int reg_width;
@@ -169,6 +177,10 @@ static int xpcs_mmio_read_c22(struct mii_bus *bus, int addr, int reg)
 	if (addr != 0)
 		return -ENODEV;
 
+	if (pxpcs->ops)
+		return pxpcs->ops->reg_read(pxpcs->pdev, pxpcs->reg_base,
+					    MDIO_MMD_VEND2, reg);
+
 	if (pxpcs->reg_indir)
 		return xpcs_mmio_read_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg);
 	else
@@ -182,6 +194,10 @@ static int xpcs_mmio_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)
 	if (addr != 0)
 		return -ENODEV;
 
+	if (pxpcs->ops)
+		return pxpcs->ops->reg_write(pxpcs->pdev, pxpcs->reg_base,
+					     MDIO_MMD_VEND2, reg, val);
+
 	if (pxpcs->reg_indir)
 		return xpcs_mmio_write_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg, val);
 	else
@@ -195,6 +211,10 @@ static int xpcs_mmio_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
 	if (addr != 0)
 		return -ENODEV;
 
+	if (pxpcs->ops)
+		return pxpcs->ops->reg_read(pxpcs->pdev, pxpcs->reg_base,
+					    dev, reg);
+
 	if (pxpcs->reg_indir)
 		return xpcs_mmio_read_reg_indirect(pxpcs, dev, reg);
 	else
@@ -209,6 +229,10 @@ static int xpcs_mmio_write_c45(struct mii_bus *bus, int addr, int dev,
 	if (addr != 0)
 		return -ENODEV;
 
+	if (pxpcs->ops)
+		return pxpcs->ops->reg_write(pxpcs->pdev, pxpcs->reg_base,
+					     dev, reg, val);
+
 	if (pxpcs->reg_indir)
 		return xpcs_mmio_write_reg_indirect(pxpcs, dev, reg, val);
 	else

-- 
2.34.1


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

* [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (2 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-23 12:07   ` Andrew Lunn
                     ` (2 more replies)
  2026-09-23  1:07 ` [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended Mohd Ayaan Anwar
                   ` (6 subsequent siblings)
  10 siblings, 3 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Qualcomm Nord exposes the DesignWare XPCS register blocks through
separate direct-MMIO windows instead of the standard contiguous
MMD/register layout. Add accessors that translate MMD accesses to the
Nord windows:

  MMD 3 (PCS), standard registers: SR_XS at 0x0000
  MMD 3 (PCS), vendor registers:   VR_XS at 0x2000
  MMD 1 (PMA/PMD):                  SR_PMA at 0x3000
  MMD 31 (VEND2), standard regs:    SR_MII at 0x4000
  MMD 31 (VEND2), vendor registers: VR_MII at 0x5000

Each register uses a 32-bit MMIO stride. The vendor bit is removed from
the register index before calculating a vendor-window offset.

Select these accessors using the Nord synthetic XPCS ID, allow its
smaller direct-MMIO resource, and add the Nord USXGMII Clause 37
compatibility.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 drivers/net/pcs/Makefile        |  3 +-
 drivers/net/pcs/pcs-xpcs-plat.c | 17 +++++++-
 drivers/net/pcs/pcs-xpcs-qcom.c | 86 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/pcs/pcs-xpcs-qcom.h | 16 ++++++++
 drivers/net/pcs/pcs-xpcs.c      | 13 +++++++
 include/linux/pcs/pcs-xpcs.h    |  1 +
 6 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index 4f7920618b90051e839a74a7101aaaf055a77f74..3d7cf1a5cd0783078edcefc6dfec626af469495d 100644
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -2,7 +2,8 @@
 # Makefile for Linux PCS drivers
 
 pcs_xpcs-$(CONFIG_PCS_XPCS)	:= pcs-xpcs.o pcs-xpcs-plat.o \
-				   pcs-xpcs-nxp.o pcs-xpcs-wx.o
+				   pcs-xpcs-nxp.o pcs-xpcs-qcom.o \
+				   pcs-xpcs-wx.o
 
 obj-$(CONFIG_PCS_XPCS)		+= pcs_xpcs.o
 obj-$(CONFIG_PCS_LYNX)		+= pcs-lynx.o
diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index e78a233fb198d940951064a71e8597c6c666bc9d..e013a5253a22651220e62352d03faabc3a3c3658 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -20,6 +20,7 @@
 #include <linux/sizes.h>
 
 #include "pcs-xpcs.h"
+#include "pcs-xpcs-qcom.h"
 
 /* Page select register for the indirect MMIO CSRs access */
 #define DW_VR_CSR_VIEWPORT		0xff
@@ -239,8 +240,14 @@ static int xpcs_mmio_write_c45(struct mii_bus *bus, int addr, int dev,
 		return xpcs_mmio_write_reg_direct(pxpcs, dev, reg, val);
 }
 
+static const struct dw_xpcs_plat_ops xpcs_qcom_ops = {
+	.reg_read = xpcs_qcom_reg_read,
+	.reg_write = xpcs_qcom_reg_write,
+};
+
 static struct dw_xpcs_plat *xpcs_plat_create_data(struct platform_device *pdev)
 {
+	const struct dw_xpcs_info *info;
 	struct dw_xpcs_plat *pxpcs;
 
 	pxpcs = devm_kzalloc(&pdev->dev, sizeof(*pxpcs), GFP_KERNEL);
@@ -248,6 +255,12 @@ static struct dw_xpcs_plat *xpcs_plat_create_data(struct platform_device *pdev)
 		return ERR_PTR(-ENOMEM);
 
 	pxpcs->pdev = pdev;
+	info = device_get_match_data(&pdev->dev);
+	if (!info)
+		return ERR_PTR(-EINVAL);
+
+	if (info->pcs == QCOM_NORD_XPCS_ID)
+		pxpcs->ops = &xpcs_qcom_ops;
 
 	dev_set_drvdata(&pdev->dev, pxpcs);
 
@@ -285,7 +298,7 @@ static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)
 	else
 		spc_size = pxpcs->reg_width * SZ_2M;
 
-	if (resource_size(res) < spc_size) {
+	if (!pxpcs->ops && resource_size(res) < spc_size) {
 		dev_err(dev, "Invalid reg-space size\n");
 		return -EINVAL;
 	}
@@ -452,8 +465,10 @@ DW_XPCS_INFO_DECLARE(xpcs_pma_gen4_3g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN4_3G_ID
 DW_XPCS_INFO_DECLARE(xpcs_pma_gen4_6g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN4_6G_ID);
 DW_XPCS_INFO_DECLARE(xpcs_pma_gen5_10g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN5_10G_ID);
 DW_XPCS_INFO_DECLARE(xpcs_pma_gen5_12g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN5_12G_ID);
+DW_XPCS_INFO_DECLARE(xpcs_qcom_nord, QCOM_NORD_XPCS_ID, DW_XPCS_PMA_ID_NATIVE);
 
 static const struct of_device_id xpcs_of_ids[] = {
+	{ .compatible = "qcom,nord-dw-xpcs", .data = &xpcs_qcom_nord },
 	{ .compatible = "snps,dw-xpcs", .data = &xpcs_generic },
 	{ .compatible = "snps,dw-xpcs-gen1-3g", .data = &xpcs_pma_gen1_3g },
 	{ .compatible = "snps,dw-xpcs-gen2-3g", .data = &xpcs_pma_gen2_3g },
diff --git a/drivers/net/pcs/pcs-xpcs-qcom.c b/drivers/net/pcs/pcs-xpcs-qcom.c
new file mode 100644
index 0000000000000000000000000000000000000000..63c95c951454819b62eb3fd00abcc6b529e2004b
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-qcom.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Qualcomm DesignWare XPCS platform helpers
+ *
+ * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/io.h>
+#include <linux/mdio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "pcs-xpcs.h"
+#include "pcs-xpcs-qcom.h"
+
+/* Qualcomm Nord direct MMIO XPCS windows. */
+#define QCOM_XPCS_SR_XS_BASE		0x0000
+#define QCOM_XPCS_VR_XS_BASE		0x2000
+#define QCOM_XPCS_SR_PMA_BASE		0x3000
+#define QCOM_XPCS_SR_MII_BASE		0x4000
+#define QCOM_XPCS_VR_MII_BASE		0x5000
+
+static int xpcs_qcom_reg_offset(int dev, int reg)
+{
+	switch (dev) {
+	case MDIO_MMD_PCS:
+		if (reg & DW_VENDOR)
+			return QCOM_XPCS_VR_XS_BASE +
+			       ((reg & ~DW_VENDOR) << 2);
+
+		return QCOM_XPCS_SR_XS_BASE + (reg << 2);
+
+	case MDIO_MMD_PMAPMD:
+		return QCOM_XPCS_SR_PMA_BASE + (reg << 2);
+
+	case MDIO_MMD_VEND2:
+		if (reg >= DW_VENDOR)
+			return QCOM_XPCS_VR_MII_BASE +
+			       ((reg - DW_VENDOR) << 2);
+
+		return QCOM_XPCS_SR_MII_BASE + (reg << 2);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+int xpcs_qcom_reg_read(struct platform_device *pdev, void __iomem *reg_base,
+		       int dev, int reg)
+{
+	int offset, ret;
+
+	offset = xpcs_qcom_reg_offset(dev, reg);
+	if (offset < 0)
+		return offset;
+
+	ret = pm_runtime_resume_and_get(&pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	ret = readl(reg_base + offset) & 0xffff;
+
+	pm_runtime_put(&pdev->dev);
+
+	return ret;
+}
+
+int xpcs_qcom_reg_write(struct platform_device *pdev, void __iomem *reg_base,
+			int dev, int reg, u16 val)
+{
+	int offset, ret;
+
+	offset = xpcs_qcom_reg_offset(dev, reg);
+	if (offset < 0)
+		return offset;
+
+	ret = pm_runtime_resume_and_get(&pdev->dev);
+	if (ret < 0)
+		return ret;
+
+	writel(val, reg_base + offset);
+
+	pm_runtime_put(&pdev->dev);
+
+	return 0;
+}
diff --git a/drivers/net/pcs/pcs-xpcs-qcom.h b/drivers/net/pcs/pcs-xpcs-qcom.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1084f6a10a96baa8ba0d192ee64cdaed90da125
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-qcom.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __PCS_XPCS_QCOM_H
+#define __PCS_XPCS_QCOM_H
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+struct platform_device;
+
+int xpcs_qcom_reg_read(struct platform_device *pdev, void __iomem *reg_base,
+		       int dev, int reg);
+int xpcs_qcom_reg_write(struct platform_device *pdev, void __iomem *reg_base,
+			int dev, int reg, u16 val);
+
+#endif /* __PCS_XPCS_QCOM_H */
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 7f5c7a275630f2b064e4b9abdd6c3619e9346cec..1f556b4f7c44f06f24a2f724734d3a7d71424de3 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -1571,6 +1571,15 @@ static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[] = {
 	}
 };
 
+static const struct dw_xpcs_compat qcom_nord_xpcs_compat[] = {
+	{
+		.interface = PHY_INTERFACE_MODE_USXGMII,
+		.supported = xpcs_usxgmii_features,
+		.an_mode = DW_AN_C37_USXGMII,
+	}, {
+	}
+};
+
 static const struct dw_xpcs_desc xpcs_desc_list[] = {
 	{
 		.id = DW_XPCS_ID,
@@ -1584,6 +1593,10 @@ static const struct dw_xpcs_desc xpcs_desc_list[] = {
 		.id = NXP_SJA1110_XPCS_ID,
 		.mask = DW_XPCS_ID_MASK,
 		.compat = nxp_sja1110_xpcs_compat,
+	}, {
+		.id = QCOM_NORD_XPCS_ID,
+		.mask = DW_XPCS_ID_MASK,
+		.compat = qcom_nord_xpcs_compat,
 	},
 };
 
diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
index 4ea995b70150e33e1e1a47cc7aa324c53742fbdc..0f69e14b2a4c8d17b59a570debd14a77ab040182 100644
--- a/include/linux/pcs/pcs-xpcs.h
+++ b/include/linux/pcs/pcs-xpcs.h
@@ -26,6 +26,7 @@ enum dw_xpcs_pcs_id {
 	DW_XPCS_ID_NATIVE = 0,
 	NXP_SJA1105_XPCS_ID = 0x00000010,
 	NXP_SJA1110_XPCS_ID = 0x00000020,
+	QCOM_NORD_XPCS_ID = 0x00000030,
 	DW_XPCS_ID = 0x7996ced0,
 	DW_XPCS_ID_MASK = 0xffffffff,
 };

-- 
2.34.1


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

* [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (3 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-25 11:03   ` Lorenzo Bianconi
  2026-09-23  1:07 ` [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord Mohd Ayaan Anwar
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

xpcs_plat_init_clk() acquires the optional CSR clock but does not
prepare or enable it. Marking the device runtime-active at that point
makes the PM core assume that the hardware is already powered.

On Nord, once the XPCS CSR clock was described, the first
pm_runtime_resume_and_get() accessed XPCS registers without invoking
runtime_resume() to enable the clock. The matching runtime put then
invoked runtime_suspend() and attempted to disable a clock which was
never enabled, producing an already-disabled clock warning.

Initialize the runtime-PM state as suspended instead. The first
register access now runs the resume callback and enables the CSR clock,
while the subsequent suspend callback performs the matching disable.
Check and propagate the state-transition error as part of probe.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 drivers/net/pcs/pcs-xpcs-plat.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index e013a5253a22651220e62352d03faabc3a3c3658..328c50940d46eb8e7bea06ecd1a20214e3cde61c 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -322,7 +322,11 @@ static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
 		return dev_err_probe(dev, PTR_ERR(pxpcs->cclk),
 				     "Failed to get CSR clock\n");
 
-	pm_runtime_set_active(dev);
+	ret = pm_runtime_set_suspended(dev);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to set runtime-PM suspended state\n");
+
 	ret = devm_pm_runtime_enable(dev);
 	if (ret) {
 		dev_err(dev, "Failed to enable runtime-PM\n");

-- 
2.34.1


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

* [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (4 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  2026-09-23  1:07 ` [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts Mohd Ayaan Anwar
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Qualcomm Nord integrates two ETHQOS controllers based on the Synopsys
DesignWare 25GMAC IP. Each controller has five clocks, one power domain
and ten SMMU stream mappings.

Due to a hardware quirk, PCS link-up depends on the EEE clock being
enabled.

Add the Nord compatible and describe its platform-specific resource
requirements. Also add Nord to the common DWMAC schema exceptions used
by Qualcomm ETHQOS platforms.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 .../devicetree/bindings/net/qcom,ethqos.yaml       | 57 +++++++++++++++++-----
 .../devicetree/bindings/net/snps,dwmac.yaml        |  2 +
 2 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
index 423959cb928d945aa3e758a3c803d12bd61ec42b..41de2ccd56458ed20620905d5d3716b3d2568531 100644
--- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
+++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
@@ -11,11 +11,33 @@ maintainers:
   - Konrad Dybcio <konradybcio@kernel.org>
 
 description:
-  dwmmac based Qualcomm ethernet devices which support Gigabit
-  ethernet (version v2.3.0 and onwards).
+  DWMAC and XGMAC based Qualcomm Ethernet devices supporting Gigabit and
+  multi-gigabit Ethernet.
 
 allOf:
   - $ref: snps,dwmac.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: qcom,nord-ethqos
+    then:
+      properties:
+        clocks:
+          minItems: 5
+          maxItems: 5
+        clock-names:
+          minItems: 5
+          maxItems: 5
+        iommus:
+          minItems: 10
+          maxItems: 10
+      required:
+        - power-domains
+    else:
+      properties:
+        iommus:
+          maxItems: 1
 
 properties:
   compatible:
@@ -30,6 +52,7 @@ properties:
           - const: qcom,sa8775p-ethqos
       - enum:
           - qcom,qcs404-ethqos
+          - qcom,nord-ethqos
           - qcom,sa8775p-ethqos
           - qcom,sc8280xp-ethqos
           - qcom,sm8150-ethqos
@@ -57,19 +80,31 @@ properties:
       - const: sfty
 
   clocks:
-    maxItems: 4
+    minItems: 4
+    maxItems: 5
 
   clock-names:
-    items:
-      - const: stmmaceth
-      - const: pclk
-      - const: ptp_ref
-      - enum:
-          - rgmii
-          - phyaux
+    oneOf:
+      - items:
+          - const: stmmaceth
+          - const: pclk
+          - const: ptp_ref
+          - const: phyaux
+          - const: eee
+            description: |
+              Due to a hardware quirk, PCS link-up depends on the EEE clock
+              being enabled.
+      - items:
+          - const: stmmaceth
+          - const: pclk
+          - const: ptp_ref
+          - enum:
+              - rgmii
+              - phyaux
 
   iommus:
-    maxItems: 1
+    minItems: 1
+    maxItems: 10
 
   dma-coherent: true
 
diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
index 0ff9e3284a06124cb0a3ee62e2ea6d0b1f7f646d..e8c2911d9817cdf64e426a5a02d5f335a0fb8241 100644
--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
@@ -72,6 +72,7 @@ properties:
         - nuvoton,ma35d1-dwmac
         - nxp,s32g2-dwmac
         - qcom,qcs404-ethqos
+        - qcom,nord-ethqos
         - qcom,sa8775p-ethqos
         - qcom,sc8280xp-ethqos
         - qcom,sm8150-ethqos
@@ -631,6 +632,7 @@ allOf:
                 - ingenic,x1830-mac
                 - ingenic,x2000-mac
                 - qcom,qcs404-ethqos
+                - qcom,nord-ethqos
                 - qcom,sa8775p-ethqos
                 - qcom,sc8280xp-ethqos
                 - qcom,sm8150-ethqos

-- 
2.34.1


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

* [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (5 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  2026-09-25 12:22   ` Lorenzo Bianconi
  2026-09-23  1:07 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
                   ` (3 subsequent siblings)
  10 siblings, 2 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Some XGMAC integrations place their MTL queues and DMA channels at
different offsets from the standard register layout. Allow platform
data to override these addresses while retaining the standard layout by
default.

This follows the approach used by commit 33719b57f52e ("net: stmmac:
dwmac4: Allow platforms to specify some DMA/MTL offsets"). Qualcomm
XGMAC hardware similarly uses differently aligned queue and channel
registers.

Also allow platforms to override the timestamp register base.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |   1 +
 .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c    |   2 +-
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h     |  94 ++++++++++-----
 .../net/ethernet/stmicro/stmmac/dwxgmac2_core.c    |  34 +++---
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 128 +++++++++++++--------
 drivers/net/ethernet/stmicro/stmmac/hwif.c         |   5 +-
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |   5 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c   |  15 ++-
 include/linux/stmmac.h                             |  11 ++
 9 files changed, 193 insertions(+), 102 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 1729fb29ece3853584bc27ed541413bcba88c695..c6387cecaf5d93ef10c45475a533bf1d0a4e0b45 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -622,6 +622,7 @@ struct mac_device_info {
 	const struct stmmac_mmc_ops *mmc;
 	const struct stmmac_est_ops *est;
 	const struct stmmac_vlan_ops *vlan;
+	const struct dwxgmac_addrs *dwxgmac_addrs;
 	struct dw_xpcs *xpcs;
 	struct phylink_pcs *phylink_pcs;
 	struct mii_regs mii;	/* MII register Addresses */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 1d7f0a57d28897005cdc1c5dcbd3c2f737a6c967..331ba38abae66f03b69c383b30762c9a09735a37 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -365,7 +365,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
 	};
 
 	num_snapshot = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK,
-				 readl(ioaddr + XGMAC_TIMESTAMP_STATUS));
+				 readl(ioaddr + XGMAC_TIMESTAMP_STATUS(NULL)));
 
 	/* Repeat until the timestamps are from the FIFO last segment */
 	for (i = 0; i < num_snapshot; i++) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index f8ab347f7b5b9e1b2df662785bb25cf875456088..22b476358a2028de862186c3d38295b2d48d87d6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -220,12 +220,21 @@
 #define XGMAC_CT			BIT(1)
 #define XGMAC_OB			BIT(0)
 #define XGMAC_RSS_DATA			0x00000c8c
-#define XGMAC_TIMESTAMP_STATUS		0x00000d20
+
+/* Timestamp registers */
+#define XGMAC_TIMESTAMP_BASE_ADDR	0x00000d00
+
+static inline u32 xgmac_timestamp_base_addr(const struct dwxgmac_addrs *addrs)
+{
+	return addrs ? addrs->timestamp_base : XGMAC_TIMESTAMP_BASE_ADDR;
+}
+
+#define XGMAC_TIMESTAMP_STATUS(a)	(xgmac_timestamp_base_addr(a) + 0x20)
 #define XGMAC_TIMESTAMP_ATSNS_MASK	GENMASK(29, 25)
 #define XGMAC_TXTSC			BIT(15)
-#define XGMAC_TXTIMESTAMP_NSEC		0x00000d30
+#define XGMAC_TXTIMESTAMP_NSEC(a)	(xgmac_timestamp_base_addr(a) + 0x30)
 #define XGMAC_TXTSSTSLO			GENMASK(30, 0)
-#define XGMAC_TXTIMESTAMP_SEC		0x00000d34
+#define XGMAC_TXTIMESTAMP_SEC(a)	(xgmac_timestamp_base_addr(a) + 0x34)
 #define XGMAC_PPS_CONTROL		0x00000d70
 #define XGMAC_PPS_MAXIDX(x)		((((x) + 1) * 8) - 1)
 #define XGMAC_PPS_MINIDX(x)		((x) * 8)
@@ -285,37 +294,49 @@
 #define XGMAC_MTL_ECC_INT_STATUS	0x000010cc
 #define XGMAC_MTL_DPP_CONTROL		0x000010e0
 #define XGMAC_DPP_DISABLE		BIT(0)
-#define XGMAC_MTL_TXQ_OPMODE(x)		(0x00001100 + (0x80 * (x)))
+
+/* MTL per-queue registers */
+#define XGMAC_MTL_CHAN_BASE_ADDR	0x00001100
+#define XGMAC_MTL_CHAN_OFFSET		0x80
+
+static inline u32
+xgmac_mtl_chanx_base_addr(const struct dwxgmac_addrs *addrs, u32 x)
+{
+	return addrs ? addrs->mtl_chan_base + x * addrs->mtl_chan_offset
+		     : XGMAC_MTL_CHAN_BASE_ADDR + x * XGMAC_MTL_CHAN_OFFSET;
+}
+
+#define XGMAC_MTL_TXQ_OPMODE(a, x)		xgmac_mtl_chanx_base_addr(a, x)
 #define XGMAC_TQS			GENMASK(25, 16)
 #define XGMAC_Q2TCMAP			GENMASK(10, 8)
 #define XGMAC_TTC			GENMASK(6, 4)
 #define XGMAC_TXQEN			GENMASK(3, 2)
 #define XGMAC_TSF			BIT(1)
-#define XGMAC_MTL_TCx_ETS_CONTROL(x)	(0x00001110 + (0x80 * (x)))
-#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x)	(0x00001118 + (0x80 * (x)))
-#define XGMAC_MTL_TCx_SENDSLOPE(x)	(0x0000111c + (0x80 * (x)))
-#define XGMAC_MTL_TCx_HICREDIT(x)	(0x00001120 + (0x80 * (x)))
-#define XGMAC_MTL_TCx_LOCREDIT(x)	(0x00001124 + (0x80 * (x)))
+#define XGMAC_MTL_TCx_ETS_CONTROL(a, x)	(xgmac_mtl_chanx_base_addr(a, x) + 0x10)
+#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(a, x)	(xgmac_mtl_chanx_base_addr(a, x) + 0x18)
+#define XGMAC_MTL_TCx_SENDSLOPE(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x1c)
+#define XGMAC_MTL_TCx_HICREDIT(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x20)
+#define XGMAC_MTL_TCx_LOCREDIT(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x24)
 #define XGMAC_CC			BIT(3)
 #define XGMAC_TSA			GENMASK(1, 0)
 #define XGMAC_SP			(0x0 << 0)
 #define XGMAC_CBS			(0x1 << 0)
 #define XGMAC_ETS			(0x2 << 0)
-#define XGMAC_MTL_RXQ_OPMODE(x)		(0x00001140 + (0x80 * (x)))
+#define XGMAC_MTL_RXQ_OPMODE(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x40)
 #define XGMAC_RQS			GENMASK(25, 16)
 #define XGMAC_EHFC			BIT(7)
 #define XGMAC_RSF			BIT(5)
 #define XGMAC_RTC			GENMASK(1, 0)
-#define XGMAC_MTL_RXQ_FLOW_CONTROL(x)	(0x00001150 + (0x80 * (x)))
+#define XGMAC_MTL_RXQ_FLOW_CONTROL(a, x)	(xgmac_mtl_chanx_base_addr(a, x) + 0x50)
 #define XGMAC_RFD			GENMASK(31, 17)
 #define XGMAC_RFA			GENMASK(15, 1)
-#define XGMAC_MTL_QINTEN(x)		(0x00001170 + (0x80 * (x)))
+#define XGMAC_MTL_QINTEN(a, x)			(xgmac_mtl_chanx_base_addr(a, x) + 0x70)
 #define XGMAC_RXOIE			BIT(16)
-#define XGMAC_MTL_QINT_STATUS(x)	(0x00001174 + (0x80 * (x)))
+#define XGMAC_MTL_QINT_STATUS(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x74)
 #define XGMAC_RXOVFIS			BIT(16)
 #define XGMAC_ABPSIS			BIT(1)
 #define XGMAC_TXUNFIS			BIT(0)
-#define XGMAC_MAC_REGSIZE		(XGMAC_MTL_QINT_STATUS(15) / 4)
+#define XGMAC_MAC_REGSIZE(a)		(XGMAC_MTL_QINT_STATUS(a, 15) / 4)
 
 /* DMA Registers */
 #define XGMAC_DMA_MODE			0x00003000
@@ -353,28 +374,43 @@
 #define XGMAC_TCEIE			BIT(0)
 #define XGMAC_DMA_ECC_INT_STATUS	0x0000306c
 #define XGMAC_DMA_DPP_INT_STATUS	0x00003074
-#define XGMAC_DMA_CH_CONTROL(x)		(0x00003100 + (0x80 * (x)))
+
+/* DMA per-channel registers */
+#define XGMAC_DMA_CHAN_BASE_ADDR	0x00003100
+#define XGMAC_DMA_CHAN_OFFSET		0x80
+
+static inline u32
+xgmac_dma_chanx_base_addr(const struct dwxgmac_addrs *addrs, u32 x)
+{
+	if (addrs && (x & 1))
+		return addrs->dma_odd_chan_base + x * addrs->dma_chan_offset;
+	if (addrs)
+		return addrs->dma_even_chan_base + x * addrs->dma_chan_offset;
+	return XGMAC_DMA_CHAN_BASE_ADDR + x * XGMAC_DMA_CHAN_OFFSET;
+}
+
+#define XGMAC_DMA_CH_CONTROL(a, x)		(xgmac_dma_chanx_base_addr(a, x))
 #define XGMAC_SPH			BIT(24)
 #define XGMAC_PBLx8			BIT(16)
-#define XGMAC_DMA_CH_TX_CONTROL(x)	(0x00003104 + (0x80 * (x)))
+#define XGMAC_DMA_CH_TX_CONTROL(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x04)
 #define XGMAC_EDSE			BIT(28)
 #define XGMAC_TxPBL			GENMASK(21, 16)
 #define XGMAC_TSE			BIT(12)
 #define XGMAC_OSP			BIT(4)
 #define XGMAC_TXST			BIT(0)
-#define XGMAC_DMA_CH_RX_CONTROL(x)	(0x00003108 + (0x80 * (x)))
+#define XGMAC_DMA_CH_RX_CONTROL(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x08)
 #define XGMAC_RxPBL			GENMASK(21, 16)
 #define XGMAC_RBSZ			GENMASK(14, 1)
 #define XGMAC_RXST			BIT(0)
-#define XGMAC_DMA_CH_TxDESC_HADDR(x)	(0x00003110 + (0x80 * (x)))
-#define XGMAC_DMA_CH_TxDESC_LADDR(x)	(0x00003114 + (0x80 * (x)))
-#define XGMAC_DMA_CH_RxDESC_HADDR(x)	(0x00003118 + (0x80 * (x)))
-#define XGMAC_DMA_CH_RxDESC_LADDR(x)	(0x0000311c + (0x80 * (x)))
-#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(x)	(0x00003124 + (0x80 * (x)))
-#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(x)	(0x0000312c + (0x80 * (x)))
-#define XGMAC_DMA_CH_TxDESC_RING_LEN(x)		(0x00003130 + (0x80 * (x)))
-#define XGMAC_DMA_CH_RxDESC_RING_LEN(x)		(0x00003134 + (0x80 * (x)))
-#define XGMAC_DMA_CH_INT_EN(x)		(0x00003138 + (0x80 * (x)))
+#define XGMAC_DMA_CH_TxDESC_HADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x10)
+#define XGMAC_DMA_CH_TxDESC_LADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x14)
+#define XGMAC_DMA_CH_RxDESC_HADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x18)
+#define XGMAC_DMA_CH_RxDESC_LADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x1c)
+#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x24)
+#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x2c)
+#define XGMAC_DMA_CH_TxDESC_RING_LEN(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x30)
+#define XGMAC_DMA_CH_RxDESC_RING_LEN(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x34)
+#define XGMAC_DMA_CH_INT_EN(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x38)
 #define XGMAC_NIE			BIT(15)
 #define XGMAC_AIE			BIT(14)
 #define XGMAC_RBUE			BIT(7)
@@ -385,9 +421,9 @@
 					XGMAC_RIE | XGMAC_TIE)
 #define XGMAC_DMA_INT_DEFAULT_RX	(XGMAC_RIE)
 #define XGMAC_DMA_INT_DEFAULT_TX	(XGMAC_TIE)
-#define XGMAC_DMA_CH_Rx_WATCHDOG(x)	(0x0000313c + (0x80 * (x)))
+#define XGMAC_DMA_CH_Rx_WATCHDOG(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x3c)
 #define XGMAC_RWT			GENMASK(7, 0)
-#define XGMAC_DMA_CH_STATUS(x)		(0x00003160 + (0x80 * (x)))
+#define XGMAC_DMA_CH_STATUS(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x60)
 #define XGMAC_NIS			BIT(15)
 #define XGMAC_AIS			BIT(14)
 #define XGMAC_FBE			BIT(12)
@@ -396,7 +432,7 @@
 #define XGMAC_TBU			BIT(2)
 #define XGMAC_TPS			BIT(1)
 #define XGMAC_TI			BIT(0)
-#define XGMAC_REGSIZE			((0x0000317c + (0x80 * 15)) / 4)
+#define XGMAC_REGSIZE(a)		((xgmac_dma_chanx_base_addr(a, 15) + 0x7c) / 4)
 
 #define XGMAC_DMA_STATUS_MSK_COMMON	(XGMAC_NIS | XGMAC_AIS | XGMAC_FBE)
 #define XGMAC_DMA_STATUS_MSK_RX		(XGMAC_RBU | XGMAC_RI | \
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index 1a88cbaed70ca18bbb714681569ede863f7130e5..d1099a1cf9ea56661e2beceeaa3f1938e51dfb3c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -234,11 +234,11 @@ static void dwxgmac2_prog_mtl_tx_algorithms(struct mac_device_info *hw,
 
 	/* Set ETS if desired */
 	for (i = 0; i < MTL_MAX_TX_QUEUES; i++) {
-		value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(i));
+		value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(hw->dwxgmac_addrs, i));
 		value &= ~XGMAC_TSA;
 		if (ets)
 			value |= XGMAC_ETS;
-		writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(i));
+		writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(hw->dwxgmac_addrs, i));
 	}
 }
 
@@ -246,9 +246,10 @@ static void dwxgmac2_set_mtl_tx_queue_weight(struct stmmac_priv *priv,
 					     struct mac_device_info *hw,
 					     u32 weight, u32 queue)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	void __iomem *ioaddr = hw->pcsr;
 
-	writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
+	writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(addrs, queue));
 }
 
 static void dwxgmac2_map_mtl_to_dma(struct mac_device_info *hw, u32 queue,
@@ -273,18 +274,19 @@ static void dwxgmac2_config_cbs(struct stmmac_priv *priv,
 				u32 send_slope, u32 idle_slope,
 				u32 high_credit, u32 low_credit, u32 queue)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
 
-	writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(queue));
-	writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
-	writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(queue));
-	writel(low_credit, ioaddr + XGMAC_MTL_TCx_LOCREDIT(queue));
+	writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(addrs, queue));
+	writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(addrs, queue));
+	writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(addrs, queue));
+	writel(low_credit, ioaddr + XGMAC_MTL_TCx_LOCREDIT(addrs, queue));
 
-	value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
+	value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(addrs, queue));
 	value &= ~XGMAC_TSA;
 	value |= XGMAC_CC | XGMAC_CBS;
-	writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
+	writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(addrs, queue));
 }
 
 static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space)
@@ -292,7 +294,7 @@ static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space)
 	void __iomem *ioaddr = hw->pcsr;
 	int i;
 
-	for (i = 0; i < XGMAC_MAC_REGSIZE; i++)
+	for (i = 0; i < XGMAC_MAC_REGSIZE(hw->dwxgmac_addrs); i++)
 		reg_space[i] = readl(ioaddr + i * 4);
 }
 
@@ -336,18 +338,19 @@ static int dwxgmac2_host_irq_status(struct stmmac_priv *priv,
 static int dwxgmac2_host_mtl_irq_status(struct stmmac_priv *priv,
 					struct mac_device_info *hw, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	void __iomem *ioaddr = hw->pcsr;
 	int ret = 0;
 	u32 status;
 
 	status = readl(ioaddr + XGMAC_MTL_INT_STATUS);
 	if (status & BIT(chan)) {
-		u32 chan_status = readl(ioaddr + XGMAC_MTL_QINT_STATUS(chan));
+		u32 chan_status = readl(ioaddr + XGMAC_MTL_QINT_STATUS(addrs, chan));
 
 		if (chan_status & XGMAC_RXOVFIS)
 			ret |= CORE_IRQ_MTL_RX_OVERFLOW;
 
-		writel(~0x0, ioaddr + XGMAC_MTL_QINT_STATUS(chan));
+		writel(~0x0, ioaddr + XGMAC_MTL_QINT_STATUS(addrs, chan));
 	}
 
 	return ret;
@@ -1143,14 +1146,15 @@ static int dwxgmac3_rxp_config(void __iomem *ioaddr,
 static int dwxgmac2_get_mac_tx_timestamp(struct mac_device_info *hw, u64 *ts)
 {
 	void __iomem *ioaddr = hw->pcsr;
+	const struct dwxgmac_addrs *addrs = hw->dwxgmac_addrs;
 	u32 value;
 
-	if (readl_poll_timeout_atomic(ioaddr + XGMAC_TIMESTAMP_STATUS,
+	if (readl_poll_timeout_atomic(ioaddr + XGMAC_TIMESTAMP_STATUS(addrs),
 				      value, value & XGMAC_TXTSC, 100, 10000))
 		return -EBUSY;
 
-	*ts = readl(ioaddr + XGMAC_TXTIMESTAMP_NSEC) & XGMAC_TXTSSTSLO;
-	*ts += readl(ioaddr + XGMAC_TXTIMESTAMP_SEC) * 1000000000ULL;
+	*ts = readl(ioaddr + XGMAC_TXTIMESTAMP_NSEC(addrs)) & XGMAC_TXTSSTSLO;
+	*ts += readl(ioaddr + XGMAC_TXTIMESTAMP_SEC(addrs)) * 1000000000ULL;
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index ff83858ebc1f33aa8092a2d83018bd5f96b7eead..65d5e2a828076563a1c7368124ddda226bfffc7a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -47,13 +47,14 @@ static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv,
 				   void __iomem *ioaddr,
 				   struct stmmac_dma_cfg *dma_cfg, u32 chan)
 {
-	u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
 
 	if (dma_cfg->pblx8)
 		value |= XGMAC_PBLx8;
 
-	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
-	writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
+	writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
 }
 
 static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
@@ -61,15 +62,16 @@ static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
 				      struct stmmac_dma_cfg *dma_cfg,
 				      dma_addr_t phy, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 	value = u32_replace_bits(value, rxpbl, XGMAC_RxPBL);
-	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 
-	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
-	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
+	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(addrs, chan));
+	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(addrs, chan));
 }
 
 static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
@@ -77,15 +79,16 @@ static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
 				      struct stmmac_dma_cfg *dma_cfg,
 				      dma_addr_t phy, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 	value = u32_replace_bits(value, txpbl, XGMAC_TxPBL);
-	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 
-	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
-	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
+	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(addrs, chan));
+	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(addrs, chan));
 }
 
 static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
@@ -118,16 +121,18 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
 static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv,
 				   void __iomem *ioaddr, u32 *reg_space)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	int i;
 
-	for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++)
+	for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE(addrs); i++)
 		reg_space[i] = readl(ioaddr + i * 4);
 }
 
 static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
 				 int mode, u32 channel, int fifosz, u8 qmode)
 {
-	u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(addrs, channel));
 	unsigned int rqs = fifosz / 256 - 1;
 	unsigned int rtc;
 
@@ -149,7 +154,7 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
 	value = u32_replace_bits(value, rqs, XGMAC_RQS);
 
 	if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
-		u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
+		u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(addrs, channel));
 		unsigned int rfd, rfa;
 
 		value |= XGMAC_EHFC;
@@ -178,16 +183,17 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
 		flow = u32_replace_bits(flow, rfd, XGMAC_RFD);
 		flow = u32_replace_bits(flow, rfa, XGMAC_RFA);
 
-		writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
+		writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(addrs, channel));
 	}
 
-	writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
+	writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(addrs, channel));
 }
 
 static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
 				 int mode, u32 channel, int fifosz, u8 qmode)
 {
-	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(addrs, channel));
 	unsigned int tqs = fifosz / 256 - 1;
 	unsigned int ttc, txqen;
 
@@ -225,45 +231,48 @@ static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
 	value = u32_replace_bits(value, txqen, XGMAC_TXQEN);
 	value = u32_replace_bits(value, tqs, XGMAC_TQS);
 
-	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(channel));
+	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(addrs, channel));
 }
 
 static void dwxgmac2_enable_dma_irq(struct stmmac_priv *priv,
 				    void __iomem *ioaddr, u32 chan,
 				    bool rx, bool tx)
 {
-	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
 
 	if (rx)
 		value |= XGMAC_DMA_INT_DEFAULT_RX;
 	if (tx)
 		value |= XGMAC_DMA_INT_DEFAULT_TX;
 
-	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
 }
 
 static void dwxgmac2_disable_dma_irq(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 chan,
 				     bool rx, bool tx)
 {
-	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
 
 	if (rx)
 		value &= ~XGMAC_DMA_INT_DEFAULT_RX;
 	if (tx)
 		value &= ~XGMAC_DMA_INT_DEFAULT_TX;
 
-	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
 }
 
 static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv,
 				  void __iomem *ioaddr, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 	value |= XGMAC_TXST;
-	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 
 	value = readl(ioaddr + XGMAC_TX_CONFIG);
 	value |= XGMAC_CONFIG_TE;
@@ -273,11 +282,12 @@ static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv,
 static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
 				 u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 	value &= ~XGMAC_TXST;
-	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 
 	value = readl(ioaddr + XGMAC_TX_CONFIG);
 	value &= ~XGMAC_CONFIG_TE;
@@ -287,11 +297,12 @@ static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
 static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv,
 				  void __iomem *ioaddr, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 	value |= XGMAC_RXST;
-	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 
 	value = readl(ioaddr + XGMAC_RX_CONFIG);
 	value |= XGMAC_CONFIG_RE;
@@ -301,11 +312,12 @@ static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv,
 static void dwxgmac2_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
 				 u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 	value &= ~XGMAC_RXST;
-	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 }
 
 static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
@@ -314,8 +326,9 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
 				  u32 dir)
 {
 	struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
-	u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
-	u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(addrs, chan));
+	u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
 	int ret = 0;
 
 	if (dir == DMA_DIR_RX)
@@ -354,7 +367,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
 	}
 
 	/* Clear interrupts */
-	writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(chan));
+	writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(addrs, chan));
 
 	return ret;
 }
@@ -483,105 +496,120 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
 static void dwxgmac2_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
 				 u32 riwt, u32 queue)
 {
-	writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(queue));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+
+	writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(addrs, queue));
 }
 
 static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 len, u32 chan)
 {
-	writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+
+	writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(addrs, chan));
 }
 
 static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 len, u32 chan)
 {
-	writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+
+	writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(addrs, chan));
 }
 
 static void dwxgmac2_set_rx_tail_ptr(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 ptr, u32 chan)
 {
-	writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+
+	writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(addrs, chan));
 }
 
 static void dwxgmac2_set_tx_tail_ptr(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 ptr, u32 chan)
 {
-	writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+
+	writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(addrs, chan));
 }
 
 static void dwxgmac2_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr,
 				bool en, u32 chan)
 {
-	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 
 	if (en)
 		value |= XGMAC_TSE;
 	else
 		value &= ~XGMAC_TSE;
 
-	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 }
 
 static void dwxgmac2_qmode(struct stmmac_priv *priv, void __iomem *ioaddr,
 			   u32 channel, u8 qmode)
 {
-	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(addrs, channel));
 	u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL);
 	unsigned int txqen;
 
 	if (qmode != MTL_QUEUE_AVB) {
 		txqen = 0x2;
-		writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel));
+		writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(addrs, channel));
 	} else {
 		txqen = 0x1;
 		writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL);
 	}
 
 	value = u32_replace_bits(value, txqen, XGMAC_TXQEN);
-	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(channel));
+	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(addrs, channel));
 }
 
 static void dwxgmac2_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr,
 				int bfsize, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 value;
 
-	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 	value = u32_replace_bits(value, bfsize, XGMAC_RBSZ);
-	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
 }
 
 static void dwxgmac2_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr,
 				bool en, u32 chan)
 {
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
 	u32 value = readl(ioaddr + XGMAC_RX_CONFIG);
 
 	value &= ~XGMAC_CONFIG_HDSMS;
 	value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
 	writel(value, ioaddr + XGMAC_RX_CONFIG);
 
-	value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
+	value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
 	if (en)
 		value |= XGMAC_SPH;
 	else
 		value &= ~XGMAC_SPH;
-	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
 }
 
 static int dwxgmac2_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr,
 			       bool en, u32 chan)
 {
-	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
+	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 
 	if (en)
 		value |= XGMAC_EDSE;
 	else
 		value &= ~XGMAC_EDSE;
 
-	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
+	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
 
-	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)) & XGMAC_EDSE;
+	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan)) & XGMAC_EDSE;
 	if (en && !value)
 		return -EIO;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 265671170bf6e3856263fdcf99afbf3eac79a211..fdae241e5cf49a8d7a15aadb67d40700ab5b4429 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -368,8 +368,11 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
 	mac->vlan = mac->vlan ? : entry->vlan;
 
 	priv->hw = mac;
+	mac->dwxgmac_addrs = priv->plat->dwxgmac_addrs;
 	priv->fpe_cfg.reg = entry->regs.fpe_reg;
-	priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
+	priv->ptpaddr = priv->ioaddr +
+		(priv->plat->dwxgmac_addrs ?
+		 priv->plat->dwxgmac_addrs->timestamp_base : entry->regs.ptp_off);
 	priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
 	memcpy(&priv->ptp_clock_ops, entry->ptp,
 	       sizeof(struct ptp_clock_info));
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 1cf0f8820b337a0d7a9aa23c7d9b34e3f5616dad..82ce81fb6a18b66f2028a5a7784f0a3b9317b9bc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -351,8 +351,9 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
 {
 	struct stmmac_priv *priv = netdev_priv(dev);
 
-	if (priv->plat->core_type == DWMAC_CORE_XGMAC)
-		return XGMAC_REGSIZE * 4;
+	if (priv->plat->core_type == DWMAC_CORE_XGMAC ||
+	    priv->plat->core_type == DWMAC_CORE_25GMAC)
+		return XGMAC_REGSIZE(priv->plat->dwxgmac_addrs) * 4;
 	else if (priv->plat->core_type == DWMAC_CORE_GMAC4)
 		return GMAC4_REG_SPACE_SIZE;
 	return REG_SPACE_SIZE;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
index c889204a7aa5d2e74f7834ed1a22252e6c51ca36..1190b8854132915905773796f07503a9bf1446a0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
@@ -265,9 +265,12 @@ int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
 	if (!num_tc) {
 		/* Restore default TC:Queue mapping */
 		for (u32 i = 0; i < priv->plat->tx_queues_to_use; i++) {
-			val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
+			val = readl(priv->ioaddr +
+				    XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs,
+							 i));
 			writel(u32_replace_bits(val, i, XGMAC_Q2TCMAP),
-			       priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
+			       priv->ioaddr +
+			       XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs, i));
 		}
 	}
 
@@ -288,9 +291,13 @@ int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
 			preemptible_txqs |= GENMASK(offset + count - 1, offset);
 
 		for (u32 i = 0; i < count; i++) {
-			val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
+			val = readl(priv->ioaddr +
+				    XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs,
+							 offset + i));
 			writel(u32_replace_bits(val, tc, XGMAC_Q2TCMAP),
-			       priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
+			       priv->ioaddr +
+			       XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs,
+						    offset + i));
 		}
 	}
 
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 00be2df63d2206a5865bd29333f2f3ba3442962a..5bb904030ef99ac91f66fabaa6c2159da1ec8811 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -188,6 +188,16 @@ struct dwmac4_addrs {
 	u32 mtl_low_cred_offset;
 };
 
+/* Address layout for XGMAC MTL, DMA, and timestamp registers */
+struct dwxgmac_addrs {
+	u32 dma_even_chan_base;
+	u32 dma_odd_chan_base;
+	u32 dma_chan_offset;
+	u32 mtl_chan_base;
+	u32 mtl_chan_offset;
+	u32 timestamp_base;
+};
+
 enum dwmac_core_type {
 	DWMAC_CORE_MAC100,
 	DWMAC_CORE_GMAC,
@@ -358,6 +368,7 @@ struct plat_stmmacenet_data {
 	int msi_rx_base_vec;
 	int msi_tx_base_vec;
 	const struct dwmac4_addrs *dwmac4_addrs;
+	const struct dwxgmac_addrs *dwxgmac_addrs;
 	unsigned int flags;
 	struct stmmac_dma_cfg __dma_cfg;
 };

-- 
2.34.1


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

* [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (6 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  2026-09-28 15:15   ` Maxime Chevallier
  2026-09-23  1:07 ` [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support Mohd Ayaan Anwar
                   ` (2 subsequent siblings)
  10 siblings, 2 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Select the XPCS instance initialized by stmmac when firmware provides
a pcs-handle. Reject interfaces that are not supported by the selected
PCS.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c  | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index ac7d6d3e205a1ab5b391def879d6f1033a0961b6..a99a78880c0fb7858e90b6212b37ebfc7fccaf84 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -7,6 +7,8 @@
 #include <linux/platform_device.h>
 #include <linux/phy.h>
 #include <linux/phy/phy.h>
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/property.h>
 
 #include "stmmac.h"
 #include "stmmac_platform.h"
@@ -681,6 +683,21 @@ static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv)
 	netdev_dbg(priv->dev, "PTP rate %lu\n", plat_dat->clk_ptp_rate);
 }
 
+static struct phylink_pcs *
+qcom_ethqos_select_pcs(struct stmmac_priv *priv, phy_interface_t interface)
+{
+	struct phylink_pcs *pcs;
+
+	if (!priv->hw->xpcs)
+		return ERR_PTR(-ENODEV);
+
+	pcs = xpcs_to_phylink_pcs(priv->hw->xpcs);
+	if (!test_bit(interface, pcs->supported_interfaces))
+		return ERR_PTR(-EOPNOTSUPP);
+
+	return pcs;
+}
+
 static int qcom_ethqos_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -794,6 +811,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
 	for (i = 1; i < plat_dat->tx_queues_to_use; i++)
 		plat_dat->tx_queues_cfg[i].tbs_en = 1;
 
+	if (fwnode_property_present(dev_fwnode(dev), "pcs-handle"))
+		plat_dat->select_pcs = qcom_ethqos_select_pcs;
+
 	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
 }
 

-- 
2.34.1


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

* [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (7 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
@ 2026-09-23  1:07 ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  2026-09-25 13:02   ` Lorenzo Bianconi
  2026-09-23  8:50 ` [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Zhangfei Gao
  2026-09-23  9:41 ` Maxime Chevallier
  10 siblings, 2 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23  1:07 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju, Mohd Ayaan Anwar

Qualcomm Nord provides two ETHQOS controllers based on the Synopsys
DesignWare 25GMAC IP.

The Nord integration uses platform-specific MTL queue, DMA channel and
timestamp register addresses. It also requires wrapper programming for
USXGMII operation and an EEE clock vote for PCS link-up.

Add the Nord platform data, select the DW25GMAC core, describe its
register layout and configure the ETHQOS wrapper for USXGMII. Also add
the platform-specific loopback control needed while the MAC is being
initialized.

Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
---
 .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c    | 142 ++++++++++++++++++++-
 1 file changed, 137 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index a99a78880c0fb7858e90b6212b37ebfc7fccaf84..a03c8e203920a70238deff9f1f970d29d1293893 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -23,8 +23,14 @@
 #define RGMII_IO_MACRO_CONFIG2		0x1C
 #define RGMII_IO_MACRO_DEBUG1		0x20
 #define EMAC_SYSTEM_LOW_POWER_DEBUG	0x28
+#define RGMII_IO_MACRO_SCRATCH_2	0x44
 #define EMAC_WRAPPER_SGMII_PHY_CNTRL1	0xf4
 
+#define RGMII_IO_MACRO_BYPASS			0x16C
+#define EMAC_WRAPPER_SGMII_PHY_CNTRL0		0x170
+#define EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4	0x174
+#define EMAC_WRAPPER_USXGMII_MUX_SEL		0x1D0
+
 /* RGMII_IO_MACRO_CONFIG fields */
 #define RGMII_CONFIG_FUNC_CLK_EN		BIT(30)
 #define RGMII_CONFIG_POS_NEG_DATA_SEL		BIT(23)
@@ -77,6 +83,21 @@
 #define RGMII_CONFIG2_RX_PROG_SWAP		BIT(7)
 #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL	BIT(6)
 #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN	BIT(5)
+#define RGMII_CONFIG2_MODE_EN_VIA_GMII		BIT(21)
+
+/* EMAC_WRAPPER_SGMII_PHY_CNTRL0 fields */
+#define SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL	GENMASK(6, 5)
+
+/* EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4 fields */
+#define SGMII_PHY_CNTRL1_USXGMII_GMII_MASTER_CLK_MUX_SEL	BIT(4)
+#define SGMII_PHY_CNTRL1_RGMII_SGMII_CLK_MUX_SEL		BIT(0)
+
+/* RGMII_IO_MACRO_BYPASS fields */
+#define RGMII_BYPASS_EN				BIT(0)
+
+/* EMAC_WRAPPER_USXGMII_MUX_SEL fields */
+#define USXGMII_CLK_BLK_GMII_CLK_BLK_SEL	BIT(1)
+#define USXGMII_CLK_BLK_CLK_EN			BIT(0)
 
 /* EMAC_WRAPPER_SGMII_PHY_CNTRL1 bits */
 #define SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN	BIT(3)
@@ -88,6 +109,8 @@ struct ethqos_emac_por {
 	unsigned int value;
 };
 
+struct qcom_ethqos;
+
 struct ethqos_emac_driver_data {
 	const struct ethqos_emac_por *rgmii_por;
 	unsigned int num_rgmii_por;
@@ -97,12 +120,16 @@ struct ethqos_emac_driver_data {
 	const char *link_clk_name;
 	struct dwmac4_addrs dwmac4_addrs;
 	bool needs_sgmii_loopback;
+	struct dwxgmac_addrs dwxgmac_addrs;
+	enum dwmac_core_type core_type;
+	void (*set_sgmii_loopback)(struct qcom_ethqos *ethqos, bool enable);
 };
 
 struct qcom_ethqos {
 	struct platform_device *pdev;
 	void __iomem *rgmii_base;
 	struct clk *link_clk;
+	struct clk *eee_clk;
 	struct phy *serdes_phy;
 	phy_interface_t phy_mode;
 
@@ -111,6 +138,7 @@ struct qcom_ethqos {
 	bool rgmii_config_loopback_en;
 	bool has_emac_ge_3;
 	bool needs_sgmii_loopback;
+	void (*set_sgmii_loopback)(struct qcom_ethqos *ethqos, bool enable);
 };
 
 static u32 rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset)
@@ -201,6 +229,15 @@ qcom_ethqos_set_sgmii_loopback(struct qcom_ethqos *ethqos, bool enable)
 		      EMAC_WRAPPER_SGMII_PHY_CNTRL1);
 }
 
+static void
+qcom_ethqos_set_sgmii_loopback_nord(struct qcom_ethqos *ethqos, bool enable)
+{
+	rgmii_updatel(ethqos,
+		      SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN,
+		      enable ? SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN : 0,
+		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
+}
+
 static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos)
 {
 	rgmii_setmask(ethqos, RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG);
@@ -220,6 +257,7 @@ static const struct ethqos_emac_driver_data emac_v2_3_0_data = {
 	.num_rgmii_por = ARRAY_SIZE(emac_v2_3_0_por),
 	.rgmii_config_loopback_en = true,
 	.has_emac_ge_3 = false,
+	.core_type = DWMAC_CORE_GMAC4,
 };
 
 static const struct ethqos_emac_por emac_v2_1_0_por[] = {
@@ -236,6 +274,7 @@ static const struct ethqos_emac_driver_data emac_v2_1_0_data = {
 	.num_rgmii_por = ARRAY_SIZE(emac_v2_1_0_por),
 	.rgmii_config_loopback_en = false,
 	.has_emac_ge_3 = false,
+	.core_type = DWMAC_CORE_GMAC4,
 };
 
 static const struct ethqos_emac_por emac_v3_0_0_por[] = {
@@ -252,6 +291,7 @@ static const struct ethqos_emac_driver_data emac_v3_0_0_data = {
 	.num_rgmii_por = ARRAY_SIZE(emac_v3_0_0_por),
 	.rgmii_config_loopback_en = false,
 	.has_emac_ge_3 = true,
+	.core_type = DWMAC_CORE_GMAC4,
 	.dwmac4_addrs = {
 		.dma_chan = 0x00008100,
 		.dma_chan_offset = 0x1000,
@@ -286,6 +326,8 @@ static const struct ethqos_emac_driver_data emac_v4_0_0_data = {
 	.has_emac_ge_3 = true,
 	.link_clk_name = "phyaux",
 	.needs_sgmii_loopback = true,
+	.core_type = DWMAC_CORE_GMAC4,
+	.set_sgmii_loopback = qcom_ethqos_set_sgmii_loopback,
 	.dma_addr_width = 36,
 	.dwmac4_addrs = {
 		.dma_chan = 0x00008100,
@@ -485,6 +527,47 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed)
 	return 0;
 }
 
+static void ethqos_configure_usxgmii(struct qcom_ethqos *ethqos)
+{
+	unsigned int i;
+
+	for (i = 0; i < ethqos->num_rgmii_por; i++)
+		rgmii_writel(ethqos, ethqos->rgmii_por[i].value,
+			     ethqos->rgmii_por[i].offset);
+
+	ethqos_set_func_clk_en(ethqos);
+
+	rgmii_updatel(ethqos, RGMII_BYPASS_EN, RGMII_BYPASS_EN,
+		      RGMII_IO_MACRO_BYPASS);
+	rgmii_updatel(ethqos, RGMII_CONFIG2_MODE_EN_VIA_GMII, 0,
+		      RGMII_IO_MACRO_CONFIG2);
+	rgmii_updatel(ethqos, SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL, BIT(5),
+		      EMAC_WRAPPER_SGMII_PHY_CNTRL0);
+	rgmii_updatel(ethqos, SGMII_PHY_CNTRL1_RGMII_SGMII_CLK_MUX_SEL, 0,
+		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
+	rgmii_updatel(ethqos, SGMII_PHY_CNTRL1_USXGMII_GMII_MASTER_CLK_MUX_SEL,
+		      SGMII_PHY_CNTRL1_USXGMII_GMII_MASTER_CLK_MUX_SEL,
+		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
+
+	rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL, 0,
+		      EMAC_WRAPPER_USXGMII_MUX_SEL);
+	rgmii_updatel(ethqos, USXGMII_CLK_BLK_CLK_EN, 0,
+		      EMAC_WRAPPER_USXGMII_MUX_SEL);
+
+	rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
+		      USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
+		      EMAC_WRAPPER_USXGMII_MUX_SEL);
+}
+
+static void
+ethqos_fix_mac_speed_usxgmii(void *bsp_priv, phy_interface_t interface,
+			     int speed, unsigned int mode)
+{
+	struct qcom_ethqos *ethqos = bsp_priv;
+
+	ethqos_configure_usxgmii(ethqos);
+}
+
 static void ethqos_fix_mac_speed_rgmii(void *bsp_priv,
 				       phy_interface_t interface, int speed,
 				       unsigned int mode)
@@ -625,7 +708,8 @@ static int ethqos_mac_finish_serdes(struct net_device *ndev, void *priv,
 	struct qcom_ethqos *ethqos = priv;
 	int ret = 0;
 
-	qcom_ethqos_set_sgmii_loopback(ethqos, false);
+	if (ethqos->set_sgmii_loopback)
+		ethqos->set_sgmii_loopback(ethqos, false);
 
 	if (interface == PHY_INTERFACE_MODE_SGMII ||
 	    interface == PHY_INTERFACE_MODE_2500BASEX)
@@ -647,14 +731,24 @@ static int ethqos_clks_config(void *priv, bool enabled)
 			return ret;
 		}
 
+		/* PCS link-up depends on the EEE clock due to a hardware quirk. */
+		ret = clk_prepare_enable(ethqos->eee_clk);
+		if (ret) {
+			dev_err(&ethqos->pdev->dev, "eee_clk enable failed\n");
+			clk_disable_unprepare(ethqos->link_clk);
+			return ret;
+		}
+
 		/* Enable functional clock to prevent DMA reset to timeout due
 		 * to lacking PHY clock after the hardware block has been power
 		 * cycled. The actual configuration will be adjusted once
 		 * ethqos' fix_mac_speed() method is invoked.
 		 */
-		qcom_ethqos_set_sgmii_loopback(ethqos, true);
+		if (ethqos->set_sgmii_loopback)
+			ethqos->set_sgmii_loopback(ethqos, true);
 		ethqos_set_func_clk_en(ethqos);
 	} else {
+		clk_disable_unprepare(ethqos->eee_clk);
 		clk_disable_unprepare(ethqos->link_clk);
 	}
 
@@ -738,6 +832,10 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
 		plat_dat->fix_mac_speed = ethqos_fix_mac_speed_sgmii;
 		plat_dat->mac_finish = ethqos_mac_finish_serdes;
 		break;
+	case PHY_INTERFACE_MODE_USXGMII:
+		plat_dat->fix_mac_speed = ethqos_fix_mac_speed_usxgmii;
+		plat_dat->mac_finish = ethqos_mac_finish_serdes;
+		break;
 	default:
 		dev_err(dev, "Unsupported phy mode %s\n",
 			phy_modes(ethqos->phy_mode));
@@ -756,12 +854,18 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
 	ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en;
 	ethqos->has_emac_ge_3 = data->has_emac_ge_3;
 	ethqos->needs_sgmii_loopback = data->needs_sgmii_loopback;
+	ethqos->set_sgmii_loopback = data->set_sgmii_loopback;
 
 	ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii");
 	if (IS_ERR(ethqos->link_clk))
 		return dev_err_probe(dev, PTR_ERR(ethqos->link_clk),
 				     "Failed to get link_clk\n");
 
+	ethqos->eee_clk = devm_clk_get_optional(dev, "eee");
+	if (IS_ERR(ethqos->eee_clk))
+		return dev_err_probe(dev, PTR_ERR(ethqos->eee_clk),
+				     "Failed to get eee_clk\n");
+
 	ret = ethqos_clks_config(ethqos, true);
 	if (ret)
 		return ret;
@@ -778,7 +882,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
 	ethqos_set_clk_tx_rate(ethqos, NULL, plat_dat->phy_interface,
 			       SPEED_1000);
 
-	qcom_ethqos_set_sgmii_loopback(ethqos, true);
+	if (ethqos->set_sgmii_loopback)
+		ethqos->set_sgmii_loopback(ethqos, true);
 	ethqos_set_func_clk_en(ethqos);
 
 	/* The clocks are controlled by firmware, so we don't know for certain
@@ -791,9 +896,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
 	plat_dat->set_clk_tx_rate = ethqos_set_clk_tx_rate;
 	plat_dat->dump_debug_regs = rgmii_dump;
 	plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config;
-	plat_dat->core_type = DWMAC_CORE_GMAC4;
+	plat_dat->core_type = data->core_type;
 	if (ethqos->has_emac_ge_3)
 		plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
+	if (data->dwxgmac_addrs.dma_even_chan_base)
+		plat_dat->dwxgmac_addrs = &data->dwxgmac_addrs;
 	plat_dat->pmt = true;
 	if (of_property_read_bool(np, "snps,tso"))
 		plat_dat->flags |= STMMAC_FLAG_TSO_EN;
@@ -817,8 +924,33 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
 	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
 }
 
+static const struct ethqos_emac_por emac_nord_por[] = {
+	{ .offset = RGMII_IO_MACRO_CONFIG,    .value = 0x00C04D03 },
+	{ .offset = SDCC_HC_REG_DLL_CONFIG,   .value = 0x2004642C },
+	{ .offset = RGMII_IO_MACRO_CONFIG2,   .value = 0x00222060 },
+	{ .offset = RGMII_IO_MACRO_SCRATCH_2, .value = 0x4c },
+};
+
+static const struct ethqos_emac_driver_data emac_nord_data = {
+	.rgmii_por = emac_nord_por,
+	.num_rgmii_por = ARRAY_SIZE(emac_nord_por),
+	.dma_addr_width = 40,
+	.link_clk_name = "phyaux",
+	.core_type = DWMAC_CORE_25GMAC,
+	.set_sgmii_loopback = qcom_ethqos_set_sgmii_loopback_nord,
+	.dwxgmac_addrs = {
+		.dma_even_chan_base = 0x00008500,
+		.dma_odd_chan_base  = 0x00008580,
+		.dma_chan_offset    = 0x00001000,
+		.mtl_chan_base      = 0x00008000,
+		.mtl_chan_offset    = 0x00001000,
+		.timestamp_base     = 0x00007000,
+	},
+};
+
 static const struct of_device_id qcom_ethqos_match[] = {
-	{ .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data},
+	{ .compatible = "qcom,nord-ethqos",    .data = &emac_nord_data },
+	{ .compatible = "qcom,qcs404-ethqos",  .data = &emac_v2_3_0_data },
 	{ .compatible = "qcom,sa8775p-ethqos", .data = &emac_v4_0_0_data},
 	{ .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data},
 	{ .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data},

-- 
2.34.1


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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (8 preceding siblings ...)
  2026-09-23  1:07 ` [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support Mohd Ayaan Anwar
@ 2026-09-23  8:50 ` Zhangfei Gao
  2026-09-23 15:15   ` Andrew Lunn
  2026-09-28 10:21   ` Krzysztof Kozlowski
  2026-09-23  9:41 ` Maxime Chevallier
  10 siblings, 2 replies; 38+ messages in thread
From: Zhangfei Gao @ 2026-09-23  8:50 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Jitendra Vegiraju

On Wed, Sep 23, 2026 at 9:08 AM Mohd Ayaan Anwar
<mohd.anwar@oss.qualcomm.com> wrote:
>
> Hi,
>
> This is an early RFC which adds the XPCS and ETHQOS plumbing required
> to enable 10 Gigabit Ethernet on the Qualcomm Nord SoC. This is the
> first time USXGMII together with an external PCS is being supported by
> the dwmac-qcom-ethqos driver.
>
> This platform was somewhat tricky to work on, with several new pieces
> having to come together across the MAC, XPCS and SerDes layers. Any
> feedback would be appreciated, particularly around the XPCS modelling
> and the generic stmmac register-layout changes.
>
> The overall hardware path looks like this:
>
>   +------------------+      +------------------+      +------------------+      +------------------+
>   |    DW25GMAC      | ---> |  Synopsys XPCS   | ---> | QCOM SGMII PHY   | ===> | Ext PHY / Switch |
>   | + QCOM ETHQOS    |      | + QCOM wrapper   |      |    (SerDes)      |      | USX/10GBASE-R    |
>   +------------------+      +------------------+      +------------------+      +------------------+
>
> The series can be broadly divided into two areas:
>
> 1. Qualcomm XPCS support
>
> Nord integrates a Synopsys DesignWare XPCS, but exposes the PCS,
> PMA/PMD and MII MMD register regions through separate direct-MMIO
> windows instead of the standard contiguous or indirect XPCS mappings.
> Patches 1 through 5 add the binding, generic platform register-access
> hooks, the Qualcomm MMD-to-MMIO translation, and the runtime-PM handling
> needed for the CSR clock.
>
> The XPCS also uses Clause 37 control and status for USXGMII, while the
> generic XPCS support currently handles USXGMII using Clause 73. Patch 2
> adds the required Clause 37 USXGMII configuration and link-state path.
>
> Using a small Qualcomm-specific access layer around the existing XPCS
> core was the most straightforward way I could find to model this IP.
> The core already uses synthetic IDs for the NXP integrations and has
> vendor-specific hooks for other XPCS implementations, so this series
> follows a similar approach. I am very much open to suggestions if there
> is a cleaner way to represent the non-standard register mapping.
>
> 2. DW25GMAC and Qualcomm ETHQOS support
>
> Patches 6 through 9 add the Nord ETHQOS binding and driver support. The
> Nord integration has sparse, platform-specific MTL queue and DMA channel
> addresses, as well as a relocated timestamp register bank. The series
> therefore adds optional XGMAC register-layout data while preserving the
> standard layout for existing platforms.
>
> The ETHQOS driver then selects the XPCS provided through pcs-handle and
> adds the Nord wrapper programming required for USXGMII, including the
> EEE clock vote needed for PCS link-up and the platform-specific SerDes
> loopback control.
>
> This series has an obvious dependency on Jitendra Vegiraju's DW25GMAC
> work:
> https://lore.kernel.org/netdev/20260402213629.1996133-1-jitendra.vegiraju@broadcom.com/
>
> I understand that a v10 of that series is planned. While bringing up
> Nord, I also needed a few fixes on top of the DW25GMAC series. Those are
> not included here; I will share them separately with Jitendra in case
> they are useful for the next revision.
>
> Testing:
> Initial testing was done on the Nord Ride SX platform, where both
> Ethernet ports connect to the on-board MV-Q6223 switch using fixed-link
> USXGMII at 10 Gbps. The testing tree included the DW25GMAC dependency
> and the additional fixups mentioned above.
>
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
> ---
> Mohd Ayaan Anwar (9):
>       dt-bindings: net: pcs: add Qualcomm Nord XPCS
>       net: pcs: xpcs: add USXGMII Clause 37 autoneg support
>       net: pcs: xpcs: add custom platform register accessors
>       net: pcs: xpcs: add Qualcomm Nord platform support
>       net: pcs: xpcs: initialize runtime PM as suspended
>       dt-bindings: net: qcom,ethqos: add Qualcomm Nord
>       net: stmmac: support custom XGMAC register layouts
>       net: stmmac: qcom-ethqos: support external PCS
>       net: stmmac: qcom-ethqos: add Qualcomm Nord support
>
>  .../devicetree/bindings/net/pcs/snps,dw-xpcs.yaml  |  17 +++
>  .../devicetree/bindings/net/qcom,ethqos.yaml       |  57 ++++++--
>  .../devicetree/bindings/net/snps,dwmac.yaml        |   2 +
>  drivers/net/ethernet/stmicro/stmmac/common.h       |   1 +
>  .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c    | 162 ++++++++++++++++++++-
>  .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c    |   2 +-
>  drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h     |  94 ++++++++----
>  .../net/ethernet/stmicro/stmmac/dwxgmac2_core.c    |  34 +++--
>  drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 128 +++++++++-------
>  drivers/net/ethernet/stmicro/stmmac/hwif.c         |   5 +-
>  .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |   5 +-
>  drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c   |  15 +-
>  drivers/net/pcs/Makefile                           |   3 +-
>  drivers/net/pcs/pcs-xpcs-plat.c                    |  47 +++++-
>  drivers/net/pcs/pcs-xpcs-qcom.c                    |  86 +++++++++++
>  drivers/net/pcs/pcs-xpcs-qcom.h                    |  16 ++
>  drivers/net/pcs/pcs-xpcs.c                         | 126 ++++++++++++++++
>  drivers/net/pcs/pcs-xpcs.h                         |  15 ++
>  include/linux/pcs/pcs-xpcs.h                       |   2 +
>  include/linux/stmmac.h                             |  11 ++
>  20 files changed, 707 insertions(+), 121 deletions(-)
> ---
> base-commit: 6598456d72e48d779445bfec8f72114747f8b8d7
> change-id: 20260923-qcom_xpcs_nord_emac-bf296eb48e4b
>
> Best regards,
> --
> Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
>

Good Job, Mohd

Tested-by: Zhangfei Gao <zhangfei.gao@oss.qualcomm.com>

Tested on both IQ10 RRD and Ride

Full test patch is in the git
https://github.com/zhangfei-gao/kernel-topics/tree/next-9.23

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
                   ` (9 preceding siblings ...)
  2026-09-23  8:50 ` [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Zhangfei Gao
@ 2026-09-23  9:41 ` Maxime Chevallier
  2026-09-23 10:43   ` Mohd Ayaan Anwar
  10 siblings, 1 reply; 38+ messages in thread
From: Maxime Chevallier @ 2026-09-23  9:41 UTC (permalink / raw)
  To: Mohd Ayaan Anwar, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Serge Semin, Andrew Lunn, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Coia Prant, Jan Petrous, Jose.Abreu@synopsys.com
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

Hi,

On 9/23/26 03:07, Mohd Ayaan Anwar wrote:
> Hi,
> 
> This is an early RFC which adds the XPCS and ETHQOS plumbing required
> to enable 10 Gigabit Ethernet on the Qualcomm Nord SoC. This is the
> first time USXGMII together with an external PCS is being supported by
> the dwmac-qcom-ethqos driver.

There are currently 3 in-flight series that adds glues to DW XPCS and stmmac: 

This one,
The Rockchip one from Coia [1]
The S32 one from Jan [2]


[1] : https://lore.kernel.org/netdev/20260922200336.2201212-1-coiaprant@gmail.com/
[2] : https://lore.kernel.org/netdev/20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com/

MAINTAINERS entry for XPCS says :

SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
L:      netdev@vger.kernel.org          
S:      Orphan                          
F:      drivers/net/pcs/pcs-xpcs.c      
F:      drivers/net/pcs/pcs-xpcs.h      
F:      include/linux/pcs/pcs-xpcs.h    

It would nice if some of you could help maintain the core XPCS driver, and make sure
these series aren't stepping on one another :( I personnaly don't have any XPCS HW
for tests.

You don't have to do it alone, multiple people can co-maintain that :) Maybe
Synopsys folks can also chime in ?

Maxime

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23  9:41 ` Maxime Chevallier
@ 2026-09-23 10:43   ` Mohd Ayaan Anwar
  2026-09-23 13:17     ` Coia Prant
  0 siblings, 1 reply; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23 10:43 UTC (permalink / raw)
  To: Maxime Chevallier
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin, Coia Prant,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju

Hi Maxime,

On Wed, Sep 23, 2026 at 11:41:14AM +0200, Maxime Chevallier wrote:
> Hi,
> 
> On 9/23/26 03:07, Mohd Ayaan Anwar wrote:
> > Hi,
> > 
> > This is an early RFC which adds the XPCS and ETHQOS plumbing required
> > to enable 10 Gigabit Ethernet on the Qualcomm Nord SoC. This is the
> > first time USXGMII together with an external PCS is being supported by
> > the dwmac-qcom-ethqos driver.
> 
> There are currently 3 in-flight series that adds glues to DW XPCS and stmmac: 
> 
> This one,
> The Rockchip one from Coia [1]
> The S32 one from Jan [2]
> 
> 
> [1] : https://lore.kernel.org/netdev/20260922200336.2201212-1-coiaprant@gmail.com/
> [2] : https://lore.kernel.org/netdev/20260919-s32g_serdes-v3-0-9d68868c1e89@oss.nxp.com/
> 
> MAINTAINERS entry for XPCS says :
> 
> SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
> L:      netdev@vger.kernel.org          
> S:      Orphan                          
> F:      drivers/net/pcs/pcs-xpcs.c      
> F:      drivers/net/pcs/pcs-xpcs.h      
> F:      include/linux/pcs/pcs-xpcs.h    
> 
> It would nice if some of you could help maintain the core XPCS driver, and make sure
> these series aren't stepping on one another :( I personnaly don't have any XPCS HW
> for tests.
> 
> You don't have to do it alone, multiple people can co-maintain that :) Maybe
> Synopsys folks can also chime in ?
> 

Thank you for sharing these series, I can help review them based on my
understanding of this IP. Hope that helps.

	Ayaan

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

* Re: [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support
  2026-09-23  1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
@ 2026-09-23 12:07   ` Andrew Lunn
  2026-09-23 12:57     ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  2026-09-25 10:37   ` Lorenzo Bianconi
  2 siblings, 1 reply; 38+ messages in thread
From: Andrew Lunn @ 2026-09-23 12:07 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Heiner Kallweit, Russell King, Richard Cochran,
	Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Zhangfei Gao, Jitendra Vegiraju

On Wed, Sep 23, 2026 at 06:37:30AM +0530, Mohd Ayaan Anwar wrote:
> Qualcomm Nord exposes the DesignWare XPCS register blocks through
> separate direct-MMIO windows instead of the standard contiguous
> MMD/register layout. Add accessors that translate MMD accesses to the
> Nord windows:
> 
>   MMD 3 (PCS), standard registers: SR_XS at 0x0000

What does standard mean? 802.3 C45.2.3 defines registers 3.0 -
3.32767 as standardised. 

>   MMD 3 (PCS), vendor registers:   VR_XS at 0x2000

and 3.32768 - 3.65535 as vendor.

However, with a length of 0x2000, there is only space for 8192 of the
standardised registers, and 0x1000 gives 4096 vendor registers.

>   MMD 1 (PMA/PMD):                  SR_PMA at 0x3000
>   MMD 31 (VEND2), standard regs:    SR_MII at 0x4000

What do you mean by standard registers when talking about VEND2?

>   MMD 31 (VEND2), vendor registers: VR_MII at 0x5000

	Andrew

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

* Re: [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors
  2026-09-23  1:07 ` [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors Mohd Ayaan Anwar
@ 2026-09-23 12:18   ` Andrew Lunn
  2026-09-23 12:37     ` Mohd Ayaan Anwar
  2026-09-25 10:18   ` Lorenzo Bianconi
  1 sibling, 1 reply; 38+ messages in thread
From: Andrew Lunn @ 2026-09-23 12:18 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Heiner Kallweit, Russell King, Richard Cochran,
	Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Zhangfei Gao, Jitendra Vegiraju

On Wed, Sep 23, 2026 at 06:37:29AM +0530, Mohd Ayaan Anwar wrote:
> Some XPCS integrations do not expose the standard direct or indirect
> register layout. Allow the platform driver to use optional register read
> and write callbacks for both Clause 22 and Clause 45 accesses, while
> retaining the existing access paths when no callbacks are supplied.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
> ---
>  drivers/net/pcs/pcs-xpcs-plat.c | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
> index e669a7b248ac4677aeb5cd1874108f5c87f837d2..e78a233fb198d940951064a71e8597c6c666bc9d 100644
> --- a/drivers/net/pcs/pcs-xpcs-plat.c
> +++ b/drivers/net/pcs/pcs-xpcs-plat.c
> @@ -24,8 +24,16 @@
>  /* Page select register for the indirect MMIO CSRs access */
>  #define DW_VR_CSR_VIEWPORT		0xff
>  
> +struct dw_xpcs_plat_ops {
> +	int (*reg_read)(struct platform_device *pdev, void __iomem *reg_base,
> +			int dev, int reg);
> +	int (*reg_write)(struct platform_device *pdev, void __iomem *reg_base,
> +			 int dev, int reg, u16 val);
> +};
> +
>  struct dw_xpcs_plat {
>  	struct platform_device *pdev;
> +	const struct dw_xpcs_plat_ops *ops;
>  	struct mii_bus *bus;
>  	bool reg_indir;
>  	int reg_width;
> @@ -169,6 +177,10 @@ static int xpcs_mmio_read_c22(struct mii_bus *bus, int addr, int reg)
>  	if (addr != 0)
>  		return -ENODEV;
>  
> +	if (pxpcs->ops)
> +		return pxpcs->ops->reg_read(pxpcs->pdev, pxpcs->reg_base,
> +					    MDIO_MMD_VEND2, reg);
> +
>  	if (pxpcs->reg_indir)
>  		return xpcs_mmio_read_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg);
>  	else

Ugly.

How about changing pxpcs->reg_indir to an enum, with values indirect, direct.

One patch.

Then look at

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "direct") ?:
	      platform_get_resource_byname(pdev, IORESOURCE_MEM, "indirect");
	if (!res) {
		dev_err(dev, "No reg-space found\n");
		return -EINVAL;
	}

	if (!strcmp(res->name, "indirect"))
		pxpcs->reg_indir = true;

	if (pxpcs->reg_indir)
		spc_size = pxpcs->reg_width * SZ_256;
	else
		spc_size = pxpcs->reg_width * SZ_2M;

Look how easy it is to cleanly extend this with a new resource name?
And add accessors using the funky mapping your device has. Another
patch.

    Andrew

---
pw-bot: cr

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

* Re: [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors
  2026-09-23 12:18   ` Andrew Lunn
@ 2026-09-23 12:37     ` Mohd Ayaan Anwar
  0 siblings, 0 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23 12:37 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Heiner Kallweit, Russell King, Richard Cochran,
	Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Zhangfei Gao, Jitendra Vegiraju

On Wed, Sep 23, 2026 at 02:18:17PM +0200, Andrew Lunn wrote:
> On Wed, Sep 23, 2026 at 06:37:29AM +0530, Mohd Ayaan Anwar wrote:
> > +	if (pxpcs->ops)
> > +		return pxpcs->ops->reg_read(pxpcs->pdev, pxpcs->reg_base,
> > +					    MDIO_MMD_VEND2, reg);
> > +
> >  	if (pxpcs->reg_indir)
> >  		return xpcs_mmio_read_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg);
> >  	else
> 
> Ugly.
> 
> How about changing pxpcs->reg_indir to an enum, with values indirect, direct.
> 
> One patch.
> 
> Then look at
> 
> 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "direct") ?:
> 	      platform_get_resource_byname(pdev, IORESOURCE_MEM, "indirect");
> 	if (!res) {
> 		dev_err(dev, "No reg-space found\n");
> 		return -EINVAL;
> 	}
> 
> 	if (!strcmp(res->name, "indirect"))
> 		pxpcs->reg_indir = true;
> 
> 	if (pxpcs->reg_indir)
> 		spc_size = pxpcs->reg_width * SZ_256;
> 	else
> 		spc_size = pxpcs->reg_width * SZ_2M;
> 
> Look how easy it is to cleanly extend this with a new resource name?
> And add accessors using the funky mapping your device has. Another
> patch.
> 

That's a better idea. I was debating whether using pcs-xpcs-plat.c
with this HW was a good idea, but what you are proposing should hide
away the ugliness. Thank you for the suggestion.

	Ayaan

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

* Re: [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support
  2026-09-23 12:07   ` Andrew Lunn
@ 2026-09-23 12:57     ` Mohd Ayaan Anwar
  0 siblings, 0 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23 12:57 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Heiner Kallweit, Russell King, Richard Cochran,
	Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Zhangfei Gao, Jitendra Vegiraju

On Wed, Sep 23, 2026 at 02:07:07PM +0200, Andrew Lunn wrote:
> On Wed, Sep 23, 2026 at 06:37:30AM +0530, Mohd Ayaan Anwar wrote:
> > Qualcomm Nord exposes the DesignWare XPCS register blocks through
> > separate direct-MMIO windows instead of the standard contiguous
> > MMD/register layout. Add accessors that translate MMD accesses to the
> > Nord windows:
> > 
> >   MMD 3 (PCS), standard registers: SR_XS at 0x0000
> 
> What does standard mean? 802.3 C45.2.3 defines registers 3.0 -
> 3.32767 as standardised. 
> 
> >   MMD 3 (PCS), vendor registers:   VR_XS at 0x2000
> 
> and 3.32768 - 3.65535 as vendor.
> 
> However, with a length of 0x2000, there is only space for 8192 of the
> standardised registers, and 0x1000 gives 4096 vendor registers.
> 
> >   MMD 1 (PMA/PMD):                  SR_PMA at 0x3000
> >   MMD 31 (VEND2), standard regs:    SR_MII at 0x4000
> 
> What do you mean by standard registers when talking about VEND2?

This is incorrect, these are non-standard VEND2 registers.

> 
> >   MMD 31 (VEND2), vendor registers: VR_MII at 0x5000
> 

Overall, it's a mess, with some registers marked as reserved, and some
not defined. I will go through the list once again and document them
properly. Thank you for the pointers, this is the first time I am
working with this IP and I have found the specific version of the
databook to be confusing.

	Ayaan

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23 10:43   ` Mohd Ayaan Anwar
@ 2026-09-23 13:17     ` Coia Prant
  2026-09-23 14:03       ` Mohd Ayaan Anwar
                         ` (2 more replies)
  0 siblings, 3 replies; 38+ messages in thread
From: Coia Prant @ 2026-09-23 13:17 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Serge Semin, Andrew Lunn, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju

Hello,

Thanks for the RFC. A few comments.

XPCS_ID
-------
Is 0x00000030 documented for Qualcomm, or is it derived from
NXP_SJA1110_XPCS_ID + 0x10? If it's the latter, it's a magic value and
I'd rather see it confirmed against the Qualcomm documentation or a
register dump from real hardware before it's used for platform
identification.

Non-existent MMDs
-----------------
Returning 0xffff on reads and silently discarding writes is what a
floating bus / unimplemented feature looks like, so I agree with that
direction. My pcs-xpcs-rk does the same.

Structure
---------
pcs-xpcs-plat is itself a platform glue driver, for SoCs that don't
need any platform-specific handling. Adding another abstraction layer
on top of it to cover Qualcomm would be glue on glue. Generic, Qualcomm
and Rockchip differ in power management, address window size (2M vs 8M,
...) and MMD redirection, so they don't share a probe path.

Pushing that into pcs-xpcs-plat would also drag every existing user of
the generic glue along: they would suddenly depend on GENERIC_PHY,
PM_GENERIC_DOMAINS and whatever else the Qualcomm path needs, or they
would have to carry per-platform branches in a driver that is supposed
to be platform-agnostic. A per-SoC-family glue driver, the same way
dwmac-intel, dwmac-rk, dwmac-renesas-gbeth and dwmac-rzn1 are
separate, keeps each integration self-contained and leaves the generic
glue alone.

Would it make sense to take that route here? My pcs-xpcs-rk does the
MMD redirection through a custom MDIO bus; maybe the Qualcomm glue can
reuse that idea directly instead of extending pcs-xpcs-plat. Happy to
help with the generic parts if that's useful.

Best,
Coia

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

* Re: [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support
  2026-09-23  1:07 ` [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support Mohd Ayaan Anwar
@ 2026-09-23 13:31   ` Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
  1 sibling, 0 replies; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23 13:31 UTC (permalink / raw)
  To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

Hi Andrew,
On Wed, Sep 23, 2026 at 06:37:28AM +0530, Mohd Ayaan Anwar wrote:
> The generic DesignWare XPCS support currently associates USXGMII with
> Clause 73 auto-negotiation. The XPCS integration on Qualcomm Nord
> instead uses the vendor MII register block and Clause 37 control and
> status for USXGMII.
> 
> Add a separate Clause 37 USXGMII mode which configures the PCS for
> BASE-R, enables single-port 10G-SXGMII operation and enables
> PHY-side Clause 37 auto-negotiation.
> 
> Also decode the negotiated link, speed and duplex from the vendor
> Clause 37 status register. This supports 10 Mbps through 10 Gbps link
> rates exposed by the USXGMII status fields.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
> ---

Seeing your question below, I think I should have probably mentioned
here that this sequence is given in the programming guidelines of the
XPCS 3.50a databook. Section 7.6 Switching to USXGMII Mode, point 10.
states:
  Set bit(12) of SR_MII_CTRL to 1 to enable CL37 auto-negotiation
  (paraphrased).

So this is a part of the licensed IP, rather than a Qualcomm specific
addition.

> @@ -687,6 +736,7 @@ static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
>  
>  	case DW_10GBASER:
>  	case DW_2500BASEX:
> +	case DW_AN_C37_USXGMII:
>  		return LINK_INBAND_DISABLE;
>  

This is incorrect and I did not find out its side effect as I was
working with a firmware managed external sitch. The XPCS supports
USXGMII with AN always, so this case should return LINK_INBAND_ENABLE.

	Ayaan

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23 13:17     ` Coia Prant
@ 2026-09-23 14:03       ` Mohd Ayaan Anwar
  2026-09-24  5:54         ` Coia Prant
  2026-09-23 18:35       ` Andrew Lunn
  2026-09-23 18:40       ` Andrew Lunn
  2 siblings, 1 reply; 38+ messages in thread
From: Mohd Ayaan Anwar @ 2026-09-23 14:03 UTC (permalink / raw)
  To: Coia Prant
  Cc: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Serge Semin, Andrew Lunn, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju,
	Alex Elder, Daniel Thompson

On Wed, Sep 23, 2026 at 09:17:44PM +0800, Coia Prant wrote:
> Hello,
> 
> Thanks for the RFC. A few comments.
> 
> XPCS_ID
> -------
> Is 0x00000030 documented for Qualcomm, or is it derived from
> NXP_SJA1110_XPCS_ID + 0x10? If it's the latter, it's a magic value and
> I'd rather see it confirmed against the Qualcomm documentation or a
> register dump from real hardware before it's used for platform
> identification.
> 

It's the latter (NXP XPCS ID + 0x10). The Qualcomm hardware returns the
standard XPCS identifier (0x7996ced0) upon reading the 3.2, 3.3
PCS_DEV_ID registers. I tried following a similar approach to the NXP
DSA driver of reporting a synthetic value to bind to the Qualcomm part. 

All this was just to make it work with pcs-xpcs-plat without introducing
a ton of code.

> Structure
> ---------
> pcs-xpcs-plat is itself a platform glue driver, for SoCs that don't
> need any platform-specific handling. Adding another abstraction layer
> on top of it to cover Qualcomm would be glue on glue. Generic, Qualcomm
> and Rockchip differ in power management, address window size (2M vs 8M,
> ...) and MMD redirection, so they don't share a probe path.
> 
> Pushing that into pcs-xpcs-plat would also drag every existing user of
> the generic glue along: they would suddenly depend on GENERIC_PHY,
> PM_GENERIC_DOMAINS and whatever else the Qualcomm path needs, or they
> would have to carry per-platform branches in a driver that is supposed
> to be platform-agnostic. A per-SoC-family glue driver, the same way
> dwmac-intel, dwmac-rk, dwmac-renesas-gbeth and dwmac-rzn1 are
> separate, keeps each integration self-contained and leaves the generic
> glue alone.
> 
> Would it make sense to take that route here? My pcs-xpcs-rk does the
> MMD redirection through a custom MDIO bus; maybe the Qualcomm glue can
> reuse that idea directly instead of extending pcs-xpcs-plat. Happy to
> help with the generic parts if that's useful.
> 

I agree with your concerns regarding the glue on glue architecture. I
also don't know if each platform glue should define a custom MDIO bus
with similar logic. Maybe we can have a generic abstraction for it?

I know that Alex had a patch introducing pcs-xpcs-regmap.c [1]. My
original code for this platform actually built on top of it before I
moved to the current implementation.

At least I now know that multiple vendors have an MMIO based XPCS,
albeit with differing MMD redirection mechanisms.

I am going through the pcs-xpcs-rk patch and the eee_clk already stood
out to me. On my board, the PCS link does not come up if the EEE clock
is stopped. Going through the databook, I did find a barebones
explanation of why that might be happening for USXGMII, but I need to
dig more into it.

Thank you for the review.

	Ayaan

[1] https://lore.kernel.org/netdev/20260501155421.3329862-2-elder@riscstar.com/

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23  8:50 ` [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Zhangfei Gao
@ 2026-09-23 15:15   ` Andrew Lunn
  2026-09-28 10:21   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 38+ messages in thread
From: Andrew Lunn @ 2026-09-23 15:15 UTC (permalink / raw)
  To: Zhangfei Gao
  Cc: Mohd Ayaan Anwar, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Serge Semin, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Jitendra Vegiraju

> Good Job, Mohd
> 
> Tested-by: Zhangfei Gao <zhangfei.gao@oss.qualcomm.com>
> 
> Tested on both IQ10 RRD and Ride

Thanks for testing, but its a bit early yet. You might want to wait
until we get to version 5 or more, and it is no longer RFC, code the
author no longer is requesting comments on but is Mainline Linux
production quality. And after the AI reviews have stopped pointing out
issues.  Only then does a tested-by: make any real sense.

Reporting your test results internally is probably appreciated as the
patchset goes through revisions.

	 Andrew

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23 13:17     ` Coia Prant
  2026-09-23 14:03       ` Mohd Ayaan Anwar
@ 2026-09-23 18:35       ` Andrew Lunn
  2026-09-24  5:25         ` Coia Prant
  2026-09-23 18:40       ` Andrew Lunn
  2 siblings, 1 reply; 38+ messages in thread
From: Andrew Lunn @ 2026-09-23 18:35 UTC (permalink / raw)
  To: Coia Prant
  Cc: Mohd Ayaan Anwar, Maxime Chevallier, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Serge Semin, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju

> Non-existent MMDs
> -----------------
> Returning 0xffff on reads and silently discarding writes is what a
> floating bus / unimplemented feature looks like, so I agree with that
> direction. My pcs-xpcs-rk does the same.

Did you read 802.3?

  45.2:

  If a device supports the MDIO interface it shall respond to all
  possible register addresses for the device and return a value of
  zero for undefined and unsupported registers. Writes to undefined
  registers and read-only registers shall have no effect. The
  operation of an MMD shall not be affected by writes to reserved and
  unsupported register bits, and such register bits shall return a
  value of zero when read.

This is what i was commenting about in my review, returning EOPNOTSUPP
is not correct according to the standard.

	Andrew

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23 13:17     ` Coia Prant
  2026-09-23 14:03       ` Mohd Ayaan Anwar
  2026-09-23 18:35       ` Andrew Lunn
@ 2026-09-23 18:40       ` Andrew Lunn
  2 siblings, 0 replies; 38+ messages in thread
From: Andrew Lunn @ 2026-09-23 18:40 UTC (permalink / raw)
  To: Coia Prant
  Cc: Mohd Ayaan Anwar, Maxime Chevallier, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Serge Semin, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju

> Would it make sense to take that route here? My pcs-xpcs-rk does the
> MMD redirection through a custom MDIO bus; maybe the Qualcomm glue can
> reuse that idea directly instead of extending pcs-xpcs-plat. Happy to
> help with the generic parts if that's useful.

I would be happy with a custom MDIO bus as well.

  Andrew

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

* Re: [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord
  2026-09-23  1:07 ` [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord Mohd Ayaan Anwar
@ 2026-09-24  1:09   ` sashiko-bot
  0 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-09-24  1:09 UTC (permalink / raw)
  To: Mohd Ayaan Anwar; +Cc: conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] dt-bindings: missing clock constraint restriction for older ethqos devices
--

commit 2ec6ff874b6b04da419dd5b3f1e6b8a59de089ce
Author: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

dt-bindings: net: qcom,ethqos: add Qualcomm Nord

This commit adds the Qualcomm Nord compatible string to the qcom,ethqos
binding schema. It updates the constraints to support the new variant's
requirement for 5 clocks, 1 power domain, and 10 SMMU stream mappings.

> diff --git a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
> index 423959cb928d9..41de2ccd56458 100644
> --- a/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
> +++ b/Documentation/devicetree/bindings/net/qcom,ethqos.yaml
[ ... ]
>  allOf:
>    - $ref: snps,dwmac.yaml#
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: qcom,nord-ethqos
> +    then:
> +      properties:
> +        clocks:
> +          minItems: 5
> +          maxItems: 5
> +        clock-names:
> +          minItems: 5
> +          maxItems: 5
> +        iommus:
> +          minItems: 10
> +          maxItems: 10
> +      required:
> +        - power-domains
> +    else:
> +      properties:
> +        iommus:
> +          maxItems: 1

[Severity: Medium]
Since the global constraints for clocks and clock-names are relaxed later in
this file to allow up to 5 items, does this else block also need to restrict
clocks and clock-names back to a maximum of 4 items?

Without this restriction in the else block, device trees for older hardware
generations might silently pass validation even if incorrectly configured
with 5 clocks.

[ ... ]
> @@ -57,19 +80,31 @@ properties:
>        - const: sfty
>  
>    clocks:
> -    maxItems: 4
> +    minItems: 4
> +    maxItems: 5
>  
>    clock-names:
> -    items:
> -      - const: stmmaceth
> -      - const: pclk
> -      - const: ptp_ref
> -      - enum:
> -          - rgmii
> -          - phyaux
> +    oneOf:
> +      - items:
> +          - const: stmmaceth
> +          - const: pclk
> +          - const: ptp_ref
> +          - const: phyaux
> +          - const: eee
> +            description: |
> +              Due to a hardware quirk, PCS link-up depends on the EEE clock
> +              being enabled.
> +      - items:
> +          - const: stmmaceth
> +          - const: pclk
> +          - const: ptp_ref
> +          - enum:
> +              - rgmii
> +              - phyaux

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-qcom_xpcs_nord_emac-v1-0-4b1c682af70f@oss.qualcomm.com?part=6

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

* Re: [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support
  2026-09-23  1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
  2026-09-23 12:07   ` Andrew Lunn
@ 2026-09-24  1:09   ` sashiko-bot
  2026-09-25 10:37   ` Lorenzo Bianconi
  2 siblings, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-09-24  1:09 UTC (permalink / raw)
  To: Mohd Ayaan Anwar; +Cc: conor+dt, robh, devicetree

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] net: pcs: missing bounds check enables out-of-bounds MMIO read/write
--

commit 2b4e5bfd24ebda95c719fb78f892dda332feef24
Author: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

net: pcs: xpcs: add Qualcomm Nord platform support

Adds Qualcomm Nord platform support by exposing DW XPCS register blocks via
separate direct-MMIO windows. It introduces accessors to translate MMD
accesses to these Nord windows and selects them using the Nord synthetic
XPCS ID.

> diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
> index e78a233fb198d..e013a5253a226 100644
> --- a/drivers/net/pcs/pcs-xpcs-plat.c
> +++ b/drivers/net/pcs/pcs-xpcs-plat.c
[ ... ]
> @@ -285,7 +298,7 @@ static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)
>  	else
>  		spc_size = pxpcs->reg_width * SZ_2M;
>  
> -	if (resource_size(res) < spc_size) {
> +	if (!pxpcs->ops && resource_size(res) < spc_size) {
>  		dev_err(dev, "Invalid reg-space size\n");
>  		return -EINVAL;
>  	}

[Severity: High]
Does bypassing the resource_size() check for platforms with custom ops in
xpcs_plat_init_res() leave the hardware mapping size unvalidated?

Since xpcs_qcom_ops is set for the Qualcomm Nord platform, this skips
ensuring the physical mapped region is large enough to encompass the largest
possible offset.

> diff --git a/drivers/net/pcs/pcs-xpcs-qcom.c b/drivers/net/pcs/pcs-xpcs-qcom.c
> new file mode 100644
> index 0000000000000..63c95c9514548
> --- /dev/null
> +++ b/drivers/net/pcs/pcs-xpcs-qcom.c
[ ... ]
> +static int xpcs_qcom_reg_offset(int dev, int reg)
> +{
> +	switch (dev) {
[ ... ]
> +	case MDIO_MMD_VEND2:
> +		if (reg >= DW_VENDOR)
> +			return QCOM_XPCS_VR_MII_BASE +
> +			       ((reg - DW_VENDOR) << 2);

[Severity: High]
Is there a bounds check missing for the reg index in xpcs_qcom_reg_offset()?

MDIO registers can be read from userspace up to 0xFFFF via ioctl or ethtool.
With MDIO_MMD_VEND2, a large index like 0xFFFF translates into an offset of
0x24fffc (approx 2.4MB), which may exceed standard hardware mapping slices.

> +
> +		return QCOM_XPCS_SR_MII_BASE + (reg << 2);
> +
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +int xpcs_qcom_reg_read(struct platform_device *pdev, void __iomem *reg_base,
> +		       int dev, int reg)
> +{
> +	int offset, ret;
> +
> +	offset = xpcs_qcom_reg_offset(dev, reg);
> +	if (offset < 0)
> +		return offset;
> +
> +	ret = pm_runtime_resume_and_get(&pdev->dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = readl(reg_base + offset) & 0xffff;

[Severity: High]
Could this readl() in xpcs_qcom_reg_read() trigger an out-of-bounds MMIO
access and a Data Abort?

Because xpcs_plat_init_res() bypassed the mapping size check, and
xpcs_qcom_reg_offset() translates unvalidated register indices into large
offsets, this reads from an unmapped physical address if a large reg value
is provided. (The same question applies to writel() in xpcs_qcom_reg_write()
below this block).

> +
> +	pm_runtime_put(&pdev->dev);
> +
> +	return ret;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-qcom_xpcs_nord_emac-v1-0-4b1c682af70f@oss.qualcomm.com?part=4

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

* Re: [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support
  2026-09-23  1:07 ` [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support Mohd Ayaan Anwar
  2026-09-23 13:31   ` Mohd Ayaan Anwar
@ 2026-09-24  1:09   ` sashiko-bot
  1 sibling, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-09-24  1:09 UTC (permalink / raw)
  To: Mohd Ayaan Anwar; +Cc: conor+dt, devicetree, robh

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] net: pcs: xpcs: USXGMII link up forces full-duplex and ignores negotiated duplex
- [Low] net: pcs: xpcs: unconditional disable of Clause 37 AN interrupts for USXGMII
- [Low] net: pcs: xpcs: incorrect use of standard MDIO_CTRL1 in vendor-specific register access
--

commit a4e7caa76a7f032f82d43f5626c2004e96588abf
Author: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
net: pcs: xpcs: add USXGMII Clause 37 autoneg support

This commit adds Clause 37 USXGMII auto-negotiation support to the generic
DesignWare XPCS driver. It configures the PCS for BASE-R, enables single-port
10G-SXGMII operation, and decodes the negotiated link, speed, and duplex.

> diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
> index 0337e2bcc0125..7f5c7a275630f 100644
> --- a/drivers/net/pcs/pcs-xpcs.c
> +++ b/drivers/net/pcs/pcs-xpcs.c
[ ... ]
> @@ -355,6 +356,54 @@ static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
>  	return 0;
>  }
>  
> +static int xpcs_config_aneg_c37_usxgmii(struct dw_xpcs *xpcs)
> +{
> +	u16 mask, val;
> +	int ret;
[ ... ]
> +	/* Configure USXGMII per XPCS databook section 7.6. */
> +	mask = DW_VR_MII_AN_CTRL_8BIT | DW_VR_MII_SGMII_LINK_STS |
> +	       DW_VR_MII_TX_CONFIG_MASK | DW_VR_MII_PCS_MODE_MASK |
> +	       DW_VR_MII_AN_INTR_EN;
> +	val = FIELD_PREP(DW_VR_MII_TX_CONFIG_MASK,
> +			 DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII) |
> +	      DW_VR_MII_SGMII_LINK_STS;
> +
> +	ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL,
> +			  mask, val);

[Severity: Low]
Does this unconditionally disable Clause 37 AN interrupts for USXGMII?

DW_VR_MII_AN_INTR_EN is included in the mask but is missing from val, which
explicitly and unconditionally clears the interrupt enable bit.

Although USXGMII currently defaults to polling mode, could explicitly disabling
it here break interrupt-driven operation if a MAC driver attempts to use it?

> +	if (ret < 0)
> +		return ret;
> +
> +	return xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR,
> +			   BMCR_ANENABLE, BMCR_ANENABLE);
> +}
> +
>  static void xpcs_link_up_usxgmii(struct dw_xpcs *xpcs, int speed)
>  {
>  	int ret, speed_sel;

[Severity: Low]
Is the standard MDIO_CTRL1 macro used incorrectly here for a vendor-specific
register?

In xpcs_link_up_usxgmii(), there are calls like:

    ret = xpcs_modify_vpcs(xpcs, MDIO_CTRL1, DW_USXGMII_EN, DW_USXGMII_EN);

Both MDIO_CTRL1 and DW_VR_XS_PCS_DIG_CTRL1 evaluate to 0x00, but using the
standard IEEE macro instead of the vendor-specific one in xpcs_modify_vpcs()
breaks consistency. This also occurs when applying DW_USXGMII_RST.

[ ... ]
> @@ -1158,6 +1213,58 @@ static int xpcs_get_state_2500basex(struct dw_xpcs *xpcs,
>  	return 0;
>  }
>  
> +static int xpcs_get_state_c37_usxgmii(struct dw_xpcs *xpcs,
> +				      struct phylink_link_state *state)
> +{
> +	u16 speed;
> +	int ret;
[ ... ]
> +	state->duplex = ret & DW_VR_MII_USXG_FULL ?
> +			DUPLEX_FULL : DUPLEX_HALF;
> +
> +	return 0;
> +}

[Severity: Medium]
Will xpcs_link_up_usxgmii() ignore this negotiated duplex state?

If the link negotiates half-duplex (which is supported here as DUPLEX_HALF),
the xpcs_link_up() function passes this state, but xpcs_link_up_usxgmii()
ignores the duplex parameter entirely and unconditionally sets DW_USXGMII_FULL.

Furthermore, DW_USXGMII_FULL is missing from DW_USXGMII_SS_MASK:

    ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, DW_USXGMII_SS_MASK,
                      speed_sel | DW_USXGMII_FULL);

Is it impossible to clear the full-duplex bit if it was previously set,
leading to a duplex mismatch?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-qcom_xpcs_nord_emac-v1-0-4b1c682af70f@oss.qualcomm.com?part=2

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

* Re: [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts
  2026-09-23  1:07 ` [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts Mohd Ayaan Anwar
@ 2026-09-24  1:09   ` sashiko-bot
  2026-09-25 12:22   ` Lorenzo Bianconi
  1 sibling, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-09-24  1:09 UTC (permalink / raw)
  To: Mohd Ayaan Anwar; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] mm: heap OOB write in ethtool register dump with custom MAC/DMA layouts
- [High] net: stmmac: SError panic during ethtool dump over unmapped sparse MMIO gaps
- [High] net: stmmac: incorrect DMA channel offset scaling for odd/even bases
- [Medium] net: stmmac: PPS registers ignore custom timestamp_base override
- [Medium] net: stmmac: zero-initialized dwxgmac_addrs fields silently overwrite critical MAC registers
- [Low] net: stmmac: socfpga explicitly hardcodes NULL for custom address overrides
--

commit c3f13a2a3a2ef1c42853ddb7b0f741ba03e49292
Author: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

net: stmmac: support custom XGMAC register layouts

This commit allows platforms to override the MTL queues, DMA channels, and
timestamp register offsets via custom platform data, while retaining the
standard layout by default. It updates various macro definitions and driver
functions to use these configurable bases instead of hardcoded addresses.

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> index 1d7f0a57d2889..331ba38abae66 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> @@ -365,7 +365,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
>  	};
>  
>  	num_snapshot = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK,
> -				 readl(ioaddr + XGMAC_TIMESTAMP_STATUS));
> +				 readl(ioaddr + XGMAC_TIMESTAMP_STATUS(NULL)));

[Severity: Low]
Does explicitly passing NULL here break future compatibility? By hardcoding
the fallback state instead of using the layout configuration available via
the local priv context (e.g., priv->plat->dwxgmac_addrs), it seems this would
fail to use a custom PTP base on future socfpga hardware revisions.

>  
>  	/* Repeat until the timestamps are from the FIFO last segment */
>  	for (i = 0; i < num_snapshot; i++) {
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> index f8ab347f7b5b9..22b476358a202 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> @@ -220,12 +220,21 @@
>  #define XGMAC_CT			BIT(1)
>  #define XGMAC_OB			BIT(0)
>  #define XGMAC_RSS_DATA			0x00000c8c
> -#define XGMAC_TIMESTAMP_STATUS		0x00000d20
> +
> +/* Timestamp registers */
> +#define XGMAC_TIMESTAMP_BASE_ADDR	0x00000d00
> +
> +static inline u32 xgmac_timestamp_base_addr(const struct dwxgmac_addrs *addrs)
> +{
> +	return addrs ? addrs->timestamp_base : XGMAC_TIMESTAMP_BASE_ADDR;
> +}

[Severity: Medium]
Will this return 0 if a platform supplies dwxgmac_addrs for DMA overrides but
leaves timestamp_base uninitialized? If addrs is non-NULL but timestamp_base
is 0, this inline helper doesn't fall back to XGMAC_TIMESTAMP_BASE_ADDR, which
could map critical operations to offset 0 (the MAC TX Configuration register)
and silently corrupt MAC state.

> +
> +#define XGMAC_TIMESTAMP_STATUS(a)	(xgmac_timestamp_base_addr(a) + 0x20)
>  #define XGMAC_TIMESTAMP_ATSNS_MASK	GENMASK(29, 25)
>  #define XGMAC_TXTSC			BIT(15)
> -#define XGMAC_TXTIMESTAMP_NSEC		0x00000d30
> +#define XGMAC_TXTIMESTAMP_NSEC(a)	(xgmac_timestamp_base_addr(a) + 0x30)
>  #define XGMAC_TXTSSTSLO			GENMASK(30, 0)
> -#define XGMAC_TXTIMESTAMP_SEC		0x00000d34
> +#define XGMAC_TXTIMESTAMP_SEC(a)	(xgmac_timestamp_base_addr(a) + 0x34)
>  #define XGMAC_PPS_CONTROL		0x00000d70

[Severity: Medium]
Should XGMAC_PPS_CONTROL and other PPS registers also use the custom
xgmac_timestamp_base_addr override? By remaining hardcoded to 0x0d70,
if a platform uses a custom timestamp_base, PTP PPS functionality will write
to standard hardware offsets rather than the custom relocated timestamp block.

[ ... ]

> +static inline u32
> +xgmac_mtl_chanx_base_addr(const struct dwxgmac_addrs *addrs, u32 x)
> +{
> +	return addrs ? addrs->mtl_chan_base + x * addrs->mtl_chan_offset
> +		     : XGMAC_MTL_CHAN_BASE_ADDR + x * XGMAC_MTL_CHAN_OFFSET;
> +}

[Severity: Medium]
Similar to the timestamp base helper, does this properly fall back to
XGMAC_MTL_CHAN_BASE_ADDR if addrs is provided but mtl_chan_base is 0?
This could also silently overwrite offset 0.

[ ... ]

> +static inline u32
> +xgmac_dma_chanx_base_addr(const struct dwxgmac_addrs *addrs, u32 x)
> +{
> +	if (addrs && (x & 1))
> +		return addrs->dma_odd_chan_base + x * addrs->dma_chan_offset;
> +	if (addrs)
> +		return addrs->dma_even_chan_base + x * addrs->dma_chan_offset;
> +	return XGMAC_DMA_CHAN_BASE_ADDR + x * XGMAC_DMA_CHAN_OFFSET;
> +}

[Severity: High]
Does multiplying by the absolute index x here incorrectly double the intended
physical spacing for channels using split odd/even bases? For instance,
channel 1 will map to odd_base + 1 * offset, and channel 2 to
even_base + 2 * offset. Should this scale by (x / 2) to interleave the
odd and even channels correctly?

[ ... ]

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
> index 1a88cbaed70ca..d1099a1cf9ea5 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c

[ ... ]

> @@ -292,7 +294,7 @@ static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space)
>  	void __iomem *ioaddr = hw->pcsr;
>  	int i;
>  
> -	for (i = 0; i < XGMAC_MAC_REGSIZE; i++)
> +	for (i = 0; i < XGMAC_MAC_REGSIZE(hw->dwxgmac_addrs); i++)
>  		reg_space[i] = readl(ioaddr + i * 4);
>  }

[Severity: High]
Can this result in a heap out-of-bounds write? The ethtool register buffer is
allocated based on stmmac_ethtool_get_regs_len(), which uses
XGMAC_REGSIZE(priv->plat->dwxgmac_addrs) * 4 (the maximum DMA channel offset).
However, dwxgmac2_dump_regs() writes up to
XGMAC_MAC_REGSIZE(hw->dwxgmac_addrs). If a platform configures a layout
where the maximum MTL offset exceeds the maximum DMA offset, the loop will
write past the end of the allocated buffer.

[Severity: High]
Could this linear read sweep also cause a synchronous external abort
(bus fault) on ARM/ARM64 devices? If a platform uses custom bases (like
dma_even_chan_base = 0x8500), it might create large unmapped MMIO gaps
between standard blocks and custom channels. Iterating through the entire
range with readl() would attempt to read from these unmapped physical
addresses.

[ ... ]

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> index ff83858ebc1f3..65d5e2a828076 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c

[ ... ]

> @@ -118,16 +121,18 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
>  static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv,
>  				   void __iomem *ioaddr, u32 *reg_space)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	int i;
>  
> -	for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++)
> +	for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE(addrs); i++)
>  		reg_space[i] = readl(ioaddr + i * 4);
>  }

[Severity: High]
Similar to dwxgmac2_dump_regs(), could this loop read from unmapped memory
gaps if custom DMA channel offsets are used, potentially triggering a
hardware bus fault during an ethtool dump?

[ ... ]

> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> index 1cf0f8820b337..82ce81fb6a18b 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> @@ -351,8 +351,9 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
>  {
>  	struct stmmac_priv *priv = netdev_priv(dev);
>  
> -	if (priv->plat->core_type == DWMAC_CORE_XGMAC)
> -		return XGMAC_REGSIZE * 4;
> +	if (priv->plat->core_type == DWMAC_CORE_XGMAC ||
> +	    priv->plat->core_type == DWMAC_CORE_25GMAC)
> +		return XGMAC_REGSIZE(priv->plat->dwxgmac_addrs) * 4;
>  	else if (priv->plat->core_type == DWMAC_CORE_GMAC4)
>  		return GMAC4_REG_SPACE_SIZE;
>  	return REG_SPACE_SIZE;

[Severity: High]
As mentioned above, this allocates a buffer bounded exclusively by the
maximum DMA offset, which can lead to an out-of-bounds write in
dwxgmac2_dump_regs() if the custom MTL offset is larger.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-qcom_xpcs_nord_emac-v1-0-4b1c682af70f@oss.qualcomm.com?part=7

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

* Re: [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS
  2026-09-23  1:07 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
@ 2026-09-24  1:09   ` sashiko-bot
  2026-09-28 15:15   ` Maxime Chevallier
  1 sibling, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-09-24  1:09 UTC (permalink / raw)
  To: Mohd Ayaan Anwar; +Cc: devicetree, conor+dt, robh

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] net: stmmac: unsupported PCS interfaces are silently accepted without a PCS
--

commit 7e5af7c53413fc3b964ab675b20db937601457fb
Author: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

net: stmmac: qcom-ethqos: support external PCS

Select the XPCS instance initialized by stmmac when firmware provides
a pcs-handle. Reject interfaces that are not supported by the selected
PCS.

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> index ac7d6d3e205a1..a99a78880c0fb 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c

[ ... ]

> @@ -681,6 +683,21 @@ static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv)
>  	netdev_dbg(priv->dev, "PTP rate %lu\n", plat_dat->clk_ptp_rate);
>  }
>  
> +static struct phylink_pcs *
> +qcom_ethqos_select_pcs(struct stmmac_priv *priv, phy_interface_t interface)
> +{
> +	struct phylink_pcs *pcs;
> +
> +	if (!priv->hw->xpcs)
> +		return ERR_PTR(-ENODEV);
> +
> +	pcs = xpcs_to_phylink_pcs(priv->hw->xpcs);
> +	if (!test_bit(interface, pcs->supported_interfaces))
> +		return ERR_PTR(-EOPNOTSUPP);

[Severity: High]
Does returning an error pointer here actually reject the unsupported
interface?

Looking at stmmac_mac_select_pcs() in
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c:

	if (priv->plat->select_pcs) {
		pcs = priv->plat->select_pcs(priv, interface);
		if (!IS_ERR(pcs))
			return pcs;
	}
	...
	return NULL;

It appears that if select_pcs() returns an error pointer like
ERR_PTR(-EOPNOTSUPP), stmmac_mac_select_pcs() will ignore the error and
eventually fall through to return NULL.

Since phylink interprets a NULL return from stmmac_mac_select_pcs() as "no PCS
required" rather than a failure, won't this result in silently accepting the
unsupported interface mode and configuring the link without a PCS instead of
failing the initialization?

> +
> +	return pcs;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-qcom_xpcs_nord_emac-v1-0-4b1c682af70f@oss.qualcomm.com?part=8

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

* Re: [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support
  2026-09-23  1:07 ` [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support Mohd Ayaan Anwar
@ 2026-09-24  1:09   ` sashiko-bot
  2026-09-25 13:02   ` Lorenzo Bianconi
  1 sibling, 0 replies; 38+ messages in thread
From: sashiko-bot @ 2026-09-24  1:09 UTC (permalink / raw)
  To: Mohd Ayaan Anwar; +Cc: robh, conor+dt, devicetree

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] net: stmmac: qcom-ethqos: USXGMII clock remains disabled due to copy-paste error
- [High] net: stmmac: qcom-ethqos: SGMII loopback permanently enabled for non-SerDes PHY modes on Nord
- [High] net: stmmac: qcom-ethqos: missing USXGMII SerDes PHY mode configuration
- [Low] net: stmmac: qcom-ethqos: build failure due to undeclared DWMAC_CORE_25GMAC
--

commit f5df70773c629bcedc94b2086fbc5776c1a49506
Author: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

net: stmmac: qcom-ethqos: add Qualcomm Nord support

This commit adds support for the Qualcomm Nord ETHQOS controllers based on
the Synopsys DesignWare 25GMAC IP. It configures the Nord platform data,
DW25GMAC core register layout, USXGMII wrapper programming, and an EEE clock
vote.

> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> index a99a78880c0fb..a03c8e203920a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
[ ... ]
> @@ -201,6 +229,15 @@ qcom_ethqos_set_sgmii_loopback(struct qcom_ethqos *ethqos, bool enable)
>  		      EMAC_WRAPPER_SGMII_PHY_CNTRL1);
>  }
>  
> +static void
> +qcom_ethqos_set_sgmii_loopback_nord(struct qcom_ethqos *ethqos, bool enable)
> +{
> +	rgmii_updatel(ethqos,
> +		      SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN,
> +		      enable ? SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN : 0,
> +		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
> +}

[Severity: High]
Does this leave the SGMII loopback permanently enabled for non-SerDes PHY
modes on Nord?

Looking at ethqos_clks_config(), .set_sgmii_loopback(..., true) is called
unconditionally. However, for non-SerDes modes, .mac_finish is NULL, so
.set_sgmii_loopback(..., false) is never invoked.

The generic qcom_ethqos_set_sgmii_loopback() has a safety check for
ethqos->needs_sgmii_loopback and ethqos->phy_mode to prevent this, but the
new Nord-specific function lacks it.

[ ... ]
> @@ -485,6 +527,47 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed)
>  	return 0;
>  }
>  
> +static void ethqos_configure_usxgmii(struct qcom_ethqos *ethqos)
> +{
[ ... ]
> +	rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL, 0,
> +		      EMAC_WRAPPER_USXGMII_MUX_SEL);
> +	rgmii_updatel(ethqos, USXGMII_CLK_BLK_CLK_EN, 0,
> +		      EMAC_WRAPPER_USXGMII_MUX_SEL);
> +
> +	rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
> +		      USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
> +		      EMAC_WRAPPER_USXGMII_MUX_SEL);
> +}

[Severity: High]
Will this leave the USXGMII clock permanently disabled?

The code clears USXGMII_CLK_BLK_CLK_EN to disable the clock, but then
incorrectly writes to USXGMII_CLK_BLK_GMII_CLK_BLK_SEL again instead of
setting USXGMII_CLK_BLK_CLK_EN to re-enable it.

This appears to be a copy-paste error that will prevent the network interface
from functioning in USXGMII mode.

[ ... ]
> @@ -625,7 +708,8 @@ static int ethqos_mac_finish_serdes(struct net_device *ndev, void *priv,
>  	struct qcom_ethqos *ethqos = priv;
>  	int ret = 0;
>  
> -	qcom_ethqos_set_sgmii_loopback(ethqos, false);
> +	if (ethqos->set_sgmii_loopback)
> +		ethqos->set_sgmii_loopback(ethqos, false);
>  
>  	if (interface == PHY_INTERFACE_MODE_SGMII ||
>  	    interface == PHY_INTERFACE_MODE_2500BASEX)
>  		ret = phy_set_mode_ext(ethqos->serdes_phy, PHY_MODE_ETHERNET,
>  				       interface);
>  
>  	return ret;
>  }

[Severity: High]
Is the PHY_INTERFACE_MODE_USXGMII check missing here?

Since this function is now configured as the .mac_finish callback for the
newly added PHY_INTERFACE_MODE_USXGMII, omitting it from this condition
causes the SerDes PHY configuration to be silently bypassed, which will
prevent link establishment.

[ ... ]
> @@ -817,8 +924,33 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
>  }
>  
> +static const struct ethqos_emac_por emac_nord_por[] = {
> +	{ .offset = RGMII_IO_MACRO_CONFIG,    .value = 0x00C04D03 },
> +	{ .offset = SDCC_HC_REG_DLL_CONFIG,   .value = 0x2004642C },
> +	{ .offset = RGMII_IO_MACRO_CONFIG2,   .value = 0x00222060 },
> +	{ .offset = RGMII_IO_MACRO_SCRATCH_2, .value = 0x4c },
> +};
> +
> +static const struct ethqos_emac_driver_data emac_nord_data = {
> +	.rgmii_por = emac_nord_por,
> +	.num_rgmii_por = ARRAY_SIZE(emac_nord_por),
> +	.dma_addr_width = 40,
> +	.link_clk_name = "phyaux",
> +	.core_type = DWMAC_CORE_25GMAC,

[Severity: Low]
Does this cause a build failure?

The patch assigns DWMAC_CORE_25GMAC to .core_type, but this enum value is
not defined in enum dwmac_core_type in include/linux/stmmac.h.

> +	.set_sgmii_loopback = qcom_ethqos_set_sgmii_loopback_nord,
> +	.dwxgmac_addrs = {
> +		.dma_even_chan_base = 0x00008500,
> +		.dma_odd_chan_base  = 0x00008580,
> +		.dma_chan_offset    = 0x00001000,
> +		.mtl_chan_base      = 0x00008000,
> +		.mtl_chan_offset    = 0x00001000,
> +		.timestamp_base     = 0x00007000,
> +	},
> +};

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260923-qcom_xpcs_nord_emac-v1-0-4b1c682af70f@oss.qualcomm.com?part=9

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23 18:35       ` Andrew Lunn
@ 2026-09-24  5:25         ` Coia Prant
  0 siblings, 0 replies; 38+ messages in thread
From: Coia Prant @ 2026-09-24  5:25 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Mohd Ayaan Anwar, Maxime Chevallier, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Serge Semin, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju

Andrew Lunn <andrew@lunn.ch> 于2026年9月24日周四 02:35写道:
>
> > Non-existent MMDs
> > -----------------
> > Returning 0xffff on reads and silently discarding writes is what a
> > floating bus / unimplemented feature looks like, so I agree with that
> > direction. My pcs-xpcs-rk does the same.
>
> Did you read 802.3?
>
>   45.2:
>
>   If a device supports the MDIO interface it shall respond to all
>   possible register addresses for the device and return a value of
>   zero for undefined and unsupported registers. Writes to undefined
>   registers and read-only registers shall have no effect. The
>   operation of an MMD shall not be affected by writes to reserved and
>   unsupported register bits, and such register bits shall return a
>   value of zero when read.
>
> This is what i was commenting about in my review, returning EOPNOTSUPP
> is not correct according to the standard.
>
>         Andrew

I hadn't gone back to 45.2 when I wrote that, so fair enough on the
standard. For what it's worth, pcs-xpcs already treats 0 and 0xff as
the "no device" values in the identity path, so the glue follows that
convention rather than inventing a new one.

Sorry for that.
Coia

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23 14:03       ` Mohd Ayaan Anwar
@ 2026-09-24  5:54         ` Coia Prant
  0 siblings, 0 replies; 38+ messages in thread
From: Coia Prant @ 2026-09-24  5:54 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Serge Semin, Andrew Lunn, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin,
	Jan Petrous, Jose.Abreu@synopsys.com, netdev, devicetree,
	linux-kernel, linux-arm-msm, linux-stm32, linux-arm-kernel,
	Lorenzo Bianconi, Shawn Guo, Zhangfei Gao, Jitendra Vegiraju,
	Alex Elder, Daniel Thompson

Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com> 于2026年9月23日周三 22:03写道:
>
> On Wed, Sep 23, 2026 at 09:17:44PM +0800, Coia Prant wrote:
> > Hello,
> >
> > Thanks for the RFC. A few comments.
> >
> > XPCS_ID
> > -------
> > Is 0x00000030 documented for Qualcomm, or is it derived from
> > NXP_SJA1110_XPCS_ID + 0x10? If it's the latter, it's a magic value and
> > I'd rather see it confirmed against the Qualcomm documentation or a
> > register dump from real hardware before it's used for platform
> > identification.
> >
>
> It's the latter (NXP XPCS ID + 0x10). The Qualcomm hardware returns the
> standard XPCS identifier (0x7996ced0) upon reading the 3.2, 3.3
> PCS_DEV_ID registers. I tried following a similar approach to the NXP
> DSA driver of reporting a synthetic value to bind to the Qualcomm part.
>
> All this was just to make it work with pcs-xpcs-plat without introducing
> a ton of code.

OK, so it's a deliberate workaround, not a hardware value. I see the
NXP precedent, but I'm not sure it's a good one to extend: the ID space
is global and finite, so a synthetic 0x30 could collide with a future
real part and bind the wrong glue. NXP at least needs its synthetic ID
to select a platform-specific PMA config; if the Qualcomm part is
otherwise standard XPCS, matching on a fabricated ID just to bind the
same generic code seems like the wrong place to solve the problem.

Leaving the final call to the maintainers, I just wanted to make sure
we weren't matching on something made up.

> > Structure
> > ---------
> > pcs-xpcs-plat is itself a platform glue driver, for SoCs that don't
> > need any platform-specific handling. Adding another abstraction layer
> > on top of it to cover Qualcomm would be glue on glue. Generic, Qualcomm
> > and Rockchip differ in power management, address window size (2M vs 8M,
> > ...) and MMD redirection, so they don't share a probe path.
> >
> > Pushing that into pcs-xpcs-plat would also drag every existing user of
> > the generic glue along: they would suddenly depend on GENERIC_PHY,
> > PM_GENERIC_DOMAINS and whatever else the Qualcomm path needs, or they
> > would have to carry per-platform branches in a driver that is supposed
> > to be platform-agnostic. A per-SoC-family glue driver, the same way
> > dwmac-intel, dwmac-rk, dwmac-renesas-gbeth and dwmac-rzn1 are
> > separate, keeps each integration self-contained and leaves the generic
> > glue alone.
> >
> > Would it make sense to take that route here? My pcs-xpcs-rk does the
> > MMD redirection through a custom MDIO bus; maybe the Qualcomm glue can
> > reuse that idea directly instead of extending pcs-xpcs-plat. Happy to
> > help with the generic parts if that's useful.
> >
>
> I agree with your concerns regarding the glue on glue architecture. I
> also don't know if each platform glue should define a custom MDIO bus
> with similar logic. Maybe we can have a generic abstraction for it?
>
> I know that Alex had a patch introducing pcs-xpcs-regmap.c [1]. My
> original code for this platform actually built on top of it before I
> moved to the current implementation.
>
> At least I now know that multiple vendors have an MMIO based XPCS,
> albeit with differing MMD redirection mechanisms.

I looked at both pcs-xpcs-regmap and pcs-xpcs-plat. Neither fits.

The regmap helper targets a window that doesn't align to a page
boundary, but still assumes a single contiguous region. pcs-xpcs-plat's
indirect mode uses only 8 lower address bits for the register and a
viewport CSR for the upper bits. Your own patch describes the Nord
layout as "separate direct-MMIO windows" with MMD 3 at 0x0000, MMD 1 at
0x3000, MMD 31 at 0x4000 and so on. That is not a contiguous Clause 45
space, and it is not the indirect paged layout either.

Mapping the Nord registers onto pcs-xpcs-plat's indirect mode would
mean claiming the memory is something it isn't: the hardware exposes
direct windows, but the driver would have to lie about the access
model. It also doesn't match the DT binding, which describes a single
reg-names = "indirect" region. A platform with separate direct windows
should describe those windows, not pretend they are paged.

The Rockchip glue differs from pcs-xpcs-plat in more than just address
translation:

- it marks PD_PIPE as part of the wakeup path so genpd keeps the
  power domain on during system suspend, which is required for MAC WoL
- it keeps PD_PIPE on at runtime via dev_pm_genpd_rpm_always_on()
- it adds a separate "eee" clock on top of the csr/core/pad clocks that
  the generic driver knows about, and derives the
  DW_VR_MII_EEE_MULT_FACT_100NS value from the EEE clock rate at runtime
- the read and write remapping paths differ

None of that is address translation. Folding it into a generic glue
means either per-platform conditionals or an ops layer where each
platform stubs half the callbacks. I'd rather keep them separate, the
same way dwmac-intel, dwmac-rk, dwmac-renesas-gbeth and dwmac-rzn1 are
separate.

If the common parts can be factored out cleanly later, I'm happy to
rebase onto that. But the platform glue is where the platform
differences live, and right now those differences are substantial.

> I am going through the pcs-xpcs-rk patch and the eee_clk already stood
> out to me. On my board, the PCS link does not come up if the EEE clock
> is stopped. Going through the databook, I did find a barebones
> explanation of why that might be happening for USXGMII, but I need to
> dig more into it.

Same on RK3568. Without clk_xpcs_eee the SGMII link is unstable, which
is how the Rockchip glue ended up enabling it unconditionally in
xpcs_rk_init_clk(). Downstream carried a fix for the same problem:

  https://github.com/immortalwrt/immortalwrt/commit/2ff0f9435f688b1d9ae275710e13ecd0c54e9724

The databook calls it clk_xpcs_eee, but the generic XPCS driver only
knows about the core/pad clocks, so the Rockchip glue adds a separate
"eee" clock for it.

Looking forward to seeing where the Qualcomm glue lands.

Best regards,
Coia

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

* Re: [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors
  2026-09-23  1:07 ` [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors Mohd Ayaan Anwar
  2026-09-23 12:18   ` Andrew Lunn
@ 2026-09-25 10:18   ` Lorenzo Bianconi
  1 sibling, 0 replies; 38+ messages in thread
From: Lorenzo Bianconi @ 2026-09-25 10:18 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

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

> Some XPCS integrations do not expose the standard direct or indirect
> register layout. Allow the platform driver to use optional register read
> and write callbacks for both Clause 22 and Clause 45 accesses, while
> retaining the existing access paths when no callbacks are supplied.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
> ---
>  drivers/net/pcs/pcs-xpcs-plat.c | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
> index e669a7b248ac4677aeb5cd1874108f5c87f837d2..e78a233fb198d940951064a71e8597c6c666bc9d 100644
> --- a/drivers/net/pcs/pcs-xpcs-plat.c
> +++ b/drivers/net/pcs/pcs-xpcs-plat.c
> @@ -24,8 +24,16 @@
>  /* Page select register for the indirect MMIO CSRs access */
>  #define DW_VR_CSR_VIEWPORT		0xff
>  
> +struct dw_xpcs_plat_ops {
> +	int (*reg_read)(struct platform_device *pdev, void __iomem *reg_base,
> +			int dev, int reg);
> +	int (*reg_write)(struct platform_device *pdev, void __iomem *reg_base,
> +			 int dev, int reg, u16 val);

I guess here we can use the same signature used in
xpcs_mmio_read_reg_{direct,indirect}()/xpcs_mmio_write_reg_{direct,indirect}().
Doing so we can probably have a generic platform ops the driver can set during
probe. What do you think?

Regards,
Lorenzo

> +};
> +
>  struct dw_xpcs_plat {
>  	struct platform_device *pdev;
> +	const struct dw_xpcs_plat_ops *ops;
>  	struct mii_bus *bus;
>  	bool reg_indir;
>  	int reg_width;
> @@ -169,6 +177,10 @@ static int xpcs_mmio_read_c22(struct mii_bus *bus, int addr, int reg)
>  	if (addr != 0)
>  		return -ENODEV;
>  
> +	if (pxpcs->ops)
> +		return pxpcs->ops->reg_read(pxpcs->pdev, pxpcs->reg_base,
> +					    MDIO_MMD_VEND2, reg);
> +
>  	if (pxpcs->reg_indir)
>  		return xpcs_mmio_read_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg);
>  	else
> @@ -182,6 +194,10 @@ static int xpcs_mmio_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)
>  	if (addr != 0)
>  		return -ENODEV;
>  
> +	if (pxpcs->ops)
> +		return pxpcs->ops->reg_write(pxpcs->pdev, pxpcs->reg_base,
> +					     MDIO_MMD_VEND2, reg, val);
> +
>  	if (pxpcs->reg_indir)
>  		return xpcs_mmio_write_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg, val);
>  	else
> @@ -195,6 +211,10 @@ static int xpcs_mmio_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
>  	if (addr != 0)
>  		return -ENODEV;
>  
> +	if (pxpcs->ops)
> +		return pxpcs->ops->reg_read(pxpcs->pdev, pxpcs->reg_base,
> +					    dev, reg);
> +
>  	if (pxpcs->reg_indir)
>  		return xpcs_mmio_read_reg_indirect(pxpcs, dev, reg);
>  	else
> @@ -209,6 +229,10 @@ static int xpcs_mmio_write_c45(struct mii_bus *bus, int addr, int dev,
>  	if (addr != 0)
>  		return -ENODEV;
>  
> +	if (pxpcs->ops)
> +		return pxpcs->ops->reg_write(pxpcs->pdev, pxpcs->reg_base,
> +					     dev, reg, val);
> +
>  	if (pxpcs->reg_indir)
>  		return xpcs_mmio_write_reg_indirect(pxpcs, dev, reg, val);
>  	else
> 
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support
  2026-09-23  1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
  2026-09-23 12:07   ` Andrew Lunn
  2026-09-24  1:09   ` sashiko-bot
@ 2026-09-25 10:37   ` Lorenzo Bianconi
  2 siblings, 0 replies; 38+ messages in thread
From: Lorenzo Bianconi @ 2026-09-25 10:37 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

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

> Qualcomm Nord exposes the DesignWare XPCS register blocks through
> separate direct-MMIO windows instead of the standard contiguous
> MMD/register layout. Add accessors that translate MMD accesses to the
> Nord windows:
> 
>   MMD 3 (PCS), standard registers: SR_XS at 0x0000
>   MMD 3 (PCS), vendor registers:   VR_XS at 0x2000
>   MMD 1 (PMA/PMD):                  SR_PMA at 0x3000
>   MMD 31 (VEND2), standard regs:    SR_MII at 0x4000
>   MMD 31 (VEND2), vendor registers: VR_MII at 0x5000
> 
> Each register uses a 32-bit MMIO stride. The vendor bit is removed from
> the register index before calculating a vendor-window offset.
> 
> Select these accessors using the Nord synthetic XPCS ID, allow its
> smaller direct-MMIO resource, and add the Nord USXGMII Clause 37
> compatibility.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
> ---
>  drivers/net/pcs/Makefile        |  3 +-
>  drivers/net/pcs/pcs-xpcs-plat.c | 17 +++++++-
>  drivers/net/pcs/pcs-xpcs-qcom.c | 86 +++++++++++++++++++++++++++++++++++++++++
>  drivers/net/pcs/pcs-xpcs-qcom.h | 16 ++++++++
>  drivers/net/pcs/pcs-xpcs.c      | 13 +++++++
>  include/linux/pcs/pcs-xpcs.h    |  1 +
>  6 files changed, 134 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
> index 4f7920618b90051e839a74a7101aaaf055a77f74..3d7cf1a5cd0783078edcefc6dfec626af469495d 100644
> --- a/drivers/net/pcs/Makefile
> +++ b/drivers/net/pcs/Makefile
> @@ -2,7 +2,8 @@
>  # Makefile for Linux PCS drivers
>  
>  pcs_xpcs-$(CONFIG_PCS_XPCS)	:= pcs-xpcs.o pcs-xpcs-plat.o \
> -				   pcs-xpcs-nxp.o pcs-xpcs-wx.o
> +				   pcs-xpcs-nxp.o pcs-xpcs-qcom.o \
> +				   pcs-xpcs-wx.o
>  
>  obj-$(CONFIG_PCS_XPCS)		+= pcs_xpcs.o
>  obj-$(CONFIG_PCS_LYNX)		+= pcs-lynx.o
> diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
> index e78a233fb198d940951064a71e8597c6c666bc9d..e013a5253a22651220e62352d03faabc3a3c3658 100644
> --- a/drivers/net/pcs/pcs-xpcs-plat.c
> +++ b/drivers/net/pcs/pcs-xpcs-plat.c
> @@ -20,6 +20,7 @@
>  #include <linux/sizes.h>
>  
>  #include "pcs-xpcs.h"
> +#include "pcs-xpcs-qcom.h"
>  
>  /* Page select register for the indirect MMIO CSRs access */
>  #define DW_VR_CSR_VIEWPORT		0xff
> @@ -239,8 +240,14 @@ static int xpcs_mmio_write_c45(struct mii_bus *bus, int addr, int dev,
>  		return xpcs_mmio_write_reg_direct(pxpcs, dev, reg, val);
>  }
>  
> +static const struct dw_xpcs_plat_ops xpcs_qcom_ops = {
> +	.reg_read = xpcs_qcom_reg_read,
> +	.reg_write = xpcs_qcom_reg_write,
> +};
> +
>  static struct dw_xpcs_plat *xpcs_plat_create_data(struct platform_device *pdev)
>  {
> +	const struct dw_xpcs_info *info;
>  	struct dw_xpcs_plat *pxpcs;
>  
>  	pxpcs = devm_kzalloc(&pdev->dev, sizeof(*pxpcs), GFP_KERNEL);
> @@ -248,6 +255,12 @@ static struct dw_xpcs_plat *xpcs_plat_create_data(struct platform_device *pdev)
>  		return ERR_PTR(-ENOMEM);
>  
>  	pxpcs->pdev = pdev;
> +	info = device_get_match_data(&pdev->dev);
> +	if (!info)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (info->pcs == QCOM_NORD_XPCS_ID)
> +		pxpcs->ops = &xpcs_qcom_ops;
>  
>  	dev_set_drvdata(&pdev->dev, pxpcs);
>  
> @@ -285,7 +298,7 @@ static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)
>  	else
>  		spc_size = pxpcs->reg_width * SZ_2M;
>  
> -	if (resource_size(res) < spc_size) {
> +	if (!pxpcs->ops && resource_size(res) < spc_size) {
>  		dev_err(dev, "Invalid reg-space size\n");
>  		return -EINVAL;
>  	}
> @@ -452,8 +465,10 @@ DW_XPCS_INFO_DECLARE(xpcs_pma_gen4_3g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN4_3G_ID
>  DW_XPCS_INFO_DECLARE(xpcs_pma_gen4_6g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN4_6G_ID);
>  DW_XPCS_INFO_DECLARE(xpcs_pma_gen5_10g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN5_10G_ID);
>  DW_XPCS_INFO_DECLARE(xpcs_pma_gen5_12g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN5_12G_ID);
> +DW_XPCS_INFO_DECLARE(xpcs_qcom_nord, QCOM_NORD_XPCS_ID, DW_XPCS_PMA_ID_NATIVE);
>  
>  static const struct of_device_id xpcs_of_ids[] = {
> +	{ .compatible = "qcom,nord-dw-xpcs", .data = &xpcs_qcom_nord },
>  	{ .compatible = "snps,dw-xpcs", .data = &xpcs_generic },
>  	{ .compatible = "snps,dw-xpcs-gen1-3g", .data = &xpcs_pma_gen1_3g },
>  	{ .compatible = "snps,dw-xpcs-gen2-3g", .data = &xpcs_pma_gen2_3g },
> diff --git a/drivers/net/pcs/pcs-xpcs-qcom.c b/drivers/net/pcs/pcs-xpcs-qcom.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..63c95c951454819b62eb3fd00abcc6b529e2004b
> --- /dev/null
> +++ b/drivers/net/pcs/pcs-xpcs-qcom.c
> @@ -0,0 +1,86 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Qualcomm DesignWare XPCS platform helpers
> + *
> + * Copyright (c) 2026 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/mdio.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +
> +#include "pcs-xpcs.h"
> +#include "pcs-xpcs-qcom.h"
> +
> +/* Qualcomm Nord direct MMIO XPCS windows. */
> +#define QCOM_XPCS_SR_XS_BASE		0x0000
> +#define QCOM_XPCS_VR_XS_BASE		0x2000
> +#define QCOM_XPCS_SR_PMA_BASE		0x3000
> +#define QCOM_XPCS_SR_MII_BASE		0x4000
> +#define QCOM_XPCS_VR_MII_BASE		0x5000
> +
> +static int xpcs_qcom_reg_offset(int dev, int reg)
> +{
> +	switch (dev) {
> +	case MDIO_MMD_PCS:
> +		if (reg & DW_VENDOR)
> +			return QCOM_XPCS_VR_XS_BASE +
> +			       ((reg & ~DW_VENDOR) << 2);
> +
> +		return QCOM_XPCS_SR_XS_BASE + (reg << 2);
> +
> +	case MDIO_MMD_PMAPMD:
> +		return QCOM_XPCS_SR_PMA_BASE + (reg << 2);
> +
> +	case MDIO_MMD_VEND2:
> +		if (reg >= DW_VENDOR)
> +			return QCOM_XPCS_VR_MII_BASE +
> +			       ((reg - DW_VENDOR) << 2);
> +
> +		return QCOM_XPCS_SR_MII_BASE + (reg << 2);
> +
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}

This seems to be the real difference with respect to the
xpcs_mmio_read_reg_direct()/xpcs_mmio_write_reg_direct(), right?
Maybe a different approach (simpler but probably less flexible is to make
xpcs_mmio_addr_format() SoC dependent. What do you think?

> +
> +int xpcs_qcom_reg_read(struct platform_device *pdev, void __iomem *reg_base,
> +		       int dev, int reg)
> +{
> +	int offset, ret;
> +
> +	offset = xpcs_qcom_reg_offset(dev, reg);
> +	if (offset < 0)
> +		return offset;
> +
> +	ret = pm_runtime_resume_and_get(&pdev->dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = readl(reg_base + offset) & 0xffff;
> +
> +	pm_runtime_put(&pdev->dev);
> +
> +	return ret;
> +}
> +
> +int xpcs_qcom_reg_write(struct platform_device *pdev, void __iomem *reg_base,
> +			int dev, int reg, u16 val)
> +{
> +	int offset, ret;
> +
> +	offset = xpcs_qcom_reg_offset(dev, reg);
> +	if (offset < 0)
> +		return offset;
> +
> +	ret = pm_runtime_resume_and_get(&pdev->dev);
> +	if (ret < 0)
> +		return ret;
> +
> +	writel(val, reg_base + offset);
> +
> +	pm_runtime_put(&pdev->dev);
> +
> +	return 0;
> +}
> diff --git a/drivers/net/pcs/pcs-xpcs-qcom.h b/drivers/net/pcs/pcs-xpcs-qcom.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..a1084f6a10a96baa8ba0d192ee64cdaed90da125
> --- /dev/null
> +++ b/drivers/net/pcs/pcs-xpcs-qcom.h
> @@ -0,0 +1,16 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __PCS_XPCS_QCOM_H
> +#define __PCS_XPCS_QCOM_H
> +
> +#include <linux/io.h>
> +#include <linux/types.h>
> +
> +struct platform_device;
> +
> +int xpcs_qcom_reg_read(struct platform_device *pdev, void __iomem *reg_base,
> +		       int dev, int reg);
> +int xpcs_qcom_reg_write(struct platform_device *pdev, void __iomem *reg_base,
> +			int dev, int reg, u16 val);
> +
> +#endif /* __PCS_XPCS_QCOM_H */
> diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
> index 7f5c7a275630f2b064e4b9abdd6c3619e9346cec..1f556b4f7c44f06f24a2f724734d3a7d71424de3 100644
> --- a/drivers/net/pcs/pcs-xpcs.c
> +++ b/drivers/net/pcs/pcs-xpcs.c
> @@ -1571,6 +1571,15 @@ static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[] = {
>  	}
>  };
>  
> +static const struct dw_xpcs_compat qcom_nord_xpcs_compat[] = {
> +	{
> +		.interface = PHY_INTERFACE_MODE_USXGMII,
> +		.supported = xpcs_usxgmii_features,
> +		.an_mode = DW_AN_C37_USXGMII,
> +	}, {
> +	}
> +};
> +
>  static const struct dw_xpcs_desc xpcs_desc_list[] = {
>  	{
>  		.id = DW_XPCS_ID,
> @@ -1584,6 +1593,10 @@ static const struct dw_xpcs_desc xpcs_desc_list[] = {
>  		.id = NXP_SJA1110_XPCS_ID,
>  		.mask = DW_XPCS_ID_MASK,
>  		.compat = nxp_sja1110_xpcs_compat,
> +	}, {
> +		.id = QCOM_NORD_XPCS_ID,
> +		.mask = DW_XPCS_ID_MASK,
> +		.compat = qcom_nord_xpcs_compat,
>  	},

I guess this part is supposed to be part of patch 2/9, right?

Regards,
Lorenzo

>  };
>  
> diff --git a/include/linux/pcs/pcs-xpcs.h b/include/linux/pcs/pcs-xpcs.h
> index 4ea995b70150e33e1e1a47cc7aa324c53742fbdc..0f69e14b2a4c8d17b59a570debd14a77ab040182 100644
> --- a/include/linux/pcs/pcs-xpcs.h
> +++ b/include/linux/pcs/pcs-xpcs.h
> @@ -26,6 +26,7 @@ enum dw_xpcs_pcs_id {
>  	DW_XPCS_ID_NATIVE = 0,
>  	NXP_SJA1105_XPCS_ID = 0x00000010,
>  	NXP_SJA1110_XPCS_ID = 0x00000020,
> +	QCOM_NORD_XPCS_ID = 0x00000030,
>  	DW_XPCS_ID = 0x7996ced0,
>  	DW_XPCS_ID_MASK = 0xffffffff,
>  };
> 
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended
  2026-09-23  1:07 ` [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended Mohd Ayaan Anwar
@ 2026-09-25 11:03   ` Lorenzo Bianconi
  0 siblings, 0 replies; 38+ messages in thread
From: Lorenzo Bianconi @ 2026-09-25 11:03 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

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

> xpcs_plat_init_clk() acquires the optional CSR clock but does not
> prepare or enable it. Marking the device runtime-active at that point
> makes the PM core assume that the hardware is already powered.
> 
> On Nord, once the XPCS CSR clock was described, the first
> pm_runtime_resume_and_get() accessed XPCS registers without invoking
> runtime_resume() to enable the clock. The matching runtime put then
> invoked runtime_suspend() and attempted to disable a clock which was
> never enabled, producing an already-disabled clock warning.
> 
> Initialize the runtime-PM state as suspended instead. The first
> register access now runs the resume callback and enables the CSR clock,
> while the subsequent suspend callback performs the matching disable.
> Check and propagate the state-transition error as part of probe.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

This patch seems a fix to me even for other SoCs. The pcs device is marked
as 'PM active' in xpcs_plat_init_clk() but the CSR clock is not actually
enabled. Moreover, the CSR clock will not be enabled even in the pm ops
since xpcs_plat_pm_runtime_resume() will not be executed (the device is
already as PM active). Am I missing something?

Regards,
Lorenzo

> ---
>  drivers/net/pcs/pcs-xpcs-plat.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
> index e013a5253a22651220e62352d03faabc3a3c3658..328c50940d46eb8e7bea06ecd1a20214e3cde61c 100644
> --- a/drivers/net/pcs/pcs-xpcs-plat.c
> +++ b/drivers/net/pcs/pcs-xpcs-plat.c
> @@ -322,7 +322,11 @@ static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
>  		return dev_err_probe(dev, PTR_ERR(pxpcs->cclk),
>  				     "Failed to get CSR clock\n");
>  
> -	pm_runtime_set_active(dev);
> +	ret = pm_runtime_set_suspended(dev);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "Failed to set runtime-PM suspended state\n");
> +
>  	ret = devm_pm_runtime_enable(dev);
>  	if (ret) {
>  		dev_err(dev, "Failed to enable runtime-PM\n");
> 
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts
  2026-09-23  1:07 ` [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
@ 2026-09-25 12:22   ` Lorenzo Bianconi
  1 sibling, 0 replies; 38+ messages in thread
From: Lorenzo Bianconi @ 2026-09-25 12:22 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

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

> Some XGMAC integrations place their MTL queues and DMA channels at
> different offsets from the standard register layout. Allow platform
> data to override these addresses while retaining the standard layout by
> default.
> 
> This follows the approach used by commit 33719b57f52e ("net: stmmac:
> dwmac4: Allow platforms to specify some DMA/MTL offsets"). Qualcomm
> XGMAC hardware similarly uses differently aligned queue and channel
> registers.
> 
> Also allow platforms to override the timestamp register base.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

Hi Mohd,

Some nits inline.

Regards,
Lorenzo

> ---
>  drivers/net/ethernet/stmicro/stmmac/common.h       |   1 +
>  .../net/ethernet/stmicro/stmmac/dwmac-socfpga.c    |   2 +-
>  drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h     |  94 ++++++++++-----
>  .../net/ethernet/stmicro/stmmac/dwxgmac2_core.c    |  34 +++---
>  drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 128 +++++++++++++--------
>  drivers/net/ethernet/stmicro/stmmac/hwif.c         |   5 +-
>  .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |   5 +-
>  drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c   |  15 ++-
>  include/linux/stmmac.h                             |  11 ++
>  9 files changed, 193 insertions(+), 102 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index 1729fb29ece3853584bc27ed541413bcba88c695..c6387cecaf5d93ef10c45475a533bf1d0a4e0b45 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -622,6 +622,7 @@ struct mac_device_info {
>  	const struct stmmac_mmc_ops *mmc;
>  	const struct stmmac_est_ops *est;
>  	const struct stmmac_vlan_ops *vlan;
> +	const struct dwxgmac_addrs *dwxgmac_addrs;
>  	struct dw_xpcs *xpcs;
>  	struct phylink_pcs *phylink_pcs;
>  	struct mii_regs mii;	/* MII register Addresses */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> index 1d7f0a57d28897005cdc1c5dcbd3c2f737a6c967..331ba38abae66f03b69c383b30762c9a09735a37 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
> @@ -365,7 +365,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
>  	};
>  
>  	num_snapshot = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK,
> -				 readl(ioaddr + XGMAC_TIMESTAMP_STATUS));
> +				 readl(ioaddr + XGMAC_TIMESTAMP_STATUS(NULL)));
>  
>  	/* Repeat until the timestamps are from the FIFO last segment */
>  	for (i = 0; i < num_snapshot; i++) {
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> index f8ab347f7b5b9e1b2df662785bb25cf875456088..22b476358a2028de862186c3d38295b2d48d87d6 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> @@ -220,12 +220,21 @@
>  #define XGMAC_CT			BIT(1)
>  #define XGMAC_OB			BIT(0)
>  #define XGMAC_RSS_DATA			0x00000c8c
> -#define XGMAC_TIMESTAMP_STATUS		0x00000d20
> +
> +/* Timestamp registers */
> +#define XGMAC_TIMESTAMP_BASE_ADDR	0x00000d00
> +
> +static inline u32 xgmac_timestamp_base_addr(const struct dwxgmac_addrs *addrs)
> +{
> +	return addrs ? addrs->timestamp_base : XGMAC_TIMESTAMP_BASE_ADDR;
> +}
> +
> +#define XGMAC_TIMESTAMP_STATUS(a)	(xgmac_timestamp_base_addr(a) + 0x20)
>  #define XGMAC_TIMESTAMP_ATSNS_MASK	GENMASK(29, 25)
>  #define XGMAC_TXTSC			BIT(15)
> -#define XGMAC_TXTIMESTAMP_NSEC		0x00000d30
> +#define XGMAC_TXTIMESTAMP_NSEC(a)	(xgmac_timestamp_base_addr(a) + 0x30)
>  #define XGMAC_TXTSSTSLO			GENMASK(30, 0)
> -#define XGMAC_TXTIMESTAMP_SEC		0x00000d34
> +#define XGMAC_TXTIMESTAMP_SEC(a)	(xgmac_timestamp_base_addr(a) + 0x34)
>  #define XGMAC_PPS_CONTROL		0x00000d70
>  #define XGMAC_PPS_MAXIDX(x)		((((x) + 1) * 8) - 1)
>  #define XGMAC_PPS_MINIDX(x)		((x) * 8)
> @@ -285,37 +294,49 @@
>  #define XGMAC_MTL_ECC_INT_STATUS	0x000010cc
>  #define XGMAC_MTL_DPP_CONTROL		0x000010e0
>  #define XGMAC_DPP_DISABLE		BIT(0)
> -#define XGMAC_MTL_TXQ_OPMODE(x)		(0x00001100 + (0x80 * (x)))
> +
> +/* MTL per-queue registers */
> +#define XGMAC_MTL_CHAN_BASE_ADDR	0x00001100
> +#define XGMAC_MTL_CHAN_OFFSET		0x80
> +
> +static inline u32
> +xgmac_mtl_chanx_base_addr(const struct dwxgmac_addrs *addrs, u32 x)
> +{
> +	return addrs ? addrs->mtl_chan_base + x * addrs->mtl_chan_offset
> +		     : XGMAC_MTL_CHAN_BASE_ADDR + x * XGMAC_MTL_CHAN_OFFSET;
> +}

I think if we introduce a dma map even for default case these functions will be more
readable. What do you think?

> +
> +#define XGMAC_MTL_TXQ_OPMODE(a, x)		xgmac_mtl_chanx_base_addr(a, x)
>  #define XGMAC_TQS			GENMASK(25, 16)
>  #define XGMAC_Q2TCMAP			GENMASK(10, 8)
>  #define XGMAC_TTC			GENMASK(6, 4)
>  #define XGMAC_TXQEN			GENMASK(3, 2)
>  #define XGMAC_TSF			BIT(1)
> -#define XGMAC_MTL_TCx_ETS_CONTROL(x)	(0x00001110 + (0x80 * (x)))
> -#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x)	(0x00001118 + (0x80 * (x)))
> -#define XGMAC_MTL_TCx_SENDSLOPE(x)	(0x0000111c + (0x80 * (x)))
> -#define XGMAC_MTL_TCx_HICREDIT(x)	(0x00001120 + (0x80 * (x)))
> -#define XGMAC_MTL_TCx_LOCREDIT(x)	(0x00001124 + (0x80 * (x)))
> +#define XGMAC_MTL_TCx_ETS_CONTROL(a, x)	(xgmac_mtl_chanx_base_addr(a, x) + 0x10)
> +#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(a, x)	(xgmac_mtl_chanx_base_addr(a, x) + 0x18)
> +#define XGMAC_MTL_TCx_SENDSLOPE(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x1c)
> +#define XGMAC_MTL_TCx_HICREDIT(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x20)
> +#define XGMAC_MTL_TCx_LOCREDIT(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x24)
>  #define XGMAC_CC			BIT(3)
>  #define XGMAC_TSA			GENMASK(1, 0)
>  #define XGMAC_SP			(0x0 << 0)
>  #define XGMAC_CBS			(0x1 << 0)
>  #define XGMAC_ETS			(0x2 << 0)
> -#define XGMAC_MTL_RXQ_OPMODE(x)		(0x00001140 + (0x80 * (x)))
> +#define XGMAC_MTL_RXQ_OPMODE(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x40)
>  #define XGMAC_RQS			GENMASK(25, 16)
>  #define XGMAC_EHFC			BIT(7)
>  #define XGMAC_RSF			BIT(5)
>  #define XGMAC_RTC			GENMASK(1, 0)
> -#define XGMAC_MTL_RXQ_FLOW_CONTROL(x)	(0x00001150 + (0x80 * (x)))
> +#define XGMAC_MTL_RXQ_FLOW_CONTROL(a, x)	(xgmac_mtl_chanx_base_addr(a, x) + 0x50)
>  #define XGMAC_RFD			GENMASK(31, 17)
>  #define XGMAC_RFA			GENMASK(15, 1)
> -#define XGMAC_MTL_QINTEN(x)		(0x00001170 + (0x80 * (x)))
> +#define XGMAC_MTL_QINTEN(a, x)			(xgmac_mtl_chanx_base_addr(a, x) + 0x70)
>  #define XGMAC_RXOIE			BIT(16)
> -#define XGMAC_MTL_QINT_STATUS(x)	(0x00001174 + (0x80 * (x)))
> +#define XGMAC_MTL_QINT_STATUS(a, x)		(xgmac_mtl_chanx_base_addr(a, x) + 0x74)
>  #define XGMAC_RXOVFIS			BIT(16)
>  #define XGMAC_ABPSIS			BIT(1)
>  #define XGMAC_TXUNFIS			BIT(0)
> -#define XGMAC_MAC_REGSIZE		(XGMAC_MTL_QINT_STATUS(15) / 4)
> +#define XGMAC_MAC_REGSIZE(a)		(XGMAC_MTL_QINT_STATUS(a, 15) / 4)
>  
>  /* DMA Registers */
>  #define XGMAC_DMA_MODE			0x00003000
> @@ -353,28 +374,43 @@
>  #define XGMAC_TCEIE			BIT(0)
>  #define XGMAC_DMA_ECC_INT_STATUS	0x0000306c
>  #define XGMAC_DMA_DPP_INT_STATUS	0x00003074
> -#define XGMAC_DMA_CH_CONTROL(x)		(0x00003100 + (0x80 * (x)))
> +
> +/* DMA per-channel registers */
> +#define XGMAC_DMA_CHAN_BASE_ADDR	0x00003100
> +#define XGMAC_DMA_CHAN_OFFSET		0x80
> +
> +static inline u32
> +xgmac_dma_chanx_base_addr(const struct dwxgmac_addrs *addrs, u32 x)
> +{
> +	if (addrs && (x & 1))
> +		return addrs->dma_odd_chan_base + x * addrs->dma_chan_offset;
> +	if (addrs)
> +		return addrs->dma_even_chan_base + x * addrs->dma_chan_offset;
> +	return XGMAC_DMA_CHAN_BASE_ADDR + x * XGMAC_DMA_CHAN_OFFSET;
> +}
> +
> +#define XGMAC_DMA_CH_CONTROL(a, x)		(xgmac_dma_chanx_base_addr(a, x))
>  #define XGMAC_SPH			BIT(24)
>  #define XGMAC_PBLx8			BIT(16)
> -#define XGMAC_DMA_CH_TX_CONTROL(x)	(0x00003104 + (0x80 * (x)))
> +#define XGMAC_DMA_CH_TX_CONTROL(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x04)
>  #define XGMAC_EDSE			BIT(28)
>  #define XGMAC_TxPBL			GENMASK(21, 16)
>  #define XGMAC_TSE			BIT(12)
>  #define XGMAC_OSP			BIT(4)
>  #define XGMAC_TXST			BIT(0)
> -#define XGMAC_DMA_CH_RX_CONTROL(x)	(0x00003108 + (0x80 * (x)))
> +#define XGMAC_DMA_CH_RX_CONTROL(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x08)
>  #define XGMAC_RxPBL			GENMASK(21, 16)
>  #define XGMAC_RBSZ			GENMASK(14, 1)
>  #define XGMAC_RXST			BIT(0)
> -#define XGMAC_DMA_CH_TxDESC_HADDR(x)	(0x00003110 + (0x80 * (x)))
> -#define XGMAC_DMA_CH_TxDESC_LADDR(x)	(0x00003114 + (0x80 * (x)))
> -#define XGMAC_DMA_CH_RxDESC_HADDR(x)	(0x00003118 + (0x80 * (x)))
> -#define XGMAC_DMA_CH_RxDESC_LADDR(x)	(0x0000311c + (0x80 * (x)))
> -#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(x)	(0x00003124 + (0x80 * (x)))
> -#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(x)	(0x0000312c + (0x80 * (x)))
> -#define XGMAC_DMA_CH_TxDESC_RING_LEN(x)		(0x00003130 + (0x80 * (x)))
> -#define XGMAC_DMA_CH_RxDESC_RING_LEN(x)		(0x00003134 + (0x80 * (x)))
> -#define XGMAC_DMA_CH_INT_EN(x)		(0x00003138 + (0x80 * (x)))
> +#define XGMAC_DMA_CH_TxDESC_HADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x10)
> +#define XGMAC_DMA_CH_TxDESC_LADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x14)
> +#define XGMAC_DMA_CH_RxDESC_HADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x18)
> +#define XGMAC_DMA_CH_RxDESC_LADDR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x1c)
> +#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x24)
> +#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x2c)
> +#define XGMAC_DMA_CH_TxDESC_RING_LEN(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x30)
> +#define XGMAC_DMA_CH_RxDESC_RING_LEN(a, x)	(xgmac_dma_chanx_base_addr(a, x) + 0x34)
> +#define XGMAC_DMA_CH_INT_EN(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x38)
>  #define XGMAC_NIE			BIT(15)
>  #define XGMAC_AIE			BIT(14)
>  #define XGMAC_RBUE			BIT(7)
> @@ -385,9 +421,9 @@
>  					XGMAC_RIE | XGMAC_TIE)
>  #define XGMAC_DMA_INT_DEFAULT_RX	(XGMAC_RIE)
>  #define XGMAC_DMA_INT_DEFAULT_TX	(XGMAC_TIE)
> -#define XGMAC_DMA_CH_Rx_WATCHDOG(x)	(0x0000313c + (0x80 * (x)))
> +#define XGMAC_DMA_CH_Rx_WATCHDOG(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x3c)
>  #define XGMAC_RWT			GENMASK(7, 0)
> -#define XGMAC_DMA_CH_STATUS(x)		(0x00003160 + (0x80 * (x)))
> +#define XGMAC_DMA_CH_STATUS(a, x)		(xgmac_dma_chanx_base_addr(a, x) + 0x60)
>  #define XGMAC_NIS			BIT(15)
>  #define XGMAC_AIS			BIT(14)
>  #define XGMAC_FBE			BIT(12)
> @@ -396,7 +432,7 @@
>  #define XGMAC_TBU			BIT(2)
>  #define XGMAC_TPS			BIT(1)
>  #define XGMAC_TI			BIT(0)
> -#define XGMAC_REGSIZE			((0x0000317c + (0x80 * 15)) / 4)
> +#define XGMAC_REGSIZE(a)		((xgmac_dma_chanx_base_addr(a, 15) + 0x7c) / 4)
>  
>  #define XGMAC_DMA_STATUS_MSK_COMMON	(XGMAC_NIS | XGMAC_AIS | XGMAC_FBE)
>  #define XGMAC_DMA_STATUS_MSK_RX		(XGMAC_RBU | XGMAC_RI | \
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
> index 1a88cbaed70ca18bbb714681569ede863f7130e5..d1099a1cf9ea56661e2beceeaa3f1938e51dfb3c 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
> @@ -234,11 +234,11 @@ static void dwxgmac2_prog_mtl_tx_algorithms(struct mac_device_info *hw,
>  
>  	/* Set ETS if desired */
>  	for (i = 0; i < MTL_MAX_TX_QUEUES; i++) {
> -		value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(i));
> +		value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(hw->dwxgmac_addrs, i));
>  		value &= ~XGMAC_TSA;
>  		if (ets)
>  			value |= XGMAC_ETS;
> -		writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(i));
> +		writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(hw->dwxgmac_addrs, i));
>  	}
>  }
>  
> @@ -246,9 +246,10 @@ static void dwxgmac2_set_mtl_tx_queue_weight(struct stmmac_priv *priv,
>  					     struct mac_device_info *hw,
>  					     u32 weight, u32 queue)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	void __iomem *ioaddr = hw->pcsr;
>  
> -	writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
> +	writel(weight, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(addrs, queue));
>  }
>  
>  static void dwxgmac2_map_mtl_to_dma(struct mac_device_info *hw, u32 queue,
> @@ -273,18 +274,19 @@ static void dwxgmac2_config_cbs(struct stmmac_priv *priv,
>  				u32 send_slope, u32 idle_slope,
>  				u32 high_credit, u32 low_credit, u32 queue)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	void __iomem *ioaddr = hw->pcsr;
>  	u32 value;
>  
> -	writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(queue));
> -	writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(queue));
> -	writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(queue));
> -	writel(low_credit, ioaddr + XGMAC_MTL_TCx_LOCREDIT(queue));
> +	writel(send_slope, ioaddr + XGMAC_MTL_TCx_SENDSLOPE(addrs, queue));
> +	writel(idle_slope, ioaddr + XGMAC_MTL_TCx_QUANTUM_WEIGHT(addrs, queue));
> +	writel(high_credit, ioaddr + XGMAC_MTL_TCx_HICREDIT(addrs, queue));
> +	writel(low_credit, ioaddr + XGMAC_MTL_TCx_LOCREDIT(addrs, queue));
>  
> -	value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
> +	value = readl(ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(addrs, queue));
>  	value &= ~XGMAC_TSA;
>  	value |= XGMAC_CC | XGMAC_CBS;
> -	writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(queue));
> +	writel(value, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(addrs, queue));
>  }
>  
>  static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space)
> @@ -292,7 +294,7 @@ static void dwxgmac2_dump_regs(struct mac_device_info *hw, u32 *reg_space)
>  	void __iomem *ioaddr = hw->pcsr;
>  	int i;
>  
> -	for (i = 0; i < XGMAC_MAC_REGSIZE; i++)
> +	for (i = 0; i < XGMAC_MAC_REGSIZE(hw->dwxgmac_addrs); i++)
>  		reg_space[i] = readl(ioaddr + i * 4);
>  }
>  
> @@ -336,18 +338,19 @@ static int dwxgmac2_host_irq_status(struct stmmac_priv *priv,
>  static int dwxgmac2_host_mtl_irq_status(struct stmmac_priv *priv,
>  					struct mac_device_info *hw, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	void __iomem *ioaddr = hw->pcsr;
>  	int ret = 0;
>  	u32 status;
>  
>  	status = readl(ioaddr + XGMAC_MTL_INT_STATUS);
>  	if (status & BIT(chan)) {
> -		u32 chan_status = readl(ioaddr + XGMAC_MTL_QINT_STATUS(chan));
> +		u32 chan_status = readl(ioaddr + XGMAC_MTL_QINT_STATUS(addrs, chan));
>  
>  		if (chan_status & XGMAC_RXOVFIS)
>  			ret |= CORE_IRQ_MTL_RX_OVERFLOW;
>  
> -		writel(~0x0, ioaddr + XGMAC_MTL_QINT_STATUS(chan));
> +		writel(~0x0, ioaddr + XGMAC_MTL_QINT_STATUS(addrs, chan));
>  	}
>  
>  	return ret;
> @@ -1143,14 +1146,15 @@ static int dwxgmac3_rxp_config(void __iomem *ioaddr,
>  static int dwxgmac2_get_mac_tx_timestamp(struct mac_device_info *hw, u64 *ts)
>  {
>  	void __iomem *ioaddr = hw->pcsr;
> +	const struct dwxgmac_addrs *addrs = hw->dwxgmac_addrs;
>  	u32 value;
>  
> -	if (readl_poll_timeout_atomic(ioaddr + XGMAC_TIMESTAMP_STATUS,
> +	if (readl_poll_timeout_atomic(ioaddr + XGMAC_TIMESTAMP_STATUS(addrs),
>  				      value, value & XGMAC_TXTSC, 100, 10000))
>  		return -EBUSY;
>  
> -	*ts = readl(ioaddr + XGMAC_TXTIMESTAMP_NSEC) & XGMAC_TXTSSTSLO;
> -	*ts += readl(ioaddr + XGMAC_TXTIMESTAMP_SEC) * 1000000000ULL;
> +	*ts = readl(ioaddr + XGMAC_TXTIMESTAMP_NSEC(addrs)) & XGMAC_TXTSSTSLO;
> +	*ts += readl(ioaddr + XGMAC_TXTIMESTAMP_SEC(addrs)) * 1000000000ULL;
>  	return 0;
>  }
>  
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> index ff83858ebc1f33aa8092a2d83018bd5f96b7eead..65d5e2a828076563a1c7368124ddda226bfffc7a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> @@ -47,13 +47,14 @@ static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv,
>  				   void __iomem *ioaddr,
>  				   struct stmmac_dma_cfg *dma_cfg, u32 chan)
>  {
> -	u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
>  
>  	if (dma_cfg->pblx8)
>  		value |= XGMAC_PBLx8;
>  
> -	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
> -	writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
> +	writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
>  }
>  
>  static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
> @@ -61,15 +62,16 @@ static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
>  				      struct stmmac_dma_cfg *dma_cfg,
>  				      dma_addr_t phy, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  	value = u32_replace_bits(value, rxpbl, XGMAC_RxPBL);
> -	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  
> -	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
> -	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
> +	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(addrs, chan));
> +	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(addrs, chan));
>  }
>  
>  static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
> @@ -77,15 +79,16 @@ static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
>  				      struct stmmac_dma_cfg *dma_cfg,
>  				      dma_addr_t phy, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  	value = u32_replace_bits(value, txpbl, XGMAC_TxPBL);
> -	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  
> -	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
> -	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
> +	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(addrs, chan));
> +	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(addrs, chan));
>  }
>  
>  static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
> @@ -118,16 +121,18 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
>  static void dwxgmac2_dma_dump_regs(struct stmmac_priv *priv,
>  				   void __iomem *ioaddr, u32 *reg_space)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	int i;
>  
> -	for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE; i++)
> +	for (i = (XGMAC_DMA_MODE / 4); i < XGMAC_REGSIZE(addrs); i++)
>  		reg_space[i] = readl(ioaddr + i * 4);
>  }
>  
>  static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				 int mode, u32 channel, int fifosz, u8 qmode)
>  {
> -	u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_MTL_RXQ_OPMODE(addrs, channel));
>  	unsigned int rqs = fifosz / 256 - 1;
>  	unsigned int rtc;
>  
> @@ -149,7 +154,7 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
>  	value = u32_replace_bits(value, rqs, XGMAC_RQS);
>  
>  	if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
> -		u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
> +		u32 flow = readl(ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(addrs, channel));
>  		unsigned int rfd, rfa;
>  
>  		value |= XGMAC_EHFC;
> @@ -178,16 +183,17 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
>  		flow = u32_replace_bits(flow, rfd, XGMAC_RFD);
>  		flow = u32_replace_bits(flow, rfa, XGMAC_RFA);
>  
> -		writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(channel));
> +		writel(flow, ioaddr + XGMAC_MTL_RXQ_FLOW_CONTROL(addrs, channel));
>  	}
>  
> -	writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel));
> +	writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(addrs, channel));
>  }
>  
>  static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				 int mode, u32 channel, int fifosz, u8 qmode)
>  {
> -	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(addrs, channel));
>  	unsigned int tqs = fifosz / 256 - 1;
>  	unsigned int ttc, txqen;
>  
> @@ -225,45 +231,48 @@ static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr,
>  	value = u32_replace_bits(value, txqen, XGMAC_TXQEN);
>  	value = u32_replace_bits(value, tqs, XGMAC_TQS);
>  
> -	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(channel));
> +	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(addrs, channel));
>  }
>  
>  static void dwxgmac2_enable_dma_irq(struct stmmac_priv *priv,
>  				    void __iomem *ioaddr, u32 chan,
>  				    bool rx, bool tx)
>  {
> -	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
>  
>  	if (rx)
>  		value |= XGMAC_DMA_INT_DEFAULT_RX;
>  	if (tx)
>  		value |= XGMAC_DMA_INT_DEFAULT_TX;
>  
> -	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
>  }
>  
>  static void dwxgmac2_disable_dma_irq(struct stmmac_priv *priv,
>  				     void __iomem *ioaddr, u32 chan,
>  				     bool rx, bool tx)
>  {
> -	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
>  
>  	if (rx)
>  		value &= ~XGMAC_DMA_INT_DEFAULT_RX;
>  	if (tx)
>  		value &= ~XGMAC_DMA_INT_DEFAULT_TX;
>  
> -	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
>  }
>  
>  static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv,
>  				  void __iomem *ioaddr, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  	value |= XGMAC_TXST;
> -	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  
>  	value = readl(ioaddr + XGMAC_TX_CONFIG);
>  	value |= XGMAC_CONFIG_TE;
> @@ -273,11 +282,12 @@ static void dwxgmac2_dma_start_tx(struct stmmac_priv *priv,
>  static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				 u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  	value &= ~XGMAC_TXST;
> -	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  
>  	value = readl(ioaddr + XGMAC_TX_CONFIG);
>  	value &= ~XGMAC_CONFIG_TE;
> @@ -287,11 +297,12 @@ static void dwxgmac2_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr,
>  static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv,
>  				  void __iomem *ioaddr, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  	value |= XGMAC_RXST;
> -	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  
>  	value = readl(ioaddr + XGMAC_RX_CONFIG);
>  	value |= XGMAC_CONFIG_RE;
> @@ -301,11 +312,12 @@ static void dwxgmac2_dma_start_rx(struct stmmac_priv *priv,
>  static void dwxgmac2_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				 u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  	value &= ~XGMAC_RXST;
> -	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  }
>  
>  static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
> @@ -314,8 +326,9 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
>  				  u32 dir)
>  {
>  	struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);
> -	u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan));
> -	u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(addrs, chan));
> +	u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(addrs, chan));
>  	int ret = 0;
>  
>  	if (dir == DMA_DIR_RX)
> @@ -354,7 +367,7 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv,
>  	}
>  
>  	/* Clear interrupts */
> -	writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(chan));
> +	writel(intr_en & intr_status, ioaddr + XGMAC_DMA_CH_STATUS(addrs, chan));
>  
>  	return ret;
>  }
> @@ -483,105 +496,120 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr,
>  static void dwxgmac2_rx_watchdog(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				 u32 riwt, u32 queue)
>  {
> -	writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(queue));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +
> +	writel(riwt & XGMAC_RWT, ioaddr + XGMAC_DMA_CH_Rx_WATCHDOG(addrs, queue));
>  }
>  
>  static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv,
>  				     void __iomem *ioaddr, u32 len, u32 chan)
>  {
> -	writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +
> +	writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(addrs, chan));
>  }
>  
>  static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv,
>  				     void __iomem *ioaddr, u32 len, u32 chan)
>  {
> -	writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +
> +	writel(len, ioaddr + XGMAC_DMA_CH_TxDESC_RING_LEN(addrs, chan));
>  }
>  
>  static void dwxgmac2_set_rx_tail_ptr(struct stmmac_priv *priv,
>  				     void __iomem *ioaddr, u32 ptr, u32 chan)
>  {
> -	writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +
> +	writel(ptr, ioaddr + XGMAC_DMA_CH_RxDESC_TAIL_LPTR(addrs, chan));
>  }
>  
>  static void dwxgmac2_set_tx_tail_ptr(struct stmmac_priv *priv,
>  				     void __iomem *ioaddr, u32 ptr, u32 chan)
>  {
> -	writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +
> +	writel(ptr, ioaddr + XGMAC_DMA_CH_TxDESC_TAIL_LPTR(addrs, chan));
>  }
>  
>  static void dwxgmac2_enable_tso(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				bool en, u32 chan)
>  {
> -	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  
>  	if (en)
>  		value |= XGMAC_TSE;
>  	else
>  		value &= ~XGMAC_TSE;
>  
> -	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  }
>  
>  static void dwxgmac2_qmode(struct stmmac_priv *priv, void __iomem *ioaddr,
>  			   u32 channel, u8 qmode)
>  {
> -	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(channel));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_MTL_TXQ_OPMODE(addrs, channel));
>  	u32 flow = readl(ioaddr + XGMAC_RX_FLOW_CTRL);
>  	unsigned int txqen;
>  
>  	if (qmode != MTL_QUEUE_AVB) {
>  		txqen = 0x2;
> -		writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(channel));
> +		writel(0, ioaddr + XGMAC_MTL_TCx_ETS_CONTROL(addrs, channel));
>  	} else {
>  		txqen = 0x1;
>  		writel(flow & (~XGMAC_RFE), ioaddr + XGMAC_RX_FLOW_CTRL);
>  	}
>  
>  	value = u32_replace_bits(value, txqen, XGMAC_TXQEN);
> -	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(channel));
> +	writel(value, ioaddr +  XGMAC_MTL_TXQ_OPMODE(addrs, channel));
>  }
>  
>  static void dwxgmac2_set_bfsize(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				int bfsize, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 value;
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  	value = u32_replace_bits(value, bfsize, XGMAC_RBSZ);
> -	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_RX_CONTROL(addrs, chan));
>  }
>  
>  static void dwxgmac2_enable_sph(struct stmmac_priv *priv, void __iomem *ioaddr,
>  				bool en, u32 chan)
>  {
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
>  	u32 value = readl(ioaddr + XGMAC_RX_CONFIG);
>  
>  	value &= ~XGMAC_CONFIG_HDSMS;
>  	value |= XGMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */
>  	writel(value, ioaddr + XGMAC_RX_CONFIG);
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(chan));
> +	value = readl(ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
>  	if (en)
>  		value |= XGMAC_SPH;
>  	else
>  		value &= ~XGMAC_SPH;
> -	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_CONTROL(addrs, chan));
>  }
>  
>  static int dwxgmac2_enable_tbs(struct stmmac_priv *priv, void __iomem *ioaddr,
>  			       bool en, u32 chan)
>  {
> -	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	const struct dwxgmac_addrs *addrs = priv->plat->dwxgmac_addrs;
> +	u32 value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  
>  	if (en)
>  		value |= XGMAC_EDSE;
>  	else
>  		value &= ~XGMAC_EDSE;
>  
> -	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan));
> +	writel(value, ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan));
>  
> -	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(chan)) & XGMAC_EDSE;
> +	value = readl(ioaddr + XGMAC_DMA_CH_TX_CONTROL(addrs, chan)) & XGMAC_EDSE;
>  	if (en && !value)
>  		return -EIO;
>  
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
> index 265671170bf6e3856263fdcf99afbf3eac79a211..fdae241e5cf49a8d7a15aadb67d40700ab5b4429 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
> @@ -368,8 +368,11 @@ int stmmac_hwif_init(struct stmmac_priv *priv)
>  	mac->vlan = mac->vlan ? : entry->vlan;
>  
>  	priv->hw = mac;
> +	mac->dwxgmac_addrs = priv->plat->dwxgmac_addrs;
>  	priv->fpe_cfg.reg = entry->regs.fpe_reg;
> -	priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off;
> +	priv->ptpaddr = priv->ioaddr +
> +		(priv->plat->dwxgmac_addrs ?
> +		 priv->plat->dwxgmac_addrs->timestamp_base : entry->regs.ptp_off);
>  	priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off;
>  	memcpy(&priv->ptp_clock_ops, entry->ptp,
>  	       sizeof(struct ptp_clock_info));
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> index 1cf0f8820b337a0d7a9aa23c7d9b34e3f5616dad..82ce81fb6a18b66f2028a5a7784f0a3b9317b9bc 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
> @@ -351,8 +351,9 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
>  {
>  	struct stmmac_priv *priv = netdev_priv(dev);
>  
> -	if (priv->plat->core_type == DWMAC_CORE_XGMAC)
> -		return XGMAC_REGSIZE * 4;
> +	if (priv->plat->core_type == DWMAC_CORE_XGMAC ||
> +	    priv->plat->core_type == DWMAC_CORE_25GMAC)

I guess the DWMAC_CORE_25GMAC is never defined, in fact I have the following
compilation error:

drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c:355:38: error: ‘DWMAC_CORE_25GMAC’ undeclared (first use in this function); did you mean ‘DWMAC_CORE_XGMAC’?


> +		return XGMAC_REGSIZE(priv->plat->dwxgmac_addrs) * 4;
>  	else if (priv->plat->core_type == DWMAC_CORE_GMAC4)
>  		return GMAC4_REG_SPACE_SIZE;
>  	return REG_SPACE_SIZE;
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
> index c889204a7aa5d2e74f7834ed1a22252e6c51ca36..1190b8854132915905773796f07503a9bf1446a0 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
> @@ -265,9 +265,12 @@ int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
>  	if (!num_tc) {
>  		/* Restore default TC:Queue mapping */
>  		for (u32 i = 0; i < priv->plat->tx_queues_to_use; i++) {
> -			val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
> +			val = readl(priv->ioaddr +
> +				    XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs,
> +							 i));
>  			writel(u32_replace_bits(val, i, XGMAC_Q2TCMAP),
> -			       priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(i));
> +			       priv->ioaddr +
> +			       XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs, i));
>  		}
>  	}
>  
> @@ -288,9 +291,13 @@ int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
>  			preemptible_txqs |= GENMASK(offset + count - 1, offset);
>  
>  		for (u32 i = 0; i < count; i++) {
> -			val = readl(priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
> +			val = readl(priv->ioaddr +
> +				    XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs,
> +							 offset + i));
>  			writel(u32_replace_bits(val, tc, XGMAC_Q2TCMAP),
> -			       priv->ioaddr + XGMAC_MTL_TXQ_OPMODE(offset + i));
> +			       priv->ioaddr +
> +			       XGMAC_MTL_TXQ_OPMODE(priv->plat->dwxgmac_addrs,
> +						    offset + i));
>  		}
>  	}
>  
> diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
> index 00be2df63d2206a5865bd29333f2f3ba3442962a..5bb904030ef99ac91f66fabaa6c2159da1ec8811 100644
> --- a/include/linux/stmmac.h
> +++ b/include/linux/stmmac.h
> @@ -188,6 +188,16 @@ struct dwmac4_addrs {
>  	u32 mtl_low_cred_offset;
>  };
>  
> +/* Address layout for XGMAC MTL, DMA, and timestamp registers */
> +struct dwxgmac_addrs {
> +	u32 dma_even_chan_base;
> +	u32 dma_odd_chan_base;
> +	u32 dma_chan_offset;
> +	u32 mtl_chan_base;
> +	u32 mtl_chan_offset;
> +	u32 timestamp_base;
> +};
> +
>  enum dwmac_core_type {
>  	DWMAC_CORE_MAC100,
>  	DWMAC_CORE_GMAC,
> @@ -358,6 +368,7 @@ struct plat_stmmacenet_data {
>  	int msi_rx_base_vec;
>  	int msi_tx_base_vec;
>  	const struct dwmac4_addrs *dwmac4_addrs;
> +	const struct dwxgmac_addrs *dwxgmac_addrs;

nit: what about union here?

>  	unsigned int flags;
>  	struct stmmac_dma_cfg __dma_cfg;
>  };
> 
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support
  2026-09-23  1:07 ` [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
@ 2026-09-25 13:02   ` Lorenzo Bianconi
  1 sibling, 0 replies; 38+ messages in thread
From: Lorenzo Bianconi @ 2026-09-25 13:02 UTC (permalink / raw)
  To: Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

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

> Qualcomm Nord provides two ETHQOS controllers based on the Synopsys
> DesignWare 25GMAC IP.
> 
> The Nord integration uses platform-specific MTL queue, DMA channel and
> timestamp register addresses. It also requires wrapper programming for
> USXGMII operation and an EEE clock vote for PCS link-up.
> 
> Add the Nord platform data, select the DW25GMAC core, describe its
> register layout and configure the ETHQOS wrapper for USXGMII. Also add
> the platform-specific loopback control needed while the MAC is being
> initialized.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

Hi Mohd,

some nits inline.

Regards,
Lorenzo

> ---
>  .../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c    | 142 ++++++++++++++++++++-
>  1 file changed, 137 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> index a99a78880c0fb7858e90b6212b37ebfc7fccaf84..a03c8e203920a70238deff9f1f970d29d1293893 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> @@ -23,8 +23,14 @@
>  #define RGMII_IO_MACRO_CONFIG2		0x1C
>  #define RGMII_IO_MACRO_DEBUG1		0x20
>  #define EMAC_SYSTEM_LOW_POWER_DEBUG	0x28
> +#define RGMII_IO_MACRO_SCRATCH_2	0x44
>  #define EMAC_WRAPPER_SGMII_PHY_CNTRL1	0xf4
>  
> +#define RGMII_IO_MACRO_BYPASS			0x16C
> +#define EMAC_WRAPPER_SGMII_PHY_CNTRL0		0x170
> +#define EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4	0x174
> +#define EMAC_WRAPPER_USXGMII_MUX_SEL		0x1D0
> +
>  /* RGMII_IO_MACRO_CONFIG fields */
>  #define RGMII_CONFIG_FUNC_CLK_EN		BIT(30)
>  #define RGMII_CONFIG_POS_NEG_DATA_SEL		BIT(23)
> @@ -77,6 +83,21 @@
>  #define RGMII_CONFIG2_RX_PROG_SWAP		BIT(7)
>  #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL	BIT(6)
>  #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN	BIT(5)
> +#define RGMII_CONFIG2_MODE_EN_VIA_GMII		BIT(21)
> +
> +/* EMAC_WRAPPER_SGMII_PHY_CNTRL0 fields */
> +#define SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL	GENMASK(6, 5)
> +
> +/* EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4 fields */
> +#define SGMII_PHY_CNTRL1_USXGMII_GMII_MASTER_CLK_MUX_SEL	BIT(4)
> +#define SGMII_PHY_CNTRL1_RGMII_SGMII_CLK_MUX_SEL		BIT(0)
> +
> +/* RGMII_IO_MACRO_BYPASS fields */
> +#define RGMII_BYPASS_EN				BIT(0)
> +
> +/* EMAC_WRAPPER_USXGMII_MUX_SEL fields */
> +#define USXGMII_CLK_BLK_GMII_CLK_BLK_SEL	BIT(1)
> +#define USXGMII_CLK_BLK_CLK_EN			BIT(0)
>  
>  /* EMAC_WRAPPER_SGMII_PHY_CNTRL1 bits */
>  #define SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN	BIT(3)
> @@ -88,6 +109,8 @@ struct ethqos_emac_por {
>  	unsigned int value;
>  };
>  
> +struct qcom_ethqos;
> +
>  struct ethqos_emac_driver_data {
>  	const struct ethqos_emac_por *rgmii_por;
>  	unsigned int num_rgmii_por;
> @@ -97,12 +120,16 @@ struct ethqos_emac_driver_data {
>  	const char *link_clk_name;
>  	struct dwmac4_addrs dwmac4_addrs;
>  	bool needs_sgmii_loopback;
> +	struct dwxgmac_addrs dwxgmac_addrs;
> +	enum dwmac_core_type core_type;
> +	void (*set_sgmii_loopback)(struct qcom_ethqos *ethqos, bool enable);

I guess introducing this function pointer you can drop needs_sgmii_loopback
field since you always check set_sgmii_loopback is not NULL, right?

>  };
>  
>  struct qcom_ethqos {
>  	struct platform_device *pdev;
>  	void __iomem *rgmii_base;
>  	struct clk *link_clk;
> +	struct clk *eee_clk;
>  	struct phy *serdes_phy;
>  	phy_interface_t phy_mode;
>  
> @@ -111,6 +138,7 @@ struct qcom_ethqos {
>  	bool rgmii_config_loopback_en;
>  	bool has_emac_ge_3;
>  	bool needs_sgmii_loopback;
> +	void (*set_sgmii_loopback)(struct qcom_ethqos *ethqos, bool enable);
>  };
>  
>  static u32 rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset)
> @@ -201,6 +229,15 @@ qcom_ethqos_set_sgmii_loopback(struct qcom_ethqos *ethqos, bool enable)
>  		      EMAC_WRAPPER_SGMII_PHY_CNTRL1);
>  }
>  
> +static void
> +qcom_ethqos_set_sgmii_loopback_nord(struct qcom_ethqos *ethqos, bool enable)
> +{
> +	rgmii_updatel(ethqos,
> +		      SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN,
> +		      enable ? SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN : 0,
> +		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
> +}
> +
>  static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos)
>  {
>  	rgmii_setmask(ethqos, RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG);
> @@ -220,6 +257,7 @@ static const struct ethqos_emac_driver_data emac_v2_3_0_data = {
>  	.num_rgmii_por = ARRAY_SIZE(emac_v2_3_0_por),
>  	.rgmii_config_loopback_en = true,
>  	.has_emac_ge_3 = false,
> +	.core_type = DWMAC_CORE_GMAC4,
>  };
>  
>  static const struct ethqos_emac_por emac_v2_1_0_por[] = {
> @@ -236,6 +274,7 @@ static const struct ethqos_emac_driver_data emac_v2_1_0_data = {
>  	.num_rgmii_por = ARRAY_SIZE(emac_v2_1_0_por),
>  	.rgmii_config_loopback_en = false,
>  	.has_emac_ge_3 = false,
> +	.core_type = DWMAC_CORE_GMAC4,
>  };
>  
>  static const struct ethqos_emac_por emac_v3_0_0_por[] = {
> @@ -252,6 +291,7 @@ static const struct ethqos_emac_driver_data emac_v3_0_0_data = {
>  	.num_rgmii_por = ARRAY_SIZE(emac_v3_0_0_por),
>  	.rgmii_config_loopback_en = false,
>  	.has_emac_ge_3 = true,
> +	.core_type = DWMAC_CORE_GMAC4,
>  	.dwmac4_addrs = {
>  		.dma_chan = 0x00008100,
>  		.dma_chan_offset = 0x1000,
> @@ -286,6 +326,8 @@ static const struct ethqos_emac_driver_data emac_v4_0_0_data = {
>  	.has_emac_ge_3 = true,
>  	.link_clk_name = "phyaux",
>  	.needs_sgmii_loopback = true,
> +	.core_type = DWMAC_CORE_GMAC4,
> +	.set_sgmii_loopback = qcom_ethqos_set_sgmii_loopback,
>  	.dma_addr_width = 36,
>  	.dwmac4_addrs = {
>  		.dma_chan = 0x00008100,
> @@ -485,6 +527,47 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed)
>  	return 0;
>  }
>  
> +static void ethqos_configure_usxgmii(struct qcom_ethqos *ethqos)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ethqos->num_rgmii_por; i++)
> +		rgmii_writel(ethqos, ethqos->rgmii_por[i].value,
> +			     ethqos->rgmii_por[i].offset);
> +
> +	ethqos_set_func_clk_en(ethqos);
> +
> +	rgmii_updatel(ethqos, RGMII_BYPASS_EN, RGMII_BYPASS_EN,
> +		      RGMII_IO_MACRO_BYPASS);
> +	rgmii_updatel(ethqos, RGMII_CONFIG2_MODE_EN_VIA_GMII, 0,
> +		      RGMII_IO_MACRO_CONFIG2);
> +	rgmii_updatel(ethqos, SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL, BIT(5),
> +		      EMAC_WRAPPER_SGMII_PHY_CNTRL0);
> +	rgmii_updatel(ethqos, SGMII_PHY_CNTRL1_RGMII_SGMII_CLK_MUX_SEL, 0,
> +		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
> +	rgmii_updatel(ethqos, SGMII_PHY_CNTRL1_USXGMII_GMII_MASTER_CLK_MUX_SEL,
> +		      SGMII_PHY_CNTRL1_USXGMII_GMII_MASTER_CLK_MUX_SEL,
> +		      EMAC_WRAPPER_SGMII_PHY_CNTRL1_V4);
> +
> +	rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL, 0,
> +		      EMAC_WRAPPER_USXGMII_MUX_SEL);
> +	rgmii_updatel(ethqos, USXGMII_CLK_BLK_CLK_EN, 0,
> +		      EMAC_WRAPPER_USXGMII_MUX_SEL);
> +
> +	rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
> +		      USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
> +		      EMAC_WRAPPER_USXGMII_MUX_SEL);
> +}
> +
> +static void
> +ethqos_fix_mac_speed_usxgmii(void *bsp_priv, phy_interface_t interface,
> +			     int speed, unsigned int mode)
> +{
> +	struct qcom_ethqos *ethqos = bsp_priv;
> +
> +	ethqos_configure_usxgmii(ethqos);

I guess you can just open-code ethqos_configure_usxgmii() here.

> +}
> +
>  static void ethqos_fix_mac_speed_rgmii(void *bsp_priv,
>  				       phy_interface_t interface, int speed,
>  				       unsigned int mode)
> @@ -625,7 +708,8 @@ static int ethqos_mac_finish_serdes(struct net_device *ndev, void *priv,
>  	struct qcom_ethqos *ethqos = priv;
>  	int ret = 0;
>  
> -	qcom_ethqos_set_sgmii_loopback(ethqos, false);
> +	if (ethqos->set_sgmii_loopback)
> +		ethqos->set_sgmii_loopback(ethqos, false);
>  
>  	if (interface == PHY_INTERFACE_MODE_SGMII ||
>  	    interface == PHY_INTERFACE_MODE_2500BASEX)
> @@ -647,14 +731,24 @@ static int ethqos_clks_config(void *priv, bool enabled)
>  			return ret;
>  		}
>  
> +		/* PCS link-up depends on the EEE clock due to a hardware quirk. */
> +		ret = clk_prepare_enable(ethqos->eee_clk);
> +		if (ret) {
> +			dev_err(&ethqos->pdev->dev, "eee_clk enable failed\n");
> +			clk_disable_unprepare(ethqos->link_clk);
> +			return ret;
> +		}
> +
>  		/* Enable functional clock to prevent DMA reset to timeout due
>  		 * to lacking PHY clock after the hardware block has been power
>  		 * cycled. The actual configuration will be adjusted once
>  		 * ethqos' fix_mac_speed() method is invoked.
>  		 */
> -		qcom_ethqos_set_sgmii_loopback(ethqos, true);
> +		if (ethqos->set_sgmii_loopback)
> +			ethqos->set_sgmii_loopback(ethqos, true);

I guess you should move this above the comment.

>  		ethqos_set_func_clk_en(ethqos);
>  	} else {
> +		clk_disable_unprepare(ethqos->eee_clk);
>  		clk_disable_unprepare(ethqos->link_clk);
>  	}
>  
> @@ -738,6 +832,10 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  		plat_dat->fix_mac_speed = ethqos_fix_mac_speed_sgmii;
>  		plat_dat->mac_finish = ethqos_mac_finish_serdes;
>  		break;
> +	case PHY_INTERFACE_MODE_USXGMII:
> +		plat_dat->fix_mac_speed = ethqos_fix_mac_speed_usxgmii;
> +		plat_dat->mac_finish = ethqos_mac_finish_serdes;
> +		break;
>  	default:
>  		dev_err(dev, "Unsupported phy mode %s\n",
>  			phy_modes(ethqos->phy_mode));
> @@ -756,12 +854,18 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  	ethqos->rgmii_config_loopback_en = data->rgmii_config_loopback_en;
>  	ethqos->has_emac_ge_3 = data->has_emac_ge_3;
>  	ethqos->needs_sgmii_loopback = data->needs_sgmii_loopback;
> +	ethqos->set_sgmii_loopback = data->set_sgmii_loopback;
>  
>  	ethqos->link_clk = devm_clk_get(dev, data->link_clk_name ?: "rgmii");
>  	if (IS_ERR(ethqos->link_clk))
>  		return dev_err_probe(dev, PTR_ERR(ethqos->link_clk),
>  				     "Failed to get link_clk\n");
>  
> +	ethqos->eee_clk = devm_clk_get_optional(dev, "eee");
> +	if (IS_ERR(ethqos->eee_clk))
> +		return dev_err_probe(dev, PTR_ERR(ethqos->eee_clk),
> +				     "Failed to get eee_clk\n");
> +
>  	ret = ethqos_clks_config(ethqos, true);
>  	if (ret)
>  		return ret;
> @@ -778,7 +882,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  	ethqos_set_clk_tx_rate(ethqos, NULL, plat_dat->phy_interface,
>  			       SPEED_1000);
>  
> -	qcom_ethqos_set_sgmii_loopback(ethqos, true);
> +	if (ethqos->set_sgmii_loopback)
> +		ethqos->set_sgmii_loopback(ethqos, true);
>  	ethqos_set_func_clk_en(ethqos);
>  
>  	/* The clocks are controlled by firmware, so we don't know for certain
> @@ -791,9 +896,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  	plat_dat->set_clk_tx_rate = ethqos_set_clk_tx_rate;
>  	plat_dat->dump_debug_regs = rgmii_dump;
>  	plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config;
> -	plat_dat->core_type = DWMAC_CORE_GMAC4;
> +	plat_dat->core_type = data->core_type;
>  	if (ethqos->has_emac_ge_3)
>  		plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
> +	if (data->dwxgmac_addrs.dma_even_chan_base)

it seems a bit odd to check dma_even_chan_base is set. Maybe it is better to
check core_type is DWMAC_CORE_25GMAC?

> +		plat_dat->dwxgmac_addrs = &data->dwxgmac_addrs;
>  	plat_dat->pmt = true;
>  	if (of_property_read_bool(np, "snps,tso"))
>  		plat_dat->flags |= STMMAC_FLAG_TSO_EN;
> @@ -817,8 +924,33 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
>  	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
>  }
>  
> +static const struct ethqos_emac_por emac_nord_por[] = {
> +	{ .offset = RGMII_IO_MACRO_CONFIG,    .value = 0x00C04D03 },
> +	{ .offset = SDCC_HC_REG_DLL_CONFIG,   .value = 0x2004642C },
> +	{ .offset = RGMII_IO_MACRO_CONFIG2,   .value = 0x00222060 },
> +	{ .offset = RGMII_IO_MACRO_SCRATCH_2, .value = 0x4c },
> +};
> +
> +static const struct ethqos_emac_driver_data emac_nord_data = {
> +	.rgmii_por = emac_nord_por,
> +	.num_rgmii_por = ARRAY_SIZE(emac_nord_por),
> +	.dma_addr_width = 40,
> +	.link_clk_name = "phyaux",
> +	.core_type = DWMAC_CORE_25GMAC,
> +	.set_sgmii_loopback = qcom_ethqos_set_sgmii_loopback_nord,
> +	.dwxgmac_addrs = {
> +		.dma_even_chan_base = 0x00008500,
> +		.dma_odd_chan_base  = 0x00008580,
> +		.dma_chan_offset    = 0x00001000,
> +		.mtl_chan_base      = 0x00008000,
> +		.mtl_chan_offset    = 0x00001000,
> +		.timestamp_base     = 0x00007000,
> +	},
> +};

I would move emac_nord_por and emac_nord_data definitions close to the other
ones. I guess the code is more readable.

Regards,
Lorenzo

> +
>  static const struct of_device_id qcom_ethqos_match[] = {
> -	{ .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data},
> +	{ .compatible = "qcom,nord-ethqos",    .data = &emac_nord_data },
> +	{ .compatible = "qcom,qcs404-ethqos",  .data = &emac_v2_3_0_data },
>  	{ .compatible = "qcom,sa8775p-ethqos", .data = &emac_v4_0_0_data},
>  	{ .compatible = "qcom,sc8280xp-ethqos", .data = &emac_v3_0_0_data},
>  	{ .compatible = "qcom,sm8150-ethqos", .data = &emac_v2_1_0_data},
> 
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing
  2026-09-23  8:50 ` [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Zhangfei Gao
  2026-09-23 15:15   ` Andrew Lunn
@ 2026-09-28 10:21   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 38+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-28 10:21 UTC (permalink / raw)
  To: Zhangfei Gao, Mohd Ayaan Anwar
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Serge Semin, Andrew Lunn, Heiner Kallweit, Russell King,
	Richard Cochran, Bjorn Andersson, Konrad Dybcio, Alexandre Torgue,
	Giuseppe Cavallaro, Jose Abreu, Maxime Chevallier,
	Maxime Coquelin, netdev, devicetree, linux-kernel, linux-arm-msm,
	linux-stm32, linux-arm-kernel, Lorenzo Bianconi, Shawn Guo,
	Jitendra Vegiraju

On 23/09/2026 10:50, Zhangfei Gao wrote:
>>
>> Best regards,
>> --
>> Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
>>
> 
> Good Job, Mohd
> 
> Tested-by: Zhangfei Gao <zhangfei.gao@oss.qualcomm.com>

Again blanket tag, not real one. If you tested EVERYTHING, then explain
me how did you execute bindings code on the target?

I expect fake parts of the testing won't be picked up.


Best regards,
Krzysztof

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

* Re: [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS
  2026-09-23  1:07 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
  2026-09-24  1:09   ` sashiko-bot
@ 2026-09-28 15:15   ` Maxime Chevallier
  1 sibling, 0 replies; 38+ messages in thread
From: Maxime Chevallier @ 2026-09-28 15:15 UTC (permalink / raw)
  To: Mohd Ayaan Anwar, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Serge Semin, Andrew Lunn, Heiner Kallweit,
	Russell King, Richard Cochran, Bjorn Andersson, Konrad Dybcio,
	Alexandre Torgue, Giuseppe Cavallaro, Jose Abreu, Maxime Coquelin
  Cc: netdev, devicetree, linux-kernel, linux-arm-msm, linux-stm32,
	linux-arm-kernel, Lorenzo Bianconi, Shawn Guo, Zhangfei Gao,
	Jitendra Vegiraju

Hi Ayaan,

On 9/23/26 03:07, Mohd Ayaan Anwar wrote:
> Select the XPCS instance initialized by stmmac when firmware provides
> a pcs-handle. Reject interfaces that are not supported by the selected
> PCS.
> 
> Signed-off-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>
> ---
>  .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c  | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> index ac7d6d3e205a1ab5b391def879d6f1033a0961b6..a99a78880c0fb7858e90b6212b37ebfc7fccaf84 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
> @@ -7,6 +7,8 @@
>  #include <linux/platform_device.h>
>  #include <linux/phy.h>
>  #include <linux/phy/phy.h>
> +#include <linux/pcs/pcs-xpcs.h>
> +#include <linux/property.h>
>  
>  #include "stmmac.h"
>  #include "stmmac_platform.h"
> @@ -681,6 +683,21 @@ static void ethqos_ptp_clk_freq_config(struct stmmac_priv *priv)
>  	netdev_dbg(priv->dev, "PTP rate %lu\n", plat_dat->clk_ptp_rate);
>  }
>  
> +static struct phylink_pcs *
> +qcom_ethqos_select_pcs(struct stmmac_priv *priv, phy_interface_t interface)
> +{
> +	struct phylink_pcs *pcs;
> +
> +	if (!priv->hw->xpcs)
> +		return ERR_PTR(-ENODEV);

If there's no device (i.e. no PCS), then you should return NULL.

> +
> +	pcs = xpcs_to_phylink_pcs(priv->hw->xpcs);
> +	if (!test_bit(interface, pcs->supported_interfaces))
> +		return ERR_PTR(-EOPNOTSUPP);

phylink already checks if the interface is in pcs->supported_interfaces,
no need to do it here :)

Thanks,

Maxime

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

end of thread, other threads:[~2026-09-28 15:15 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23  1:07 [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Mohd Ayaan Anwar
2026-09-23  1:07 ` [PATCH RFC net-next 1/9] dt-bindings: net: pcs: add Qualcomm Nord XPCS Mohd Ayaan Anwar
2026-09-23  1:07 ` [PATCH RFC net-next 2/9] net: pcs: xpcs: add USXGMII Clause 37 autoneg support Mohd Ayaan Anwar
2026-09-23 13:31   ` Mohd Ayaan Anwar
2026-09-24  1:09   ` sashiko-bot
2026-09-23  1:07 ` [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors Mohd Ayaan Anwar
2026-09-23 12:18   ` Andrew Lunn
2026-09-23 12:37     ` Mohd Ayaan Anwar
2026-09-25 10:18   ` Lorenzo Bianconi
2026-09-23  1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
2026-09-23 12:07   ` Andrew Lunn
2026-09-23 12:57     ` Mohd Ayaan Anwar
2026-09-24  1:09   ` sashiko-bot
2026-09-25 10:37   ` Lorenzo Bianconi
2026-09-23  1:07 ` [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended Mohd Ayaan Anwar
2026-09-25 11:03   ` Lorenzo Bianconi
2026-09-23  1:07 ` [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord Mohd Ayaan Anwar
2026-09-24  1:09   ` sashiko-bot
2026-09-23  1:07 ` [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts Mohd Ayaan Anwar
2026-09-24  1:09   ` sashiko-bot
2026-09-25 12:22   ` Lorenzo Bianconi
2026-09-23  1:07 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
2026-09-24  1:09   ` sashiko-bot
2026-09-28 15:15   ` Maxime Chevallier
2026-09-23  1:07 ` [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support Mohd Ayaan Anwar
2026-09-24  1:09   ` sashiko-bot
2026-09-25 13:02   ` Lorenzo Bianconi
2026-09-23  8:50 ` [PATCH RFC net-next 0/9] net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing Zhangfei Gao
2026-09-23 15:15   ` Andrew Lunn
2026-09-28 10:21   ` Krzysztof Kozlowski
2026-09-23  9:41 ` Maxime Chevallier
2026-09-23 10:43   ` Mohd Ayaan Anwar
2026-09-23 13:17     ` Coia Prant
2026-09-23 14:03       ` Mohd Ayaan Anwar
2026-09-24  5:54         ` Coia Prant
2026-09-23 18:35       ` Andrew Lunn
2026-09-24  5:25         ` Coia Prant
2026-09-23 18:40       ` Andrew Lunn

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