Re: [PATCH 3/4 v4] PCI: s32g: Add initial PCIe support (RC)
From: Frank Li <Frank.li@nxp.com>
Date: 2025-11-10 19:30:36
Also in:
imx, linux-devicetree, linux-pci, lkml
On Mon, Nov 10, 2025 at 06:33:33PM +0100, Vincent Guittot wrote:
quoted hunk ↗ jump to hunk
Add initial support of the PCIe controller for S32G Soc family. Only host mode is supported. Co-developed-by: Ionut Vicovan <redacted> Signed-off-by: Ionut Vicovan <redacted> Co-developed-by: Ciprian Marian Costea <redacted> Signed-off-by: Ciprian Marian Costea <redacted> Co-developed-by: Ghennadi Procopciuc <redacted> Signed-off-by: Ghennadi Procopciuc <redacted> Co-developed-by: Larisa Grigore <redacted> Signed-off-by: Larisa Grigore <redacted> 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 | 27 ++ drivers/pci/controller/dwc/pcie-nxp-s32g.c | 435 ++++++++++++++++++ 4 files changed, 473 insertions(+) create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h create mode 100644 drivers/pci/controller/dwc/pcie-nxp-s32g.cdiff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 349d4657393c..e276956c3fca 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig@@ -256,6 +256,16 @@ config PCIE_TEGRA194_EP in order to enable device-specific features PCIE_TEGRA194_EP must be selected. This uses the DesignWare core. +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_NXP_S32G must be selected. + config PCIE_DW_PLAT booldiff --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.odiff --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..c264446a8f21 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g-regs.h@@ -0,0 +1,27 @@ +/* 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 */ + +/* PCIe controller 0 General Control 1 */ +#define PCIE_S32G_PE0_GEN_CTRL_1 0x50 +#define DEVICE_TYPE_MASK GENMASK(3, 0) +#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 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..18bf0fe6f416 --- /dev/null +++ b/drivers/pci/controller/dwc/pcie-nxp-s32g.c@@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PCIe host controller driver for NXP S32G SoCs + * + * Copyright 2019-2025 NXP + */ +
...
+
+#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;Are you sure code can go here? I think IP set flag PCIE_LINKUP of PCIE_S32G_PE0_LINK_DBG_2 only after LTSSM in above states. Do you know which case PCIE_LINKUP is true, but LTSSM is not other state? I remember I asked if DEBUG0 register work? any conclusion?
+ } + } + + return false; +} +
...
+
+static int s32g_pcie_parse_port(struct s32g_pcie *s32g_pp, struct device_node *node)
+{
+ struct device *dev = s32g_pp->pci.dev;
+ struct s32g_pcie_port *port;
+ int num_lanes;
+
+ port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return -ENOMEM;
+
+ port->phy = devm_of_phy_get(dev, node, NULL);
+ if (IS_ERR(port->phy))
+ return dev_err_probe(dev, PTR_ERR(port->phy),
+ "Failed to get serdes PHY\n");
+
+ INIT_LIST_HEAD(&port->list);
+ list_add_tail(&port->list, &s32g_pp->ports);
+
+ /*
+ * The DWC core initialization code cannot parse yet the num-lanes
+ * attribute in the Root Port node. The S32G only supports one Root
+ * Port for now so its driver can parse the node and set the num_lanes
+ * field of struct dwc_pcie before calling dw_pcie_host_init().
+ */
+ if (!of_property_read_u32(node, "num-lanes", &num_lanes))
+ s32g_pp->pci.num_lanes = num_lanes;Can you add this to dwc core driver? Frank
+ + return 0; +} +
...
-- 2.43.0