dt_idle_genpd.c (3706B)
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 24static 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 47free_state: 48 i--; 49 for (; i >= 0; i--) 50 kfree(states[i].data); 51 return ret; 52} 53 54static 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 74static 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 84void 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 91struct 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 122free_name: 123 kfree(pd->name); 124free_pd: 125 kfree(pd); 126out: 127 pr_err("failed to alloc PM domain %pOF\n", np); 128 return NULL; 129} 130 131int dt_idle_pd_init_topology(struct device_node *np) 132{ 133 struct device_node *node; 134 struct of_phandle_args child, parent; 135 int ret; 136 137 for_each_child_of_node(np, node) { 138 if (of_parse_phandle_with_args(node, "power-domains", 139 "#power-domain-cells", 0, &parent)) 140 continue; 141 142 child.np = node; 143 child.args_count = 0; 144 ret = of_genpd_add_subdomain(&parent, &child); 145 of_node_put(parent.np); 146 if (ret) { 147 of_node_put(node); 148 return ret; 149 } 150 } 151 152 return 0; 153} 154 155struct device *dt_idle_attach_cpu(int cpu, const char *name) 156{ 157 struct device *dev; 158 159 dev = dev_pm_domain_attach_by_name(get_cpu_device(cpu), name); 160 if (IS_ERR_OR_NULL(dev)) 161 return dev; 162 163 pm_runtime_irq_safe(dev); 164 if (cpu_online(cpu)) 165 pm_runtime_get_sync(dev); 166 167 dev_pm_syscore_device(dev, true); 168 169 return dev; 170} 171 172void dt_idle_detach_cpu(struct device *dev) 173{ 174 if (IS_ERR_OR_NULL(dev)) 175 return; 176 177 dev_pm_domain_detach(dev, false); 178}