1 // SPDX-License-Identifier: GPL-2.0-only
3 * PM domains for CPUs via genpd.
5 * Copyright (C) 2019 Linaro Ltd.
6 * Author: Ulf Hansson <ulf.hansson@linaro.org>
8 * Copyright (c) 2021 Western Digital Corporation or its affiliates.
9 * Copyright (c) 2022 Ventana Micro Systems Inc.
12 #define pr_fmt(fmt) "dt-idle-genpd: " fmt
14 #include <linux/cpu.h>
15 #include <linux/device.h>
16 #include <linux/kernel.h>
17 #include <linux/pm_domain.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/slab.h>
20 #include <linux/string.h>
22 #include "dt_idle_genpd.h"
24 static int pd_parse_state_nodes(
25 int (*parse_state
)(struct device_node
*, u32
*),
26 struct genpd_power_state
*states
, int state_count
)
29 u32 state
, *state_buf
;
31 for (i
= 0; i
< state_count
; i
++) {
32 ret
= parse_state(to_of_node(states
[i
].fwnode
), &state
);
36 state_buf
= kmalloc(sizeof(u32
), GFP_KERNEL
);
42 states
[i
].data
= state_buf
;
50 kfree(states
[i
].data
);
54 static int pd_parse_states(struct device_node
*np
,
55 int (*parse_state
)(struct device_node
*, u32
*),
56 struct genpd_power_state
**states
,
61 /* Parse the domain idle states. */
62 ret
= of_genpd_parse_idle_states(np
, states
, state_count
);
66 /* Fill out the dt specifics for each found state. */
67 ret
= pd_parse_state_nodes(parse_state
, *states
, *state_count
);
74 static void pd_free_states(struct genpd_power_state
*states
,
75 unsigned int state_count
)
79 for (i
= 0; i
< state_count
; i
++)
80 kfree(states
[i
].data
);
84 void dt_idle_pd_free(struct generic_pm_domain
*pd
)
86 pd_free_states(pd
->states
, pd
->state_count
);
91 struct generic_pm_domain
*dt_idle_pd_alloc(struct device_node
*np
,
92 int (*parse_state
)(struct device_node
*, u32
*))
94 struct generic_pm_domain
*pd
;
95 struct genpd_power_state
*states
= NULL
;
96 int ret
, state_count
= 0;
98 pd
= kzalloc(sizeof(*pd
), GFP_KERNEL
);
102 pd
->name
= kasprintf(GFP_KERNEL
, "%pOF", np
);
107 * Parse the domain idle states and let genpd manage the state selection
108 * for those being compatible with "domain-idle-state".
110 ret
= pd_parse_states(np
, parse_state
, &states
, &state_count
);
114 pd
->free_states
= pd_free_states
;
115 pd
->name
= kbasename(pd
->name
);
117 pd
->state_count
= state_count
;
119 pr_debug("alloc PM domain %s\n", pd
->name
);
127 pr_err("failed to alloc PM domain %pOF\n", np
);
131 int dt_idle_pd_init_topology(struct device_node
*np
)
133 struct of_phandle_args child
, parent
;
136 for_each_child_of_node_scoped(np
, node
) {
137 if (of_parse_phandle_with_args(node
, "power-domains",
138 "#power-domain-cells", 0, &parent
))
142 child
.args_count
= 0;
143 ret
= of_genpd_add_subdomain(&parent
, &child
);
144 of_node_put(parent
.np
);
152 int dt_idle_pd_remove_topology(struct device_node
*np
)
154 struct of_phandle_args child
, parent
;
157 for_each_child_of_node_scoped(np
, node
) {
158 if (of_parse_phandle_with_args(node
, "power-domains",
159 "#power-domain-cells", 0, &parent
))
163 child
.args_count
= 0;
164 ret
= of_genpd_remove_subdomain(&parent
, &child
);
165 of_node_put(parent
.np
);
173 struct device
*dt_idle_attach_cpu(int cpu
, const char *name
)
177 dev
= dev_pm_domain_attach_by_name(get_cpu_device(cpu
), name
);
178 if (IS_ERR_OR_NULL(dev
))
181 pm_runtime_irq_safe(dev
);
183 pm_runtime_get_sync(dev
);
185 dev_pm_syscore_device(dev
, true);
190 void dt_idle_detach_cpu(struct device
*dev
)
192 if (IS_ERR_OR_NULL(dev
))
195 dev_pm_domain_detach(dev
, false);