From 53df57b3ae880914b5b4ea51a5e8e52c2729258a Mon Sep 17 00:00:00 2001 From: "Kevin Hilman (TI)" Date: Mon, 20 Apr 2026 16:51:17 -0700 Subject: [PATCH 01/14] dt-bindings: power: Add power-domains-child-ids property 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) Reviewed-by: Rob Herring (Arm) Signed-off-by: Ulf Hansson --- .../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>; + }; From 29e34a882b09e9f01d0fff5e312ea0cf9499137d Mon Sep 17 00:00:00 2001 From: "Kevin Hilman (TI)" Date: Mon, 20 Apr 2026 16:51:18 -0700 Subject: [PATCH 02/14] pmdomain: core: add support for power-domains-child-ids 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) Signed-off-by: Ulf Hansson --- drivers/pmdomain/core.c | 167 ++++++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 16 ++++ 2 files changed, 183 insertions(+) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 71e930e80178..f7731270015d 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -2924,6 +2924,173 @@ 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 the number of parent-child relationships established on success, + * 0 if the properties don't exist, or a negative error code on failure. + */ +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 0; + + child_count = of_property_count_u32_elems(np, "power-domains-child-ids"); + if (child_count < 0) + return 0; + 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 count; + +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 b299dc0128d6..f925614aebdb 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -467,6 +467,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, @@ -536,6 +540,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 From fba9c703c18459e936c365442667c08ca40dadcb Mon Sep 17 00:00:00 2001 From: "Kevin Hilman (TI)" Date: Mon, 20 Apr 2026 16:51:19 -0700 Subject: [PATCH 03/14] pmdomain: arm_scmi: add support for domain hierarchies 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) Signed-off-by: Ulf Hansson --- drivers/pmdomain/arm/scmi_pm_domain.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/arm/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c index 5454faed7d5d..3d73aef21d2f 100644 --- a/drivers/pmdomain/arm/scmi_pm_domain.c +++ b/drivers/pmdomain/arm/scmi_pm_domain.c @@ -113,6 +113,15 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev) goto err_rm_genpds; 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) + dev_err(dev, "Failed to add child domain hierarchy: %d\n", ret); + dev_info(dev, "Initialized %d power domains", num_domains); return 0; @@ -130,9 +139,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; From 43a4b19c17d156786adf3515434e7d522664d75d Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Tue, 14 Apr 2026 11:59:07 +0800 Subject: [PATCH 04/14] dt-bindings: power: qcom,rpmhpd: Fix whitespace in RPMHPD defines Some RPMHPD_* defines in the Generic RPMH Power Domain Indexes section were using spaces instead of tabs for alignment. Fix them to be consistent with the rest of the file. Signed-off-by: Shawn Guo Acked-by: Rob Herring (Arm) Signed-off-by: Ulf Hansson --- include/dt-bindings/power/qcom,rpmhpd.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/dt-bindings/power/qcom,rpmhpd.h b/include/dt-bindings/power/qcom,rpmhpd.h index 67e2634fdc99..74e910150956 100644 --- a/include/dt-bindings/power/qcom,rpmhpd.h +++ b/include/dt-bindings/power/qcom,rpmhpd.h @@ -7,7 +7,7 @@ #define _DT_BINDINGS_POWER_QCOM_RPMHPD_H /* Generic RPMH Power Domain Indexes */ -#define RPMHPD_CX 0 +#define RPMHPD_CX 0 #define RPMHPD_CX_AO 1 #define RPMHPD_EBI 2 #define RPMHPD_GFX 3 @@ -19,14 +19,14 @@ #define RPMHPD_MX_AO 9 #define RPMHPD_MXC 10 #define RPMHPD_MXC_AO 11 -#define RPMHPD_MSS 12 +#define RPMHPD_MSS 12 #define RPMHPD_NSP 13 -#define RPMHPD_NSP0 14 -#define RPMHPD_NSP1 15 -#define RPMHPD_QPHY 16 -#define RPMHPD_DDR 17 -#define RPMHPD_XO 18 -#define RPMHPD_NSP2 19 +#define RPMHPD_NSP0 14 +#define RPMHPD_NSP1 15 +#define RPMHPD_QPHY 16 +#define RPMHPD_DDR 17 +#define RPMHPD_XO 18 +#define RPMHPD_NSP2 19 #define RPMHPD_GMXC 20 #define RPMHPD_DCX 21 #define RPMHPD_GBX 22 From 5f0e40827295a4e46da719a399eb72cc2a5a14d6 Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Tue, 14 Apr 2026 11:59:08 +0800 Subject: [PATCH 05/14] dt-bindings: power: qcom,rpmhpd: Add RPMh power domain for Nord SoC Document the RPMh power domain for Nord SoC, and add definitions for the new power domains present on Nord SoC. - RPMHPD_NSP3: power domain for the 4th NSP subsystem - RPMHPD_GFX1: power domain for the 2nd GFX subsystem Signed-off-by: Kamal Wadhwa Signed-off-by: Shawn Guo Acked-by: Rob Herring (Arm) Reviewed-by: Konrad Dybcio Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 1 + include/dt-bindings/power/qcom,rpmhpd.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 0bf1e13a9964..779380cc7e44 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -35,6 +35,7 @@ properties: - qcom,msm8994-rpmpd - qcom,msm8996-rpmpd - qcom,msm8998-rpmpd + - qcom,nord-rpmhpd - qcom,qcm2290-rpmpd - qcom,qcs404-rpmpd - qcom,qcs615-rpmhpd diff --git a/include/dt-bindings/power/qcom,rpmhpd.h b/include/dt-bindings/power/qcom,rpmhpd.h index 74e910150956..07bd2a7b0150 100644 --- a/include/dt-bindings/power/qcom,rpmhpd.h +++ b/include/dt-bindings/power/qcom,rpmhpd.h @@ -30,6 +30,8 @@ #define RPMHPD_GMXC 20 #define RPMHPD_DCX 21 #define RPMHPD_GBX 22 +#define RPMHPD_NSP3 23 +#define RPMHPD_GFX1 24 /* RPMh Power Domain performance levels */ #define RPMH_REGULATOR_LEVEL_RETENTION 16 From bb85d843e3aaa452ba7084e9695163cbede206da Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 22 Apr 2026 10:33:42 +0200 Subject: [PATCH 06/14] pmdomain: qcom: Unify user-visible "Qualcomm" name Various names for Qualcomm as a company are used in user-visible config options: QCOM, Qualcomm and Qualcomm Technologies. Switch to unified "Qualcomm" so it will be easier for users to identify the options when for example running menuconfig. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Ulf Hansson --- drivers/pmdomain/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pmdomain/qcom/Kconfig b/drivers/pmdomain/qcom/Kconfig index 72cbcfe7a0c9..4abd43a88d08 100644 --- a/drivers/pmdomain/qcom/Kconfig +++ b/drivers/pmdomain/qcom/Kconfig @@ -2,7 +2,7 @@ menu "Qualcomm PM Domains" config QCOM_CPR - tristate "QCOM Core Power Reduction (CPR) support" + tristate "Qualcomm Core Power Reduction (CPR) support" depends on (ARCH_QCOM || COMPILE_TEST) && HAS_IOMEM select PM_OPP select REGMAP From a96e40f4afdcb52a9c97a5465c964e010734d105 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 24 Apr 2026 12:40:50 +0200 Subject: [PATCH 07/14] pmdomain: core: switch to dynamic root device Driver core expects devices to be dynamically allocated and will, for example, complain loudly if a device that lacks a release function is ever freed. Use root_device_register() to allocate and register the root device instead of open coding using a static device. Signed-off-by: Johan Hovold Signed-off-by: Ulf Hansson --- drivers/pmdomain/core.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index f7731270015d..7c96e88302d3 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -33,9 +33,7 @@ static const struct bus_type genpd_provider_bus_type = { }; /* The parent for genpd_provider devices. */ -static struct device genpd_provider_bus = { - .init_name = "genpd_provider", -}; +static struct device *genpd_provider_bus; #define GENPD_RETRY_MAX_MS 250 /* Approximate */ @@ -2325,7 +2323,7 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd) device_initialize(&genpd->dev); genpd->dev.release = genpd_provider_release; genpd->dev.bus = &genpd_provider_bus_type; - genpd->dev.parent = &genpd_provider_bus; + genpd->dev.parent = genpd_provider_bus; if (!genpd_is_dev_name_fw(genpd)) { dev_set_name(&genpd->dev, "%s", genpd->name); @@ -3742,11 +3740,9 @@ static int __init genpd_bus_init(void) { int ret; - ret = device_register(&genpd_provider_bus); - if (ret) { - put_device(&genpd_provider_bus); - return ret; - } + genpd_provider_bus = root_device_register("genpd_provider"); + if (IS_ERR(genpd_provider_bus)) + return PTR_ERR(genpd_provider_bus); ret = bus_register(&genpd_provider_bus_type); if (ret) @@ -3768,7 +3764,7 @@ static int __init genpd_bus_init(void) err_prov_bus: bus_unregister(&genpd_provider_bus_type); err_dev: - device_unregister(&genpd_provider_bus); + root_device_unregister(genpd_provider_bus); return ret; } core_initcall(genpd_bus_init); From b462a227d8547d62b1f654bf80b3505a84746b54 Mon Sep 17 00:00:00 2001 From: Yuanshen Cao Date: Sun, 10 May 2026 05:25:35 +0000 Subject: [PATCH 08/14] pmdomain: sunxi: support power domain flags for pck600 While bringing up the PowerVR GPU on the A733 (Radxa Cubie A7Z), we found that one of the GPU power domains must be configured as "always on." While the Radxa BSP device tree leaves the GPU power domain nodes commented out, the GPU driver code contains traces indicating an "always on" requirement [1]. Currently, sunxi_pck600_desc only supports specifying pd_names. This patch introduces sunxi_pck600_pd_desc, which stores both the name and its associated flags. This also (more or less) aligns the implementation with the existing sun50i PPU handling of always-on domains. With this change, individual power domains can now be configured more granularly. In particular, the GPU_CORE domain in sun60i_a733_pck600_pds can now be explicitly marked with GENPD_FLAG_ALWAYS_ON. The patch was tested on the Radxa Cubie A7Z, where the GPU now functions as expected. Thanks to Icenowy for her support and expertise on sunxi and PowerVR, and thanks to Mikhail for identifying this exact cause of the GPU bring-up issue. [1] https://github.com/radxa/allwinner-bsp/blob/cubie-aiot-v1.4.6/modules/gpu/img-bxm/linux/rogue_km/services/system/rogue/rgx_sunxi/sunxi_platform.c#L62 Signed-off-by: Yuanshen Cao Signed-off-by: Ulf Hansson --- drivers/pmdomain/sunxi/sun55i-pck600.c | 31 +++++++++++++++++--------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/pmdomain/sunxi/sun55i-pck600.c b/drivers/pmdomain/sunxi/sun55i-pck600.c index 1d47bbd35ced..8a37d11b65a2 100644 --- a/drivers/pmdomain/sunxi/sun55i-pck600.c +++ b/drivers/pmdomain/sunxi/sun55i-pck600.c @@ -41,8 +41,13 @@ #define PPU_REG_SIZE 0x1000 +struct sunxi_pck600_pd_desc { + const char *name; + unsigned int flags; +}; + struct sunxi_pck600_desc { - const char * const *pd_names; + const struct sunxi_pck600_pd_desc *pd_descs; unsigned int num_domains; u32 logic_power_switch0_delay_offset; u32 logic_power_switch1_delay_offset; @@ -164,10 +169,12 @@ static int sunxi_pck600_probe(struct platform_device *pdev) for (i = 0; i < desc->num_domains; i++) { struct sunxi_pck600_pd *pd = &pck->pds[i]; + const struct sunxi_pck600_pd_desc *pd_desc = &desc->pd_descs[i]; - pd->genpd.name = desc->pd_names[i]; + pd->genpd.name = pd_desc->name; pd->genpd.power_off = sunxi_pck600_power_off; pd->genpd.power_on = sunxi_pck600_power_on; + pd->genpd.flags = pd_desc->flags; pd->base = base + PPU_REG_SIZE * i; sunxi_pck600_pd_setup(pd, desc); @@ -195,13 +202,14 @@ static int sunxi_pck600_probe(struct platform_device *pdev) return ret; } -static const char * const sun55i_a523_pck600_pd_names[] = { - "VE", "GPU", "VI", "VO0", "VO1", "DE", "NAND", "PCIE" +static const struct sunxi_pck600_pd_desc sun55i_a523_pck600_pds[] = { + { "VE", }, { "GPU", }, { "VI", }, { "VO0", }, { "VO1", }, + { "DE", }, { "NAND", }, { "PCIE", }, }; static const struct sunxi_pck600_desc sun55i_a523_pck600_desc = { - .pd_names = sun55i_a523_pck600_pd_names, - .num_domains = ARRAY_SIZE(sun55i_a523_pck600_pd_names), + .pd_descs = sun55i_a523_pck600_pds, + .num_domains = ARRAY_SIZE(sun55i_a523_pck600_pds), .logic_power_switch0_delay_offset = 0xc00, .logic_power_switch1_delay_offset = 0xc04, .off2on_delay_offset = 0xc10, @@ -213,14 +221,15 @@ static const struct sunxi_pck600_desc sun55i_a523_pck600_desc = { .has_rst_clk = true, }; -static const char * const sun60i_a733_pck600_pd_names[] = { - "VI", "DE_SYS", "VE_DEC", "VE_ENC", "NPU", - "GPU_TOP", "GPU_CORE", "PCIE", "USB2", "VO", "VO1" +static const struct sunxi_pck600_pd_desc sun60i_a733_pck600_pds[] = { + { "VI", }, { "DE_SYS", }, { "VE_DEC", }, { "VE_ENC", }, { "NPU", }, + { "GPU_TOP", }, { "GPU_CORE", GENPD_FLAG_ALWAYS_ON }, + { "PCIE", }, { "USB2", }, { "VO", }, { "VO1", }, }; static const struct sunxi_pck600_desc sun60i_a733_pck600_desc = { - .pd_names = sun60i_a733_pck600_pd_names, - .num_domains = ARRAY_SIZE(sun60i_a733_pck600_pd_names), + .pd_descs = sun60i_a733_pck600_pds, + .num_domains = ARRAY_SIZE(sun60i_a733_pck600_pds), .logic_power_switch0_delay_offset = 0xc00, .logic_power_switch1_delay_offset = 0xc04, .off2on_delay_offset = 0xc10, From d8985743dcf86245cd4583a7855e248955d42c2b Mon Sep 17 00:00:00 2001 From: Rakesh Kota Date: Fri, 22 May 2026 13:51:54 +0530 Subject: [PATCH 09/14] dt-bindings: power: qcom,rpmpd: document the Shikra RPM Power Domains Document the RPM Power Domains on the Shikra Platform. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rakesh Kota Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/power/qcom,rpmpd.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 779380cc7e44..0744a867c79e 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -56,6 +56,7 @@ properties: - qcom,sdx55-rpmhpd - qcom,sdx65-rpmhpd - qcom,sdx75-rpmhpd + - qcom,shikra-rpmpd - qcom,sm4450-rpmhpd - qcom,sm6115-rpmpd - qcom,sm6125-rpmpd From eaefa3d6095b88227bf374e3a36fe2e9fab4cbbc Mon Sep 17 00:00:00 2001 From: Kamal Wadhwa Date: Tue, 14 Apr 2026 11:59:09 +0800 Subject: [PATCH 10/14] pmdomain: qcom: rpmhpd: Add power domains for Nord SoC Add RPMh power domains required for Nord SoC. This includes new definitions for power domains supplying GFX1 and NSP3 subsystem. Co-developed-by: Bartosz Golaszewski Signed-off-by: Bartosz Golaszewski Signed-off-by: Kamal Wadhwa Signed-off-by: Shawn Guo Reviewed-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Signed-off-by: Ulf Hansson --- drivers/pmdomain/qcom/rpmhpd.c | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c index ba0cf4694435..63120e703923 100644 --- a/drivers/pmdomain/qcom/rpmhpd.c +++ b/drivers/pmdomain/qcom/rpmhpd.c @@ -122,6 +122,11 @@ static struct rpmhpd gfx = { .res_name = "gfx.lvl", }; +static struct rpmhpd gfx1 = { + .pd = { .name = "gfx1", }, + .res_name = "gfx1.lvl", +}; + static struct rpmhpd lcx = { .pd = { .name = "lcx", }, .res_name = "lcx.lvl", @@ -217,6 +222,11 @@ static struct rpmhpd nsp2 = { .res_name = "nsp2.lvl", }; +static struct rpmhpd nsp3 = { + .pd = { .name = "nsp3", }, + .res_name = "nsp3.lvl", +}; + static struct rpmhpd qphy = { .pd = { .name = "qphy", }, .res_name = "qphy.lvl", @@ -308,6 +318,30 @@ static const struct rpmhpd_desc sa8775p_desc = { .num_pds = ARRAY_SIZE(sa8775p_rpmhpds), }; +/* Nord RPMH powerdomains */ +static struct rpmhpd *nord_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_GFX1] = &gfx1, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MMCX] = &mmcx, + [RPMHPD_MMCX_AO] = &mmcx_ao, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, + [RPMHPD_NSP0] = &nsp0, + [RPMHPD_NSP1] = &nsp1, + [RPMHPD_NSP2] = &nsp2, + [RPMHPD_NSP3] = &nsp3, +}; + +static const struct rpmhpd_desc nord_desc = { + .rpmhpds = nord_rpmhpds, + .num_pds = ARRAY_SIZE(nord_rpmhpds), +}; + /* SAR2130P RPMH powerdomains */ static struct rpmhpd *sar2130p_rpmhpds[] = { [RPMHPD_CX] = &cx, @@ -856,6 +890,7 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,hawi-rpmhpd", .data = &hawi_desc }, { .compatible = "qcom,kaanapali-rpmhpd", .data = &kaanapali_desc }, { .compatible = "qcom,milos-rpmhpd", .data = &milos_desc }, + { .compatible = "qcom,nord-rpmhpd", .data = &nord_desc }, { .compatible = "qcom,qcs615-rpmhpd", .data = &qcs615_desc }, { .compatible = "qcom,qcs8300-rpmhpd", .data = &qcs8300_desc }, { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc }, From b3677645c72686a7e707aff233de5aa4888cb8fd Mon Sep 17 00:00:00 2001 From: Rakesh Kota Date: Fri, 22 May 2026 13:51:55 +0530 Subject: [PATCH 11/14] pmdomain: qcom: rpmpd: Add Shikra RPM Power Domains Add RPM power domain support for Shikra, reusing SM6125 power domains with RPM_SMD_LEVEL_TURBO_NO_CPR as the max state. Reviewed-by: Konrad Dybcio Signed-off-by: Rakesh Kota Reviewed-by: Dmitry Baryshkov Signed-off-by: Ulf Hansson --- drivers/pmdomain/qcom/rpmpd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pmdomain/qcom/rpmpd.c b/drivers/pmdomain/qcom/rpmpd.c index 15a11ff282c3..5f55fc791131 100644 --- a/drivers/pmdomain/qcom/rpmpd.c +++ b/drivers/pmdomain/qcom/rpmpd.c @@ -895,6 +895,12 @@ static const struct rpmpd_desc sm6125_desc = { .max_state = RPM_SMD_LEVEL_BINNING, }; +static const struct rpmpd_desc shikra_desc = { + .rpmpds = sm6125_rpmpds, + .num_pds = ARRAY_SIZE(sm6125_rpmpds), + .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, +}; + static struct rpmpd *sm6375_rpmpds[] = { [SM6375_VDDCX] = &cx_rwcx0_lvl, [SM6375_VDDCX_AO] = &cx_rwcx0_lvl_ao, @@ -949,6 +955,7 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, { .compatible = "qcom,qm215-rpmpd", .data = &qm215_desc }, { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc }, + { .compatible = "qcom,shikra-rpmpd", .data = &shikra_desc }, { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc }, { .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc }, { .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc }, From e46d95f060a2d465413638c5861ee0c205ba12b5 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Thu, 28 May 2026 13:24:55 -0700 Subject: [PATCH 12/14] pmdomain: mediatek: mfg: move __packed after struct name to fix kernel-doc The kernel-doc parser cannot parse 'struct __packed mtk_mfg_opp_entry {'. Move __packed to the closing brace, which is the more common kernel style. Assisted-by: Opencode:Big-pickle Signed-off-by: Rosen Penev Signed-off-by: Ulf Hansson --- drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c index 3ce6fb74dd53..53bdab66cf15 100644 --- a/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c +++ b/drivers/pmdomain/mediatek/mtk-mfg-pmdomain.c @@ -236,14 +236,14 @@ struct __packed mtk_mfg_ipi_sleep_msg { * * This struct is part of the ABI with the EB firmware. Do not change it. */ -struct __packed mtk_mfg_opp_entry { +struct mtk_mfg_opp_entry { __le32 freq_khz; __le32 voltage_core; __le32 voltage_sram; __le32 posdiv; __le32 voltage_margin; __le32 power_mw; -}; +} __packed; struct mtk_mfg_mbox { struct mbox_client cl; From 92b69eff8012f1c8d79f2153857208f36277e0e5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 9 Jun 2026 18:06:34 +0200 Subject: [PATCH 13/14] pmdomain: core: fix early domain registration A recent change switching to a dynamically allocated root device broke platforms like rcar-sysc that registers PM domains before the PM domain bus itself has been registered (cf. commit c5ae5a0c6112 ("pmdomain: renesas: rcar-sysc: Add genpd OF provider at postcore_initcall")). Defer the assignment of the parent root device until the domain is registered with driver core to avoid it being left unset. Fixes: a96e40f4afdc ("pmdomain: core: switch to dynamic root device") Reported-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/CAMuHMdUHabMGJyJ7e7yp7DLC+JJc9k6NK9p4anj2wRKNuwZUng@mail.gmail.com Signed-off-by: Johan Hovold Tested-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson --- drivers/pmdomain/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 7c96e88302d3..7796042e3f37 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -2323,7 +2323,6 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd) device_initialize(&genpd->dev); genpd->dev.release = genpd_provider_release; genpd->dev.bus = &genpd_provider_bus_type; - genpd->dev.parent = genpd_provider_bus; if (!genpd_is_dev_name_fw(genpd)) { dev_set_name(&genpd->dev, "%s", genpd->name); @@ -2688,6 +2687,7 @@ int of_genpd_add_provider_simple(struct device_node *np, if (!genpd_present(genpd)) return -EINVAL; + genpd->dev.parent = genpd_provider_bus; genpd->dev.of_node = np; fwnode = of_fwnode_handle(np); @@ -2782,6 +2782,7 @@ int of_genpd_add_provider_onecell(struct device_node *np, if (!genpd_present(genpd)) goto error; + genpd->dev.parent = genpd_provider_bus; genpd->dev.of_node = np; if (sync_state && !genpd_is_no_sync_state(genpd)) { From 528ad521a433cf873724893bda339df95d8ac1e0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 11 Jun 2026 14:03:45 +0200 Subject: [PATCH 14/14] pmdomain: core: fix unused variable warning with !PM_GENERIC_DOMAINS_OF The genpd provider bus is really only used when CONFIG_PM_GENERIC_DOMAINS_OF is enabled, and since the recent deferred initialisation of domain parent devices, the root device pointer is otherwise unused. Fix the unused variable warning by moving the definition of the root device pointer inside the corresponding ifdef. Fixes: 92b69eff8012 ("pmdomain: core: fix early domain registration") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202606111746.kAxaAbwg-lkp@intel.com/ Signed-off-by: Johan Hovold Signed-off-by: Ulf Hansson --- drivers/pmdomain/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c index 7796042e3f37..842c4169e290 100644 --- a/drivers/pmdomain/core.c +++ b/drivers/pmdomain/core.c @@ -32,9 +32,6 @@ static const struct bus_type genpd_provider_bus_type = { .name = "genpd_provider", }; -/* The parent for genpd_provider devices. */ -static struct device *genpd_provider_bus; - #define GENPD_RETRY_MAX_MS 250 /* Approximate */ #define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ @@ -2566,6 +2563,10 @@ struct of_genpd_provider { static LIST_HEAD(of_genpd_providers); /* Mutex to protect the list above. */ static DEFINE_MUTEX(of_genpd_mutex); + +/* The parent for genpd_provider devices. */ +static struct device *genpd_provider_bus; + /* Used to prevent registering devices before the bus. */ static bool genpd_bus_registered;