GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / clk / tegra / clk-bpmp.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2016 NVIDIA Corporation
4  */
5
6 #include <linux/clk-provider.h>
7 #include <linux/device.h>
8 #include <linux/seq_buf.h>
9 #include <linux/slab.h>
10
11 #include <soc/tegra/bpmp.h>
12 #include <soc/tegra/bpmp-abi.h>
13
14 #define TEGRA_BPMP_DUMP_CLOCK_INFO      0
15
16 #define TEGRA_BPMP_CLK_HAS_MUX          BIT(0)
17 #define TEGRA_BPMP_CLK_HAS_SET_RATE     BIT(1)
18 #define TEGRA_BPMP_CLK_IS_ROOT          BIT(2)
19
20 struct tegra_bpmp_clk_info {
21         unsigned int id;
22         char name[MRQ_CLK_NAME_MAXLEN];
23         unsigned int parents[MRQ_CLK_MAX_PARENTS];
24         unsigned int num_parents;
25         unsigned long flags;
26 };
27
28 struct tegra_bpmp_clk {
29         struct clk_hw hw;
30
31         struct tegra_bpmp *bpmp;
32         unsigned int id;
33
34         unsigned int num_parents;
35         unsigned int *parents;
36 };
37
38 static inline struct tegra_bpmp_clk *to_tegra_bpmp_clk(struct clk_hw *hw)
39 {
40         return container_of(hw, struct tegra_bpmp_clk, hw);
41 }
42
43 struct tegra_bpmp_clk_message {
44         unsigned int cmd;
45         unsigned int id;
46
47         struct {
48                 const void *data;
49                 size_t size;
50         } tx;
51
52         struct {
53                 void *data;
54                 size_t size;
55                 int ret;
56         } rx;
57 };
58
59 static int tegra_bpmp_clk_transfer(struct tegra_bpmp *bpmp,
60                                    const struct tegra_bpmp_clk_message *clk)
61 {
62         struct mrq_clk_request request;
63         struct tegra_bpmp_message msg;
64         void *req = &request;
65         int err;
66
67         memset(&request, 0, sizeof(request));
68         request.cmd_and_id = (clk->cmd << 24) | clk->id;
69
70         /*
71          * The mrq_clk_request structure has an anonymous union at offset 4
72          * that contains all possible sub-command structures. Copy the data
73          * to that union. Ideally we'd be able to refer to it by name, but
74          * doing so would require changing the ABI header and increase the
75          * maintenance burden.
76          */
77         memcpy(req + 4, clk->tx.data, clk->tx.size);
78
79         memset(&msg, 0, sizeof(msg));
80         msg.mrq = MRQ_CLK;
81         msg.tx.data = &request;
82         msg.tx.size = sizeof(request);
83         msg.rx.data = clk->rx.data;
84         msg.rx.size = clk->rx.size;
85
86         err = tegra_bpmp_transfer(bpmp, &msg);
87         if (err < 0)
88                 return err;
89         else if (msg.rx.ret < 0)
90                 return -EINVAL;
91
92         return 0;
93 }
94
95 static int tegra_bpmp_clk_prepare(struct clk_hw *hw)
96 {
97         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
98         struct tegra_bpmp_clk_message msg;
99
100         memset(&msg, 0, sizeof(msg));
101         msg.cmd = CMD_CLK_ENABLE;
102         msg.id = clk->id;
103
104         return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
105 }
106
107 static void tegra_bpmp_clk_unprepare(struct clk_hw *hw)
108 {
109         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
110         struct tegra_bpmp_clk_message msg;
111         int err;
112
113         memset(&msg, 0, sizeof(msg));
114         msg.cmd = CMD_CLK_DISABLE;
115         msg.id = clk->id;
116
117         err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
118         if (err < 0)
119                 dev_err(clk->bpmp->dev, "failed to disable clock %s: %d\n",
120                         clk_hw_get_name(hw), err);
121 }
122
123 static int tegra_bpmp_clk_is_prepared(struct clk_hw *hw)
124 {
125         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
126         struct cmd_clk_is_enabled_response response;
127         struct tegra_bpmp_clk_message msg;
128         int err;
129
130         memset(&msg, 0, sizeof(msg));
131         msg.cmd = CMD_CLK_IS_ENABLED;
132         msg.id = clk->id;
133         msg.rx.data = &response;
134         msg.rx.size = sizeof(response);
135
136         err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
137         if (err < 0)
138                 return err;
139
140         return response.state;
141 }
142
143 static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw,
144                                                 unsigned long parent_rate)
145 {
146         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
147         struct cmd_clk_get_rate_response response;
148         struct cmd_clk_get_rate_request request;
149         struct tegra_bpmp_clk_message msg;
150         int err;
151
152         memset(&msg, 0, sizeof(msg));
153         msg.cmd = CMD_CLK_GET_RATE;
154         msg.id = clk->id;
155         msg.tx.data = &request;
156         msg.tx.size = sizeof(request);
157         msg.rx.data = &response;
158         msg.rx.size = sizeof(response);
159
160         err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
161         if (err < 0)
162                 return 0;
163
164         return response.rate;
165 }
166
167 static long tegra_bpmp_clk_round_rate(struct clk_hw *hw, unsigned long rate,
168                                       unsigned long *parent_rate)
169 {
170         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
171         struct cmd_clk_round_rate_response response;
172         struct cmd_clk_round_rate_request request;
173         struct tegra_bpmp_clk_message msg;
174         int err;
175
176         memset(&request, 0, sizeof(request));
177         request.rate = rate;
178
179         memset(&msg, 0, sizeof(msg));
180         msg.cmd = CMD_CLK_ROUND_RATE;
181         msg.id = clk->id;
182         msg.tx.data = &request;
183         msg.tx.size = sizeof(request);
184         msg.rx.data = &response;
185         msg.rx.size = sizeof(response);
186
187         err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
188         if (err < 0)
189                 return err;
190
191         return response.rate;
192 }
193
194 static int tegra_bpmp_clk_set_parent(struct clk_hw *hw, u8 index)
195 {
196         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
197         struct cmd_clk_set_parent_response response;
198         struct cmd_clk_set_parent_request request;
199         struct tegra_bpmp_clk_message msg;
200         int err;
201
202         memset(&request, 0, sizeof(request));
203         request.parent_id = clk->parents[index];
204
205         memset(&msg, 0, sizeof(msg));
206         msg.cmd = CMD_CLK_SET_PARENT;
207         msg.id = clk->id;
208         msg.tx.data = &request;
209         msg.tx.size = sizeof(request);
210         msg.rx.data = &response;
211         msg.rx.size = sizeof(response);
212
213         err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
214         if (err < 0)
215                 return err;
216
217         /* XXX check parent ID in response */
218
219         return 0;
220 }
221
222 static u8 tegra_bpmp_clk_get_parent(struct clk_hw *hw)
223 {
224         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
225         struct cmd_clk_get_parent_response response;
226         struct tegra_bpmp_clk_message msg;
227         unsigned int i;
228         int err;
229
230         memset(&msg, 0, sizeof(msg));
231         msg.cmd = CMD_CLK_GET_PARENT;
232         msg.id = clk->id;
233         msg.rx.data = &response;
234         msg.rx.size = sizeof(response);
235
236         err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
237         if (err < 0) {
238                 dev_err(clk->bpmp->dev, "failed to get parent for %s: %d\n",
239                         clk_hw_get_name(hw), err);
240                 return U8_MAX;
241         }
242
243         for (i = 0; i < clk->num_parents; i++)
244                 if (clk->parents[i] == response.parent_id)
245                         return i;
246
247         return U8_MAX;
248 }
249
250 static int tegra_bpmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
251                                    unsigned long parent_rate)
252 {
253         struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
254         struct cmd_clk_set_rate_response response;
255         struct cmd_clk_set_rate_request request;
256         struct tegra_bpmp_clk_message msg;
257
258         memset(&request, 0, sizeof(request));
259         request.rate = rate;
260
261         memset(&msg, 0, sizeof(msg));
262         msg.cmd = CMD_CLK_SET_RATE;
263         msg.id = clk->id;
264         msg.tx.data = &request;
265         msg.tx.size = sizeof(request);
266         msg.rx.data = &response;
267         msg.rx.size = sizeof(response);
268
269         return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
270 }
271
272 static const struct clk_ops tegra_bpmp_clk_gate_ops = {
273         .prepare = tegra_bpmp_clk_prepare,
274         .unprepare = tegra_bpmp_clk_unprepare,
275         .is_prepared = tegra_bpmp_clk_is_prepared,
276         .recalc_rate = tegra_bpmp_clk_recalc_rate,
277 };
278
279 static const struct clk_ops tegra_bpmp_clk_mux_ops = {
280         .prepare = tegra_bpmp_clk_prepare,
281         .unprepare = tegra_bpmp_clk_unprepare,
282         .is_prepared = tegra_bpmp_clk_is_prepared,
283         .recalc_rate = tegra_bpmp_clk_recalc_rate,
284         .set_parent = tegra_bpmp_clk_set_parent,
285         .get_parent = tegra_bpmp_clk_get_parent,
286 };
287
288 static const struct clk_ops tegra_bpmp_clk_rate_ops = {
289         .prepare = tegra_bpmp_clk_prepare,
290         .unprepare = tegra_bpmp_clk_unprepare,
291         .is_prepared = tegra_bpmp_clk_is_prepared,
292         .recalc_rate = tegra_bpmp_clk_recalc_rate,
293         .round_rate = tegra_bpmp_clk_round_rate,
294         .set_rate = tegra_bpmp_clk_set_rate,
295 };
296
297 static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
298         .prepare = tegra_bpmp_clk_prepare,
299         .unprepare = tegra_bpmp_clk_unprepare,
300         .is_prepared = tegra_bpmp_clk_is_prepared,
301         .recalc_rate = tegra_bpmp_clk_recalc_rate,
302         .round_rate = tegra_bpmp_clk_round_rate,
303         .set_parent = tegra_bpmp_clk_set_parent,
304         .get_parent = tegra_bpmp_clk_get_parent,
305         .set_rate = tegra_bpmp_clk_set_rate,
306 };
307
308 static int tegra_bpmp_clk_get_max_id(struct tegra_bpmp *bpmp)
309 {
310         struct cmd_clk_get_max_clk_id_response response;
311         struct tegra_bpmp_clk_message msg;
312         int err;
313
314         memset(&msg, 0, sizeof(msg));
315         msg.cmd = CMD_CLK_GET_MAX_CLK_ID;
316         msg.rx.data = &response;
317         msg.rx.size = sizeof(response);
318
319         err = tegra_bpmp_clk_transfer(bpmp, &msg);
320         if (err < 0)
321                 return err;
322
323         if (response.max_id > INT_MAX)
324                 return -E2BIG;
325
326         return response.max_id;
327 }
328
329 static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
330                                    struct tegra_bpmp_clk_info *info)
331 {
332         struct cmd_clk_get_all_info_response response;
333         struct tegra_bpmp_clk_message msg;
334         unsigned int i;
335         int err;
336
337         memset(&msg, 0, sizeof(msg));
338         msg.cmd = CMD_CLK_GET_ALL_INFO;
339         msg.id = id;
340         msg.rx.data = &response;
341         msg.rx.size = sizeof(response);
342
343         err = tegra_bpmp_clk_transfer(bpmp, &msg);
344         if (err < 0)
345                 return err;
346
347         strlcpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
348         info->num_parents = response.num_parents;
349
350         for (i = 0; i < info->num_parents; i++)
351                 info->parents[i] = response.parents[i];
352
353         info->flags = response.flags;
354
355         return 0;
356 }
357
358 static void tegra_bpmp_clk_info_dump(struct tegra_bpmp *bpmp,
359                                      const char *level,
360                                      const struct tegra_bpmp_clk_info *info)
361 {
362         const char *prefix = "";
363         struct seq_buf buf;
364         unsigned int i;
365         char flags[64];
366
367         seq_buf_init(&buf, flags, sizeof(flags));
368
369         if (info->flags)
370                 seq_buf_printf(&buf, "(");
371
372         if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
373                 seq_buf_printf(&buf, "%smux", prefix);
374                 prefix = ", ";
375         }
376
377         if ((info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE) == 0) {
378                 seq_buf_printf(&buf, "%sfixed", prefix);
379                 prefix = ", ";
380         }
381
382         if (info->flags & TEGRA_BPMP_CLK_IS_ROOT) {
383                 seq_buf_printf(&buf, "%sroot", prefix);
384                 prefix = ", ";
385         }
386
387         if (info->flags)
388                 seq_buf_printf(&buf, ")");
389
390         dev_printk(level, bpmp->dev, "%03u: %s\n", info->id, info->name);
391         dev_printk(level, bpmp->dev, "  flags: %lx %s\n", info->flags, flags);
392         dev_printk(level, bpmp->dev, "  parents: %u\n", info->num_parents);
393
394         for (i = 0; i < info->num_parents; i++)
395                 dev_printk(level, bpmp->dev, "    %03u\n", info->parents[i]);
396 }
397
398 static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp,
399                                    struct tegra_bpmp_clk_info **clocksp)
400 {
401         struct tegra_bpmp_clk_info *clocks;
402         unsigned int max_id, id, count = 0;
403         unsigned int holes = 0;
404         int err;
405
406         err = tegra_bpmp_clk_get_max_id(bpmp);
407         if (err < 0)
408                 return err;
409
410         max_id = err;
411
412         dev_dbg(bpmp->dev, "maximum clock ID: %u\n", max_id);
413
414         clocks = kcalloc(max_id + 1, sizeof(*clocks), GFP_KERNEL);
415         if (!clocks)
416                 return -ENOMEM;
417
418         for (id = 0; id <= max_id; id++) {
419                 struct tegra_bpmp_clk_info *info = &clocks[count];
420
421                 err = tegra_bpmp_clk_get_info(bpmp, id, info);
422                 if (err < 0)
423                         continue;
424
425                 if (info->num_parents >= U8_MAX) {
426                         dev_err(bpmp->dev,
427                                 "clock %u has too many parents (%u, max: %u)\n",
428                                 id, info->num_parents, U8_MAX);
429                         continue;
430                 }
431
432                 /* clock not exposed by BPMP */
433                 if (info->name[0] == '\0') {
434                         holes++;
435                         continue;
436                 }
437
438                 info->id = id;
439                 count++;
440
441                 if (TEGRA_BPMP_DUMP_CLOCK_INFO)
442                         tegra_bpmp_clk_info_dump(bpmp, KERN_DEBUG, info);
443         }
444
445         dev_dbg(bpmp->dev, "holes: %u\n", holes);
446         *clocksp = clocks;
447
448         return count;
449 }
450
451 static const struct tegra_bpmp_clk_info *
452 tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info *clocks,
453                     unsigned int num_clocks, unsigned int id)
454 {
455         unsigned int i;
456
457         for (i = 0; i < num_clocks; i++)
458                 if (clocks[i].id == id)
459                         return &clocks[i];
460
461         return NULL;
462 }
463
464 static struct tegra_bpmp_clk *
465 tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
466                         const struct tegra_bpmp_clk_info *info,
467                         const struct tegra_bpmp_clk_info *clocks,
468                         unsigned int num_clocks)
469 {
470         struct tegra_bpmp_clk *clk;
471         struct clk_init_data init;
472         const char **parents;
473         unsigned int i;
474         int err;
475
476         clk = devm_kzalloc(bpmp->dev, sizeof(*clk), GFP_KERNEL);
477         if (!clk)
478                 return ERR_PTR(-ENOMEM);
479
480         clk->id = info->id;
481         clk->bpmp = bpmp;
482
483         clk->parents = devm_kcalloc(bpmp->dev, info->num_parents,
484                                     sizeof(*clk->parents), GFP_KERNEL);
485         if (!clk->parents)
486                 return ERR_PTR(-ENOMEM);
487
488         clk->num_parents = info->num_parents;
489
490         /* hardware clock initialization */
491         memset(&init, 0, sizeof(init));
492         init.name = info->name;
493         clk->hw.init = &init;
494
495         if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
496                 if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
497                         init.ops = &tegra_bpmp_clk_mux_rate_ops;
498                 else
499                         init.ops = &tegra_bpmp_clk_mux_ops;
500         } else {
501                 if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
502                         init.ops = &tegra_bpmp_clk_rate_ops;
503                 else
504                         init.ops = &tegra_bpmp_clk_gate_ops;
505         }
506
507         init.num_parents = info->num_parents;
508
509         parents = kcalloc(info->num_parents, sizeof(*parents), GFP_KERNEL);
510         if (!parents)
511                 return ERR_PTR(-ENOMEM);
512
513         for (i = 0; i < info->num_parents; i++) {
514                 const struct tegra_bpmp_clk_info *parent;
515
516                 /* keep a private copy of the ID to parent index map */
517                 clk->parents[i] = info->parents[i];
518
519                 parent = tegra_bpmp_clk_find(clocks, num_clocks,
520                                              info->parents[i]);
521                 if (!parent) {
522                         dev_err(bpmp->dev, "no parent %u found for %u\n",
523                                 info->parents[i], info->id);
524                         continue;
525                 }
526
527                 parents[i] = parent->name;
528         }
529
530         init.parent_names = parents;
531
532         err = devm_clk_hw_register(bpmp->dev, &clk->hw);
533
534         kfree(parents);
535
536         if (err < 0)
537                 return ERR_PTR(err);
538
539         return clk;
540 }
541
542 static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp,
543                                       struct tegra_bpmp_clk_info *infos,
544                                       unsigned int count)
545 {
546         struct tegra_bpmp_clk *clk;
547         unsigned int i;
548
549         bpmp->num_clocks = count;
550
551         bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(clk), GFP_KERNEL);
552         if (!bpmp->clocks)
553                 return -ENOMEM;
554
555         for (i = 0; i < count; i++) {
556                 struct tegra_bpmp_clk_info *info = &infos[i];
557
558                 clk = tegra_bpmp_clk_register(bpmp, info, infos, count);
559                 if (IS_ERR(clk)) {
560                         dev_err(bpmp->dev,
561                                 "failed to register clock %u (%s): %ld\n",
562                                 info->id, info->name, PTR_ERR(clk));
563                         continue;
564                 }
565
566                 bpmp->clocks[i] = clk;
567         }
568
569         return 0;
570 }
571
572 static void tegra_bpmp_unregister_clocks(struct tegra_bpmp *bpmp)
573 {
574         unsigned int i;
575
576         for (i = 0; i < bpmp->num_clocks; i++)
577                 clk_hw_unregister(&bpmp->clocks[i]->hw);
578 }
579
580 static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec,
581                                               void *data)
582 {
583         unsigned int id = clkspec->args[0], i;
584         struct tegra_bpmp *bpmp = data;
585
586         for (i = 0; i < bpmp->num_clocks; i++) {
587                 struct tegra_bpmp_clk *clk = bpmp->clocks[i];
588
589                 if (!clk)
590                         continue;
591
592                 if (clk->id == id)
593                         return &clk->hw;
594         }
595
596         return NULL;
597 }
598
599 int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp)
600 {
601         struct tegra_bpmp_clk_info *clocks;
602         unsigned int count;
603         int err;
604
605         err = tegra_bpmp_probe_clocks(bpmp, &clocks);
606         if (err < 0)
607                 return err;
608
609         count = err;
610
611         dev_dbg(bpmp->dev, "%u clocks probed\n", count);
612
613         err = tegra_bpmp_register_clocks(bpmp, clocks, count);
614         if (err < 0)
615                 goto free;
616
617         err = of_clk_add_hw_provider(bpmp->dev->of_node,
618                                      tegra_bpmp_clk_of_xlate,
619                                      bpmp);
620         if (err < 0) {
621                 tegra_bpmp_unregister_clocks(bpmp);
622                 goto free;
623         }
624
625 free:
626         kfree(clocks);
627         return err;
628 }