[PATCH 2/7] pmdomain: st: add STM32MP power domain
Ulf Hansson
ulf.hansson at oss.qualcomm.com
Sat Nov 14 02:40:52 PST 2026
On Wed, Nov 4, 2026 at 3:02 PM Patrick Delaunay
<patrick.delaunay at foss.st.com> wrote:
>
> 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.
Would you mind elaborating on the system wakeups a bit more?
The devices that get attached to the D1 PM domain do they have another
PM domain as well, to support the system wakeups?
Just trying to make sure this gets modeled correctly.
One comment in the code below.
>
> 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);
What is this used for?
> + 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
>
Kind regards
Uffe
More information about the linux-arm-kernel
mailing list