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 WAKE# GPIO.
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 | 360 ++++++++++++++++++++++++
drivers/pci/controller/dwc/pcie-stm32.h | 15 +
4 files changed, 388 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 deafc512b079..a8174817fd5b 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -423,6 +423,18 @@ config PCIE_SPEAR13XX
help
Say Y here if you want PCIe support on SPEAr13XX SoCs.
+config PCIE_STM32_HOST
+ tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on PCI_MSI
+ select PCIE_DW_HOST
+ help
+ Enables Root Complex (RC) support for the 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.
+
config PCI_DRA7XX
tristate
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
index 6919d27798d1..1307a87b1cf0 100644
--- a/drivers/pci/controller/dwc/Makefile
+++ b/drivers/pci/controller/dwc/Makefile
@@ -31,6 +31,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_HOST) += 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..964fa6f674c8
--- /dev/null
+++ b/drivers/pci/controller/dwc/pcie-stm32.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * STMicroelectronics STM32MP25 PCIe root complex driver.
+ *
+ * Copyright (C) 2025 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/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_wakeirq.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;
+};
+
+static void stm32_pcie_deassert_perst(struct stm32_pcie *stm32_pcie)
+{
+ if (stm32_pcie->perst_gpio) {
+ msleep(PCIE_T_PVPERL_MS);
+ gpiod_set_value(stm32_pcie->perst_gpio, 0);
+ }
+
+ msleep(PCIE_RESET_CONFIG_WAIT_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_noirq(struct device *dev)
+{
+ struct stm32_pcie *stm32_pcie = dev_get_drvdata(dev);
+ int ret;
+
+ ret = dw_pcie_suspend_noirq(&stm32_pcie->pci);
+ if (ret)
+ return ret;
+
+ stm32_pcie_assert_perst(stm32_pcie);
+
+ clk_disable_unprepare(stm32_pcie->clk);
+
+ if (!device_wakeup_path(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);
+ int ret;
+
+ /*
+ * The core clock is gated with CLKREQ# from the COMBOPHY REFCLK,
+ * thus if no device is present, must deassert it with a GPIO from
+ * pinctrl pinmux before accessing the DBI registers.
+ */
+ ret = pinctrl_pm_select_init_state(dev);
+ if (ret) {
+ dev_err(dev, "Failed to activate pinctrl pm state: %d\n", ret);
+ return ret;
+ }
+
+ if (!device_wakeup_path(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_resume_noirq(&stm32_pcie->pci);
+ if (ret)
+ goto err_disable_clk;
+
+ 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)
+};
+
+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 device *dev = stm32_pcie->pci.dev;
+ unsigned int wake_irq;
+ 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;
+
+ stm32_pcie_deassert_perst(stm32_pcie);
+
+ if (stm32_pcie->wake_gpio) {
+ wake_irq = gpiod_to_irq(stm32_pcie->wake_gpio);
+ ret = dev_pm_set_dedicated_wake_irq(dev, wake_irq);
+ if (ret) {
+ dev_err(dev, "Failed to enable wakeup irq %d\n", ret);
+ goto err_assert_perst;
+ }
+ irq_set_irq_type(wake_irq, IRQ_TYPE_EDGE_FALLING);
+ }
+
+ return 0;
+
+err_assert_perst:
+ stm32_pcie_assert_perst(stm32_pcie);
+
+err_phy_exit:
+ phy_exit(stm32_pcie->phy);
+
+ return ret;
+}
+
+static void stm32_remove_pcie_port(struct stm32_pcie *stm32_pcie)
+{
+ dev_pm_clear_wake_irq(stm32_pcie->pci.dev);
+
+ stm32_pcie_assert_perst(stm32_pcie);
+
+ phy_exit(stm32_pcie->phy);
+}
+
+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)) {
+ of_node_put(root_port);
+ 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) {
+ of_node_put(root_port);
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->perst_gpio),
+ "Failed to get reset GPIO\n");
+ }
+ stm32_pcie->perst_gpio = NULL;
+ }
+
+ 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) {
+ of_node_put(root_port);
+ return dev_err_probe(dev, PTR_ERR(stm32_pcie->wake_gpio),
+ "Failed to get wake GPIO\n");
+ }
+ stm32_pcie->wake_gpio = NULL;
+ }
+
+ of_node_put(root_port);
+
+ 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->pci.pp.ops = &stm32_pcie_host_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);
+
+ ret = stm32_add_pcie_port(stm32_pcie);
+ if (ret)
+ return ret;
+
+ 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_remove_port;
+ }
+
+ ret = pm_runtime_set_active(dev);
+ if (ret < 0) {
+ clk_disable_unprepare(stm32_pcie->clk);
+ stm32_remove_pcie_port(stm32_pcie);
+ return dev_err_probe(dev, ret, "Failed to activate runtime PM\n");
+ }
+
+ pm_runtime_no_callbacks(dev);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret < 0) {
+ clk_disable_unprepare(stm32_pcie->clk);
+ stm32_remove_pcie_port(stm32_pcie);
+ return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
+ }
+
+ ret = dw_pcie_host_init(&stm32_pcie->pci.pp);
+ if (ret)
+ goto err_disable_clk;
+
+ if (stm32_pcie->wake_gpio)
+ device_init_wakeup(dev, true);
+
+ return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(stm32_pcie->clk);
+
+err_remove_port:
+ stm32_remove_pcie_port(stm32_pcie);
+
+ return ret;
+}
+
+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);
+
+ clk_disable_unprepare(stm32_pcie->clk);
+
+ stm32_remove_pcie_port(stm32_pcie);
+
+ pm_runtime_put_noidle(&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..387112c4e42c
--- /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) 2025 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
On Mi, 2025-08-20 at 09:54 +0200, 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 WAKE# GPIO. > > 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 | 360 ++++++++++++++++++++++++ > drivers/pci/controller/dwc/pcie-stm32.h | 15 + > 4 files changed, 388 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 deafc512b079..a8174817fd5b 100644 > --- a/drivers/pci/controller/dwc/Kconfig > +++ b/drivers/pci/controller/dwc/Kconfig > @@ -423,6 +423,18 @@ config PCIE_SPEAR13XX > help > Say Y here if you want PCIe support on SPEAr13XX SoCs. > > +config PCIE_STM32_HOST > + tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)" > + depends on ARCH_STM32 || COMPILE_TEST > + depends on PCI_MSI > + select PCIE_DW_HOST > + help > + Enables Root Complex (RC) support for the 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. > + > config PCI_DRA7XX > tristate > > diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile > index 6919d27798d1..1307a87b1cf0 100644 > --- a/drivers/pci/controller/dwc/Makefile > +++ b/drivers/pci/controller/dwc/Makefile > @@ -31,6 +31,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_HOST) += 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..964fa6f674c8 > --- /dev/null > +++ b/drivers/pci/controller/dwc/pcie-stm32.c > @@ -0,0 +1,360 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * STMicroelectronics STM32MP25 PCIe root complex driver. > + * > + * Copyright (C) 2025 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/consumer.h> > +#include <linux/platform_device.h> > +#include <linux/pm_runtime.h> > +#include <linux/pm_wakeirq.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; This could be a local variable in stm32_pcie_probe(). regards Philipp
On 8/25/25 11:15, Philipp Zabel wrote: > On Mi, 2025-08-20 at 09:54 +0200, 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 WAKE# GPIO. >> >> 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 | 360 ++++++++++++++++++++++++ >> drivers/pci/controller/dwc/pcie-stm32.h | 15 + >> 4 files changed, 388 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 deafc512b079..a8174817fd5b 100644 >> --- a/drivers/pci/controller/dwc/Kconfig >> +++ b/drivers/pci/controller/dwc/Kconfig >> @@ -423,6 +423,18 @@ config PCIE_SPEAR13XX >> help >> Say Y here if you want PCIe support on SPEAr13XX SoCs. >> >> +config PCIE_STM32_HOST >> + tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)" >> + depends on ARCH_STM32 || COMPILE_TEST >> + depends on PCI_MSI >> + select PCIE_DW_HOST >> + help >> + Enables Root Complex (RC) support for the 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. >> + >> config PCI_DRA7XX >> tristate >> >> diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile >> index 6919d27798d1..1307a87b1cf0 100644 >> --- a/drivers/pci/controller/dwc/Makefile >> +++ b/drivers/pci/controller/dwc/Makefile >> @@ -31,6 +31,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_HOST) += 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..964fa6f674c8 >> --- /dev/null >> +++ b/drivers/pci/controller/dwc/pcie-stm32.c >> @@ -0,0 +1,360 @@ >> +// SPDX-License-Identifier: GPL-2.0-only >> +/* >> + * STMicroelectronics STM32MP25 PCIe root complex driver. >> + * >> + * Copyright (C) 2025 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/consumer.h> >> +#include <linux/platform_device.h> >> +#include <linux/pm_runtime.h> >> +#include <linux/pm_wakeirq.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; > > This could be a local variable in stm32_pcie_probe(). Thank you for pointing that out. Since we use the same common resources in stm32_pcie for both the host and endpoint drivers, aligning the same fields in the struct stm32_pcie seems more consistent. Additionally, we could improve the code by moving regmap, clk, and rst out of probe into a new function, stm32_pcie_resource_get(). Which approach do you think is best? Moving rst to stm32_pcie_probe() offers slight optimization, while using a new stm32_pcie_resource_get() provides better modularity. Shall I re-spin a v14 with either of these options? thank you, Christian > > regards > Philipp
On Mo, 2025-08-25 at 16:47 +0200, Christian Bruel wrote: > > On 8/25/25 11:15, Philipp Zabel wrote: > > On Mi, 2025-08-20 at 09:54 +0200, 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 WAKE# GPIO. > > > > > > 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 | 360 ++++++++++++++++++++++++ > > > drivers/pci/controller/dwc/pcie-stm32.h | 15 + > > > 4 files changed, 388 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 deafc512b079..a8174817fd5b 100644 > > > --- a/drivers/pci/controller/dwc/Kconfig > > > +++ b/drivers/pci/controller/dwc/Kconfig > > > @@ -423,6 +423,18 @@ config PCIE_SPEAR13XX > > > help > > > Say Y here if you want PCIe support on SPEAr13XX SoCs. > > > > > > +config PCIE_STM32_HOST > > > + tristate "STMicroelectronics STM32MP25 PCIe Controller (host mode)" > > > + depends on ARCH_STM32 || COMPILE_TEST > > > + depends on PCI_MSI > > > + select PCIE_DW_HOST > > > + help > > > + Enables Root Complex (RC) support for the 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. > > > + > > > config PCI_DRA7XX > > > tristate > > > > > > diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile > > > index 6919d27798d1..1307a87b1cf0 100644 > > > --- a/drivers/pci/controller/dwc/Makefile > > > +++ b/drivers/pci/controller/dwc/Makefile > > > @@ -31,6 +31,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_HOST) += 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..964fa6f674c8 > > > --- /dev/null > > > +++ b/drivers/pci/controller/dwc/pcie-stm32.c > > > @@ -0,0 +1,360 @@ > > > +// SPDX-License-Identifier: GPL-2.0-only > > > +/* > > > + * STMicroelectronics STM32MP25 PCIe root complex driver. > > > + * > > > + * Copyright (C) 2025 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/consumer.h> > > > +#include <linux/platform_device.h> > > > +#include <linux/pm_runtime.h> > > > +#include <linux/pm_wakeirq.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; > > > > This could be a local variable in stm32_pcie_probe(). > > Thank you for pointing that out. > > Since we use the same common resources in stm32_pcie for both the host > and endpoint drivers, aligning the same fields in the struct stm32_pcie > seems more consistent. I hadn't seen the host driver at that point. Aligning struct stm32_pcie with another struct in another .c file as an unwritten rule doesn't make sense to me. If parts of the structs should be kept aligned between host and endpoint drivers, it would be better to define a common base struct in a shared header. > Additionally, we could improve the code by moving regmap, clk, and rst > out of probe into a new function, stm32_pcie_resource_get(). > > Which approach do you think is best? Moving rst to stm32_pcie_probe() > offers slight optimization, This option would be my preference, but it's not a strong one. Storing a single pointer unnecessarily isn't a big deal. My mind just went "where is it used? - oh, nowhere", so I thought I'd point that out. > while using a new stm32_pcie_resource_get() > provides better modularity. I think this isn't enough code to warrant sharing stm32_pcie_resource_get() between host and endpoint drivers in the absence of other shared code. Whether splitting this out in each driver improves readability of the probe functions is a matter of taste. I think it's fine as-is. I wouldn't argue against the change either. > Shall I re-spin a v14 with either of these options? Don't respin just for this. regards Philipp
© 2016 - 2025 Red Hat, Inc.