1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * PM domains for CPUs via genpd. 4 * 5 * Copyright (C) 2019 Linaro Ltd. 6 * Author: Ulf Hansson <ulf.hansson@linaro.org> 7 * 8 * Copyright (c) 2021 Western Digital Corporation or its affiliates. 9 * Copyright (c) 2022 Ventana Micro Systems Inc. 10 */ 11 12 #define pr_fmt(fmt) "dt-idle-genpd: " fmt 13 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> 21 22 #include "dt_idle_genpd.h" 23 24 static int pd_parse_state_nodes( 25 int (*parse_state)(struct device_node *, u32 *), 26 struct genpd_power_state *states, int state_count) 27 { 28 int i, ret; 29 u32 state, *state_buf; 30 31 for (i = 0; i < state_count; i++) { 32 ret = parse_state(to_of_node(states[i].fwnode), &state); 33 if (ret) 34 goto free_state; 35 36 state_buf = kmalloc(sizeof(u32), GFP_KERNEL); 37 if (!state_buf) { 38 ret = -ENOMEM; 39 goto free_state; 40 } 41 *state_buf = state; 42 states[i].data = state_buf; 43 } 44 45 return 0; 46 47 free_state: 48 i--; 49 for (; i >= 0; i--) 50 kfree(states[i].data); 51 return ret; 52 } 53 54 static int pd_parse_states(struct device_node *np, 55 int (*parse_state)(struct device_node *, u32 *), 56 struct genpd_power_state **states, 57 int *state_count) 58 { 59 int ret; 60 61 /* Parse the domain idle states. */ 62 ret = of_genpd_parse_idle_states(np, states, state_count); 63 if (ret) 64 return ret; 65 66 /* Fill out the dt specifics for each found state. */ 67 ret = pd_parse_state_nodes(parse_state, *states, *state_count); 68 if (ret) 69 kfree(*states); 70 71 return ret; 72 } 73 74 static void pd_free_states(struct genpd_power_state *states, 75 unsigned int state_count) 76 { 77 int i; 78 79 for (i = 0; i < state_count; i++) 80 kfree(states[i].data); 81 kfree(states); 82 } 83 84 void dt_idle_pd_free(struct generic_pm_domain *pd) 85 { 86 pd_free_states(pd->states, pd->state_count); 87 kfree(pd->name); 88 kfree(pd); 89 } 90 91 struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np, 92 int (*parse_state)(struct device_node *, u32 *)) 93 { 94 struct generic_pm_domain *pd; 95 struct genpd_power_state *states = NULL; 96 int ret, state_count = 0; 97 98 pd = kzalloc_obj(*pd); 99 if (!pd) 100 goto out; 101 102 pd->name = kstrdup(kbasename(of_node_full_name(np)), GFP_KERNEL); 103 if (!pd->name) 104 goto free_pd; 105 106 /* 107 * Parse the domain idle states and let genpd manage the state selection 108 * for those being compatible with "domain-idle-state". 109 */ 110 ret = pd_parse_states(np, parse_state, &states, &state_count); 111 if (ret) 112 goto free_name; 113 114 pd->free_states = pd_free_states; 115 pd->states = states; 116 pd->state_count = state_count; 117 118 pr_debug("alloc PM domain %s\n", pd->name); 119 return pd; 120 121 free_name: 122 kfree(pd->name); 123 free_pd: 124 kfree(pd); 125 out: 126 pr_err("failed to alloc PM domain %pOF\n", np); 127 return NULL; 128 } 129 130 int dt_idle_pd_init_topology(struct device_node *np) 131 { 132 struct of_phandle_args child, parent; 133 int ret; 134 135 for_each_child_of_node_scoped(np, node) { 136 if (of_parse_phandle_with_args(node, "power-domains", 137 "#power-domain-cells", 0, &parent)) 138 continue; 139 140 child.np = node; 141 child.args_count = 0; 142 ret = of_genpd_add_subdomain(&parent, &child); 143 of_node_put(parent.np); 144 if (ret) 145 return ret; 146 } 147 148 return 0; 149 } 150 151 int dt_idle_pd_remove_topology(struct device_node *np) 152 { 153 struct of_phandle_args child, parent; 154 int ret; 155 156 for_each_child_of_node_scoped(np, node) { 157 if (of_parse_phandle_with_args(node, "power-domains", 158 "#power-domain-cells", 0, &parent)) 159 continue; 160 161 child.np = node; 162 child.args_count = 0; 163 ret = of_genpd_remove_subdomain(&parent, &child); 164 of_node_put(parent.np); 165 if (ret) 166 return ret; 167 } 168 169 return 0; 170 } 171 172 struct device *dt_idle_attach_cpu(int cpu, const char *name) 173 { 174 struct device *dev; 175 176 dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), name); 177 if (IS_ERR_OR_NULL(dev)) 178 return dev; 179 180 pm_runtime_irq_safe(dev); 181 if (cpu_online(cpu)) 182 pm_runtime_get_sync(dev); 183 184 dev_pm_syscore_device(dev, true); 185 186 return dev; 187 } 188 189 void dt_idle_detach_cpu(struct device *dev) 190 { 191 if (IS_ERR_OR_NULL(dev)) 192 return; 193 194 dev_pm_domain_detach(dev, false); 195 } 196