Merge tag 'drivers-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / soc / tegra / powergate-bpmp.c
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 *
26 to_tegra_powergate(struct generic_pm_domain *genpd)
27 {
28         return container_of(genpd, struct tegra_powergate, genpd);
29 }
30
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
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
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
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
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
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
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 *
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
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
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
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(genpd->domains);
290         return err;
291 }
292
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 *
308 tegra_powergate_xlate(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
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 }