* [PATCH 0/4 v3] PCI: s32g: Add support for PCIe controller
@ 2025-10-22 17:43 Vincent Guittot
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
` (3 more replies)
0 siblings, 4 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-10-22 17:43 UTC (permalink / raw)
To: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx
Cc: cassel
The S32G SoC family has 2 PCIe controllers based on Designware IP.
Add the support for Host mode.
Change since v2:
- More cleanup on DT binding to comply with schemas/pci/snps,dw-pcie.yaml
- Added new reg and bit fields in pcie-designware.h
- Rename Kconfig PCIE_NXP_S32G and files to use pcie-nxp-s32g prefix
- Prefixed s32G registers with PCIE_S32G_ and use generic regs otherwise
- Use memblock_start_of_DRAM to set coherency boundary and add comments
- Fixed suspend/resume sequence by adding missing pme_turn_off function
- Added .probe_type = PROBE_PREFER_ASYNCHRONOUS to speedup probe
- Added pm_runtime_no_callbacks() as device doesn't have runtime ops
- Use writel/readl in ctrl function instead of dw_pcie_write/read
- Move Maintainer section in a dedicated entry
Change since v1:
- Cleanup DT binding
- Removed useless description and fixed typo, naming and indentation.
- Removed nxp,phy-mode binding until we agreed on a generic binding.
Default (crnss) mode is used for now. Generic binding wil be discussed
in a separate patch.
- Removed max-link-speed and num-lanes which are coming from
snps,dw-pcie-common.yaml. They are needed only if to restrict from the
the default hw config.
- Added unevaluatedProperties: false
- Keep Phys in host node until dw support Root Port node.
- Removed nxp-s32g-pcie-phy-submode.h until there is a generic clock and
spectrum binding.
- Rename files to start with pcie-s32g instead of pci-s32g
- Cleanup pcie-s32-reg.h and use dw_pcie_find_capability()
- cleanup and rename in s32g-pcie.c in addtion to remove useless check or
duplicate code.
- dw_pcie_suspend/resume_noirq() doesn't woork, need to set child device
to reach lowest state.
- Added L: imx@lists.linux.dev in MAINTAINERS
Vincent Guittot (4):
dt-bindings: PCI: s32g: Add NXP PCIe controller
PCI: dw: Add more registers and bitfield definition
PCI: s32g: Add initial PCIe support (RC)
MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver
.../bindings/pci/nxp,s32g-pcie.yaml | 102 ++++
MAINTAINERS | 9 +
drivers/pci/controller/dwc/Kconfig | 10 +
drivers/pci/controller/dwc/Makefile | 1 +
drivers/pci/controller/dwc/pcie-designware.h | 8 +
.../pci/controller/dwc/pcie-nxp-s32g-regs.h | 37 ++
drivers/pci/controller/dwc/pcie-nxp-s32g.c | 439 ++++++++++++++++++
7 files changed, 606 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g.c
--
2.43.0
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-10-22 17:43 [PATCH 0/4 v3] PCI: s32g: Add support for PCIe controller Vincent Guittot
@ 2025-10-22 17:43 ` Vincent Guittot
2025-10-22 19:17 ` Frank Li
` (2 more replies)
2025-10-22 17:43 ` [PATCH 2/4 v3] PCI: dw: Add more registers and bitfield definition Vincent Guittot
` (2 subsequent siblings)
3 siblings, 3 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-10-22 17:43 UTC (permalink / raw)
To: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx
Cc: cassel
Describe the PCIe host controller available on the S32G platforms.
Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
Co-developed-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
Signed-off-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
Co-developed-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
---
.../bindings/pci/nxp,s32g-pcie.yaml | 102 ++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
diff --git a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
new file mode 100644
index 000000000000..2d8f7ad67651
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/nxp,s32g-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP S32G2xxx/S32G3xxx PCIe Root Complex controller
+
+maintainers:
+ - Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
+ - Ionut Vicovan <ionut.vicovan@nxp.com>
+
+description:
+ This PCIe controller is based on the Synopsys DesignWare PCIe IP.
+ The S32G SoC family has two PCIe controllers, which can be configured as
+ either Root Complex or Endpoint.
+
+allOf:
+ - $ref: /schemas/pci/snps,dw-pcie.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - nxp,s32g2-pcie
+ - items:
+ - const: nxp,s32g3-pcie
+ - const: nxp,s32g2-pcie
+
+ reg:
+ maxItems: 6
+
+ reg-names:
+ items:
+ - const: dbi
+ - const: dbi2
+ - const: atu
+ - const: dma
+ - const: ctrl
+ - const: config
+
+ interrupts:
+ maxItems: 2
+
+ interrupt-names:
+ items:
+ - const: dma
+ - const: msi
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - interrupt-names
+ - ranges
+ - phys
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/phy/phy.h>
+
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ pcie@40400000 {
+ compatible = "nxp,s32g3-pcie",
+ "nxp,s32g2-pcie";
+ reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
+ <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
+ <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
+ <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
+ <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
+ <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
+ reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
+ dma-coherent;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges =
+ <0x81000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
+ <0x82000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
+ <0x82000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
+
+ bus-range = <0x0 0xff>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "dma", "msi";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0x7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &gic 0 0 GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &gic 0 0 GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
+
+ phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
+ };
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 2/4 v3] PCI: dw: Add more registers and bitfield definition
2025-10-22 17:43 [PATCH 0/4 v3] PCI: s32g: Add support for PCIe controller Vincent Guittot
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
@ 2025-10-22 17:43 ` Vincent Guittot
2025-10-22 17:43 ` [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC) Vincent Guittot
2025-10-22 17:43 ` [PATCH 4/4 v3] MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver Vincent Guittot
3 siblings, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-10-22 17:43 UTC (permalink / raw)
To: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx
Cc: cassel
Add new registers and bitfield definition:
- GEN3_RELATED_OFF_EQ_PHASE_2_3 field of GEN3_RELATED_OFF
- 3 Coherency control registers
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
---
drivers/pci/controller/dwc/pcie-designware.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index e995f692a1ec..e60b77f1b5e6 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -121,6 +121,7 @@
#define GEN3_RELATED_OFF 0x890
#define GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL BIT(0)
+#define GEN3_RELATED_OFF_EQ_PHASE_2_3 BIT(9)
#define GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS BIT(13)
#define GEN3_RELATED_OFF_GEN3_EQ_DISABLE BIT(16)
#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT 24
@@ -138,6 +139,13 @@
#define GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA GENMASK(13, 10)
#define GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA GENMASK(17, 14)
+#define COHERENCY_CONTROL_1_OFF 0x8E0
+#define CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK GENMASK(31, 2)
+#define CFG_MEMTYPE_VALUE BIT(0)
+
+#define COHERENCY_CONTROL_2_OFF 0x8E4
+#define COHERENCY_CONTROL_3_OFF 0x8E8
+
#define PCIE_PORT_MULTI_LANE_CTRL 0x8C0
#define PORT_MLTI_UPCFG_SUPPORT BIT(7)
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-22 17:43 [PATCH 0/4 v3] PCI: s32g: Add support for PCIe controller Vincent Guittot
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
2025-10-22 17:43 ` [PATCH 2/4 v3] PCI: dw: Add more registers and bitfield definition Vincent Guittot
@ 2025-10-22 17:43 ` Vincent Guittot
2025-10-22 19:04 ` Bjorn Helgaas
` (2 more replies)
2025-10-22 17:43 ` [PATCH 4/4 v3] MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver Vincent Guittot
3 siblings, 3 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-10-22 17:43 UTC (permalink / raw)
To: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx
Cc: cassel
Add initial support of the PCIe controller for S32G Soc family. Only
host mode is supported.
Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
---
drivers/pci/controller/dwc/Kconfig | 10 +
drivers/pci/controller/dwc/Makefile | 1 +
.../pci/controller/dwc/pcie-nxp-s32g-regs.h | 37 ++
drivers/pci/controller/dwc/pcie-nxp-s32g.c | 439 ++++++++++++++++++
4 files changed, 487 insertions(+)
create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g.c
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 349d4657393c..3f3172a0cd95 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -406,6 +406,16 @@ config PCIE_UNIPHIER_EP
Say Y here if you want PCIe endpoint controller support on
UniPhier SoCs. This driver supports Pro5 SoC.
+config PCIE_NXP_S32G
+ tristate "NXP S32G PCIe controller (host mode)"
+ depends on ARCH_S32 || COMPILE_TEST
+ select PCIE_DW_HOST
+ help
+ Enable support for the PCIe controller in NXP S32G based boards to
+ work in Host mode. The controller is based on DesignWare IP and
+ can work either as RC or EP. In order to enable host-specific
+ features PCIE_S32G must be selected.
+
config PCIE_SOPHGO_DW
bool "Sophgo DesignWare PCIe controller (host mode)"
depends on ARCH_SOPHGO || COMPILE_TEST
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 7ae28f3b0fb3..3301bbbad78c 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
+obj-$(CONFIG_PCIE_NXP_S32G) += pcie-nxp-s32g.o
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
new file mode 100644
index 000000000000..6f04204054dd
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2023, 2025 NXP
+ */
+
+#ifndef PCIE_S32G_REGS_H
+#define PCIE_S32G_REGS_H
+
+/* PCIe controller Sub-System */
+
+/* Link Interrupt Control And Status */
+#define PCIE_S32G_LINK_INT_CTRL_STS 0x40
+#define LINK_REQ_RST_NOT_INT_EN BIT(1)
+#define LINK_REQ_RST_NOT_CLR BIT(2)
+
+/* PCIe controller 0 General Control 1 */
+#define PCIE_S32G_PE0_GEN_CTRL_1 0x50
+#define DEVICE_TYPE_MASK GENMASK(3, 0)
+#define DEVICE_TYPE(x) FIELD_PREP(DEVICE_TYPE_MASK, x)
+#define SRIS_MODE BIT(8)
+
+/* PCIe controller 0 General Control 3 */
+#define PCIE_S32G_PE0_GEN_CTRL_3 0x58
+#define LTSSM_EN BIT(0)
+
+/* PCIe Controller 0 Transmit Message Request */
+#define PCIE_S32G_PE0_TX_MSG_REQ 0x80
+#define PME_TURN_OFF_REQ BIT(19)
+
+/* PCIe Controller 0 Link Debug 2 */
+#define PCIE_S32G_PE0_LINK_DBG_2 0xB4
+#define SMLH_LTSSM_STATE_MASK GENMASK(5, 0)
+#define SMLH_LINK_UP BIT(6)
+#define RDLH_LINK_UP BIT(7)
+
+#endif /* PCI_S32G_REGS_H */
diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
new file mode 100644
index 000000000000..53529f63c555
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
@@ -0,0 +1,439 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PCIe host controller driver for NXP S32G SoCs
+ *
+ * Copyright 2019-2025 NXP
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pci.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sizes.h>
+#include <linux/types.h>
+
+#include "pcie-designware.h"
+#include "pcie-nxp-s32g-regs.h"
+
+struct s32g_pcie {
+ struct dw_pcie pci;
+ void __iomem *ctrl_base;
+ struct phy *phy;
+};
+
+#define to_s32g_from_dw_pcie(x) \
+ container_of(x, struct s32g_pcie, pci)
+
+static void s32g_pcie_writel_ctrl(struct s32g_pcie *s32g_pp, u32 reg, u32 val)
+{
+ writel(val, s32g_pp->ctrl_base + reg);
+}
+
+static u32 s32g_pcie_readl_ctrl(struct s32g_pcie *s32g_pp, u32 reg)
+{
+ return readl(s32g_pp->ctrl_base + reg);
+}
+
+static void s32g_pcie_enable_ltssm(struct s32g_pcie *s32g_pp)
+{
+ u32 reg;
+
+ reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
+ reg |= LTSSM_EN;
+ s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
+}
+
+static void s32g_pcie_disable_ltssm(struct s32g_pcie *s32g_pp)
+{
+ u32 reg;
+
+ reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
+ reg &= ~LTSSM_EN;
+ s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
+}
+
+static bool is_s32g_pcie_ltssm_enabled(struct s32g_pcie *s32g_pp)
+{
+ return (s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3) & LTSSM_EN);
+}
+
+static enum dw_pcie_ltssm s32g_pcie_get_ltssm(struct dw_pcie *pci)
+{
+ struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
+ u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
+
+ return (enum dw_pcie_ltssm)FIELD_GET(SMLH_LTSSM_STATE_MASK, reg);
+}
+
+#define PCIE_LINKUP (SMLH_LINK_UP | RDLH_LINK_UP)
+
+static bool s32g_has_data_phy_link(struct s32g_pcie *s32g_pp)
+{
+ u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
+
+ if ((reg & PCIE_LINKUP) == PCIE_LINKUP) {
+ switch (FIELD_GET(SMLH_LTSSM_STATE_MASK, reg)) {
+ case DW_PCIE_LTSSM_L0:
+ case DW_PCIE_LTSSM_L0S:
+ case DW_PCIE_LTSSM_L1_IDLE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ return false;
+}
+
+static bool s32g_pcie_link_up(struct dw_pcie *pci)
+{
+ struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
+
+ if (!is_s32g_pcie_ltssm_enabled(s32g_pp))
+ return false;
+
+ return s32g_has_data_phy_link(s32g_pp);
+}
+
+static int s32g_pcie_start_link(struct dw_pcie *pci)
+{
+ struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
+
+ s32g_pcie_enable_ltssm(s32g_pp);
+
+ return 0;
+}
+
+static void s32g_pcie_stop_link(struct dw_pcie *pci)
+{
+ struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
+
+ s32g_pcie_disable_ltssm(s32g_pp);
+}
+
+static struct dw_pcie_ops s32g_pcie_ops = {
+ .get_ltssm = s32g_pcie_get_ltssm,
+ .link_up = s32g_pcie_link_up,
+ .start_link = s32g_pcie_start_link,
+ .stop_link = s32g_pcie_stop_link,
+};
+
+static void s32g_pcie_pme_turn_off(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
+ u32 reg;
+
+ reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ);
+ reg |= PME_TURN_OFF_REQ;
+ s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ, reg);
+}
+
+static const struct dw_pcie_host_ops s32g_pcie_host_ops = {
+ .pme_turn_off = s32g_pcie_pme_turn_off,
+};
+
+static void s32g_pcie_disable_equalization(struct dw_pcie *pci)
+{
+ u32 reg;
+
+ reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
+ reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE |
+ GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
+ reg |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_FB_MODE, 1) |
+ FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x84);
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg);
+ dw_pcie_dbi_ro_wr_dis(pci);
+}
+
+/* Configure the AMBA AXI Coherency Extensions (ACE) interface */
+static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
+{
+ u32 ddr_base_low = lower_32_bits(ddr_base_addr);
+ u32 ddr_base_high = upper_32_bits(ddr_base_addr);
+
+ dw_pcie_dbi_ro_wr_en(pci);
+ dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
+
+ /*
+ * Ncore is a cache-coherent interconnect module that enables the
+ * integration of heterogeneous coherent and non-coherent agents in
+ * the chip. Ncore Transactions to peripheral should be non-coherent
+ * or it might drop them.
+ * One example where this is needed are PCIe MSIs, which use NoSnoop=0
+ * and might end up routed to Ncore.
+ * Define the start of DDR as seen by Linux as the boundary between
+ * "memory" and "peripherals", with peripherals being below.
+ */
+ dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
+ (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));
+ dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high);
+ dw_pcie_dbi_ro_wr_dis(pci);
+}
+
+static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
+{
+ struct dw_pcie *pci = &s32g_pp->pci;
+ u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u32 val;
+
+ /* Set RP mode */
+ val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1);
+ val &= ~DEVICE_TYPE_MASK;
+ val |= DEVICE_TYPE(PCI_EXP_TYPE_ROOT_PORT);
+
+ /* Use default CRNS */
+ val &= ~SRIS_MODE;
+
+ s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val);
+
+ /* Disable phase 2,3 equalization */
+ s32g_pcie_disable_equalization(pci);
+
+ /*
+ * Make sure we use the coherency defaults (just in case the settings
+ * have been changed from their reset values)
+ */
+ s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
+
+ dw_pcie_dbi_ro_wr_en(pci);
+
+ val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
+ val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
+ dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
+
+ /*
+ * Set max payload supported, 256 bytes and
+ * relaxed ordering.
+ */
+ val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
+ val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
+ PCI_EXP_DEVCTL_PAYLOAD |
+ PCI_EXP_DEVCTL_READRQ);
+ val |= PCI_EXP_DEVCTL_RELAX_EN |
+ PCI_EXP_DEVCTL_PAYLOAD_256B |
+ PCI_EXP_DEVCTL_READRQ_256B;
+ dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+
+ /* Enable errors */
+ val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
+ val |= PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE;
+ dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+
+ val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
+ val |= GEN3_RELATED_OFF_EQ_PHASE_2_3;
+ dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
+
+ dw_pcie_dbi_ro_wr_dis(pci);
+}
+
+static int s32g_init_pcie_phy(struct s32g_pcie *s32g_pp)
+{
+ struct dw_pcie *pci = &s32g_pp->pci;
+ struct device *dev = pci->dev;
+ int ret;
+
+ ret = phy_init(s32g_pp->phy);
+ if (ret) {
+ dev_err(dev, "Failed to init serdes PHY\n");
+ return ret;
+ }
+
+ ret = phy_set_mode_ext(s32g_pp->phy, PHY_MODE_PCIE, 0);
+ if (ret) {
+ dev_err(dev, "Failed to set mode on serdes PHY\n");
+ goto err_phy_exit;
+ }
+
+ ret = phy_power_on(s32g_pp->phy);
+ if (ret) {
+ dev_err(dev, "Failed to power on serdes PHY\n");
+ goto err_phy_exit;
+ }
+
+ return 0;
+
+err_phy_exit:
+ phy_exit(s32g_pp->phy);
+ return ret;
+}
+
+static int s32g_deinit_pcie_phy(struct s32g_pcie *s32g_pp)
+{
+ struct dw_pcie *pci = &s32g_pp->pci;
+ struct device *dev = pci->dev;
+ int ret;
+
+ ret = phy_power_off(s32g_pp->phy);
+ if (ret) {
+ dev_err(dev, "Failed to power off serdes PHY\n");
+ return ret;
+ }
+
+ ret = phy_exit(s32g_pp->phy);
+ if (ret) {
+ dev_err(dev, "Failed to exit serdes PHY\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int s32g_pcie_init(struct device *dev,
+ struct s32g_pcie *s32g_pp)
+{
+ int ret;
+
+ s32g_pcie_disable_ltssm(s32g_pp);
+
+ ret = s32g_init_pcie_phy(s32g_pp);
+ if (ret)
+ return ret;
+
+ s32g_init_pcie_controller(s32g_pp);
+
+ return 0;
+}
+
+static void s32g_pcie_deinit(struct s32g_pcie *s32g_pp)
+{
+ s32g_pcie_disable_ltssm(s32g_pp);
+ s32g_deinit_pcie_phy(s32g_pp);
+}
+
+static int s32g_pcie_host_init(struct s32g_pcie *s32g_pp)
+{
+ struct dw_pcie *pci = &s32g_pp->pci;
+ struct dw_pcie_rp *pp = &pci->pp;
+ int ret;
+
+ pp->ops = &s32g_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+
+ return ret;
+}
+
+static int s32g_pcie_get_resources(struct platform_device *pdev,
+ struct s32g_pcie *s32g_pp)
+{
+ struct device *dev = &pdev->dev;
+ struct dw_pcie *pci = &s32g_pp->pci;
+
+ s32g_pp->phy = devm_phy_get(dev, NULL);
+ if (IS_ERR(s32g_pp->phy))
+ return dev_err_probe(dev, PTR_ERR(s32g_pp->phy),
+ "Failed to get serdes PHY\n");
+ s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
+ if (IS_ERR(s32g_pp->ctrl_base))
+ return PTR_ERR(s32g_pp->ctrl_base);
+
+ pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
+ if (IS_ERR(pci->dbi_base))
+ return PTR_ERR(pci->dbi_base);
+
+ pci->dev = dev;
+ pci->ops = &s32g_pcie_ops;
+
+ platform_set_drvdata(pdev, s32g_pp);
+
+ return 0;
+}
+
+static int s32g_pcie_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct s32g_pcie *s32g_pp;
+ int ret;
+
+ s32g_pp = devm_kzalloc(dev, sizeof(*s32g_pp), GFP_KERNEL);
+ if (!s32g_pp)
+ return -ENOMEM;
+
+ ret = s32g_pcie_get_resources(pdev, s32g_pp);
+ if (ret)
+ return ret;
+
+ pm_runtime_no_callbacks(dev);
+ devm_pm_runtime_enable(dev);
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ goto err_pm_runtime_put;
+
+ ret = s32g_pcie_init(dev, s32g_pp);
+ if (ret)
+ goto err_pm_runtime_put;
+
+ ret = s32g_pcie_host_init(s32g_pp);
+ if (ret)
+ goto err_pcie_deinit;
+
+ return 0;
+
+err_pcie_deinit:
+ s32g_pcie_deinit(s32g_pp);
+err_pm_runtime_put:
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static int s32g_pcie_suspend_noirq(struct device *dev)
+{
+ struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
+ struct dw_pcie *pci = &s32g_pp->pci;
+
+ if (!dw_pcie_link_up(pci))
+ return 0;
+
+ return dw_pcie_suspend_noirq(pci);
+}
+
+static int s32g_pcie_resume_noirq(struct device *dev)
+{
+ struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
+ struct dw_pcie *pci = &s32g_pp->pci;
+
+ s32g_init_pcie_controller(s32g_pp);
+
+ return dw_pcie_resume_noirq(pci);
+}
+
+static const struct dev_pm_ops s32g_pcie_pm_ops = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(s32g_pcie_suspend_noirq,
+ s32g_pcie_resume_noirq)
+};
+
+static const struct of_device_id s32g_pcie_of_match[] = {
+ { .compatible = "nxp,s32g2-pcie"},
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, s32g_pcie_of_match);
+
+static struct platform_driver s32g_pcie_driver = {
+ .driver = {
+ .name = "s32g-pcie",
+ .of_match_table = s32g_pcie_of_match,
+ .suppress_bind_attrs = true,
+ .pm = pm_sleep_ptr(&s32g_pcie_pm_ops),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .probe = s32g_pcie_probe,
+};
+
+module_platform_driver(s32g_pcie_driver);
+
+MODULE_AUTHOR("Ionut Vicovan <Ionut.Vicovan@nxp.com>");
+MODULE_DESCRIPTION("NXP S32G PCIe Host controller driver");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH 4/4 v3] MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver
2025-10-22 17:43 [PATCH 0/4 v3] PCI: s32g: Add support for PCIe controller Vincent Guittot
` (2 preceding siblings ...)
2025-10-22 17:43 ` [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC) Vincent Guittot
@ 2025-10-22 17:43 ` Vincent Guittot
2025-10-22 19:20 ` Frank Li
3 siblings, 1 reply; 30+ messages in thread
From: Vincent Guittot @ 2025-10-22 17:43 UTC (permalink / raw)
To: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx
Cc: cassel
Add a new entry for S32G PCIe driver.
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 545a4776795e..e542aae55556 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3132,6 +3132,15 @@ F: arch/arm64/boot/dts/freescale/s32g*.dts*
F: drivers/pinctrl/nxp/
F: drivers/rtc/rtc-s32g.c
+ARM/NXP S32G PCIE CONTROLLER DRIVER
+M: Ghennadi Procopciuc <ghennadi.procopciuc@oss.nxp.com>
+R: NXP S32 Linux Team <s32@nxp.com>
+L: imx@lists.linux.dev
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
+F: drivers/pci/controller/dwc/pcie-nxp-s32g*
+
ARM/NXP S32G/S32R DWMAC ETHERNET DRIVER
M: Jan Petrous <jan.petrous@oss.nxp.com>
R: s32@nxp.com
--
2.43.0
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-22 17:43 ` [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC) Vincent Guittot
@ 2025-10-22 19:04 ` Bjorn Helgaas
2025-10-24 6:50 ` Vincent Guittot
2025-10-22 19:44 ` Frank Li
2025-11-06 17:23 ` Bjorn Helgaas
2 siblings, 1 reply; 30+ messages in thread
From: Bjorn Helgaas @ 2025-10-22 19:04 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> Add initial support of the PCIe controller for S32G Soc family. Only
> host mode is supported.
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -406,6 +406,16 @@ config PCIE_UNIPHIER_EP
> Say Y here if you want PCIe endpoint controller support on
> UniPhier SoCs. This driver supports Pro5 SoC.
>
> +config PCIE_NXP_S32G
> + tristate "NXP S32G PCIe controller (host mode)"
> + depends on ARCH_S32 || COMPILE_TEST
> + select PCIE_DW_HOST
> + help
> + Enable support for the PCIe controller in NXP S32G based boards to
> + work in Host mode. The controller is based on DesignWare IP and
> + can work either as RC or EP. In order to enable host-specific
> + features PCIE_S32G must be selected.
Reorder this so the menu item is sorted by vendor name.
> +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> +/* Link Interrupt Control And Status */
> +#define PCIE_S32G_LINK_INT_CTRL_STS 0x40
> +#define LINK_REQ_RST_NOT_INT_EN BIT(1)
> +#define LINK_REQ_RST_NOT_CLR BIT(2)
None of these are used; remove until you need them.
> +/* PCIe controller 0 General Control 1 */
> +#define PCIE_S32G_PE0_GEN_CTRL_1 0x50
> +#define DEVICE_TYPE_MASK GENMASK(3, 0)
> +#define DEVICE_TYPE(x) FIELD_PREP(DEVICE_TYPE_MASK, x)
Not sure this adds much over just doing this:
#define DEVICE_TYPE GENMASK(3, 0)
val |= FIELD_PREP(DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT);
> +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> +{
> + u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> + u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> +
> + /*
> + * Ncore is a cache-coherent interconnect module that enables the
> + * integration of heterogeneous coherent and non-coherent agents in
> + * the chip. Ncore Transactions to peripheral should be non-coherent
> + * or it might drop them.
> + * One example where this is needed are PCIe MSIs, which use NoSnoop=0
> + * and might end up routed to Ncore.
> + * Define the start of DDR as seen by Linux as the boundary between
> + * "memory" and "peripherals", with peripherals being below.
Add blank lines between paragraphs.
> + */
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
> + (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +}
> +
> +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> +{
> + struct dw_pcie *pci = &s32g_pp->pci;
> + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> + u32 val;
> +
> + /* Set RP mode */
> + val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1);
> + val &= ~DEVICE_TYPE_MASK;
> + val |= DEVICE_TYPE(PCI_EXP_TYPE_ROOT_PORT);
> +
> + /* Use default CRNS */
> + val &= ~SRIS_MODE;
> +
> + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val);
> +
> + /* Disable phase 2,3 equalization */
> + s32g_pcie_disable_equalization(pci);
> +
> + /*
> + * Make sure we use the coherency defaults (just in case the settings
> + * have been changed from their reset values)
> + */
> + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
This seems sketchy and no other driver uses memblock_start_of_DRAM().
Shouldn't a physical memory address like this come from devicetree
somehow?
> + dw_pcie_dbi_ro_wr_en(pci);
> +
> + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> +
> + /*
> + * Set max payload supported, 256 bytes and
> + * relaxed ordering.
> + */
> + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> + PCI_EXP_DEVCTL_PAYLOAD |
> + PCI_EXP_DEVCTL_READRQ);
> + val |= PCI_EXP_DEVCTL_RELAX_EN |
> + PCI_EXP_DEVCTL_PAYLOAD_256B |
> + PCI_EXP_DEVCTL_READRQ_256B;
> + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
MPS and relaxed ordering should be configured by the PCI core. Is
there some s32g-specific restriction about these?
> + /* Enable errors */
> + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> + val |= PCI_EXP_DEVCTL_CERE |
> + PCI_EXP_DEVCTL_NFERE |
> + PCI_EXP_DEVCTL_FERE |
> + PCI_EXP_DEVCTL_URRE;
> + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
Enabling these errors doesn't really seem device-specific, and
pci_enable_pcie_error_reporting() would enable all these.
But that only happens with CONFIG_PCIEAER=y, and since this is
DWC-based, you probably don't have standard interrupts for AER and
CONFIG_PCIEAER isn't useful. Someday we might have support for
non-standard AER interrupts, but we don't have it yet.
I guess you get platform-specific System Errors when any of these
errors are detected (see PCIe r7.0, sec 6.2.6)? What is the handler
for these?
> +static int s32g_pcie_host_init(struct s32g_pcie *s32g_pp)
> +{
> + struct dw_pcie *pci = &s32g_pp->pci;
> + struct dw_pcie_rp *pp = &pci->pp;
> + int ret;
> +
> + pp->ops = &s32g_pcie_host_ops;
> +
> + ret = dw_pcie_host_init(pp);
> +
> + return ret;
return dw_pcie_host_init(pp);
Not sure this is really worth a wrapper.
> +static int s32g_pcie_get_resources(struct platform_device *pdev,
> + struct s32g_pcie *s32g_pp)
> +{
> + struct device *dev = &pdev->dev;
> + struct dw_pcie *pci = &s32g_pp->pci;
> +
> + s32g_pp->phy = devm_phy_get(dev, NULL);
> + if (IS_ERR(s32g_pp->phy))
> + return dev_err_probe(dev, PTR_ERR(s32g_pp->phy),
> + "Failed to get serdes PHY\n");
Add blank line here.
> + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> + if (IS_ERR(s32g_pp->ctrl_base))
> + return PTR_ERR(s32g_pp->ctrl_base);
This looks like the first DWC driver that uses a "ctrl" resource. Is
this something unique to s32g, or do other drivers have something
similar but use a different name?
> + pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
> + if (IS_ERR(pci->dbi_base))
> + return PTR_ERR(pci->dbi_base);
Isn't this already done by dw_pcie_get_resources()?
> +static int s32g_pcie_suspend_noirq(struct device *dev)
> +{
> + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> + struct dw_pcie *pci = &s32g_pp->pci;
> +
> + if (!dw_pcie_link_up(pci))
> + return 0;
Does something bad happen if you omit the link up check and the link
is not up when we get here? The check is racy (the link could go down
between dw_pcie_link_up() and dw_pcie_suspend_noirq()), so it's not
completely reliable.
If you have to check, please add a comment about why this driver needs
it when no other driver does.
> + return dw_pcie_suspend_noirq(pci);
> +}
> +
> +static int s32g_pcie_resume_noirq(struct device *dev)
> +{
> + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> + struct dw_pcie *pci = &s32g_pp->pci;
> +
> + s32g_init_pcie_controller(s32g_pp);
Odd that you need this. Other drivers really don't do anything
similar, probably because this could be done by the
pci->pp.ops->init() call in dw_pcie_resume_noirq().
> + return dw_pcie_resume_noirq(pci);
> +}
> +static const struct of_device_id s32g_pcie_of_match[] = {
> + { .compatible = "nxp,s32g2-pcie"},
Add space before "}"
> + { /* sentinel */ },
> +};
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
@ 2025-10-22 19:17 ` Frank Li
2025-10-24 6:58 ` Vincent Guittot
2025-11-06 0:00 ` Bjorn Helgaas
2025-11-06 7:12 ` Manivannan Sadhasivam
2 siblings, 1 reply; 30+ messages in thread
From: Frank Li @ 2025-10-22 19:17 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, linux-arm-kernel, linux-pci,
devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> Describe the PCIe host controller available on the S32G platforms.
>
> Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> Co-developed-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> Signed-off-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> Co-developed-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> ---
> .../bindings/pci/nxp,s32g-pcie.yaml | 102 ++++++++++++++++++
> 1 file changed, 102 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
>
> diff --git a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> new file mode 100644
> index 000000000000..2d8f7ad67651
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> @@ -0,0 +1,102 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/nxp,s32g-pcie.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NXP S32G2xxx/S32G3xxx PCIe Root Complex controller
> +
> +maintainers:
> + - Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> + - Ionut Vicovan <ionut.vicovan@nxp.com>
> +
> +description:
> + This PCIe controller is based on the Synopsys DesignWare PCIe IP.
> + The S32G SoC family has two PCIe controllers, which can be configured as
> + either Root Complex or Endpoint.
> +
> +allOf:
> + - $ref: /schemas/pci/snps,dw-pcie.yaml#
> +
> +properties:
> + compatible:
> + oneOf:
> + - enum:
> + - nxp,s32g2-pcie
> + - items:
> + - const: nxp,s32g3-pcie
> + - const: nxp,s32g2-pcie
> +
> + reg:
> + maxItems: 6
> +
> + reg-names:
> + items:
> + - const: dbi
> + - const: dbi2
> + - const: atu
> + - const: dma
> + - const: ctrl
> + - const: config
> +
> + interrupts:
> + maxItems: 2
> +
> + interrupt-names:
> + items:
> + - const: dma
> + - const: msi
Most likely dma irq is optional irq, seldom use built-in edma in RC mode.
so put msi to the first.
interrupt-names:
items:
- const: msi
- const: dma
minItems: 1
missed phys
phys:
maxItems: 1
Frank
> +
> +required:
> + - compatible
> + - reg
> + - reg-names
> + - interrupts
> + - interrupt-names
> + - ranges
> + - phys
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/phy/phy.h>
> +
> + bus {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + pcie@40400000 {
> + compatible = "nxp,s32g3-pcie",
> + "nxp,s32g2-pcie";
> + reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
> + <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
> + <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
> + <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
> + <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
> + <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
> + reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
> + dma-coherent;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges =
> + <0x81000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
> + <0x82000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
> + <0x82000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
> +
> + bus-range = <0x0 0xff>;
> + interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "dma", "msi";
> + #interrupt-cells = <1>;
> + interrupt-map-mask = <0 0 0 0x7>;
> + interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 2 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 3 &gic 0 0 GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 4 &gic 0 0 GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +
> + phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
> + };
> + };
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 4/4 v3] MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver
2025-10-22 17:43 ` [PATCH 4/4 v3] MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver Vincent Guittot
@ 2025-10-22 19:20 ` Frank Li
0 siblings, 0 replies; 30+ messages in thread
From: Frank Li @ 2025-10-22 19:20 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, linux-arm-kernel, linux-pci,
devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:09PM +0200, Vincent Guittot wrote:
> Add a new entry for S32G PCIe driver.
>
> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> MAINTAINERS | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 545a4776795e..e542aae55556 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3132,6 +3132,15 @@ F: arch/arm64/boot/dts/freescale/s32g*.dts*
> F: drivers/pinctrl/nxp/
> F: drivers/rtc/rtc-s32g.c
>
> +ARM/NXP S32G PCIE CONTROLLER DRIVER
> +M: Ghennadi Procopciuc <ghennadi.procopciuc@oss.nxp.com>
> +R: NXP S32 Linux Team <s32@nxp.com>
> +L: imx@lists.linux.dev
> +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
> +S: Maintained
> +F: Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> +F: drivers/pci/controller/dwc/pcie-nxp-s32g*
> +
> ARM/NXP S32G/S32R DWMAC ETHERNET DRIVER
> M: Jan Petrous <jan.petrous@oss.nxp.com>
> R: s32@nxp.com
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-22 17:43 ` [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC) Vincent Guittot
2025-10-22 19:04 ` Bjorn Helgaas
@ 2025-10-22 19:44 ` Frank Li
2025-10-24 6:53 ` Vincent Guittot
2025-11-06 17:23 ` Bjorn Helgaas
2 siblings, 1 reply; 30+ messages in thread
From: Frank Li @ 2025-10-22 19:44 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, linux-arm-kernel, linux-pci,
devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> Add initial support of the PCIe controller for S32G Soc family. Only
> host mode is supported.
>
> Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> ---
> drivers/pci/controller/dwc/Kconfig | 10 +
> drivers/pci/controller/dwc/Makefile | 1 +
> .../pci/controller/dwc/pcie-nxp-s32g-regs.h | 37 ++
> drivers/pci/controller/dwc/pcie-nxp-s32g.c | 439 ++++++++++++++++++
> 4 files changed, 487 insertions(+)
> create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g.c
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index 349d4657393c..3f3172a0cd95 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -406,6 +406,16 @@ config PCIE_UNIPHIER_EP
> Say Y here if you want PCIe endpoint controller support on
> UniPhier SoCs. This driver supports Pro5 SoC.
>
> +config PCIE_NXP_S32G
> + tristate "NXP S32G PCIe controller (host mode)"
> + depends on ARCH_S32 || COMPILE_TEST
> + select PCIE_DW_HOST
> + help
> + Enable support for the PCIe controller in NXP S32G based boards to
> + work in Host mode. The controller is based on DesignWare IP and
> + can work either as RC or EP. In order to enable host-specific
> + features PCIE_S32G must be selected.
> +
> config PCIE_SOPHGO_DW
> bool "Sophgo DesignWare PCIe controller (host mode)"
> depends on ARCH_SOPHGO || COMPILE_TEST
> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> index 7ae28f3b0fb3..3301bbbad78c 100644
> --- a/drivers/pci/controller/dwc/Makefile
> +++ b/drivers/pci/controller/dwc/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
> obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
> obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
> obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
> +obj-$(CONFIG_PCIE_NXP_S32G) += pcie-nxp-s32g.o
> obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
> obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
> obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
> diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> new file mode 100644
> index 000000000000..6f04204054dd
> --- /dev/null
> +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2015-2016 Freescale Semiconductor, Inc.
> + * Copyright 2016-2023, 2025 NXP
> + */
> +
> +#ifndef PCIE_S32G_REGS_H
> +#define PCIE_S32G_REGS_H
> +
> +/* PCIe controller Sub-System */
> +
> +/* Link Interrupt Control And Status */
> +#define PCIE_S32G_LINK_INT_CTRL_STS 0x40
> +#define LINK_REQ_RST_NOT_INT_EN BIT(1)
> +#define LINK_REQ_RST_NOT_CLR BIT(2)
> +
> +/* PCIe controller 0 General Control 1 */
> +#define PCIE_S32G_PE0_GEN_CTRL_1 0x50
> +#define DEVICE_TYPE_MASK GENMASK(3, 0)
> +#define DEVICE_TYPE(x) FIELD_PREP(DEVICE_TYPE_MASK, x)
> +#define SRIS_MODE BIT(8)
> +
> +/* PCIe controller 0 General Control 3 */
> +#define PCIE_S32G_PE0_GEN_CTRL_3 0x58
> +#define LTSSM_EN BIT(0)
Need S32G prefix for register field to avoid name collision.
> +
> +/* PCIe Controller 0 Transmit Message Request */
> +#define PCIE_S32G_PE0_TX_MSG_REQ 0x80
> +#define PME_TURN_OFF_REQ BIT(19)
I think needn't use customized pme_turn_off. You can use common
dw_pcie_pme_turn_off(), which use iatu map a windows to send out pcie msg.
That's fit all new version dwc controller. I think s32 should be new enough.
> +
> +/* PCIe Controller 0 Link Debug 2 */
> +#define PCIE_S32G_PE0_LINK_DBG_2 0xB4
> +#define SMLH_LTSSM_STATE_MASK GENMASK(5, 0)
> +#define SMLH_LINK_UP BIT(6)
> +#define RDLH_LINK_UP BIT(7)
> +
> +#endif /* PCI_S32G_REGS_H */
> diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> new file mode 100644
> index 000000000000..53529f63c555
> --- /dev/null
> +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> @@ -0,0 +1,439 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * PCIe host controller driver for NXP S32G SoCs
> + *
> + * Copyright 2019-2025 NXP
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/memblock.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_address.h>
> +#include <linux/pci.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/sizes.h>
> +#include <linux/types.h>
> +
> +#include "pcie-designware.h"
> +#include "pcie-nxp-s32g-regs.h"
> +
> +struct s32g_pcie {
> + struct dw_pcie pci;
> + void __iomem *ctrl_base;
> + struct phy *phy;
> +};
> +
> +#define to_s32g_from_dw_pcie(x) \
> + container_of(x, struct s32g_pcie, pci)
> +
> +static void s32g_pcie_writel_ctrl(struct s32g_pcie *s32g_pp, u32 reg, u32 val)
> +{
> + writel(val, s32g_pp->ctrl_base + reg);
> +}
> +
> +static u32 s32g_pcie_readl_ctrl(struct s32g_pcie *s32g_pp, u32 reg)
> +{
> + return readl(s32g_pp->ctrl_base + reg);
> +}
> +
> +static void s32g_pcie_enable_ltssm(struct s32g_pcie *s32g_pp)
> +{
> + u32 reg;
> +
> + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
> + reg |= LTSSM_EN;
> + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
> +}
> +
> +static void s32g_pcie_disable_ltssm(struct s32g_pcie *s32g_pp)
> +{
> + u32 reg;
> +
> + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
> + reg &= ~LTSSM_EN;
> + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
> +}
> +
> +static bool is_s32g_pcie_ltssm_enabled(struct s32g_pcie *s32g_pp)
> +{
> + return (s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3) & LTSSM_EN);
> +}
> +
> +static enum dw_pcie_ltssm s32g_pcie_get_ltssm(struct dw_pcie *pci)
> +{
> + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> + u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
> +
> + return (enum dw_pcie_ltssm)FIELD_GET(SMLH_LTSSM_STATE_MASK, reg);
> +}
Does dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); work for s32?
> +
> +#define PCIE_LINKUP (SMLH_LINK_UP | RDLH_LINK_UP)
> +
> +static bool s32g_has_data_phy_link(struct s32g_pcie *s32g_pp)
> +{
> + u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
> +
> + if ((reg & PCIE_LINKUP) == PCIE_LINKUP) {
> + switch (FIELD_GET(SMLH_LTSSM_STATE_MASK, reg)) {
> + case DW_PCIE_LTSSM_L0:
> + case DW_PCIE_LTSSM_L0S:
> + case DW_PCIE_LTSSM_L1_IDLE:
> + return true;
> + default:
> + return false;
> + }
> + }
> +
> + return false;
> +}
> +
> +static bool s32g_pcie_link_up(struct dw_pcie *pci)
> +{
> + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> +
> + if (!is_s32g_pcie_ltssm_enabled(s32g_pp))
> + return false;
> +
> + return s32g_has_data_phy_link(s32g_pp);
> +}
> +
> +static int s32g_pcie_start_link(struct dw_pcie *pci)
> +{
> + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> +
> + s32g_pcie_enable_ltssm(s32g_pp);
> +
> + return 0;
> +}
> +
> +static void s32g_pcie_stop_link(struct dw_pcie *pci)
> +{
> + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> +
> + s32g_pcie_disable_ltssm(s32g_pp);
> +}
> +
> +static struct dw_pcie_ops s32g_pcie_ops = {
> + .get_ltssm = s32g_pcie_get_ltssm,
> + .link_up = s32g_pcie_link_up,
> + .start_link = s32g_pcie_start_link,
> + .stop_link = s32g_pcie_stop_link,
> +};
> +
> +static void s32g_pcie_pme_turn_off(struct dw_pcie_rp *pp)
> +{
> + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> + u32 reg;
> +
> + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ);
> + reg |= PME_TURN_OFF_REQ;
> + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ, reg);
> +}
> +
> +static const struct dw_pcie_host_ops s32g_pcie_host_ops = {
> + .pme_turn_off = s32g_pcie_pme_turn_off,
> +};
See above comments, I think common dwc pme_turn_off() should work for s32g.
> +
> +static void s32g_pcie_disable_equalization(struct dw_pcie *pci)
> +{
> + u32 reg;
> +
> + reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> + reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE |
> + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> + reg |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_FB_MODE, 1) |
> + FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x84);
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +}
> +
> +/* Configure the AMBA AXI Coherency Extensions (ACE) interface */
> +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> +{
> + u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> + u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> +
> + /*
> + * Ncore is a cache-coherent interconnect module that enables the
> + * integration of heterogeneous coherent and non-coherent agents in
> + * the chip. Ncore Transactions to peripheral should be non-coherent
> + * or it might drop them.
> + * One example where this is needed are PCIe MSIs, which use NoSnoop=0
> + * and might end up routed to Ncore.
> + * Define the start of DDR as seen by Linux as the boundary between
> + * "memory" and "peripherals", with peripherals being below.
> + */
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
> + (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));
> + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high);
> + dw_pcie_dbi_ro_wr_dis(pci);
> +}
> +
> +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> +{
> + struct dw_pcie *pci = &s32g_pp->pci;
> + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> + u32 val;
> +
> + /* Set RP mode */
> + val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1);
> + val &= ~DEVICE_TYPE_MASK;
> + val |= DEVICE_TYPE(PCI_EXP_TYPE_ROOT_PORT);
> +
> + /* Use default CRNS */
> + val &= ~SRIS_MODE;
> +
> + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val);
> +
> + /* Disable phase 2,3 equalization */
> + s32g_pcie_disable_equalization(pci);
> +
> + /*
> + * Make sure we use the coherency defaults (just in case the settings
> + * have been changed from their reset values)
> + */
> + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> +
> + dw_pcie_dbi_ro_wr_en(pci);
> +
> + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> +
> + /*
> + * Set max payload supported, 256 bytes and
> + * relaxed ordering.
> + */
> + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> + PCI_EXP_DEVCTL_PAYLOAD |
> + PCI_EXP_DEVCTL_READRQ);
> + val |= PCI_EXP_DEVCTL_RELAX_EN |
> + PCI_EXP_DEVCTL_PAYLOAD_256B |
> + PCI_EXP_DEVCTL_READRQ_256B;
> + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> +
> + /* Enable errors */
> + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> + val |= PCI_EXP_DEVCTL_CERE |
> + PCI_EXP_DEVCTL_NFERE |
> + PCI_EXP_DEVCTL_FERE |
> + PCI_EXP_DEVCTL_URRE;
> + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> +
> + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> + val |= GEN3_RELATED_OFF_EQ_PHASE_2_3;
> + dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> +
> + dw_pcie_dbi_ro_wr_dis(pci);
> +}
> +
> +static int s32g_init_pcie_phy(struct s32g_pcie *s32g_pp)
> +{
> + struct dw_pcie *pci = &s32g_pp->pci;
> + struct device *dev = pci->dev;
> + int ret;
> +
> + ret = phy_init(s32g_pp->phy);
> + if (ret) {
> + dev_err(dev, "Failed to init serdes PHY\n");
> + return ret;
> + }
> +
> + ret = phy_set_mode_ext(s32g_pp->phy, PHY_MODE_PCIE, 0);
0 use PHY_MODE_PCIE_RC
> + if (ret) {
> + dev_err(dev, "Failed to set mode on serdes PHY\n");
> + goto err_phy_exit;
> + }
> +
> + ret = phy_power_on(s32g_pp->phy);
> + if (ret) {
> + dev_err(dev, "Failed to power on serdes PHY\n");
> + goto err_phy_exit;
> + }
> +
> + return 0;
> +
> +err_phy_exit:
> + phy_exit(s32g_pp->phy);
> + return ret;
> +}
> +
> +static int s32g_deinit_pcie_phy(struct s32g_pcie *s32g_pp)
> +{
> + struct dw_pcie *pci = &s32g_pp->pci;
> + struct device *dev = pci->dev;
> + int ret;
> +
> + ret = phy_power_off(s32g_pp->phy);
> + if (ret) {
> + dev_err(dev, "Failed to power off serdes PHY\n");
> + return ret;
> + }
> +
> + ret = phy_exit(s32g_pp->phy);
> + if (ret) {
> + dev_err(dev, "Failed to exit serdes PHY\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int s32g_pcie_init(struct device *dev,
> + struct s32g_pcie *s32g_pp)
> +{
> + int ret;
> +
> + s32g_pcie_disable_ltssm(s32g_pp);
> +
> + ret = s32g_init_pcie_phy(s32g_pp);
> + if (ret)
> + return ret;
> +
> + s32g_init_pcie_controller(s32g_pp);
> +
> + return 0;
> +}
> +
> +static void s32g_pcie_deinit(struct s32g_pcie *s32g_pp)
> +{
> + s32g_pcie_disable_ltssm(s32g_pp);
> + s32g_deinit_pcie_phy(s32g_pp);
> +}
> +
> +static int s32g_pcie_host_init(struct s32g_pcie *s32g_pp)
> +{
> + struct dw_pcie *pci = &s32g_pp->pci;
> + struct dw_pcie_rp *pp = &pci->pp;
> + int ret;
> +
> + pp->ops = &s32g_pcie_host_ops;
> +
> + ret = dw_pcie_host_init(pp);
> +
> + return ret;
> +}
> +
> +static int s32g_pcie_get_resources(struct platform_device *pdev,
> + struct s32g_pcie *s32g_pp)
> +{
> + struct device *dev = &pdev->dev;
> + struct dw_pcie *pci = &s32g_pp->pci;
> +
> + s32g_pp->phy = devm_phy_get(dev, NULL);
> + if (IS_ERR(s32g_pp->phy))
> + return dev_err_probe(dev, PTR_ERR(s32g_pp->phy),
> + "Failed to get serdes PHY\n");
> + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> + if (IS_ERR(s32g_pp->ctrl_base))
> + return PTR_ERR(s32g_pp->ctrl_base);
> +
> + pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
> + if (IS_ERR(pci->dbi_base))
> + return PTR_ERR(pci->dbi_base);
suppose dw_pcie_get_resources() already fetch dbi resource for you.
> +
> + pci->dev = dev;
> + pci->ops = &s32g_pcie_ops;
> +
> + platform_set_drvdata(pdev, s32g_pp);
> +
> + return 0;
> +}
> +
> +static int s32g_pcie_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct s32g_pcie *s32g_pp;
> + int ret;
> +
> + s32g_pp = devm_kzalloc(dev, sizeof(*s32g_pp), GFP_KERNEL);
> + if (!s32g_pp)
> + return -ENOMEM;
> +
> + ret = s32g_pcie_get_resources(pdev, s32g_pp);
> + if (ret)
> + return ret;
> +
> + pm_runtime_no_callbacks(dev);
> + devm_pm_runtime_enable(dev);
> + ret = pm_runtime_get_sync(dev);
> + if (ret < 0)
> + goto err_pm_runtime_put;
> +
> + ret = s32g_pcie_init(dev, s32g_pp);
> + if (ret)
> + goto err_pm_runtime_put;
> +
> + ret = s32g_pcie_host_init(s32g_pp);
> + if (ret)
> + goto err_pcie_deinit;
> +
> + return 0;
> +
> +err_pcie_deinit:
> + s32g_pcie_deinit(s32g_pp);
> +err_pm_runtime_put:
> + pm_runtime_put(dev);
> +
> + return ret;
> +}
> +
> +static int s32g_pcie_suspend_noirq(struct device *dev)
> +{
> + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> + struct dw_pcie *pci = &s32g_pp->pci;
> +
> + if (!dw_pcie_link_up(pci))
> + return 0;
> +
> + return dw_pcie_suspend_noirq(pci);
> +}
> +
> +static int s32g_pcie_resume_noirq(struct device *dev)
> +{
> + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> + struct dw_pcie *pci = &s32g_pp->pci;
> +
> + s32g_init_pcie_controller(s32g_pp);
I think it should belong to host_init();
Frank
> +
> + return dw_pcie_resume_noirq(pci);
> +}
> +
> +static const struct dev_pm_ops s32g_pcie_pm_ops = {
> + NOIRQ_SYSTEM_SLEEP_PM_OPS(s32g_pcie_suspend_noirq,
> + s32g_pcie_resume_noirq)
> +};
> +
> +static const struct of_device_id s32g_pcie_of_match[] = {
> + { .compatible = "nxp,s32g2-pcie"},
> + { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(of, s32g_pcie_of_match);
> +
> +static struct platform_driver s32g_pcie_driver = {
> + .driver = {
> + .name = "s32g-pcie",
> + .of_match_table = s32g_pcie_of_match,
> + .suppress_bind_attrs = true,
> + .pm = pm_sleep_ptr(&s32g_pcie_pm_ops),
> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> + },
> + .probe = s32g_pcie_probe,
> +};
> +
> +module_platform_driver(s32g_pcie_driver);
> +
> +MODULE_AUTHOR("Ionut Vicovan <Ionut.Vicovan@nxp.com>");
> +MODULE_DESCRIPTION("NXP S32G PCIe Host controller driver");
> +MODULE_LICENSE("GPL");
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-22 19:04 ` Bjorn Helgaas
@ 2025-10-24 6:50 ` Vincent Guittot
2025-11-05 10:28 ` Niklas Cassel
2025-11-06 0:05 ` Bjorn Helgaas
0 siblings, 2 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-10-24 6:50 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > Add initial support of the PCIe controller for S32G Soc family. Only
> > host mode is supported.
>
> > +++ b/drivers/pci/controller/dwc/Kconfig
> > @@ -406,6 +406,16 @@ config PCIE_UNIPHIER_EP
> > Say Y here if you want PCIe endpoint controller support on
> > UniPhier SoCs. This driver supports Pro5 SoC.
> >
> > +config PCIE_NXP_S32G
> > + tristate "NXP S32G PCIe controller (host mode)"
> > + depends on ARCH_S32 || COMPILE_TEST
> > + select PCIE_DW_HOST
> > + help
> > + Enable support for the PCIe controller in NXP S32G based boards to
> > + work in Host mode. The controller is based on DesignWare IP and
> > + can work either as RC or EP. In order to enable host-specific
> > + features PCIE_S32G must be selected.
>
> Reorder this so the menu item is sorted by vendor name.
Okay
>
> > +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
>
> > +/* Link Interrupt Control And Status */
> > +#define PCIE_S32G_LINK_INT_CTRL_STS 0x40
> > +#define LINK_REQ_RST_NOT_INT_EN BIT(1)
> > +#define LINK_REQ_RST_NOT_CLR BIT(2)
>
> None of these are used; remove until you need them.
That's a mistake and should not be in there.
>
> > +/* PCIe controller 0 General Control 1 */
> > +#define PCIE_S32G_PE0_GEN_CTRL_1 0x50
> > +#define DEVICE_TYPE_MASK GENMASK(3, 0)
> > +#define DEVICE_TYPE(x) FIELD_PREP(DEVICE_TYPE_MASK, x)
>
> Not sure this adds much over just doing this:
>
> #define DEVICE_TYPE GENMASK(3, 0)
>
> val |= FIELD_PREP(DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT);
fair enough
>
> > +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
>
> > +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> > +{
> > + u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> > + u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> > +
> > + dw_pcie_dbi_ro_wr_en(pci);
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> > +
> > + /*
> > + * Ncore is a cache-coherent interconnect module that enables the
> > + * integration of heterogeneous coherent and non-coherent agents in
> > + * the chip. Ncore Transactions to peripheral should be non-coherent
> > + * or it might drop them.
> > + * One example where this is needed are PCIe MSIs, which use NoSnoop=0
> > + * and might end up routed to Ncore.
> > + * Define the start of DDR as seen by Linux as the boundary between
> > + * "memory" and "peripherals", with peripherals being below.
>
> Add blank lines between paragraphs.
okay
>
> > + */
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
> > + (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high);
> > + dw_pcie_dbi_ro_wr_dis(pci);
> > +}
> > +
> > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > +{
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> > + u32 val;
> > +
> > + /* Set RP mode */
> > + val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1);
> > + val &= ~DEVICE_TYPE_MASK;
> > + val |= DEVICE_TYPE(PCI_EXP_TYPE_ROOT_PORT);
> > +
> > + /* Use default CRNS */
> > + val &= ~SRIS_MODE;
> > +
> > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val);
> > +
> > + /* Disable phase 2,3 equalization */
> > + s32g_pcie_disable_equalization(pci);
> > +
> > + /*
> > + * Make sure we use the coherency defaults (just in case the settings
> > + * have been changed from their reset values)
> > + */
> > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
>
> This seems sketchy and no other driver uses memblock_start_of_DRAM().
> Shouldn't a physical memory address like this come from devicetree
> somehow?
I was using DT but has been asked to not use it and was proposed to
use memblock_start_of_DRAM() instead
>
> > + dw_pcie_dbi_ro_wr_en(pci);
> > +
> > + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> > + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> > + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> > +
> > + /*
> > + * Set max payload supported, 256 bytes and
> > + * relaxed ordering.
> > + */
> > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> > + PCI_EXP_DEVCTL_PAYLOAD |
> > + PCI_EXP_DEVCTL_READRQ);
> > + val |= PCI_EXP_DEVCTL_RELAX_EN |
> > + PCI_EXP_DEVCTL_PAYLOAD_256B |
> > + PCI_EXP_DEVCTL_READRQ_256B;
> > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
>
> MPS and relaxed ordering should be configured by the PCI core. Is
> there some s32g-specific restriction about these?
I will check with the team why they did that
>
> > + /* Enable errors */
> > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > + val |= PCI_EXP_DEVCTL_CERE |
> > + PCI_EXP_DEVCTL_NFERE |
> > + PCI_EXP_DEVCTL_FERE |
> > + PCI_EXP_DEVCTL_URRE;
> > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
>
> Enabling these errors doesn't really seem device-specific, and
> pci_enable_pcie_error_reporting() would enable all these.
>
> But that only happens with CONFIG_PCIEAER=y, and since this is
> DWC-based, you probably don't have standard interrupts for AER and
> CONFIG_PCIEAER isn't useful. Someday we might have support for
> non-standard AER interrupts, but we don't have it yet.
>
> I guess you get platform-specific System Errors when any of these
> errors are detected (see PCIe r7.0, sec 6.2.6)? What is the handler
> for these?
Same has above but I suspect we can remove it
>
> > +static int s32g_pcie_host_init(struct s32g_pcie *s32g_pp)
> > +{
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > + struct dw_pcie_rp *pp = &pci->pp;
> > + int ret;
> > +
> > + pp->ops = &s32g_pcie_host_ops;
> > +
> > + ret = dw_pcie_host_init(pp);
> > +
> > + return ret;
>
> return dw_pcie_host_init(pp);
fair enough
>
> Not sure this is really worth a wrapper.
More feature will come but with init ops, i will put everything in probe for now
>
> > +static int s32g_pcie_get_resources(struct platform_device *pdev,
> > + struct s32g_pcie *s32g_pp)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > +
> > + s32g_pp->phy = devm_phy_get(dev, NULL);
> > + if (IS_ERR(s32g_pp->phy))
> > + return dev_err_probe(dev, PTR_ERR(s32g_pp->phy),
> > + "Failed to get serdes PHY\n");
>
> Add blank line here.
yes
>
> > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > + if (IS_ERR(s32g_pp->ctrl_base))
> > + return PTR_ERR(s32g_pp->ctrl_base);
>
> This looks like the first DWC driver that uses a "ctrl" resource. Is
> this something unique to s32g, or do other drivers have something
> similar but use a different name?
AFAICT this seems to be s32g specific in the RM
>
> > + pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
> > + if (IS_ERR(pci->dbi_base))
> > + return PTR_ERR(pci->dbi_base);
>
> Isn't this already done by dw_pcie_get_resources()?
We needed dbi to be mapped before dw host init but this will not be
the case anymore with ops->init()
>
> > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > +{
> > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > +
> > + if (!dw_pcie_link_up(pci))
> > + return 0;
>
> Does something bad happen if you omit the link up check and the link
> is not up when we get here? The check is racy (the link could go down
> between dw_pcie_link_up() and dw_pcie_suspend_noirq()), so it's not
> completely reliable.
>
> If you have to check, please add a comment about why this driver needs
> it when no other driver does.
dw_pcie_suspend_noirq returns an error and the suspend fails
I will add a comment
/*
* If the link is not up, there is nothing to suspend and resume
*/
>
> > + return dw_pcie_suspend_noirq(pci);
> > +}
> > +
> > +static int s32g_pcie_resume_noirq(struct device *dev)
> > +{
> > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > +
> > + s32g_init_pcie_controller(s32g_pp);
>
> Odd that you need this. Other drivers really don't do anything
> similar, probably because this could be done by the
> pci->pp.ops->init() call in dw_pcie_resume_noirq().
no reason, i misread the impact of init in dw_pcie_host_init()
>
> > + return dw_pcie_resume_noirq(pci);
> > +}
>
> > +static const struct of_device_id s32g_pcie_of_match[] = {
> > + { .compatible = "nxp,s32g2-pcie"},
>
> Add space before "}"
>
> > + { /* sentinel */ },
> > +};
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-22 19:44 ` Frank Li
@ 2025-10-24 6:53 ` Vincent Guittot
2025-11-05 7:58 ` Vincent Guittot
0 siblings, 1 reply; 30+ messages in thread
From: Vincent Guittot @ 2025-10-24 6:53 UTC (permalink / raw)
To: Frank Li
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, linux-arm-kernel, linux-pci,
devicetree, linux-kernel, imx, cassel
On Wed, 22 Oct 2025 at 21:44, Frank Li <Frank.li@nxp.com> wrote:
>
> On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > Add initial support of the PCIe controller for S32G Soc family. Only
> > host mode is supported.
> >
> > Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> > Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> > Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> > ---
> > drivers/pci/controller/dwc/Kconfig | 10 +
> > drivers/pci/controller/dwc/Makefile | 1 +
> > .../pci/controller/dwc/pcie-nxp-s32g-regs.h | 37 ++
> > drivers/pci/controller/dwc/pcie-nxp-s32g.c | 439 ++++++++++++++++++
> > 4 files changed, 487 insertions(+)
> > create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> > create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g.c
> >
> > diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> > index 349d4657393c..3f3172a0cd95 100644
> > --- a/drivers/pci/controller/dwc/Kconfig
> > +++ b/drivers/pci/controller/dwc/Kconfig
> > @@ -406,6 +406,16 @@ config PCIE_UNIPHIER_EP
> > Say Y here if you want PCIe endpoint controller support on
> > UniPhier SoCs. This driver supports Pro5 SoC.
> >
> > +config PCIE_NXP_S32G
> > + tristate "NXP S32G PCIe controller (host mode)"
> > + depends on ARCH_S32 || COMPILE_TEST
> > + select PCIE_DW_HOST
> > + help
> > + Enable support for the PCIe controller in NXP S32G based boards to
> > + work in Host mode. The controller is based on DesignWare IP and
> > + can work either as RC or EP. In order to enable host-specific
> > + features PCIE_S32G must be selected.
> > +
> > config PCIE_SOPHGO_DW
> > bool "Sophgo DesignWare PCIe controller (host mode)"
> > depends on ARCH_SOPHGO || COMPILE_TEST
> > diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> > index 7ae28f3b0fb3..3301bbbad78c 100644
> > --- a/drivers/pci/controller/dwc/Makefile
> > +++ b/drivers/pci/controller/dwc/Makefile
> > @@ -10,6 +10,7 @@ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
> > obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
> > obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
> > obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
> > +obj-$(CONFIG_PCIE_NXP_S32G) += pcie-nxp-s32g.o
> > obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
> > obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
> > obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
> > diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> > new file mode 100644
> > index 000000000000..6f04204054dd
> > --- /dev/null
> > +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> > @@ -0,0 +1,37 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ */
> > +/*
> > + * Copyright 2015-2016 Freescale Semiconductor, Inc.
> > + * Copyright 2016-2023, 2025 NXP
> > + */
> > +
> > +#ifndef PCIE_S32G_REGS_H
> > +#define PCIE_S32G_REGS_H
> > +
> > +/* PCIe controller Sub-System */
> > +
> > +/* Link Interrupt Control And Status */
> > +#define PCIE_S32G_LINK_INT_CTRL_STS 0x40
> > +#define LINK_REQ_RST_NOT_INT_EN BIT(1)
> > +#define LINK_REQ_RST_NOT_CLR BIT(2)
> > +
> > +/* PCIe controller 0 General Control 1 */
> > +#define PCIE_S32G_PE0_GEN_CTRL_1 0x50
> > +#define DEVICE_TYPE_MASK GENMASK(3, 0)
> > +#define DEVICE_TYPE(x) FIELD_PREP(DEVICE_TYPE_MASK, x)
> > +#define SRIS_MODE BIT(8)
> > +
> > +/* PCIe controller 0 General Control 3 */
> > +#define PCIE_S32G_PE0_GEN_CTRL_3 0x58
> > +#define LTSSM_EN BIT(0)
>
> Need S32G prefix for register field to avoid name collision.
I have followed what others were also doing for define ltssm_en
>
> > +
> > +/* PCIe Controller 0 Transmit Message Request */
> > +#define PCIE_S32G_PE0_TX_MSG_REQ 0x80
> > +#define PME_TURN_OFF_REQ BIT(19)
>
> I think needn't use customized pme_turn_off. You can use common
> dw_pcie_pme_turn_off(), which use iatu map a windows to send out pcie msg.
> That's fit all new version dwc controller. I think s32 should be new enough.
RM said to use this and last time that I test it failed but I will
test with the latest changes and after enabling use_atu_msg which I
didn't do last time
>
> > +
> > +/* PCIe Controller 0 Link Debug 2 */
> > +#define PCIE_S32G_PE0_LINK_DBG_2 0xB4
> > +#define SMLH_LTSSM_STATE_MASK GENMASK(5, 0)
> > +#define SMLH_LINK_UP BIT(6)
> > +#define RDLH_LINK_UP BIT(7)
> > +
> > +#endif /* PCI_S32G_REGS_H */
> > diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> > new file mode 100644
> > index 000000000000..53529f63c555
> > --- /dev/null
> > +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> > @@ -0,0 +1,439 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * PCIe host controller driver for NXP S32G SoCs
> > + *
> > + * Copyright 2019-2025 NXP
> > + */
> > +
> > +#include <linux/interrupt.h>
> > +#include <linux/io.h>
> > +#include <linux/memblock.h>
> > +#include <linux/module.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_address.h>
> > +#include <linux/pci.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/sizes.h>
> > +#include <linux/types.h>
> > +
> > +#include "pcie-designware.h"
> > +#include "pcie-nxp-s32g-regs.h"
> > +
> > +struct s32g_pcie {
> > + struct dw_pcie pci;
> > + void __iomem *ctrl_base;
> > + struct phy *phy;
> > +};
> > +
> > +#define to_s32g_from_dw_pcie(x) \
> > + container_of(x, struct s32g_pcie, pci)
> > +
> > +static void s32g_pcie_writel_ctrl(struct s32g_pcie *s32g_pp, u32 reg, u32 val)
> > +{
> > + writel(val, s32g_pp->ctrl_base + reg);
> > +}
> > +
> > +static u32 s32g_pcie_readl_ctrl(struct s32g_pcie *s32g_pp, u32 reg)
> > +{
> > + return readl(s32g_pp->ctrl_base + reg);
> > +}
> > +
> > +static void s32g_pcie_enable_ltssm(struct s32g_pcie *s32g_pp)
> > +{
> > + u32 reg;
> > +
> > + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
> > + reg |= LTSSM_EN;
> > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
> > +}
> > +
> > +static void s32g_pcie_disable_ltssm(struct s32g_pcie *s32g_pp)
> > +{
> > + u32 reg;
> > +
> > + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
> > + reg &= ~LTSSM_EN;
> > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
> > +}
> > +
> > +static bool is_s32g_pcie_ltssm_enabled(struct s32g_pcie *s32g_pp)
> > +{
> > + return (s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3) & LTSSM_EN);
> > +}
> > +
> > +static enum dw_pcie_ltssm s32g_pcie_get_ltssm(struct dw_pcie *pci)
> > +{
> > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > + u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
> > +
> > + return (enum dw_pcie_ltssm)FIELD_GET(SMLH_LTSSM_STATE_MASK, reg);
> > +}
>
> Does dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); work for s32?
I reused what has been used internally. I will check but RM only
mentioned an opaque cxpl_debug_info[31:0].
>
> > +
> > +#define PCIE_LINKUP (SMLH_LINK_UP | RDLH_LINK_UP)
> > +
> > +static bool s32g_has_data_phy_link(struct s32g_pcie *s32g_pp)
> > +{
> > + u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
> > +
> > + if ((reg & PCIE_LINKUP) == PCIE_LINKUP) {
> > + switch (FIELD_GET(SMLH_LTSSM_STATE_MASK, reg)) {
> > + case DW_PCIE_LTSSM_L0:
> > + case DW_PCIE_LTSSM_L0S:
> > + case DW_PCIE_LTSSM_L1_IDLE:
> > + return true;
> > + default:
> > + return false;
> > + }
> > + }
> > +
> > + return false;
> > +}
> > +
> > +static bool s32g_pcie_link_up(struct dw_pcie *pci)
> > +{
> > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > +
> > + if (!is_s32g_pcie_ltssm_enabled(s32g_pp))
> > + return false;
> > +
> > + return s32g_has_data_phy_link(s32g_pp);
> > +}
> > +
> > +static int s32g_pcie_start_link(struct dw_pcie *pci)
> > +{
> > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > +
> > + s32g_pcie_enable_ltssm(s32g_pp);
> > +
> > + return 0;
> > +}
> > +
> > +static void s32g_pcie_stop_link(struct dw_pcie *pci)
> > +{
> > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > +
> > + s32g_pcie_disable_ltssm(s32g_pp);
> > +}
> > +
> > +static struct dw_pcie_ops s32g_pcie_ops = {
> > + .get_ltssm = s32g_pcie_get_ltssm,
> > + .link_up = s32g_pcie_link_up,
> > + .start_link = s32g_pcie_start_link,
> > + .stop_link = s32g_pcie_stop_link,
> > +};
> > +
> > +static void s32g_pcie_pme_turn_off(struct dw_pcie_rp *pp)
> > +{
> > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > + u32 reg;
> > +
> > + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ);
> > + reg |= PME_TURN_OFF_REQ;
> > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ, reg);
> > +}
> > +
> > +static const struct dw_pcie_host_ops s32g_pcie_host_ops = {
> > + .pme_turn_off = s32g_pcie_pme_turn_off,
> > +};
>
> See above comments, I think common dwc pme_turn_off() should work for s32g.
>
> > +
> > +static void s32g_pcie_disable_equalization(struct dw_pcie *pci)
> > +{
> > + u32 reg;
> > +
> > + reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> > + reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE |
> > + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> > + reg |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_FB_MODE, 1) |
> > + FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x84);
> > +
> > + dw_pcie_dbi_ro_wr_en(pci);
> > + dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg);
> > + dw_pcie_dbi_ro_wr_dis(pci);
> > +}
> > +
> > +/* Configure the AMBA AXI Coherency Extensions (ACE) interface */
> > +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> > +{
> > + u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> > + u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> > +
> > + dw_pcie_dbi_ro_wr_en(pci);
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> > +
> > + /*
> > + * Ncore is a cache-coherent interconnect module that enables the
> > + * integration of heterogeneous coherent and non-coherent agents in
> > + * the chip. Ncore Transactions to peripheral should be non-coherent
> > + * or it might drop them.
> > + * One example where this is needed are PCIe MSIs, which use NoSnoop=0
> > + * and might end up routed to Ncore.
> > + * Define the start of DDR as seen by Linux as the boundary between
> > + * "memory" and "peripherals", with peripherals being below.
> > + */
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
> > + (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high);
> > + dw_pcie_dbi_ro_wr_dis(pci);
> > +}
> > +
> > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > +{
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> > + u32 val;
> > +
> > + /* Set RP mode */
> > + val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1);
> > + val &= ~DEVICE_TYPE_MASK;
> > + val |= DEVICE_TYPE(PCI_EXP_TYPE_ROOT_PORT);
> > +
> > + /* Use default CRNS */
> > + val &= ~SRIS_MODE;
> > +
> > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val);
> > +
> > + /* Disable phase 2,3 equalization */
> > + s32g_pcie_disable_equalization(pci);
> > +
> > + /*
> > + * Make sure we use the coherency defaults (just in case the settings
> > + * have been changed from their reset values)
> > + */
> > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> > +
> > + dw_pcie_dbi_ro_wr_en(pci);
> > +
> > + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> > + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> > + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> > +
> > + /*
> > + * Set max payload supported, 256 bytes and
> > + * relaxed ordering.
> > + */
> > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> > + PCI_EXP_DEVCTL_PAYLOAD |
> > + PCI_EXP_DEVCTL_READRQ);
> > + val |= PCI_EXP_DEVCTL_RELAX_EN |
> > + PCI_EXP_DEVCTL_PAYLOAD_256B |
> > + PCI_EXP_DEVCTL_READRQ_256B;
> > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> > +
> > + /* Enable errors */
> > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > + val |= PCI_EXP_DEVCTL_CERE |
> > + PCI_EXP_DEVCTL_NFERE |
> > + PCI_EXP_DEVCTL_FERE |
> > + PCI_EXP_DEVCTL_URRE;
> > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> > +
> > + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> > + val |= GEN3_RELATED_OFF_EQ_PHASE_2_3;
> > + dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> > +
> > + dw_pcie_dbi_ro_wr_dis(pci);
> > +}
> > +
> > +static int s32g_init_pcie_phy(struct s32g_pcie *s32g_pp)
> > +{
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > + struct device *dev = pci->dev;
> > + int ret;
> > +
> > + ret = phy_init(s32g_pp->phy);
> > + if (ret) {
> > + dev_err(dev, "Failed to init serdes PHY\n");
> > + return ret;
> > + }
> > +
> > + ret = phy_set_mode_ext(s32g_pp->phy, PHY_MODE_PCIE, 0);
>
> 0 use PHY_MODE_PCIE_RC
This is not PHY_MODE_PCIE_EP vs PHY_MODE_PCIE_RC which is set by this
driver but clock mode which is the default crns for now until we get a
generic wait to define the different
>
> > + if (ret) {
> > + dev_err(dev, "Failed to set mode on serdes PHY\n");
> > + goto err_phy_exit;
> > + }
> > +
> > + ret = phy_power_on(s32g_pp->phy);
> > + if (ret) {
> > + dev_err(dev, "Failed to power on serdes PHY\n");
> > + goto err_phy_exit;
> > + }
> > +
> > + return 0;
> > +
> > +err_phy_exit:
> > + phy_exit(s32g_pp->phy);
> > + return ret;
> > +}
> > +
> > +static int s32g_deinit_pcie_phy(struct s32g_pcie *s32g_pp)
> > +{
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > + struct device *dev = pci->dev;
> > + int ret;
> > +
> > + ret = phy_power_off(s32g_pp->phy);
> > + if (ret) {
> > + dev_err(dev, "Failed to power off serdes PHY\n");
> > + return ret;
> > + }
> > +
> > + ret = phy_exit(s32g_pp->phy);
> > + if (ret) {
> > + dev_err(dev, "Failed to exit serdes PHY\n");
> > + return ret;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int s32g_pcie_init(struct device *dev,
> > + struct s32g_pcie *s32g_pp)
> > +{
> > + int ret;
> > +
> > + s32g_pcie_disable_ltssm(s32g_pp);
> > +
> > + ret = s32g_init_pcie_phy(s32g_pp);
> > + if (ret)
> > + return ret;
> > +
> > + s32g_init_pcie_controller(s32g_pp);
> > +
> > + return 0;
> > +}
> > +
> > +static void s32g_pcie_deinit(struct s32g_pcie *s32g_pp)
> > +{
> > + s32g_pcie_disable_ltssm(s32g_pp);
> > + s32g_deinit_pcie_phy(s32g_pp);
> > +}
> > +
> > +static int s32g_pcie_host_init(struct s32g_pcie *s32g_pp)
> > +{
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > + struct dw_pcie_rp *pp = &pci->pp;
> > + int ret;
> > +
> > + pp->ops = &s32g_pcie_host_ops;
> > +
> > + ret = dw_pcie_host_init(pp);
> > +
> > + return ret;
> > +}
> > +
> > +static int s32g_pcie_get_resources(struct platform_device *pdev,
> > + struct s32g_pcie *s32g_pp)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > +
> > + s32g_pp->phy = devm_phy_get(dev, NULL);
> > + if (IS_ERR(s32g_pp->phy))
> > + return dev_err_probe(dev, PTR_ERR(s32g_pp->phy),
> > + "Failed to get serdes PHY\n");
> > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > + if (IS_ERR(s32g_pp->ctrl_base))
> > + return PTR_ERR(s32g_pp->ctrl_base);
> > +
> > + pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
> > + if (IS_ERR(pci->dbi_base))
> > + return PTR_ERR(pci->dbi_base);
>
> suppose dw_pcie_get_resources() already fetch dbi resource for you.
it will be the case now with ops->init()
>
> > +
> > + pci->dev = dev;
> > + pci->ops = &s32g_pcie_ops;
> > +
> > + platform_set_drvdata(pdev, s32g_pp);
> > +
> > + return 0;
> > +}
> > +
> > +static int s32g_pcie_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct s32g_pcie *s32g_pp;
> > + int ret;
> > +
> > + s32g_pp = devm_kzalloc(dev, sizeof(*s32g_pp), GFP_KERNEL);
> > + if (!s32g_pp)
> > + return -ENOMEM;
> > +
> > + ret = s32g_pcie_get_resources(pdev, s32g_pp);
> > + if (ret)
> > + return ret;
> > +
> > + pm_runtime_no_callbacks(dev);
> > + devm_pm_runtime_enable(dev);
> > + ret = pm_runtime_get_sync(dev);
> > + if (ret < 0)
> > + goto err_pm_runtime_put;
> > +
> > + ret = s32g_pcie_init(dev, s32g_pp);
> > + if (ret)
> > + goto err_pm_runtime_put;
> > +
> > + ret = s32g_pcie_host_init(s32g_pp);
> > + if (ret)
> > + goto err_pcie_deinit;
> > +
> > + return 0;
> > +
> > +err_pcie_deinit:
> > + s32g_pcie_deinit(s32g_pp);
> > +err_pm_runtime_put:
> > + pm_runtime_put(dev);
> > +
> > + return ret;
> > +}
> > +
> > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > +{
> > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > +
> > + if (!dw_pcie_link_up(pci))
> > + return 0;
> > +
> > + return dw_pcie_suspend_noirq(pci);
> > +}
> > +
> > +static int s32g_pcie_resume_noirq(struct device *dev)
> > +{
> > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > + struct dw_pcie *pci = &s32g_pp->pci;
> > +
> > + s32g_init_pcie_controller(s32g_pp);
>
> I think it should belong to host_init();
>
> Frank
>
> > +
> > + return dw_pcie_resume_noirq(pci);
> > +}
> > +
> > +static const struct dev_pm_ops s32g_pcie_pm_ops = {
> > + NOIRQ_SYSTEM_SLEEP_PM_OPS(s32g_pcie_suspend_noirq,
> > + s32g_pcie_resume_noirq)
> > +};
> > +
> > +static const struct of_device_id s32g_pcie_of_match[] = {
> > + { .compatible = "nxp,s32g2-pcie"},
> > + { /* sentinel */ },
> > +};
> > +MODULE_DEVICE_TABLE(of, s32g_pcie_of_match);
> > +
> > +static struct platform_driver s32g_pcie_driver = {
> > + .driver = {
> > + .name = "s32g-pcie",
> > + .of_match_table = s32g_pcie_of_match,
> > + .suppress_bind_attrs = true,
> > + .pm = pm_sleep_ptr(&s32g_pcie_pm_ops),
> > + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> > + },
> > + .probe = s32g_pcie_probe,
> > +};
> > +
> > +module_platform_driver(s32g_pcie_driver);
> > +
> > +MODULE_AUTHOR("Ionut Vicovan <Ionut.Vicovan@nxp.com>");
> > +MODULE_DESCRIPTION("NXP S32G PCIe Host controller driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-10-22 19:17 ` Frank Li
@ 2025-10-24 6:58 ` Vincent Guittot
0 siblings, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-10-24 6:58 UTC (permalink / raw)
To: Frank Li
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, linux-arm-kernel, linux-pci,
devicetree, linux-kernel, imx, cassel
On Wed, 22 Oct 2025 at 21:18, Frank Li <Frank.li@nxp.com> wrote:
>
> On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> > Describe the PCIe host controller available on the S32G platforms.
> >
> > Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > Co-developed-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> > Signed-off-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> > Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> > Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> > Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > Co-developed-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> > Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> > Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> > ---
> > .../bindings/pci/nxp,s32g-pcie.yaml | 102 ++++++++++++++++++
> > 1 file changed, 102 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> > new file mode 100644
> > index 000000000000..2d8f7ad67651
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> > @@ -0,0 +1,102 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pci/nxp,s32g-pcie.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: NXP S32G2xxx/S32G3xxx PCIe Root Complex controller
> > +
> > +maintainers:
> > + - Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> > + - Ionut Vicovan <ionut.vicovan@nxp.com>
> > +
> > +description:
> > + This PCIe controller is based on the Synopsys DesignWare PCIe IP.
> > + The S32G SoC family has two PCIe controllers, which can be configured as
> > + either Root Complex or Endpoint.
> > +
> > +allOf:
> > + - $ref: /schemas/pci/snps,dw-pcie.yaml#
> > +
> > +properties:
> > + compatible:
> > + oneOf:
> > + - enum:
> > + - nxp,s32g2-pcie
> > + - items:
> > + - const: nxp,s32g3-pcie
> > + - const: nxp,s32g2-pcie
> > +
> > + reg:
> > + maxItems: 6
> > +
> > + reg-names:
> > + items:
> > + - const: dbi
> > + - const: dbi2
> > + - const: atu
> > + - const: dma
> > + - const: ctrl
> > + - const: config
> > +
> > + interrupts:
> > + maxItems: 2
> > +
> > + interrupt-names:
> > + items:
> > + - const: dma
> > + - const: msi
>
> Most likely dma irq is optional irq, seldom use built-in edma in RC mode.
> so put msi to the first.
>
> interrupt-names:
> items:
> - const: msi
> - const: dma
> minItems: 1
>
> missed phys
>
> phys:
> maxItems: 1
okay
>
> Frank
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - reg-names
> > + - interrupts
> > + - interrupt-names
> > + - ranges
> > + - phys
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/interrupt-controller/arm-gic.h>
> > + #include <dt-bindings/phy/phy.h>
> > +
> > + bus {
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + pcie@40400000 {
> > + compatible = "nxp,s32g3-pcie",
> > + "nxp,s32g2-pcie";
> > + reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
> > + <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
> > + <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
> > + <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
> > + <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
> > + <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
> > + reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
> > + dma-coherent;
> > + #address-cells = <3>;
> > + #size-cells = <2>;
> > + device_type = "pci";
> > + ranges =
> > + <0x81000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
> > + <0x82000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
> > + <0x82000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
> > +
> > + bus-range = <0x0 0xff>;
> > + interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
> > + interrupt-names = "dma", "msi";
> > + #interrupt-cells = <1>;
> > + interrupt-map-mask = <0 0 0 0x7>;
> > + interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
> > + <0 0 0 2 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
> > + <0 0 0 3 &gic 0 0 GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
> > + <0 0 0 4 &gic 0 0 GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> > +
> > + phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
> > + };
> > + };
> > --
> > 2.43.0
> >
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-24 6:53 ` Vincent Guittot
@ 2025-11-05 7:58 ` Vincent Guittot
0 siblings, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-11-05 7:58 UTC (permalink / raw)
To: Frank Li
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, linux-arm-kernel, linux-pci,
devicetree, linux-kernel, imx, cassel
On Fri, 24 Oct 2025 at 08:53, Vincent Guittot
<vincent.guittot@linaro.org> wrote:
>
> On Wed, 22 Oct 2025 at 21:44, Frank Li <Frank.li@nxp.com> wrote:
> >
> > On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > > Add initial support of the PCIe controller for S32G Soc family. Only
> > > host mode is supported.
> > >
> > > Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > > Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > > Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > > Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > > Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > > Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > > Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> > > Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> > > Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> > > ---
> > > drivers/pci/controller/dwc/Kconfig | 10 +
> > > drivers/pci/controller/dwc/Makefile | 1 +
> > > .../pci/controller/dwc/pcie-nxp-s32g-regs.h | 37 ++
> > > drivers/pci/controller/dwc/pcie-nxp-s32g.c | 439 ++++++++++++++++++
> > > 4 files changed, 487 insertions(+)
> > > create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> > > create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g.c
> > >
> > > diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> > > index 349d4657393c..3f3172a0cd95 100644
> > > --- a/drivers/pci/controller/dwc/Kconfig
> > > +++ b/drivers/pci/controller/dwc/Kconfig
> > > @@ -406,6 +406,16 @@ config PCIE_UNIPHIER_EP
> > > Say Y here if you want PCIe endpoint controller support on
> > > UniPhier SoCs. This driver supports Pro5 SoC.
> > >
> > > +config PCIE_NXP_S32G
> > > + tristate "NXP S32G PCIe controller (host mode)"
> > > + depends on ARCH_S32 || COMPILE_TEST
> > > + select PCIE_DW_HOST
> > > + help
> > > + Enable support for the PCIe controller in NXP S32G based boards to
> > > + work in Host mode. The controller is based on DesignWare IP and
> > > + can work either as RC or EP. In order to enable host-specific
> > > + features PCIE_S32G must be selected.
> > > +
> > > config PCIE_SOPHGO_DW
> > > bool "Sophgo DesignWare PCIe controller (host mode)"
> > > depends on ARCH_SOPHGO || COMPILE_TEST
> > > diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> > > index 7ae28f3b0fb3..3301bbbad78c 100644
> > > --- a/drivers/pci/controller/dwc/Makefile
> > > +++ b/drivers/pci/controller/dwc/Makefile
> > > @@ -10,6 +10,7 @@ obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
> > > obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
> > > obj-$(CONFIG_PCIE_FU740) += pcie-fu740.o
> > > obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
> > > +obj-$(CONFIG_PCIE_NXP_S32G) += pcie-nxp-s32g.o
> > > obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
> > > obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone.o
> > > obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
> > > diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> > > new file mode 100644
> > > index 000000000000..6f04204054dd
> > > --- /dev/null
> > > +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h
> > > @@ -0,0 +1,37 @@
> > > +/* SPDX-License-Identifier: GPL-2.0+ */
> > > +/*
> > > + * Copyright 2015-2016 Freescale Semiconductor, Inc.
> > > + * Copyright 2016-2023, 2025 NXP
> > > + */
> > > +
> > > +#ifndef PCIE_S32G_REGS_H
> > > +#define PCIE_S32G_REGS_H
> > > +
> > > +/* PCIe controller Sub-System */
> > > +
> > > +/* Link Interrupt Control And Status */
> > > +#define PCIE_S32G_LINK_INT_CTRL_STS 0x40
> > > +#define LINK_REQ_RST_NOT_INT_EN BIT(1)
> > > +#define LINK_REQ_RST_NOT_CLR BIT(2)
> > > +
> > > +/* PCIe controller 0 General Control 1 */
> > > +#define PCIE_S32G_PE0_GEN_CTRL_1 0x50
> > > +#define DEVICE_TYPE_MASK GENMASK(3, 0)
> > > +#define DEVICE_TYPE(x) FIELD_PREP(DEVICE_TYPE_MASK, x)
> > > +#define SRIS_MODE BIT(8)
> > > +
> > > +/* PCIe controller 0 General Control 3 */
> > > +#define PCIE_S32G_PE0_GEN_CTRL_3 0x58
> > > +#define LTSSM_EN BIT(0)
> >
> > Need S32G prefix for register field to avoid name collision.
>
> I have followed what others were also doing for define ltssm_en
>
> >
> > > +
> > > +/* PCIe Controller 0 Transmit Message Request */
> > > +#define PCIE_S32G_PE0_TX_MSG_REQ 0x80
> > > +#define PME_TURN_OFF_REQ BIT(19)
> >
> > I think needn't use customized pme_turn_off. You can use common
> > dw_pcie_pme_turn_off(), which use iatu map a windows to send out pcie msg.
> > That's fit all new version dwc controller. I think s32 should be new enough.
>
> RM said to use this and last time that I test it failed but I will
> test with the latest changes and after enabling use_atu_msg which I
> didn't do last time
>
> >
> > > +
> > > +/* PCIe Controller 0 Link Debug 2 */
> > > +#define PCIE_S32G_PE0_LINK_DBG_2 0xB4
> > > +#define SMLH_LTSSM_STATE_MASK GENMASK(5, 0)
> > > +#define SMLH_LINK_UP BIT(6)
> > > +#define RDLH_LINK_UP BIT(7)
> > > +
> > > +#endif /* PCI_S32G_REGS_H */
> > > diff --git a/drivers/pci/controller/dwc/pcie-nxp-s32g.c b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> > > new file mode 100644
> > > index 000000000000..53529f63c555
> > > --- /dev/null
> > > +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c
> > > @@ -0,0 +1,439 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * PCIe host controller driver for NXP S32G SoCs
> > > + *
> > > + * Copyright 2019-2025 NXP
> > > + */
> > > +
> > > +#include <linux/interrupt.h>
> > > +#include <linux/io.h>
> > > +#include <linux/memblock.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/pci.h>
> > > +#include <linux/phy/phy.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/pm_runtime.h>
> > > +#include <linux/sizes.h>
> > > +#include <linux/types.h>
> > > +
> > > +#include "pcie-designware.h"
> > > +#include "pcie-nxp-s32g-regs.h"
> > > +
> > > +struct s32g_pcie {
> > > + struct dw_pcie pci;
> > > + void __iomem *ctrl_base;
> > > + struct phy *phy;
> > > +};
> > > +
> > > +#define to_s32g_from_dw_pcie(x) \
> > > + container_of(x, struct s32g_pcie, pci)
> > > +
> > > +static void s32g_pcie_writel_ctrl(struct s32g_pcie *s32g_pp, u32 reg, u32 val)
> > > +{
> > > + writel(val, s32g_pp->ctrl_base + reg);
> > > +}
> > > +
> > > +static u32 s32g_pcie_readl_ctrl(struct s32g_pcie *s32g_pp, u32 reg)
> > > +{
> > > + return readl(s32g_pp->ctrl_base + reg);
> > > +}
> > > +
> > > +static void s32g_pcie_enable_ltssm(struct s32g_pcie *s32g_pp)
> > > +{
> > > + u32 reg;
> > > +
> > > + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
> > > + reg |= LTSSM_EN;
> > > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
> > > +}
> > > +
> > > +static void s32g_pcie_disable_ltssm(struct s32g_pcie *s32g_pp)
> > > +{
> > > + u32 reg;
> > > +
> > > + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3);
> > > + reg &= ~LTSSM_EN;
> > > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3, reg);
> > > +}
> > > +
> > > +static bool is_s32g_pcie_ltssm_enabled(struct s32g_pcie *s32g_pp)
> > > +{
> > > + return (s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_3) & LTSSM_EN);
> > > +}
> > > +
> > > +static enum dw_pcie_ltssm s32g_pcie_get_ltssm(struct dw_pcie *pci)
> > > +{
> > > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > > + u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
> > > +
> > > + return (enum dw_pcie_ltssm)FIELD_GET(SMLH_LTSSM_STATE_MASK, reg);
> > > +}
> >
> > Does dw_pcie_readl_dbi(pci, PCIE_PORT_DEBUG0); work for s32?
>
> I reused what has been used internally. I will check but RM only
> mentioned an opaque cxpl_debug_info[31:0].
I'm waiting for confirmation from the team that we can use
PCIE_PORT_DEBUG0 and PCIE_PORT_DEBUG1 but I may send a new version in
the meantime with other fixes
>
> >
> > > +
> > > +#define PCIE_LINKUP (SMLH_LINK_UP | RDLH_LINK_UP)
> > > +
> > > +static bool s32g_has_data_phy_link(struct s32g_pcie *s32g_pp)
> > > +{
> > > + u32 reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_LINK_DBG_2);
> > > +
> > > + if ((reg & PCIE_LINKUP) == PCIE_LINKUP) {
> > > + switch (FIELD_GET(SMLH_LTSSM_STATE_MASK, reg)) {
> > > + case DW_PCIE_LTSSM_L0:
> > > + case DW_PCIE_LTSSM_L0S:
> > > + case DW_PCIE_LTSSM_L1_IDLE:
> > > + return true;
> > > + default:
> > > + return false;
> > > + }
> > > + }
> > > +
> > > + return false;
> > > +}
> > > +
> > > +static bool s32g_pcie_link_up(struct dw_pcie *pci)
> > > +{
> > > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > > +
> > > + if (!is_s32g_pcie_ltssm_enabled(s32g_pp))
> > > + return false;
> > > +
> > > + return s32g_has_data_phy_link(s32g_pp);
> > > +}
> > > +
> > > +static int s32g_pcie_start_link(struct dw_pcie *pci)
> > > +{
> > > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > > +
> > > + s32g_pcie_enable_ltssm(s32g_pp);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void s32g_pcie_stop_link(struct dw_pcie *pci)
> > > +{
> > > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > > +
> > > + s32g_pcie_disable_ltssm(s32g_pp);
> > > +}
> > > +
> > > +static struct dw_pcie_ops s32g_pcie_ops = {
> > > + .get_ltssm = s32g_pcie_get_ltssm,
> > > + .link_up = s32g_pcie_link_up,
> > > + .start_link = s32g_pcie_start_link,
> > > + .stop_link = s32g_pcie_stop_link,
> > > +};
> > > +
> > > +static void s32g_pcie_pme_turn_off(struct dw_pcie_rp *pp)
> > > +{
> > > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > > + struct s32g_pcie *s32g_pp = to_s32g_from_dw_pcie(pci);
> > > + u32 reg;
> > > +
> > > + reg = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ);
> > > + reg |= PME_TURN_OFF_REQ;
> > > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_TX_MSG_REQ, reg);
> > > +}
> > > +
> > > +static const struct dw_pcie_host_ops s32g_pcie_host_ops = {
> > > + .pme_turn_off = s32g_pcie_pme_turn_off,
> > > +};
> >
> > See above comments, I think common dwc pme_turn_off() should work for s32g.
> >
> > > +
> > > +static void s32g_pcie_disable_equalization(struct dw_pcie *pci)
> > > +{
> > > + u32 reg;
> > > +
> > > + reg = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> > > + reg &= ~(GEN3_EQ_CONTROL_OFF_FB_MODE |
> > > + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> > > + reg |= FIELD_PREP(GEN3_EQ_CONTROL_OFF_FB_MODE, 1) |
> > > + FIELD_PREP(GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC, 0x84);
> > > +
> > > + dw_pcie_dbi_ro_wr_en(pci);
> > > + dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, reg);
> > > + dw_pcie_dbi_ro_wr_dis(pci);
> > > +}
> > > +
> > > +/* Configure the AMBA AXI Coherency Extensions (ACE) interface */
> > > +static void s32g_pcie_reset_mstr_ace(struct dw_pcie *pci, u64 ddr_base_addr)
> > > +{
> > > + u32 ddr_base_low = lower_32_bits(ddr_base_addr);
> > > + u32 ddr_base_high = upper_32_bits(ddr_base_addr);
> > > +
> > > + dw_pcie_dbi_ro_wr_en(pci);
> > > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, 0x0);
> > > +
> > > + /*
> > > + * Ncore is a cache-coherent interconnect module that enables the
> > > + * integration of heterogeneous coherent and non-coherent agents in
> > > + * the chip. Ncore Transactions to peripheral should be non-coherent
> > > + * or it might drop them.
> > > + * One example where this is needed are PCIe MSIs, which use NoSnoop=0
> > > + * and might end up routed to Ncore.
> > > + * Define the start of DDR as seen by Linux as the boundary between
> > > + * "memory" and "peripherals", with peripherals being below.
> > > + */
> > > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_1_OFF,
> > > + (ddr_base_low & CFG_MEMTYPE_BOUNDARY_LOW_ADDR_MASK));
> > > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_2_OFF, ddr_base_high);
> > > + dw_pcie_dbi_ro_wr_dis(pci);
> > > +}
> > > +
> > > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > > +{
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > + u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> > > + u32 val;
> > > +
> > > + /* Set RP mode */
> > > + val = s32g_pcie_readl_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1);
> > > + val &= ~DEVICE_TYPE_MASK;
> > > + val |= DEVICE_TYPE(PCI_EXP_TYPE_ROOT_PORT);
> > > +
> > > + /* Use default CRNS */
> > > + val &= ~SRIS_MODE;
> > > +
> > > + s32g_pcie_writel_ctrl(s32g_pp, PCIE_S32G_PE0_GEN_CTRL_1, val);
> > > +
> > > + /* Disable phase 2,3 equalization */
> > > + s32g_pcie_disable_equalization(pci);
> > > +
> > > + /*
> > > + * Make sure we use the coherency defaults (just in case the settings
> > > + * have been changed from their reset values)
> > > + */
> > > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> > > +
> > > + dw_pcie_dbi_ro_wr_en(pci);
> > > +
> > > + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> > > + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> > > + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> > > +
> > > + /*
> > > + * Set max payload supported, 256 bytes and
> > > + * relaxed ordering.
> > > + */
> > > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > > + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> > > + PCI_EXP_DEVCTL_PAYLOAD |
> > > + PCI_EXP_DEVCTL_READRQ);
> > > + val |= PCI_EXP_DEVCTL_RELAX_EN |
> > > + PCI_EXP_DEVCTL_PAYLOAD_256B |
> > > + PCI_EXP_DEVCTL_READRQ_256B;
> > > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> > > +
> > > + /* Enable errors */
> > > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > > + val |= PCI_EXP_DEVCTL_CERE |
> > > + PCI_EXP_DEVCTL_NFERE |
> > > + PCI_EXP_DEVCTL_FERE |
> > > + PCI_EXP_DEVCTL_URRE;
> > > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> > > +
> > > + val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
> > > + val |= GEN3_RELATED_OFF_EQ_PHASE_2_3;
> > > + dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
> > > +
> > > + dw_pcie_dbi_ro_wr_dis(pci);
> > > +}
> > > +
> > > +static int s32g_init_pcie_phy(struct s32g_pcie *s32g_pp)
> > > +{
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > + struct device *dev = pci->dev;
> > > + int ret;
> > > +
> > > + ret = phy_init(s32g_pp->phy);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to init serdes PHY\n");
> > > + return ret;
> > > + }
> > > +
> > > + ret = phy_set_mode_ext(s32g_pp->phy, PHY_MODE_PCIE, 0);
> >
> > 0 use PHY_MODE_PCIE_RC
>
> This is not PHY_MODE_PCIE_EP vs PHY_MODE_PCIE_RC which is set by this
> driver but clock mode which is the default crns for now until we get a
> generic wait to define the different
>
> >
> > > + if (ret) {
> > > + dev_err(dev, "Failed to set mode on serdes PHY\n");
> > > + goto err_phy_exit;
> > > + }
> > > +
> > > + ret = phy_power_on(s32g_pp->phy);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to power on serdes PHY\n");
> > > + goto err_phy_exit;
> > > + }
> > > +
> > > + return 0;
> > > +
> > > +err_phy_exit:
> > > + phy_exit(s32g_pp->phy);
> > > + return ret;
> > > +}
> > > +
> > > +static int s32g_deinit_pcie_phy(struct s32g_pcie *s32g_pp)
> > > +{
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > + struct device *dev = pci->dev;
> > > + int ret;
> > > +
> > > + ret = phy_power_off(s32g_pp->phy);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to power off serdes PHY\n");
> > > + return ret;
> > > + }
> > > +
> > > + ret = phy_exit(s32g_pp->phy);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to exit serdes PHY\n");
> > > + return ret;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int s32g_pcie_init(struct device *dev,
> > > + struct s32g_pcie *s32g_pp)
> > > +{
> > > + int ret;
> > > +
> > > + s32g_pcie_disable_ltssm(s32g_pp);
> > > +
> > > + ret = s32g_init_pcie_phy(s32g_pp);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + s32g_init_pcie_controller(s32g_pp);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void s32g_pcie_deinit(struct s32g_pcie *s32g_pp)
> > > +{
> > > + s32g_pcie_disable_ltssm(s32g_pp);
> > > + s32g_deinit_pcie_phy(s32g_pp);
> > > +}
> > > +
> > > +static int s32g_pcie_host_init(struct s32g_pcie *s32g_pp)
> > > +{
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > + struct dw_pcie_rp *pp = &pci->pp;
> > > + int ret;
> > > +
> > > + pp->ops = &s32g_pcie_host_ops;
> > > +
> > > + ret = dw_pcie_host_init(pp);
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +static int s32g_pcie_get_resources(struct platform_device *pdev,
> > > + struct s32g_pcie *s32g_pp)
> > > +{
> > > + struct device *dev = &pdev->dev;
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > +
> > > + s32g_pp->phy = devm_phy_get(dev, NULL);
> > > + if (IS_ERR(s32g_pp->phy))
> > > + return dev_err_probe(dev, PTR_ERR(s32g_pp->phy),
> > > + "Failed to get serdes PHY\n");
> > > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > > + if (IS_ERR(s32g_pp->ctrl_base))
> > > + return PTR_ERR(s32g_pp->ctrl_base);
> > > +
> > > + pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
> > > + if (IS_ERR(pci->dbi_base))
> > > + return PTR_ERR(pci->dbi_base);
> >
> > suppose dw_pcie_get_resources() already fetch dbi resource for you.
>
> it will be the case now with ops->init()
>
>
>
> >
> > > +
> > > + pci->dev = dev;
> > > + pci->ops = &s32g_pcie_ops;
> > > +
> > > + platform_set_drvdata(pdev, s32g_pp);
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int s32g_pcie_probe(struct platform_device *pdev)
> > > +{
> > > + struct device *dev = &pdev->dev;
> > > + struct s32g_pcie *s32g_pp;
> > > + int ret;
> > > +
> > > + s32g_pp = devm_kzalloc(dev, sizeof(*s32g_pp), GFP_KERNEL);
> > > + if (!s32g_pp)
> > > + return -ENOMEM;
> > > +
> > > + ret = s32g_pcie_get_resources(pdev, s32g_pp);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + pm_runtime_no_callbacks(dev);
> > > + devm_pm_runtime_enable(dev);
> > > + ret = pm_runtime_get_sync(dev);
> > > + if (ret < 0)
> > > + goto err_pm_runtime_put;
> > > +
> > > + ret = s32g_pcie_init(dev, s32g_pp);
> > > + if (ret)
> > > + goto err_pm_runtime_put;
> > > +
> > > + ret = s32g_pcie_host_init(s32g_pp);
> > > + if (ret)
> > > + goto err_pcie_deinit;
> > > +
> > > + return 0;
> > > +
> > > +err_pcie_deinit:
> > > + s32g_pcie_deinit(s32g_pp);
> > > +err_pm_runtime_put:
> > > + pm_runtime_put(dev);
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > > +{
> > > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > +
> > > + if (!dw_pcie_link_up(pci))
> > > + return 0;
> > > +
> > > + return dw_pcie_suspend_noirq(pci);
> > > +}
> > > +
> > > +static int s32g_pcie_resume_noirq(struct device *dev)
> > > +{
> > > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > +
> > > + s32g_init_pcie_controller(s32g_pp);
> >
> > I think it should belong to host_init();
> >
> > Frank
> >
> > > +
> > > + return dw_pcie_resume_noirq(pci);
> > > +}
> > > +
> > > +static const struct dev_pm_ops s32g_pcie_pm_ops = {
> > > + NOIRQ_SYSTEM_SLEEP_PM_OPS(s32g_pcie_suspend_noirq,
> > > + s32g_pcie_resume_noirq)
> > > +};
> > > +
> > > +static const struct of_device_id s32g_pcie_of_match[] = {
> > > + { .compatible = "nxp,s32g2-pcie"},
> > > + { /* sentinel */ },
> > > +};
> > > +MODULE_DEVICE_TABLE(of, s32g_pcie_of_match);
> > > +
> > > +static struct platform_driver s32g_pcie_driver = {
> > > + .driver = {
> > > + .name = "s32g-pcie",
> > > + .of_match_table = s32g_pcie_of_match,
> > > + .suppress_bind_attrs = true,
> > > + .pm = pm_sleep_ptr(&s32g_pcie_pm_ops),
> > > + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> > > + },
> > > + .probe = s32g_pcie_probe,
> > > +};
> > > +
> > > +module_platform_driver(s32g_pcie_driver);
> > > +
> > > +MODULE_AUTHOR("Ionut Vicovan <Ionut.Vicovan@nxp.com>");
> > > +MODULE_DESCRIPTION("NXP S32G PCIe Host controller driver");
> > > +MODULE_LICENSE("GPL");
> > > --
> > > 2.43.0
> > >
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-24 6:50 ` Vincent Guittot
@ 2025-11-05 10:28 ` Niklas Cassel
2025-11-05 10:43 ` Ilpo Järvinen
2025-11-06 0:05 ` Bjorn Helgaas
1 sibling, 1 reply; 30+ messages in thread
From: Niklas Cassel @ 2025-11-05 10:28 UTC (permalink / raw)
To: Vincent Guittot
Cc: Bjorn Helgaas, chester62515, mbrugger, ghennadi.procopciuc, s32,
bhelgaas, jingoohan1, lpieralisi, kwilczynski, mani, robh,
krzk+dt, conor+dt, Ionut.Vicovan, larisa.grigore,
Ghennadi.Procopciuc, ciprianmarian.costea, bogdan.hamciuc,
Frank.li, linux-arm-kernel, linux-pci, devicetree, linux-kernel,
imx
On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > > + dw_pcie_dbi_ro_wr_en(pci);
> > > +
> > > + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> > > + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> > > + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> > > +
> > > + /*
> > > + * Set max payload supported, 256 bytes and
> > > + * relaxed ordering.
> > > + */
> > > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > > + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> > > + PCI_EXP_DEVCTL_PAYLOAD |
> > > + PCI_EXP_DEVCTL_READRQ);
> > > + val |= PCI_EXP_DEVCTL_RELAX_EN |
> > > + PCI_EXP_DEVCTL_PAYLOAD_256B |
> > > + PCI_EXP_DEVCTL_READRQ_256B;
> > > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> >
> > MPS and relaxed ordering should be configured by the PCI core. Is
> > there some s32g-specific restriction about these?
>
> I will check with the team why they did that
Most likely, the reason is that, the PCI core does not set the MPS to the
maximum supported MPS for the root port.
So without that change, the port will use use 128B instead of 256B.
I assume that you should be able to drop (at least the MPS part) if this
change gets accepted:
https://lore.kernel.org/linux-pci/20251104165125.174168-1-18255117159@163.com/
Kind regards,
Niklas
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-05 10:28 ` Niklas Cassel
@ 2025-11-05 10:43 ` Ilpo Järvinen
2025-11-05 11:00 ` Niklas Cassel
0 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2025-11-05 10:43 UTC (permalink / raw)
To: Niklas Cassel
Cc: Vincent Guittot, Bjorn Helgaas, chester62515, mbrugger,
ghennadi.procopciuc, s32, bhelgaas, jingoohan1, lpieralisi,
kwilczynski, mani, robh, krzk+dt, conor+dt, Ionut.Vicovan,
larisa.grigore, Ghennadi.Procopciuc, ciprianmarian.costea,
bogdan.hamciuc, Frank.li, linux-arm-kernel, linux-pci, devicetree,
LKML, imx
On Wed, 5 Nov 2025, Niklas Cassel wrote:
> On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> > On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > > > + dw_pcie_dbi_ro_wr_en(pci);
> > > > +
> > > > + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> > > > + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> > > > + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> > > > +
> > > > + /*
> > > > + * Set max payload supported, 256 bytes and
> > > > + * relaxed ordering.
> > > > + */
> > > > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > > > + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> > > > + PCI_EXP_DEVCTL_PAYLOAD |
> > > > + PCI_EXP_DEVCTL_READRQ);
> > > > + val |= PCI_EXP_DEVCTL_RELAX_EN |
> > > > + PCI_EXP_DEVCTL_PAYLOAD_256B |
> > > > + PCI_EXP_DEVCTL_READRQ_256B;
> > > > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> > >
> > > MPS and relaxed ordering should be configured by the PCI core. Is
> > > there some s32g-specific restriction about these?
> >
> > I will check with the team why they did that
>
> Most likely, the reason is that, the PCI core does not set the MPS to the
> maximum supported MPS for the root port.
PCI core set/doesn't set MPS based on config. Perhaps try with
CONFIG_PCIE_BUS_PERFORMANCE.
> So without that change, the port will use use 128B instead of 256B.
>
> I assume that you should be able to drop (at least the MPS part) if this
> change gets accepted:
> https://lore.kernel.org/linux-pci/20251104165125.174168-1-18255117159@163.com/
>
>
> Kind regards,
> Niklas
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-05 10:43 ` Ilpo Järvinen
@ 2025-11-05 11:00 ` Niklas Cassel
0 siblings, 0 replies; 30+ messages in thread
From: Niklas Cassel @ 2025-11-05 11:00 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Vincent Guittot, Bjorn Helgaas, chester62515, mbrugger,
ghennadi.procopciuc, s32, bhelgaas, jingoohan1, lpieralisi,
kwilczynski, mani, robh, krzk+dt, conor+dt, Ionut.Vicovan,
larisa.grigore, Ghennadi.Procopciuc, ciprianmarian.costea,
bogdan.hamciuc, Frank.li, linux-arm-kernel, linux-pci, devicetree,
LKML, imx
On Wed, Nov 05, 2025 at 12:43:09PM +0200, Ilpo Järvinen wrote:
> On Wed, 5 Nov 2025, Niklas Cassel wrote:
>
> > On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> > > On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > > > > + dw_pcie_dbi_ro_wr_en(pci);
> > > > > +
> > > > > + val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
> > > > > + val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
> > > > > + dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);
> > > > > +
> > > > > + /*
> > > > > + * Set max payload supported, 256 bytes and
> > > > > + * relaxed ordering.
> > > > > + */
> > > > > + val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
> > > > > + val &= ~(PCI_EXP_DEVCTL_RELAX_EN |
> > > > > + PCI_EXP_DEVCTL_PAYLOAD |
> > > > > + PCI_EXP_DEVCTL_READRQ);
> > > > > + val |= PCI_EXP_DEVCTL_RELAX_EN |
> > > > > + PCI_EXP_DEVCTL_PAYLOAD_256B |
> > > > > + PCI_EXP_DEVCTL_READRQ_256B;
> > > > > + dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
> > > >
> > > > MPS and relaxed ordering should be configured by the PCI core. Is
> > > > there some s32g-specific restriction about these?
> > >
> > > I will check with the team why they did that
> >
> > Most likely, the reason is that, the PCI core does not set the MPS to the
> > maximum supported MPS for the root port.
>
> PCI core set/doesn't set MPS based on config. Perhaps try with
> CONFIG_PCIE_BUS_PERFORMANCE.
Sorry, I should have been more clear.
Since a lot of PCIe controller drivers have similar code to the above,
it is obvious that a lot of controller drivers want to increase the MPS
regardless of PCIE_BUS_* bus config value.
With the current PCI code, MPS for root ports will not be touched if
PCIE_BUS_TUNE_OFF or PCIE_BUS_DEFAULT.
After the above series, MPS for root ports will be set to max supported
also for PCIE_BUS_DEFAULT.
Kind regards,
Niklas
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
2025-10-22 19:17 ` Frank Li
@ 2025-11-06 0:00 ` Bjorn Helgaas
2025-11-06 7:51 ` Vincent Guittot
2025-11-06 7:12 ` Manivannan Sadhasivam
2 siblings, 1 reply; 30+ messages in thread
From: Bjorn Helgaas @ 2025-11-06 0:00 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> Describe the PCIe host controller available on the S32G platforms.
> + reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
> + <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
> + <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
> + <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
> + <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
> + <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
Fix comment alignment.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-24 6:50 ` Vincent Guittot
2025-11-05 10:28 ` Niklas Cassel
@ 2025-11-06 0:05 ` Bjorn Helgaas
2025-11-06 6:24 ` Manivannan Sadhasivam
2025-11-06 7:46 ` Vincent Guittot
1 sibling, 2 replies; 30+ messages in thread
From: Bjorn Helgaas @ 2025-11-06 0:05 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel, Richard Zhu,
Lucas Stach, Minghuan Lian, Mingkai Hu, Roy Zang, Christian Bruel,
linux-stm32
[+cc imx6, layerscape, stm32 maintainers for possible suspend bug]
On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > > Add initial support of the PCIe controller for S32G Soc family. Only
> > > host mode is supported.
> > > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > > +{
> > > ...
> > > + /*
> > > + * Make sure we use the coherency defaults (just in case the settings
> > > + * have been changed from their reset values)
> > > + */
> > > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> >
> > This seems sketchy and no other driver uses memblock_start_of_DRAM().
> > Shouldn't a physical memory address like this come from devicetree
> > somehow?
>
> I was using DT but has been asked to not use it and was proposed to
> use memblock_start_of_DRAM() instead
Can you point me to that conversation?
> > > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > > + if (IS_ERR(s32g_pp->ctrl_base))
> > > + return PTR_ERR(s32g_pp->ctrl_base);
> >
> > This looks like the first DWC driver that uses a "ctrl" resource. Is
> > this something unique to s32g, or do other drivers have something
> > similar but use a different name?
>
> AFAICT this seems to be s32g specific in the RM
It does look like there's very little consistency in reg-names across
drivers, so I guess it's fine.
> > > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > > +{
> > > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > +
> > > + if (!dw_pcie_link_up(pci))
> > > + return 0;
> >
> > Does something bad happen if you omit the link up check and the link
> > is not up when we get here? The check is racy (the link could go down
> > between dw_pcie_link_up() and dw_pcie_suspend_noirq()), so it's not
> > completely reliable.
> >
> > If you have to check, please add a comment about why this driver needs
> > it when no other driver does.
>
> dw_pcie_suspend_noirq returns an error and the suspend fails
The implication is that *every* user of dw_pcie_suspend_noirq() would
have to check for the link being up. There are only three existing
callers:
imx_pcie_suspend_noirq()
ls_pcie_suspend_noirq()
stm32_pcie_suspend_noirq()
but none of them checks for the link being up.
> I will add a comment
> /*
> * If the link is not up, there is nothing to suspend and resume
Sometimes true, but still racy as I mentioned, and doesn't explain why
s32g is different from imx, ls, and stm32.
> > > + return dw_pcie_suspend_noirq(pci);
> > > +}
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-06 0:05 ` Bjorn Helgaas
@ 2025-11-06 6:24 ` Manivannan Sadhasivam
2025-11-06 7:50 ` Vincent Guittot
2025-11-14 10:05 ` Christian Bruel
2025-11-06 7:46 ` Vincent Guittot
1 sibling, 2 replies; 30+ messages in thread
From: Manivannan Sadhasivam @ 2025-11-06 6:24 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Vincent Guittot, chester62515, mbrugger, ghennadi.procopciuc, s32,
bhelgaas, jingoohan1, lpieralisi, kwilczynski, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel, Richard Zhu,
Lucas Stach, Minghuan Lian, Mingkai Hu, Roy Zang, Christian Bruel,
linux-stm32
On Wed, Nov 05, 2025 at 06:05:31PM -0600, Bjorn Helgaas wrote:
> [+cc imx6, layerscape, stm32 maintainers for possible suspend bug]
>
> On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> > On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > > On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > > > Add initial support of the PCIe controller for S32G Soc family. Only
> > > > host mode is supported.
>
> > > > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > > > +{
> > > > ...
> > > > + /*
> > > > + * Make sure we use the coherency defaults (just in case the settings
> > > > + * have been changed from their reset values)
> > > > + */
> > > > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> > >
> > > This seems sketchy and no other driver uses memblock_start_of_DRAM().
> > > Shouldn't a physical memory address like this come from devicetree
> > > somehow?
> >
> > I was using DT but has been asked to not use it and was proposed to
> > use memblock_start_of_DRAM() instead
>
> Can you point me to that conversation?
>
> > > > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > > > + if (IS_ERR(s32g_pp->ctrl_base))
> > > > + return PTR_ERR(s32g_pp->ctrl_base);
> > >
> > > This looks like the first DWC driver that uses a "ctrl" resource. Is
> > > this something unique to s32g, or do other drivers have something
> > > similar but use a different name?
> >
> > AFAICT this seems to be s32g specific in the RM
>
> It does look like there's very little consistency in reg-names across
> drivers, so I guess it's fine.
>
> > > > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > > > +{
> > > > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > > +
> > > > + if (!dw_pcie_link_up(pci))
> > > > + return 0;
> > >
> > > Does something bad happen if you omit the link up check and the link
> > > is not up when we get here? The check is racy (the link could go down
> > > between dw_pcie_link_up() and dw_pcie_suspend_noirq()), so it's not
> > > completely reliable.
> > >
> > > If you have to check, please add a comment about why this driver needs
> > > it when no other driver does.
> >
> > dw_pcie_suspend_noirq returns an error and the suspend fails
>
> The implication is that *every* user of dw_pcie_suspend_noirq() would
> have to check for the link being up. There are only three existing
> callers:
>
> imx_pcie_suspend_noirq()
> ls_pcie_suspend_noirq()
> stm32_pcie_suspend_noirq()
>
> but none of them checks for the link being up.
>
If no devices are attached to the bus, then there is no need to broadcast
PME_Turn_Off and wait for L2/L3. I've just sent out a series that fixes it [1].
Hopefully, this will allow Vincent to use dw_pcie_{suspend/resume}_noirq() APIs.
- Mani
[1] https://lore.kernel.org/linux-pci/20251106061326.8241-1-manivannan.sadhasivam@oss.qualcomm.com/
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
2025-10-22 19:17 ` Frank Li
2025-11-06 0:00 ` Bjorn Helgaas
@ 2025-11-06 7:12 ` Manivannan Sadhasivam
2025-11-06 8:09 ` Vincent Guittot
2 siblings, 1 reply; 30+ messages in thread
From: Manivannan Sadhasivam @ 2025-11-06 7:12 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> Describe the PCIe host controller available on the S32G platforms.
>
> Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> Co-developed-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> Signed-off-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> Co-developed-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> ---
> .../bindings/pci/nxp,s32g-pcie.yaml | 102 ++++++++++++++++++
> 1 file changed, 102 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
>
> diff --git a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> new file mode 100644
> index 000000000000..2d8f7ad67651
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> @@ -0,0 +1,102 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/nxp,s32g-pcie.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NXP S32G2xxx/S32G3xxx PCIe Root Complex controller
> +
> +maintainers:
> + - Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> + - Ionut Vicovan <ionut.vicovan@nxp.com>
> +
> +description:
> + This PCIe controller is based on the Synopsys DesignWare PCIe IP.
> + The S32G SoC family has two PCIe controllers, which can be configured as
> + either Root Complex or Endpoint.
> +
> +allOf:
> + - $ref: /schemas/pci/snps,dw-pcie.yaml#
> +
> +properties:
> + compatible:
> + oneOf:
> + - enum:
> + - nxp,s32g2-pcie
> + - items:
> + - const: nxp,s32g3-pcie
> + - const: nxp,s32g2-pcie
> +
> + reg:
> + maxItems: 6
> +
> + reg-names:
> + items:
> + - const: dbi
> + - const: dbi2
> + - const: atu
> + - const: dma
> + - const: ctrl
> + - const: config
> +
> + interrupts:
> + maxItems: 2
> +
> + interrupt-names:
> + items:
> + - const: dma
> + - const: msi
> +
> +required:
> + - compatible
> + - reg
> + - reg-names
> + - interrupts
> + - interrupt-names
> + - ranges
> + - phys
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/phy/phy.h>
> +
> + bus {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + pcie@40400000 {
> + compatible = "nxp,s32g3-pcie",
> + "nxp,s32g2-pcie";
> + reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
> + <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
> + <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
> + <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
> + <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
> + <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
> + reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
> + dma-coherent;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + device_type = "pci";
> + ranges =
> + <0x81000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
> + <0x82000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
> + <0x82000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
> +
> + bus-range = <0x0 0xff>;
> + interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
> + interrupt-names = "dma", "msi";
> + #interrupt-cells = <1>;
> + interrupt-map-mask = <0 0 0 0x7>;
> + interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 2 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 3 &gic 0 0 GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 4 &gic 0 0 GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> +
> + phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
PHY is a Root Port specific resource, not Root Complex. So it should be moved to
the Root Port node and the controller driver should parse the Root Port node and
control PHY. Most of the existing platforms still specify PHY and other Root
Port properties in controller node, but they are wrong.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-06 0:05 ` Bjorn Helgaas
2025-11-06 6:24 ` Manivannan Sadhasivam
@ 2025-11-06 7:46 ` Vincent Guittot
1 sibling, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-11-06 7:46 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel, Richard Zhu,
Lucas Stach, Minghuan Lian, Mingkai Hu, Roy Zang, Christian Bruel,
linux-stm32
On Thu, 6 Nov 2025 at 01:05, Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> [+cc imx6, layerscape, stm32 maintainers for possible suspend bug]
>
> On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> > On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > > On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > > > Add initial support of the PCIe controller for S32G Soc family. Only
> > > > host mode is supported.
>
> > > > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > > > +{
> > > > ...
> > > > + /*
> > > > + * Make sure we use the coherency defaults (just in case the settings
> > > > + * have been changed from their reset values)
> > > > + */
> > > > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> > >
> > > This seems sketchy and no other driver uses memblock_start_of_DRAM().
> > > Shouldn't a physical memory address like this come from devicetree
> > > somehow?
> >
> > I was using DT but has been asked to not use it and was proposed to
> > use memblock_start_of_DRAM() instead
>
> Can you point me to that conversation?
https://lore.kernel.org/all/CAKfTPtDcvrAcgFcyFLnzaKnfuU3iB551qed4fnZH=b7Ntkpxpg@mail.gmail.com/
>
> > > > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > > > + if (IS_ERR(s32g_pp->ctrl_base))
> > > > + return PTR_ERR(s32g_pp->ctrl_base);
> > >
> > > This looks like the first DWC driver that uses a "ctrl" resource. Is
> > > this something unique to s32g, or do other drivers have something
> > > similar but use a different name?
> >
> > AFAICT this seems to be s32g specific in the RM
>
> It does look like there's very little consistency in reg-names across
> drivers, so I guess it's fine.
>
> > > > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > > > +{
> > > > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > > +
> > > > + if (!dw_pcie_link_up(pci))
> > > > + return 0;
> > >
> > > Does something bad happen if you omit the link up check and the link
> > > is not up when we get here? The check is racy (the link could go down
> > > between dw_pcie_link_up() and dw_pcie_suspend_noirq()), so it's not
> > > completely reliable.
> > >
> > > If you have to check, please add a comment about why this driver needs
> > > it when no other driver does.
> >
> > dw_pcie_suspend_noirq returns an error and the suspend fails
>
> The implication is that *every* user of dw_pcie_suspend_noirq() would
> have to check for the link being up. There are only three existing
> callers:
>
> imx_pcie_suspend_noirq()
> ls_pcie_suspend_noirq()
> stm32_pcie_suspend_noirq()
>
> but none of them checks for the link being up.
>
> > I will add a comment
> > /*
> > * If the link is not up, there is nothing to suspend and resume
>
> Sometimes true, but still racy as I mentioned, and doesn't explain why
> s32g is different from imx, ls, and stm32.
>
> > > > + return dw_pcie_suspend_noirq(pci);
> > > > +}
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-06 6:24 ` Manivannan Sadhasivam
@ 2025-11-06 7:50 ` Vincent Guittot
2025-11-14 10:05 ` Christian Bruel
1 sibling, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-11-06 7:50 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: Bjorn Helgaas, chester62515, mbrugger, ghennadi.procopciuc, s32,
bhelgaas, jingoohan1, lpieralisi, kwilczynski, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel, Richard Zhu,
Lucas Stach, Minghuan Lian, Mingkai Hu, Roy Zang, Christian Bruel,
linux-stm32
On Thu, 6 Nov 2025 at 07:24, Manivannan Sadhasivam <mani@kernel.org> wrote:
>
> On Wed, Nov 05, 2025 at 06:05:31PM -0600, Bjorn Helgaas wrote:
> > [+cc imx6, layerscape, stm32 maintainers for possible suspend bug]
> >
> > On Fri, Oct 24, 2025 at 08:50:46AM +0200, Vincent Guittot wrote:
> > > On Wed, 22 Oct 2025 at 21:04, Bjorn Helgaas <helgaas@kernel.org> wrote:
> > > > On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > > > > Add initial support of the PCIe controller for S32G Soc family. Only
> > > > > host mode is supported.
> >
> > > > > +static void s32g_init_pcie_controller(struct s32g_pcie *s32g_pp)
> > > > > +{
> > > > > ...
> > > > > + /*
> > > > > + * Make sure we use the coherency defaults (just in case the settings
> > > > > + * have been changed from their reset values)
> > > > > + */
> > > > > + s32g_pcie_reset_mstr_ace(pci, memblock_start_of_DRAM());
> > > >
> > > > This seems sketchy and no other driver uses memblock_start_of_DRAM().
> > > > Shouldn't a physical memory address like this come from devicetree
> > > > somehow?
> > >
> > > I was using DT but has been asked to not use it and was proposed to
> > > use memblock_start_of_DRAM() instead
> >
> > Can you point me to that conversation?
> >
> > > > > + s32g_pp->ctrl_base = devm_platform_ioremap_resource_byname(pdev, "ctrl");
> > > > > + if (IS_ERR(s32g_pp->ctrl_base))
> > > > > + return PTR_ERR(s32g_pp->ctrl_base);
> > > >
> > > > This looks like the first DWC driver that uses a "ctrl" resource. Is
> > > > this something unique to s32g, or do other drivers have something
> > > > similar but use a different name?
> > >
> > > AFAICT this seems to be s32g specific in the RM
> >
> > It does look like there's very little consistency in reg-names across
> > drivers, so I guess it's fine.
> >
> > > > > +static int s32g_pcie_suspend_noirq(struct device *dev)
> > > > > +{
> > > > > + struct s32g_pcie *s32g_pp = dev_get_drvdata(dev);
> > > > > + struct dw_pcie *pci = &s32g_pp->pci;
> > > > > +
> > > > > + if (!dw_pcie_link_up(pci))
> > > > > + return 0;
> > > >
> > > > Does something bad happen if you omit the link up check and the link
> > > > is not up when we get here? The check is racy (the link could go down
> > > > between dw_pcie_link_up() and dw_pcie_suspend_noirq()), so it's not
> > > > completely reliable.
> > > >
> > > > If you have to check, please add a comment about why this driver needs
> > > > it when no other driver does.
> > >
> > > dw_pcie_suspend_noirq returns an error and the suspend fails
> >
> > The implication is that *every* user of dw_pcie_suspend_noirq() would
> > have to check for the link being up. There are only three existing
> > callers:
> >
> > imx_pcie_suspend_noirq()
> > ls_pcie_suspend_noirq()
> > stm32_pcie_suspend_noirq()
> >
> > but none of them checks for the link being up.
> >
>
> If no devices are attached to the bus, then there is no need to broadcast
> PME_Turn_Off and wait for L2/L3. I've just sent out a series that fixes it [1].
> Hopefully, this will allow Vincent to use dw_pcie_{suspend/resume}_noirq() APIs.
I'm going to test it
Thanks
>
> - Mani
>
> [1] https://lore.kernel.org/linux-pci/20251106061326.8241-1-manivannan.sadhasivam@oss.qualcomm.com/
>
> --
> மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-11-06 0:00 ` Bjorn Helgaas
@ 2025-11-06 7:51 ` Vincent Guittot
0 siblings, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-11-06 7:51 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Thu, 6 Nov 2025 at 01:00, Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> > Describe the PCIe host controller available on the S32G platforms.
>
> > + reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
> > + <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
> > + <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
> > + <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
> > + <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
> > + <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
>
> Fix comment alignment.
okay
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-11-06 7:12 ` Manivannan Sadhasivam
@ 2025-11-06 8:09 ` Vincent Guittot
2025-11-06 17:38 ` Bjorn Helgaas
0 siblings, 1 reply; 30+ messages in thread
From: Vincent Guittot @ 2025-11-06 8:09 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, robh, krzk+dt, conor+dt,
Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Thu, 6 Nov 2025 at 08:12, Manivannan Sadhasivam <mani@kernel.org> wrote:
>
> On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> > Describe the PCIe host controller available on the S32G platforms.
> >
> > Co-developed-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > Signed-off-by: Ionut Vicovan <Ionut.Vicovan@nxp.com>
> > Co-developed-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> > Signed-off-by: Bogdan-Gabriel Roman <bogdan-gabriel.roman@nxp.com>
> > Co-developed-by: Larisa Grigore <larisa.grigore@nxp.com>
> > Signed-off-by: Larisa Grigore <larisa.grigore@nxp.com>
> > Co-developed-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > Signed-off-by: Ghennadi Procopciuc <Ghennadi.Procopciuc@nxp.com>
> > Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com>
> > Co-developed-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> > Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> > Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> > ---
> > .../bindings/pci/nxp,s32g-pcie.yaml | 102 ++++++++++++++++++
> > 1 file changed, 102 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> > new file mode 100644
> > index 000000000000..2d8f7ad67651
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pci/nxp,s32g-pcie.yaml
> > @@ -0,0 +1,102 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pci/nxp,s32g-pcie.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: NXP S32G2xxx/S32G3xxx PCIe Root Complex controller
> > +
> > +maintainers:
> > + - Bogdan Hamciuc <bogdan.hamciuc@nxp.com>
> > + - Ionut Vicovan <ionut.vicovan@nxp.com>
> > +
> > +description:
> > + This PCIe controller is based on the Synopsys DesignWare PCIe IP.
> > + The S32G SoC family has two PCIe controllers, which can be configured as
> > + either Root Complex or Endpoint.
> > +
> > +allOf:
> > + - $ref: /schemas/pci/snps,dw-pcie.yaml#
> > +
> > +properties:
> > + compatible:
> > + oneOf:
> > + - enum:
> > + - nxp,s32g2-pcie
> > + - items:
> > + - const: nxp,s32g3-pcie
> > + - const: nxp,s32g2-pcie
> > +
> > + reg:
> > + maxItems: 6
> > +
> > + reg-names:
> > + items:
> > + - const: dbi
> > + - const: dbi2
> > + - const: atu
> > + - const: dma
> > + - const: ctrl
> > + - const: config
> > +
> > + interrupts:
> > + maxItems: 2
> > +
> > + interrupt-names:
> > + items:
> > + - const: dma
> > + - const: msi
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - reg-names
> > + - interrupts
> > + - interrupt-names
> > + - ranges
> > + - phys
> > +
> > +unevaluatedProperties: false
> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/interrupt-controller/arm-gic.h>
> > + #include <dt-bindings/phy/phy.h>
> > +
> > + bus {
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + pcie@40400000 {
> > + compatible = "nxp,s32g3-pcie",
> > + "nxp,s32g2-pcie";
> > + reg = <0x00 0x40400000 0x0 0x00001000>, /* dbi registers */
> > + <0x00 0x40420000 0x0 0x00001000>, /* dbi2 registers */
> > + <0x00 0x40460000 0x0 0x00001000>, /* atu registers */
> > + <0x00 0x40470000 0x0 0x00001000>, /* dma registers */
> > + <0x00 0x40481000 0x0 0x000000f8>, /* ctrl registers */
> > + <0x5f 0xffffe000 0x0 0x00002000>; /* config space */
> > + reg-names = "dbi", "dbi2", "atu", "dma", "ctrl", "config";
> > + dma-coherent;
> > + #address-cells = <3>;
> > + #size-cells = <2>;
> > + device_type = "pci";
> > + ranges =
> > + <0x81000000 0x0 0x00000000 0x5f 0xfffe0000 0x0 0x00010000>,
> > + <0x82000000 0x0 0x00000000 0x58 0x00000000 0x0 0x80000000>,
> > + <0x82000000 0x1 0x00000000 0x59 0x00000000 0x6 0xfffe0000>;
> > +
> > + bus-range = <0x0 0xff>;
> > + interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
> > + <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
> > + interrupt-names = "dma", "msi";
> > + #interrupt-cells = <1>;
> > + interrupt-map-mask = <0 0 0 0x7>;
> > + interrupt-map = <0 0 0 1 &gic 0 0 GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
> > + <0 0 0 2 &gic 0 0 GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
> > + <0 0 0 3 &gic 0 0 GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
> > + <0 0 0 4 &gic 0 0 GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
> > +
> > + phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
>
> PHY is a Root Port specific resource, not Root Complex. So it should be moved to
> the Root Port node and the controller driver should parse the Root Port node and
> control PHY. Most of the existing platforms still specify PHY and other Root
> Port properties in controller node, but they are wrong.
Yeah, we had similar discussion on v1 and as designware core code
doesn't support it, the goal was to follow other implementations until
designware core is able to parse root port nodes.
I can add a root port node for the phy and parse it in s32 probe
function but then If I need to restrict the number of lane to 1
instead of the default 2 with num-lanes then I have to put it the
controller node otherwise designware core node will not get it.
>
> - Mani
>
> --
> மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-10-22 17:43 ` [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC) Vincent Guittot
2025-10-22 19:04 ` Bjorn Helgaas
2025-10-22 19:44 ` Frank Li
@ 2025-11-06 17:23 ` Bjorn Helgaas
2025-11-06 17:33 ` Vincent Guittot
2 siblings, 1 reply; 30+ messages in thread
From: Bjorn Helgaas @ 2025-11-06 17:23 UTC (permalink / raw)
To: Vincent Guittot
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> Add initial support of the PCIe controller for S32G Soc family. Only
> host mode is supported.
> +config PCIE_NXP_S32G
> + tristate "NXP S32G PCIe controller (host mode)"
> + depends on ARCH_S32 || COMPILE_TEST
> + select PCIE_DW_HOST
> + help
> + Enable support for the PCIe controller in NXP S32G based boards to
> + work in Host mode. The controller is based on DesignWare IP and
> + can work either as RC or EP. In order to enable host-specific
> + features PCIE_S32G must be selected.
Did you mean PCIE_NXP_S32G here?
PCIE_S32G itself doesn't appear in this series.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-06 17:23 ` Bjorn Helgaas
@ 2025-11-06 17:33 ` Vincent Guittot
0 siblings, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-11-06 17:33 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: chester62515, mbrugger, ghennadi.procopciuc, s32, bhelgaas,
jingoohan1, lpieralisi, kwilczynski, mani, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel
On Thu, 6 Nov 2025 at 18:23, Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> On Wed, Oct 22, 2025 at 07:43:08PM +0200, Vincent Guittot wrote:
> > Add initial support of the PCIe controller for S32G Soc family. Only
> > host mode is supported.
>
> > +config PCIE_NXP_S32G
> > + tristate "NXP S32G PCIe controller (host mode)"
> > + depends on ARCH_S32 || COMPILE_TEST
> > + select PCIE_DW_HOST
> > + help
> > + Enable support for the PCIe controller in NXP S32G based boards to
> > + work in Host mode. The controller is based on DesignWare IP and
> > + can work either as RC or EP. In order to enable host-specific
> > + features PCIE_S32G must be selected.
>
> Did you mean PCIE_NXP_S32G here?
>
> PCIE_S32G itself doesn't appear in this series.
Yes I failed to rename this one.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-11-06 8:09 ` Vincent Guittot
@ 2025-11-06 17:38 ` Bjorn Helgaas
2025-11-10 9:14 ` Vincent Guittot
0 siblings, 1 reply; 30+ messages in thread
From: Bjorn Helgaas @ 2025-11-06 17:38 UTC (permalink / raw)
To: Vincent Guittot
Cc: Manivannan Sadhasivam, chester62515, mbrugger,
ghennadi.procopciuc, s32, bhelgaas, jingoohan1, lpieralisi,
kwilczynski, robh, krzk+dt, conor+dt, Ionut.Vicovan,
larisa.grigore, Ghennadi.Procopciuc, ciprianmarian.costea,
bogdan.hamciuc, Frank.li, linux-arm-kernel, linux-pci, devicetree,
linux-kernel, imx, cassel, Senchuan Zhang
[+cc Senchuan]
On Thu, Nov 06, 2025 at 09:09:01AM +0100, Vincent Guittot wrote:
> On Thu, 6 Nov 2025 at 08:12, Manivannan Sadhasivam <mani@kernel.org> wrote:
> > On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> > > Describe the PCIe host controller available on the S32G platforms.
> > > + phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
> >
> > PHY is a Root Port specific resource, not Root Complex. So it
> > should be moved to the Root Port node and the controller driver
> > should parse the Root Port node and control PHY. Most of the
> > existing platforms still specify PHY and other Root Port
> > properties in controller node, but they are wrong.
>
> Yeah, we had similar discussion on v1 and as designware core code
> doesn't support it, the goal was to follow other implementations
> until designware core is able to parse root port nodes. I can add a
> root port node for the phy and parse it in s32 probe function but
> then If I need to restrict the number of lane to 1 instead of the
> default 2 with num-lanes then I have to put it the controller node
> otherwise designware core node will not get it.
I think it's better to put the PHY info, including num-lanes, in Root
Port DT nodes now even thought the DWC core doesn't explicitly support
that yet because it's much easier to change the DWC core and the
driver code than it is to change the DT structure.
That will mean a little extra code in the s32g driver now, but we will
be able to remove that eventually. If we leave the PHY in the DT
controller node, we may eventually end up having to support two s32g
DT structures: the single RP style with PHY in the controller, and a
multiple RP style with PHY in the RP.
We'll likely have both structures for many existing drivers, but I
think it will be simpler if new drivers can avoid the old one.
The eic7700 driver is an example of num-lanes support in the driver:
https://lore.kernel.org/linux-pci/20251030083143.1341-1-zhangsenchuan@eswincomputing.com/
Bjorn
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP PCIe controller
2025-11-06 17:38 ` Bjorn Helgaas
@ 2025-11-10 9:14 ` Vincent Guittot
0 siblings, 0 replies; 30+ messages in thread
From: Vincent Guittot @ 2025-11-10 9:14 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: Manivannan Sadhasivam, chester62515, mbrugger,
ghennadi.procopciuc, s32, bhelgaas, jingoohan1, lpieralisi,
kwilczynski, robh, krzk+dt, conor+dt, Ionut.Vicovan,
larisa.grigore, Ghennadi.Procopciuc, ciprianmarian.costea,
bogdan.hamciuc, Frank.li, linux-arm-kernel, linux-pci, devicetree,
linux-kernel, imx, cassel, Senchuan Zhang
On Thu, 6 Nov 2025 at 18:38, Bjorn Helgaas <helgaas@kernel.org> wrote:
>
> [+cc Senchuan]
>
> On Thu, Nov 06, 2025 at 09:09:01AM +0100, Vincent Guittot wrote:
> > On Thu, 6 Nov 2025 at 08:12, Manivannan Sadhasivam <mani@kernel.org> wrote:
> > > On Wed, Oct 22, 2025 at 07:43:06PM +0200, Vincent Guittot wrote:
> > > > Describe the PCIe host controller available on the S32G platforms.
>
> > > > + phys = <&serdes0 PHY_TYPE_PCIE 0 0>;
> > >
> > > PHY is a Root Port specific resource, not Root Complex. So it
> > > should be moved to the Root Port node and the controller driver
> > > should parse the Root Port node and control PHY. Most of the
> > > existing platforms still specify PHY and other Root Port
> > > properties in controller node, but they are wrong.
> >
> > Yeah, we had similar discussion on v1 and as designware core code
> > doesn't support it, the goal was to follow other implementations
> > until designware core is able to parse root port nodes. I can add a
> > root port node for the phy and parse it in s32 probe function but
> > then If I need to restrict the number of lane to 1 instead of the
> > default 2 with num-lanes then I have to put it the controller node
> > otherwise designware core node will not get it.
>
> I think it's better to put the PHY info, including num-lanes, in Root
> Port DT nodes now even thought the DWC core doesn't explicitly support
> that yet because it's much easier to change the DWC core and the
> driver code than it is to change the DT structure.
>
> That will mean a little extra code in the s32g driver now, but we will
> be able to remove that eventually. If we leave the PHY in the DT
> controller node, we may eventually end up having to support two s32g
> DT structures: the single RP style with PHY in the controller, and a
> multiple RP style with PHY in the RP.
>
> We'll likely have both structures for many existing drivers, but I
> think it will be simpler if new drivers can avoid the old one.
Okay, i will add a RP node
>
> The eic7700 driver is an example of num-lanes support in the driver:
> https://lore.kernel.org/linux-pci/20251030083143.1341-1-zhangsenchuan@eswincomputing.com/
>
> Bjorn
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-06 6:24 ` Manivannan Sadhasivam
2025-11-06 7:50 ` Vincent Guittot
@ 2025-11-14 10:05 ` Christian Bruel
2025-11-14 21:35 ` Bjorn Helgaas
1 sibling, 1 reply; 30+ messages in thread
From: Christian Bruel @ 2025-11-14 10:05 UTC (permalink / raw)
To: Manivannan Sadhasivam, Bjorn Helgaas
Cc: Vincent Guittot, chester62515, mbrugger, ghennadi.procopciuc, s32,
bhelgaas, jingoohan1, lpieralisi, kwilczynski, robh, krzk+dt,
conor+dt, Ionut.Vicovan, larisa.grigore, Ghennadi.Procopciuc,
ciprianmarian.costea, bogdan.hamciuc, Frank.li, linux-arm-kernel,
linux-pci, devicetree, linux-kernel, imx, cassel, Richard Zhu,
Lucas Stach, Minghuan Lian, Mingkai Hu, Roy Zang, linux-stm32
>>
>> The implication is that *every* user of dw_pcie_suspend_noirq() would
>> have to check for the link being up. There are only three existing
>> callers:
>>
>> imx_pcie_suspend_noirq()
>> ls_pcie_suspend_noirq()
>> stm32_pcie_suspend_noirq()
>>
>> but none of them checks for the link being up.
>>
stm32 supports L1.1, so we bail out before pme_turn_off() in
dw_pcie_suspend_noirq()
>
> If no devices are attached to the bus, then there is no need to broadcast
> PME_Turn_Off and wait for L2/L3. I've just sent out a series that fixes it [1].
> Hopefully, this will allow Vincent to use dw_pcie_{suspend/resume}_noirq() APIs.
>
> - Mani
>
> [1] https://lore.kernel.org/linux-pci/20251106061326.8241-1-manivannan.sadhasivam@oss.qualcomm.com/
dw_pcie_suspend_noirq() path tested OK on stm32mp2.
Regards
Christian
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC)
2025-11-14 10:05 ` Christian Bruel
@ 2025-11-14 21:35 ` Bjorn Helgaas
0 siblings, 0 replies; 30+ messages in thread
From: Bjorn Helgaas @ 2025-11-14 21:35 UTC (permalink / raw)
To: Christian Bruel
Cc: Manivannan Sadhasivam, Vincent Guittot, chester62515, mbrugger,
ghennadi.procopciuc, s32, bhelgaas, jingoohan1, lpieralisi,
kwilczynski, robh, krzk+dt, conor+dt, Ionut.Vicovan,
larisa.grigore, Ghennadi.Procopciuc, ciprianmarian.costea,
bogdan.hamciuc, Frank.li, linux-arm-kernel, linux-pci, devicetree,
linux-kernel, imx, cassel, Richard Zhu, Lucas Stach,
Minghuan Lian, Mingkai Hu, Roy Zang, linux-stm32
On Fri, Nov 14, 2025 at 11:05:45AM +0100, Christian Bruel wrote:
> > > The implication is that *every* user of dw_pcie_suspend_noirq() would
> > > have to check for the link being up. There are only three existing
> > > callers:
> > >
> > > imx_pcie_suspend_noirq()
> > > ls_pcie_suspend_noirq()
> > > stm32_pcie_suspend_noirq()
> > >
> > > but none of them checks for the link being up.
>
> stm32 supports L1.1, so we bail out before pme_turn_off() in
> dw_pcie_suspend_noirq()
I think you're referring to this code::
dw_pcie_suspend_noirq()
{
/*
* If L1SS is supported, then do not put the link into L2 as some
* devices such as NVMe expect low resume latency.
*/
if (dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKCTL) & PCI_EXP_LNKCTL_ASPM_L1)
return 0;
if (pci->pp.ops->pme_turn_off) {
pci->pp.ops->pme_turn_off(&pci->pp);
} else {
ret = dw_pcie_pme_turn_off(pci);
if (ret)
return ret;
}
I think this is bogus. For starters, the code doesn't match the
comment. The comment talks about "L1SS being supported", but the code
checks for L1 (not L1SS). And it checks whether L1 is *enabled* (in
Link Control), not whether it's *supported* (in Link Capabilities).
And it's up to the user whether L1 is enabled. Users can disable L1
by building the kernel with PCIEASPM_PERFORMANCE, booting with
"pcie_aspm.policy=performance", or using sysfs.
It doesn't make sense to me to decide anything about PME_Turn_Off
based on PCI_EXP_LNKCTL_ASPM_L1.
We've had this conversation before, e.g.,
https://lore.kernel.org/linux-pci/?q=b%3Adw_pcie_suspend_noirq+b%3ANVMe+f%3Ahelgaas,
and Richard actually posted a patch to remove this code [2], but I
hesitated because I didn't think we had a good explanation for why it
was there in the first place and it was now OK to remove it.
But I think I was wrong and we should just remove this code and debug
whatever breaks.
> > If no devices are attached to the bus, then there is no need to
> > broadcast PME_Turn_Off and wait for L2/L3. I've just sent out a
> > series that fixes it [1]. Hopefully, this will allow Vincent to
> > use dw_pcie_{suspend/resume}_noirq() APIs.
> >
> > - Mani
> >
> > [1] https://lore.kernel.org/linux-pci/20251106061326.8241-1-manivannan.sadhasivam@oss.qualcomm.com/
>
> dw_pcie_suspend_noirq() path tested OK on stm32mp2.
>
> Regards
>
> Christian
[2] https://lore.kernel.org/linux-pci/20250924194457.GA2131297@bhelgaas/
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2025-11-14 21:35 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-22 17:43 [PATCH 0/4 v3] PCI: s32g: Add support for PCIe controller Vincent Guittot
2025-10-22 17:43 ` [PATCH 1/4 v3] dt-bindings: PCI: s32g: Add NXP " Vincent Guittot
2025-10-22 19:17 ` Frank Li
2025-10-24 6:58 ` Vincent Guittot
2025-11-06 0:00 ` Bjorn Helgaas
2025-11-06 7:51 ` Vincent Guittot
2025-11-06 7:12 ` Manivannan Sadhasivam
2025-11-06 8:09 ` Vincent Guittot
2025-11-06 17:38 ` Bjorn Helgaas
2025-11-10 9:14 ` Vincent Guittot
2025-10-22 17:43 ` [PATCH 2/4 v3] PCI: dw: Add more registers and bitfield definition Vincent Guittot
2025-10-22 17:43 ` [PATCH 3/4 v3] PCI: s32g: Add initial PCIe support (RC) Vincent Guittot
2025-10-22 19:04 ` Bjorn Helgaas
2025-10-24 6:50 ` Vincent Guittot
2025-11-05 10:28 ` Niklas Cassel
2025-11-05 10:43 ` Ilpo Järvinen
2025-11-05 11:00 ` Niklas Cassel
2025-11-06 0:05 ` Bjorn Helgaas
2025-11-06 6:24 ` Manivannan Sadhasivam
2025-11-06 7:50 ` Vincent Guittot
2025-11-14 10:05 ` Christian Bruel
2025-11-14 21:35 ` Bjorn Helgaas
2025-11-06 7:46 ` Vincent Guittot
2025-10-22 19:44 ` Frank Li
2025-10-24 6:53 ` Vincent Guittot
2025-11-05 7:58 ` Vincent Guittot
2025-11-06 17:23 ` Bjorn Helgaas
2025-11-06 17:33 ` Vincent Guittot
2025-10-22 17:43 ` [PATCH 4/4 v3] MAINTAINERS: Add MAINTAINER for NXP S32G PCIe driver Vincent Guittot
2025-10-22 19:20 ` Frank Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).