[Linux-stm32] [PATCH 2/7] pmdomain: st: add STM32MP power domain

Patrick Delaunay patrick.delaunay at foss.st.com
Wed Nov 4 14:55:05 CET 2026


Add a generic PM domain for the STM32MP D1 domain, using the PM
framework to manage attached devices.

Make D1 a subdomain of the PSCI cluster domain, so active devices keep
the Cortex-A35 cluster in Run1. Do not set GENPD_FLAG_ACTIVE_WAKEUP on
D1: system wakeups are handled by EXTI1 through the RET_PD PSCI domain.

Signed-off-by: Patrick Delaunay <patrick.delaunay at foss.st.com>
---

 drivers/pmdomain/st/Kconfig             |  14 +++
 drivers/pmdomain/st/Makefile            |   1 +
 drivers/pmdomain/st/stm32mp-pm-domain.c | 128 ++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100644 drivers/pmdomain/st/stm32mp-pm-domain.c

diff --git a/drivers/pmdomain/st/Kconfig b/drivers/pmdomain/st/Kconfig
index a77a70211f61..da8a54d44158 100644
--- a/drivers/pmdomain/st/Kconfig
+++ b/drivers/pmdomain/st/Kconfig
@@ -1,4 +1,18 @@
 # SPDX-License-Identifier: GPL-2.0-only
+
+config STM32MP_PM_DOMAIN
+	tristate "STM32MP PM domain"
+	depends on ARCH_STM32 || COMPILE_TEST
+	select PM_GENERIC_DOMAINS
+	default y
+	help
+	  Enable support for the STM32MP Power Management (PM) domain driver.
+	  This driver implements a generic PM domain for STM32MP SoCs, allowing
+	  the kernel to manage power domains for various hardware blocks using
+	  the generic power management framework. It is typically used to
+	  control the power state of devices and peripherals on STM32MP
+	  platforms. If unsure, say Y.
+
 config UX500_PM_DOMAIN
 	bool "ST-Ericsson ux500 Power Domain"
 	depends on ARCH_U8500 || COMPILE_TEST
diff --git a/drivers/pmdomain/st/Makefile b/drivers/pmdomain/st/Makefile
index 6d8b617eb834..0e8131b7fe9d 100644
--- a/drivers/pmdomain/st/Makefile
+++ b/drivers/pmdomain/st/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_STM32MP_PM_DOMAIN)		+= stm32mp-pm-domain.o
 obj-$(CONFIG_UX500_PM_DOMAIN)		+= ste-ux500-pm-domain.o
diff --git a/drivers/pmdomain/st/stm32mp-pm-domain.c b/drivers/pmdomain/st/stm32mp-pm-domain.c
new file mode 100644
index 000000000000..1a6393840f56
--- /dev/null
+++ b/drivers/pmdomain/st/stm32mp-pm-domain.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Implements PM domain using the generic PM domain for STM32MP SoC.
+ *
+ * Copyright (C) STMicroelectronics 2026
+ * Author(s): Patrick Delaunay <patrick.delaunay at foss.st.com>
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+struct stm32mp_pm_subdomain_link {
+	struct generic_pm_domain *domain;
+	struct generic_pm_domain *subdomain;
+};
+
+static void stm32mp_pm_domain_genpd_remove(void *data)
+{
+	struct generic_pm_domain *genpd = data;
+
+	pm_genpd_remove(genpd);
+}
+
+static void stm32mp_pm_domain_release_subdomain(void *data)
+{
+	struct stm32mp_pm_subdomain_link *link = data;
+
+	pm_genpd_remove_subdomain(link->domain, link->subdomain);
+}
+
+static void stm32mp_pm_domain_release_genpd_provider(void *data)
+{
+	struct device_node *np = data;
+
+	of_genpd_del_provider(np);
+}
+
+static int stm32mp_pm_domain_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct generic_pm_domain *pd;
+	struct stm32mp_pm_subdomain_link *link;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	/* The OF node must specify us as a power-domain provider. */
+	if (!of_property_present(np, "#power-domain-cells")) {
+		dev_warn(dev, "%pOF lacks #power-domain-cells\n", np);
+		return 0;
+	}
+
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd)
+		return -ENOMEM;
+
+	pd->name = dev_name(dev);
+
+	/*
+	 * Domain based only on PM clk framework, no GENPD_FLAG_ACTIVE_WAKEUP
+	 * support, the wake-up path is handled by interrupt driver with its
+	 * power domain. GENPD_FLAG_NO_STAY_ON as domain no required sync state,
+	 * domain allow low power modes even if devices are not probed
+	 */
+	pd->flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_NO_STAY_ON;
+
+	ret = pm_genpd_init(pd, NULL, false);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to init power domain\n");
+
+	ret = devm_add_action_or_reset(dev, stm32mp_pm_domain_genpd_remove, pd);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add action\n");
+
+	link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL);
+	if (!link)
+		return -ENOMEM;
+	link->domain = pd_to_genpd(dev->pm_domain);
+	link->subdomain = pd;
+
+	ret = pm_genpd_add_subdomain(link->domain, link->subdomain);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add subdomain\n");
+
+	ret = devm_add_action_or_reset(dev, stm32mp_pm_domain_release_subdomain, link);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add action\n");
+
+	ret = of_genpd_add_provider_simple(np, pd);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add power domain provider\n");
+
+	ret = devm_add_action_or_reset(dev, stm32mp_pm_domain_release_genpd_provider, np);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to add action\n");
+
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable pm-runtime\n");
+
+	return 0;
+}
+
+static const struct of_device_id stm32mp_pm_domain_matches[] = {
+	{ .compatible = "st,stm32mp-pm-domain", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, stm32mp_pm_domain_matches);
+
+static struct platform_driver stm32mp_pm_domain_driver = {
+	.driver = {
+		.name = "stm32mp_pm_domain",
+		.of_match_table = stm32mp_pm_domain_matches,
+	},
+	.probe  = stm32mp_pm_domain_probe,
+};
+
+module_platform_driver(stm32mp_pm_domain_driver);
+
+MODULE_AUTHOR("Patrick Delaunay <patrick.delaunay at foss.st.com>");
+MODULE_DESCRIPTION("ST STM32MP power domain driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0



More information about the Linux-stm32 mailing list