1
2
3
4
5
6
7
8
9
10#include <linux/clk.h>
11#include <linux/clk-provider.h>
12#include <linux/clk/zynqmp.h>
13#include <linux/io.h>
14#include <linux/of.h>
15#include <linux/of_address.h>
16#include <linux/slab.h>
17#include <linux/string.h>
18
19#define MAX_PARENT 100
20#define MAX_NODES 6
21#define MAX_NAME_LEN 50
22#define MAX_CLOCK 300
23
24#define CLK_INIT_ENABLE_SHIFT 1
25#define CLK_TYPE_SHIFT 2
26
27#define PM_API_PAYLOAD_LEN 3
28
29#define NA_PARENT -1
30#define DUMMY_PARENT -2
31
32#define CLK_TYPE_FIELD_LEN 4
33#define CLK_TOPOLOGY_NODE_OFFSET 16
34#define NODES_PER_RESP 3
35
36#define CLK_TYPE_FIELD_MASK 0xF
37#define CLK_FLAG_FIELD_SHIFT 8
38#define CLK_FLAG_FIELD_MASK 0x3FFF
39#define CLK_TYPE_FLAG_FIELD_SHIFT 24
40#define CLK_TYPE_FLAG_FIELD_MASK 0xFF
41
42#define CLK_PARENTS_ID_LEN 16
43#define CLK_PARENTS_ID_MASK 0xFFFF
44
45
46#define PARENT_CLK_SELF 0
47#define PARENT_CLK_NODE1 1
48#define PARENT_CLK_NODE2 2
49#define PARENT_CLK_NODE3 3
50#define PARENT_CLK_NODE4 4
51#define PARENT_CLK_EXTERNAL 5
52
53#define END_OF_CLK_NAME "END_OF_CLK"
54#define RESERVED_CLK_NAME ""
55
56#define CLK_VALID_MASK 0x1
57#define CLK_INIT_ENABLE_MASK (0x1 << CLK_INIT_ENABLE_SHIFT)
58
59enum clk_type {
60 CLK_TYPE_OUTPUT,
61 CLK_TYPE_EXTERNAL,
62};
63
64
65
66
67
68
69
70struct clock_parent {
71 char name[MAX_NAME_LEN];
72 int id;
73 u32 flag;
74};
75
76
77
78
79
80
81
82struct clock_topology {
83 u32 type;
84 u32 flag;
85 u32 type_flag;
86};
87
88
89
90
91
92
93
94
95
96
97
98
99struct zynqmp_clock {
100 char clk_name[MAX_NAME_LEN];
101 u32 valid;
102 u32 init_enable;
103 enum clk_type type;
104 struct clock_topology node[MAX_NODES];
105 u32 num_nodes;
106 struct clock_parent parent[MAX_PARENT];
107 u32 num_parents;
108};
109
110static const char clk_type_postfix[][10] = {
111 [TYPE_INVALID] = "",
112 [TYPE_MUX] = "_mux",
113 [TYPE_GATE] = "",
114 [TYPE_DIV1] = "_div1",
115 [TYPE_DIV2] = "_div2",
116 [TYPE_FIXEDFACTOR] = "_ff",
117 [TYPE_PLL] = ""
118};
119
120static struct zynqmp_clock clock[MAX_CLOCK];
121static struct clk_onecell_data zynqmp_clk_data;
122static struct clk *zynqmp_clks[MAX_CLOCK];
123static unsigned int clock_max_idx;
124static const struct zynqmp_eemi_ops *eemi_ops;
125
126
127
128
129
130
131
132
133
134static int is_valid_clock(u32 clk_id, u32 *valid)
135{
136 if (clk_id < 0 || clk_id > clock_max_idx)
137 return -ENODEV;
138
139 *valid = clock[clk_id].valid;
140
141 return *valid ? 0 : -EINVAL;
142}
143
144
145
146
147
148
149
150
151static int zynqmp_get_clock_name(u32 clk_id, char *clk_name)
152{
153 int ret;
154 u32 valid;
155
156 ret = is_valid_clock(clk_id, &valid);
157 if (!ret && valid) {
158 strncpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN);
159 return 0;
160 } else {
161 return ret;
162 }
163}
164
165
166
167
168
169
170
171
172static int get_clock_type(u32 clk_id, u32 *type)
173{
174 int ret;
175 u32 valid;
176
177 ret = is_valid_clock(clk_id, &valid);
178 if (!ret && valid) {
179 *type = clock[clk_id].type;
180 return 0;
181 } else {
182 return ret;
183 }
184}
185
186
187
188
189
190
191
192
193
194
195
196static int zynqmp_pm_clock_get_name(u32 clock_id, char *name)
197{
198 struct zynqmp_pm_query_data qdata = {0};
199 u32 ret_payload[PAYLOAD_ARG_CNT];
200
201 qdata.qid = PM_QID_CLOCK_GET_NAME;
202 qdata.arg1 = clock_id;
203
204 eemi_ops->query_data(qdata, ret_payload);
205 memcpy(name, ret_payload, CLK_GET_NAME_RESP_LEN);
206
207 return 0;
208}
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, u32 *topology)
228{
229 struct zynqmp_pm_query_data qdata = {0};
230 u32 ret_payload[PAYLOAD_ARG_CNT];
231 int ret;
232
233 qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY;
234 qdata.arg1 = clock_id;
235 qdata.arg2 = index;
236
237 ret = eemi_ops->query_data(qdata, ret_payload);
238 memcpy(topology, &ret_payload[1], CLK_GET_TOPOLOGY_RESP_WORDS * 4);
239
240 return ret;
241}
242
243
244
245
246
247
248
249
250
251
252
253
254static int zynqmp_pm_clock_get_fixedfactor_params(u32 clock_id,
255 u32 *mul,
256 u32 *div)
257{
258 struct zynqmp_pm_query_data qdata = {0};
259 u32 ret_payload[PAYLOAD_ARG_CNT];
260 int ret;
261
262 qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
263 qdata.arg1 = clock_id;
264
265 ret = eemi_ops->query_data(qdata, ret_payload);
266 *mul = ret_payload[1];
267 *div = ret_payload[2];
268
269 return ret;
270}
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents)
290{
291 struct zynqmp_pm_query_data qdata = {0};
292 u32 ret_payload[PAYLOAD_ARG_CNT];
293 int ret;
294
295 qdata.qid = PM_QID_CLOCK_GET_PARENTS;
296 qdata.arg1 = clock_id;
297 qdata.arg2 = index;
298
299 ret = eemi_ops->query_data(qdata, ret_payload);
300 memcpy(parents, &ret_payload[1], CLK_GET_PARENTS_RESP_WORDS * 4);
301
302 return ret;
303}
304
305
306
307
308
309
310
311
312
313
314static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr)
315{
316 struct zynqmp_pm_query_data qdata = {0};
317 u32 ret_payload[PAYLOAD_ARG_CNT];
318 int ret;
319
320 qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES;
321 qdata.arg1 = clock_id;
322
323 ret = eemi_ops->query_data(qdata, ret_payload);
324 memcpy(attr, &ret_payload[1], CLK_GET_ATTR_RESP_WORDS * 4);
325
326 return ret;
327}
328
329
330
331
332
333
334
335
336
337static int clock_get_topology(u32 clk_id, struct clock_topology *clk_topology,
338 u32 *num_nodes)
339{
340 int j, k = 0, ret;
341 u32 pm_resp[PM_API_PAYLOAD_LEN] = {0};
342
343 *num_nodes = 0;
344 for (j = 0; j <= MAX_NODES; j += 3) {
345 ret = zynqmp_pm_clock_get_topology(clk_id, j, pm_resp);
346 if (ret)
347 return ret;
348 for (k = 0; k < PM_API_PAYLOAD_LEN; k++) {
349 if (!(pm_resp[k] & CLK_TYPE_FIELD_MASK))
350 goto done;
351 clk_topology[*num_nodes].type = pm_resp[k] &
352 CLK_TYPE_FIELD_MASK;
353 clk_topology[*num_nodes].flag =
354 (pm_resp[k] >> CLK_FLAG_FIELD_SHIFT) &
355 CLK_FLAG_FIELD_MASK;
356 clk_topology[*num_nodes].type_flag =
357 (pm_resp[k] >> CLK_TYPE_FLAG_FIELD_SHIFT) &
358 CLK_TYPE_FLAG_FIELD_MASK;
359 (*num_nodes)++;
360 }
361 }
362done:
363 return 0;
364}
365
366
367
368
369
370
371
372
373
374static int clock_get_parents(u32 clk_id, struct clock_parent *parents,
375 u32 *num_parents)
376{
377 int j = 0, k, ret, total_parents = 0;
378 u32 pm_resp[PM_API_PAYLOAD_LEN] = {0};
379
380 do {
381
382 ret = zynqmp_pm_clock_get_parents(clk_id, j, pm_resp);
383 if (ret)
384 return ret;
385
386 for (k = 0; k < PM_API_PAYLOAD_LEN; k++) {
387 if (pm_resp[k] == (u32)NA_PARENT) {
388 *num_parents = total_parents;
389 return 0;
390 }
391
392 parents[k + j].id = pm_resp[k] & CLK_PARENTS_ID_MASK;
393 if (pm_resp[k] == (u32)DUMMY_PARENT) {
394 strncpy(parents[k + j].name,
395 "dummy_name", MAX_NAME_LEN);
396 parents[k + j].flag = 0;
397 } else {
398 parents[k + j].flag = pm_resp[k] >>
399 CLK_PARENTS_ID_LEN;
400 if (zynqmp_get_clock_name(parents[k + j].id,
401 parents[k + j].name))
402 continue;
403 }
404 total_parents++;
405 }
406 j += PM_API_PAYLOAD_LEN;
407 } while (total_parents <= MAX_PARENT);
408 return 0;
409}
410
411
412
413
414
415
416
417
418
419
420static int get_parent_list(struct device_node *np, u32 clk_id,
421 const char **parent_list, u32 *num_parents)
422{
423 int i = 0, ret;
424 u32 total_parents = clock[clk_id].num_parents;
425 struct clock_topology *clk_nodes;
426 struct clock_parent *parents;
427
428 clk_nodes = clock[clk_id].node;
429 parents = clock[clk_id].parent;
430
431 for (i = 0; i < total_parents; i++) {
432 if (!parents[i].flag) {
433 parent_list[i] = parents[i].name;
434 } else if (parents[i].flag == PARENT_CLK_EXTERNAL) {
435 ret = of_property_match_string(np, "clock-names",
436 parents[i].name);
437 if (ret < 0)
438 strncpy(parents[i].name,
439 "dummy_name", MAX_NAME_LEN);
440 parent_list[i] = parents[i].name;
441 } else {
442 strcat(parents[i].name,
443 clk_type_postfix[clk_nodes[parents[i].flag - 1].
444 type]);
445 parent_list[i] = parents[i].name;
446 }
447 }
448
449 *num_parents = total_parents;
450 return 0;
451}
452
453
454
455
456
457
458
459
460
461
462static struct clk *zynqmp_register_clk_topology(int clk_id, char *clk_name,
463 int num_parents,
464 const char **parent_names)
465{
466 int j, ret;
467 u32 num_nodes, mult, div;
468 char *clk_out = NULL;
469 struct clock_topology *nodes;
470 struct clk *clk = NULL;
471
472 nodes = clock[clk_id].node;
473 num_nodes = clock[clk_id].num_nodes;
474
475 for (j = 0; j < num_nodes; j++) {
476 if (j != (num_nodes - 1)) {
477 clk_out = kasprintf(GFP_KERNEL, "%s%s", clk_name,
478 clk_type_postfix[nodes[j].type]);
479 } else {
480 clk_out = kasprintf(GFP_KERNEL, "%s", clk_name);
481 }
482
483 switch (nodes[j].type) {
484 case TYPE_MUX:
485 clk = zynqmp_clk_register_mux(NULL, clk_out,
486 clk_id, parent_names,
487 num_parents,
488 nodes[j].flag,
489 nodes[j].type_flag);
490 break;
491 case TYPE_PLL:
492 clk = clk_register_zynqmp_pll(clk_out, clk_id,
493 parent_names, 1,
494 nodes[j].flag);
495 break;
496 case TYPE_FIXEDFACTOR:
497 ret = zynqmp_pm_clock_get_fixedfactor_params(clk_id,
498 &mult,
499 &div);
500 clk = clk_register_fixed_factor(NULL, clk_out,
501 parent_names[0],
502 nodes[j].flag, mult,
503 div);
504 break;
505 case TYPE_DIV1:
506 case TYPE_DIV2:
507 clk = zynqmp_clk_register_divider(NULL, clk_out, clk_id,
508 nodes[j].type,
509 parent_names, 1,
510 nodes[j].flag,
511 nodes[j].type_flag);
512 break;
513 case TYPE_GATE:
514 clk = zynqmp_clk_register_gate(NULL, clk_out, clk_id,
515 parent_names, 1,
516 nodes[j].flag,
517 nodes[j].type_flag);
518 break;
519 default:
520 pr_err("%s() Unknown topology for %s\n",
521 __func__, clk_out);
522 break;
523 }
524 if (IS_ERR(clk))
525 pr_warn_once("%s() %s register fail with %ld\n",
526 __func__, clk_name, PTR_ERR(clk));
527
528 parent_names[0] = clk_out;
529 }
530 kfree(clk_out);
531 return clk;
532}
533
534
535
536
537
538
539
540static int zynqmp_register_clocks(struct device_node *np)
541{
542 int ret;
543 u32 i, total_parents = 0, type = 0;
544 const char *parent_names[MAX_PARENT];
545
546 for (i = 0; i < clock_max_idx; i++) {
547 char clk_name[MAX_NAME_LEN];
548
549
550 if (zynqmp_get_clock_name(i, clk_name))
551 continue;
552
553
554
555
556 ret = get_clock_type(i, &type);
557 if (ret || type != CLK_TYPE_OUTPUT)
558 continue;
559
560
561 if (get_parent_list(np, i, parent_names, &total_parents)) {
562 WARN_ONCE(1, "No parents found for %s\n",
563 clock[i].clk_name);
564 continue;
565 }
566
567 zynqmp_clks[i] = zynqmp_register_clk_topology(i, clk_name,
568 total_parents,
569 parent_names);
570
571
572 if (clock[i].init_enable)
573 clk_prepare_enable(zynqmp_clks[i]);
574 }
575
576 for (i = 0; i < clock_max_idx; i++) {
577 if (IS_ERR(zynqmp_clks[i])) {
578 pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n",
579 clock[i].clk_name, PTR_ERR(zynqmp_clks[i]));
580 WARN_ON(1);
581 }
582 }
583 return 0;
584}
585
586
587
588
589static void zynqmp_get_clock_info(void)
590{
591 int i, ret;
592 u32 attr, type = 0;
593
594 memset(clock, 0, sizeof(clock));
595 for (i = 0; i < MAX_CLOCK; i++) {
596 zynqmp_pm_clock_get_name(i, clock[i].clk_name);
597 if (!strncmp(clock[i].clk_name, END_OF_CLK_NAME,
598 MAX_NAME_LEN)) {
599 clock_max_idx = i;
600 break;
601 } else if (!strncmp(clock[i].clk_name, RESERVED_CLK_NAME,
602 MAX_NAME_LEN)) {
603 continue;
604 }
605
606 ret = zynqmp_pm_clock_get_attributes(i, &attr);
607 if (ret)
608 continue;
609
610 clock[i].valid = attr & CLK_VALID_MASK;
611 clock[i].init_enable = !!(attr & CLK_INIT_ENABLE_MASK);
612 clock[i].type = attr >> CLK_TYPE_SHIFT ? CLK_TYPE_EXTERNAL :
613 CLK_TYPE_OUTPUT;
614 }
615
616
617 for (i = 0; i < clock_max_idx; i++) {
618 ret = get_clock_type(i, &type);
619 if (ret || type != CLK_TYPE_OUTPUT)
620 continue;
621
622 ret = clock_get_topology(i, clock[i].node, &clock[i].num_nodes);
623 if (ret)
624 continue;
625
626 ret = clock_get_parents(i, clock[i].parent,
627 &clock[i].num_parents);
628 if (ret)
629 continue;
630 }
631}
632
633
634
635
636
637static void __init zynqmp_clk_setup(struct device_node *np)
638{
639 int idx;
640
641 idx = of_property_match_string(np, "clock-names", "pss_ref_clk");
642 if (idx < 0) {
643 pr_err("pss_ref_clk not provided\n");
644 return;
645 }
646 idx = of_property_match_string(np, "clock-names", "video_clk");
647 if (idx < 0) {
648 pr_err("video_clk not provided\n");
649 return;
650 }
651 idx = of_property_match_string(np, "clock-names", "pss_alt_ref_clk");
652 if (idx < 0) {
653 pr_err("pss_alt_ref_clk not provided\n");
654 return;
655 }
656 idx = of_property_match_string(np, "clock-names", "aux_ref_clk");
657 if (idx < 0) {
658 pr_err("aux_ref_clk not provided\n");
659 return;
660 }
661 idx = of_property_match_string(np, "clock-names", "gt_crx_ref_clk");
662 if (idx < 0) {
663 pr_err("aux_ref_clk not provided\n");
664 return;
665 }
666
667 zynqmp_get_clock_info();
668 zynqmp_register_clocks(np);
669
670 zynqmp_clk_data.clks = zynqmp_clks;
671 zynqmp_clk_data.clk_num = clock_max_idx;
672 of_clk_add_provider(np, of_clk_src_onecell_get, &zynqmp_clk_data);
673}
674
675
676
677
678
679
680static int __init zynqmp_clock_init(void)
681{
682 struct device_node *np;
683
684 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
685 if (!np)
686 return 0;
687 of_node_put(np);
688
689 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp-clkc");
690 if (np)
691 panic("%s: %s binding is deprecated, please use new DT binding\n",
692 __func__, np->name);
693
694 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp-clk");
695 if (!np) {
696 pr_err("%s: clk node not found\n", __func__);
697 of_node_put(np);
698 return 0;
699 }
700
701 eemi_ops = zynqmp_pm_get_eemi_ops();
702 if (!eemi_ops || !eemi_ops->query_data) {
703 pr_err("%s: clk data not found\n", __func__);
704 of_node_put(np);
705 return 0;
706 }
707
708 zynqmp_clk_setup(np);
709
710 return 0;
711}
712arch_initcall(zynqmp_clock_init);
713