* [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
` (11 more replies)
0 siblings, 12 replies; 30+ 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] 30+ 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
` (10 subsequent siblings)
11 siblings, 0 replies; 30+ 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 [flat|nested] 30+ 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-23 1:07 ` [PATCH RFC net-next 3/9] net: pcs: xpcs: add custom platform register accessors Mohd Ayaan Anwar
` (9 subsequent siblings)
11 siblings, 1 reply; 30+ 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 [flat|nested] 30+ 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-23 1:07 ` [PATCH RFC net-next 4/9] net: pcs: xpcs: add Qualcomm Nord platform support Mohd Ayaan Anwar
` (8 subsequent siblings)
11 siblings, 1 reply; 30+ 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 [flat|nested] 30+ 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
2026-09-23 1:07 ` [PATCH RFC net-next 5/9] net: pcs: xpcs: initialize runtime PM as suspended Mohd Ayaan Anwar
` (7 subsequent siblings)
11 siblings, 1 reply; 30+ 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 [flat|nested] 30+ 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-23 1:07 ` [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord Mohd Ayaan Anwar
` (6 subsequent siblings)
11 siblings, 0 replies; 30+ 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 [flat|nested] 30+ 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-23 1:07 ` [PATCH RFC net-next 7/9] net: stmmac: support custom XGMAC register layouts Mohd Ayaan Anwar
` (5 subsequent siblings)
11 siblings, 0 replies; 30+ 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 [flat|nested] 30+ 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-23 1:07 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
` (4 subsequent siblings)
11 siblings, 0 replies; 30+ 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 [flat|nested] 30+ 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-23 1:07 ` [PATCH RFC net-next 9/9] net: stmmac: qcom-ethqos: add Qualcomm Nord support Mohd Ayaan Anwar
` (3 subsequent siblings)
11 siblings, 0 replies; 30+ 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 [flat|nested] 30+ 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-23 8:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
` (2 subsequent siblings)
11 siblings, 0 replies; 30+ 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(ðqos->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 [flat|nested] 30+ messages in thread
* [PATCH 0/3] Nord ethernet followup
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:49 ` Zhangfei Gao
2026-09-23 8:49 ` [PATCH 1/3] net: stmmac: support low-speed USXGMII validation Zhangfei Gao
` (3 more replies)
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
11 siblings, 4 replies; 30+ messages in thread
From: Zhangfei Gao @ 2026-09-23 8:49 UTC (permalink / raw)
To: shengchao.guo, bartosz.golaszewski, mohd.anwar
Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel, Zhangfei Gao
This series verifies Mohd Ayaan Anwar's patch set:
net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing [1]
Tested on both IQ10 RRD and Ride
The full test branch is available at:
https://github.com/zhangfei-gao/kernel-topics/tree/next-9.23
[1] https://lore.kernel.org/linux-arm-msm/?q=qcom_xpcs_nord_emac
Zhangfei Gao (3):
net: stmmac: support low-speed USXGMII validation
net: stmmac: qcom-ethqos: configure USXGMII rates
net: stmmac: fix 10/100 support and MDIO for DW25GMAC
.../stmicro/stmmac/dwmac-qcom-ethqos.c | 65 ++++++++++++++++++-
.../ethernet/stmicro/stmmac/dwxgmac2_core.c | 6 +-
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +
.../net/ethernet/stmicro/stmmac/stmmac_mdio.c | 9 ++-
drivers/net/pcs/pcs-xpcs.c | 9 ++-
5 files changed, 82 insertions(+), 9 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 1/3] net: stmmac: support low-speed USXGMII validation
2026-09-23 8:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
@ 2026-09-23 8:49 ` Zhangfei Gao
2026-09-23 12:58 ` Andrew Lunn
2026-09-23 13:09 ` Andrew Lunn
2026-09-23 8:49 ` [PATCH 2/3] net: stmmac: qcom-ethqos: configure USXGMII rates Zhangfei Gao
` (2 subsequent siblings)
3 siblings, 2 replies; 30+ messages in thread
From: Zhangfei Gao @ 2026-09-23 8:49 UTC (permalink / raw)
To: shengchao.guo, bartosz.golaszewski, mohd.anwar
Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel, Zhangfei Gao
USXGMII transports the negotiated copper media rate over a fixed-rate
serial link. The PCS and MAC must retain the corresponding
10/100/1000/2500/5000/10000M full-duplex capabilities.
Advertise the media-rate link modes from the XPCS and allow the stmmac
MAC to validate 10M and 100M USXGMII links. This keeps phylink from
rejecting an AQR113C PHY whose advertisement contains base-T modes.
The XPCS also consumes the PHY-generated Clause 37 in-band link and
speed status, so USXGMII must use in-band signalling.
Signed-off-by: Zhangfei Gao <zhangfei.gao@oss.qualcomm.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 ++
drivers/net/pcs/pcs-xpcs.c | 9 ++++++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 2dc0cb2916daf..5954048a9f7fc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1045,6 +1045,8 @@ static unsigned long stmmac_mac_get_caps(struct phylink_config *config,
priv->hw->link.caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD);
config->mac_capabilities = priv->hw->link.caps;
+ if (interface == PHY_INTERFACE_MODE_USXGMII)
+ config->mac_capabilities |= MAC_10FD | MAC_100FD;
if (priv->plat->max_speed)
phylink_limit_mac_speed(config, priv->plat->max_speed);
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 091c9b57388fa..58ca296fc4420 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -23,6 +23,12 @@ static const int xpcs_usxgmii_features[] = {
ETHTOOL_LINK_MODE_Pause_BIT,
ETHTOOL_LINK_MODE_Asym_Pause_BIT,
ETHTOOL_LINK_MODE_Autoneg_BIT,
+ ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
@@ -737,7 +743,8 @@ 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;
+ /* The PCS consumes the PHY's CL37 in-band link and speed status. */
+ return LINK_INBAND_ENABLE;
default:
return 0;
--
2.43.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 2/3] net: stmmac: qcom-ethqos: configure USXGMII rates
2026-09-23 8:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
2026-09-23 8:49 ` [PATCH 1/3] net: stmmac: support low-speed USXGMII validation Zhangfei Gao
@ 2026-09-23 8:49 ` Zhangfei Gao
2026-09-23 8:49 ` [PATCH 3/3] net: stmmac: fix 10/100 support and MDIO for DW25GMAC Zhangfei Gao
2026-09-23 12:50 ` [PATCH 0/3] Nord ethernet followup Andrew Lunn
3 siblings, 0 replies; 30+ messages in thread
From: Zhangfei Gao @ 2026-09-23 8:49 UTC (permalink / raw)
To: shengchao.guo, bartosz.golaszewski, mohd.anwar
Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel, Zhangfei Gao
Program the Qualcomm EMAC wrapper for the negotiated USXGMII media
rate. The serial SerDes lane remains at the USXGMII rate, while the
wrapper clock and IO macro settings follow the
10/100/1000/2500/5000/10000M MAC rate.
Without the low-speed settings, a 100M link is reported by the PHY but
the wrapper rejects it as an unsupported USXGMII speed.
USXGMII also defaults to phylink in-band mode because the QCOM host
requires the PHY-generated in-band link status.
Signed-off-by: Zhangfei Gao <zhangfei.gao@oss.qualcomm.com>
---
.../stmicro/stmmac/dwmac-qcom-ethqos.c | 65 ++++++++++++++++++-
1 file changed, 62 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index 280f9289753da..54a6c98e42057 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -38,6 +38,7 @@
#define RGMII_CONFIG_GPIO_CFG_TX_INT GENMASK(19, 17)
#define RGMII_CONFIG_MAX_SPD_PRG_9 GENMASK(16, 8)
#define RGMII_CONFIG_MAX_SPD_PRG_2 GENMASK(7, 6)
+#define RGMII_CONFIG_MAX_SPD_PRG_2_V4 GENMASK(9, 6)
#define RGMII_CONFIG_INTF_SEL GENMASK(5, 4)
#define RGMII_CONFIG_BYPASS_TX_ID_EN BIT(3)
#define RGMII_CONFIG_LOOPBACK_EN BIT(2)
@@ -84,6 +85,12 @@
#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)
+#define RGMII_CONFIG2_MAX_SPD_PRG_3 GENMASK(20, 17)
+
+/* RGMII_IO_MACRO_SCRATCH_2 fields */
+#define RGMII_SCRATCH2_MAX_SPD_PRG_4 GENMASK(5, 2)
+#define RGMII_SCRATCH2_MAX_SPD_PRG_5 GENMASK(9, 6)
+#define RGMII_SCRATCH2_MAX_SPD_PRG_6 GENMASK(13, 10)
/* EMAC_WRAPPER_SGMII_PHY_CNTRL0 fields */
#define SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL GENMASK(6, 5)
@@ -135,6 +142,7 @@ struct qcom_ethqos {
struct clk *eee_clk;
struct phy *serdes_phy;
phy_interface_t phy_mode;
+ int speed;
const struct ethqos_emac_por *rgmii_por;
unsigned int num_rgmii_por;
@@ -557,9 +565,56 @@ static void ethqos_configure_usxgmii(struct qcom_ethqos *ethqos)
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);
+ switch (ethqos->speed) {
+ case SPEED_10000:
+ rgmii_updatel(ethqos, USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
+ USXGMII_CLK_BLK_GMII_CLK_BLK_SEL,
+ EMAC_WRAPPER_USXGMII_MUX_SEL);
+ break;
+ case SPEED_5000:
+ rgmii_updatel(ethqos, SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL, 0,
+ EMAC_WRAPPER_SGMII_PHY_CNTRL0);
+ rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2_V4,
+ BIT(6) | BIT(7), RGMII_IO_MACRO_CONFIG);
+ rgmii_updatel(ethqos, RGMII_CONFIG2_MAX_SPD_PRG_3,
+ BIT(17) | BIT(18), RGMII_IO_MACRO_CONFIG2);
+ break;
+ case SPEED_2500:
+ rgmii_updatel(ethqos, SGMII_PHY_CNTRL0_2P5G_1G_CLK_SEL, 0,
+ EMAC_WRAPPER_SGMII_PHY_CNTRL0);
+ rgmii_updatel(ethqos, RGMII_CONFIG_SGMII_CLK_DVDR,
+ BIT(10) | BIT(11), RGMII_IO_MACRO_CONFIG);
+ rgmii_updatel(ethqos, RGMII_SCRATCH2_MAX_SPD_PRG_4,
+ BIT(2) | BIT(3), RGMII_IO_MACRO_SCRATCH_2);
+ rgmii_updatel(ethqos, RGMII_SCRATCH2_MAX_SPD_PRG_5, 0,
+ RGMII_IO_MACRO_SCRATCH_2);
+ break;
+ case SPEED_1000:
+ case SPEED_100:
+ rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
+ RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
+ RGMII_IO_MACRO_CONFIG2);
+ if (ethqos->speed == SPEED_100) {
+ rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2_V4,
+ BIT(9), RGMII_IO_MACRO_CONFIG);
+ rgmii_updatel(ethqos, RGMII_CONFIG2_MAX_SPD_PRG_3,
+ BIT(20), RGMII_IO_MACRO_CONFIG2);
+ rgmii_updatel(ethqos, RGMII_SCRATCH2_MAX_SPD_PRG_6,
+ BIT(10), RGMII_IO_MACRO_SCRATCH_2);
+ }
+ break;
+ case SPEED_10:
+ rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
+ RGMII_CONFIG2_RGMII_CLK_SEL_CFG,
+ RGMII_IO_MACRO_CONFIG2);
+ break;
+ default:
+ dev_err(ðqos->pdev->dev,
+ "unsupported USXGMII speed %d\n", ethqos->speed);
+ return;
+ }
+
+ return;
}
static void
@@ -568,6 +623,7 @@ ethqos_fix_mac_speed_usxgmii(void *bsp_priv, phy_interface_t interface,
{
struct qcom_ethqos *ethqos = bsp_priv;
+ ethqos->speed = speed;
ethqos_configure_usxgmii(ethqos);
}
@@ -836,6 +892,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
plat_dat->mac_finish = ethqos_mac_finish_serdes;
break;
case PHY_INTERFACE_MODE_USXGMII:
+ plat_dat->default_an_inband = true;
+ fallthrough;
+ case PHY_INTERFACE_MODE_10GBASER:
plat_dat->fix_mac_speed = ethqos_fix_mac_speed_usxgmii;
plat_dat->mac_finish = ethqos_mac_finish_serdes;
break;
--
2.43.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 3/3] net: stmmac: fix 10/100 support and MDIO for DW25GMAC
2026-09-23 8:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
2026-09-23 8:49 ` [PATCH 1/3] net: stmmac: support low-speed USXGMII validation Zhangfei Gao
2026-09-23 8:49 ` [PATCH 2/3] net: stmmac: qcom-ethqos: configure USXGMII rates Zhangfei Gao
@ 2026-09-23 8:49 ` Zhangfei Gao
2026-09-23 12:50 ` [PATCH 0/3] Nord ethernet followup Andrew Lunn
3 siblings, 0 replies; 30+ messages in thread
From: Zhangfei Gao @ 2026-09-23 8:49 UTC (permalink / raw)
To: shengchao.guo, bartosz.golaszewski, mohd.anwar
Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel, Zhangfei Gao
DW25GMAC currently advertises link modes starting at 1Gbps and does not
provide the MAC speed encodings for 10Mbps and 100Mbps. This leaves the
MAC speed field incorrectly configured when a USXGMII PHY negotiates a
legacy speed.
The MDIO setup also selects the XGMAC clock divider table and MDIO
accessors only for DWMAC_CORE_XGMAC. DW25GMAC uses the same MDIO
interface, so falling back to the generic path can cause PHY register
accesses to time out and prevent the PHY from probing.
Add the missing 10/100 capabilities and speed encodings, and handle
DWMAC_CORE_25GMAC through the XGMAC MDIO paths.
Fixes: 4975cb3b1b66 ("net: stmmac: Add DW25GMAC support in stmmac core driver")
Signed-off-by: Zhangfei Gao <zhangfei.gao@oss.qualcomm.com>
---
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 6 ++++--
drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 9 ++++++---
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index 0b00d880fd305..65221b4becf51 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -1563,9 +1563,11 @@ int dw25gmac_setup(struct stmmac_priv *priv)
dwxgmac2_common_setup(priv, "DW25GMAC");
mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
- MAC_1000FD | MAC_2500FD | MAC_5000FD |
- MAC_10000FD | MAC_25000FD;
+ MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD | MAC_5000FD |
+ MAC_10000FD | MAC_25000FD;
mac->link.duplex = 0;
+ mac->link.speed10 = XGMAC_CONFIG_SS_10_MII;
+ mac->link.speed100 = XGMAC_CONFIG_SS_100_MII;
mac->link.speed1000 = XGMAC_CONFIG_SS_1000_GMII;
mac->link.speed2500 = XGMAC_CONFIG_SS_2500_GMII;
mac->link.xgmii.speed2500 = XGMAC_CONFIG_SS_2500;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index afe98ff5bdcb0..f20a6e056781f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -552,7 +552,8 @@ static u32 stmmac_clk_csr_set(struct stmmac_priv *priv)
rates = stmmac_std_csr_to_mdc;
if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I)
rates = stmmac_sun8i_csr_to_mdc;
- if (priv->plat->core_type == DWMAC_CORE_XGMAC)
+ if (priv->plat->core_type == DWMAC_CORE_XGMAC ||
+ priv->plat->core_type == DWMAC_CORE_25GMAC)
rates = stmmac_xgmac_csr_to_mdc;
for (i = 0; rates[i].rate; i++)
@@ -619,7 +620,8 @@ int stmmac_mdio_register(struct net_device *ndev)
new_bus->name = "stmmac";
- if (priv->plat->core_type == DWMAC_CORE_XGMAC) {
+ if (priv->plat->core_type == DWMAC_CORE_XGMAC ||
+ priv->plat->core_type == DWMAC_CORE_25GMAC) {
new_bus->read = &stmmac_xgmac2_mdio_read_c22;
new_bus->write = &stmmac_xgmac2_mdio_write_c22;
new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45;
@@ -663,7 +665,8 @@ int stmmac_mdio_register(struct net_device *ndev)
}
/* Looks like we need a dummy read for XGMAC only and C45 PHYs */
- if (priv->plat->core_type == DWMAC_CORE_XGMAC)
+ if (priv->plat->core_type == DWMAC_CORE_XGMAC ||
+ priv->plat->core_type == DWMAC_CORE_25GMAC)
stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0);
/* If fixed-link is set, skip PHY scanning */
--
2.43.0
^ permalink raw reply [flat|nested] 30+ 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:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
@ 2026-09-23 8:50 ` Zhangfei Gao
2026-09-23 15:15 ` Andrew Lunn
2026-09-23 9:41 ` Maxime Chevallier
11 siblings, 1 reply; 30+ 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] 30+ 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
` (10 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
11 siblings, 1 reply; 30+ 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
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] 30+ 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; 30+ 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, 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] 30+ 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
0 siblings, 1 reply; 30+ 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] 30+ 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
0 siblings, 1 reply; 30+ 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] 30+ 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; 30+ 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] 30+ messages in thread
* Re: [PATCH 0/3] Nord ethernet followup
2026-09-23 8:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
` (2 preceding siblings ...)
2026-09-23 8:49 ` [PATCH 3/3] net: stmmac: fix 10/100 support and MDIO for DW25GMAC Zhangfei Gao
@ 2026-09-23 12:50 ` Andrew Lunn
3 siblings, 0 replies; 30+ messages in thread
From: Andrew Lunn @ 2026-09-23 12:50 UTC (permalink / raw)
To: Zhangfei Gao
Cc: shengchao.guo, bartosz.golaszewski, mohd.anwar,
maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel
On Wed, Sep 23, 2026 at 04:49:18PM +0800, Zhangfei Gao wrote:
> This series verifies Mohd Ayaan Anwar's patch set:
>
> net: introduce Qualcomm XPCS support and add Nord Ethernet plumbing [1]
>
> Tested on both IQ10 RRD and Ride
>
> The full test branch is available at:
>
> https://github.com/zhangfei-gao/kernel-topics/tree/next-9.23
>
>
> [1] https://lore.kernel.org/linux-arm-msm/?q=qcom_xpcs_nord_emac
Please don't submit two overlapping patches for the same driver. Wait
for the first patchset to get merged, and then submit a follow up
series.
Qualcomm has a number of Mainline Linux mentors. Please talk with
them, because these two patch series are not great.
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 30+ 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; 30+ 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] 30+ messages in thread
* Re: [PATCH 1/3] net: stmmac: support low-speed USXGMII validation
2026-09-23 8:49 ` [PATCH 1/3] net: stmmac: support low-speed USXGMII validation Zhangfei Gao
@ 2026-09-23 12:58 ` Andrew Lunn
2026-09-23 13:09 ` Andrew Lunn
1 sibling, 0 replies; 30+ messages in thread
From: Andrew Lunn @ 2026-09-23 12:58 UTC (permalink / raw)
To: Zhangfei Gao
Cc: shengchao.guo, bartosz.golaszewski, mohd.anwar,
maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel
> diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
> index 091c9b57388fa..58ca296fc4420 100644
> --- a/drivers/net/pcs/pcs-xpcs.c
> +++ b/drivers/net/pcs/pcs-xpcs.c
> @@ -23,6 +23,12 @@ static const int xpcs_usxgmii_features[] = {
> ETHTOOL_LINK_MODE_Pause_BIT,
> ETHTOOL_LINK_MODE_Asym_Pause_BIT,
> ETHTOOL_LINK_MODE_Autoneg_BIT,
> + ETHTOOL_LINK_MODE_10baseT_Full_BIT,
> + ETHTOOL_LINK_MODE_100baseT_Full_BIT,
> + ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
> + ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
> + ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
> + ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
What does T in 10000baseT mean?
> ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
> ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
> ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
Compare and contract with KX.
Andrew
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/3] net: stmmac: support low-speed USXGMII validation
2026-09-23 8:49 ` [PATCH 1/3] net: stmmac: support low-speed USXGMII validation Zhangfei Gao
2026-09-23 12:58 ` Andrew Lunn
@ 2026-09-23 13:09 ` Andrew Lunn
1 sibling, 0 replies; 30+ messages in thread
From: Andrew Lunn @ 2026-09-23 13:09 UTC (permalink / raw)
To: Zhangfei Gao
Cc: shengchao.guo, bartosz.golaszewski, mohd.anwar,
maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
mcoquelin.stm32, alexandre.torgue, hkallweit1, linux, netdev,
linux-stm32, linux-arm-kernel, linux-kernel
> The XPCS also consumes the PHY-generated Clause 37 in-band link and
> speed status, so USXGMII must use in-band signalling.
Is this a qualcomm specific feature, or defined in the databook of the
licensed IP.
> case DW_AN_C37_USXGMII:
> - return LINK_INBAND_DISABLE;
> + /* The PCS consumes the PHY's CL37 in-band link and speed status. */
> + return LINK_INBAND_ENABLE;
I ask, because when i look at this, i immediately think is this a
behaviour change? Is it going to break existing systems? Or was the
old code broken?
The commit message is where you try to guess what reviewers are going
to ask, and answer the question before they ask. Seeing such answers
in the commit message gives me a good idea you have done your due
diligence, and the patch is probably O.K. Without such comments, i
have to assume this is poor quality code and really exam it in detail.
Andrew
^ permalink raw reply [flat|nested] 30+ 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; 30+ 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, 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] 30+ 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
0 siblings, 0 replies; 30+ 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] 30+ 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; 30+ 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, 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] 30+ 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
0 siblings, 0 replies; 30+ 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] 30+ 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; 30+ 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, 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] 30+ 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; 30+ 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, 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] 30+ messages in thread
end of thread, other threads:[~2026-09-23 18:40 UTC | newest]
Thread overview: 30+ 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-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-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-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 ` [PATCH RFC net-next 6/9] dt-bindings: net: qcom,ethqos: add Qualcomm Nord Mohd Ayaan Anwar
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 ` [PATCH RFC net-next 8/9] net: stmmac: qcom-ethqos: support external PCS Mohd Ayaan Anwar
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:49 ` [PATCH 0/3] Nord ethernet followup Zhangfei Gao
2026-09-23 8:49 ` [PATCH 1/3] net: stmmac: support low-speed USXGMII validation Zhangfei Gao
2026-09-23 12:58 ` Andrew Lunn
2026-09-23 13:09 ` Andrew Lunn
2026-09-23 8:49 ` [PATCH 2/3] net: stmmac: qcom-ethqos: configure USXGMII rates Zhangfei Gao
2026-09-23 8:49 ` [PATCH 3/3] net: stmmac: fix 10/100 support and MDIO for DW25GMAC Zhangfei Gao
2026-09-23 12:50 ` [PATCH 0/3] Nord ethernet followup Andrew Lunn
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-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-23 18:35 ` Andrew Lunn
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
all inboxes | Powered by JetHome®