Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564
@ 2026-10-19  3:01 Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 1/5] dt-bindings: net: add support for " Alex Elder
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Alex Elder @ 2026-10-19  3:01 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt
  Cc: mcoquelin.stm32, alexandre.torgue, hkallweit1, linux,
	richardcochran, p.zabel, peppe.cavallaro, joabreu, mohd.anwar,
	lorenzo.bianconi, daniel, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

This series enables the two XGMAC interfaces present in the Toshiba
TC9564 SoC.

The TC9564 SoC connects to a host using the upstream interface of
the PCIe switch it implements.  The PCIe switch has three downstream
ports; two are exposed externally, and one implements an embedded
PCIe endpoint.  That endpoint has two functions, and each of those
has a 10 Gbps capable DesignWare XGMAC interface.

This support was originally submitted earlier this year using a
PCI driver within the stmmac source directory.  This version
instead implements a platform driver, "dwmac-tc9564.c".

					-Alex

Alex Elder (1):
  dt-bindings: net: add support for Toshiba TC9564

Daniel Thompson (4):
  net: pcs: pcs-xpcs-regmap: support XPCS memory-mapped MDIO bus via
    regmap
  net: stmmac: dwxgmac2: Add XGMAC 3.01a support
  net: stmmac: dwxgmac2: export symbols for XGMAC 3.01a DMA
  net: stmmac: support the TC9564 SoC

 .../devicetree/bindings/net/snps,dwmac.yaml   |  26 +-
 .../bindings/net/toshiba,tc9564-xgmac.yaml    | 327 ++++++++++
 MAINTAINERS                                   |  10 +
 drivers/net/ethernet/stmicro/stmmac/Kconfig   |  11 +
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   1 +
 .../ethernet/stmicro/stmmac/dwmac-tc9564.c    | 590 ++++++++++++++++++
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h    |  10 +
 .../ethernet/stmicro/stmmac/dwxgmac2_core.c   |   1 +
 .../ethernet/stmicro/stmmac/dwxgmac2_descs.c  |   1 +
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    |  70 ++-
 drivers/net/pcs/Makefile                      |   3 +-
 drivers/net/pcs/pcs-xpcs-regmap.c             | 169 +++++
 include/linux/pcs/pcs-xpcs-regmap.h           |  13 +
 13 files changed, 1214 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/toshiba,tc9564-xgmac.yaml
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
 create mode 100644 drivers/net/pcs/pcs-xpcs-regmap.c
 create mode 100644 include/linux/pcs/pcs-xpcs-regmap.h


base-commit: 2efb7a11f1aa4d2dc285fe2680cca22cb9f72f64
-- 
2.53.0



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

* [PATCH net-next 1/5] dt-bindings: net: add support for Toshiba TC9564
  2026-10-19  3:01 [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564 Alex Elder
@ 2026-10-19  3:01 ` Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 2/5] net: pcs: pcs-xpcs-regmap: support XPCS memory-mapped MDIO bus via regmap Alex Elder
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Alex Elder @ 2026-10-19  3:01 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt
  Cc: mcoquelin.stm32, alexandre.torgue, hkallweit1, linux,
	richardcochran, p.zabel, peppe.cavallaro, joabreu, mohd.anwar,
	lorenzo.bianconi, daniel, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

The Toshiba TC9564 is an SoC that exposes two XGMAC 10 Gbps Ethernet
interfaces, each of which is attached to an embedded PCIe function.

These XGMAC interfaces have three resets, for the MAC, PMA, and XPCS
layers.  These resets differ from the standard two resets defined
in "snps,dwmac.yaml".

To permit these other resets to be used, modify the way resets are
defined in "snps,dwmac.yaml" to be similar to the way interrupts and
their names are defined earlier in the file.  That is, rather than
adding descriptions with the resets property values, just specify the
maximum number of items.  Then, in the reset-names property, provide
a list of description/constant value pairs, indicating which renames
may be used among the (three) reset items specified.

Signed-off-by: Alex Elder <elder@riscstar.com>
---
 .../devicetree/bindings/net/snps,dwmac.yaml   |  26 +-
 .../bindings/net/toshiba,tc9564-xgmac.yaml    | 327 ++++++++++++++++++
 MAINTAINERS                                   |   7 +
 3 files changed, 351 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/net/toshiba,tc9564-xgmac.yaml

diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
index 2218a492817fd..ace827ee4eb6c 100644
--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
@@ -120,6 +120,7 @@ properties:
         - starfive,jh7110-dwmac
         - tesla,fsd-ethqos
         - thead,th1520-gmac
+        - toshiba,tc9564-xgmac
         - ultrarisc,dp1000-gmac
 
   reg:
@@ -174,17 +175,24 @@ properties:
 
   resets:
     minItems: 1
-    items:
-      - description: GMAC stmmaceth reset
-      - description: AHB or OCP reset
+    maxItems: 3
 
   reset-names:
-    oneOf:
-      - items:
-          - enum: [stmmaceth, ahb]
-      - items:
-          - const: stmmaceth
-          - enum: [ahb, stmmaceth-ocp]
+    maxItems: 3
+    items:
+      - oneOf:
+          - description: GMAC stmmaceth reset
+            const: stmmaceth
+          - description: AHB reset
+            const: ahb
+          - description: MAC reset
+            const: mac-reset
+          - description: PMA (Physical Medium Attachment) reset
+            const: pma-reset
+          - description: XPCS reset
+            const: xpcs-reset
+          - description: OCP reset (deprecated)
+            const: stmmaceth-ocp
 
   power-domains:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/net/toshiba,tc9564-xgmac.yaml b/Documentation/devicetree/bindings/net/toshiba,tc9564-xgmac.yaml
new file mode 100644
index 0000000000000..9c494d216c3a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/toshiba,tc9564-xgmac.yaml
@@ -0,0 +1,327 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/toshiba,tc9564-xgmac.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Toshiba TC9564 XGMAC Ethernet Controller
+
+maintainers:
+  - Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
+  - Alex Elder <elder@riscstar.com>
+  - Daniel Thompson <daniel@riscstar.com>
+
+description:
+  This binding describes the Toshiba TC9564 SoC implementation of the
+  Synopsys XGMAC Ethernet controller.
+
+  The Toshiba TC9564 incorporates a PCIe gen 3 switch with one upstream
+  and three downstream ports.  The first two downstream ports are exposed
+  externally, while the third is used by an internal PCIe endpoint.  The
+  PCIe endpoint implements two PCIe functions, and attached to each of
+  these is a 10 Gbps capable Synopsys XGMAC Ethernet controller.  Access
+  to management registers for each controller is via BAR 4 of its
+  respective PCI function.
+
+allOf:
+  - $ref: snps,dwmac.yaml#
+
+select:
+  properties:
+    compatible:
+      contains:
+        const: toshiba,tc9564-xgmac
+  required:
+    - compatible
+
+properties:
+  compatible:
+    const: toshiba,tc9564-xgmac
+
+  reg:
+    maxItems: 1
+
+  toshiba,config-syscon:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description:
+      The phandle and offset for a syscon that provides access to a
+      register containing a bit that indicates that PMA initialization
+      is done.
+    maxItems: 1
+
+  clocks:
+    minItems: 5
+    items:
+      - description: MAC main clock (125 MHz)
+      - description: PTP reference clock (250 MHz)
+      - description: MAC TX clock
+      - description: MAC RX clock
+      - description: MAC all clock gate
+      - description: MAC RMII clock (function 1 only)
+
+  clock-names:
+    minItems: 5
+    items:
+      - const: stmmaceth
+      - const: ptp_ref
+      - const: mac-tx-clock
+      - const: mac-rx-clock
+      - const: mac-all-clock
+      - const: mac-rmii-clock
+
+  resets:
+    items:
+      - description: MAC reset
+      - description: PMA (Physical Medium Attachment) reset
+      - description: XPCS reset
+
+  reset-names:
+    items:
+      - const: mac-reset
+      - const: pma-reset
+      - const: xpcs-reset
+
+  interrupts:
+    minItems: 17
+    maxItems: 17
+
+  interrupt-names:
+    minItems: 17
+    maxItems: 17
+
+  snps,tso:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Enable TCP segmentation offload.
+
+  snps,pbl:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Set the programmable burst length.
+
+  snps,force_sf_dma_mode:
+    $ref: /schemas/types.yaml#/definitions/flag
+    description:
+      Force store-and-forward mode for both TX and RX DMA.
+
+  snps,perfect-filter-entries:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      Set the number of perfect filter entries supported.
+
+  snps,mtl-rx-config:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to a rx-queues-config node that describes the RX queues
+      managed by the stmmac memory transfer layer.
+
+  snps,mtl-tx-config:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to a tx-queues-config node that describes the TX queues
+      managed by the stmmac memory transfer layer.
+
+  rx-fifo-depth:
+    $ref: /schemas/net/ethernet-controller.yaml#/properties/rx-fifo-depth
+    maximum: 47104
+    description:
+      RX FIFO size in bytes.  This must be set explicitly because
+      the size (46KB) differs from the power-of-2 indicated by the
+      HW_FEATURE0 register, so the size is not accurately detected.
+
+  tx-fifo-depth:
+    $ref: /schemas/net/ethernet-controller.yaml#/properties/tx-fifo-depth
+    maximum: 47104
+    description:
+      TX FIFO size in bytes.  This must be set explicitly because
+      the size (46KB) differs from the power-of-2 indicated by the
+      HW_FEATURE0 register, so the size is not accurately detected.
+
+  snps,axi-config:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      Phandle to a node describing AXI burst configuration.
+
+  iommus:
+    maxItems: 1
+
+  phy-mode:
+    const: sgmii
+
+  phy-handle: true
+
+  tx-queues-config:
+    $ref: /schemas/net/snps,dwmac.yaml#/properties/tx-queues-config
+
+  rx-queues-config:
+    $ref: /schemas/net/snps,dwmac.yaml#/properties/rx-queues-config
+
+  stmmac-axi-config:
+    $ref: /schemas/net/snps,dwmac-common.yaml#/properties/stmmac-axi-config
+
+  mdio:
+    $ref: /schemas/net/snps,dwmac.yaml#/properties/mdio
+
+required:
+  - toshiba,config-syscon
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - rx-fifo-depth
+  - tx-fifo-depth
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    ethernet@48000 {
+        compatible = "toshiba,tc9564-xgmac";
+        reg = <0x48000 0x8000>;
+        toshiba,config-syscon = <&tc9564_config_syscon0 0x1074>;
+
+        clocks = <&tc9564_ref_125mhz_clk>,
+                 <&tc9564_ref_250mhz_clk>,
+                 <&tc9564_clock0 13>,
+                 <&tc9564_clock0 14>,
+                 <&tc9564_clock0 18>,
+                 <&tc9564_clock0 15>;
+        clock-names = "stmmaceth",
+                      "ptp_ref",
+                      "mac-tx-clock",
+                      "mac-rx-clock",
+                      "mac-all-clock",
+                      "mac-rmii-clock";
+
+        resets = <&tc9564_reset0 8>,
+                 <&tc9564_reset0 9>,
+                 <&tc9564_reset0 10>;
+        reset-names = "mac-reset",
+                      "pma-reset",
+                      "xpcs-reset";
+
+        interrupts-extended = <&tc9564_msigen1 2>,
+                              <&tc9564_msigen1 3>,
+                              <&tc9564_msigen1 4>,
+                              <&tc9564_msigen1 5>,
+                              <&tc9564_msigen1 6>,
+                              <&tc9564_msigen1 7>,
+                              <&tc9564_msigen1 8>,
+                              <&tc9564_msigen1 9>,
+                              <&tc9564_msigen1 10>,
+                              <&tc9564_msigen1 11>,
+                              <&tc9564_msigen1 12>,
+                              <&tc9564_msigen1 13>,
+                              <&tc9564_msigen1 14>,
+                              <&tc9564_msigen1 15>,
+                              <&tc9564_msigen1 16>,
+                              <&tc9564_msigen1 17>,
+                              <&tc9564_msigen1 18>;
+        interrupt-names = "macirq",
+                          "tx-queue-0",
+                          "tx-queue-1",
+                          "tx-queue-2",
+                          "tx-queue-3",
+                          "tx-queue-4",
+                          "tx-queue-5",
+                          "tx-queue-6",
+                          "tx-queue-7",
+                          "rx-queue-0",
+                          "rx-queue-1",
+                          "rx-queue-2",
+                          "rx-queue-3",
+                          "rx-queue-4",
+                          "rx-queue-5",
+                          "rx-queue-6",
+                          "rx-queue-7";
+
+        snps,tso;
+        snps,pbl = <32>;
+        snps,force_sf_dma_mode;
+        snps,perfect-filter-entries = <32>;
+
+        snps,mtl-rx-config = <&tc9564_mtl_rx_emac1_setup>;
+        snps,mtl-tx-config = <&tc9564_mtl_tx_emac1_setup>;
+        rx-fifo-depth = <32768>;
+        tx-fifo-depth = <32768>;
+
+        snps,axi-config = <&tc9564_axi_emac1_setup>;
+
+        /* SID comes from the iommu-map for &pcie1 */
+        iommus = <&apps_smmu 0x1c90 0x0>;
+
+        phy-mode = "sgmii";
+        phy-handle = <&tc9564_emac1_phy>;
+
+        tc9564_mtl_rx_emac1_setup: rx-queues-config {
+            snps,rx-queues-to-use = <4>;
+            snps,rx-sched-sp;
+            queue0 {
+                snps,dcb-algorithm;
+                snps,map-to-dma-channel = <0x0>;
+            };
+            queue1 {
+                snps,dcb-algorithm;
+                snps,map-to-dma-channel = <0x1>;
+            };
+            queue2 {
+                snps,dcb-algorithm;
+                snps,map-to-dma-channel = <0x2>;
+            };
+            queue3 {
+                snps,dcb-algorithm;
+                snps,map-to-dma-channel = <0x3>;
+            };
+        };
+
+        tc9564_mtl_tx_emac1_setup: tx-queues-config {
+            snps,tx-queues-to-use = <4>;
+            snps,tx-sched-wrr;
+            queue0 {
+                snps,weight = <0x0c>;
+                snps,dcb-algorithm;
+            };
+            queue1 {
+                snps,weight = <0x0c>;
+                snps,dcb-algorithm;
+            };
+            queue2 {
+                snps,weight = <0x0c>;
+                snps,dcb-algorithm;
+            };
+            queue3 {
+                snps,weight = <0x0c>;
+                snps,dcb-algorithm;
+            };
+        };
+
+        tc9564_axi_emac1_setup: stmmac-axi-config {
+            snps,lpi_en;
+            snps,wr_osr_lmt = <31>;
+            snps,rd_osr_lmt = <31>;
+            snps,blen = <256 128 64 32 16 8 4>;
+        };
+
+        mdio {
+            compatible = "snps,dwmac-mdio";
+
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            tc9564_emac1_phy: ethernet-phy@1c {
+                compatible = "ethernet-phy-id004d.d101";
+                reg = <0x1c>;
+
+                reset-assert-us = <11000>;
+                reset-deassert-us = <70000>;
+
+                vdd18-supply = <&qep_1p8>;
+
+                pinctrl-names = "default";
+                pinctrl-0 = <&qep_irq_pin>;
+                interrupts-extended = <&tlmm 101 IRQ_TYPE_LEVEL_LOW>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 149bc44003bda..55ead3d1007a8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -28305,6 +28305,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/misc/pci1179,0220.yaml
 F:	drivers/misc/tc9564-pci.c
 
+TOSHIBA TC9564 DWMAC ETHERNET DRIVER
+M:	Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
+M:	Alex Elder <elder@kernel.org>
+M:	Daniel Thompson <danielt@kernel.org>
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/toshiba,tc9564-dwmac.yaml
+
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>
 L:	platform-driver-x86@vger.kernel.org
-- 
2.53.0



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

* [PATCH net-next 2/5] net: pcs: pcs-xpcs-regmap: support XPCS memory-mapped MDIO bus via regmap
  2026-10-19  3:01 [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564 Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 1/5] dt-bindings: net: add support for " Alex Elder
@ 2026-10-19  3:01 ` Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 3/5] net: stmmac: dwxgmac2: Add XGMAC 3.01a support Alex Elder
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Alex Elder @ 2026-10-19  3:01 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt
  Cc: Daniel Thompson, mcoquelin.stm32, alexandre.torgue, hkallweit1,
	linux, richardcochran, p.zabel, peppe.cavallaro, joabreu,
	mohd.anwar, lorenzo.bianconi, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

