1 // SPDX-License-Identifier: GPL-2.0
3 * PM domains for CPUs via genpd - managed by cpuidle-psci.
5 * Copyright (C) 2019 Linaro Ltd.
6 * Author: Ulf Hansson <ulf.hansson@linaro.org>
10 #define pr_fmt(fmt) "CPUidle PSCI: " fmt
12 #include <linux/cpu.h>
13 #include <linux/device.h>
14 #include <linux/kernel.h>
15 #include <linux/pm_domain.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/psci.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
21 #include "cpuidle-psci.h"
23 struct psci_pd_provider
{
24 struct list_head link
;
25 struct device_node
*node
;
28 static LIST_HEAD(psci_pd_providers
);
29 static bool osi_mode_enabled __initdata
;
31 static int psci_pd_power_off(struct generic_pm_domain
*pd
)
33 struct genpd_power_state
*state
= &pd
->states
[pd
->state_idx
];
39 /* OSI mode is enabled, set the corresponding domain state. */
40 pd_state
= state
->data
;
41 psci_set_domain_state(*pd_state
);
46 static int __init
psci_pd_parse_state_nodes(struct genpd_power_state
*states
,
50 u32 psci_state
, *psci_state_buf
;
52 for (i
= 0; i
< state_count
; i
++) {
53 ret
= psci_dt_parse_state_node(to_of_node(states
[i
].fwnode
),
58 psci_state_buf
= kmalloc(sizeof(u32
), GFP_KERNEL
);
59 if (!psci_state_buf
) {
63 *psci_state_buf
= psci_state
;
64 states
[i
].data
= psci_state_buf
;
72 kfree(states
[i
].data
);
76 static int __init
psci_pd_parse_states(struct device_node
*np
,
77 struct genpd_power_state
**states
, int *state_count
)
81 /* Parse the domain idle states. */
82 ret
= of_genpd_parse_idle_states(np
, states
, state_count
);
86 /* Fill out the PSCI specifics for each found state. */
87 ret
= psci_pd_parse_state_nodes(*states
, *state_count
);
94 static void psci_pd_free_states(struct genpd_power_state
*states
,
95 unsigned int state_count
)
99 for (i
= 0; i
< state_count
; i
++)
100 kfree(states
[i
].data
);
104 static int __init
psci_pd_init(struct device_node
*np
)
106 struct generic_pm_domain
*pd
;
107 struct psci_pd_provider
*pd_provider
;
108 struct dev_power_governor
*pd_gov
;
109 struct genpd_power_state
*states
= NULL
;
110 int ret
= -ENOMEM
, state_count
= 0;
112 pd
= kzalloc(sizeof(*pd
), GFP_KERNEL
);
116 pd_provider
= kzalloc(sizeof(*pd_provider
), GFP_KERNEL
);
120 pd
->name
= kasprintf(GFP_KERNEL
, "%pOF", np
);
125 * Parse the domain idle states and let genpd manage the state selection
126 * for those being compatible with "domain-idle-state".
128 ret
= psci_pd_parse_states(np
, &states
, &state_count
);
132 pd
->free_states
= psci_pd_free_states
;
133 pd
->name
= kbasename(pd
->name
);
134 pd
->power_off
= psci_pd_power_off
;
136 pd
->state_count
= state_count
;
137 pd
->flags
|= GENPD_FLAG_IRQ_SAFE
| GENPD_FLAG_CPU_DOMAIN
;
139 /* Use governor for CPU PM domains if it has some states to manage. */
140 pd_gov
= state_count
> 0 ? &pm_domain_cpu_gov
: NULL
;
142 ret
= pm_genpd_init(pd
, pd_gov
, false);
144 psci_pd_free_states(states
, state_count
);
148 ret
= of_genpd_add_provider_simple(np
, pd
);
152 pd_provider
->node
= of_node_get(np
);
153 list_add(&pd_provider
->link
, &psci_pd_providers
);
155 pr_debug("init PM domain %s\n", pd
->name
);
167 pr_err("failed to init PM domain ret=%d %pOF\n", ret
, np
);
171 static void __init
psci_pd_remove(void)
173 struct psci_pd_provider
*pd_provider
, *it
;
174 struct generic_pm_domain
*genpd
;
176 list_for_each_entry_safe(pd_provider
, it
, &psci_pd_providers
, link
) {
177 of_genpd_del_provider(pd_provider
->node
);
179 genpd
= of_genpd_remove_last(pd_provider
->node
);
183 of_node_put(pd_provider
->node
);
184 list_del(&pd_provider
->link
);
189 static int __init
psci_pd_init_topology(struct device_node
*np
, bool add
)
191 struct device_node
*node
;
192 struct of_phandle_args child
, parent
;
195 for_each_child_of_node(np
, node
) {
196 if (of_parse_phandle_with_args(node
, "power-domains",
197 "#power-domain-cells", 0, &parent
))
201 child
.args_count
= 0;
203 ret
= add
? of_genpd_add_subdomain(&parent
, &child
) :
204 of_genpd_remove_subdomain(&parent
, &child
);
205 of_node_put(parent
.np
);
215 static int __init
psci_pd_add_topology(struct device_node
*np
)
217 return psci_pd_init_topology(np
, true);
220 static void __init
psci_pd_remove_topology(struct device_node
*np
)
222 psci_pd_init_topology(np
, false);
225 static const struct of_device_id psci_of_match
[] __initconst
= {
226 { .compatible
= "arm,psci-1.0" },
230 static int __init
psci_idle_init_domains(void)
232 struct device_node
*np
= of_find_matching_node(NULL
, psci_of_match
);
233 struct device_node
*node
;
234 int ret
= 0, pd_count
= 0;
239 /* Currently limit the hierarchical topology to be used in OSI mode. */
240 if (!psci_has_osi_support())
244 * Parse child nodes for the "#power-domain-cells" property and
245 * initialize a genpd/genpd-of-provider pair when it's found.
247 for_each_child_of_node(np
, node
) {
248 if (!of_find_property(node
, "#power-domain-cells", NULL
))
251 ret
= psci_pd_init(node
);
258 /* Bail out if not using the hierarchical CPU topology. */
262 /* Link genpd masters/subdomains to model the CPU topology. */
263 ret
= psci_pd_add_topology(np
);
267 /* Try to enable OSI mode. */
268 ret
= psci_set_osi_mode();
270 pr_warn("failed to enable OSI mode: %d\n", ret
);
271 psci_pd_remove_topology(np
);
275 osi_mode_enabled
= true;
277 pr_info("Initialized CPU PM domain topology\n");
285 pr_err("failed to create CPU PM domains ret=%d\n", ret
);
290 subsys_initcall(psci_idle_init_domains
);
292 struct device __init
*psci_dt_attach_cpu(int cpu
)
296 if (!osi_mode_enabled
)
299 dev
= dev_pm_domain_attach_by_name(get_cpu_device(cpu
), "psci");
300 if (IS_ERR_OR_NULL(dev
))
303 pm_runtime_irq_safe(dev
);
305 pm_runtime_get_sync(dev
);