1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2024, Microchip
4 */
5
6 #include <assert.h>
7 #include <dt-bindings/clock/at91.h>
8 #include <io.h>
9 #include <kernel/boot.h>
10 #include <kernel/dt.h>
11 #include <kernel/panic.h>
12 #include <libfdt.h>
13 #include <matrix.h>
14 #include <sama7g5.h>
15 #include <stdint.h>
16 #include <util.h>
17 #include "at91_clk.h"
18
19 #define CLK_IS_CRITICAL 0
20
21 /* PLL clocks identifiers */
22 enum pll_ids {
23 PLL_ID_CPU,
24 PLL_ID_SYS,
25 PLL_ID_DDR,
26 PLL_ID_IMG,
27 PLL_ID_BAUD,
28 PLL_ID_AUDIO,
29 PLL_ID_ETH,
30 PLL_ID_MAX,
31 };
32
33 /* PLL type identifiers */
34 enum pll_type {
35 PLL_TYPE_FRAC,
36 PLL_TYPE_DIV,
37 PLL_TYPE_CNT,
38 };
39
40 /* Layout for fractional PLLs */
41 static const struct clk_pll_layout pll_layout_frac = {
42 .mul_mask = GENMASK_32(31, 24),
43 .frac_mask = GENMASK_32(21, 0),
44 .mul_shift = 24,
45 .frac_shift = 0,
46 };
47
48 /* Layout for DIVPMC dividers */
49 static const struct clk_pll_layout pll_layout_divpmc = {
50 .div_mask = GENMASK_32(7, 0),
51 .endiv_mask = BIT(29),
52 .div_shift = 0,
53 .endiv_shift = 29,
54 };
55
56 /* Layout for DIVIO dividers */
57 static const struct clk_pll_layout pll_layout_divio = {
58 .div_mask = GENMASK_32(19, 12),
59 .endiv_mask = BIT(30),
60 .div_shift = 12,
61 .endiv_shift = 30,
62 };
63
64 /*
65 * CPU PLL output range
66 * Notice: The upper limit has been setup to 1000000002 due to hardware
67 * block which cannot output exactly 1GHz.
68 */
69 static const struct clk_range cpu_pll_output[] = {
70 { .min = 2343750, .max = 1000000002 },
71 };
72
73 /* PLL output range */
74 static const struct clk_range pll_output[] = {
75 { .min = 2343750, .max = 1200000000 },
76 };
77
78 /* CPU PLL characteristics */
79 static const struct clk_pll_charac cpu_pll_characteristics = {
80 .input = { .min = 12000000, .max = 50000000 },
81 .num_output = ARRAY_SIZE(cpu_pll_output),
82 .output = cpu_pll_output,
83 };
84
85 /* PLL characteristics */
86 static const struct clk_pll_charac pll_characteristics = {
87 .input = { .min = 12000000, .max = 50000000 },
88 .num_output = ARRAY_SIZE(pll_output),
89 .output = pll_output,
90 };
91
92 /* PLL clocks description */
93 struct sama7g5_pll {
94 const char *name;
95 const char *parent;
96 const struct clk_pll_layout *layout;
97 const struct clk_pll_charac *charac;
98 unsigned long flags;
99 uint8_t type;
100 uint8_t eid; /* export index in sama7g5->chws[] array */
101 uint8_t safe_div; /* intermediate divider need to be set on
102 * PRE_RATE_CHANGE notification
103 */
104 };
105
106 static const struct sama7g5_pll sama7g5_plls[][PLL_ID_MAX] = {
107 [PLL_ID_CPU] = {
108 {
109 .name = "cpupll_fracck",
110 .parent = "mainck",
111 .layout = &pll_layout_frac,
112 .charac = &cpu_pll_characteristics,
113 .type = PLL_TYPE_FRAC,
114 /*
115 * This feeds cpupll_divpmcck which feeds CPU. It
116 * should not be disabled.
117 */
118 .flags = CLK_IS_CRITICAL,
119 },
120 {
121 .name = "cpupll_divpmcck",
122 .parent = "cpupll_fracck",
123 .layout = &pll_layout_divpmc,
124 .charac = &cpu_pll_characteristics,
125 .type = PLL_TYPE_DIV,
126 /* This feeds CPU. It should not be disabled. */
127 .flags = CLK_IS_CRITICAL,
128 .eid = PMC_CPUPLL,
129 /*
130 * Safe div=15 should be safe even for switching b/w
131 * 1GHz and 90MHz (frac pll might go up to 1.2GHz).
132 */
133 .safe_div = 15,
134 },
135 },
136
137 [PLL_ID_SYS] = {
138 {
139 .name = "syspll_fracck",
140 .parent = "mainck",
141 .layout = &pll_layout_frac,
142 .charac = &pll_characteristics,
143 .type = PLL_TYPE_FRAC,
144 /*
145 * This feeds syspll_divpmcck which may feed critical
146 * parts of the systems like timers. Therefore it
147 * should not be disabled.
148 */
149 .flags = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
150 },
151 {
152 .name = "syspll_divpmcck",
153 .parent = "syspll_fracck",
154 .layout = &pll_layout_divpmc,
155 .charac = &pll_characteristics,
156 .type = PLL_TYPE_DIV,
157 /*
158 * This may feed critical parts of the systems like
159 * timers. Therefore it should not be disabled.
160 */
161 .flags = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
162 .eid = PMC_SYSPLL,
163 },
164 },
165
166 [PLL_ID_DDR] = {
167 {
168 .name = "ddrpll_fracck",
169 .parent = "mainck",
170 .layout = &pll_layout_frac,
171 .charac = &pll_characteristics,
172 .type = PLL_TYPE_FRAC,
173 /*
174 * This feeds ddrpll_divpmcck which feeds DDR. It
175 * should not be disabled.
176 */
177 .flags = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
178 },
179 {
180 .name = "ddrpll_divpmcck",
181 .parent = "ddrpll_fracck",
182 .layout = &pll_layout_divpmc,
183 .charac = &pll_characteristics,
184 .type = PLL_TYPE_DIV,
185 /* This feeds DDR. It should not be disabled. */
186 .flags = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
187 .eid = PMC_DDRPLL,
188 },
189 },
190
191 [PLL_ID_IMG] = {
192 {
193 .name = "imgpll_fracck",
194 .parent = "mainck",
195 .layout = &pll_layout_frac,
196 .charac = &pll_characteristics,
197 .type = PLL_TYPE_FRAC,
198 .flags = CLK_SET_RATE_GATE,
199 },
200 {
201 .name = "imgpll_divpmcck",
202 .parent = "imgpll_fracck",
203 .layout = &pll_layout_divpmc,
204 .charac = &pll_characteristics,
205 .type = PLL_TYPE_DIV,
206 .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,
207 .eid = PMC_IMGPLL,
208 },
209 },
210
211 [PLL_ID_BAUD] = {
212 {
213 .name = "baudpll_fracck",
214 .parent = "mainck",
215 .layout = &pll_layout_frac,
216 .charac = &pll_characteristics,
217 .type = PLL_TYPE_FRAC,
218 .flags = CLK_SET_RATE_GATE,
219 },
220 {
221 .name = "baudpll_divpmcck",
222 .parent = "baudpll_fracck",
223 .layout = &pll_layout_divpmc,
224 .charac = &pll_characteristics,
225 .type = PLL_TYPE_DIV,
226 .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,
227 .eid = PMC_BAUDPLL,
228 },
229 },
230
231 [PLL_ID_AUDIO] = {
232 {
233 .name = "audiopll_fracck",
234 .parent = "main_xtal",
235 .layout = &pll_layout_frac,
236 .charac = &pll_characteristics,
237 .type = PLL_TYPE_FRAC,
238 .flags = CLK_SET_RATE_GATE,
239 },
240 {
241 .name = "audiopll_divck",
242 .parent = "audiopll_fracck",
243 .layout = &pll_layout_divpmc,
244 .charac = &pll_characteristics,
245 .type = PLL_TYPE_DIV,
246 .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,
247 .eid = PMC_AUDIOPMCPLL,
248 },
249 {
250 .name = "audiopll_diviock",
251 .parent = "audiopll_fracck",
252 .layout = &pll_layout_divio,
253 .charac = &pll_characteristics,
254 .type = PLL_TYPE_DIV,
255 .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,
256 .eid = PMC_AUDIOIOPLL,
257 },
258 },
259
260 [PLL_ID_ETH] = {
261 {
262 .name = "ethpll_fracck",
263 .parent = "main_xtal",
264 .layout = &pll_layout_frac,
265 .charac = &pll_characteristics,
266 .type = PLL_TYPE_FRAC,
267 .flags = CLK_SET_RATE_GATE,
268 },
269 {
270 .name = "ethpll_divpmcck",
271 .parent = "ethpll_fracck",
272 .layout = &pll_layout_divpmc,
273 .charac = &pll_characteristics,
274 .type = PLL_TYPE_DIV,
275 .flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,
276 .eid = PMC_ETHPLL,
277 },
278 },
279 };
280
281 /*
282 * Master clock (MCK[1..4]) description
283 * @eparents: extra parents names array
284 * @eparents_chg_id: index in parents array that specifies the changeable
285 * parent
286 * @eparents_count: extra parents count
287 * @eparents_mux_table: mux table for extra parents
288 * @id: clock id
289 * @eid: export index in sama7g5->chws[] array
290 */
291 struct sama7g5_mck {
292 const char *name;
293 const char *eparents[4];
294 int eparents_chg_id;
295 uint8_t eparents_count;
296 uint8_t eparents_mux_table[4];
297 uint8_t id;
298 uint8_t eid;
299 };
300
301 static const struct sama7g5_mck sama7g5_mckx[] = {
302 {
303 .name = "mck1",
304 .id = 1,
305 .eparents = { "syspll_divpmcck", },
306 .eparents_mux_table = { 5, },
307 .eparents_count = 1,
308 .eparents_chg_id = INT_MIN,
309 .eid = PMC_MCK1,
310 },
311 {
312 .name = "mck2",
313 .id = 2,
314 .eparents = { "ddrpll_divpmcck", },
315 .eparents_mux_table = { 6, },
316 .eparents_count = 1,
317 .eparents_chg_id = INT_MIN,
318 },
319 {
320 .name = "mck3",
321 .id = 3,
322 .eparents = { "syspll_divpmcck",
323 "ddrpll_divpmcck",
324 "imgpll_divpmcck", },
325 .eparents_mux_table = { 5, 6, 7, },
326 .eparents_count = 3,
327 .eparents_chg_id = 5,
328 },
329 {
330 .name = "mck4",
331 .id = 4,
332 .eparents = { "syspll_divpmcck", },
333 .eparents_mux_table = { 5, },
334 .eparents_count = 1,
335 .eparents_chg_id = INT_MIN,
336 },
337 };
338
339 /* System clock description */
340 static const struct {
341 const char *name;
342 const char *parent;
343 uint8_t id;
344 } sama7g5_systemck[] = {
345 { .name = "pck0", .parent = "prog0", .id = 8, },
346 { .name = "pck1", .parent = "prog1", .id = 9, },
347 { .name = "pck2", .parent = "prog2", .id = 10, },
348 { .name = "pck3", .parent = "prog3", .id = 11, },
349 { .name = "pck4", .parent = "prog4", .id = 12, },
350 { .name = "pck5", .parent = "prog5", .id = 13, },
351 { .name = "pck6", .parent = "prog6", .id = 14, },
352 { .name = "pck7", .parent = "prog7", .id = 15, },
353 };
354
355 /* Peripheral clock description */
356 static const struct {
357 const char *name;
358 const char *parent;
359 struct clk_range output;
360 uint8_t id;
361 } peri_clks[] = {
362 {
363 .name = "pioA_clk",
364 .parent = "mck0",
365 .id = 11,
366 },
367 {
368 .name = "securam_clk",
369 .parent = "mck0",
370 .id = 18,
371 },
372 {
373 .name = "sfr_clk",
374 .parent = "mck1",
375 .id = 19,
376 },
377 {
378 .name = "hsmc_clk",
379 .parent = "mck1",
380 .id = 21,
381 },
382 {
383 .name = "xdmac0_clk",
384 .parent = "mck1",
385 .id = 22,
386 },
387 {
388 .name = "xdmac1_clk",
389 .parent = "mck1",
390 .id = 23,
391 },
392 {
393 .name = "xdmac2_clk",
394 .parent = "mck1",
395 .id = 24,
396 },
397 {
398 .name = "acc_clk",
399 .parent = "mck1",
400 .id = 25,
401 },
402 {
403 .name = "aes_clk",
404 .parent = "mck1",
405 .id = 27,
406 },
407 {
408 .name = "tzaesbasc_clk",
409 .parent = "mck1",
410 .id = 28,
411 },
412 {
413 .name = "asrc_clk",
414 .parent = "mck1",
415 .id = 30,
416 .output = { .max = 200000000, },
417 },
418 {
419 .name = "cpkcc_clk",
420 .parent = "mck0",
421 .id = 32,
422 },
423 {
424 .name = "csi_clk",
425 .parent = "mck3",
426 .id = 33,
427 .output = { .max = 266000000, },
428 },
429 {
430 .name = "csi2dc_clk",
431 .parent = "mck3",
432 .id = 34,
433 .output = { .max = 266000000, },
434 },
435 {
436 .name = "eic_clk",
437 .parent = "mck1",
438 .id = 37,
439 },
440 {
441 .name = "flex0_clk",
442 .parent = "mck1",
443 .id = 38,
444 },
445 {
446 .name = "flex1_clk",
447 .parent = "mck1",
448 .id = 39,
449 },
450 {
451 .name = "flex2_clk",
452 .parent = "mck1",
453 .id = 40,
454 },
455 {
456 .name = "flex3_clk",
457 .parent = "mck1",
458 .id = 41,
459 },
460 {
461 .name = "flex4_clk",
462 .parent = "mck1",
463 .id = 42,
464 },
465 {
466 .name = "flex5_clk",
467 .parent = "mck1",
468 .id = 43,
469 },
470 {
471 .name = "flex6_clk",
472 .parent = "mck1",
473 .id = 44,
474 },
475 {
476 .name = "flex7_clk",
477 .parent = "mck1",
478 .id = 45,
479 },
480 {
481 .name = "flex8_clk",
482 .parent = "mck1",
483 .id = 46,
484 },
485 {
486 .name = "flex9_clk",
487 .parent = "mck1",
488 .id = 47,
489 },
490 {
491 .name = "flex10_clk",
492 .parent = "mck1",
493 .id = 48,
494 },
495 {
496 .name = "flex11_clk",
497 .parent = "mck1",
498 .id = 49,
499 },
500 {
501 .name = "gmac0_clk",
502 .parent = "mck1",
503 .id = 51,
504 },
505 {
506 .name = "gmac1_clk",
507 .parent = "mck1",
508 .id = 52,
509 },
510 {
511 .name = "icm_clk",
512 .parent = "mck1",
513 .id = 55,
514 },
515 {
516 .name = "isc_clk",
517 .parent = "mck3",
518 .id = 56,
519 .output = { .max = 266000000, },
520 },
521 {
522 .name = "i2smcc0_clk",
523 .parent = "mck1",
524 .id = 57,
525 .output = { .max = 200000000, },
526 },
527 {
528 .name = "i2smcc1_clk",
529 .parent = "mck1",
530 .id = 58,
531 .output = { .max = 200000000, },
532 },
533 {
534 .name = "matrix_clk",
535 .parent = "mck1",
536 .id = 60, },
537 {
538 .name = "mcan0_clk",
539 .parent = "mck1",
540 .id = 61,
541 .output = { .max = 200000000, },
542 },
543 {
544 .name = "mcan1_clk",
545 .parent = "mck1",
546 .id = 62,
547 .output = { .max = 200000000, },
548 },
549 {
550 .name = "mcan2_clk",
551 .parent = "mck1",
552 .id = 63,
553 .output = { .max = 200000000, },
554 },
555 {
556 .name = "mcan3_clk",
557 .parent = "mck1",
558 .id = 64,
559 .output = { .max = 200000000, },
560 },
561 {
562 .name = "mcan4_clk",
563 .parent = "mck1",
564 .id = 65,
565 .output = { .max = 200000000, },
566 },
567 {
568 .name = "mcan5_clk",
569 .parent = "mck1",
570 .id = 66,
571 .output = { .max = 200000000, },
572 },
573 {
574 .name = "pdmc0_clk",
575 .parent = "mck1",
576 .id = 68,
577 .output = { .max = 200000000, },
578 },
579 {
580 .name = "pdmc1_clk",
581 .parent = "mck1",
582 .id = 69,
583 .output = { .max = 200000000, },
584 },
585 {
586 .name = "pit64b0_clk",
587 .parent = "mck1",
588 .id = 70,
589 },
590 {
591 .name = "pit64b1_clk",
592 .parent = "mck1",
593 .id = 71,
594 },
595 {
596 .name = "pit64b2_clk",
597 .parent = "mck1",
598 .id = 72,
599 },
600 {
601 .name = "pit64b3_clk",
602 .parent = "mck1",
603 .id = 73,
604 },
605 {
606 .name = "pit64b4_clk",
607 .parent = "mck1",
608 .id = 74,
609 },
610 {
611 .name = "pit64b5_clk",
612 .parent = "mck1",
613 .id = 75,
614 },
615 {
616 .name = "pwm_clk",
617 .parent = "mck1",
618 .id = 77,
619 },
620 {
621 .name = "qspi0_clk",
622 .parent = "mck1",
623 .id = 78,
624 },
625 {
626 .name = "qspi1_clk",
627 .parent = "mck1",
628 .id = 79,
629 },
630 {
631 .name = "sdmmc0_clk",
632 .parent = "mck1",
633 .id = 80,
634 },
635 {
636 .name = "sdmmc1_clk",
637 .parent = "mck1",
638 .id = 81,
639 },
640 {
641 .name = "sdmmc2_clk",
642 .parent = "mck1",
643 .id = 82,
644 },
645 {
646 .name = "sha_clk",
647 .parent = "mck1",
648 .id = 83,
649 },
650 {
651 .name = "spdifrx_clk",
652 .parent = "mck1",
653 .id = 84,
654 .output = { .max = 200000000, },
655 },
656 {
657 .name = "spdiftx_clk",
658 .parent = "mck1",
659 .id = 85,
660 .output = { .max = 200000000, },
661 },
662 {
663 .name = "ssc0_clk",
664 .parent = "mck1",
665 .id = 86,
666 .output = { .max = 200000000, },
667 },
668 {
669 .name = "ssc1_clk",
670 .parent = "mck1",
671 .id = 87,
672 .output = { .max = 200000000, },
673 },
674 {
675 .name = "tcb0_ch0_clk",
676 .parent = "mck1",
677 .id = 88,
678 .output = { .max = 200000000, },
679 },
680 {
681 .name = "tcb0_ch1_clk",
682 .parent = "mck1",
683 .id = 89,
684 .output = { .max = 200000000, },
685 },
686 {
687 .name = "tcb0_ch2_clk",
688 .parent = "mck1",
689 .id = 90,
690 .output = { .max = 200000000, },
691 },
692 {
693 .name = "tcb1_ch0_clk",
694 .parent = "mck1",
695 .id = 91,
696 .output = { .max = 200000000, },
697 },
698 {
699 .name = "tcb1_ch1_clk",
700 .parent = "mck1",
701 .id = 92,
702 .output = { .max = 200000000, },
703 },
704 {
705 .name = "tcb1_ch2_clk",
706 .parent = "mck1",
707 .id = 93,
708 .output = { .max = 200000000, },
709 },
710 {
711 .name = "tcpca_clk",
712 .parent = "mck1",
713 .id = 94,
714 },
715 {
716 .name = "tcpcb_clk",
717 .parent = "mck1",
718 .id = 95,
719 },
720 {
721 .name = "tdes_clk",
722 .parent = "mck1",
723 .id = 96,
724 },
725 {
726 .name = "trng_clk",
727 .parent = "mck1",
728 .id = 97,
729 },
730 {
731 .name = "udphsa_clk",
732 .parent = "mck1",
733 .id = 104,
734 },
735 {
736 .name = "udphsb_clk",
737 .parent = "mck1",
738 .id = 105,
739 },
740 {
741 .name = "uhphs_clk",
742 .parent = "mck1",
743 .id = 106,
744 },
745 };
746
747 /* UTMI clock description */
748 static struct {
749 const char *name;
750 const char *parent;
751 uint8_t id;
752 } sama7_utmick[] = {
753 { .name = "utmi1ck", .parent = "utmick", .id = 0, },
754 { .name = "utmi2ck", .parent = "utmi1ck", .id = 1, },
755 { .name = "utmi3ck", .parent = "utmi1ck", .id = 2, },
756 };
757
758 /* Generic clock description */
759 struct sama7g5_gck {
760 const char *name;
761 const char *parents[8];
762 const char parents_mux_table[8];
763 struct clk_range output;
764 int parents_chg_id; /* id in parent array of changeable PLL parent */
765 uint8_t parents_count;
766 uint8_t id;
767 };
768
769 static const struct sama7g5_gck sama7g5_gcks[] = {
770 {
771 .name = "adc_gclk",
772 .id = 26,
773 .output = { .max = 100000000, },
774 .parents = { "syspll_divpmcck",
775 "imgpll_divpmcck",
776 "audiopll_divck", },
777 .parents_mux_table = { 5, 7, 9, },
778 .parents_count = 3,
779 .parents_chg_id = INT_MIN,
780 },
781 {
782 .name = "asrc_gclk",
783 .id = 30,
784 .output = { .max = 200000000 },
785 .parents = { "audiopll_divck", },
786 .parents_mux_table = { 9, },
787 .parents_count = 1,
788 .parents_chg_id = INT_MIN,
789 },
790 {
791 .name = "csi_gclk",
792 .id = 33,
793 .output = { .max = 27000000 },
794 .parents = { "ddrpll_divpmcck", "imgpll_divpmcck", },
795 .parents_mux_table = { 6, 7, },
796 .parents_count = 2,
797 .parents_chg_id = INT_MIN,
798 },
799 {
800 .name = "flex0_gclk",
801 .id = 38,
802 .output = { .max = 200000000 },
803 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
804 .parents_mux_table = { 5, 8, },
805 .parents_count = 2,
806 .parents_chg_id = INT_MIN,
807 },
808 {
809 .name = "flex1_gclk",
810 .id = 39,
811 .output = { .max = 200000000 },
812 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
813 .parents_mux_table = { 5, 8, },
814 .parents_count = 2,
815 .parents_chg_id = INT_MIN,
816 },
817 {
818 .name = "flex2_gclk",
819 .id = 40,
820 .output = { .max = 200000000 },
821 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
822 .parents_mux_table = { 5, 8, },
823 .parents_count = 2,
824 .parents_chg_id = INT_MIN,
825 },
826 {
827 .name = "flex3_gclk",
828 .id = 41,
829 .output = { .max = 200000000 },
830 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
831 .parents_mux_table = { 5, 8, },
832 .parents_count = 2,
833 .parents_chg_id = INT_MIN,
834 },
835 {
836 .name = "flex4_gclk",
837 .id = 42,
838 .output = { .max = 200000000 },
839 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
840 .parents_mux_table = { 5, 8, },
841 .parents_count = 2,
842 .parents_chg_id = INT_MIN,
843 },
844 {
845 .name = "flex5_gclk",
846 .id = 43,
847 .output = { .max = 200000000 },
848 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
849 .parents_mux_table = { 5, 8, },
850 .parents_count = 2,
851 .parents_chg_id = INT_MIN,
852 },
853 {
854 .name = "flex6_gclk",
855 .id = 44,
856 .output = { .max = 200000000 },
857 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
858 .parents_mux_table = { 5, 8, },
859 .parents_count = 2,
860 .parents_chg_id = INT_MIN,
861 },
862 {
863 .name = "flex7_gclk",
864 .id = 45,
865 .output = { .max = 200000000 },
866 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
867 .parents_mux_table = { 5, 8, },
868 .parents_count = 2,
869 .parents_chg_id = INT_MIN,
870 },
871 {
872 .name = "flex8_gclk",
873 .id = 46,
874 .output = { .max = 200000000 },
875 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
876 .parents_mux_table = { 5, 8, },
877 .parents_count = 2,
878 .parents_chg_id = INT_MIN,
879 },
880 {
881 .name = "flex9_gclk",
882 .id = 47,
883 .output = { .max = 200000000 },
884 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
885 .parents_mux_table = { 5, 8, },
886 .parents_count = 2,
887 .parents_chg_id = INT_MIN,
888 },
889 {
890 .name = "flex10_gclk",
891 .id = 48,
892 .output = { .max = 200000000 },
893 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
894 .parents_mux_table = { 5, 8, },
895 .parents_count = 2,
896 .parents_chg_id = INT_MIN,
897 },
898 {
899 .name = "flex11_gclk",
900 .id = 49,
901 .output = { .max = 200000000 },
902 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
903 .parents_mux_table = { 5, 8, },
904 .parents_count = 2,
905 .parents_chg_id = INT_MIN,
906 },
907 {
908 .name = "gmac0_gclk",
909 .id = 51,
910 .output = { .max = 125000000 },
911 .parents = { "ethpll_divpmcck", },
912 .parents_mux_table = { 10, },
913 .parents_count = 1,
914 .parents_chg_id = 3,
915 },
916 {
917 .name = "gmac1_gclk",
918 .id = 52,
919 .output = { .max = 50000000 },
920 .parents = { "ethpll_divpmcck", },
921 .parents_mux_table = { 10, },
922 .parents_count = 1,
923 .parents_chg_id = INT_MIN,
924 },
925 {
926 .name = "gmac0_tsu_gclk",
927 .id = 53,
928 .output = { .max = 300000000 },
929 .parents = { "audiopll_divck", "ethpll_divpmcck", },
930 .parents_mux_table = { 9, 10, },
931 .parents_count = 2,
932 .parents_chg_id = INT_MIN,
933 },
934 {
935 .name = "gmac1_tsu_gclk",
936 .id = 54,
937 .output = { .max = 300000000 },
938 .parents = { "audiopll_divck", "ethpll_divpmcck", },
939 .parents_mux_table = { 9, 10, },
940 .parents_count = 2,
941 .parents_chg_id = INT_MIN,
942 },
943 {
944 .name = "i2smcc0_gclk",
945 .id = 57,
946 .output = { .max = 100000000 },
947 .parents = { "syspll_divpmcck", "audiopll_divck", },
948 .parents_mux_table = { 5, 9, },
949 .parents_count = 2,
950 .parents_chg_id = INT_MIN,
951 },
952 {
953 .name = "i2smcc1_gclk",
954 .id = 58,
955 .output = { .max = 100000000 },
956 .parents = { "syspll_divpmcck", "audiopll_divck", },
957 .parents_mux_table = { 5, 9, },
958 .parents_count = 2,
959 .parents_chg_id = INT_MIN,
960 },
961 {
962 .name = "mcan0_gclk",
963 .id = 61,
964 .output = { .max = 200000000 },
965 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
966 .parents_mux_table = { 5, 8, },
967 .parents_count = 2,
968 .parents_chg_id = INT_MIN,
969 },
970 {
971 .name = "mcan1_gclk",
972 .id = 62,
973 .output = { .max = 200000000 },
974 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
975 .parents_mux_table = { 5, 8, },
976 .parents_count = 2,
977 .parents_chg_id = INT_MIN,
978 },
979 {
980 .name = "mcan2_gclk",
981 .id = 63,
982 .output = { .max = 200000000 },
983 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
984 .parents_mux_table = { 5, 8, },
985 .parents_count = 2,
986 .parents_chg_id = INT_MIN,
987 },
988 {
989 .name = "mcan3_gclk",
990 .id = 64,
991 .output = { .max = 200000000 },
992 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
993 .parents_mux_table = { 5, 8, },
994 .parents_count = 2,
995 .parents_chg_id = INT_MIN,
996 },
997 {
998 .name = "mcan4_gclk",
999 .id = 65,
1000 .output = { .max = 200000000 },
1001 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1002 .parents_mux_table = { 5, 8, },
1003 .parents_count = 2,
1004 .parents_chg_id = INT_MIN,
1005 },
1006 {
1007 .name = "mcan5_gclk",
1008 .id = 66,
1009 .output = { .max = 200000000 },
1010 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1011 .parents_mux_table = { 5, 8, },
1012 .parents_count = 2,
1013 .parents_chg_id = INT_MIN,
1014 },
1015 {
1016 .name = "pdmc0_gclk",
1017 .id = 68,
1018 .output = { .max = 50000000 },
1019 .parents = { "syspll_divpmcck", "audiopll_divck", },
1020 .parents_mux_table = { 5, 9, },
1021 .parents_count = 2,
1022 .parents_chg_id = INT_MIN,
1023 },
1024 {
1025 .name = "pdmc1_gclk",
1026 .id = 69,
1027 .output = { .max = 50000000, },
1028 .parents = { "syspll_divpmcck", "audiopll_divck", },
1029 .parents_mux_table = { 5, 9, },
1030 .parents_count = 2,
1031 .parents_chg_id = INT_MIN,
1032 },
1033 {
1034 .name = "pit64b0_gclk",
1035 .id = 70,
1036 .output = { .max = 200000000 },
1037 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1038 "baudpll_divpmcck", "audiopll_divck",
1039 "ethpll_divpmcck", },
1040 .parents_mux_table = { 5, 7, 8, 9, 10, },
1041 .parents_count = 5,
1042 .parents_chg_id = INT_MIN,
1043 },
1044 {
1045 .name = "pit64b1_gclk",
1046 .id = 71,
1047 .output = { .max = 200000000 },
1048 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1049 "baudpll_divpmcck", "audiopll_divck",
1050 "ethpll_divpmcck", },
1051 .parents_mux_table = { 5, 7, 8, 9, 10, },
1052 .parents_count = 5,
1053 .parents_chg_id = INT_MIN,
1054 },
1055 {
1056 .name = "pit64b2_gclk",
1057 .id = 72,
1058 .output = { .max = 200000000 },
1059 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1060 "baudpll_divpmcck", "audiopll_divck",
1061 "ethpll_divpmcck", },
1062 .parents_mux_table = { 5, 7, 8, 9, 10, },
1063 .parents_count = 5,
1064 .parents_chg_id = INT_MIN,
1065 },
1066 {
1067 .name = "pit64b3_gclk",
1068 .id = 73,
1069 .output = { .max = 200000000 },
1070 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1071 "baudpll_divpmcck", "audiopll_divck",
1072 "ethpll_divpmcck", },
1073 .parents_mux_table = { 5, 7, 8, 9, 10, },
1074 .parents_count = 5,
1075 .parents_chg_id = INT_MIN,
1076 },
1077 {
1078 .name = "pit64b4_gclk",
1079 .id = 74,
1080 .output = { .max = 200000000 },
1081 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1082 "baudpll_divpmcck", "audiopll_divck",
1083 "ethpll_divpmcck", },
1084 .parents_mux_table = { 5, 7, 8, 9, 10, },
1085 .parents_count = 5,
1086 .parents_chg_id = INT_MIN,
1087 },
1088 {
1089 .name = "pit64b5_gclk",
1090 .id = 75,
1091 .output = { .max = 200000000 },
1092 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1093 "baudpll_divpmcck", "audiopll_divck",
1094 "ethpll_divpmcck", },
1095 .parents_mux_table = { 5, 7, 8, 9, 10, },
1096 .parents_count = 5,
1097 .parents_chg_id = INT_MIN,
1098 },
1099 {
1100 .name = "qspi0_gclk",
1101 .id = 78,
1102 .output = { .max = 200000000 },
1103 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1104 .parents_mux_table = { 5, 8, },
1105 .parents_count = 2,
1106 .parents_chg_id = INT_MIN,
1107 },
1108 {
1109 .name = "qspi1_gclk",
1110 .id = 79,
1111 .output = { .max = 200000000 },
1112 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1113 .parents_mux_table = { 5, 8, },
1114 .parents_count = 2,
1115 .parents_chg_id = INT_MIN,
1116 },
1117 {
1118 .name = "sdmmc0_gclk",
1119 .id = 80,
1120 .output = { .max = 208000000 },
1121 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1122 .parents_mux_table = { 5, 8, },
1123 .parents_count = 2,
1124 .parents_chg_id = 4,
1125 },
1126 {
1127 .name = "sdmmc1_gclk",
1128 .id = 81,
1129 .output = { .max = 208000000 },
1130 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1131 .parents_mux_table = { 5, 8, },
1132 .parents_count = 2,
1133 .parents_chg_id = 4,
1134 },
1135 {
1136 .name = "sdmmc2_gclk",
1137 .id = 82,
1138 .output = { .max = 208000000 },
1139 .parents = { "syspll_divpmcck", "baudpll_divpmcck", },
1140 .parents_mux_table = { 5, 8, },
1141 .parents_count = 2,
1142 .parents_chg_id = 4,
1143 },
1144 {
1145 .name = "spdifrx_gclk",
1146 .id = 84,
1147 .output = { .max = 150000000 },
1148 .parents = { "syspll_divpmcck", "audiopll_divck", },
1149 .parents_mux_table = { 5, 9, },
1150 .parents_count = 2,
1151 .parents_chg_id = INT_MIN,
1152 },
1153 {
1154 .name = "spdiftx_gclk",
1155 .id = 85,
1156 .output = { .max = 25000000 },
1157 .parents = { "syspll_divpmcck", "audiopll_divck", },
1158 .parents_mux_table = { 5, 9, },
1159 .parents_count = 2,
1160 .parents_chg_id = INT_MIN,
1161 },
1162 {
1163 .name = "tcb0_ch0_gclk",
1164 .id = 88,
1165 .output = { .max = 200000000 },
1166 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1167 "baudpll_divpmcck", "audiopll_divck",
1168 "ethpll_divpmcck", },
1169 .parents_mux_table = { 5, 7, 8, 9, 10, },
1170 .parents_count = 5,
1171 .parents_chg_id = INT_MIN,
1172 },
1173 {
1174 .name = "tcb1_ch0_gclk",
1175 .id = 91,
1176 .output = { .max = 200000000 },
1177 .parents = { "syspll_divpmcck", "imgpll_divpmcck",
1178 "baudpll_divpmcck", "audiopll_divck",
1179 "ethpll_divpmcck", },
1180 .parents_mux_table = { 5, 7, 8, 9, 10, },
1181 .parents_count = 5,
1182 .parents_chg_id = INT_MIN,
1183 },
1184 {
1185 .name = "tcpca_gclk",
1186 .id = 94,
1187 .output = { .max = 32768, },
1188 .parents_chg_id = INT_MIN,
1189 },
1190 {
1191 .name = "tcpcb_gclk",
1192 .id = 95,
1193 .output = { .max = 32768, },
1194 .parents_chg_id = INT_MIN,
1195 },
1196 };
1197
1198 /* MCK0 characteristics */
1199 static const struct clk_master_charac mck0_characteristics = {
1200 .output = { .min = 32768, .max = 200000000 },
1201 .divisors = { 1, 2, 4, 3, 5 },
1202 .have_div3_pres = 1,
1203 };
1204
1205 /* MCK0 layout */
1206 static const struct clk_master_layout mck0_layout = {
1207 .mask = 0x773,
1208 .pres_shift = 4,
1209 .offset = 0x28,
1210 };
1211
1212 /* Peripheral clock layout */
1213 static const struct clk_pcr_layout sama7g5_pcr_layout = {
1214 .offset = 0x88,
1215 .cmd = BIT(31),
1216 .div_mask = GENMASK_32(27, 20),
1217 .gckcss_mask = GENMASK_32(12, 8),
1218 .pid_mask = GENMASK_32(6, 0),
1219 };
1220
1221 static const struct clk_programmable_layout sama7g5_prog_layout = {
1222 .pres_mask = 0xff,
1223 .pres_shift = 8,
1224 .css_mask = GENMASK_32(4, 0),
1225 .have_slck_mck = 0,
1226 .is_pres_direct = 1,
1227 };
1228
1229 static const struct {
1230 const char *name;
1231 uint8_t id;
1232 } sama7g5_progck[] = {
1233 { .name = "prog0", .id = 0 },
1234 { .name = "prog1", .id = 1 },
1235 { .name = "prog2", .id = 2 },
1236 { .name = "prog3", .id = 3 },
1237 { .name = "prog4", .id = 4 },
1238 { .name = "prog5", .id = 5 },
1239 { .name = "prog6", .id = 6 },
1240 { .name = "prog7", .id = 7 },
1241 };
1242
1243 static struct pmc_data *sama7g5_pmc;
1244
at91_pmc_get_base(void)1245 vaddr_t at91_pmc_get_base(void)
1246 {
1247 assert(sama7g5_pmc);
1248
1249 return sama7g5_pmc->base;
1250 }
1251
at91_pmc_clk_get(unsigned int type,unsigned int idx,struct clk ** clk)1252 TEE_Result at91_pmc_clk_get(unsigned int type, unsigned int idx,
1253 struct clk **clk)
1254 {
1255 return pmc_clk_get(sama7g5_pmc, type, idx, clk);
1256 }
1257
pmc_setup_sama7g5(const void * fdt,int nodeoffset,const void * data __unused)1258 static TEE_Result pmc_setup_sama7g5(const void *fdt, int nodeoffset,
1259 const void *data __unused)
1260 {
1261 struct clk *pll_frac_clk[PLL_ID_MAX] = { };
1262 struct clk *pll_div_clk[PLL_ID_MAX] = { };
1263 TEE_Result res = TEE_ERROR_GENERIC;
1264 const uint32_t *fdt_prop = NULL;
1265 struct pmc_clk *pmc_clk = NULL;
1266 struct clk *parents[11] = { };
1267 struct clk *main_xtal_clk = NULL;
1268 struct clk *main_rc_osc = NULL;
1269 struct clk *main_osc = NULL;
1270 struct clk *mck0_clk = NULL;
1271 struct clk *main_clk = NULL;
1272 struct clk *md_slck = NULL;
1273 struct clk *td_slck = NULL;
1274 struct clk *parent = NULL;
1275 struct clk *clk = NULL;
1276 unsigned int i = 0;
1277 unsigned int j = 0;
1278 vaddr_t base = 0;
1279 size_t size = 0;
1280 int bypass = 0;
1281
1282 if (dt_map_dev(fdt, nodeoffset, &base, &size, DT_MAP_AUTO) < 0)
1283 panic();
1284
1285 if (fdt_get_status(fdt, nodeoffset) == DT_STATUS_OK_SEC)
1286 matrix_configure_periph_secure(ID_PMC);
1287
1288 res = clk_dt_get_by_name(fdt, nodeoffset, "md_slck", &md_slck);
1289 if (res)
1290 return res;
1291
1292 res = clk_dt_get_by_name(fdt, nodeoffset, "td_slck", &td_slck);
1293 if (res)
1294 return res;
1295
1296 res = clk_dt_get_by_name(fdt, nodeoffset, "main_xtal", &main_xtal_clk);
1297 if (res)
1298 return res;
1299
1300 sama7g5_pmc = pmc_data_allocate(PMC_SAMA7G5_CORE_CLK_COUNT,
1301 ARRAY_SIZE(sama7g5_systemck),
1302 ARRAY_SIZE(peri_clks),
1303 ARRAY_SIZE(sama7g5_gcks), 8);
1304 if (!sama7g5_pmc)
1305 panic();
1306
1307 sama7g5_pmc->base = base;
1308
1309 main_rc_osc = pmc_register_main_rc_osc(sama7g5_pmc, "main_rc_osc",
1310 12000000);
1311 if (!main_rc_osc)
1312 panic();
1313
1314 fdt_prop = fdt_getprop(fdt, nodeoffset, "atmel,osc-bypass", NULL);
1315 if (fdt_prop)
1316 bypass = fdt32_to_cpu(*fdt_prop);
1317
1318 main_osc = pmc_register_main_osc(sama7g5_pmc, "main_osc",
1319 main_xtal_clk, bypass);
1320 if (!main_osc)
1321 panic();
1322
1323 parents[0] = main_rc_osc;
1324 parents[1] = main_osc;
1325 main_clk = at91_clk_register_sam9x5_main(sama7g5_pmc, "mainck",
1326 parents, 2);
1327 if (!main_clk)
1328 panic();
1329 pmc_clk = &sama7g5_pmc->chws[PMC_MAIN];
1330 pmc_clk->clk = main_clk;
1331 pmc_clk->id = PMC_MAIN;
1332
1333 for (i = 0; i < PLL_ID_MAX; i++) {
1334 struct pmc_data *pmc = sama7g5_pmc;
1335 const struct sama7g5_pll *p = NULL;
1336
1337 for (j = 0; j < 3; j++) {
1338 p = &sama7g5_plls[i][j];
1339 if (!p->name)
1340 continue;
1341
1342 switch (p->type) {
1343 case PLL_TYPE_FRAC:
1344 if (!strcmp(p->parent, "mainck"))
1345 parent = main_clk;
1346 else if (!strcmp(p->parent, "main_xtal"))
1347 parent = main_xtal_clk;
1348 else
1349 parent = pmc_clk_get_by_name(pmc->chws,
1350 pmc->ncore,
1351 p->parent);
1352 assert(parent);
1353
1354 clk = sam9x60_clk_register_frac_pll(sama7g5_pmc,
1355 p->name,
1356 parent, i,
1357 p->charac,
1358 p->layout,
1359 p->flags);
1360 pll_frac_clk[i] = clk;
1361 break;
1362
1363 case PLL_TYPE_DIV:
1364 parent = clk;
1365 clk = sam9x60_clk_register_div_pll(sama7g5_pmc,
1366 p->name,
1367 parent, i,
1368 p->charac,
1369 p->layout,
1370 p->flags,
1371 p->safe_div);
1372 break;
1373
1374 default:
1375 continue;
1376 }
1377 if (!clk)
1378 panic();
1379
1380 if (p->eid) {
1381 sama7g5_pmc->chws[p->eid].clk = clk;
1382 sama7g5_pmc->chws[p->eid].id = p->eid;
1383 sam_set_clock_range(PMC_TYPE_CORE, p->eid,
1384 p->charac->output);
1385 }
1386 }
1387 p = &sama7g5_plls[i][PLL_TYPE_DIV];
1388 pll_div_clk[i] = sama7g5_pmc->chws[p->eid].clk;
1389 }
1390
1391 parents[0] = md_slck;
1392 parents[1] = main_clk;
1393 parents[2] = pll_div_clk[PLL_ID_CPU];
1394 parents[3] = pll_div_clk[PLL_ID_SYS];
1395 clk = at91_clk_register_master_pres(sama7g5_pmc, "fclk", 4,
1396 parents,
1397 &mck0_layout,
1398 &mck0_characteristics, INT_MIN);
1399 if (!clk)
1400 panic();
1401 pmc_clk = &sama7g5_pmc->chws[PMC_MCK_PRES];
1402 pmc_clk->clk = clk;
1403 pmc_clk->id = PMC_MCK_PRES;
1404
1405 mck0_clk = at91_clk_register_master_div(sama7g5_pmc, "mck0",
1406 clk,
1407 &mck0_layout,
1408 &mck0_characteristics);
1409 if (!mck0_clk)
1410 panic();
1411 pmc_clk = &sama7g5_pmc->chws[PMC_MCK];
1412 pmc_clk->clk = mck0_clk;
1413 pmc_clk->id = PMC_MCK;
1414 sam_set_clock_range(PMC_TYPE_SYSTEM, PMC_MCK,
1415 &mck0_characteristics.output);
1416
1417 parents[0] = md_slck;
1418 parents[1] = td_slck;
1419 parents[2] = main_clk;
1420 parents[3] = mck0_clk;
1421 for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) {
1422 const struct sama7g5_mck *mck = &sama7g5_mckx[i];
1423 uint8_t num_parents = 4 + mck->eparents_count;
1424 uint32_t *mux_table = calloc(num_parents, sizeof(*mux_table));
1425
1426 if (!mux_table)
1427 panic();
1428
1429 mux_table[0] = 0;
1430 mux_table[1] = 1;
1431 mux_table[2] = 2;
1432 mux_table[3] = 3;
1433 for (j = 0; j < mck->eparents_count; j++) {
1434 parents[4 + j] = pmc_clk_get_by_name(sama7g5_pmc->chws,
1435 sama7g5_pmc->ncore,
1436 mck->eparents[j]);
1437 assert(parents[4 + j]);
1438 mux_table[4 + j] = mck->eparents_mux_table[j];
1439 }
1440
1441 clk = at91_clk_sama7g5_register_master(sama7g5_pmc,
1442 mck->name,
1443 num_parents, parents,
1444 mux_table,
1445 mck->id,
1446 mck->eparents_chg_id);
1447 if (!clk)
1448 panic();
1449
1450 sama7g5_pmc->chws[PMC_MCK1 + i].clk = clk;
1451 }
1452
1453 clk = at91_clk_sama7g5_register_utmi(sama7g5_pmc, "utmick", main_clk);
1454 if (!clk)
1455 panic();
1456 sama7g5_pmc->chws[PMC_UTMI].clk = clk;
1457 sama7g5_pmc->chws[PMC_UTMI].id = PMC_UTMI;
1458
1459 for (i = 0; i < ARRAY_SIZE(sama7_utmick); i++) {
1460 if (strcmp("utmick", sama7_utmick[i].parent) == 0)
1461 parent = clk;
1462 else if (strcmp("utmi1ck", sama7_utmick[i].parent) == 0)
1463 parent = sama7g5_pmc->chws[PMC_UTMI1].clk;
1464 else
1465 panic();
1466 clk = sama7_utmi_clk_register(sama7_utmick[i].name, parent,
1467 sama7_utmick[i].id);
1468 if (!clk)
1469 panic();
1470
1471 pmc_clk = &sama7g5_pmc->chws[PMC_UTMI1 + i];
1472 pmc_clk->clk = clk;
1473 pmc_clk->id = PMC_UTMI1 + i;
1474 }
1475
1476 parents[0] = md_slck;
1477 parents[1] = td_slck;
1478 parents[2] = main_clk;
1479 parents[3] = pll_div_clk[PLL_ID_SYS];
1480 parents[4] = pll_div_clk[PLL_ID_DDR];
1481 parents[5] = pll_div_clk[PLL_ID_IMG];
1482 parents[6] = pll_div_clk[PLL_ID_BAUD];
1483 parents[7] = pll_div_clk[PLL_ID_AUDIO];
1484 parents[8] = pll_div_clk[PLL_ID_ETH];
1485 for (i = 0; i < ARRAY_SIZE(sama7g5_progck); i++) {
1486 clk = at91_clk_register_programmable(sama7g5_pmc,
1487 sama7g5_progck[i].name,
1488 parents, 9, i,
1489 &sama7g5_prog_layout);
1490 if (!clk)
1491 panic();
1492
1493 pmc_clk = &sama7g5_pmc->pchws[i];
1494 pmc_clk->clk = clk;
1495 pmc_clk->id = sama7g5_progck[i].id;
1496 }
1497
1498 for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
1499 clk = at91_clk_register_system(sama7g5_pmc,
1500 sama7g5_systemck[i].name,
1501 sama7g5_pmc->pchws[i].clk,
1502 sama7g5_systemck[i].id);
1503 if (!clk)
1504 panic();
1505
1506 pmc_clk = &sama7g5_pmc->shws[i];
1507 pmc_clk->clk = clk;
1508 pmc_clk->id = sama7g5_systemck[i].id;
1509 }
1510
1511 for (i = 0; i < ARRAY_SIZE(peri_clks); i++) {
1512 parent = pmc_clk_get_by_name(sama7g5_pmc->chws,
1513 sama7g5_pmc->ncore,
1514 peri_clks[i].parent);
1515 clk = at91_clk_register_sam9x5_periph(sama7g5_pmc,
1516 &sama7g5_pcr_layout,
1517 peri_clks[i].name,
1518 parent,
1519 peri_clks[i].id,
1520 &peri_clks[i].output);
1521 if (!clk)
1522 panic();
1523
1524 pmc_clk = &sama7g5_pmc->phws[i];
1525 pmc_clk->clk = clk;
1526 pmc_clk->id = peri_clks[i].id;
1527
1528 sam_set_clock_range(PMC_TYPE_PERIPHERAL, peri_clks[i].id,
1529 &peri_clks[i].output);
1530 }
1531
1532 parents[0] = md_slck;
1533 parents[1] = td_slck;
1534 parents[2] = main_clk;
1535 for (i = 0; i < ARRAY_SIZE(sama7g5_gcks); i++) {
1536 const struct sama7g5_gck *gck = sama7g5_gcks + i;
1537 uint8_t num_parents = 3 + gck->parents_count;
1538 uint32_t *mux_table = calloc(num_parents, sizeof(*mux_table));
1539
1540 if (!mux_table)
1541 panic();
1542
1543 mux_table[0] = 0;
1544 mux_table[1] = 1;
1545 mux_table[2] = 2;
1546 for (j = 0; j < gck->parents_count; j++) {
1547 parents[3 + j] = pmc_clk_get_by_name(sama7g5_pmc->chws,
1548 sama7g5_pmc->ncore,
1549 gck->parents[j]);
1550 assert(parents[3 + j]);
1551 mux_table[3 + j] = gck->parents_mux_table[j];
1552 }
1553
1554 clk = at91_clk_register_generated(sama7g5_pmc,
1555 &sama7g5_pcr_layout,
1556 gck->name, parents,
1557 mux_table,
1558 num_parents, gck->id,
1559 &gck->output,
1560 gck->parents_chg_id);
1561 if (!clk)
1562 panic();
1563
1564 pmc_clk = &sama7g5_pmc->ghws[i];
1565 pmc_clk->clk = clk;
1566 pmc_clk->id = gck->id;
1567
1568 sam_set_clock_range(PMC_TYPE_GCK, gck->id, &gck->output);
1569 }
1570
1571 res = clk_set_rate(pll_frac_clk[PLL_ID_ETH], 625000000);
1572 if (res)
1573 panic();
1574
1575 res = clk_set_rate(pll_div_clk[PLL_ID_ETH], 625000000);
1576 if (res)
1577 panic();
1578
1579 res = clk_set_rate(pll_frac_clk[PLL_ID_AUDIO], 983040000);
1580 if (res)
1581 panic();
1582
1583 res = clk_set_rate(pll_div_clk[PLL_ID_AUDIO], 196608000);
1584 if (res)
1585 panic();
1586
1587 clk = pmc_clk_get_by_name(sama7g5_pmc->ghws, sama7g5_pmc->ngck,
1588 "pdmc0_gclk");
1589 assert(clk);
1590 res = clk_set_parent(clk, pll_div_clk[PLL_ID_AUDIO]);
1591 if (res)
1592 panic();
1593
1594 clk = pmc_clk_get_by_name(sama7g5_pmc->ghws, sama7g5_pmc->ngck,
1595 "i2smcc0_gclk");
1596 assert(clk);
1597 res = clk_set_parent(clk, pll_div_clk[PLL_ID_AUDIO]);
1598 if (res)
1599 panic();
1600
1601 res = clk_dt_register_clk_provider(fdt, nodeoffset, clk_dt_pmc_get,
1602 sama7g5_pmc);
1603 if (res)
1604 panic();
1605
1606 pmc_register_pm();
1607
1608 return TEE_SUCCESS;
1609 }
1610
1611 CLK_DT_DECLARE(sama7g5_clk, "microchip,sama7g5-pmc", pmc_setup_sama7g5);
1612