1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
7 #include <linux/platform_device.h>
8 #include <linux/pm_domain.h>
9 #include <linux/slab.h>
10 #include <linux/version.h>
12 #include <soc/tegra/bpmp.h>
13 #include <soc/tegra/bpmp-abi.h>
15 struct tegra_powergate_info {
20 struct tegra_powergate {
21 struct generic_pm_domain genpd;
22 struct tegra_bpmp *bpmp;
26 static inline struct tegra_powergate *
27 to_tegra_powergate(struct generic_pm_domain *genpd)
29 return container_of(genpd, struct tegra_powergate, genpd);
32 static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
33 unsigned int id, u32 state)
35 struct mrq_pg_request request;
36 struct tegra_bpmp_message msg;
39 memset(&request, 0, sizeof(request));
40 request.cmd = CMD_PG_SET_STATE;
42 request.set_state.state = state;
44 memset(&msg, 0, sizeof(msg));
46 msg.tx.data = &request;
47 msg.tx.size = sizeof(request);
49 err = tegra_bpmp_transfer(bpmp, &msg);
52 else if (msg.rx.ret < 0)
58 static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
61 struct mrq_pg_response response;
62 struct mrq_pg_request request;
63 struct tegra_bpmp_message msg;
66 memset(&request, 0, sizeof(request));
67 request.cmd = CMD_PG_GET_STATE;
70 memset(&response, 0, sizeof(response));
72 memset(&msg, 0, sizeof(msg));
74 msg.tx.data = &request;
75 msg.tx.size = sizeof(request);
76 msg.rx.data = &response;
77 msg.rx.size = sizeof(response);
79 err = tegra_bpmp_transfer(bpmp, &msg);
82 else if (msg.rx.ret < 0)
85 return response.get_state.state;
88 static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
90 struct mrq_pg_response response;
91 struct mrq_pg_request request;
92 struct tegra_bpmp_message msg;
95 memset(&request, 0, sizeof(request));
96 request.cmd = CMD_PG_GET_MAX_ID;
98 memset(&response, 0, sizeof(response));
100 memset(&msg, 0, sizeof(msg));
102 msg.tx.data = &request;
103 msg.tx.size = sizeof(request);
104 msg.rx.data = &response;
105 msg.rx.size = sizeof(response);
107 err = tegra_bpmp_transfer(bpmp, &msg);
110 else if (msg.rx.ret < 0)
113 return response.get_max_id.max_id;
116 static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
119 struct mrq_pg_response response;
120 struct mrq_pg_request request;
121 struct tegra_bpmp_message msg;
124 memset(&request, 0, sizeof(request));
125 request.cmd = CMD_PG_GET_NAME;
128 memset(&response, 0, sizeof(response));
130 memset(&msg, 0, sizeof(msg));
132 msg.tx.data = &request;
133 msg.tx.size = sizeof(request);
134 msg.rx.data = &response;
135 msg.rx.size = sizeof(response);
137 err = tegra_bpmp_transfer(bpmp, &msg);
138 if (err < 0 || msg.rx.ret < 0)
141 return kstrdup(response.get_name.name, GFP_KERNEL);
144 static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
147 return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
150 static int tegra_powergate_power_on(struct generic_pm_domain *domain)
152 struct tegra_powergate *powergate = to_tegra_powergate(domain);
153 struct tegra_bpmp *bpmp = powergate->bpmp;
155 return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
159 static int tegra_powergate_power_off(struct generic_pm_domain *domain)
161 struct tegra_powergate *powergate = to_tegra_powergate(domain);
162 struct tegra_bpmp *bpmp = powergate->bpmp;
164 return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
168 static struct tegra_powergate *
169 tegra_powergate_add(struct tegra_bpmp *bpmp,
170 const struct tegra_powergate_info *info)
172 struct tegra_powergate *powergate;
176 off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
178 powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
180 return ERR_PTR(-ENOMEM);
182 powergate->id = info->id;
183 powergate->bpmp = bpmp;
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;
189 err = pm_genpd_init(&powergate->genpd, NULL, off);
191 kfree(powergate->genpd.name);
198 static void tegra_powergate_remove(struct tegra_powergate *powergate)
200 struct generic_pm_domain *genpd = &powergate->genpd;
201 struct tegra_bpmp *bpmp = powergate->bpmp;
204 err = pm_genpd_remove(genpd);
206 dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
213 tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
214 struct tegra_powergate_info **powergatesp)
216 struct tegra_powergate_info *powergates;
217 unsigned int max_id, id, count = 0;
218 unsigned int num_holes = 0;
221 err = tegra_bpmp_powergate_get_max_id(bpmp);
227 dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
229 powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
233 for (id = 0; id <= max_id; id++) {
234 struct tegra_powergate_info *info = &powergates[count];
236 info->name = tegra_bpmp_powergate_get_name(bpmp, id);
237 if (!info->name || info->name[0] == '\0') {
246 dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
248 *powergatesp = powergates;
253 static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
254 struct tegra_powergate_info *powergates,
257 struct genpd_onecell_data *genpd = &bpmp->genpd;
258 struct generic_pm_domain **domains;
259 struct tegra_powergate *powergate;
263 domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
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);
274 dev_dbg(bpmp->dev, "added power domain %s\n",
275 powergate->genpd.name);
276 domains[i] = &powergate->genpd;
279 genpd->num_domains = count;
280 genpd->domains = domains;
286 powergate = to_tegra_powergate(domains[i]);
287 tegra_powergate_remove(powergate);
290 kfree(genpd->domains);
294 static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
296 struct genpd_onecell_data *genpd = &bpmp->genpd;
297 unsigned int i = genpd->num_domains;
298 struct tegra_powergate *powergate;
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);
308 static struct generic_pm_domain *
309 tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
311 struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
312 struct genpd_onecell_data *genpd = data;
315 for (i = 0; i < genpd->num_domains; i++) {
316 struct tegra_powergate *powergate;
318 powergate = to_tegra_powergate(genpd->domains[i]);
319 if (powergate->id == spec->args[0]) {
320 domain = &powergate->genpd;
328 int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
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;
336 err = tegra_bpmp_probe_powergates(bpmp, &powergates);
342 dev_dbg(dev, "%u power domains probed\n", count);
344 err = tegra_bpmp_add_powergates(bpmp, powergates, count);
348 bpmp->genpd.xlate = tegra_powergate_xlate;
350 err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
352 dev_err(dev, "failed to add power domain provider: %d\n", err);
353 tegra_bpmp_remove_powergates(bpmp);
357 for (i = 0; i < count; i++)
358 kfree(powergates[i].name);