From: Daniel Thompson <daniel@riscstar.com>

In some DesignWare XPCS implementations the memory-mapped MDIO bus is
allocated to a register window that does not align to a page boundary.
This makes iomapping the registers problematic.

For example the Toshiba TC9564 (a PCIe Ethernet-AVB/TSN bridge) provides
an "eMAC" subsystem with the XPCS base address cuddled up to XGMAC
registers.

Let's introduce helpers to allow the driver that owns the eMAC to register
an XPCS using is regmap for the memory-mapped MDIO bus.

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
Co-developed-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
 MAINTAINERS                         |   2 +
 drivers/net/pcs/Makefile            |   3 +-
 drivers/net/pcs/pcs-xpcs-regmap.c   | 169 ++++++++++++++++++++++++++++
 include/linux/pcs/pcs-xpcs-regmap.h |  13 +++
 4 files changed, 186 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/pcs/pcs-xpcs-regmap.c
 create mode 100644 include/linux/pcs/pcs-xpcs-regmap.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 55ead3d1007a8..972c9faead5b3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27148,8 +27148,10 @@ F:	drivers/net/ethernet/synopsys/
 SYNOPSYS DESIGNWARE ETHERNET XPCS DRIVER
 L:	netdev@vger.kernel.org
 S:	Orphan
+F:	drivers/net/pcs/pcs-xpcs-regmap.c
 F:	drivers/net/pcs/pcs-xpcs.c
 F:	drivers/net/pcs/pcs-xpcs.h
+F:	include/linux/pcs/pcs-xpcs-regmap.h
 F:	include/linux/pcs/pcs-xpcs.h
 
 SYNOPSYS DESIGNWARE HDMI RX CONTROLLER DRIVER
diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index 4f7920618b900..088d35f21a4c3 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-regmap.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-regmap.c b/drivers/net/pcs/pcs-xpcs-regmap.c
new file mode 100644
index 0000000000000..f3f3aaaf0b75a
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-regmap.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Synopsys DesignWare XPCS regmap helpers
+ *
+ * Copyright (C) 2026 RISCstar Solutions.
+ * Copyright (C) 2024 Serge Semin
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mdio.h>
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/pcs/pcs-xpcs-regmap.h>
+#include <linux/regmap.h>
+
+#include "pcs-xpcs.h"
+
+/* Page select register for the indirect MMIO CSRs access */
+#define DW_VR_CSR_VIEWPORT		0xff
+
+static ptrdiff_t xpcs_regmap_addr_format(int dev, int reg)
+{
+	return FIELD_PREP(0x1f0000, dev) | FIELD_PREP(0xffff, reg);
+}
+
+static u16 xpcs_regmap_addr_page(ptrdiff_t csr)
+{
+	return FIELD_GET(0x1fff00, csr);
+}
+
+static ptrdiff_t xpcs_regmap_addr_offset(ptrdiff_t csr)
+{
+	return FIELD_GET(0xff, csr);
+}
+
+static int
+xpcs_regmap_read_reg_indirect(struct regmap *regmap, int dev, int reg)
+{
+	ptrdiff_t csr, ofs;
+	unsigned int val;
+	u16 page;
+	int res;
+
+	csr = xpcs_regmap_addr_format(dev, reg);
+	page = xpcs_regmap_addr_page(csr);
+	ofs = xpcs_regmap_addr_offset(csr);
+
+	res = regmap_write(regmap, DW_VR_CSR_VIEWPORT, page);
+	if (res < 0)
+		return res;
+
+	res = regmap_read(regmap, ofs, &val);
+	if (res < 0)
+		return res;
+
+	return val & 0xffff;
+}
+
+static int
+xpcs_regmap_write_reg_indirect(struct regmap *regmap, int dev, int reg, u16 val)
+{
+	ptrdiff_t csr, ofs;
+	u16 page;
+	int res;
+
+	csr = xpcs_regmap_addr_format(dev, reg);
+	page = xpcs_regmap_addr_page(csr);
+	ofs = xpcs_regmap_addr_offset(csr);
+
+	res = regmap_write(regmap, DW_VR_CSR_VIEWPORT, page);
+	if (res < 0)
+		return res;
+
+	return regmap_write(regmap, ofs, val);
+}
+
+static int xpcs_regmap_read_c22(struct mii_bus *bus, int addr, int reg)
+{
+	struct regmap *regmap = bus->priv;
+
+	if (addr != 0)
+		return -ENODEV;
+
+	return xpcs_regmap_read_reg_indirect(regmap, MDIO_MMD_VEND2, reg);
+}
+
+static int
+xpcs_regmap_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+	struct regmap *regmap = bus->priv;
+
+	if (addr != 0)
+		return -ENODEV;
+
+	return xpcs_regmap_write_reg_indirect(regmap, MDIO_MMD_VEND2, reg, val);
+}
+
+static int xpcs_regmap_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
+{
+	struct regmap *regmap = bus->priv;
+
+	if (addr != 0)
+		return -ENODEV;
+
+	return xpcs_regmap_read_reg_indirect(regmap, dev, reg);
+}
+
+static int xpcs_regmap_write_c45(struct mii_bus *bus, int addr, int dev,
+				 int reg, u16 val)
+{
+	struct regmap *regmap = bus->priv;
+
+	if (addr != 0)
+		return -ENODEV;
+
+	return xpcs_regmap_write_reg_indirect(regmap, dev, reg, val);
+}
+
+static void devm_xpcs_regmap_destroy(void *data)
+{
+	struct dw_xpcs *xpcs = data;
+
+	xpcs_destroy(xpcs);
+}
+
+struct dw_xpcs *devm_xpcs_regmap_register(struct device *dev,
+					  struct regmap *regmap)
+{
+	static atomic_t id = ATOMIC_INIT(-1);
+	struct dw_xpcs *xpcs;
+	struct mii_bus *bus;
+	int ret;
+
+	bus = devm_mdiobus_alloc_size(dev, 0);
+	if (!bus)
+		return ERR_PTR(-ENOMEM);
+
+	bus->name = "DW XPCS MCI/APB3";
+	bus->read = xpcs_regmap_read_c22;
+	bus->write = xpcs_regmap_write_c22;
+	bus->read_c45 = xpcs_regmap_read_c45;
+	bus->write_c45 = xpcs_regmap_write_c45;
+	bus->phy_mask = ~0;
+	bus->parent = dev;
+	bus->priv = regmap;
+
+	snprintf(bus->id, sizeof(bus->id), "dwxpcs-%x", atomic_inc_return(&id));
+
+	/* MDIO-bus here serves as just a back-end engine abstracting out
+	 * the MDIO and MCI/APB3 IO interfaces utilized for the DW XPCS CSRs
+	 * access.
+	 */
+	ret = devm_mdiobus_register(dev, bus);
+	if (ret) {
+		dev_err(dev, "failed to create MDIO bus\n");
+		return ERR_PTR(ret);
+	}
+
+	xpcs = xpcs_create_mdiodev(bus, 0);
+	if (IS_ERR(xpcs))
+		return xpcs;
+
+	ret = devm_add_action_or_reset(dev, devm_xpcs_regmap_destroy, xpcs);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return xpcs;
+}
+EXPORT_SYMBOL_GPL(devm_xpcs_regmap_register);
diff --git a/include/linux/pcs/pcs-xpcs-regmap.h b/include/linux/pcs/pcs-xpcs-regmap.h
new file mode 100644
index 0000000000000..c6d934b1054ed
--- /dev/null
+++ b/include/linux/pcs/pcs-xpcs-regmap.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_PCS_XPCS_REGMAP_H
+#define __LINUX_PCS_XPCS_REGMAP_H
+
+struct device;
+struct regmap;
+struct dw_xpcs;
+
+struct dw_xpcs *devm_xpcs_regmap_register(struct device *dev,
+					  struct regmap *regmap);
+
+#endif /* __LINUX_PCS_XPCS_REGMAP_H */
-- 
2.53.0



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

