* [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; 7+ 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] 7+ 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; 7+ 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] 7+ 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; 7+ 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] 7+ 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; 7+ 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] 7+ 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 2026-04-20 22:13 ` Kevin Hilman 0 siblings, 1 reply; 7+ 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] 7+ messages in thread
* Re: [PATCH v2 2/3] pmdomain: core: add support for power-domains-child-ids 2026-04-14 14:03 ` Ulf Hansson @ 2026-04-20 22:13 ` Kevin Hilman 0 siblings, 0 replies; 7+ messages in thread From: Kevin Hilman @ 2026-04-20 22:13 UTC (permalink / raw) To: Ulf Hansson Cc: Rob Herring, Geert Uytterhoeven, linux-pm, devicetree, linux-kernel, arm-scmi, linux-arm-kernel Ulf Hansson <ulf.hansson@linaro.org> writes: > 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. OK, I like (2) better. I'll respin with that approach. Kevin ^ permalink raw reply [flat|nested] 7+ 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; 7+ 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] 7+ messages in thread
end of thread, other threads:[~2026-04-20 22:13 UTC | newest] Thread overview: 7+ 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-20 22:13 ` Kevin Hilman 2026-04-10 23:44 ` [PATCH v2 3/3] pmdomain: arm_scmi: add support for domain hierarchies Kevin Hilman (TI)
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.