xref: /openbmc/linux/drivers/clk/tegra/clk-bpmp.c (revision 5d0e4d78)
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 }
621