* [PATCH net-next 3/5] net: stmmac: dwxgmac2: Add XGMAC 3.01a support
  2026-10-19  3:01 [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564 Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 1/5] dt-bindings: net: add support for " Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 2/5] net: pcs: pcs-xpcs-regmap: support XPCS memory-mapped MDIO bus via regmap Alex Elder
@ 2026-10-19  3:01 ` Alex Elder
  2026-10-19  7:58   ` Maxime Chevallier
  2026-10-19  3:01 ` [PATCH net-next 4/5] net: stmmac: dwxgmac2: export symbols for XGMAC 3.01a DMA Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC Alex Elder
  4 siblings, 1 reply; 9+ messages in thread
From: Alex Elder @ 2026-10-19  3:01 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt
  Cc: Daniel Thompson, mcoquelin.stm32, alexandre.torgue, hkallweit1,
	linux, richardcochran, p.zabel, peppe.cavallaro, joabreu,
	mohd.anwar, lorenzo.bianconi, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

From: Daniel Thompson <daniel@riscstar.com>

XGMAC 2.x and 3.x are architecturally very similar.  That means that
for everything except one erratum we can simply use the XGMAC 2.x
callback functions in the stmmac_dma_ops structure.

Only the set_rx_ring_len callback is specific to XGMAC 3.01.  It
limits the number of outstanding write requests that can be serviced
per DMA.

The other erratum addressed in this patch is simply a comment to
ensure that a feature that stmmac doesn't currently use is not enabled
without contemplating the errata.

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
Co-developed-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
 .../net/ethernet/stmicro/stmmac/dwxgmac2.h    |  3 ++
 .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    | 52 +++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index f8ab347f7b5b9..0fe86e9942334 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -374,6 +374,8 @@
 #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_OWRQ			GENMASK(25, 24)
+#define XGMAC_RDRL			GENMASK(15, 0)
 #define XGMAC_DMA_CH_INT_EN(x)		(0x00003138 + (0x80 * (x)))
 #define XGMAC_NIE			BIT(15)
 #define XGMAC_AIE			BIT(14)
@@ -465,6 +467,7 @@
 extern const struct stmmac_ops dwxgmac210_ops;
 extern const struct stmmac_ops dwxlgmac2_ops;
 extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
+extern const struct stmmac_dma_ops dwxgmac301_dma_ops;
 extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
 
 #endif /* __STMMAC_DWXGMAC2_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index ff83858ebc1f3..f9a77d641eb65 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -36,6 +36,13 @@ static void dwxgmac2_dma_init(void __iomem *ioaddr,
 	 * Route DMA interrupts to per-channel lines when multi-MSI enabled.
 	 */
 	if (dma_cfg->multi_msi_en) {
+		/*
+		 * A friendly warning to future adventurers. If Descriptor Posted
+		 * Write support, which is off by default, is ever enabled then be sure
+		 * to make it optional. This is required by errata for at least XGMAC
+		 * 3.01A... and the XGMAC 2.x and 3.x are architecturally similar so we
+		 * use dwxgmac2 support for the 3.x family as well.
+		 */
 		value = readl(ioaddr + XGMAC_DMA_MODE);
 		value = u32_replace_bits(value, XGMAC_INTM_MODE1,
 					 XGMAC_INTM_MASK);
@@ -492,6 +499,20 @@ static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv,
 	writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
 }
 
+static void dwxgmac301_set_rx_ring_len(struct stmmac_priv *priv,
+				       void __iomem *ioaddr, u32 len, u32 chan)
+{
+	u32 val = FIELD_PREP(XGMAC_RDRL, len);
+
+	/*
+	 * Reduce the number of outstanding write requests to 3 (from default
+	 * of 4). This is an errata workaround for XGMAC 3.01a.
+	 */
+	val |= FIELD_PREP(XGMAC_OWRQ, 3);
+
+	writel(val, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
+}
+
 static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv,
 				     void __iomem *ioaddr, u32 len, u32 chan)
 {
@@ -621,3 +642,34 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
 	.enable_sph = dwxgmac2_enable_sph,
 	.enable_tbs = dwxgmac2_enable_tbs,
 };
+
+/* All but one field are the same as dwxgmac210_dma_ops */
+const struct stmmac_dma_ops dwxgmac301_dma_ops = {
+	.reset = dwxgmac2_dma_reset,
+	.init = dwxgmac2_dma_init,
+	.init_chan = dwxgmac2_dma_init_chan,
+	.init_rx_chan = dwxgmac2_dma_init_rx_chan,
+	.init_tx_chan = dwxgmac2_dma_init_tx_chan,
+	.axi = dwxgmac2_dma_axi,
+	.dump_regs = dwxgmac2_dma_dump_regs,
+	.dma_rx_mode = dwxgmac2_dma_rx_mode,
+	.dma_tx_mode = dwxgmac2_dma_tx_mode,
+	.enable_dma_irq = dwxgmac2_enable_dma_irq,
+	.disable_dma_irq = dwxgmac2_disable_dma_irq,
+	.start_tx = dwxgmac2_dma_start_tx,
+	.stop_tx = dwxgmac2_dma_stop_tx,
+	.start_rx = dwxgmac2_dma_start_rx,
+	.stop_rx = dwxgmac2_dma_stop_rx,
+	.dma_interrupt = dwxgmac2_dma_interrupt,
+	.get_hw_feature = dwxgmac2_get_hw_feature,
+	.rx_watchdog = dwxgmac2_rx_watchdog,
+	.set_rx_ring_len = dwxgmac301_set_rx_ring_len,	/* Only 3.01 */
+	.set_tx_ring_len = dwxgmac2_set_tx_ring_len,
+	.set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr,
+	.set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr,
+	.enable_tso = dwxgmac2_enable_tso,
+	.qmode = dwxgmac2_qmode,
+	.set_bfsize = dwxgmac2_set_bfsize,
+	.enable_sph = dwxgmac2_enable_sph,
+	.enable_tbs = dwxgmac2_enable_tbs,
+};
-- 
2.53.0



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

* [PATCH net-next 4/5] net: stmmac: dwxgmac2: export symbols for XGMAC 3.01a DMA
  2026-10-19  3:01 [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564 Alex Elder
                   ` (2 preceding siblings ...)
  2026-10-19  3:01 ` [PATCH net-next 3/5] net: stmmac: dwxgmac2: Add XGMAC 3.01a support Alex Elder
@ 2026-10-19  3:01 ` Alex Elder
  2026-10-19  3:01 ` [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC Alex Elder
  4 siblings, 0 replies; 9+ messages in thread
From: Alex Elder @ 2026-10-19  3:01 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt
  Cc: Daniel Thompson, mcoquelin.stm32, alexandre.torgue, hkallweit1,
	linux, richardcochran, p.zabel, peppe.cavallaro, joabreu,
	mohd.anwar, lorenzo.bianconi, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

From: Daniel Thompson <daniel@riscstar.com>

Toshiba TC9564 is an Ethernet-AVB/TSN bridge and is essentially a
small and highly-specialised SoC. Ethernet on this chip is provided
by a DesignWare XGMAC.

One consequence of the SoC-like design is that the internal AXI bus
(used by the XGMAC for DMA) maps the PCI DMA space with a non-zero base
address. This requires a translation step (happily just simple addition)
to convert the PCI DMA address to the hardware DMA address.

This is pretty funky so rather than push that translation logic into
the core driver we intend to keep that logic inside the TC9564
platform code. In order to do that we need to export a few symbols
to allow us to override some of the DMA and descriptor op tables.

FWIW this approach to overriding the ops tables is similar to the
mechanism currently found in dwmac-loongson.c (with the exception
that we have also exported a couple of functions so we don't
have to replicate their content in the TC9564 platform code).

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
Co-developed-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h |  7 +++++++
 .../ethernet/stmicro/stmmac/dwxgmac2_core.c    |  1 +
 .../ethernet/stmicro/stmmac/dwxgmac2_descs.c   |  1 +
 .../net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 18 ++++++++++--------
 4 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
index 0fe86e9942334..1b32d14c37440 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
@@ -470,4 +470,11 @@ extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
 extern const struct stmmac_dma_ops dwxgmac301_dma_ops;
 extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
 
+void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv, void __iomem *ioaddr,
+			       struct stmmac_dma_cfg *dma_cfg, dma_addr_t phy,
+			       u32 chan);
+void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv, void __iomem *ioaddr,
+			       struct stmmac_dma_cfg *dma_cfg, dma_addr_t phy,
+			       u32 chan);
+
 #endif /* __STMMAC_DWXGMAC2_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index 1a88cbaed70ca..0effdd6969d65 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -1542,6 +1542,7 @@ int dwxgmac2_setup(struct stmmac_priv *priv)
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(dwxgmac2_setup);
 
 int dwxlgmac2_setup(struct stmmac_priv *priv)
 {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
index 6719ac6e395bc..f0e7b8ee48ac7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
@@ -374,3 +374,4 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = {
 	.set_vlan = dwxgmac2_set_vlan,
 	.set_tbs = dwxgmac2_set_tbs,
 };
+EXPORT_SYMBOL_GPL(dwxgmac210_desc_ops);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
index f9a77d641eb65..2f9334d7cb922 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
@@ -63,10 +63,10 @@ static void dwxgmac2_dma_init_chan(struct stmmac_priv *priv,
 	writel(XGMAC_DMA_INT_DEFAULT_EN, ioaddr + XGMAC_DMA_CH_INT_EN(chan));
 }
 
-static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
-				      void __iomem *ioaddr,
-				      struct stmmac_dma_cfg *dma_cfg,
-				      dma_addr_t phy, u32 chan)
+void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
+			       void __iomem *ioaddr,
+			       struct stmmac_dma_cfg *dma_cfg,
+			       dma_addr_t phy, u32 chan)
 {
 	u32 rxpbl = dma_cfg->rxpbl ?: dma_cfg->pbl;
 	u32 value;
@@ -78,11 +78,11 @@ static void dwxgmac2_dma_init_rx_chan(struct stmmac_priv *priv,
 	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
 	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
 }
+EXPORT_SYMBOL_GPL(dwxgmac2_dma_init_rx_chan);
 
-static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
-				      void __iomem *ioaddr,
-				      struct stmmac_dma_cfg *dma_cfg,
-				      dma_addr_t phy, u32 chan)
+void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv, void __iomem *ioaddr,
+			       struct stmmac_dma_cfg *dma_cfg, dma_addr_t phy,
+			       u32 chan)
 {
 	u32 txpbl = dma_cfg->txpbl ?: dma_cfg->pbl;
 	u32 value;
@@ -94,6 +94,7 @@ static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv,
 	writel(upper_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
 	writel(lower_32_bits(phy), ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
 }
+EXPORT_SYMBOL_GPL(dwxgmac2_dma_init_tx_chan);
 
 static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
 {
@@ -673,3 +674,4 @@ const struct stmmac_dma_ops dwxgmac301_dma_ops = {
 	.enable_sph = dwxgmac2_enable_sph,
 	.enable_tbs = dwxgmac2_enable_tbs,
 };
+EXPORT_SYMBOL_GPL(dwxgmac301_dma_ops);
-- 
2.53.0



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

* [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC
  2026-10-19  3:01 [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564 Alex Elder
                   ` (3 preceding siblings ...)
  2026-10-19  3:01 ` [PATCH net-next 4/5] net: stmmac: dwxgmac2: export symbols for XGMAC 3.01a DMA Alex Elder
@ 2026-10-19  3:01 ` Alex Elder
  2026-10-19  7:52   ` Maxime Chevallier
  2026-10-19  9:14   ` Mohd Ayaan Anwar
  4 siblings, 2 replies; 9+ messages in thread
