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