1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved 4 */ 5 6#include <linux/of.h> 7#include <linux/platform_device.h> 8#include <linux/pm_domain.h> 9#include <linux/slab.h> 10#include <linux/version.h> 11 12#include <soc/tegra/bpmp.h> 13#include <soc/tegra/bpmp-abi.h> 14 15struct tegra_powergate_info { 16 unsigned int id; 17 char *name; 18}; 19 20struct tegra_powergate { 21 struct generic_pm_domain genpd; 22 struct tegra_bpmp *bpmp; 23 unsigned int id; 24}; 25 26static inline struct tegra_powergate * 27to_tegra_powergate(struct generic_pm_domain *genpd) 28{ 29 return container_of(genpd, struct tegra_powergate, genpd); 30} 31 32static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp, 33 unsigned int id, u32 state) 34{ 35 struct mrq_pg_request request; 36 struct tegra_bpmp_message msg; 37 int err; 38 39 memset(&request, 0, sizeof(request)); 40 request.cmd = CMD_PG_SET_STATE; 41 request.id = id; 42 request.set_state.state = state; 43 44 memset(&msg, 0, sizeof(msg)); 45 msg.mrq = MRQ_PG; 46 msg.tx.data = &request; 47 msg.tx.size = sizeof(request); 48 49 err = tegra_bpmp_transfer(bpmp, &msg); 50 if (err < 0) 51 return err; 52 else if (msg.rx.ret < 0) 53 return -EINVAL; 54 55 return 0; 56} 57 58static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp, 59 unsigned int id) 60{ 61 struct mrq_pg_response response; 62 struct mrq_pg_request request; 63 struct tegra_bpmp_message msg; 64 int err; 65 66 memset(&request, 0, sizeof(request)); 67 request.cmd = CMD_PG_GET_STATE; 68 request.id = id; 69 70 memset(&response, 0, sizeof(response)); 71 72 memset(&msg, 0, sizeof(msg)); 73 msg.mrq = MRQ_PG; 74 msg.tx.data = &request; 75 msg.tx.size = sizeof(request); 76 msg.rx.data = &response; 77 msg.rx.size = sizeof(response); 78 79 err = tegra_bpmp_transfer(bpmp, &msg); 80 if (err < 0) 81 return PG_STATE_OFF; 82 else if (msg.rx.ret < 0) 83 return -EINVAL; 84 85 return response.get_state.state; 86} 87 88static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp) 89{ 90 struct mrq_pg_response response; 91 struct mrq_pg_request request; 92 struct tegra_bpmp_message msg; 93 int err; 94 95 memset(&request, 0, sizeof(request)); 96 request.cmd = CMD_PG_GET_MAX_ID; 97 98 memset(&response, 0, sizeof(response)); 99 100 memset(&msg, 0, sizeof(msg)); 101 msg.mrq = MRQ_PG; 102 msg.tx.data = &request; 103 msg.tx.size = sizeof(request); 104 msg.rx.data = &response; 105 msg.rx.size = sizeof(response); 106 107 err = tegra_bpmp_transfer(bpmp, &msg); 108 if (err < 0) 109 return err; 110 else if (msg.rx.ret < 0) 111 return -EINVAL; 112 113 return response.get_max_id.max_id; 114} 115 116static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp, 117 unsigned int id) 118{ 119 struct mrq_pg_response response; 120 struct mrq_pg_request request; 121 struct tegra_bpmp_message msg; 122 int err; 123 124 memset(&request, 0, sizeof(request)); 125 request.cmd = CMD_PG_GET_NAME; 126 request.id = id; 127 128 memset(&response, 0, sizeof(response)); 129 130 memset(&msg, 0, sizeof(msg)); 131 msg.mrq = MRQ_PG; 132 msg.tx.data = &request; 133 msg.tx.size = sizeof(request); 134 msg.rx.data = &response; 135 msg.rx.size = sizeof(response); 136 137 err = tegra_bpmp_transfer(bpmp, &msg); 138 if (err < 0 || msg.rx.ret < 0) 139 return NULL; 140 141 return kstrdup(response.get_name.name, GFP_KERNEL); 142} 143 144static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp, 145 unsigned int id) 146{ 147 return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF; 148} 149 150static int tegra_powergate_power_on(struct generic_pm_domain *domain) 151{ 152 struct tegra_powergate *powergate = to_tegra_powergate(domain); 153 struct tegra_bpmp *bpmp = powergate->bpmp; 154 155 return tegra_bpmp_powergate_set_state(bpmp, powergate->id, 156 PG_STATE_ON); 157} 158 159static int tegra_powergate_power_off(struct generic_pm_domain *domain) 160{ 161 struct tegra_powergate *powergate = to_tegra_powergate(domain); 162 struct tegra_bpmp *bpmp = powergate->bpmp; 163 164 return tegra_bpmp_powergate_set_state(bpmp, powergate->id, 165 PG_STATE_OFF); 166} 167 168static struct tegra_powergate * 169tegra_powergate_add(struct tegra_bpmp *bpmp, 170 const struct tegra_powergate_info *info) 171{ 172 struct tegra_powergate *powergate; 173 bool off; 174 int err; 175 176 off = !tegra_bpmp_powergate_is_powered(bpmp, info->id); 177 178 powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL); 179 if (!powergate) 180 return ERR_PTR(-ENOMEM); 181 182 powergate->id = info->id; 183 powergate->bpmp = bpmp; 184 185 powergate->genpd.name = kstrdup(info->name, GFP_KERNEL); 186 powergate->genpd.power_on = tegra_powergate_power_on; 187 powergate->genpd.power_off = tegra_powergate_power_off; 188 189 err = pm_genpd_init(&powergate->genpd, NULL, off); 190 if (err < 0) { 191 kfree(powergate->genpd.name); 192 return ERR_PTR(err); 193 } 194 195 return powergate; 196} 197 198static void tegra_powergate_remove(struct tegra_powergate *powergate) 199{ 200 struct generic_pm_domain *genpd = &powergate->genpd; 201 struct tegra_bpmp *bpmp = powergate->bpmp; 202 int err; 203 204 err = pm_genpd_remove(genpd); 205 if (err < 0) 206 dev_err(bpmp->dev, "failed to remove power domain %s: %d\n", 207 genpd->name, err); 208 209 kfree(genpd->name); 210} 211 212static int 213tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp, 214 struct tegra_powergate_info **powergatesp) 215{ 216 struct tegra_powergate_info *powergates; 217 unsigned int max_id, id, count = 0; 218 unsigned int num_holes = 0; 219 int err; 220 221 err = tegra_bpmp_powergate_get_max_id(bpmp); 222 if (err < 0) 223 return err; 224 225 max_id = err; 226 227 dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id); 228 229 powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL); 230 if (!powergates) 231 return -ENOMEM; 232 233 for (id = 0; id <= max_id; id++) { 234 struct tegra_powergate_info *info = &powergates[count]; 235 236 info->name = tegra_bpmp_powergate_get_name(bpmp, id); 237 if (!info->name || info->name[0] == '\0') { 238 num_holes++; 239 continue; 240 } 241 242 info->id = id; 243 count++; 244 } 245 246 dev_dbg(bpmp->dev, "holes: %u\n", num_holes); 247 248 *powergatesp = powergates; 249 250 return count; 251} 252 253static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp, 254 struct tegra_powergate_info *powergates, 255 unsigned int count) 256{ 257 struct genpd_onecell_data *genpd = &bpmp->genpd; 258 struct generic_pm_domain **domains; 259 struct tegra_powergate *powergate; 260 unsigned int i; 261 int err; 262 263 domains = kcalloc(count, sizeof(*domains), GFP_KERNEL); 264 if (!domains) 265 return -ENOMEM; 266 267 for (i = 0; i < count; i++) { 268 powergate = tegra_powergate_add(bpmp, &powergates[i]); 269 if (IS_ERR(powergate)) { 270 err = PTR_ERR(powergate); 271 goto remove; 272 } 273 274 dev_dbg(bpmp->dev, "added power domain %s\n", 275 powergate->genpd.name); 276 domains[i] = &powergate->genpd; 277 } 278 279 genpd->num_domains = count; 280 genpd->domains = domains; 281 282 return 0; 283 284remove: 285 while (i--) { 286 powergate = to_tegra_powergate(domains[i]); 287 tegra_powergate_remove(powergate); 288 } 289 290 kfree(genpd->domains); 291 return err; 292} 293 294static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp) 295{ 296 struct genpd_onecell_data *genpd = &bpmp->genpd; 297 unsigned int i = genpd->num_domains; 298 struct tegra_powergate *powergate; 299 300 while (i--) { 301 dev_dbg(bpmp->dev, "removing power domain %s\n", 302 genpd->domains[i]->name); 303 powergate = to_tegra_powergate(genpd->domains[i]); 304 tegra_powergate_remove(powergate); 305 } 306} 307 308static struct generic_pm_domain * 309tegra_powergate_xlate(struct of_phandle_args *spec, void *data) 310{ 311 struct generic_pm_domain *domain = ERR_PTR(-ENOENT); 312 struct genpd_onecell_data *genpd = data; 313 unsigned int i; 314 315 for (i = 0; i < genpd->num_domains; i++) { 316 struct tegra_powergate *powergate; 317 318 powergate = to_tegra_powergate(genpd->domains[i]); 319 if (powergate->id == spec->args[0]) { 320 domain = &powergate->genpd; 321 break; 322 } 323 } 324 325 return domain; 326} 327 328int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp) 329{ 330 struct device_node *np = bpmp->dev->of_node; 331 struct tegra_powergate_info *powergates; 332 struct device *dev = bpmp->dev; 333 unsigned int count, i; 334 int err; 335 336 err = tegra_bpmp_probe_powergates(bpmp, &powergates); 337 if (err < 0) 338 return err; 339 340 count = err; 341 342 dev_dbg(dev, "%u power domains probed\n", count); 343 344 err = tegra_bpmp_add_powergates(bpmp, powergates, count); 345 if (err < 0) 346 goto free; 347 348 bpmp->genpd.xlate = tegra_powergate_xlate; 349 350 err = of_genpd_add_provider_onecell(np, &bpmp->genpd); 351 if (err < 0) { 352 dev_err(dev, "failed to add power domain provider: %d\n", err); 353 tegra_bpmp_remove_powergates(bpmp); 354 } 355 356free: 357 for (i = 0; i < count; i++) 358 kfree(powergates[i].name); 359 360 kfree(powergates); 361 return err; 362} 363