From: Alex Elder @ 2026-10-19  3:01 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt
  Cc: Daniel Thompson, mcoquelin.stm32, alexandre.torgue, hkallweit1,
	linux, richardcochran, p.zabel, peppe.cavallaro, joabreu,
	mohd.anwar, lorenzo.bianconi, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

From: Daniel Thompson <daniel@riscstar.com>

Add support for the Ethernet XGMAC functionality present in the
Toshiba TC9564 SoC.

The TC9564 is a fairly complex chip that attaches to a host via
the upstream port of a PCIe switch it implements.  That switch
has three downstream ports, and one of those has an embedded PCI
endpoint.  The PCI endpoint implements two PCI functions, and a
10 Gbps-capable XGMAC interface is attached to each.

The TC9564 implements additional peripherals, and access to them
is provided by a PCI endpoint bus associated with BAR 4 of the
first PCI function.  A PCI driver sets up the PCI function for
use, and peripherals using the bus use platform drivers, matched
by compatible string.

We use the pci-ep-bus approach for the stmmac driver as well, with
each PCI function exposing access to its BAR 4 via an endpoint bus.
The XGMAC device is defined within a pci-ep-bus node, and is bound
to the platform driver based on its compatible string.

Signed-off-by: Daniel Thompson <daniel@riscstar.com>
Co-developed-by: Alex Elder <elder@riscstar.com>
Signed-off-by: Alex Elder <elder@riscstar.com>
---
 MAINTAINERS                                   |   1 +
 drivers/net/ethernet/stmicro/stmmac/Kconfig   |  11 +
 drivers/net/ethernet/stmicro/stmmac/Makefile  |   1 +
 .../ethernet/stmicro/stmmac/dwmac-tc9564.c    | 590 ++++++++++++++++++
 4 files changed, 603 insertions(+)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 972c9faead5b3..69f301aa26eb9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -28313,6 +28313,7 @@ M:	Alex Elder <elder@kernel.org>
 M:	Daniel Thompson <danielt@kernel.org>
 S:	Maintained
 F:	Documentation/devicetree/bindings/net/toshiba,tc9564-dwmac.yaml
+F:	drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
 
 TOSHIBA WMI HOTKEYS DRIVER
 M:	Azael Avalos <coproscefalo@gmail.com>
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index ab3c4cf964239..5613921188df4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -363,6 +363,17 @@ config DWMAC_LOONGSON1
 	  device driver. This driver is used for Loongson1-based boards
 	  like Loongson LS1B/LS1C.
 
+config DWMAC_TC9564
+	tristate "Toshiba TC9564 DWMAC support"
+	depends on OF && COMMON_CLK && TC9564_PCI
+	default TC9564_PCI
+	help
+	  Support for the Ethernet controllers on the Toshiba TC9564.
+
+	  This enables glue layer support in the stmmac driver support
+	  for the Toshiba TC9564.  This chip implements two embedded
+	  PCIe functions, each of which has an XGMAC interface.
+
 config DWMAC_TEGRA
 	tristate "NVIDIA Tegra MGBE support"
 	depends on ARCH_TEGRA || COMPILE_TEST
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index b16a456b730ec..c4de25db93715 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -52,4 +52,5 @@ obj-$(CONFIG_STMMAC_PCI)	+= stmmac-pci.o
 obj-$(CONFIG_DWMAC_INTEL)	+= dwmac-intel.o
 obj-$(CONFIG_DWMAC_LOONGSON)	+= dwmac-loongson.o
 obj-$(CONFIG_DWMAC_MOTORCOMM)	+= dwmac-motorcomm.o
+obj-$(CONFIG_DWMAC_TC9564)	+= dwmac-tc9564.o
 stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
