2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include <linux/platform_device.h>
16 #include <linux/pm_domain.h>
17 #include <linux/slab.h>
18 #include <linux/version.h>
20 #include <soc/tegra/bpmp.h>
21 #include <soc/tegra/bpmp-abi.h>
23 struct tegra_powergate_info {
28 struct tegra_powergate {
29 struct generic_pm_domain genpd;
30 struct tegra_bpmp *bpmp;
34 static inline struct tegra_powergate *
35 to_tegra_powergate(struct generic_pm_domain *genpd)
37 return container_of(genpd, struct tegra_powergate, genpd);
40 static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
41 unsigned int id, u32 state)
43 struct mrq_pg_request request;
44 struct tegra_bpmp_message msg;
46 memset(&request, 0, sizeof(request));
47 request.cmd = CMD_PG_SET_STATE;
49 request.set_state.state = state;
51 memset(&msg, 0, sizeof(msg));
53 msg.tx.data = &request;
54 msg.tx.size = sizeof(request);
56 return tegra_bpmp_transfer(bpmp, &msg);
59 static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
62 struct mrq_pg_response response;
63 struct mrq_pg_request request;
64 struct tegra_bpmp_message msg;
67 memset(&request, 0, sizeof(request));
68 request.cmd = CMD_PG_GET_STATE;
71 memset(&response, 0, sizeof(response));
73 memset(&msg, 0, sizeof(msg));
75 msg.tx.data = &request;
76 msg.tx.size = sizeof(request);
77 msg.rx.data = &response;
78 msg.rx.size = sizeof(response);
80 err = tegra_bpmp_transfer(bpmp, &msg);
84 return response.get_state.state;
87 static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
89 struct mrq_pg_response response;
90 struct mrq_pg_request request;
91 struct tegra_bpmp_message msg;
94 memset(&request, 0, sizeof(request));
95 request.cmd = CMD_PG_GET_MAX_ID;
97 memset(&response, 0, sizeof(response));
99 memset(&msg, 0, sizeof(msg));
101 msg.tx.data = &request;
102 msg.tx.size = sizeof(request);
103 msg.rx.data = &response;
104 msg.rx.size = sizeof(response);
106 err = tegra_bpmp_transfer(bpmp, &msg);
110 return response.get_max_id.max_id;
113 static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
116 struct mrq_pg_response response;
117 struct mrq_pg_request request;
118 struct tegra_bpmp_message msg;
121 memset(&request, 0, sizeof(request));
122 request.cmd = CMD_PG_GET_NAME;
125 memset(&response, 0, sizeof(response));
127 memset(&msg, 0, sizeof(msg));
129 msg.tx.data = &request;
130 msg.tx.size = sizeof(request);
131 msg.rx.data = &response;
132 msg.rx.size = sizeof(response);
134 err = tegra_bpmp_transfer(bpmp, &msg);
138 return kstrdup(response.get_name.name, GFP_KERNEL);
141 static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
144 return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
147 static int tegra_powergate_power_on(struct generic_pm_domain *domain)
149 struct tegra_powergate *powergate = to_tegra_powergate(domain);
150 struct tegra_bpmp *bpmp = powergate->bpmp;
152 return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
156 static int tegra_powergate_power_off(struct generic_pm_domain *domain)
158 struct tegra_powergate *powergate = to_tegra_powergate(domain);
159 struct tegra_bpmp *bpmp = powergate->bpmp;
161 return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
165 static struct tegra_powergate *
166 tegra_powergate_add(struct tegra_bpmp *bpmp,
167 const struct tegra_powergate_info *info)
169 struct tegra_powergate *powergate;
173 off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
175 powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
177 return ERR_PTR(-ENOMEM);
179 powergate->id = info->id;
180 powergate->bpmp = bpmp;
182 powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
183 powergate->genpd.power_on = tegra_powergate_power_on;
184 powergate->genpd.power_off = tegra_powergate_power_off;
186 err = pm_genpd_init(&powergate->genpd, NULL, off);
188 kfree(powergate->genpd.name);
195 static void tegra_powergate_remove(struct tegra_powergate *powergate)
197 struct generic_pm_domain *genpd = &powergate->genpd;
198 struct tegra_bpmp *bpmp = powergate->bpmp;
201 err = pm_genpd_remove(genpd);
203 dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
210 tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
211 struct tegra_powergate_info **powergatesp)
213 struct tegra_powergate_info *powergates;
214 unsigned int max_id, id, count = 0;
215 unsigned int num_holes = 0;
218 err = tegra_bpmp_powergate_get_max_id(bpmp);
224 dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
226 powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
230 for (id = 0; id <= max_id; id++) {
231 struct tegra_powergate_info *info = &powergates[count];
233 info->name = tegra_bpmp_powergate_get_name(bpmp, id);
234 if (!info->name || info->name[0] == '\0') {
243 dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
245 *powergatesp = powergates;
250 static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
251 struct tegra_powergate_info *powergates,
254 struct genpd_onecell_data *genpd = &bpmp->genpd;
255 struct generic_pm_domain **domains;
256 struct tegra_powergate *powergate;
260 domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
264 for (i = 0; i < count; i++) {
265 powergate = tegra_powergate_add(bpmp, &powergates[i]);
266 if (IS_ERR(powergate)) {
267 err = PTR_ERR(powergate);
271 dev_dbg(bpmp->dev, "added power domain %s\n",
272 powergate->genpd.name);
273 domains[i] = &powergate->genpd;
276 genpd->num_domains = count;
277 genpd->domains = domains;
283 powergate = to_tegra_powergate(domains[i]);
284 tegra_powergate_remove(powergate);
287 kfree(genpd->domains);
291 static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
293 struct genpd_onecell_data *genpd = &bpmp->genpd;
294 unsigned int i = genpd->num_domains;
295 struct tegra_powergate *powergate;
298 dev_dbg(bpmp->dev, "removing power domain %s\n",
299 genpd->domains[i]->name);
300 powergate = to_tegra_powergate(genpd->domains[i]);
301 tegra_powergate_remove(powergate);
305 static struct generic_pm_domain *
306 tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
308 struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
309 struct genpd_onecell_data *genpd = data;
312 for (i = 0; i < genpd->num_domains; i++) {
313 struct tegra_powergate *powergate;
315 powergate = to_tegra_powergate(genpd->domains[i]);
316 if (powergate->id == spec->args[0]) {
317 domain = &powergate->genpd;
325 int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
327 struct device_node *np = bpmp->dev->of_node;
328 struct tegra_powergate_info *powergates;
329 struct device *dev = bpmp->dev;
330 unsigned int count, i;
333 err = tegra_bpmp_probe_powergates(bpmp, &powergates);
339 dev_dbg(dev, "%u power domains probed\n", count);
341 err = tegra_bpmp_add_powergates(bpmp, powergates, count);
345 bpmp->genpd.xlate = tegra_powergate_xlate;
347 err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
349 dev_err(dev, "failed to add power domain provider: %d\n", err);
350 tegra_bpmp_remove_powergates(bpmp);
354 for (i = 0; i < count; i++)
355 kfree(powergates[i].name);