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