new file mode 100644
index 0000000000000..21098f91e3bbf
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
@@ -0,0 +1,590 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2026 by RISCstar Solutions Corporation.  All rights reserved.
+ *
+ * Derived from code having the following copyrights:
+ * Copyright (C) 2011-2012  Vayavya Labs Pvt Ltd
+ * Copyright (C) 2025 Toshiba Electronic Devices & Storage Corporation
+ */
+
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/pcs/pcs-xpcs-regmap.h>
+#include <linux/pcs/pcs-xpcs.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+#include <linux/stmmac.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include "common.h"
+#include "dwxgmac2.h"
+#include "stmmac.h"
+#include "stmmac_platform.h"
+
+#define DRIVER_NAME			"dwmac-tc9564"
+
+/* Start of range representing PCI space on the TC9564 internal bus */
+#define TC9564_SLV00_SRC_ADDR		0x0000001000000000ULL
+
+#define TC9564_PTP_CLOCK_RATE		(250 * HZ_PER_MHZ)
+
+#define TC9564_RX_FIFO_SIZE		(46 * SZ_1K)
+#define TC9564_TX_FIFO_SIZE		(46 * SZ_1K)
+
+/* Fields and values for the EMACTL registers */
+#define EMAC_SP_SEL_MASK		GENMASK(3, 0)
+#define SP_SEL_2500BASEX		4
+#define SP_SEL_SGMII_1000M		5
+#define SP_SEL_SGMII_100M		6
+#define SP_SEL_SGMII_10M		7
+#define EMAC_PHY_INF_SEL_MASK		GENMASK(5, 4)
+#define PCS_CLK_PHY			1	/* Clock from PHY */
+#define EMAC_INV_SGM_SIG_DET		BIT(6)	/* 1 = polarity inverted */
+#define EMAC_LPIHWCLKEN			BIT(8)	/* 1 = low power mode */
+#define EMAC_INIT_DONE			BIT(21)
+
+/* Offset to the XPCS memory block, relative to the EMAC address range */
+#define DWMAC_XPCS_OFFSET		0x3a00
+
+/* Offset to the PMATOP memory block, relative to the EMAC address range */
+#define DWMAC_PMATOP_OFFSET			0x4000
+
+#define PMA_CML_GL_PM_CFG0			0x01b8
+
+/*
+ * Five sets three registers must be configured for PMA.  The HWT_REFCLK
+ * registers are each separated by 0x14 bytes.  The Common0 configuration
+ * registers are separated by 0x8 bytes.
+ */
+#define PMA_REG_COUNT				5
+
+#define PMA_HWT_REFCK_R_EN			0x1080
+#define PMA_HWT_REFCK_TERM_EN			0x1090
+#define PMA_HWT_REFCK_STRIDE			0x0014
+
+#define PMA_COMM_CFG_0_1			0x1888
+#define PMA_COMM_CFG_0_1_STRIDE			0x0008
+
+/* PMA_COMM_CFG_0_1 fields (WRITE_MASK is a field name) */
+#define COMM_CFG_WRITE_MASK_MASK		GENMASK(16, 9)
+#define WRITE_MASK_VALUE			0xf7	/* Power-on value */
+#define COMM_CFG_ENABLE				BIT(8)
+#define COMM_CFG_WRITE_DATA_MASK		GENMASK(7, 0)
+#define WRITE_DATA_VALUE			0x04	/* Power-on value */
+
+enum {
+	RESET_ID_MAC,
+	RESET_ID_XPCS,
+	RESET_ID_PMA,
+};
+
+static const char * const tc9564_reset_names[] = {
+	[RESET_ID_MAC] = "mac",
+	[RESET_ID_XPCS] = "xpcs",
+	[RESET_ID_PMA] = "pma",
+};
+
+/**
+ * struct tc9564_data - Toshiba-specific platform data
+ * @dev:		Device pointer
+ * @ioaddr:		Pointer to mapped eMAC memory
+ * @plat:		Pointer to our stmmac platform data
+ * @resets:		Reset controller bulk array
+ * @clocks:		Clock controller bulk array
+ * @clock_count:	Number of valid elements in the clock array
+ * @config_regmap:	Regmap used to access eMAC configuration registers
+ * @emac_ctl_offset:	Offset of the eMAC control register within the regmap
+ * @res:		Structure passed to stmmac_dvr_probe()
+ * @desc:		DMA descriptor data used by mac_device_info
+ * @dma:		DMA operations data used by mac_device_info
+ */
+struct tc9564_data {
+	struct device *dev;
+	void __iomem *ioaddr;
+	struct plat_stmmacenet_data *plat;
+	struct reset_control_bulk_data resets[ARRAY_SIZE(tc9564_reset_names)];
+	struct clk_bulk_data *clocks;
+	u32 clock_count;
+
+	struct regmap *config_regmap;
+	u32 emac_ctl_offset;
+
+	/* This field is data passed to stmmac_dvr_probe() */
+	struct stmmac_resources res;
+
+	/* These two fields are used by the mac_device_info structure */
+	struct stmmac_desc_ops desc;
+	struct stmmac_dma_ops dma;
+};
+
+struct tc9564_mac_speed {
+	phy_interface_t phy_interface;
+	int speed;
+	u32 sp_sel;
+};
+
+static struct tc9564_mac_speed mac_speed[] = {
+	{ PHY_INTERFACE_MODE_2500BASEX,	SPEED_2500,  SP_SEL_2500BASEX },
+	{ PHY_INTERFACE_MODE_SGMII,	SPEED_1000,  SP_SEL_SGMII_1000M },
+	{ PHY_INTERFACE_MODE_SGMII,	SPEED_100,   SP_SEL_SGMII_100M },
+	{ PHY_INTERFACE_MODE_SGMII,	SPEED_10,    SP_SEL_SGMII_10M },
+};
+
+/* TC9564 uses indirect addressing so this need only describe a 1KiB range */
+static const struct regmap_config xpcs_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_base	= 0x00,		/* Minimum XPCS reg offset */
+	.max_register	= 0xff,		/* Register DW_VR_CSR_VIEWPORT */
+	.reg_shift	= REGMAP_UPSHIFT(2),
+};
+
+/**
+ * tc9564_pma_init() - Initialize PMA
+ * @td:	bsp_priv pointer
+ *
+ * Initialize (or re-initialize) the PMA, configure the clocks and wait for the
+ * eMAC to be ready.
+ */
+static void tc9564_pma_init(struct tc9564_data *td)
+{
+	struct reset_control *rstc = td->resets[RESET_ID_PMA].rstc;
+	struct regmap *regmap = td->config_regmap;
+	void __iomem *pmatop;
+	u32 val;
+	int ret;
+	u32 i;
+
+	/*
+	 * When we re-initialize the PMA then the reset will already have
+	 * been deasserted. We must make sure the PMA reset is asserted
+	 * before we change the clock settings.
+	 */
+	WARN_ON(reset_control_assert(rstc));
+
+	pmatop = td->res.addr + DWMAC_PMATOP_OFFSET;
+
+	/* Power on CML buffer (0 = normal mode, 1 = power down) */
+	writel(0, pmatop + PMA_CML_GL_PM_CFG0);
+
+	/* This value switches clock from C0_REFCK to CLK_REF_I */
+	val = u32_encode_bits(WRITE_MASK_VALUE, COMM_CFG_WRITE_MASK_MASK);
+	val |= COMM_CFG_ENABLE;
+	val |= u32_encode_bits(WRITE_DATA_VALUE, COMM_CFG_WRITE_DATA_MASK);
+
+	for (i = 0; i < PMA_REG_COUNT; i++) {
+		u32 offset =  i * PMA_HWT_REFCK_STRIDE;
+
+		/* Disable C0_REFCK and 100 ohm termination */
+		writel(0, pmatop + PMA_HWT_REFCK_R_EN + offset);
+		writel(0, pmatop + PMA_HWT_REFCK_TERM_EN + offset);
+
+		/* Switch clock from C0_REFCK to CLK_REF_I */
+		offset =  i * PMA_COMM_CFG_0_1_STRIDE;
+		writel(val, pmatop + PMA_COMM_CFG_0_1 + offset);
+	}
+
+	WARN_ON(reset_control_deassert(rstc));
+
+	ret = regmap_read_poll_timeout(regmap, td->emac_ctl_offset,
+				       val, val & EMAC_INIT_DONE, 50, 1000000);
+	WARN(ret, "timeout waiting for MAC init done\n");
+}
+
+static int tc9564_mac_speed_select(struct tc9564_data *td,
+				   phy_interface_t interface, int speed)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mac_speed); i++) {
+		if (mac_speed[i].phy_interface != interface)
+			continue;
+
+		if (speed == mac_speed[i].speed || speed == SPEED_UNKNOWN)
+			return mac_speed[i].sp_sel;
+	}
+	dev_err(td->dev, "%s/%d unsupported\n", phy_modes(interface), speed);
+
+	return -EOPNOTSUPP;
+}
+
+static void tc9564_mac_configure(struct tc9564_data *td,
+				 phy_interface_t interface, int speed)
+{
+	struct regmap *regmap = td->config_regmap;
+	u32 offset = td->emac_ctl_offset;
+	int sp_sel;
+	u32 val;
+
+	sp_sel = tc9564_mac_speed_select(td, interface, speed);
+	if (sp_sel < 0)
+		return;
+
+	/* No error checking needed for MMIO regmap */
+	regmap_read(regmap, offset, &val);
+	val |= EMAC_LPIHWCLKEN;
+	val &= ~EMAC_INV_SGM_SIG_DET;
+	val = u32_replace_bits(val, PCS_CLK_PHY, EMAC_PHY_INF_SEL_MASK);
+	val = u32_replace_bits(val, sp_sel, EMAC_SP_SEL_MASK);
+	regmap_write(regmap, offset, val);
+}
+
+static void tc9564_mac_enable(struct tc9564_data *td)
+{
+	WARN_ON(clk_bulk_prepare_enable(td->clock_count, td->clocks));
+
+	WARN_ON(reset_control_deassert(td->resets[RESET_ID_MAC].rstc));
+
+	tc9564_mac_configure(td, td->plat->phy_interface, SPEED_UNKNOWN);
+	tc9564_pma_init(td);
+
+	WARN_ON(reset_control_deassert(td->resets[RESET_ID_XPCS].rstc));
+}
+
+static void tc9564_mac_disable(struct tc9564_data *td)
+{
+	WARN_ON(reset_control_bulk_assert(ARRAY_SIZE(td->resets), td->resets));
+
+	clk_bulk_disable_unprepare(td->clock_count, td->clocks);
+}
+
+/*
+ * Override method for dwxgmac301_dma_ops->init_rx_chan
+ *
+ * This differs from the dwxgmac301_dma_ops->init_rx_chan by translating the DMA
+ * address for TC9564 internal bus. The window that provides DMA access to PCI
+ * is linearly mapped at 0x10_0000_0000.
+ */
+static void tc9564_dma_init_rx_chan(struct stmmac_priv *priv,
+				    void __iomem *ioaddr,
+				    struct stmmac_dma_cfg *dma_cfg,
+				    dma_addr_t phy, u32 chan)
+{
+	u64 translated = phy + TC9564_SLV00_SRC_ADDR;
+
+	dwxgmac2_dma_init_rx_chan(priv, ioaddr, dma_cfg, phy, chan);
+
+	writel(upper_32_bits(translated),
+	       ioaddr + XGMAC_DMA_CH_RxDESC_HADDR(chan));
+	writel(lower_32_bits(translated),
+	       ioaddr + XGMAC_DMA_CH_RxDESC_LADDR(chan));
+}
+
+/* Override method for dwxgmac301_dma_ops->init_tx_chan */
+static void tc9564_dma_init_tx_chan(struct stmmac_priv *priv,
+				    void __iomem *ioaddr,
+				    struct stmmac_dma_cfg *dma_cfg,
+				    dma_addr_t phy, u32 chan)
+{
+	u64 translated = phy + TC9564_SLV00_SRC_ADDR;
+
+	dwxgmac2_dma_init_tx_chan(priv, ioaddr, dma_cfg, phy, chan);
+
+	writel(upper_32_bits(translated),
+	       ioaddr + XGMAC_DMA_CH_TxDESC_HADDR(chan));
+	writel(lower_32_bits(translated),
+	       ioaddr + XGMAC_DMA_CH_TxDESC_LADDR(chan));
+}
+
+/* Override method for dwxgmac210_desc_ops->set_addr */
+static void tc9564_desc_set_addr(struct dma_desc *p, dma_addr_t addr)
+{
+	u64 translated = addr + TC9564_SLV00_SRC_ADDR;
+
+	p->des0 = cpu_to_le32(lower_32_bits(translated));
+	p->des1 = cpu_to_le32(upper_32_bits(translated));
+}
+
+/* Override method for dwxgmac210_desc_ops->set_sec_addr */
+static void tc9564_desc_set_sec_addr(struct dma_desc *p, dma_addr_t addr,
+				     bool is_valid)
+{
+	u64 translated = addr + TC9564_SLV00_SRC_ADDR;
+
+	p->des2 = cpu_to_le32(lower_32_bits(translated));
+	p->des3 = cpu_to_le32(upper_32_bits(translated));
+}
+
+/*
+ * Use mac_setup to apply the override methods above.
+ *
+ * The memory for the modified ops structures is pre-allocated as part of
+ * struct tc9564_data.
+ */
+static int tc9564_mac_setup(void *apriv, struct mac_device_info *mac)
+{
+	struct stmmac_priv *priv = apriv;
+	struct tc9564_data *td;
+
+	td = priv->plat->bsp_priv;
+
+	/* dwxgmac301_dma_ops needs extending to provide DMA address translation */
+	td->dma = dwxgmac301_dma_ops;
+	td->dma.init_rx_chan = tc9564_dma_init_rx_chan;
+	td->dma.init_tx_chan = tc9564_dma_init_tx_chan;
+	mac->dma = &td->dma;
+
+	/* dwxgmac210_desc_ops also needs extending for the same reason */
+	td->desc = dwxgmac210_desc_ops;
+	td->desc.set_addr = tc9564_desc_set_addr;
+	td->desc.set_sec_addr = tc9564_desc_set_sec_addr;
+	mac->desc = &td->desc;
+
+	priv->hw = mac;
+
+	return dwxgmac2_setup(priv);
+}
+
+static int tc9564_pcs_init(struct stmmac_priv *priv)
+{
+	void __iomem *emac = priv->ioaddr;
+	struct regmap *xpcs_regmap;
+	void __iomem *xpcs_addr;
+	struct dw_xpcs *xpcs;
+
+	xpcs_addr = emac + DWMAC_XPCS_OFFSET;
+	xpcs_regmap = devm_regmap_init_mmio(priv->device, xpcs_addr,
+					    &xpcs_regmap_config);
+	if (IS_ERR(xpcs_regmap))
+		return PTR_ERR(xpcs_regmap);
+
+	xpcs = devm_xpcs_regmap_register(priv->device, xpcs_regmap);
+	if (IS_ERR(xpcs))
+		return PTR_ERR(xpcs);
+
+	xpcs_config_eee_mult_fact(xpcs, priv->plat->mult_fact_100ns);
+	priv->hw->phylink_pcs = xpcs_to_phylink_pcs(xpcs);
+
+	return 0;
+}
+
+static struct phylink_pcs *tc9564_select_pcs(struct stmmac_priv *priv,
+					     phy_interface_t interface)
+{
+	return priv->hw->phylink_pcs;
+}
+
+static void tc9564_fix_mac_speed(void *bsp_priv, phy_interface_t interface,
+				 int speed, unsigned int mode)
+{
+	struct tc9564_data *td = bsp_priv;
+
+	tc9564_mac_configure(td, interface, speed);
+	tc9564_pma_init(td);
+}
+
+static int tc9564_dwmac_suspend(struct device *dev, void *bsp_priv)
+{
+	struct tc9564_data *td = bsp_priv;
+
+	tc9564_mac_disable(td);
+
+	return 0;
+}
+
+static int tc9564_dwmac_resume(struct device *dev, void *bsp_priv)
+{
+	struct tc9564_data *td = bsp_priv;
+
+	tc9564_mac_enable(td);
+
+	return 0;
+}
+
+static int tc9564_probe_config_dt(struct tc9564_data *td)
+{
+	struct platform_device *pdev = to_platform_device(td->dev);
+	struct device_node *np = td->dev->of_node;
+	struct plat_stmmacenet_data *plat;
+	phy_interface_t phy_interface;
+	struct device *dev = td->dev;
+	int ret;
+
+	ret = device_get_phy_mode(dev);
+	if (ret < 0)
+		return -ENODEV;
+	phy_interface = ret;
+
+	/* The platform structure is allocated with devm_kzalloc() */
+	plat = devm_stmmac_probe_config_dt(pdev, td->res.mac);
+	if (IS_ERR(plat))
+		return PTR_ERR(plat);
+
+	/*
+	 * Core driver cannot deduce or validate fifo size because the bits
+	 * that provide FIFO size only worth in powers of two.
+	 */
+	if (plat->rx_fifo_size == 0 || plat->tx_fifo_size == 0)
+		return dev_err_probe(dev, -EINVAL, "fifo size is not set\n");
+	if (plat->rx_fifo_size > TC9564_RX_FIFO_SIZE ||
+	    plat->tx_fifo_size > TC9564_TX_FIFO_SIZE)
+		return dev_err_probe(dev, -EINVAL, "fifo size too big (%u/%u)\n",
+				     plat->rx_fifo_size, plat->tx_fifo_size);
+
+	/*
+	 * toshiba,tc9564-xgmac is *not* compatible with snps,dwxgmac because
+	 * generic drivers cannot possibly work on TC9564 (without clocks
+	 * reading registers wedges the bus). However, without snps,dwxgmac,
+	 * devm_stmmac_probe_config_dt(), can't figure of the core type and
+	 * won't parse a couple of extra properties. Let's handle that here!
+	 */
+	plat->core_type = DWMAC_CORE_XGMAC;
+	plat->pmt = true;
+	if (of_property_read_bool(np, "snps,tso"))
+		plat->flags |= STMMAC_FLAG_TSO_EN;
+	of_property_read_u32(np, "snps,multicast-filter-bins",
+			     &plat->multicast_filter_bins);
+	of_property_read_u32(np, "snps,perfect-filter-entries",
+			     &plat->unicast_filter_entries);
+
+	plat->phy_interface = phy_interface;
+
+	/*
+	 * Set a few additional flags and settings that are always needed for
+	 * TC9564.
+	 */
+	plat->default_an_inband = true;
+	plat->host_dma_width = 36;
+	plat->flags |= STMMAC_FLAG_MULTI_MSI_EN;
+	for (int i = 4; i < plat->tx_queues_to_use; i++) {
+		plat->tx_queues_cfg[i].coe_unsupported = true;
+		plat->tx_queues_cfg[i].tbs_en = 1;
+	}
+
+	plat->fix_mac_speed = tc9564_fix_mac_speed;
+	plat->suspend = tc9564_dwmac_suspend;
+	plat->resume = tc9564_dwmac_resume;
+	plat->mac_setup = tc9564_mac_setup;
+	plat->pcs_init = tc9564_pcs_init;
+	plat->select_pcs = tc9564_select_pcs;
+
+	plat->bsp_priv = td;
+
+	td->plat = plat;
+
+	return 0;
+}
+
+/* Look up resets, and ensure they're initially all asserted */
+static int tc9564_reset_init(struct tc9564_data *td)
+{
+	u32 reset_count = ARRAY_SIZE(td->resets);
+	int ret;
+	u32 i;
+
+	for (i = 0; i < reset_count; i++)
+		td->resets[i].id = tc9564_reset_names[i];
+
+	ret = devm_reset_control_bulk_get_exclusive(td->dev, reset_count,
+						    td->resets);
+	if (ret)
+		return ret;
+
+	return reset_control_bulk_assert(reset_count, td->resets);
+}
+
+static int tc9564_clock_init(struct tc9564_data *td)
+{
+	struct device *dev = td->dev;
+	int ret;
+
+	ret = devm_clk_bulk_get_all(dev, &td->clocks);
+	if (ret < 0)
+		return ret;
+	td->clock_count = ret;
+
+	return 0;
+}
+
+static int tc9564_dwmac_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct tc9564_data *td;
+	struct device_node *np;
+	struct regmap *regmap;
+	int ret;
+
+	td = devm_kzalloc(dev, sizeof(*td), GFP_KERNEL);
+	if (!td)
+		return -ENOMEM;
+
+	td->dev = dev;
+
+	np = dev_of_node(dev);
+	regmap = syscon_regmap_lookup_by_phandle_args(np,
+						      "toshiba,config-syscon",
+						      1, &td->emac_ctl_offset);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "failed to get config regmap\n");
+	td->config_regmap = regmap;
+
+	ret = tc9564_reset_init(td);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to initialize resets\n");
+
+	ret = tc9564_clock_init(td);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to initialize clocks\n");
+
+	ret = tc9564_probe_config_dt(td);
+	if (ret)
+		return ret;
+
+	ret = stmmac_get_platform_resources(pdev, &td->res);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "failed to initialize stmmac resources\n");
+
+	tc9564_mac_enable(td);
+
+	ret = stmmac_dvr_probe(dev, td->plat, &td->res);
+	if (ret) {
+		ret = dev_err_probe(dev, ret, "failed stmmac probe\n");
+		goto err_disable_mac;
+	}
+
+	return 0;
+
+err_disable_mac:
+	tc9564_mac_disable(td);
+
+	return ret;
+}
+
+static void tc9564_dwmac_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct net_device *ndev = dev_get_drvdata(dev);
+	struct stmmac_priv *priv = netdev_priv(ndev);
+	struct tc9564_data *td = priv->plat->bsp_priv;
+
+	stmmac_dvr_remove(dev);
+	tc9564_mac_disable(td);
+}
+
+static const struct of_device_id tc9564_dwmac_ids[] = {
+	{ .compatible = "toshiba,tc9564-xgmac", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tc9564_dwmac_ids);
+
+static struct platform_driver tc9564_dwmac_driver = {
+	.probe			= tc9564_dwmac_probe,
+	.remove			= tc9564_dwmac_remove,
+	.driver = {
+		.name		= DRIVER_NAME,
+		.of_match_table	= tc9564_dwmac_ids,
+		.pm		= &stmmac_simple_pm_ops,
+		.owner		= THIS_MODULE,
+	},
+};
+module_platform_driver(tc9564_dwmac_driver);
+
+MODULE_DESCRIPTION("Toshiba TC9564 PCIe Ethernet Network Driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0



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

* Re: [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC
  2026-10-19  3:01 ` [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC Alex Elder
@ 2026-10-19  7:52   ` Maxime Chevallier
  2026-10-19  9:14   ` Mohd Ayaan Anwar
  1 sibling, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-10-19  7:52 UTC (permalink / raw)
  To: Alex Elder, andrew+netdev, davem, edumazet, kuba, pabeni, robh,
	krzk+dt, conor+dt
  Cc: Daniel Thompson, mcoquelin.stm32, alexandre.torgue, hkallweit1,
	linux, richardcochran, p.zabel, peppe.cavallaro, joabreu,
	mohd.anwar, lorenzo.bianconi, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

Hi Alex,

On 10/19/26 05:01, Alex Elder wrote:
> From: Daniel Thompson <daniel@riscstar.com>
> 
> Add support for the Ethernet XGMAC functionality present in the
> Toshiba TC9564 SoC.
> 
> The TC9564 is a fairly complex chip that attaches to a host via
> the upstream port of a PCIe switch it implements.  That switch
> has three downstream ports, and one of those has an embedded PCI
> endpoint.  The PCI endpoint implements two PCI functions, and a
> 10 Gbps-capable XGMAC interface is attached to each.
> 
> The TC9564 implements additional peripherals, and access to them
> is provided by a PCI endpoint bus associated with BAR 4 of the
> first PCI function.  A PCI driver sets up the PCI function for
> use, and peripherals using the bus use platform drivers, matched
> by compatible string.
> 
> We use the pci-ep-bus approach for the stmmac driver as well, with
> each PCI function exposing access to its BAR 4 via an endpoint bus.
> The XGMAC device is defined within a pci-ep-bus node, and is bound
> to the platform driver based on its compatible string.
> 
> Signed-off-by: Daniel Thompson <daniel@riscstar.com>
> Co-developed-by: Alex Elder <elder@riscstar.com>
> Signed-off-by: Alex Elder <elder@riscstar.com>
> ---
>  MAINTAINERS                                   |   1 +
>  drivers/net/ethernet/stmicro/stmmac/Kconfig   |  11 +
>  drivers/net/ethernet/stmicro/stmmac/Makefile  |   1 +
>  .../ethernet/stmicro/stmmac/dwmac-tc9564.c    | 590 ++++++++++++++++++
>  4 files changed, 603 insertions(+)
>  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 972c9faead5b3..69f301aa26eb9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -28313,6 +28313,7 @@ M:	Alex Elder <elder@kernel.org>
>  M:	Daniel Thompson <danielt@kernel.org>
>  S:	Maintained
>  F:	Documentation/devicetree/bindings/net/toshiba,tc9564-dwmac.yaml
> +F:	drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
>  
>  TOSHIBA WMI HOTKEYS DRIVER
>  M:	Azael Avalos <coproscefalo@gmail.com>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> index ab3c4cf964239..5613921188df4 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
> +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> @@ -363,6 +363,17 @@ config DWMAC_LOONGSON1
>  	  device driver. This driver is used for Loongson1-based boards
>  	  like Loongson LS1B/LS1C.
>  
> +config DWMAC_TC9564
> +	tristate "Toshiba TC9564 DWMAC support"
> +	depends on OF && COMMON_CLK && TC9564_PCI
> +	default TC9564_PCI
> +	help
> +	  Support for the Ethernet controllers on the Toshiba TC9564.
> +
> +	  This enables glue layer support in the stmmac driver support
> +	  for the Toshiba TC9564.  This chip implements two embedded
> +	  PCIe functions, each of which has an XGMAC interface.
> +
>  config DWMAC_TEGRA
>  	tristate "NVIDIA Tegra MGBE support"
>  	depends on ARCH_TEGRA || COMPILE_TEST
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index b16a456b730ec..c4de25db93715 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -52,4 +52,5 @@ obj-$(CONFIG_STMMAC_PCI)	+= stmmac-pci.o
>  obj-$(CONFIG_DWMAC_INTEL)	+= dwmac-intel.o
>  obj-$(CONFIG_DWMAC_LOONGSON)	+= dwmac-loongson.o
>  obj-$(CONFIG_DWMAC_MOTORCOMM)	+= dwmac-motorcomm.o
> +obj-$(CONFIG_DWMAC_TC9564)	+= dwmac-tc9564.o
>  stmmac-pci-objs:= stmmac_pci.o
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
> new file mode 100644
> index 0000000000000..21098f91e3bbf
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tc9564.c
> @@ -0,0 +1,590 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (C) 2026 by RISCstar Solutions Corporation.  All rights reserved.
> + *
> + * Derived from code having the following copyrights:
> + * Copyright (C) 2011-2012  Vayavya Labs Pvt Ltd
> + * Copyright (C) 2025 Toshiba Electronic Devices & Storage Corporation
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/iopoll.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/pcs/pcs-xpcs-regmap.h>
> +#include <linux/pcs/pcs-xpcs.h>
> +#include <linux/phy.h>
> +#include <linux/regmap.h>
> +#include <linux/stmmac.h>
> +#include <linux/types.h>
> +#include <linux/units.h>
> +
> +#include "common.h"
> +#include "dwxgmac2.h"
> +#include "stmmac.h"
> +#include "stmmac_platform.h"
> +
> +#define DRIVER_NAME			"dwmac-tc9564"
> +
> +/* Start of range representing PCI space on the TC9564 internal bus */
> +#define TC9564_SLV00_SRC_ADDR		0x0000001000000000ULL
> +
> +#define TC9564_PTP_CLOCK_RATE		(250 * HZ_PER_MHZ)
> +
> +#define TC9564_RX_FIFO_SIZE		(46 * SZ_1K)
> +#define TC9564_TX_FIFO_SIZE		(46 * SZ_1K)
> +
> +/* Fields and values for the EMACTL registers */
> +#define EMAC_SP_SEL_MASK		GENMASK(3, 0)
> +#define SP_SEL_2500BASEX		4
> +#define SP_SEL_SGMII_1000M		5
> +#define SP_SEL_SGMII_100M		6
> +#define SP_SEL_SGMII_10M		7
> +#define EMAC_PHY_INF_SEL_MASK		GENMASK(5, 4)
> +#define PCS_CLK_PHY			1	/* Clock from PHY */
> +#define EMAC_INV_SGM_SIG_DET		BIT(6)	/* 1 = polarity inverted */
> +#define EMAC_LPIHWCLKEN			BIT(8)	/* 1 = low power mode */
> +#define EMAC_INIT_DONE			BIT(21)
> +
> +/* Offset to the XPCS memory block, relative to the EMAC address range */
> +#define DWMAC_XPCS_OFFSET		0x3a00
> +
> +/* Offset to the PMATOP memory block, relative to the EMAC address range */
> +#define DWMAC_PMATOP_OFFSET			0x4000
> +
> +#define PMA_CML_GL_PM_CFG0			0x01b8
> +
> +/*
> + * Five sets three registers must be configured for PMA.  The HWT_REFCLK
> + * registers are each separated by 0x14 bytes.  The Common0 configuration
> + * registers are separated by 0x8 bytes.
> + */
> +#define PMA_REG_COUNT				5
> +
> +#define PMA_HWT_REFCK_R_EN			0x1080
> +#define PMA_HWT_REFCK_TERM_EN			0x1090
> +#define PMA_HWT_REFCK_STRIDE			0x0014
> +
> +#define PMA_COMM_CFG_0_1			0x1888
> +#define PMA_COMM_CFG_0_1_STRIDE			0x0008
> +
> +/* PMA_COMM_CFG_0_1 fields (WRITE_MASK is a field name) */
> +#define COMM_CFG_WRITE_MASK_MASK		GENMASK(16, 9)
> +#define WRITE_MASK_VALUE			0xf7	/* Power-on value */
> +#define COMM_CFG_ENABLE				BIT(8)
> +#define COMM_CFG_WRITE_DATA_MASK		GENMASK(7, 0)
> +#define WRITE_DATA_VALUE			0x04	/* Power-on value */
> +
> +enum {
> +	RESET_ID_MAC,
> +	RESET_ID_XPCS,
> +	RESET_ID_PMA,
> +};
> +
> +static const char * const tc9564_reset_names[] = {
> +	[RESET_ID_MAC] = "mac",
> +	[RESET_ID_XPCS] = "xpcs",
> +	[RESET_ID_PMA] = "pma",
> +};
> +
> +/**
> + * struct tc9564_data - Toshiba-specific platform data
> + * @dev:		Device pointer
> + * @ioaddr:		Pointer to mapped eMAC memory
> + * @plat:		Pointer to our stmmac platform data
> + * @resets:		Reset controller bulk array
> + * @clocks:		Clock controller bulk array
> + * @clock_count:	Number of valid elements in the clock array
> + * @config_regmap:	Regmap used to access eMAC configuration registers
> + * @emac_ctl_offset:	Offset of the eMAC control register within the regmap
> + * @res:		Structure passed to stmmac_dvr_probe()
> + * @desc:		DMA descriptor data used by mac_device_info
> + * @dma:		DMA operations data used by mac_device_info
> + */
> +struct tc9564_data {
> +	struct device *dev;
> +	void __iomem *ioaddr;
> +	struct plat_stmmacenet_data *plat;
> +	struct reset_control_bulk_data resets[ARRAY_SIZE(tc9564_reset_names)];
> +	struct clk_bulk_data *clocks;
> +	u32 clock_count;
> +
> +	struct regmap *config_regmap;
> +	u32 emac_ctl_offset;
> +
> +	/* This field is data passed to stmmac_dvr_probe() */
> +	struct stmmac_resources res;
> +
> +	/* These two fields are used by the mac_device_info structure */
> +	struct stmmac_desc_ops desc;
> +	struct stmmac_dma_ops dma;
> +};
> +
> +struct tc9564_mac_speed {
> +	phy_interface_t phy_interface;
> +	int speed;
> +	u32 sp_sel;
> +};
> +
> +static struct tc9564_mac_speed mac_speed[] = {
> +	{ PHY_INTERFACE_MODE_2500BASEX,	SPEED_2500,  SP_SEL_2500BASEX },
> +	{ PHY_INTERFACE_MODE_SGMII,	SPEED_1000,  SP_SEL_SGMII_1000M },
> +	{ PHY_INTERFACE_MODE_SGMII,	SPEED_100,   SP_SEL_SGMII_100M },
> +	{ PHY_INTERFACE_MODE_SGMII,	SPEED_10,    SP_SEL_SGMII_10M },
> +};
> +
> +/* TC9564 uses indirect addressing so this need only describe a 1KiB range */
> +static const struct regmap_config xpcs_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_base	= 0x00,		/* Minimum XPCS reg offset */
> +	.max_register	= 0xff,		/* Register DW_VR_CSR_VIEWPORT */
> +	.reg_shift	= REGMAP_UPSHIFT(2),
> +};
> +
> +/**
> + * tc9564_pma_init() - Initialize PMA
> + * @td:	bsp_priv pointer
> + *
> + * Initialize (or re-initialize) the PMA, configure the clocks and wait for the
> + * eMAC to be ready.
> + */
> +static void tc9564_pma_init(struct tc9564_data *td)
> +{
> +	struct reset_control *rstc = td->resets[RESET_ID_PMA].rstc;
> +	struct regmap *regmap = td->config_regmap;
> +	void __iomem *pmatop;
> +	u32 val;
> +	int ret;
> +	u32 i;
> +
> +	/*
> +	 * When we re-initialize the PMA then the reset will already have
> +	 * been deasserted. We must make sure the PMA reset is asserted
> +	 * before we change the clock settings.
> +	 */
> +	WARN_ON(reset_control_assert(rstc));
> +
> +	pmatop = td->res.addr + DWMAC_PMATOP_OFFSET;
> +
> +	/* Power on CML buffer (0 = normal mode, 1 = power down) */
> +	writel(0, pmatop + PMA_CML_GL_PM_CFG0);
> +
> +	/* This value switches clock from C0_REFCK to CLK_REF_I */
> +	val = u32_encode_bits(WRITE_MASK_VALUE, COMM_CFG_WRITE_MASK_MASK);
> +	val |= COMM_CFG_ENABLE;
> +	val |= u32_encode_bits(WRITE_DATA_VALUE, COMM_CFG_WRITE_DATA_MASK);
> +
> +	for (i = 0; i < PMA_REG_COUNT; i++) {
> +		u32 offset =  i * PMA_HWT_REFCK_STRIDE;
> +
> +		/* Disable C0_REFCK and 100 ohm termination */
> +		writel(0, pmatop + PMA_HWT_REFCK_R_EN + offset);
> +		writel(0, pmatop + PMA_HWT_REFCK_TERM_EN + offset);
> +
> +		/* Switch clock from C0_REFCK to CLK_REF_I */
> +		offset =  i * PMA_COMM_CFG_0_1_STRIDE;
> +		writel(val, pmatop + PMA_COMM_CFG_0_1 + offset);
> +	}
> +
> +	WARN_ON(reset_control_deassert(rstc));
> +
> +	ret = regmap_read_poll_timeout(regmap, td->emac_ctl_offset,
> +				       val, val & EMAC_INIT_DONE, 50, 1000000);
> +	WARN(ret, "timeout waiting for MAC init done\n");

This is too many WARN_ON / WARN, there's 3 just in this function. At least use
WARN_ON_ONCE, or maybe better 	print a log with pr_warn / dev_warn ?

> +}
> +
> +static int tc9564_mac_speed_select(struct tc9564_data *td,
> +				   phy_interface_t interface, int speed)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(mac_speed); i++) {
> +		if (mac_speed[i].phy_interface != interface)
> +			continue;
> +
> +		if (speed == mac_speed[i].speed || speed == SPEED_UNKNOWN)
> +			return mac_speed[i].sp_sel;
> +	}
> +	dev_err(td->dev, "%s/%d unsupported\n", phy_modes(interface), speed);

Is that "mac_speed" lookup table actually needed ? maybe a simpler switch/case
based on the speed alone would be enough, or do we really need to validate
the phy_interface_t each time ?

> +
> +	return -EOPNOTSUPP;
> +}
> +
> +static void tc9564_mac_configure(struct tc9564_data *td,
> +				 phy_interface_t interface, int speed)
> +{
> +	struct regmap *regmap = td->config_regmap;
> +	u32 offset = td->emac_ctl_offset;
> +	int sp_sel;
> +	u32 val;
> +
> +	sp_sel = tc9564_mac_speed_select(td, interface, speed);
> +	if (sp_sel < 0)
> +		return;
> +
> +	/* No error checking needed for MMIO regmap */
> +	regmap_read(regmap, offset, &val);
> +	val |= EMAC_LPIHWCLKEN;
> +	val &= ~EMAC_INV_SGM_SIG_DET;
> +	val = u32_replace_bits(val, PCS_CLK_PHY, EMAC_PHY_INF_SEL_MASK);
> +	val = u32_replace_bits(val, sp_sel, EMAC_SP_SEL_MASK);
> +	regmap_write(regmap, offset, val);
> +}
> +
> +static void tc9564_mac_enable(struct tc9564_data *td)
> +{
> +	WARN_ON(clk_bulk_prepare_enable(td->clock_count, td->clocks));
> +
> +	WARN_ON(reset_control_deassert(td->resets[RESET_ID_MAC].rstc));
> +
> +	tc9564_mac_configure(td, td->plat->phy_interface, SPEED_UNKNOWN);
> +	tc9564_pma_init(td);
> +
> +	WARN_ON(reset_control_deassert(td->resets[RESET_ID_XPCS].rstc));

Too many warns :)

> +}
> +
> +static void tc9564_mac_disable(struct tc9564_data *td)
> +{
> +	WARN_ON(reset_control_bulk_assert(ARRAY_SIZE(td->resets), td->resets));

same

Maxime


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

* Re: [PATCH net-next 3/5] net: stmmac: dwxgmac2: Add XGMAC 3.01a support
  2026-10-19  3:01 ` [PATCH net-next 3/5] net: stmmac: dwxgmac2: Add XGMAC 3.01a support Alex Elder
@ 2026-10-19  7:58   ` Maxime Chevallier
  0 siblings, 0 replies; 9+ messages in thread
From: Maxime Chevallier @ 2026-10-19  7:58 UTC (permalink / raw)
  To: Alex Elder, andrew+netdev, davem, edumazet, kuba, pabeni, robh,
	krzk+dt, conor+dt
  Cc: Daniel Thompson, mcoquelin.stm32, alexandre.torgue, hkallweit1,
	linux, richardcochran, p.zabel, peppe.cavallaro, joabreu,
	mohd.anwar, lorenzo.bianconi, netdev, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel

Hi,

On 10/19/26 05:01, Alex Elder wrote:
> From: Daniel Thompson <daniel@riscstar.com>
> 
> XGMAC 2.x and 3.x are architecturally very similar.  That means that
> for everything except one erratum we can simply use the XGMAC 2.x
> callback functions in the stmmac_dma_ops structure.
> 
> Only the set_rx_ring_len callback is specific to XGMAC 3.01.  It
> limits the number of outstanding write requests that can be serviced
> per DMA.
> 
> The other erratum addressed in this patch is simply a comment to
> ensure that a feature that stmmac doesn't currently use is not enabled
> without contemplating the errata.
> 
> Signed-off-by: Daniel Thompson <daniel@riscstar.com>
> Co-developed-by: Alex Elder <elder@riscstar.com>
> Signed-off-by: Alex Elder <elder@riscstar.com>

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

Maxime

> ---
>  .../net/ethernet/stmicro/stmmac/dwxgmac2.h    |  3 ++
>  .../ethernet/stmicro/stmmac/dwxgmac2_dma.c    | 52 +++++++++++++++++++
>  2 files changed, 55 insertions(+)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> index f8ab347f7b5b9..0fe86e9942334 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
> @@ -374,6 +374,8 @@
>  #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_OWRQ			GENMASK(25, 24)
> +#define XGMAC_RDRL			GENMASK(15, 0)
>  #define XGMAC_DMA_CH_INT_EN(x)		(0x00003138 + (0x80 * (x)))
>  #define XGMAC_NIE			BIT(15)
>  #define XGMAC_AIE			BIT(14)
> @@ -465,6 +467,7 @@
>  extern const struct stmmac_ops dwxgmac210_ops;
>  extern const struct stmmac_ops dwxlgmac2_ops;
>  extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
> +extern const struct stmmac_dma_ops dwxgmac301_dma_ops;
>  extern const struct stmmac_desc_ops dwxgmac210_desc_ops;
>  
>  #endif /* __STMMAC_DWXGMAC2_H__ */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> index ff83858ebc1f3..f9a77d641eb65 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c
> @@ -36,6 +36,13 @@ static void dwxgmac2_dma_init(void __iomem *ioaddr,
>  	 * Route DMA interrupts to per-channel lines when multi-MSI enabled.
>  	 */
>  	if (dma_cfg->multi_msi_en) {
> +		/*
> +		 * A friendly warning to future adventurers. If Descriptor Posted
> +		 * Write support, which is off by default, is ever enabled then be sure
> +		 * to make it optional. This is required by errata for at least XGMAC
> +		 * 3.01A... and the XGMAC 2.x and 3.x are architecturally similar so we
> +		 * use dwxgmac2 support for the 3.x family as well.
> +		 */
>  		value = readl(ioaddr + XGMAC_DMA_MODE);
>  		value = u32_replace_bits(value, XGMAC_INTM_MODE1,
>  					 XGMAC_INTM_MASK);
> @@ -492,6 +499,20 @@ static void dwxgmac2_set_rx_ring_len(struct stmmac_priv *priv,
>  	writel(len, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
>  }
>  
> +static void dwxgmac301_set_rx_ring_len(struct stmmac_priv *priv,
> +				       void __iomem *ioaddr, u32 len, u32 chan)
> +{
> +	u32 val = FIELD_PREP(XGMAC_RDRL, len);
> +
> +	/*
> +	 * Reduce the number of outstanding write requests to 3 (from default
> +	 * of 4). This is an errata workaround for XGMAC 3.01a.
> +	 */
> +	val |= FIELD_PREP(XGMAC_OWRQ, 3);
> +
> +	writel(val, ioaddr + XGMAC_DMA_CH_RxDESC_RING_LEN(chan));
> +}
> +
>  static void dwxgmac2_set_tx_ring_len(struct stmmac_priv *priv,
>  				     void __iomem *ioaddr, u32 len, u32 chan)
>  {
> @@ -621,3 +642,34 @@ const struct stmmac_dma_ops dwxgmac210_dma_ops = {
>  	.enable_sph = dwxgmac2_enable_sph,
>  	.enable_tbs = dwxgmac2_enable_tbs,
>  };
> +
> +/* All but one field are the same as dwxgmac210_dma_ops */
> +const struct stmmac_dma_ops dwxgmac301_dma_ops = {
> +	.reset = dwxgmac2_dma_reset,
> +	.init = dwxgmac2_dma_init,
> +	.init_chan = dwxgmac2_dma_init_chan,
> +	.init_rx_chan = dwxgmac2_dma_init_rx_chan,
> +	.init_tx_chan = dwxgmac2_dma_init_tx_chan,
> +	.axi = dwxgmac2_dma_axi,
> +	.dump_regs = dwxgmac2_dma_dump_regs,
> +	.dma_rx_mode = dwxgmac2_dma_rx_mode,
> +	.dma_tx_mode = dwxgmac2_dma_tx_mode,
> +	.enable_dma_irq = dwxgmac2_enable_dma_irq,
> +	.disable_dma_irq = dwxgmac2_disable_dma_irq,
> +	.start_tx = dwxgmac2_dma_start_tx,
> +	.stop_tx = dwxgmac2_dma_stop_tx,
> +	.start_rx = dwxgmac2_dma_start_rx,
> +	.stop_rx = dwxgmac2_dma_stop_rx,
> +	.dma_interrupt = dwxgmac2_dma_interrupt,
> +	.get_hw_feature = dwxgmac2_get_hw_feature,
> +	.rx_watchdog = dwxgmac2_rx_watchdog,
> +	.set_rx_ring_len = dwxgmac301_set_rx_ring_len,	/* Only 3.01 */
> +	.set_tx_ring_len = dwxgmac2_set_tx_ring_len,
> +	.set_rx_tail_ptr = dwxgmac2_set_rx_tail_ptr,
> +	.set_tx_tail_ptr = dwxgmac2_set_tx_tail_ptr,
> +	.enable_tso = dwxgmac2_enable_tso,
> +	.qmode = dwxgmac2_qmode,
> +	.set_bfsize = dwxgmac2_set_bfsize,
> +	.enable_sph = dwxgmac2_enable_sph,
> +	.enable_tbs = dwxgmac2_enable_tbs,
> +};



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

* Re: [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC
  2026-10-19  3:01 ` [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC Alex Elder
  2026-10-19  7:52   ` Maxime Chevallier
@ 2026-10-19  9:14   ` Mohd Ayaan Anwar
  1 sibling, 0 replies; 9+ messages in thread
From: Mohd Ayaan Anwar @ 2026-10-19  9:14 UTC (permalink / raw)
  To: Alex Elder
  Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	robh, krzk+dt, conor+dt, Daniel Thompson, mcoquelin.stm32,
	alexandre.torgue, hkallweit1, linux, richardcochran, p.zabel,
	peppe.cavallaro, joabreu, lorenzo.bianconi, netdev, devicetree,
	linux-stm32, linux-arm-kernel, linux-kernel

Hi Alex,

On Sun, Oct 18, 2026 at 10:01:28PM -0500, Alex Elder wrote:
> From: Daniel Thompson <daniel@riscstar.com>
> 
> Add support for the Ethernet XGMAC functionality present in the
> Toshiba TC9564 SoC.
> 
> The TC9564 is a fairly complex chip that attaches to a host via
> the upstream port of a PCIe switch it implements.  That switch
> has three downstream ports, and one of those has an embedded PCI
> endpoint.  The PCI endpoint implements two PCI functions, and a
> 10 Gbps-capable XGMAC interface is attached to each.
> 
> The TC9564 implements additional peripherals, and access to them
> is provided by a PCI endpoint bus associated with BAR 4 of the
> first PCI function.  A PCI driver sets up the PCI function for
> use, and peripherals using the bus use platform drivers, matched
> by compatible string.
> 
> We use the pci-ep-bus approach for the stmmac driver as well, with
> each PCI function exposing access to its BAR 4 via an endpoint bus.
> The XGMAC device is defined within a pci-ep-bus node, and is bound
> to the platform driver based on its compatible string.
> 
> Signed-off-by: Daniel Thompson <daniel@riscstar.com>
> Co-developed-by: Alex Elder <elder@riscstar.com>
> Signed-off-by: Alex Elder <elder@riscstar.com>
> ---
> ...
> +/* Fields and values for the EMACTL registers */
> +#define EMAC_SP_SEL_MASK		GENMASK(3, 0)
> +#define SP_SEL_2500BASEX		4
> +#define SP_SEL_SGMII_1000M		5
> +#define SP_SEL_SGMII_100M		6
> +#define SP_SEL_SGMII_10M		7
> +#define EMAC_PHY_INF_SEL_MASK		GENMASK(5, 4)
> +#define PCS_CLK_PHY			1	/* Clock from PHY */
> +#define EMAC_INV_SGM_SIG_DET		BIT(6)	/* 1 = polarity inverted */
> +#define EMAC_LPIHWCLKEN			BIT(8)	/* 1 = low power mode */
> +#define EMAC_INIT_DONE			BIT(21)
> +

Nit: extra tab before BIT(8) and BIT(21).

> +
> +#define PMA_HWT_REFCK_R_EN			0x1080
> +#define PMA_HWT_REFCK_TERM_EN			0x1090
> +#define PMA_HWT_REFCK_STRIDE			0x0014
> +
> +#define PMA_COMM_CFG_0_1			0x1888
> +#define PMA_COMM_CFG_0_1_STRIDE			0x0008

Nit: extra tab before 0x1090 and 0x0008.

> +
> +static int tc9564_probe_config_dt(struct tc9564_data *td)
> +{
> +	struct platform_device *pdev = to_platform_device(td->dev);
> +	struct device_node *np = td->dev->of_node;
> +	struct plat_stmmacenet_data *plat;
> +	phy_interface_t phy_interface;
> +	struct device *dev = td->dev;
> +	int ret;
> +
> +	ret = device_get_phy_mode(dev);
> +	if (ret < 0)
> +		return -ENODEV;
> +	phy_interface = ret;
> +

Nit: I think the call to devm_stmmac_probe_config_dt() will get the PHY
mode from firmware and store it in plat_dat->phy_interface so this is
probably redundant.

> +	/* The platform structure is allocated with devm_kzalloc() */
> +	plat = devm_stmmac_probe_config_dt(pdev, td->res.mac);
> +	if (IS_ERR(plat))
> +		return PTR_ERR(plat);
> +


> +static int tc9564_dwmac_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct tc9564_data *td;
> +	struct device_node *np;
> +	struct regmap *regmap;
> +	int ret;
> +
> +	td = devm_kzalloc(dev, sizeof(*td), GFP_KERNEL);
> +	if (!td)
> +		return -ENOMEM;
> +
> +	td->dev = dev;
> +
> +	np = dev_of_node(dev);
> +	regmap = syscon_regmap_lookup_by_phandle_args(np,
> +						      "toshiba,config-syscon",
> +						      1, &td->emac_ctl_offset);
> +	if (IS_ERR(regmap))
> +		return dev_err_probe(dev, PTR_ERR(regmap),
> +				     "failed to get config regmap\n");
> +	td->config_regmap = regmap;
> +
> +	ret = tc9564_reset_init(td);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to initialize resets\n");
> +
> +	ret = tc9564_clock_init(td);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to initialize clocks\n");
> +
> +	ret = tc9564_probe_config_dt(td);
> +	if (ret)
> +		return ret;
> +
> +	ret = stmmac_get_platform_resources(pdev, &td->res);
> +	if (ret)
> +		return dev_err_probe(dev, ret,
> +				     "failed to initialize stmmac resources\n");
> +
> +	tc9564_mac_enable(td);
> +
> +	ret = stmmac_dvr_probe(dev, td->plat, &td->res);
> +	if (ret) {
> +		ret = dev_err_probe(dev, ret, "failed stmmac probe\n");
> +		goto err_disable_mac;
> +	}

Nit: Could this use devm_stmmac_pltfr_probe() and drop
tc9564_dwmac_remove()?
tc9564_mac_disable() could be registered as the priv->plat->exit
callback.

> +
> +	return 0;
> +
> +err_disable_mac:
> +	tc9564_mac_disable(td);
> +
> +	return ret;
> +}
> +

	Ayaan


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

end of thread, other threads:[~2026-10-19  9:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-19  3:01 [PATCH net-next 0/5] net: stmmac: enable Toshiba TC9564 Alex Elder
2026-10-19  3:01 ` [PATCH net-next 1/5] dt-bindings: net: add support for " Alex Elder
2026-10-19  3:01 ` [PATCH net-next 2/5] net: pcs: pcs-xpcs-regmap: support XPCS memory-mapped MDIO bus via regmap Alex Elder
2026-10-19  3:01 ` [PATCH net-next 3/5] net: stmmac: dwxgmac2: Add XGMAC 3.01a support Alex Elder
2026-10-19  7:58   ` Maxime Chevallier
2026-10-19  3:01 ` [PATCH net-next 4/5] net: stmmac: dwxgmac2: export symbols for XGMAC 3.01a DMA Alex Elder
2026-10-19  3:01 ` [PATCH net-next 5/5] net: stmmac: support the TC9564 SoC Alex Elder
2026-10-19  7:52   ` Maxime Chevallier
2026-10-19  9:14   ` Mohd Ayaan Anwar

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