1 // SPDX-License-Identifier: GPL-2.0
3 * PM domains for CPUs via genpd - managed by cpuidle-psci.
5 * Copyright (C) 2019 Linaro Ltd.
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);