* [PATCH v2 0/3] pmdomain: core: add support for domain hierarchies in DT
@ 2026-04-10 23:44 Kevin Hilman (TI)
2026-04-10 23:44 ` [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property Kevin Hilman (TI)
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Kevin Hilman (TI) @ 2026-04-10 23:44 UTC (permalink / raw)
To: Ulf Hansson, Rob Herring
Cc: Geert Uytterhoeven, linux-pm, devicetree, linux-kernel, arm-scmi,
linux-arm-kernel
Currently, PM domains can only support hierarchy for simple
providers (e.g. ones with #power-domain-cells = 0).
Add support for oncell providers as well by adding a new property
`power-domains-child-ids` to describe the parent/child relationship.
Also adds the first user of the new API: the Arm SCMI PM domain driver.
Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com>
---
This idea was previously discussed on the arm-scmi mailing list[1]
where this approach was proposed by Ulf, and then an initial RFC[2]
implementation was made. From there, it was suggested by Rob[3] to
use a nexus node map instead, which led to several more versions
attempting to implement that, culminating in v5[4], where Rob and
Geert then had second thoughts about the power-domain-map approach.
Therefore, I've gone back to the approach in the initial RFC[2] to use
the child-ids approach.
Changes compared to initial RFC[2]
- dropped RFC
- rewrote the parse/add function to use iterators/helpers from of.h
- add a remove function for cleanup
- use child domain language instead of subdomain
[1] https://lore.kernel.org/arm-scmi/CAPDyKFo_P129sVirHHYjOQT+QUmpymcRJme9obzKJeRgO7B-1A@mail.gmail.com/
[2] https://lore.kernel.org/all/20250528-pmdomain-hierarchy-onecell-v1-1-851780700c68@baylibre.com/
[3] https://lore.kernel.org/all/20250528203532.GA704342-robh@kernel.org/
[4] https://lore.kernel.org/r/20260122-pmdomain-hierarchy-onecell-v5-0-76855ec856bd@baylibre.com
Changes in v2:
- dt-bindings: fix warinings from make dt_binding_check
- scmi_pm_domain: switch to dev_err()
- pmdomain: core: fix locking around add/remove domains
- pmdomain: error unwind if any children fail to be added
- pmdomain: fix node reference leak
- pmdomain: ensure power-domains and child-ids properties are same
length before iterating
- Link to v1: https://patch.msgid.link/20260310-topic-lpm-pmdomain-child-ids-v1-0-5361687a18ff@baylibre.com
---
Kevin Hilman (TI) (3):
dt-bindings: power: Add power-domains-child-ids property
pmdomain: core: add support for power-domains-child-ids
pmdomain: arm_scmi: add support for domain hierarchies
Documentation/devicetree/bindings/power/power-domain.yaml | 34 ++++++++++++++++++++++++++++++++++
drivers/pmdomain/arm/scmi_pm_domain.c | 14 +++++++++++++-
drivers/pmdomain/core.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pm_domain.h | 16 ++++++++++++++++
4 files changed, 229 insertions(+), 1 deletion(-)
---
base-commit: f7b88edb52c8dd01b7e576390d658ae6eef0e134
change-id: 20260310-topic-lpm-pmdomain-child-ids-e3d57ae57040
Best regards,
--
Kevin Hilman (TI) <khilman@baylibre.com>
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property 2026-04-10 23:44 [PATCH v2 0/3] pmdomain: core: add support for domain hierarchies in DT Kevin Hilman (TI) @ 2026-04-10 23:44 ` Kevin Hilman (TI) 2026-04-16 12:03 ` Rob Herring (Arm) 2026-04-10 23:44 ` [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids Kevin Hilman (TI) 2026-04-10 23:44 ` [PATCH v2 3/3] pmdomain: arm_scmi: add support for domain hierarchies Kevin Hilman (TI) 2 siblings, 1 reply; 6+ messages in thread From: Kevin Hilman (TI) @ 2026-04-10 23:44 UTC (permalink / raw) To: Ulf Hansson, Rob Herring Cc: Geert Uytterhoeven, linux-pm, devicetree, linux-kernel, arm-scmi, linux-arm-kernel Add binding documentation for the new power-domains-child-ids property, which works in conjunction with the existing power-domains property to establish parent-child relationships between a multi-domain power domain provider and external parent domains. Each element in the uint32 array identifies the child domain ID (index) within the provider that should be made a child domain of the corresponding phandle entry in power-domains. The two arrays must have the same number of elements. Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com> --- Documentation/devicetree/bindings/power/power-domain.yaml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Documentation/devicetree/bindings/power/power-domain.yaml b/Documentation/devicetree/bindings/power/power-domain.yaml index b1147dbf2e73..163b0af158fd 100644 --- a/Documentation/devicetree/bindings/power/power-domain.yaml +++ b/Documentation/devicetree/bindings/power/power-domain.yaml @@ -68,6 +68,21 @@ properties: by the given provider should be subdomains of the domain specified by this binding. + power-domains-child-ids: + $ref: /schemas/types.yaml#/definitions/uint32-array + description: + An array of child domain IDs that correspond to the power-domains + property. This property is only applicable to power domain providers + with "#power-domain-cells" > 0 (i.e., providers that supply multiple + power domains). It specifies which of the provider's child domains + should be associated with each parent domain listed in the power-domains + property. The number of elements in this array must match the number of + phandles in the power-domains property. Each element specifies the child + domain ID (index) that should be made a child domain of the corresponding + parent domain. This enables hierarchical power domain structures where + different child domains from the same provider can have different + parent domains. + required: - "#power-domain-cells" @@ -133,3 +148,22 @@ examples: min-residency-us = <7000>; }; }; + + - | + // Example: SCMI domain 15 -> MAIN_PD, SCMI domain 19 -> WKUP_PD + MAIN_PD: power-controller-main { + compatible = "foo,power-controller"; + #power-domain-cells = <0>; + }; + + WKUP_PD: power-controller-wkup { + compatible = "foo,power-controller"; + #power-domain-cells = <0>; + }; + + scmi_pds: power-controller-scmi { + compatible = "foo,power-controller"; + #power-domain-cells = <1>; + power-domains = <&MAIN_PD>, <&WKUP_PD>; + power-domains-child-ids = <15>, <19>; + }; -- 2.51.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property 2026-04-10 23:44 ` [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property Kevin Hilman (TI) @ 2026-04-16 12:03 ` Rob Herring (Arm) 0 siblings, 0 replies; 6+ messages in thread From: Rob Herring (Arm) @ 2026-04-16 12:03 UTC (permalink / raw) To: Kevin Hilman (TI) Cc: devicetree, Ulf Hansson, linux-arm-kernel, linux-pm, linux-kernel, arm-scmi, Geert Uytterhoeven On Fri, 10 Apr 2026 16:44:36 -0700, Kevin Hilman (TI) wrote: > Add binding documentation for the new power-domains-child-ids property, > which works in conjunction with the existing power-domains property to > establish parent-child relationships between a multi-domain power domain > provider and external parent domains. > > Each element in the uint32 array identifies the child domain > ID (index) within the provider that should be made a child domain of > the corresponding phandle entry in power-domains. The two arrays must > have the same number of elements. > > Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com> > --- > Documentation/devicetree/bindings/power/power-domain.yaml | 34 ++++++++++++++++++++++++++++++++++ > 1 file changed, 34 insertions(+) > Reviewed-by: Rob Herring (Arm) <robh@kernel.org> ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids 2026-04-10 23:44 [PATCH v2 0/3] pmdomain: core: add support for domain hierarchies in DT Kevin Hilman (TI) 2026-04-10 23:44 ` [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property Kevin Hilman (TI) @ 2026-04-10 23:44 ` Kevin Hilman (TI) 2026-04-14 14:03 ` Ulf Hansson 2026-04-10 23:44 ` [PATCH v2 3/3] pmdomain: arm_scmi: add support for domain hierarchies Kevin Hilman (TI) 2 siblings, 1 reply; 6+ messages in thread From: Kevin Hilman (TI) @ 2026-04-10 23:44 UTC (permalink / raw) To: Ulf Hansson, Rob Herring Cc: Geert Uytterhoeven, linux-pm, devicetree, linux-kernel, arm-scmi, linux-arm-kernel Currently, PM domains can only support hierarchy for simple providers (e.g. ones with #power-domain-cells = 0). Add support for oncell providers as well by adding a new property `power-domains-child-ids` to describe the parent/child relationship. For example, an SCMI PM domain provider has multiple domains, each of which might be a child of diffeent parent domains. In this example, the parent domains are MAIN_PD and WKUP_PD: scmi_pds: protocol@11 { reg = <0x11>; #power-domain-cells = <1>; power-domains = <&MAIN_PD>, <&WKUP_PD>; power-domains-child-ids = <15>, <19>; }; With this example using the new property, SCMI PM domain 15 becomes a child domain of MAIN_PD, and SCMI domain 19 becomes a child domain of WKUP_PD. To support this feature, add two new core functions - of_genpd_add_child_ids() - of_genpd_remove_child_ids() which can be called by pmdomain providers to add/remove child domains if they support the new property power-domains-child-ids. The add function is "all or nothing". If it cannot add all of the child domains in the list, it will unwind any additions already made and report a failure. Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com> --- drivers/pmdomain/core.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 16 ++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 61c2277c9ce3..f978477dd546 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -2909,6 +2909,172 @@ static struct generic_pm_domain *genpd_get_from_provider( return genpd; } +/** + * of_genpd_add_child_ids() - Parse power-domains-child-ids property + * @np: Device node pointer associated with the PM domain provider. + * @data: Pointer to the onecell data associated with the PM domain provider. + * + * Parse the power-domains and power-domains-child-ids properties to establish + * parent-child relationships for PM domains. The power-domains property lists + * parent domains, and power-domains-child-ids lists which child domain IDs + * should be associated with each parent. + * + * Uses "all or nothing" semantics: either all relationships are established + * successfully, or none are (any partially-added relationships are unwound + * on error). + * + * Returns 0 on success, -ENOENT if properties don't exist, or negative error code. + */ +int of_genpd_add_child_ids(struct device_node *np, + struct genpd_onecell_data *data) +{ + struct of_phandle_args parent_args; + struct generic_pm_domain *parent_genpd, *child_genpd; + struct generic_pm_domain **pairs; /* pairs[2*i]=parent, pairs[2*i+1]=child */ + u32 child_id; + int i, ret, count, child_count, added = 0; + + /* Check if both properties exist */ + count = of_count_phandle_with_args(np, "power-domains", "#power-domain-cells"); + if (count <= 0) + return -ENOENT; + + child_count = of_property_count_u32_elems(np, "power-domains-child-ids"); + if (child_count < 0) + return -ENOENT; + if (child_count != count) + return -EINVAL; + + /* Allocate tracking array for error unwind (parent/child pairs) */ + pairs = kmalloc_array(count * 2, sizeof(*pairs), GFP_KERNEL); + if (!pairs) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = of_property_read_u32_index(np, "power-domains-child-ids", + i, &child_id); + if (ret) + goto err_unwind; + + /* Validate child ID is within bounds */ + if (child_id >= data->num_domains) { + pr_err("Child ID %u out of bounds (max %u) for %pOF\n", + child_id, data->num_domains - 1, np); + ret = -EINVAL; + goto err_unwind; + } + + /* Get the child domain */ + child_genpd = data->domains[child_id]; + if (!child_genpd) { + pr_err("Child domain %u is NULL for %pOF\n", child_id, np); + ret = -EINVAL; + goto err_unwind; + } + + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", i, + &parent_args); + if (ret) + goto err_unwind; + + /* Get the parent domain */ + parent_genpd = genpd_get_from_provider(&parent_args); + of_node_put(parent_args.np); + if (IS_ERR(parent_genpd)) { + pr_err("Failed to get parent domain for %pOF: %ld\n", + np, PTR_ERR(parent_genpd)); + ret = PTR_ERR(parent_genpd); + goto err_unwind; + } + + /* Establish parent-child relationship */ + ret = pm_genpd_add_subdomain(parent_genpd, child_genpd); + if (ret) { + pr_err("Failed to add child domain %u to parent in %pOF: %d\n", + child_id, np, ret); + goto err_unwind; + } + + /* Track for potential unwind */ + pairs[2 * added] = parent_genpd; + pairs[2 * added + 1] = child_genpd; + added++; + + pr_debug("Added child domain %u (%s) to parent %s for %pOF\n", + child_id, child_genpd->name, parent_genpd->name, np); + } + + kfree(pairs); + return 0; + +err_unwind: + /* Reverse all previously established relationships */ + while (added-- > 0) + pm_genpd_remove_subdomain(pairs[2 * added], pairs[2 * added + 1]); + kfree(pairs); + return ret; +} +EXPORT_SYMBOL_GPL(of_genpd_add_child_ids); + +/** + * of_genpd_remove_child_ids() - Remove parent-child PM domain relationships + * @np: Device node pointer associated with the PM domain provider. + * @data: Pointer to the onecell data associated with the PM domain provider. + * + * Reverses the effect of of_genpd_add_child_ids() by parsing the same + * power-domains and power-domains-child-ids properties and calling + * pm_genpd_remove_subdomain() for each established relationship. + * + * Returns 0 on success, -ENOENT if properties don't exist, or negative error + * code on failure. + */ +int of_genpd_remove_child_ids(struct device_node *np, + struct genpd_onecell_data *data) +{ + struct of_phandle_args parent_args; + struct generic_pm_domain *parent_genpd, *child_genpd; + u32 child_id; + int i, ret, count, child_count; + + /* Check if both properties exist */ + count = of_count_phandle_with_args(np, "power-domains", "#power-domain-cells"); + if (count <= 0) + return -ENOENT; + + child_count = of_property_count_u32_elems(np, "power-domains-child-ids"); + if (child_count < 0) + return -ENOENT; + if (child_count != count) + return -EINVAL; + + for (i = 0; i < count; i++) { + if (of_property_read_u32_index(np, "power-domains-child-ids", + i, &child_id)) + continue; + + if (child_id >= data->num_domains || !data->domains[child_id]) + continue; + + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", i, + &parent_args); + if (ret) + continue; + + parent_genpd = genpd_get_from_provider(&parent_args); + of_node_put(parent_args.np); + if (IS_ERR(parent_genpd)) + continue; + + child_genpd = data->domains[child_id]; + pm_genpd_remove_subdomain(parent_genpd, child_genpd); + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_genpd_remove_child_ids); + /** * of_genpd_add_device() - Add a device to an I/O PM domain * @genpdspec: OF phandle args to use for look-up PM domain diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index f67a2cb7d781..b44615d79af6 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -465,6 +465,10 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n); void of_genpd_sync_state(struct device_node *np); +int of_genpd_add_child_ids(struct device_node *np, + struct genpd_onecell_data *data); +int of_genpd_remove_child_ids(struct device_node *np, + struct genpd_onecell_data *data); int genpd_dev_pm_attach(struct device *dev); struct device *genpd_dev_pm_attach_by_id(struct device *dev, @@ -534,6 +538,18 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) { return ERR_PTR(-EOPNOTSUPP); } + +static inline int of_genpd_add_child_ids(struct device_node *np, + struct genpd_onecell_data *data) +{ + return -EOPNOTSUPP; +} + +static inline int of_genpd_remove_child_ids(struct device_node *np, + struct genpd_onecell_data *data) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ #ifdef CONFIG_PM -- 2.51.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids 2026-04-10 23:44 ` [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids Kevin Hilman (TI) @ 2026-04-14 14:03 ` Ulf Hansson 0 siblings, 0 replies; 6+ messages in thread From: Ulf Hansson @ 2026-04-14 14:03 UTC (permalink / raw) To: Kevin Hilman (TI) Cc: Rob Herring, Geert Uytterhoeven, linux-pm, devicetree, linux-kernel, arm-scmi, linux-arm-kernel On Sat, 11 Apr 2026 at 01:44, Kevin Hilman (TI) <khilman@baylibre.com> wrote: > > Currently, PM domains can only support hierarchy for simple > providers (e.g. ones with #power-domain-cells = 0). > > Add support for oncell providers as well by adding a new property > `power-domains-child-ids` to describe the parent/child relationship. > > For example, an SCMI PM domain provider has multiple domains, each of > which might be a child of diffeent parent domains. In this example, > the parent domains are MAIN_PD and WKUP_PD: > > scmi_pds: protocol@11 { > reg = <0x11>; > #power-domain-cells = <1>; > power-domains = <&MAIN_PD>, <&WKUP_PD>; > power-domains-child-ids = <15>, <19>; > }; > > With this example using the new property, SCMI PM domain 15 becomes a > child domain of MAIN_PD, and SCMI domain 19 becomes a child domain of > WKUP_PD. > > To support this feature, add two new core functions > > - of_genpd_add_child_ids() > - of_genpd_remove_child_ids() > > which can be called by pmdomain providers to add/remove child domains > if they support the new property power-domains-child-ids. > > The add function is "all or nothing". If it cannot add all of the > child domains in the list, it will unwind any additions already made > and report a failure. > > Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com> > --- > drivers/pmdomain/core.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/pm_domain.h | 16 ++++++++++++++++ > 2 files changed, 182 insertions(+) > > diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c > index 61c2277c9ce3..f978477dd546 100644 > --- a/drivers/pmdomain/core.c > +++ b/drivers/pmdomain/core.c > @@ -2909,6 +2909,172 @@ static struct generic_pm_domain *genpd_get_from_provider( > return genpd; > } > > +/** > + * of_genpd_add_child_ids() - Parse power-domains-child-ids property > + * @np: Device node pointer associated with the PM domain provider. > + * @data: Pointer to the onecell data associated with the PM domain provider. > + * > + * Parse the power-domains and power-domains-child-ids properties to establish > + * parent-child relationships for PM domains. The power-domains property lists > + * parent domains, and power-domains-child-ids lists which child domain IDs > + * should be associated with each parent. > + * > + * Uses "all or nothing" semantics: either all relationships are established > + * successfully, or none are (any partially-added relationships are unwound > + * on error). > + * > + * Returns 0 on success, -ENOENT if properties don't exist, or negative error code. > + */ As I mentioned in my earlier reply for the previous version, returning a specific error code when the property doesn't exist will complicate handling for the caller. Moreover, we also need to make sure we don't returning the same error code (-ENOENT) for a different error further down the execution path in of_genpd_add_child_ids(). Otherwise it would the caller treat the error code in the wrong way. To me, there are two better ways to address this. For both options, of_genpd_add_child_ids() should return 0 when "power-domains-child-ids" is missing. 1) Add another helper function that checks if "power-domains-child-ids" exists. The caller can then use this to pre-parse the property and decide whether to treat it as an error. 2) As I suggested earlier, let of_genpd_add_child_ids() return the number of assigned parents/children, while still using the all or nothing approach, of course. Kind regards Uffe > +int of_genpd_add_child_ids(struct device_node *np, > + struct genpd_onecell_data *data) > +{ > + struct of_phandle_args parent_args; > + struct generic_pm_domain *parent_genpd, *child_genpd; > + struct generic_pm_domain **pairs; /* pairs[2*i]=parent, pairs[2*i+1]=child */ > + u32 child_id; > + int i, ret, count, child_count, added = 0; > + > + /* Check if both properties exist */ > + count = of_count_phandle_with_args(np, "power-domains", "#power-domain-cells"); > + if (count <= 0) > + return -ENOENT; > + > + child_count = of_property_count_u32_elems(np, "power-domains-child-ids"); > + if (child_count < 0) > + return -ENOENT; > + if (child_count != count) > + return -EINVAL; > + > + /* Allocate tracking array for error unwind (parent/child pairs) */ > + pairs = kmalloc_array(count * 2, sizeof(*pairs), GFP_KERNEL); > + if (!pairs) > + return -ENOMEM; > + > + for (i = 0; i < count; i++) { > + ret = of_property_read_u32_index(np, "power-domains-child-ids", > + i, &child_id); > + if (ret) > + goto err_unwind; > + > + /* Validate child ID is within bounds */ > + if (child_id >= data->num_domains) { > + pr_err("Child ID %u out of bounds (max %u) for %pOF\n", > + child_id, data->num_domains - 1, np); > + ret = -EINVAL; > + goto err_unwind; > + } > + > + /* Get the child domain */ > + child_genpd = data->domains[child_id]; > + if (!child_genpd) { > + pr_err("Child domain %u is NULL for %pOF\n", child_id, np); > + ret = -EINVAL; > + goto err_unwind; > + } > + > + ret = of_parse_phandle_with_args(np, "power-domains", > + "#power-domain-cells", i, > + &parent_args); > + if (ret) > + goto err_unwind; > + > + /* Get the parent domain */ > + parent_genpd = genpd_get_from_provider(&parent_args); > + of_node_put(parent_args.np); > + if (IS_ERR(parent_genpd)) { > + pr_err("Failed to get parent domain for %pOF: %ld\n", > + np, PTR_ERR(parent_genpd)); > + ret = PTR_ERR(parent_genpd); > + goto err_unwind; > + } > + > + /* Establish parent-child relationship */ > + ret = pm_genpd_add_subdomain(parent_genpd, child_genpd); > + if (ret) { > + pr_err("Failed to add child domain %u to parent in %pOF: %d\n", > + child_id, np, ret); > + goto err_unwind; > + } > + > + /* Track for potential unwind */ > + pairs[2 * added] = parent_genpd; > + pairs[2 * added + 1] = child_genpd; > + added++; > + > + pr_debug("Added child domain %u (%s) to parent %s for %pOF\n", > + child_id, child_genpd->name, parent_genpd->name, np); > + } > + > + kfree(pairs); > + return 0; > + > +err_unwind: > + /* Reverse all previously established relationships */ > + while (added-- > 0) > + pm_genpd_remove_subdomain(pairs[2 * added], pairs[2 * added + 1]); > + kfree(pairs); > + return ret; > +} > +EXPORT_SYMBOL_GPL(of_genpd_add_child_ids); > + > +/** > + * of_genpd_remove_child_ids() - Remove parent-child PM domain relationships > + * @np: Device node pointer associated with the PM domain provider. > + * @data: Pointer to the onecell data associated with the PM domain provider. > + * > + * Reverses the effect of of_genpd_add_child_ids() by parsing the same > + * power-domains and power-domains-child-ids properties and calling > + * pm_genpd_remove_subdomain() for each established relationship. > + * > + * Returns 0 on success, -ENOENT if properties don't exist, or negative error > + * code on failure. > + */ > +int of_genpd_remove_child_ids(struct device_node *np, > + struct genpd_onecell_data *data) > +{ > + struct of_phandle_args parent_args; > + struct generic_pm_domain *parent_genpd, *child_genpd; > + u32 child_id; > + int i, ret, count, child_count; > + > + /* Check if both properties exist */ > + count = of_count_phandle_with_args(np, "power-domains", "#power-domain-cells"); > + if (count <= 0) > + return -ENOENT; > + > + child_count = of_property_count_u32_elems(np, "power-domains-child-ids"); > + if (child_count < 0) > + return -ENOENT; > + if (child_count != count) > + return -EINVAL; > + > + for (i = 0; i < count; i++) { > + if (of_property_read_u32_index(np, "power-domains-child-ids", > + i, &child_id)) > + continue; > + > + if (child_id >= data->num_domains || !data->domains[child_id]) > + continue; > + > + ret = of_parse_phandle_with_args(np, "power-domains", > + "#power-domain-cells", i, > + &parent_args); > + if (ret) > + continue; > + > + parent_genpd = genpd_get_from_provider(&parent_args); > + of_node_put(parent_args.np); > + if (IS_ERR(parent_genpd)) > + continue; > + > + child_genpd = data->domains[child_id]; > + pm_genpd_remove_subdomain(parent_genpd, child_genpd); > + } > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(of_genpd_remove_child_ids); > + > /** > * of_genpd_add_device() - Add a device to an I/O PM domain > * @genpdspec: OF phandle args to use for look-up PM domain > diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h > index f67a2cb7d781..b44615d79af6 100644 > --- a/include/linux/pm_domain.h > +++ b/include/linux/pm_domain.h > @@ -465,6 +465,10 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); > int of_genpd_parse_idle_states(struct device_node *dn, > struct genpd_power_state **states, int *n); > void of_genpd_sync_state(struct device_node *np); > +int of_genpd_add_child_ids(struct device_node *np, > + struct genpd_onecell_data *data); > +int of_genpd_remove_child_ids(struct device_node *np, > + struct genpd_onecell_data *data); > > int genpd_dev_pm_attach(struct device *dev); > struct device *genpd_dev_pm_attach_by_id(struct device *dev, > @@ -534,6 +538,18 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) > { > return ERR_PTR(-EOPNOTSUPP); > } > + > +static inline int of_genpd_add_child_ids(struct device_node *np, > + struct genpd_onecell_data *data) > +{ > + return -EOPNOTSUPP; > +} > + > +static inline int of_genpd_remove_child_ids(struct device_node *np, > + struct genpd_onecell_data *data) > +{ > + return -EOPNOTSUPP; > +} > #endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ > > #ifdef CONFIG_PM > > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 3/3] pmdomain: arm_scmi: add support for domain hierarchies 2026-04-10 23:44 [PATCH v2 0/3] pmdomain: core: add support for domain hierarchies in DT Kevin Hilman (TI) 2026-04-10 23:44 ` [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property Kevin Hilman (TI) 2026-04-10 23:44 ` [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids Kevin Hilman (TI) @ 2026-04-10 23:44 ` Kevin Hilman (TI) 2 siblings, 0 replies; 6+ messages in thread From: Kevin Hilman (TI) @ 2026-04-10 23:44 UTC (permalink / raw) To: Ulf Hansson, Rob Herring Cc: Geert Uytterhoeven, linux-pm, devicetree, linux-kernel, arm-scmi, linux-arm-kernel After primary SCMI pmdomain is created, use new of_genpd helper which checks for child domain mappings defined in power-domains-child-ids. Also remove any child domain mappings when SCMI domain is removed. Signed-off-by: Kevin Hilman (TI) <khilman@baylibre.com> --- drivers/pmdomain/arm/scmi_pm_domain.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/arm/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c index b5e2ffd5ea64..6d33b3d62ef3 100644 --- a/drivers/pmdomain/arm/scmi_pm_domain.c +++ b/drivers/pmdomain/arm/scmi_pm_domain.c @@ -114,6 +114,14 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) dev_set_drvdata(dev, scmi_pd_data); + /* + * Parse (optional) power-domains-child-ids property to + * establish parent-child relationships + */ + ret = of_genpd_add_child_ids(np, scmi_pd_data); + if (ret < 0 && ret != -ENOENT) + dev_err(dev, "Failed to add child domain hierarchy: %d\n", ret); + return 0; err_rm_genpds: for (i = num_domains - 1; i >= 0; i--) @@ -129,9 +137,13 @@ static void scmi_pm_domain_remove(struct scmi_device *sdev) struct device *dev = &sdev->dev; struct device_node *np = dev->of_node; + scmi_pd_data = dev_get_drvdata(dev); + + /* Remove any parent-child relationships established at probe time */ + of_genpd_remove_child_ids(np, scmi_pd_data); + of_genpd_del_provider(np); - scmi_pd_data = dev_get_drvdata(dev); for (i = 0; i < scmi_pd_data->num_domains; i++) { if (!scmi_pd_data->domains[i]) continue; -- 2.51.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-16 12:04 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-10 23:44 [PATCH v2 0/3] pmdomain: core: add support for domain hierarchies in DT Kevin Hilman (TI) 2026-04-10 23:44 ` [PATCH v2 1/3] dt-bindings: power: Add power-domains-child-ids property Kevin Hilman (TI) 2026-04-16 12:03 ` Rob Herring (Arm) 2026-04-10 23:44 ` [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids Kevin Hilman (TI) 2026-04-14 14:03 ` Ulf Hansson 2026-04-10 23:44 ` [PATCH v2 3/3] pmdomain: arm_scmi: add support for domain hierarchies Kevin Hilman (TI)
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox