[PATCH 2/3] pmdomain: core: add support for subdomains via power-domain-map
From: Kevin Hilman
Date: Fri Jun 13 2025 - 16:49:45 EST
---
drivers/pmdomain/core.c | 60 +++++++++++++++++++++++++++++++++++++++
include/linux/pm_domain.h | 11 +++++++
2 files changed, 71 insertions(+)
diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index 88819659df83..a0dc60d4160d 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c
@@ -3100,6 +3100,66 @@ struct device *genpd_dev_pm_attach_by_name(struct device *dev, const char *name)
return genpd_dev_pm_attach_by_id(dev, index);
}
+/**
+ * genpd_dev_pm_attach_subdomain - Associate a PM domain with its parent domain
+ * @domain: The PM domain to lookup whether it has any parent
+ * @dev: The device being attached to the PM domain.
+ *
+ * Check if @domain has a power-domain-map. If present, use that map
+ * to determine the parent PM domain, and attach @domain as a
+ * subdomain to the parent PM domain.
+ *
+ * Intended to called from a PM domain provider's ->attach_dev()
+ * callback, where &gpd_list_lock will already be held by the genpd
+ * add_device() path.
+ */
+struct generic_pm_domain *
+genpd_dev_pm_attach_subdomain(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ struct of_phandle_args parent_args;
+ struct generic_pm_domain *parent_pd = NULL;
+ int ret;
+
+ /*
+ * Check for power-domain-map, which implies the primary
+ * power-doamin is a subdomain of the parent found in the map.
+ */
+ ret = of_parse_phandle_with_args_map(dev->of_node, "power-domains",
+ "power-domain", 0, &parent_args);
+ if (!ret && parent_args.np) {
+ parent_pd = genpd_get_from_provider(&parent_args);
+ of_node_put(parent_args.np);
+
+ ret = genpd_add_subdomain(parent_pd, domain);
+ if (!ret) {
+ dev_dbg(dev, "adding PM domain %s as subdomain of %s\n",
+ domain->name, parent_pd->name);
+ return parent_pd;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_subdomain);
+
+/**
+ * genpd_dev_pm_detach_subdomain - Detatch a PM domain from its parent domain
+ * @domain: The PM subdomain to detach
+ * @parent: The parent PM domain
+ * @dev: The device being attached to the PM subdomain.
+ *
+ * Remove @domain from @parent.
+ * Intended to cleanup after genpd_dev_pm_attach_subdomain()
+ */
+int genpd_dev_pm_detach_subdomain(struct generic_pm_domain *domain,
+ struct generic_pm_domain *parent,
+ struct device *dev)
+{
+ return pm_genpd_remove_subdomain(parent, domain);
+}
+EXPORT_SYMBOL_GPL(genpd_dev_pm_detach_subdomain);
+
static const struct of_device_id idle_state_match[] = {
{ .compatible = "domain-idle-state", },
{ }
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index cf4b11be3709..5d7eb3ae59dd 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -410,6 +410,11 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
unsigned int index);
struct device *genpd_dev_pm_attach_by_name(struct device *dev,
const char *name);
+struct generic_pm_domain *genpd_dev_pm_attach_subdomain(struct generic_pm_domain *domain,
+ struct device *dev);
+int genpd_dev_pm_detach_subdomain(struct generic_pm_domain *domain,
+ struct generic_pm_domain *parent,
+ struct device *dev);
#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
static inline int of_genpd_add_provider_simple(struct device_node *np,
struct generic_pm_domain *genpd)
@@ -466,6 +471,12 @@ static inline struct device *genpd_dev_pm_attach_by_name(struct device *dev,
return NULL;
}
+static inline
+struct generic_pm_domain *genpd_dev_pm_attach_subdomain(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ return NULL;
+}
static inline
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
{
--
2.49.0