* [PATCH v4 00/10] Add STM32MP25 PCIe drivers
@ 2025-01-28 12:07 Christian Bruel
2025-01-28 12:07 ` [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Christian Bruel
` (9 more replies)
0 siblings, 10 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Changes in v4:
Address bindings comments Rob Herring
- Remove phy property form common yaml
- Remove phy-name property
- Move wake_gpio and reset_gpio to the host root port
Changes in v3:
Address comments from Manivanna, Rob and Bjorn:
- Move host wakeup helper to dwc core (Mani)
- Drop num-lanes=<1> from bindings (Rob)
- Fix PCI address of I/O region (Mani)
- Moved PHY to a RC rootport subsection (Bjorn, Mani)
- Replaced dma-limit quirk by dma-ranges property (Bjorn)
- Moved out perst assert/deassert from start/stop link (Mani)
- Drop link_up test optim (Mani)
- DT and comments rephrasing (Bjorn)
- Add dts entries now that the combophy entries has landed
- Drop delaying Configuration Requests
Changes in v2:
- Fix st,stm32-pcie-common.yaml dt_binding_check
Changes in v1:
Address comments from Rob Herring and Bjorn Helgaas:
- Drop st,limit-mrrs and st,max-payload-size from this patchset
- Remove single reset and clocks binding names and misc yaml cleanups
- Split RC/EP common bindings to a separate schema file
- Use correct PCIE_T_PERST_CLK_US and PCIE_T_RRS_READY_MS defines
- Use .remove instead of .remove_new
- Fix bar reset sequence in EP driver
- Use cleanup blocks for error handling
- Cosmetic fixes
Christian Bruel (10):
dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings
PCI: dwc: Add dw_pcie_wake_irq_handler helper
PCI: stm32: Add PCIe host support for STM32MP25
dt-bindings: PCI: Add STM32MP25 PCIe Endpoint bindings
PCI: stm32: Add PCIe Endpoint support for STM32MP25
MAINTAINERS: add entry for ST STM32MP25 PCIe drivers
arm64: dts: st: add PCIe pinctrl entries in stm32mp25-pinctrl.dtsi
arm64: dts: st: Add PCIe Rootcomplex mode on stm32mp251
arm64: dts: st: Add PCIe Endpoint mode on stm32mp251
arm64: dts: st: Enable PCIe on the stm32mp257f-ev1 board
.../bindings/pci/st,stm32-pcie-common.yaml | 33 ++
.../bindings/pci/st,stm32-pcie-ep.yaml | 67 +++
.../bindings/pci/st,stm32-pcie-host.yaml | 116 +++++
MAINTAINERS | 7 +
arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi | 20 +
arch/arm64/boot/dts/st/stm32mp251.dtsi | 60 ++-
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 22 +
drivers/pci/controller/dwc/Kconfig | 24 +
drivers/pci/controller/dwc/Makefile | 2 +
.../pci/controller/dwc/pcie-designware-host.c | 15 +
drivers/pci/controller/dwc/pcie-designware.h | 2 +
drivers/pci/controller/dwc/pcie-stm32-ep.c | 420 ++++++++++++++++++
drivers/pci/controller/dwc/pcie-stm32.c | 372 ++++++++++++++++
drivers/pci/controller/dwc/pcie-stm32.h | 16 +
14 files changed, 1175 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml
create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-ep.yaml
create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml
create mode 100644 drivers/pci/controller/dwc/pcie-stm32-ep.c
create mode 100644 drivers/pci/controller/dwc/pcie-stm32.c
create mode 100644 drivers/pci/controller/dwc/pcie-stm32.h
--
2.34.1
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-29 15:44 ` Rob Herring
2025-02-02 12:25 ` Manivannan Sadhasivam
2025-01-28 12:07 ` [PATCH v4 02/10] PCI: dwc: Add dw_pcie_wake_irq_handler helper Christian Bruel
` (8 subsequent siblings)
9 siblings, 2 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Document the bindings for STM32MP25 PCIe Controller configured in
root complex mode with one root port.
Supports 4 INTx and MSI interrupts from the ARM GICv2m controller.
STM32 PCIe may be in a power domain which is the case for the STM32MP25
based boards.
Supports WAKE# from wake-gpios
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
.../bindings/pci/st,stm32-pcie-common.yaml | 33 +++++
.../bindings/pci/st,stm32-pcie-host.yaml | 116 ++++++++++++++++++
2 files changed, 149 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml
create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml
diff --git a/Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml b/Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml
new file mode 100644
index 000000000000..5adbff259204
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/st,stm32-pcie-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32MP25 PCIe RC/EP controller
+
+maintainers:
+ - Christian Bruel <christian.bruel@foss.st.com>
+
+description:
+ STM32MP25 PCIe RC/EP common properties
+
+properties:
+ clocks:
+ maxItems: 1
+ description: PCIe system clock
+
+ resets:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ access-controllers:
+ maxItems: 1
+
+required:
+ - clocks
+ - resets
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml b/Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml
new file mode 100644
index 000000000000..2a13699b3a61
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/st,stm32-pcie-host.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32MP25 PCIe Root Complex
+
+maintainers:
+ - Christian Bruel <christian.bruel@foss.st.com>
+
+description:
+ PCIe root complex controller based on the Synopsys DesignWare PCIe core.
+
+allOf:
+ - $ref: /schemas/pci/snps,dw-pcie.yaml#
+ - $ref: /schemas/pci/st,stm32-pcie-common.yaml#
+
+properties:
+ compatible:
+ const: st,stm32mp25-pcie-rc
+
+ reg:
+ items:
+ - description: Data Bus Interface (DBI) registers.
+ - description: PCIe configuration registers.
+
+ reg-names:
+ items:
+ - const: dbi
+ - const: config
+
+ msi-parent:
+ maxItems: 1
+
+ wakeup-source: true
+
+patternProperties:
+ '^pcie@[0-2],0$':
+ type: object
+ $ref: /schemas/pci/pci-pci-bridge.yaml#
+
+ properties:
+ reg:
+ maxItems: 1
+
+ phys:
+ maxItems: 1
+
+ reset-gpios:
+ description: GPIO controlled connection to PERST# signal
+ maxItems: 1
+
+ wake-gpios:
+ description: GPIO used as WAKE# input signal
+ maxItems: 1
+
+ required:
+ - phys
+ - ranges
+
+ unevaluatedProperties: false
+
+required:
+ - interrupt-map
+ - interrupt-map-mask
+ - ranges
+ - dma-ranges
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/phy/phy.h>
+ #include <dt-bindings/reset/st,stm32mp25-rcc.h>
+
+ pcie@48400000 {
+ compatible = "st,stm32mp25-pcie-rc";
+ device_type = "pci";
+ reg = <0x48400000 0x400000>,
+ <0x10000000 0x10000>;
+ reg-names = "dbi", "config";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x00000000 0x10010000 0x0 0x10000>,
+ <0x02000000 0x0 0x10020000 0x10020000 0x0 0x7fe0000>,
+ <0x42000000 0x0 0x18000000 0x18000000 0x0 0x8000000>;
+ dma-ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x80000000>;
+ clocks = <&rcc CK_BUS_PCIE>;
+ resets = <&rcc PCIE_R>;
+ msi-parent = <&v2m0>;
+ wakeup-source;
+ access-controllers = <&rifsc 68>;
+ power-domains = <&CLUSTER_PD>;
+
+ pcie@0,0 {
+ device_type = "pci";
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ phys = <&combophy PHY_TYPE_PCIE>;
+ wake-gpios = <&gpioh 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+ reset-gpios = <&gpioj 8 GPIO_ACTIVE_LOW>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 02/10] PCI: dwc: Add dw_pcie_wake_irq_handler helper
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
2025-01-28 12:07 ` [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25 Christian Bruel
` (7 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Introduce dw_pcie_wake_irq_handler function to support host wakeup from
the WAKE# irq.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 15 +++++++++++++++
drivers/pci/controller/dwc/pcie-designware.h | 2 ++
2 files changed, 17 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index ef4799effa03..5a67bee5bf3c 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -16,6 +16,7 @@
#include <linux/of_pci.h>
#include <linux/pci_regs.h>
#include <linux/platform_device.h>
+#include <linux/suspend.h>
#include "../../pci.h"
#include "pcie-designware.h"
@@ -1054,3 +1055,17 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci)
return ret;
}
EXPORT_SYMBOL_GPL(dw_pcie_resume_noirq);
+
+irqreturn_t dw_pcie_wake_irq_handler(int irq, void *arg)
+{
+ struct device *dev = arg;
+
+ dev_dbg(dev, "host wakeup by EP");
+
+ /* Notify PM core we are wakeup source */
+ pm_wakeup_event(dev, 0);
+ pm_system_wakeup();
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(dw_pcie_wake_irq_handler);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index f8bf9c89a152..f54cf7b01cbd 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -511,6 +511,8 @@ void dw_pcie_edma_remove(struct dw_pcie *pci);
int dw_pcie_suspend_noirq(struct dw_pcie *pci);
int dw_pcie_resume_noirq(struct dw_pcie *pci);
+irqreturn_t dw_pcie_wake_irq_handler(int irq, void *arg);
+
static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
{
dw_pcie_write_dbi(pci, reg, 0x4, val);
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
2025-01-28 12:07 ` [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Christian Bruel
2025-01-28 12:07 ` [PATCH v4 02/10] PCI: dwc: Add dw_pcie_wake_irq_handler helper Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-02-02 13:06 ` Manivannan Sadhasivam
2025-01-28 12:07 ` [PATCH v4 04/10] dt-bindings: PCI: Add STM32MP25 PCIe Endpoint bindings Christian Bruel
` (6 subsequent siblings)
9 siblings, 1 reply; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add driver for the STM32MP25 SoC PCIe Gen1 2.5 GT/s and Gen2 5GT/s
controller based on the DesignWare PCIe core.
Supports MSI via GICv2m, Single Virtual Channel, Single Function
Supports wakeup-source from gpio wake_irq with dw_pcie_wake_irq_handler
for host wakeup.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
drivers/pci/controller/dwc/Kconfig | 12 +
drivers/pci/controller/dwc/Makefile | 1 +
drivers/pci/controller/dwc/pcie-stm32.c | 372 ++++++++++++++++++++++++
drivers/pci/controller/dwc/pcie-stm32.h | 15 +
4 files changed, 400 insertions(+)
create mode 100644 drivers/pci/controller/dwc/pcie-stm32.c
create mode 100644 drivers/pci/controller/dwc/pcie-stm32.h
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index b6d6778b0698..0c18879b604c 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -389,6 +389,18 @@ config PCIE_SPEAR13XX
help
Say Y here if you want PCIe support on SPEAr13XX SoCs.
+config PCIE_STM32
+ tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on PCI_MSI
+ select PCIE_DW_HOST
+ help
+ Enables support for the DesignWare core based PCIe host controller
+ found in STM32MP25 SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called pcie-stm32.
+
config PCI_DRA7XX
tristate
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index a8308d9ea986..576d99cb3bc5 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
+obj-$(CONFIG_PCIE_STM32) += pcie-stm32.o
# The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pcie-stm32.c b/drivers/pci/controller/dwc/pcie-stm32.c
new file mode 100644
index 000000000000..d5e473bb390f
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-stm32.c
@@ -0,0 +1,372 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics STM32MP25 PCIe root complex driver.
+ *
+ * Copyright (C) 2024 STMicroelectronics
+ * Author: Christian Bruel <christian.bruel@foss.st.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/pinctrl/devinfo.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include "pcie-designware.h"
+#include "pcie-stm32.h"
+#include "../../pci.h"
+
+struct stm32_pcie {
+ struct dw_pcie pci;
+ struct regmap *regmap;
+ struct reset_control *rst;
+ struct phy *phy;
+ struct clk *clk;
+ struct gpio_desc *perst_gpio;
+ struct gpio_desc *wake_gpio;
+ unsigned int wake_irq;
+};
+
+static void stm32_pcie_deassert_perst(struct stm32_pcie *stm32_pcie)
+{
+ gpiod_set_value(stm32_pcie->perst_gpio, 0);
+
+ if (stm32_pcie->perst_gpio)
+ msleep(PCIE_T_RRS_READY_MS);
+}
+
+static void stm32_pcie_assert_perst(struct stm32_pcie *stm32_pcie)
+{
+ gpiod_set_value(stm32_pcie->perst_gpio, 1);
+}
+
+static int stm32_pcie_start_link(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+
+ return regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
+ STM32MP25_PCIECR_LTSSM_EN,
+ STM32MP25_PCIECR_LTSSM_EN);
+}
+
+static void stm32_pcie_stop_link(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+
+ regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
+ STM32MP25_PCIECR_LTSSM_EN, 0);
+}
+
+static int stm32_pcie_suspend(struct device *dev)
+{
+ struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(stm32_pcie->wake_irq);
+
+ return 0;
+}
+
+static int stm32_pcie_resume(struct device *dev)
+{
+ struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(stm32_pcie->wake_irq);
+
+ return 0;
+}
+
+static int stm32_pcie_suspend_noirq(struct device *dev)
+{
+ struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
+
+ stm32_pcie_stop_link(&stm32_pcie->pci);
+
+ stm32_pcie_assert_perst(stm32_pcie);
+
+ clk_disable_unprepare(stm32_pcie->clk);
+
+ if (!device_may_wakeup(dev))
+ phy_exit(stm32_pcie->phy);
+
+ return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int stm32_pcie_resume_noirq(struct device *dev)
+{
+ struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
+ struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
+ int ret;
+
+ /*
+ * The core clock is gated with CLKREQ# from the COMBOPHY REFCLK,
+ * thus if no device is present, must force it low with an init pinmux
+ * to be able to access the DBI registers.
+ */
+ if (!IS_ERR(dev->pins->init_state))
+ ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
+ else
+ ret = pinctrl_pm_select_default_state(dev);
+
+ if (ret) {
+ dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
+ return ret;
+ }
+
+ if (!device_may_wakeup(dev)) {
+ ret = phy_init(stm32_pcie->phy);
+ if (ret) {
+ pinctrl_pm_select_default_state(dev);
+ return ret;
+ }
+ }
+
+ ret = clk_prepare_enable(stm32_pcie->clk);
+ if (ret)
+ goto err_phy_exit;
+
+ stm32_pcie_deassert_perst(stm32_pcie);
+
+ ret = dw_pcie_setup_rc(pp);
+ if (ret)
+ goto err_disable_clk;
+
+ ret = stm32_pcie_start_link(&stm32_pcie->pci);
+ if (ret)
+ goto err_disable_clk;
+
+ /* Ignore errors, the link may come up later */
+ dw_pcie_wait_for_link(&stm32_pcie->pci);
+
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+
+err_disable_clk:
+ stm32_pcie_assert_perst(stm32_pcie);
+ clk_disable_unprepare(stm32_pcie->clk);
+
+err_phy_exit:
+ phy_exit(stm32_pcie->phy);
+ pinctrl_pm_select_default_state(dev);
+
+ return ret;
+}
+
+static const struct dev_pm_ops stm32_pcie_pm_ops = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend_noirq,
+ stm32_pcie_resume_noirq)
+ SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend, stm32_pcie_resume)
+};
+
+static const struct dw_pcie_host_ops stm32_pcie_host_ops = {
+};
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+ .start_link = stm32_pcie_start_link,
+ .stop_link = stm32_pcie_stop_link
+};
+
+static int stm32_add_pcie_port(struct stm32_pcie *stm32_pcie,
+ struct platform_device *pdev)
+{
+ struct device *dev = stm32_pcie->pci.dev;
+ struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
+ int ret;
+
+ ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
+ if (ret)
+ return ret;
+
+ ret = phy_init(stm32_pcie->phy);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
+ STM32MP25_PCIECR_TYPE_MASK,
+ STM32MP25_PCIECR_RC);
+ if (ret)
+ goto err_phy_exit;
+
+ reset_control_assert(stm32_pcie->rst);
+ reset_control_deassert(stm32_pcie->rst);
+
+ ret = clk_prepare_enable(stm32_pcie->clk);
+ if (ret) {
+ dev_err(dev, "Core clock enable failed %d\n", ret);
+ goto err_phy_exit;
+ }
+
+ stm32_pcie_deassert_perst(stm32_pcie);
+
+ pp->ops = &stm32_pcie_host_ops;
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(dev, "Failed to initialize host: %d\n", ret);
+ goto err_disable_clk;
+ }
+
+ return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(stm32_pcie->clk);
+ stm32_pcie_assert_perst(stm32_pcie);
+
+err_phy_exit:
+ phy_exit(stm32_pcie->phy);
+
+ return ret;
+}
+
+static int stm32_pcie_parse_port(struct stm32_pcie *stm32_pcie)
+{
+ struct device *dev = stm32_pcie->pci.dev;
+ struct device_node *root_port;
+
+ root_port = of_get_next_available_child(dev->of_node, NULL);
+
+ stm32_pcie->phy = devm_of_phy_get(dev, root_port, NULL);
+ if (IS_ERR(stm32_pcie->phy))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
+ "Failed to get pcie-phy\n");
+
+ stm32_pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
+ "reset", GPIOD_OUT_HIGH, NULL);
+ if (IS_ERR(stm32_pcie->perst_gpio)) {
+ if (PTR_ERR(stm32_pcie->perst_gpio) != -ENOENT)
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
+ "Failed to get reset GPIO\n");
+ stm32_pcie->perst_gpio = NULL;
+ }
+
+ if (device_property_read_bool(dev, "wakeup-source")) {
+ stm32_pcie->wake_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
+ "wake", GPIOD_IN, NULL);
+
+ if (IS_ERR(stm32_pcie->wake_gpio)) {
+ if (PTR_ERR(stm32_pcie->wake_gpio) != -ENOENT)
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
+ "Failed to get wake GPIO\n");
+ stm32_pcie->wake_gpio = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_pcie_probe(struct platform_device *pdev)
+{
+ struct stm32_pcie *stm32_pcie;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ stm32_pcie = devm_kzalloc(dev, sizeof(*stm32_pcie), GFP_KERNEL);
+ if (!stm32_pcie)
+ return -ENOMEM;
+
+ stm32_pcie->pci.dev = dev;
+ stm32_pcie->pci.ops = &dw_pcie_ops;
+
+ stm32_pcie->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
+ if (IS_ERR(stm32_pcie->regmap))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->regmap),
+ "No syscfg specified\n");
+
+ stm32_pcie->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(stm32_pcie->clk))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->clk),
+ "Failed to get PCIe clock source\n");
+
+ stm32_pcie->rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(stm32_pcie->rst))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->rst),
+ "Failed to get PCIe reset\n");
+
+ ret = stm32_pcie_parse_port(stm32_pcie);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, stm32_pcie);
+
+ if (stm32_pcie->wake_gpio) {
+ stm32_pcie->wake_irq = gpiod_to_irq(stm32_pcie->wake_gpio);
+
+ ret = devm_request_threaded_irq(&pdev->dev,
+ stm32_pcie->wake_irq, NULL,
+ dw_pcie_wake_irq_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "wake_irq", stm32_pcie->pci.dev);
+
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request WAKE IRQ: %d\n", ret);
+ }
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable runtime PM %d\n", ret);
+ return ret;
+ }
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get runtime PM %d\n", ret);
+ return ret;
+ }
+
+ ret = stm32_add_pcie_port(stm32_pcie, pdev);
+ if (ret) {
+ pm_runtime_put_sync(&pdev->dev);
+ return ret;
+ }
+
+ if (stm32_pcie->wake_gpio)
+ device_set_wakeup_capable(dev, true);
+
+ return 0;
+}
+
+static void stm32_pcie_remove(struct platform_device *pdev)
+{
+ struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
+ struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
+
+ if (stm32_pcie->wake_gpio)
+ device_init_wakeup(&pdev->dev, false);
+
+ dw_pcie_host_deinit(pp);
+
+ stm32_pcie_assert_perst(stm32_pcie);
+
+ clk_disable_unprepare(stm32_pcie->clk);
+
+ phy_exit(stm32_pcie->phy);
+
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+static const struct of_device_id stm32_pcie_of_match[] = {
+ { .compatible = "st,stm32mp25-pcie-rc" },
+ {},
+};
+
+static struct platform_driver stm32_pcie_driver = {
+ .probe = stm32_pcie_probe,
+ .remove = stm32_pcie_remove,
+ .driver = {
+ .name = "stm32-pcie",
+ .of_match_table = stm32_pcie_of_match,
+ .pm = &stm32_pcie_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+};
+
+module_platform_driver(stm32_pcie_driver);
+
+MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
+MODULE_DESCRIPTION("STM32MP25 PCIe Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, stm32_pcie_of_match);
diff --git a/drivers/pci/controller/dwc/pcie-stm32.h b/drivers/pci/controller/dwc/pcie-stm32.h
new file mode 100644
index 000000000000..3efd00937d3d
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-stm32.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ST PCIe driver definitions for STM32-MP25 SoC
+ *
+ * Copyright (C) 2024 STMicroelectronics - All Rights Reserved
+ * Author: Christian Bruel <christian.bruel@foss.st.com>
+ */
+
+#define to_stm32_pcie(x) dev_get_drvdata((x)->dev)
+
+#define STM32MP25_PCIECR_TYPE_MASK GENMASK(11, 8)
+#define STM32MP25_PCIECR_LTSSM_EN BIT(2)
+#define STM32MP25_PCIECR_RC BIT(10)
+
+#define SYSCFG_PCIECR 0x6000
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 04/10] dt-bindings: PCI: Add STM32MP25 PCIe Endpoint bindings
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (2 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25 Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 05/10] PCI: stm32: Add PCIe Endpoint support for STM32MP25 Christian Bruel
` (5 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
STM32MP25 PCIe Controller is based on the DesignWare core configured as
end point mode from the SYSCFG register.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Acked-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
.../bindings/pci/st,stm32-pcie-ep.yaml | 67 +++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-ep.yaml
diff --git a/Documentation/devicetree/bindings/pci/st,stm32-pcie-ep.yaml b/Documentation/devicetree/bindings/pci/st,stm32-pcie-ep.yaml
new file mode 100644
index 000000000000..fc1bbe19e616
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/st,stm32-pcie-ep.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pci/st,stm32-pcie-ep.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32MP25 PCIe Endpoint
+
+maintainers:
+ - Christian Bruel <christian.bruel@foss.st.com>
+
+description:
+ PCIe endpoint controller based on the Synopsys DesignWare PCIe core.
+
+allOf:
+ - $ref: /schemas/pci/snps,dw-pcie-ep.yaml#
+ - $ref: /schemas/pci/st,stm32-pcie-common.yaml#
+
+properties:
+ compatible:
+ const: st,stm32mp25-pcie-ep
+
+ reg:
+ items:
+ - description: Data Bus Interface (DBI) registers.
+ - description: PCIe configuration registers.
+
+ reg-names:
+ items:
+ - const: dbi
+ - const: addr_space
+
+ reset-gpios:
+ description: GPIO controlled connection to PERST# signal
+ maxItems: 1
+
+ phys:
+ maxItems: 1
+
+required:
+ - phys
+ - reset-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/phy/phy.h>
+ #include <dt-bindings/reset/st,stm32mp25-rcc.h>
+
+ pcie-ep@48400000 {
+ compatible = "st,stm32mp25-pcie-ep";
+ reg = <0x48400000 0x400000>,
+ <0x10000000 0x8000000>;
+ reg-names = "dbi", "addr_space";
+ clocks = <&rcc CK_BUS_PCIE>;
+ phys = <&combophy PHY_TYPE_PCIE>;
+ resets = <&rcc PCIE_R>;
+ pinctrl-names = "default", "init";
+ pinctrl-0 = <&pcie_pins_a>;
+ pinctrl-1 = <&pcie_init_pins_a>;
+ reset-gpios = <&gpioj 8 GPIO_ACTIVE_LOW>;
+ access-controllers = <&rifsc 68>;
+ power-domains = <&CLUSTER_PD>;
+ };
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 05/10] PCI: stm32: Add PCIe Endpoint support for STM32MP25
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (3 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 04/10] dt-bindings: PCI: Add STM32MP25 PCIe Endpoint bindings Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 06/10] MAINTAINERS: add entry for ST STM32MP25 PCIe drivers Christian Bruel
` (4 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add driver to configure the STM32MP25 SoC PCIe Gen1 2.5GT/s or Gen2 5GT/s
controller based on the DesignWare PCIe core in endpoint mode.
Uses the common reference clock provided by the host.
The PCIe core_clk receives the pipe0_clk from the ComboPHY as input,
and the ComboPHY PLL must be locked for pipe0_clk to be ready.
Consequently, PCIe core registers cannot be accessed until the ComboPHY is
fully initialised and refclk is enabled and ready.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
drivers/pci/controller/dwc/Kconfig | 12 +
drivers/pci/controller/dwc/Makefile | 1 +
drivers/pci/controller/dwc/pcie-stm32-ep.c | 420 +++++++++++++++++++++
drivers/pci/controller/dwc/pcie-stm32.h | 1 +
4 files changed, 434 insertions(+)
create mode 100644 drivers/pci/controller/dwc/pcie-stm32-ep.c
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 0c18879b604c..4a3eb838557c 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -401,6 +401,18 @@ config PCIE_STM32
This driver can also be built as a module. If so, the module
will be called pcie-stm32.
+config PCIE_STM32_EP
+ tristate "STMicroelectronics STM32MP25 PCIe Controller (endpoint mode)"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on PCI_ENDPOINT
+ select PCIE_DW_EP
+ help
+ Enables endpoint support for DesignWare core based PCIe controller
+ found in STM32MP25 SoC.
+
+ This driver can also be built as a module. If so, the module
+ will be called pcie-stm32-ep.
+
config PCI_DRA7XX
tristate
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 576d99cb3bc5..caebd98f6dd3 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
obj-$(CONFIG_PCIE_STM32) += pcie-stm32.o
+obj-$(CONFIG_PCIE_STM32_EP) += pcie-stm32-ep.o
# The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access.
diff --git a/drivers/pci/controller/dwc/pcie-stm32-ep.c b/drivers/pci/controller/dwc/pcie-stm32-ep.c
new file mode 100644
index 000000000000..317875570636
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-stm32-ep.c
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics STM32MP25 PCIe endpoint driver.
+ *
+ * Copyright (C) 2024 STMicroelectronics
+ * Author: Christian Bruel <christian.bruel@foss.st.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include "pcie-designware.h"
+#include "pcie-stm32.h"
+
+enum stm32_pcie_ep_link_status {
+ STM32_PCIE_EP_LINK_DISABLED,
+ STM32_PCIE_EP_LINK_ENABLED,
+};
+
+struct stm32_pcie {
+ struct dw_pcie pci;
+ struct regmap *regmap;
+ struct reset_control *rst;
+ struct phy *phy;
+ struct clk *clk;
+ struct gpio_desc *perst_gpio;
+ enum stm32_pcie_ep_link_status link_status;
+ unsigned int perst_irq;
+};
+
+static void stm32_pcie_ep_init(struct dw_pcie_ep *ep)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ enum pci_barno bar;
+
+ for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
+ dw_pcie_ep_reset_bar(pci, bar);
+}
+
+static int stm32_pcie_enable_link(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+
+ regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
+ STM32MP25_PCIECR_LTSSM_EN,
+ STM32MP25_PCIECR_LTSSM_EN);
+
+ return dw_pcie_wait_for_link(pci);
+}
+
+static void stm32_pcie_disable_link(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+
+ regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR, STM32MP25_PCIECR_LTSSM_EN, 0);
+}
+
+static int stm32_pcie_start_link(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+ struct dw_pcie_ep *ep = &pci->ep;
+ int ret;
+
+ if (stm32_pcie->link_status == STM32_PCIE_EP_LINK_ENABLED) {
+ dev_dbg(pci->dev, "Link is already enabled\n");
+ return 0;
+ }
+
+ ret = stm32_pcie_enable_link(pci);
+ if (ret) {
+ dev_err(pci->dev, "PCIe cannot establish link: %d\n", ret);
+ return ret;
+ }
+
+ dw_pcie_ep_linkup(ep);
+
+ stm32_pcie->link_status = STM32_PCIE_EP_LINK_ENABLED;
+
+ enable_irq(stm32_pcie->perst_irq);
+
+ return 0;
+}
+
+static void stm32_pcie_stop_link(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+
+ if (stm32_pcie->link_status == STM32_PCIE_EP_LINK_DISABLED) {
+ dev_dbg(pci->dev, "Link is already disabled\n");
+ return;
+ }
+
+ disable_irq(stm32_pcie->perst_irq);
+
+ stm32_pcie_disable_link(pci);
+
+ stm32_pcie->link_status = STM32_PCIE_EP_LINK_DISABLED;
+}
+
+static int stm32_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
+ unsigned int type, u16 interrupt_num)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ switch (type) {
+ case PCI_IRQ_INTX:
+ return dw_pcie_ep_raise_intx_irq(ep, func_no);
+ case PCI_IRQ_MSI:
+ return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
+ default:
+ dev_err(pci->dev, "UNKNOWN IRQ type\n");
+ return -EINVAL;
+ }
+}
+
+static const struct pci_epc_features stm32_pcie_epc_features = {
+ .msi_capable = true,
+ .align = SZ_64K,
+};
+
+static const struct pci_epc_features*
+stm32_pcie_get_features(struct dw_pcie_ep *ep)
+{
+ return &stm32_pcie_epc_features;
+}
+
+static const struct dw_pcie_ep_ops stm32_pcie_ep_ops = {
+ .init = stm32_pcie_ep_init,
+ .raise_irq = stm32_pcie_raise_irq,
+ .get_features = stm32_pcie_get_features,
+};
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+ .start_link = stm32_pcie_start_link,
+ .stop_link = stm32_pcie_stop_link,
+};
+
+static int stm32_pcie_enable_resources(struct stm32_pcie *stm32_pcie)
+{
+ int ret;
+
+ ret = phy_init(stm32_pcie->phy);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(stm32_pcie->clk);
+ if (ret)
+ phy_exit(stm32_pcie->phy);
+
+ return ret;
+}
+
+static void stm32_pcie_disable_resources(struct stm32_pcie *stm32_pcie)
+{
+ clk_disable_unprepare(stm32_pcie->clk);
+
+ phy_exit(stm32_pcie->phy);
+}
+
+static void stm32_pcie_perst_assert(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+ struct device *dev = pci->dev;
+
+ dev_dbg(dev, "PERST asserted by host. Shutting down the PCIe link\n");
+
+ /*
+ * Do not try to release resources if the PERST# is
+ * asserted before the link is started.
+ */
+ if (stm32_pcie->link_status == STM32_PCIE_EP_LINK_DISABLED) {
+ dev_dbg(pci->dev, "Link is already disabled\n");
+ return;
+ }
+
+ stm32_pcie_disable_link(pci);
+
+ stm32_pcie_disable_resources(stm32_pcie);
+
+ pm_runtime_put_sync(dev);
+
+ stm32_pcie->link_status = STM32_PCIE_EP_LINK_DISABLED;
+}
+
+static void stm32_pcie_perst_deassert(struct dw_pcie *pci)
+{
+ struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
+ struct device *dev = pci->dev;
+ struct dw_pcie_ep *ep = &pci->ep;
+ int ret;
+
+ if (stm32_pcie->link_status == STM32_PCIE_EP_LINK_ENABLED) {
+ dev_dbg(pci->dev, "Link is already enabled\n");
+ return;
+ }
+
+ dev_dbg(dev, "PERST de-asserted by host. Starting link training\n");
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm runtime resume failed: %d\n", ret);
+ return;
+ }
+
+ ret = stm32_pcie_enable_resources(stm32_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to enable resources: %d\n", ret);
+ goto err_pm_put_sync;
+ }
+
+ ret = dw_pcie_ep_init_registers(ep);
+ if (ret) {
+ dev_err(dev, "Failed to complete initialization: %d\n", ret);
+ goto err_disable_resources;
+ }
+
+ pci_epc_init_notify(ep->epc);
+
+ ret = stm32_pcie_enable_link(pci);
+ if (ret) {
+ dev_err(dev, "PCIe Cannot establish link: %d\n", ret);
+ goto err_deinit_notify;
+ }
+
+ stm32_pcie->link_status = STM32_PCIE_EP_LINK_ENABLED;
+
+ return;
+
+err_deinit_notify:
+ pci_epc_deinit_notify(ep->epc);
+
+err_disable_resources:
+ stm32_pcie_disable_resources(stm32_pcie);
+
+err_pm_put_sync:
+ pm_runtime_put_sync(dev);
+}
+
+static irqreturn_t stm32_pcie_ep_perst_irq_thread(int irq, void *data)
+{
+ struct stm32_pcie *stm32_pcie = data;
+ struct dw_pcie *pci = &stm32_pcie->pci;
+ u32 perst;
+
+ perst = gpiod_get_value(stm32_pcie->perst_gpio);
+ if (perst)
+ stm32_pcie_perst_assert(pci);
+ else
+ stm32_pcie_perst_deassert(pci);
+
+ return IRQ_HANDLED;
+}
+
+static int stm32_add_pcie_ep(struct stm32_pcie *stm32_pcie,
+ struct platform_device *pdev)
+{
+ struct dw_pcie_ep *ep = &stm32_pcie->pci.ep;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm runtime resume failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
+ STM32MP25_PCIECR_TYPE_MASK,
+ STM32MP25_PCIECR_EP);
+ if (ret) {
+ goto err_pm_put_sync;
+ return ret;
+ }
+
+ reset_control_assert(stm32_pcie->rst);
+ reset_control_deassert(stm32_pcie->rst);
+
+ ep->ops = &stm32_pcie_ep_ops;
+
+ ret = dw_pcie_ep_init(ep);
+ if (ret) {
+ dev_err(dev, "failed to initialize ep: %d\n", ret);
+ goto err_pm_put_sync;
+ }
+
+ ret = stm32_pcie_enable_resources(stm32_pcie);
+ if (ret) {
+ dev_err(dev, "failed to enable resources: %d\n", ret);
+ goto err_ep_deinit;
+ }
+
+ ret = dw_pcie_ep_init_registers(ep);
+ if (ret) {
+ dev_err(dev, "Failed to initialize DWC endpoint registers\n");
+ goto err_disable_resources;
+ }
+
+ pci_epc_init_notify(ep->epc);
+
+ return 0;
+
+err_disable_resources:
+ stm32_pcie_disable_resources(stm32_pcie);
+
+err_ep_deinit:
+ dw_pcie_ep_deinit(ep);
+
+err_pm_put_sync:
+ pm_runtime_put_sync(dev);
+ return ret;
+}
+
+static int stm32_pcie_probe(struct platform_device *pdev)
+{
+ struct stm32_pcie *stm32_pcie;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ stm32_pcie = devm_kzalloc(dev, sizeof(*stm32_pcie), GFP_KERNEL);
+ if (!stm32_pcie)
+ return -ENOMEM;
+
+ stm32_pcie->pci.dev = dev;
+ stm32_pcie->pci.ops = &dw_pcie_ops;
+
+ stm32_pcie->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
+ if (IS_ERR(stm32_pcie->regmap))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->regmap),
+ "No syscfg specified\n");
+
+ stm32_pcie->phy = devm_phy_get(dev, NULL);
+ if (IS_ERR(stm32_pcie->phy))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
+ "failed to get pcie-phy\n");
+
+ stm32_pcie->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(stm32_pcie->clk))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->clk),
+ "Failed to get PCIe clock source\n");
+
+ stm32_pcie->rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(stm32_pcie->rst))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->rst),
+ "Failed to get PCIe reset\n");
+
+ stm32_pcie->perst_gpio = devm_gpiod_get(dev, "reset", GPIOD_IN);
+ if (IS_ERR(stm32_pcie->perst_gpio))
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
+ "Failed to get reset GPIO\n");
+
+ ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, stm32_pcie);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable pm runtime %d\n", ret);
+ return ret;
+ }
+
+ stm32_pcie->perst_irq = gpiod_to_irq(stm32_pcie->perst_gpio);
+
+ /* Will be enabled in start_link when device is initialized. */
+ irq_set_status_flags(stm32_pcie->perst_irq, IRQ_NOAUTOEN);
+
+ ret = devm_request_threaded_irq(dev, stm32_pcie->perst_irq, NULL,
+ stm32_pcie_ep_perst_irq_thread,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "perst_irq", stm32_pcie);
+ if (ret) {
+ dev_err(dev, "Failed to request PERST IRQ: %d\n", ret);
+ return ret;
+ }
+
+ return stm32_add_pcie_ep(stm32_pcie, pdev);
+}
+
+static void stm32_pcie_remove(struct platform_device *pdev)
+{
+ struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
+ struct dw_pcie_ep *ep = &stm32_pcie->pci.ep;
+
+ disable_irq(stm32_pcie->perst_irq);
+
+ dw_pcie_ep_deinit(ep);
+
+ stm32_pcie_disable_resources(stm32_pcie);
+
+ pm_runtime_put_sync(&pdev->dev);
+}
+
+static const struct of_device_id stm32_pcie_ep_of_match[] = {
+ { .compatible = "st,stm32mp25-pcie-ep" },
+ {},
+};
+
+static struct platform_driver stm32_pcie_ep_driver = {
+ .probe = stm32_pcie_probe,
+ .remove = stm32_pcie_remove,
+ .driver = {
+ .name = "stm32-ep-pcie",
+ .of_match_table = stm32_pcie_ep_of_match,
+ },
+};
+
+module_platform_driver(stm32_pcie_ep_driver);
+
+MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
+MODULE_DESCRIPTION("STM32MP25 PCIe Endpoint Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, stm32_pcie_ep_of_match);
diff --git a/drivers/pci/controller/dwc/pcie-stm32.h b/drivers/pci/controller/dwc/pcie-stm32.h
index 3efd00937d3d..6eb684848082 100644
--- a/drivers/pci/controller/dwc/pcie-stm32.h
+++ b/drivers/pci/controller/dwc/pcie-stm32.h
@@ -9,6 +9,7 @@
#define to_stm32_pcie(x) dev_get_drvdata((x)->dev)
#define STM32MP25_PCIECR_TYPE_MASK GENMASK(11, 8)
+#define STM32MP25_PCIECR_EP 0
#define STM32MP25_PCIECR_LTSSM_EN BIT(2)
#define STM32MP25_PCIECR_RC BIT(10)
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 06/10] MAINTAINERS: add entry for ST STM32MP25 PCIe drivers
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (4 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 05/10] PCI: stm32: Add PCIe Endpoint support for STM32MP25 Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 07/10] arm64: dts: st: add PCIe pinctrl entries in stm32mp25-pinctrl.dtsi Christian Bruel
` (3 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add myself as maintainer of STM32MP25 PCIe host and PCIe endpoint drivers
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 33b9cd11a3a4..d8f2de1a3543 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18108,6 +18108,13 @@ L: linux-samsung-soc@vger.kernel.org
S: Maintained
F: drivers/pci/controller/dwc/pci-exynos.c
+PCI DRIVER FOR STM32MP25
+M: Christian Bruel <christian.bruel@foss.st.com>
+L: linux-pci@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/pci/st,stm32-pcie-*.yaml
+F: drivers/pci/controller/dwc/*stm32*
+
PCI DRIVER FOR SYNOPSYS DESIGNWARE
M: Jingoo Han <jingoohan1@gmail.com>
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 07/10] arm64: dts: st: add PCIe pinctrl entries in stm32mp25-pinctrl.dtsi
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (5 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 06/10] MAINTAINERS: add entry for ST STM32MP25 PCIe drivers Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 08/10] arm64: dts: st: Add PCIe Rootcomplex mode on stm32mp251 Christian Bruel
` (2 subsequent siblings)
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add PCIe pinctrl entries in stm32mp25-pinctrl.dtsi
init: forces GPIO to low while probing so CLKREQ is low for
phy_init
default: restore the AFMUX after controller probe
Add Analog pins of PCIe to perform power cycle
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
index 8fdd5f020425..f0d814bc7c60 100644
--- a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
@@ -82,6 +82,26 @@ pins {
};
};
+ pcie_pins_a: pcie-0 {
+ pins {
+ pinmux = <STM32_PINMUX('J', 0, AF4)>;
+ bias-disable;
+ };
+ };
+
+ pcie_init_pins_a: pcie-init-0 {
+ pins {
+ pinmux = <STM32_PINMUX('J', 0, GPIO)>;
+ output-low;
+ };
+ };
+
+ pcie_sleep_pins_a: pcie-sleep-0 {
+ pins {
+ pinmux = <STM32_PINMUX('J', 0, ANALOG)>;
+ };
+ };
+
sdmmc1_b4_pins_a: sdmmc1-b4-0 {
pins1 {
pinmux = <STM32_PINMUX('E', 4, AF10)>, /* SDMMC1_D0 */
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 08/10] arm64: dts: st: Add PCIe Rootcomplex mode on stm32mp251
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (6 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 07/10] arm64: dts: st: add PCIe pinctrl entries in stm32mp25-pinctrl.dtsi Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 09/10] arm64: dts: st: Add PCIe Endpoint " Christian Bruel
2025-01-28 12:07 ` [PATCH v4 10/10] arm64: dts: st: Enable PCIe on the stm32mp257f-ev1 board Christian Bruel
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add pcie_rc node to support STM32 MP25 PCIe driver based on the
DesignWare PCIe core configured as Rootcomplex mode
Supports Gen1/Gen2, single lane, MSI interrupts using the ARM GICv2m
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp251.dtsi | 44 +++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index f3c6cdfd7008..6cd1a765fac9 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -117,12 +117,20 @@ scmi_vdda18adc: regulator@7 {
intc: interrupt-controller@4ac00000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
- #address-cells = <1>;
+ #address-cells = <2>;
+ #size-cells = <2>;
interrupt-controller;
reg = <0x0 0x4ac10000 0x0 0x1000>,
<0x0 0x4ac20000 0x0 0x2000>,
<0x0 0x4ac40000 0x0 0x2000>,
<0x0 0x4ac60000 0x0 0x2000>;
+ ranges;
+
+ v2m0: v2m@48090000 {
+ compatible = "arm,gic-v2m-frame";
+ reg = <0x0 0x48090000 0x0 0x1000>;
+ msi-controller;
+ };
};
psci {
@@ -900,6 +908,40 @@ stmmac_axi_config_1: stmmac-axi-config {
snps,wr_osr_lmt = <0x7>;
};
};
+
+ pcie_rc: pcie@48400000 {
+ compatible = "st,stm32mp25-pcie-rc";
+ device_type = "pci";
+ reg = <0x48400000 0x400000>,
+ <0x10000000 0x10000>;
+ reg-names = "dbi", "config";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 2 &intc 0 0 GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 3 &intc 0 0 GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 0 4 &intc 0 0 GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges = <0x01000000 0x0 0x00000000 0x10010000 0x0 0x10000>,
+ <0x02000000 0x0 0x10020000 0x10020000 0x0 0x7fe0000>,
+ <0x42000000 0x0 0x18000000 0x18000000 0x0 0x8000000>;
+ dma-ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x80000000>;
+ clocks = <&rcc CK_BUS_PCIE>;
+ resets = <&rcc PCIE_R>;
+ msi-parent = <&v2m0>;
+ access-controllers = <&rifsc 68>;
+ status = "disabled";
+
+ pcie@0,0 {
+ device_type = "pci";
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ phys = <&combophy PHY_TYPE_PCIE>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ ranges;
+ };
+ };
};
bsec: efuse@44000000 {
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 09/10] arm64: dts: st: Add PCIe Endpoint mode on stm32mp251
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (7 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 08/10] arm64: dts: st: Add PCIe Rootcomplex mode on stm32mp251 Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 10/10] arm64: dts: st: Enable PCIe on the stm32mp257f-ev1 board Christian Bruel
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add pcie_ep node to support STM32 MP25 PCIe driver based on the
DesignWare PCIe core configured as Endpoint mode
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp251.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index 6cd1a765fac9..07c2d2c386f4 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -909,6 +909,19 @@ stmmac_axi_config_1: stmmac-axi-config {
};
};
+ pcie_ep: pcie-ep@48400000 {
+ compatible = "st,stm32mp25-pcie-ep";
+ reg = <0x48400000 0x400000>,
+ <0x10000000 0x8000000>;
+ reg-names = "dbi", "addr_space";
+ clocks = <&rcc CK_BUS_PCIE>;
+ resets = <&rcc PCIE_R>;
+ phys = <&combophy PHY_TYPE_PCIE>;
+ access-controllers = <&rifsc 68>;
+ power-domains = <&CLUSTER_PD>;
+ status = "disabled";
+ };
+
pcie_rc: pcie@48400000 {
compatible = "st,stm32mp25-pcie-rc";
device_type = "pci";
@@ -931,6 +944,7 @@ pcie_rc: pcie@48400000 {
resets = <&rcc PCIE_R>;
msi-parent = <&v2m0>;
access-controllers = <&rifsc 68>;
+ power-domains = <&CLUSTER_PD>;
status = "disabled";
pcie@0,0 {
@@ -942,6 +956,8 @@ pcie@0,0 {
ranges;
};
};
+
+
};
bsec: efuse@44000000 {
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 10/10] arm64: dts: st: Enable PCIe on the stm32mp257f-ev1 board
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
` (8 preceding siblings ...)
2025-01-28 12:07 ` [PATCH v4 09/10] arm64: dts: st: Add PCIe Endpoint " Christian Bruel
@ 2025-01-28 12:07 ` Christian Bruel
9 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-01-28 12:07 UTC (permalink / raw)
To: christian.bruel, bhelgaas, lpieralisi, kw, manivannan.sadhasivam,
robh, krzk+dt, conor+dt, mcoquelin.stm32, alexandre.torgue,
jingoohan1, p.zabel, johan+linaro, quic_schintav, cassel
Cc: linux-pci, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, fabrice.gasnier
Add PCIe RC and EP support on stm32mp257f-ev1 board, and enable RC mode
by default.
Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 1b88485a62a1..1a3946f47b45 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -225,6 +225,28 @@ scmi_vdd_sdcard: regulator@23 {
};
};
+&pcie_ep {
+ pinctrl-names = "default", "init";
+ pinctrl-0 = <&pcie_pins_a>;
+ pinctrl-1 = <&pcie_init_pins_a>;
+ reset-gpios = <&gpioj 8 GPIO_ACTIVE_LOW>;
+ status = "disabled";
+};
+
+&pcie_rc {
+ pinctrl-names = "default", "init", "sleep";
+ pinctrl-0 = <&pcie_pins_a>;
+ pinctrl-1 = <&pcie_init_pins_a>;
+ pinctrl-2 = <&pcie_sleep_pins_a>;
+ wakeup-source;
+ status = "okay";
+
+ pcie@0,0 {
+ reset-gpios = <&gpioj 8 GPIO_ACTIVE_LOW>;
+ wake-gpios = <&gpioh 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
+ };
+};
+
&sdmmc1 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc1_b4_pins_a>;
--
2.34.1
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings
2025-01-28 12:07 ` [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Christian Bruel
@ 2025-01-29 15:44 ` Rob Herring
2025-02-02 12:25 ` Manivannan Sadhasivam
1 sibling, 0 replies; 17+ messages in thread
From: Rob Herring @ 2025-01-29 15:44 UTC (permalink / raw)
To: Christian Bruel
Cc: bhelgaas, lpieralisi, kw, manivannan.sadhasivam, krzk+dt,
conor+dt, mcoquelin.stm32, alexandre.torgue, jingoohan1, p.zabel,
johan+linaro, quic_schintav, cassel, linux-pci, devicetree,
linux-stm32, linux-arm-kernel, linux-kernel, fabrice.gasnier
On Tue, Jan 28, 2025 at 01:07:36PM +0100, Christian Bruel wrote:
> Document the bindings for STM32MP25 PCIe Controller configured in
> root complex mode with one root port.
>
> Supports 4 INTx and MSI interrupts from the ARM GICv2m controller.
>
> STM32 PCIe may be in a power domain which is the case for the STM32MP25
> based boards.
>
> Supports WAKE# from wake-gpios
>
> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
> ---
> .../bindings/pci/st,stm32-pcie-common.yaml | 33 +++++
> .../bindings/pci/st,stm32-pcie-host.yaml | 116 ++++++++++++++++++
> 2 files changed, 149 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-common.yaml
> create mode 100644 Documentation/devicetree/bindings/pci/st,stm32-pcie-host.yaml
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings
2025-01-28 12:07 ` [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Christian Bruel
2025-01-29 15:44 ` Rob Herring
@ 2025-02-02 12:25 ` Manivannan Sadhasivam
2025-02-04 11:07 ` Christian Bruel
1 sibling, 1 reply; 17+ messages in thread
From: Manivannan Sadhasivam @ 2025-02-02 12:25 UTC (permalink / raw)
To: Christian Bruel
Cc: bhelgaas, lpieralisi, kw, robh, krzk+dt, conor+dt,
mcoquelin.stm32, alexandre.torgue, jingoohan1, p.zabel,
johan+linaro, quic_schintav, cassel, linux-pci, devicetree,
linux-stm32, linux-arm-kernel, linux-kernel, fabrice.gasnier
On Tue, Jan 28, 2025 at 01:07:36PM +0100, Christian Bruel wrote:
[...]
> + pcie@48400000 {
> + compatible = "st,stm32mp25-pcie-rc";
> + device_type = "pci";
> + reg = <0x48400000 0x400000>,
> + <0x10000000 0x10000>;
> + reg-names = "dbi", "config";
> + #interrupt-cells = <1>;
> + interrupt-map-mask = <0 0 0 7>;
> + interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 2 &intc 0 0 GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 3 &intc 0 0 GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
> + <0 0 0 4 &intc 0 0 GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
> + #address-cells = <3>;
> + #size-cells = <2>;
> + ranges = <0x01000000 0x0 0x00000000 0x10010000 0x0 0x10000>,
> + <0x02000000 0x0 0x10020000 0x10020000 0x0 0x7fe0000>,
> + <0x42000000 0x0 0x18000000 0x18000000 0x0 0x8000000>;
> + dma-ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x80000000>;
> + clocks = <&rcc CK_BUS_PCIE>;
> + resets = <&rcc PCIE_R>;
> + msi-parent = <&v2m0>;
> + wakeup-source;
Does this property really need to be present? If the WAKE# gpio is supported,
isn't it implied that the RC is a wakeup source?
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25
2025-01-28 12:07 ` [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25 Christian Bruel
@ 2025-02-02 13:06 ` Manivannan Sadhasivam
2025-02-04 16:23 ` Christian Bruel
0 siblings, 1 reply; 17+ messages in thread
From: Manivannan Sadhasivam @ 2025-02-02 13:06 UTC (permalink / raw)
To: Christian Bruel
Cc: bhelgaas, lpieralisi, kw, robh, krzk+dt, conor+dt,
mcoquelin.stm32, alexandre.torgue, jingoohan1, p.zabel,
johan+linaro, quic_schintav, cassel, linux-pci, devicetree,
linux-stm32, linux-arm-kernel, linux-kernel, fabrice.gasnier
On Tue, Jan 28, 2025 at 01:07:38PM +0100, Christian Bruel wrote:
> Add driver for the STM32MP25 SoC PCIe Gen1 2.5 GT/s and Gen2 5GT/s
> controller based on the DesignWare PCIe core.
>
> Supports MSI via GICv2m, Single Virtual Channel, Single Function
>
> Supports wakeup-source from gpio wake_irq with dw_pcie_wake_irq_handler
> for host wakeup.
>
"Supports WAKE# GPIO" is what should be mentioned above.
> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
> ---
> drivers/pci/controller/dwc/Kconfig | 12 +
> drivers/pci/controller/dwc/Makefile | 1 +
> drivers/pci/controller/dwc/pcie-stm32.c | 372 ++++++++++++++++++++++++
> drivers/pci/controller/dwc/pcie-stm32.h | 15 +
> 4 files changed, 400 insertions(+)
> create mode 100644 drivers/pci/controller/dwc/pcie-stm32.c
> create mode 100644 drivers/pci/controller/dwc/pcie-stm32.h
>
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index b6d6778b0698..0c18879b604c 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -389,6 +389,18 @@ config PCIE_SPEAR13XX
> help
> Say Y here if you want PCIe support on SPEAr13XX SoCs.
>
> +config PCIE_STM32
> + tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)"
> + depends on ARCH_STM32 || COMPILE_TEST
> + depends on PCI_MSI
> + select PCIE_DW_HOST
> + help
> + Enables support for the DesignWare core based PCIe host controller
> + found in STM32MP25 SoC.
> +
> + This driver can also be built as a module. If so, the module
> + will be called pcie-stm32.
> +
> config PCI_DRA7XX
> tristate
>
> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
> index a8308d9ea986..576d99cb3bc5 100644
> --- a/drivers/pci/controller/dwc/Makefile
> +++ b/drivers/pci/controller/dwc/Makefile
> @@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
> obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
> obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
> obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
> +obj-$(CONFIG_PCIE_STM32) += pcie-stm32.o
>
> # The following drivers are for devices that use the generic ACPI
> # pci_root.c driver but don't support standard ECAM config access.
> diff --git a/drivers/pci/controller/dwc/pcie-stm32.c b/drivers/pci/controller/dwc/pcie-stm32.c
> new file mode 100644
> index 000000000000..d5e473bb390f
> --- /dev/null
> +++ b/drivers/pci/controller/dwc/pcie-stm32.c
> @@ -0,0 +1,372 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * STMicroelectronics STM32MP25 PCIe root complex driver.
> + *
> + * Copyright (C) 2024 STMicroelectronics
2025?
> + * Author: Christian Bruel <christian.bruel@foss.st.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/pinctrl/devinfo.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include "pcie-designware.h"
> +#include "pcie-stm32.h"
> +#include "../../pci.h"
> +
> +struct stm32_pcie {
> + struct dw_pcie pci;
> + struct regmap *regmap;
> + struct reset_control *rst;
> + struct phy *phy;
> + struct clk *clk;
> + struct gpio_desc *perst_gpio;
> + struct gpio_desc *wake_gpio;
> + unsigned int wake_irq;
> +};
> +
> +static void stm32_pcie_deassert_perst(struct stm32_pcie *stm32_pcie)
> +{
> + gpiod_set_value(stm32_pcie->perst_gpio, 0);
> +
> + if (stm32_pcie->perst_gpio)
> + msleep(PCIE_T_RRS_READY_MS);
> +}
> +
> +static void stm32_pcie_assert_perst(struct stm32_pcie *stm32_pcie)
> +{
> + gpiod_set_value(stm32_pcie->perst_gpio, 1);
> +}
> +
> +static int stm32_pcie_start_link(struct dw_pcie *pci)
> +{
> + struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
> +
> + return regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
> + STM32MP25_PCIECR_LTSSM_EN,
> + STM32MP25_PCIECR_LTSSM_EN);
> +}
> +
> +static void stm32_pcie_stop_link(struct dw_pcie *pci)
> +{
> + struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
> +
> + regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
> + STM32MP25_PCIECR_LTSSM_EN, 0);
> +}
> +
> +static int stm32_pcie_suspend(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev))
> + enable_irq_wake(stm32_pcie->wake_irq);
> +
> + return 0;
> +}
> +
> +static int stm32_pcie_resume(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> +
> + if (device_may_wakeup(dev))
> + disable_irq_wake(stm32_pcie->wake_irq);
> +
> + return 0;
> +}
> +
> +static int stm32_pcie_suspend_noirq(struct device *dev)
> +{
Can you consider making use of dw_pcie_{suspend/resume}_noirq()?
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> +
> + stm32_pcie_stop_link(&stm32_pcie->pci);
> +
> + stm32_pcie_assert_perst(stm32_pcie);
> +
> + clk_disable_unprepare(stm32_pcie->clk);
> +
> + if (!device_may_wakeup(dev))
> + phy_exit(stm32_pcie->phy);
> +
> + return pinctrl_pm_select_sleep_state(dev);
> +}
> +
> +static int stm32_pcie_resume_noirq(struct device *dev)
> +{
> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
> + int ret;
> +
> + /*
> + * The core clock is gated with CLKREQ# from the COMBOPHY REFCLK,
> + * thus if no device is present, must force it low with an init pinmux
> + * to be able to access the DBI registers.
> + */
> + if (!IS_ERR(dev->pins->init_state))
> + ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
> + else
> + ret = pinctrl_pm_select_default_state(dev);
> +
> + if (ret) {
> + dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
> + return ret;
> + }
> +
> + if (!device_may_wakeup(dev)) {
> + ret = phy_init(stm32_pcie->phy);
> + if (ret) {
> + pinctrl_pm_select_default_state(dev);
> + return ret;
> + }
> + }
> +
> + ret = clk_prepare_enable(stm32_pcie->clk);
> + if (ret)
> + goto err_phy_exit;
> +
> + stm32_pcie_deassert_perst(stm32_pcie);
> +
> + ret = dw_pcie_setup_rc(pp);
> + if (ret)
> + goto err_disable_clk;
> +
> + ret = stm32_pcie_start_link(&stm32_pcie->pci);
> + if (ret)
> + goto err_disable_clk;
> +
> + /* Ignore errors, the link may come up later */
> + dw_pcie_wait_for_link(&stm32_pcie->pci);
These can be dropped when using dw_pcie_resume_noirq().
> +
> + pinctrl_pm_select_default_state(dev);
> +
> + return 0;
> +
> +err_disable_clk:
> + stm32_pcie_assert_perst(stm32_pcie);
> + clk_disable_unprepare(stm32_pcie->clk);
> +
> +err_phy_exit:
> + phy_exit(stm32_pcie->phy);
> + pinctrl_pm_select_default_state(dev);
> +
> + return ret;
> +}
> +
> +static const struct dev_pm_ops stm32_pcie_pm_ops = {
> + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend_noirq,
> + stm32_pcie_resume_noirq)
> + SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend, stm32_pcie_resume)
> +};
> +
> +static const struct dw_pcie_host_ops stm32_pcie_host_ops = {
> +};
> +
> +static const struct dw_pcie_ops dw_pcie_ops = {
> + .start_link = stm32_pcie_start_link,
> + .stop_link = stm32_pcie_stop_link
> +};
> +
> +static int stm32_add_pcie_port(struct stm32_pcie *stm32_pcie,
> + struct platform_device *pdev)
> +{
> + struct device *dev = stm32_pcie->pci.dev;
> + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
> + int ret;
> +
You need to assert PERST# before configuring the resources.
> + ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
> + if (ret)
> + return ret;
> +
> + ret = phy_init(stm32_pcie->phy);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
> + STM32MP25_PCIECR_TYPE_MASK,
> + STM32MP25_PCIECR_RC);
> + if (ret)
> + goto err_phy_exit;
> +
> + reset_control_assert(stm32_pcie->rst);
> + reset_control_deassert(stm32_pcie->rst);
> +
> + ret = clk_prepare_enable(stm32_pcie->clk);
> + if (ret) {
> + dev_err(dev, "Core clock enable failed %d\n", ret);
> + goto err_phy_exit;
> + }
> +
> + stm32_pcie_deassert_perst(stm32_pcie);
> +
> + pp->ops = &stm32_pcie_host_ops;
> + ret = dw_pcie_host_init(pp);
> + if (ret) {
> + dev_err(dev, "Failed to initialize host: %d\n", ret);
> + goto err_disable_clk;
> + }
Technically, dw_pcie_host_init() is not related to root port. So please move it
to probe() instead.
> +
> + return 0;
> +
> +err_disable_clk:
> + clk_disable_unprepare(stm32_pcie->clk);
> + stm32_pcie_assert_perst(stm32_pcie);
> +
> +err_phy_exit:
> + phy_exit(stm32_pcie->phy);
> +
> + return ret;
> +}
> +
> +static int stm32_pcie_parse_port(struct stm32_pcie *stm32_pcie)
> +{
> + struct device *dev = stm32_pcie->pci.dev;
> + struct device_node *root_port;
> +
> + root_port = of_get_next_available_child(dev->of_node, NULL);
> +
> + stm32_pcie->phy = devm_of_phy_get(dev, root_port, NULL);
> + if (IS_ERR(stm32_pcie->phy))
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
> + "Failed to get pcie-phy\n");
OF refcount not decremented in both the error and success case.
> +
> + stm32_pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
> + "reset", GPIOD_OUT_HIGH, NULL);
> + if (IS_ERR(stm32_pcie->perst_gpio)) {
> + if (PTR_ERR(stm32_pcie->perst_gpio) != -ENOENT)
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
> + "Failed to get reset GPIO\n");
> + stm32_pcie->perst_gpio = NULL;
> + }
> +
> + if (device_property_read_bool(dev, "wakeup-source")) {
As per the current logic, 'wakeup-source' is applicable even without WAKE# GPIO,
which doesn't make sense.
> + stm32_pcie->wake_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
> + "wake", GPIOD_IN, NULL);
> +
> + if (IS_ERR(stm32_pcie->wake_gpio)) {
> + if (PTR_ERR(stm32_pcie->wake_gpio) != -ENOENT)
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
> + "Failed to get wake GPIO\n");
> + stm32_pcie->wake_gpio = NULL;
> + }
Hmm. I think we need to move WAKE# handling inside drivers/pci/pcie/portdrv.c
since that is responsible for the root port. While other root port properties
have some dependency with the RC (like PERST#, PHY etc...), WAKE# handling could
be moved safely.
And once done, it can benefit all platforms.
> + }
> +
> + return 0;
> +}
> +
> +static int stm32_pcie_probe(struct platform_device *pdev)
> +{
> + struct stm32_pcie *stm32_pcie;
> + struct device *dev = &pdev->dev;
> + int ret;
> +
> + stm32_pcie = devm_kzalloc(dev, sizeof(*stm32_pcie), GFP_KERNEL);
> + if (!stm32_pcie)
> + return -ENOMEM;
> +
> + stm32_pcie->pci.dev = dev;
> + stm32_pcie->pci.ops = &dw_pcie_ops;
> +
> + stm32_pcie->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
> + if (IS_ERR(stm32_pcie->regmap))
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->regmap),
> + "No syscfg specified\n");
> +
> + stm32_pcie->clk = devm_clk_get(dev, NULL);
> + if (IS_ERR(stm32_pcie->clk))
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->clk),
> + "Failed to get PCIe clock source\n");
> +
> + stm32_pcie->rst = devm_reset_control_get_exclusive(dev, NULL);
> + if (IS_ERR(stm32_pcie->rst))
> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->rst),
> + "Failed to get PCIe reset\n");
> +
> + ret = stm32_pcie_parse_port(stm32_pcie);
> + if (ret)
> + return ret;
> +
> + platform_set_drvdata(pdev, stm32_pcie);
> +
> + if (stm32_pcie->wake_gpio) {
> + stm32_pcie->wake_irq = gpiod_to_irq(stm32_pcie->wake_gpio);
> +
> + ret = devm_request_threaded_irq(&pdev->dev,
> + stm32_pcie->wake_irq, NULL,
> + dw_pcie_wake_irq_handler,
> + IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> + "wake_irq", stm32_pcie->pci.dev);
> +
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to request WAKE IRQ: %d\n", ret);
> + }
> +
> + ret = devm_pm_runtime_enable(dev);
> + if (ret < 0) {
> + dev_err(dev, "Failed to enable runtime PM %d\n", ret);
> + return ret;
> + }
> +
> + ret = pm_runtime_resume_and_get(dev);
Why do you need to do PM resume here? Is there a parent that needs to be resumed
now? I know that other controller drivers have this pattern, but most of them
are just doing it wrong.
Most likely you need pm_runtime_set_active() before devm_pm_runtime_enable().
> + if (ret < 0) {
> + dev_err(dev, "Failed to get runtime PM %d\n", ret);
> + return ret;
> + }
> +
> + ret = stm32_add_pcie_port(stm32_pcie, pdev);
> + if (ret) {
Nit: double space.
> + pm_runtime_put_sync(&pdev->dev);
> + return ret;
> + }
> +
> + if (stm32_pcie->wake_gpio)
> + device_set_wakeup_capable(dev, true);
> +
> + return 0;
> +}
> +
> +static void stm32_pcie_remove(struct platform_device *pdev)
> +{
> + struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
> + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
> +
> + if (stm32_pcie->wake_gpio)
> + device_init_wakeup(&pdev->dev, false);
> +
> + dw_pcie_host_deinit(pp);
> +
> + stm32_pcie_assert_perst(stm32_pcie);
> +
> + clk_disable_unprepare(stm32_pcie->clk);
> +
> + phy_exit(stm32_pcie->phy);
> +
> + pm_runtime_put_sync(&pdev->dev);
> +}
> +
> +static const struct of_device_id stm32_pcie_of_match[] = {
> + { .compatible = "st,stm32mp25-pcie-rc" },
> + {},
> +};
> +
> +static struct platform_driver stm32_pcie_driver = {
> + .probe = stm32_pcie_probe,
> + .remove = stm32_pcie_remove,
> + .driver = {
> + .name = "stm32-pcie",
> + .of_match_table = stm32_pcie_of_match,
> + .pm = &stm32_pcie_pm_ops,
> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
> + },
> +};
> +
> +module_platform_driver(stm32_pcie_driver);
> +
> +MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
> +MODULE_DESCRIPTION("STM32MP25 PCIe Controller driver");
> +MODULE_LICENSE("GPL");
> +MODULE_DEVICE_TABLE(of, stm32_pcie_of_match);
> diff --git a/drivers/pci/controller/dwc/pcie-stm32.h b/drivers/pci/controller/dwc/pcie-stm32.h
> new file mode 100644
> index 000000000000..3efd00937d3d
> --- /dev/null
> +++ b/drivers/pci/controller/dwc/pcie-stm32.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * ST PCIe driver definitions for STM32-MP25 SoC
> + *
> + * Copyright (C) 2024 STMicroelectronics - All Rights Reserved
> + * Author: Christian Bruel <christian.bruel@foss.st.com>
> + */
> +
> +#define to_stm32_pcie(x) dev_get_drvdata((x)->dev)
> +
> +#define STM32MP25_PCIECR_TYPE_MASK GENMASK(11, 8)
> +#define STM32MP25_PCIECR_LTSSM_EN BIT(2)
> +#define STM32MP25_PCIECR_RC BIT(10)
> +
> +#define SYSCFG_PCIECR 0x6000
You can just move these definitions inside the driver itself.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings
2025-02-02 12:25 ` Manivannan Sadhasivam
@ 2025-02-04 11:07 ` Christian Bruel
0 siblings, 0 replies; 17+ messages in thread
From: Christian Bruel @ 2025-02-04 11:07 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: bhelgaas, lpieralisi, kw, robh, krzk+dt, conor+dt,
mcoquelin.stm32, alexandre.torgue, jingoohan1, p.zabel,
johan+linaro, quic_schintav, cassel, linux-pci, devicetree,
linux-stm32, linux-arm-kernel, linux-kernel, fabrice.gasnier
On 2/2/25 13:25, Manivannan Sadhasivam wrote:
> On Tue, Jan 28, 2025 at 01:07:36PM +0100, Christian Bruel wrote:
>
> [...]
>
>> + pcie@48400000 {
>> + compatible = "st,stm32mp25-pcie-rc";
>> + device_type = "pci";
>> + reg = <0x48400000 0x400000>,
>> + <0x10000000 0x10000>;
>> + reg-names = "dbi", "config";
>> + #interrupt-cells = <1>;
>> + interrupt-map-mask = <0 0 0 7>;
>> + interrupt-map = <0 0 0 1 &intc 0 0 GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>,
>> + <0 0 0 2 &intc 0 0 GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
>> + <0 0 0 3 &intc 0 0 GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
>> + <0 0 0 4 &intc 0 0 GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>;
>> + #address-cells = <3>;
>> + #size-cells = <2>;
>> + ranges = <0x01000000 0x0 0x00000000 0x10010000 0x0 0x10000>,
>> + <0x02000000 0x0 0x10020000 0x10020000 0x0 0x7fe0000>,
>> + <0x42000000 0x0 0x18000000 0x18000000 0x0 0x8000000>;
>> + dma-ranges = <0x42000000 0x0 0x80000000 0x80000000 0x0 0x80000000>;
>> + clocks = <&rcc CK_BUS_PCIE>;
>> + resets = <&rcc PCIE_R>;
>> + msi-parent = <&v2m0>;
>> + wakeup-source;
>
> Does this property really need to be present? If the WAKE# gpio is supported,
> isn't it implied that the RC is a wakeup source?
>
the wakeup-source property is useless indeed with the wake_gpio, will
remove,
thanks.
Christian
> - Mani
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25
2025-02-02 13:06 ` Manivannan Sadhasivam
@ 2025-02-04 16:23 ` Christian Bruel
2025-02-07 18:24 ` Manivannan Sadhasivam
0 siblings, 1 reply; 17+ messages in thread
From: Christian Bruel @ 2025-02-04 16:23 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: bhelgaas, lpieralisi, kw, robh, krzk+dt, conor+dt,
mcoquelin.stm32, alexandre.torgue, jingoohan1, p.zabel,
johan+linaro, quic_schintav, cassel, linux-pci, devicetree,
linux-stm32, linux-arm-kernel, linux-kernel, fabrice.gasnier
On 2/2/25 14:06, Manivannan Sadhasivam wrote:
> On Tue, Jan 28, 2025 at 01:07:38PM +0100, Christian Bruel wrote:
>> Add driver for the STM32MP25 SoC PCIe Gen1 2.5 GT/s and Gen2 5GT/s
>> controller based on the DesignWare PCIe core.
>>
>> Supports MSI via GICv2m, Single Virtual Channel, Single Function
>>
>> Supports wakeup-source from gpio wake_irq with dw_pcie_wake_irq_handler
>> for host wakeup.
>>
>
> "Supports WAKE# GPIO" is what should be mentioned above.
OK. dropping wakeup-source property as well
>
>> Signed-off-by: Christian Bruel <christian.bruel@foss.st.com>
>> ---
>> drivers/pci/controller/dwc/Kconfig | 12 +
>> drivers/pci/controller/dwc/Makefile | 1 +
>> drivers/pci/controller/dwc/pcie-stm32.c | 372 ++++++++++++++++++++++++
>> drivers/pci/controller/dwc/pcie-stm32.h | 15 +
>> 4 files changed, 400 insertions(+)
>> create mode 100644 drivers/pci/controller/dwc/pcie-stm32.c
>> create mode 100644 drivers/pci/controller/dwc/pcie-stm32.h
>>
>> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
>> index b6d6778b0698..0c18879b604c 100644
>> --- a/drivers/pci/controller/dwc/Kconfig
>> +++ b/drivers/pci/controller/dwc/Kconfig
>> @@ -389,6 +389,18 @@ config PCIE_SPEAR13XX
>> help
>> Say Y here if you want PCIe support on SPEAr13XX SoCs.
>>
>> +config PCIE_STM32
>> + tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)"
>> + depends on ARCH_STM32 || COMPILE_TEST
>> + depends on PCI_MSI
>> + select PCIE_DW_HOST
>> + help
>> + Enables support for the DesignWare core based PCIe host controller
>> + found in STM32MP25 SoC.
>> +
>> + This driver can also be built as a module. If so, the module
>> + will be called pcie-stm32.
>> +
>> config PCI_DRA7XX
>> tristate
>>
>> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
>> index a8308d9ea986..576d99cb3bc5 100644
>> --- a/drivers/pci/controller/dwc/Makefile
>> +++ b/drivers/pci/controller/dwc/Makefile
>> @@ -28,6 +28,7 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
>> obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
>> obj-$(CONFIG_PCIE_VISCONTI_HOST) += pcie-visconti.o
>> obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
>> +obj-$(CONFIG_PCIE_STM32) += pcie-stm32.o
>>
>> # The following drivers are for devices that use the generic ACPI
>> # pci_root.c driver but don't support standard ECAM config access.
>> diff --git a/drivers/pci/controller/dwc/pcie-stm32.c b/drivers/pci/controller/dwc/pcie-stm32.c
>> new file mode 100644
>> index 000000000000..d5e473bb390f
>> --- /dev/null
>> +++ b/drivers/pci/controller/dwc/pcie-stm32.c
>> @@ -0,0 +1,372 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * STMicroelectronics STM32MP25 PCIe root complex driver.
>> + *
>> + * Copyright (C) 2024 STMicroelectronics
>
> 2025?
>
>> + * Author: Christian Bruel <christian.bruel@foss.st.com>
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/pinctrl/devinfo.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/reset.h>
>> +#include "pcie-designware.h"
>> +#include "pcie-stm32.h"
>> +#include "../../pci.h"
>> +
>> +struct stm32_pcie {
>> + struct dw_pcie pci;
>> + struct regmap *regmap;
>> + struct reset_control *rst;
>> + struct phy *phy;
>> + struct clk *clk;
>> + struct gpio_desc *perst_gpio;
>> + struct gpio_desc *wake_gpio;
>> + unsigned int wake_irq;
>> +};
>> +
>> +static void stm32_pcie_deassert_perst(struct stm32_pcie *stm32_pcie)
>> +{
>> + gpiod_set_value(stm32_pcie->perst_gpio, 0);
>> +
>> + if (stm32_pcie->perst_gpio)
>> + msleep(PCIE_T_RRS_READY_MS);
>> +}
>> +
>> +static void stm32_pcie_assert_perst(struct stm32_pcie *stm32_pcie)
>> +{
>> + gpiod_set_value(stm32_pcie->perst_gpio, 1);
>> +}
>> +
>> +static int stm32_pcie_start_link(struct dw_pcie *pci)
>> +{
>> + struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
>> +
>> + return regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
>> + STM32MP25_PCIECR_LTSSM_EN,
>> + STM32MP25_PCIECR_LTSSM_EN);
>> +}
>> +
>> +static void stm32_pcie_stop_link(struct dw_pcie *pci)
>> +{
>> + struct stm32_pcie *stm32_pcie = to_stm32_pcie(pci);
>> +
>> + regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
>> + STM32MP25_PCIECR_LTSSM_EN, 0);
>> +}
>> +
>> +static int stm32_pcie_suspend(struct device *dev)
>> +{
>> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
>> +
>> + if (device_may_wakeup(dev))
>> + enable_irq_wake(stm32_pcie->wake_irq);
>> +
>> + return 0;
>> +}
>> +
>> +static int stm32_pcie_resume(struct device *dev)
>> +{
>> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
>> +
>> + if (device_may_wakeup(dev))
>> + disable_irq_wake(stm32_pcie->wake_irq);
>> +
>> + return 0;
>> +}
>> +
>> +static int stm32_pcie_suspend_noirq(struct device *dev)
>> +{
>
> Can you consider making use of dw_pcie_{suspend/resume}_noirq()?
I considered this, but dw_pcie_suspend_noirq needs to be tweaked as it
checks both the pme_turn_off hook and whether we are entering into L2,
which we don't support.
For the former, I can check the PCI_EXP_DEVSTAT_AUXPD capability before
polling for L2 LTSSM. It looks like only the Layerscape platform uses
this. I will need a Tested-by for this new dw_pcie_suspend_noirq.
Do you advise keeping stm32_pcie_suspend_noirq or modifying
dw_pcie_suspend_noirq to this effect?
Thanks,
>
>> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
>> +
>> + stm32_pcie_stop_link(&stm32_pcie->pci);
>> +
>> + stm32_pcie_assert_perst(stm32_pcie);
>> +
>> + clk_disable_unprepare(stm32_pcie->clk);
>> +
>> + if (!device_may_wakeup(dev))
>> + phy_exit(stm32_pcie->phy);
>> +
>> + return pinctrl_pm_select_sleep_state(dev);
>> +}
>> +
>> +static int stm32_pcie_resume_noirq(struct device *dev)
>> +{
>> + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
>> + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
>> + int ret;
>> +
>> + /*
>> + * The core clock is gated with CLKREQ# from the COMBOPHY REFCLK,
>> + * thus if no device is present, must force it low with an init pinmux
>> + * to be able to access the DBI registers.
>> + */
>> + if (!IS_ERR(dev->pins->init_state))
>> + ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
>> + else
>> + ret = pinctrl_pm_select_default_state(dev);
>> +
>> + if (ret) {
>> + dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + if (!device_may_wakeup(dev)) {
>> + ret = phy_init(stm32_pcie->phy);
>> + if (ret) {
>> + pinctrl_pm_select_default_state(dev);
>> + return ret;
>> + }
>> + }
>> +
>> + ret = clk_prepare_enable(stm32_pcie->clk);
>> + if (ret)
>> + goto err_phy_exit;
>> +
>> + stm32_pcie_deassert_perst(stm32_pcie);
>> +
>> + ret = dw_pcie_setup_rc(pp);
>> + if (ret)
>> + goto err_disable_clk;
>> +
>> + ret = stm32_pcie_start_link(&stm32_pcie->pci);
>> + if (ret)
>> + goto err_disable_clk;
>> +
>> + /* Ignore errors, the link may come up later */
>> + dw_pcie_wait_for_link(&stm32_pcie->pci);
>
> These can be dropped when using dw_pcie_resume_noirq().
OK for dw_pcie_resume_noirq if we can keep it balanced with
dw_pcie_suspend_noirq
>
>> +
>> + pinctrl_pm_select_default_state(dev);
>> +
>> + return 0;
>> +
>> +err_disable_clk:
>> + stm32_pcie_assert_perst(stm32_pcie);
>> + clk_disable_unprepare(stm32_pcie->clk);
>> +
>> +err_phy_exit:
>> + phy_exit(stm32_pcie->phy);
>> + pinctrl_pm_select_default_state(dev);
>> +
>> + return ret;
>> +}
>> +
>> +static const struct dev_pm_ops stm32_pcie_pm_ops = {
>> + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend_noirq,
>> + stm32_pcie_resume_noirq)
>> + SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend, stm32_pcie_resume)
>> +};
>> +
>> +static const struct dw_pcie_host_ops stm32_pcie_host_ops = {
>> +};
>> +
>> +static const struct dw_pcie_ops dw_pcie_ops = {
>> + .start_link = stm32_pcie_start_link,
>> + .stop_link = stm32_pcie_stop_link
>> +};
>> +
>> +static int stm32_add_pcie_port(struct stm32_pcie *stm32_pcie,
>> + struct platform_device *pdev)
>> +{
>> + struct device *dev = stm32_pcie->pci.dev;
>> + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
>> + int ret;
>> +
>
> You need to assert PERST# before configuring the resources.
It is already initialized to GPIOD_OUT_HIGH in gpiod_get, I can have an
explicit stm32_pcie_assert_perst but is it necessary ?
>
>> + ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
>> + if (ret)
>> + return ret;
>> +
>> + ret = phy_init(stm32_pcie->phy);
>> + if (ret)
>> + return ret;
>> +
>> + ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
>> + STM32MP25_PCIECR_TYPE_MASK,
>> + STM32MP25_PCIECR_RC);
>> + if (ret)
>> + goto err_phy_exit;
>> +
>> + reset_control_assert(stm32_pcie->rst);
>> + reset_control_deassert(stm32_pcie->rst);
>> +
>> + ret = clk_prepare_enable(stm32_pcie->clk);
>> + if (ret) {
>> + dev_err(dev, "Core clock enable failed %d\n", ret);
>> + goto err_phy_exit;
>> + }
>> +
>> + stm32_pcie_deassert_perst(stm32_pcie);
>> +
>> + pp->ops = &stm32_pcie_host_ops;
>> + ret = dw_pcie_host_init(pp);
>> + if (ret) {
>> + dev_err(dev, "Failed to initialize host: %d\n", ret);
>> + goto err_disable_clk;
>> + }
>
> Technically, dw_pcie_host_init() is not related to root port. So please move it
> to probe() instead.
OK will move, thanks
>
>> +
>> + return 0;
>> +
>> +err_disable_clk:
>> + clk_disable_unprepare(stm32_pcie->clk);
>> + stm32_pcie_assert_perst(stm32_pcie);
>> +
>> +err_phy_exit:
>> + phy_exit(stm32_pcie->phy);
>> +
>> + return ret;
>> +}
>> +
>> +static int stm32_pcie_parse_port(struct stm32_pcie *stm32_pcie)
>> +{
>> + struct device *dev = stm32_pcie->pci.dev;
>> + struct device_node *root_port;
>> +
>> + root_port = of_get_next_available_child(dev->of_node, NULL);
>> +
>> + stm32_pcie->phy = devm_of_phy_get(dev, root_port, NULL);
>> + if (IS_ERR(stm32_pcie->phy))
>> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
>> + "Failed to get pcie-phy\n");
>
> OF refcount not decremented in both the error and success case.
I don't understand your point, isn't devm_of_phy_get managed to
decrement the phy resources ?
>
>> +
>> + stm32_pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
>> + "reset", GPIOD_OUT_HIGH, NULL);
>> + if (IS_ERR(stm32_pcie->perst_gpio)) {
>> + if (PTR_ERR(stm32_pcie->perst_gpio) != -ENOENT)
>> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
>> + "Failed to get reset GPIO\n");
>> + stm32_pcie->perst_gpio = NULL;
>> + }
>> +
>> + if (device_property_read_bool(dev, "wakeup-source")) {
>
> As per the current logic, 'wakeup-source' is applicable even without WAKE# GPIO,
> which doesn't make sense.
Agree, wakeup-source is not needed
>
>> + stm32_pcie->wake_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
>> + "wake", GPIOD_IN, NULL);
>> +
>> + if (IS_ERR(stm32_pcie->wake_gpio)) {
>> + if (PTR_ERR(stm32_pcie->wake_gpio) != -ENOENT)
>> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
>> + "Failed to get wake GPIO\n");
>> + stm32_pcie->wake_gpio = NULL;
>> + }
>
> Hmm. I think we need to move WAKE# handling inside drivers/pci/pcie/portdrv.c
> since that is responsible for the root port. While other root port properties
> have some dependency with the RC (like PERST#, PHY etc...), WAKE# handling could
> be moved safel >
> And once done, it can benefit all platforms.
OK I'll check if there is a convenient way to do this through a
port_service
>
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int stm32_pcie_probe(struct platform_device *pdev)
>> +{
>> + struct stm32_pcie *stm32_pcie;
>> + struct device *dev = &pdev->dev;
>> + int ret;
>> +
>> + stm32_pcie = devm_kzalloc(dev, sizeof(*stm32_pcie), GFP_KERNEL);
>> + if (!stm32_pcie)
>> + return -ENOMEM;
>> +
>> + stm32_pcie->pci.dev = dev;
>> + stm32_pcie->pci.ops = &dw_pcie_ops;
>> +
>> + stm32_pcie->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg");
>> + if (IS_ERR(stm32_pcie->regmap))
>> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->regmap),
>> + "No syscfg specified\n");
>> +
>> + stm32_pcie->clk = devm_clk_get(dev, NULL);
>> + if (IS_ERR(stm32_pcie->clk))
>> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->clk),
>> + "Failed to get PCIe clock source\n");
>> +
>> + stm32_pcie->rst = devm_reset_control_get_exclusive(dev, NULL);
>> + if (IS_ERR(stm32_pcie->rst))
>> + return dev_err_probe(dev, PTR_ERR(stm32_pcie->rst),
>> + "Failed to get PCIe reset\n");
>> +
>> + ret = stm32_pcie_parse_port(stm32_pcie);
>> + if (ret)
>> + return ret;
>> +
>> + platform_set_drvdata(pdev, stm32_pcie);
>> +
>> + if (stm32_pcie->wake_gpio) {
>> + stm32_pcie->wake_irq = gpiod_to_irq(stm32_pcie->wake_gpio);
>> +
>> + ret = devm_request_threaded_irq(&pdev->dev,
>> + stm32_pcie->wake_irq, NULL,
>> + dw_pcie_wake_irq_handler,
>> + IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
>> + "wake_irq", stm32_pcie->pci.dev);
>> +
>> + if (ret)
>> + return dev_err_probe(dev, ret, "Failed to request WAKE IRQ: %d\n", ret);
>> + }
>> +
>> + ret = devm_pm_runtime_enable(dev);
>> + if (ret < 0) {
>> + dev_err(dev, "Failed to enable runtime PM %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = pm_runtime_resume_and_get(dev);
>
> Why do you need to do PM resume here? Is there a parent that needs to be resumed
> now? I know that other controller drivers have this pattern, but most of them
> are just doing it wrong.
OK, so just pm_runtime_get_noresume() should be enough
>
> Most likely you need pm_runtime_set_active() before devm_pm_runtime_enable().
OK
>
>> + if (ret < 0) {
>> + dev_err(dev, "Failed to get runtime PM %d\n", ret);
>> + return ret;
>> + }
>> +
>> + ret = stm32_add_pcie_port(stm32_pcie, pdev);
>> + if (ret) {
>
> Nit: double space.
>
>> + pm_runtime_put_sync(&pdev->dev);
>> + return ret;
>> + }
>> +
>> + if (stm32_pcie->wake_gpio)
>> + device_set_wakeup_capable(dev, true);
>> +
>> + return 0;
>> +}
>> +
>> +static void stm32_pcie_remove(struct platform_device *pdev)
>> +{
>> + struct stm32_pcie *stm32_pcie = platform_get_drvdata(pdev);
>> + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
>> +
>> + if (stm32_pcie->wake_gpio)
>> + device_init_wakeup(&pdev->dev, false);
>> +
>> + dw_pcie_host_deinit(pp);
>> +
>> + stm32_pcie_assert_perst(stm32_pcie);
>> +
>> + clk_disable_unprepare(stm32_pcie->clk);
>> +
>> + phy_exit(stm32_pcie->phy);
>> +
>> + pm_runtime_put_sync(&pdev->dev);
>> +}
>> +
>> +static const struct of_device_id stm32_pcie_of_match[] = {
>> + { .compatible = "st,stm32mp25-pcie-rc" },
>> + {},
>> +};
>> +
>> +static struct platform_driver stm32_pcie_driver = {
>> + .probe = stm32_pcie_probe,
>> + .remove = stm32_pcie_remove,
>> + .driver = {
>> + .name = "stm32-pcie",
>> + .of_match_table = stm32_pcie_of_match,
>> + .pm = &stm32_pcie_pm_ops,
>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>> + },
>> +};
>> +
>> +module_platform_driver(stm32_pcie_driver);
>> +
>> +MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>");
>> +MODULE_DESCRIPTION("STM32MP25 PCIe Controller driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_DEVICE_TABLE(of, stm32_pcie_of_match);
>> diff --git a/drivers/pci/controller/dwc/pcie-stm32.h b/drivers/pci/controller/dwc/pcie-stm32.h
>> new file mode 100644
>> index 000000000000..3efd00937d3d
>> --- /dev/null
>> +++ b/drivers/pci/controller/dwc/pcie-stm32.h
>> @@ -0,0 +1,15 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * ST PCIe driver definitions for STM32-MP25 SoC
>> + *
>> + * Copyright (C) 2024 STMicroelectronics - All Rights Reserved
>> + * Author: Christian Bruel <christian.bruel@foss.st.com>
>> + */
>> +
>> +#define to_stm32_pcie(x) dev_get_drvdata((x)->dev)
>> +
>> +#define STM32MP25_PCIECR_TYPE_MASK GENMASK(11, 8)
>> +#define STM32MP25_PCIECR_LTSSM_EN BIT(2)
>> +#define STM32MP25_PCIECR_RC BIT(10)
>> +
>> +#define SYSCFG_PCIECR 0x6000
>
> You can just move these definitions inside the driver itself.
>
Some definitions will be duplicated with the ep driver, but on the other
side this file is very small... is it OK to duplicate definitions
instead of having the bitfields together ?
> - Mani
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25
2025-02-04 16:23 ` Christian Bruel
@ 2025-02-07 18:24 ` Manivannan Sadhasivam
0 siblings, 0 replies; 17+ messages in thread
From: Manivannan Sadhasivam @ 2025-02-07 18:24 UTC (permalink / raw)
To: Christian Bruel
Cc: bhelgaas, lpieralisi, kw, robh, krzk+dt, conor+dt,
mcoquelin.stm32, alexandre.torgue, jingoohan1, p.zabel,
johan+linaro, quic_schintav, cassel, linux-pci, devicetree,
linux-stm32, linux-arm-kernel, linux-kernel, fabrice.gasnier
On Tue, Feb 04, 2025 at 05:23:05PM +0100, Christian Bruel wrote:
[...]
> > > +static int stm32_pcie_suspend_noirq(struct device *dev)
> > > +{
> >
> > Can you consider making use of dw_pcie_{suspend/resume}_noirq()?
>
> I considered this, but dw_pcie_suspend_noirq needs to be tweaked as it
> checks both the pme_turn_off hook and whether we are entering into L2, which
> we don't support.
>
> For the former, I can check the PCI_EXP_DEVSTAT_AUXPD capability before
> polling for L2 LTSSM. It looks like only the Layerscape platform uses this.
> I will need a Tested-by for this new dw_pcie_suspend_noirq.
>
> Do you advise keeping stm32_pcie_suspend_noirq or modifying
> dw_pcie_suspend_noirq to this effect?
>
Please modify dw_pcie_suspend_noirq() to fit your needs. We will review the
change.
For testing the change, you can CC the Layerscape maintainer and request for
testing.
> Thanks,
>
> >
> > > + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> > > +
> > > + stm32_pcie_stop_link(&stm32_pcie->pci);
> > > +
> > > + stm32_pcie_assert_perst(stm32_pcie);
> > > +
> > > + clk_disable_unprepare(stm32_pcie->clk);
> > > +
> > > + if (!device_may_wakeup(dev))
> > > + phy_exit(stm32_pcie->phy);
> > > +
> > > + return pinctrl_pm_select_sleep_state(dev);
> > > +}
> > > +
> > > +static int stm32_pcie_resume_noirq(struct device *dev)
> > > +{
> > > + struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
> > > + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
> > > + int ret;
> > > +
> > > + /*
> > > + * The core clock is gated with CLKREQ# from the COMBOPHY REFCLK,
> > > + * thus if no device is present, must force it low with an init pinmux
> > > + * to be able to access the DBI registers.
> > > + */
> > > + if (!IS_ERR(dev->pins->init_state))
> > > + ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);
> > > + else
> > > + ret = pinctrl_pm_select_default_state(dev);
> > > +
> > > + if (ret) {
> > > + dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
> > > + return ret;
> > > + }
> > > +
> > > + if (!device_may_wakeup(dev)) {
> > > + ret = phy_init(stm32_pcie->phy);
> > > + if (ret) {
> > > + pinctrl_pm_select_default_state(dev);
> > > + return ret;
> > > + }
> > > + }
> > > +
> > > + ret = clk_prepare_enable(stm32_pcie->clk);
> > > + if (ret)
> > > + goto err_phy_exit;
> > > +
> > > + stm32_pcie_deassert_perst(stm32_pcie);
> > > +
> > > + ret = dw_pcie_setup_rc(pp);
> > > + if (ret)
> > > + goto err_disable_clk;
> > > +
> > > + ret = stm32_pcie_start_link(&stm32_pcie->pci);
> > > + if (ret)
> > > + goto err_disable_clk;
> > > +
> > > + /* Ignore errors, the link may come up later */
> > > + dw_pcie_wait_for_link(&stm32_pcie->pci);
> >
> > These can be dropped when using dw_pcie_resume_noirq().
>
> OK for dw_pcie_resume_noirq if we can keep it balanced with
> dw_pcie_suspend_noirq
>
> >
> > > +
> > > + pinctrl_pm_select_default_state(dev);
> > > +
> > > + return 0;
> > > +
> > > +err_disable_clk:
> > > + stm32_pcie_assert_perst(stm32_pcie);
> > > + clk_disable_unprepare(stm32_pcie->clk);
> > > +
> > > +err_phy_exit:
> > > + phy_exit(stm32_pcie->phy);
> > > + pinctrl_pm_select_default_state(dev);
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +static const struct dev_pm_ops stm32_pcie_pm_ops = {
> > > + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend_noirq,
> > > + stm32_pcie_resume_noirq)
> > > + SYSTEM_SLEEP_PM_OPS(stm32_pcie_suspend, stm32_pcie_resume)
> > > +};
> > > +
> > > +static const struct dw_pcie_host_ops stm32_pcie_host_ops = {
> > > +};
> > > +
> > > +static const struct dw_pcie_ops dw_pcie_ops = {
> > > + .start_link = stm32_pcie_start_link,
> > > + .stop_link = stm32_pcie_stop_link
> > > +};
> > > +
> > > +static int stm32_add_pcie_port(struct stm32_pcie *stm32_pcie,
> > > + struct platform_device *pdev)
> > > +{
> > > + struct device *dev = stm32_pcie->pci.dev;
> > > + struct dw_pcie_rp *pp = &stm32_pcie->pci.pp;
> > > + int ret;
> > > +
> >
> > You need to assert PERST# before configuring the resources.
>
> It is already initialized to GPIOD_OUT_HIGH in gpiod_get, I can have an
> explicit stm32_pcie_assert_perst but is it necessary ?
>
Ok, not necessary. Although, I would recommend to keep a comment here so that if
someone refactors the code, they would notice it.
> >
> > > + ret = phy_set_mode(stm32_pcie->phy, PHY_MODE_PCIE);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + ret = phy_init(stm32_pcie->phy);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + ret = regmap_update_bits(stm32_pcie->regmap, SYSCFG_PCIECR,
> > > + STM32MP25_PCIECR_TYPE_MASK,
> > > + STM32MP25_PCIECR_RC);
> > > + if (ret)
> > > + goto err_phy_exit;
> > > +
> > > + reset_control_assert(stm32_pcie->rst);
> > > + reset_control_deassert(stm32_pcie->rst);
> > > +
> > > + ret = clk_prepare_enable(stm32_pcie->clk);
> > > + if (ret) {
> > > + dev_err(dev, "Core clock enable failed %d\n", ret);
> > > + goto err_phy_exit;
> > > + }
> > > +
> > > + stm32_pcie_deassert_perst(stm32_pcie);
> > > +
> > > + pp->ops = &stm32_pcie_host_ops;
> > > + ret = dw_pcie_host_init(pp);
> > > + if (ret) {
> > > + dev_err(dev, "Failed to initialize host: %d\n", ret);
> > > + goto err_disable_clk;
> > > + }
> >
> > Technically, dw_pcie_host_init() is not related to root port. So please move it
> > to probe() instead.
>
> OK will move, thanks
>
> >
> > > +
> > > + return 0;
> > > +
> > > +err_disable_clk:
> > > + clk_disable_unprepare(stm32_pcie->clk);
> > > + stm32_pcie_assert_perst(stm32_pcie);
> > > +
> > > +err_phy_exit:
> > > + phy_exit(stm32_pcie->phy);
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +static int stm32_pcie_parse_port(struct stm32_pcie *stm32_pcie)
> > > +{
> > > + struct device *dev = stm32_pcie->pci.dev;
> > > + struct device_node *root_port;
> > > +
> > > + root_port = of_get_next_available_child(dev->of_node, NULL);
> > > +
> > > + stm32_pcie->phy = devm_of_phy_get(dev, root_port, NULL);
> > > + if (IS_ERR(stm32_pcie->phy))
> > > + return dev_err_probe(dev, PTR_ERR(stm32_pcie->phy),
> > > + "Failed to get pcie-phy\n");
> >
> > OF refcount not decremented in both the error and success case.
>
> I don't understand your point, isn't devm_of_phy_get managed to decrement
> the phy resources ?
>
You should drop the refcount of the root_port using of_node_put().
> >
> > > +
> > > + stm32_pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
> > > + "reset", GPIOD_OUT_HIGH, NULL);
> > > + if (IS_ERR(stm32_pcie->perst_gpio)) {
> > > + if (PTR_ERR(stm32_pcie->perst_gpio) != -ENOENT)
> > > + return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
> > > + "Failed to get reset GPIO\n");
> > > + stm32_pcie->perst_gpio = NULL;
> > > + }
> > > +
> > > + if (device_property_read_bool(dev, "wakeup-source")) {
> >
> > As per the current logic, 'wakeup-source' is applicable even without WAKE# GPIO,
> > which doesn't make sense.
>
> Agree, wakeup-source is not needed
>
> >
> > > + stm32_pcie->wake_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(root_port),
> > > + "wake", GPIOD_IN, NULL);
> > > +
> > > + if (IS_ERR(stm32_pcie->wake_gpio)) {
> > > + if (PTR_ERR(stm32_pcie->wake_gpio) != -ENOENT)
> > > + return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
> > > + "Failed to get wake GPIO\n");
> > > + stm32_pcie->wake_gpio = NULL;
> > > + }
> >
> > Hmm. I think we need to move WAKE# handling inside drivers/pci/pcie/portdrv.c
> > since that is responsible for the root port. While other root port properties
> > have some dependency with the RC (like PERST#, PHY etc...), WAKE# handling could
> > be moved safel >
> > And once done, it can benefit all platforms.
>
> OK I'll check if there is a convenient way to do this through a port_service
>
You can drop the WAKE# support altogether and add it in the subsequent patches
once this initial driver gets merged. It is up to you.
> >
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
[...]
> > You can just move these definitions inside the driver itself.
> >
>
> Some definitions will be duplicated with the ep driver, but on the other
> side this file is very small... is it OK to duplicate definitions instead of
> having the bitfields together ?
>
I didn't notice that these are reused by the ep driver. Fine with me.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-02-07 18:24 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-28 12:07 [PATCH v4 00/10] Add STM32MP25 PCIe drivers Christian Bruel
2025-01-28 12:07 ` [PATCH v4 01/10] dt-bindings: PCI: Add STM32MP25 PCIe Root Complex bindings Christian Bruel
2025-01-29 15:44 ` Rob Herring
2025-02-02 12:25 ` Manivannan Sadhasivam
2025-02-04 11:07 ` Christian Bruel
2025-01-28 12:07 ` [PATCH v4 02/10] PCI: dwc: Add dw_pcie_wake_irq_handler helper Christian Bruel
2025-01-28 12:07 ` [PATCH v4 03/10] PCI: stm32: Add PCIe host support for STM32MP25 Christian Bruel
2025-02-02 13:06 ` Manivannan Sadhasivam
2025-02-04 16:23 ` Christian Bruel
2025-02-07 18:24 ` Manivannan Sadhasivam
2025-01-28 12:07 ` [PATCH v4 04/10] dt-bindings: PCI: Add STM32MP25 PCIe Endpoint bindings Christian Bruel
2025-01-28 12:07 ` [PATCH v4 05/10] PCI: stm32: Add PCIe Endpoint support for STM32MP25 Christian Bruel
2025-01-28 12:07 ` [PATCH v4 06/10] MAINTAINERS: add entry for ST STM32MP25 PCIe drivers Christian Bruel
2025-01-28 12:07 ` [PATCH v4 07/10] arm64: dts: st: add PCIe pinctrl entries in stm32mp25-pinctrl.dtsi Christian Bruel
2025-01-28 12:07 ` [PATCH v4 08/10] arm64: dts: st: Add PCIe Rootcomplex mode on stm32mp251 Christian Bruel
2025-01-28 12:07 ` [PATCH v4 09/10] arm64: dts: st: Add PCIe Endpoint " Christian Bruel
2025-01-28 12:07 ` [PATCH v4 10/10] arm64: dts: st: Enable PCIe on the stm32mp257f-ev1 board Christian Bruel
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).