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(sizeof(*pd), GFP_KERNEL); 99 if (!pd) 100 goto out; 101 102 pd->name = kasprintf(GFP_KERNEL, "%pOF", np); 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->name = kbasename(pd->name); 116 pd->states = states; 117 pd->state_count = state_count; 118 119 pr_debug("alloc PM domain %s\n", pd->name); 120 return pd; 121 122 free_name: 123 kfree(pd->name); 124 free_pd: 125 kfree(pd); 126 out: 127 pr_err("failed to alloc PM domain %pOF\n", np); 128 return NULL; 129 } 130 131 int dt_idle_pd_init_topology(struct device_node *np) 132 { 133 struct of_phandle_args child, parent; 134 int ret; 135 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)) 139 continue; 140 141 child.np = node; 142 child.args_count = 0; 143 ret = of_genpd_add_subdomain(&parent, &child); 144 of_node_put(parent.np); 145 if (ret) 146 return ret; 147 } 148 149 return 0; 150 } 151 152 int dt_idle_pd_remove_topology(struct device_node *np) 153 { 154 struct of_phandle_args child, parent; 155 int ret; 156 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)) 160 continue; 161 162 child.np = node; 163 child.args_count = 0; 164 ret = of_genpd_remove_subdomain(&parent, &child); 165 of_node_put(parent.np); 166 if (ret) 167 return ret; 168 } 169 170 return 0; 171 } 172 173 struct device *dt_idle_attach_cpu(int cpu, const char *name) 174 { 175 struct device *dev; 176 177 dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), name); 178 if (IS_ERR_OR_NULL(dev)) 179 return dev; 180 181 pm_runtime_irq_safe(dev); 182 if (cpu_online(cpu)) 183 pm_runtime_get_sync(dev); 184 185 dev_pm_syscore_device(dev, true); 186 187 return dev; 188 } 189 190 void dt_idle_detach_cpu(struct device *dev) 191 { 192 if (IS_ERR_OR_NULL(dev)) 193 return; 194 195 dev_pm_domain_detach(dev, false); 196 } 197