1 // SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause
2 /*
3 * Copyright (c) 2021, Microchip
4 */
5 #include <assert.h>
6 #include <kernel/boot.h>
7 #include <libfdt.h>
8 #include <kernel/dt.h>
9 #include <kernel/panic.h>
10 #include <matrix.h>
11 #include <sama5d2.h>
12 #include <stdint.h>
13 #include <util.h>
14
15 #include "at91_clk.h"
16
17 #include <dt-bindings/clock/at91.h>
18
19 #define PROGCK_PARENT_COUNT 6
20 #define PARENT_SIZE ARRAY_SIZE(sama5d2_systemck)
21
22 struct sam_clk {
23 const char *n;
24 uint8_t id;
25 };
26
27 static const struct clk_master_charac mck_charac = {
28 .output = { .min = 124000000, .max = 166000000 },
29 .divisors = { 1, 2, 4, 3 },
30 };
31
32 static uint8_t plla_out[1];
33
34 static uint16_t plla_icpll[1];
35
36 static const struct clk_range plla_outputs[] = {
37 { .min = 600000000, .max = 1200000000 },
38 };
39
40 static const struct clk_pll_charac plla_charac = {
41 .input = { .min = 12000000, .max = 24000000 },
42 .num_output = ARRAY_SIZE(plla_outputs),
43 .output = plla_outputs,
44 .icpll = plla_icpll,
45 .out = plla_out,
46 };
47
48 static const struct clk_pcr_layout sama5d2_pcr_layout = {
49 .offset = 0x10c,
50 .cmd = BIT(12),
51 .gckcss_mask = GENMASK_32(10, 8),
52 .pid_mask = GENMASK_32(6, 0),
53 };
54
55 static const struct clk_programmable_layout sama5d2_prog_layout = {
56 .pres_mask = 0xff,
57 .pres_shift = 4,
58 .css_mask = 0x7,
59 .have_slck_mck = 0,
60 .is_pres_direct = 1,
61 };
62
63 static const struct sam_clk sama5d2_systemck[] = {
64 { .n = "ddrck", .id = 2 },
65 { .n = "lcdck", .id = 3 },
66 { .n = "uhpck", .id = 6 },
67 { .n = "udpck", .id = 7 },
68 { .n = "pck0", .id = 8 },
69 { .n = "pck1", .id = 9 },
70 { .n = "pck2", .id = 10 },
71 { .n = "iscck", .id = 18 },
72 };
73
74 static const struct {
75 struct sam_clk clk;
76 struct clk_range r;
77 } sama5d2_peri32ck[] = {
78 {
79 .clk = { .n = "macb0_clk", .id = 5 },
80 .r = { .min = 0, .max = 83000000 },
81 },
82 {
83 .clk = { .n = "tdes_clk", .id = 11 },
84 .r = { .min = 0, .max = 83000000 },
85 },
86 {
87 .clk = { .n = "matrix1_clk", .id = 14 },
88 },
89 {
90 .clk = { .n = "hsmc_clk", .id = 17 },
91 },
92 {
93 .clk = { .n = "pioA_clk", .id = 18 },
94 .r = { .min = 0, .max = 83000000 },
95 },
96 {
97 .clk = { .n = "flx0_clk", .id = 19 },
98 .r = { .min = 0, .max = 83000000 },
99 },
100 {
101 .clk = { .n = "flx1_clk", .id = 20 },
102 .r = { .min = 0, .max = 83000000 },
103 },
104 {
105 .clk = { .n = "flx2_clk", .id = 21 },
106 .r = { .min = 0, .max = 83000000 },
107 },
108 {
109 .clk = { .n = "flx3_clk", .id = 22 },
110 .r = { .min = 0, .max = 83000000 },
111 },
112 {
113 .clk = { .n = "flx4_clk", .id = 23 },
114 .r = { .min = 0, .max = 83000000 },
115 },
116 {
117 .clk = { .n = "uart0_clk", .id = 24 },
118 .r = { .min = 0, .max = 83000000 },
119 },
120 {
121 .clk = { .n = "uart1_clk", .id = 25 },
122 .r = { .min = 0, .max = 83000000 },
123 },
124 {
125 .clk = { .n = "uart2_clk", .id = 26 },
126 .r = { .min = 0, .max = 83000000 },
127 },
128 {
129 .clk = { .n = "uart3_clk", .id = 27 },
130 .r = { .min = 0, .max = 83000000 },
131 },
132 {
133 .clk = { .n = "uart4_clk", .id = 28 },
134 .r = { .min = 0, .max = 83000000 },
135 },
136 {
137 .clk = { .n = "twi0_clk", .id = 29 },
138 .r = { .min = 0, .max = 83000000 },
139 },
140 {
141 .clk = { .n = "twi1_clk", .id = 30 },
142 .r = { .min = 0, .max = 83000000 },
143 },
144 {
145 .clk = { .n = "spi0_clk", .id = 33 },
146 .r = { .min = 0, .max = 83000000 },
147 },
148 {
149 .clk = { .n = "spi1_clk", .id = 34 },
150 .r = { .min = 0, .max = 83000000 },
151 },
152 {
153 .clk = { .n = "tcb0_clk", .id = 35 },
154 .r = { .min = 0, .max = 83000000 },
155 },
156 {
157 .clk = { .n = "tcb1_clk", .id = 36 },
158 .r = { .min = 0, .max = 83000000 },
159 },
160 {
161 .clk = { .n = "pwm_clk", .id = 38 },
162 .r = { .min = 0, .max = 83000000 },
163 },
164 {
165 .clk = { .n = "adc_clk", .id = 40 },
166 .r = { .min = 0, .max = 83000000 },
167 },
168 {
169 .clk = { .n = "uhphs_clk", .id = 41 },
170 .r = { .min = 0, .max = 83000000 },
171 },
172 {
173 .clk = { .n = "udphs_clk", .id = 42 },
174 .r = { .min = 0, .max = 83000000 },
175 },
176 {
177 .clk = { .n = "ssc0_clk", .id = 43 },
178 .r = { .min = 0, .max = 83000000 },
179 },
180 {
181 .clk = { .n = "ssc1_clk", .id = 44 },
182 .r = { .min = 0, .max = 83000000 },
183 },
184 {
185 .clk = { .n = "trng_clk", .id = 47 },
186 .r = { .min = 0, .max = 83000000 },
187 },
188 {
189 .clk = { .n = "pdmic_clk", .id = 48 },
190 .r = { .min = 0, .max = 83000000 },
191 },
192 {
193 .clk = { .n = "securam_clk", .id = 51 }, },
194 {
195 .clk = { .n = "i2s0_clk", .id = 54 },
196 .r = { .min = 0, .max = 83000000 },
197 },
198 {
199 .clk = { .n = "i2s1_clk", .id = 55 },
200 .r = { .min = 0, .max = 83000000 },
201 },
202 {
203 .clk = { .n = "can0_clk", .id = 56 },
204 .r = { .min = 0, .max = 83000000 },
205 },
206 {
207 .clk = { .n = "can1_clk", .id = 57 },
208 .r = { .min = 0, .max = 83000000 },
209 },
210 {
211 .clk = { .n = "ptc_clk", .id = 58 },
212 .r = { .min = 0, .max = 83000000 },
213 },
214 {
215 .clk = { .n = "classd_clk", .id = 59 },
216 .r = { .min = 0, .max = 83000000 },
217 },
218 };
219
220 static const struct sam_clk sama5d2_perick[] = {
221 { .n = "dma0_clk", .id = 6 },
222 { .n = "dma1_clk", .id = 7 },
223 { .n = "aes_clk", .id = 9 },
224 { .n = "aesb_clk", .id = 10 },
225 { .n = "sha_clk", .id = 12 },
226 { .n = "mpddr_clk", .id = 13 },
227 { .n = "matrix0_clk", .id = 15 },
228 { .n = "sdmmc0_hclk", .id = 31 },
229 { .n = "sdmmc1_hclk", .id = 32 },
230 { .n = "lcdc_clk", .id = 45 },
231 { .n = "isc_clk", .id = 46 },
232 { .n = "qspi0_clk", .id = 52 },
233 { .n = "qspi1_clk", .id = 53 },
234 };
235
236 static const struct {
237 struct sam_clk clk;
238 struct clk_range r;
239 int chg_pid;
240 } sama5d2_gck[] = {
241 {
242 .clk = { .n = "sdmmc0_gclk", .id = 31 },
243 .chg_pid = INT_MIN,
244 },
245 {
246 .clk = { .n = "sdmmc1_gclk", .id = 32 },
247 .chg_pid = INT_MIN,
248 },
249 {
250 .clk = { .n = "tcb0_gclk", .id = 35 },
251 .r = { .min = 0, .max = 83000000 },
252 .chg_pid = INT_MIN,
253 },
254 {
255 .clk = { .n = "tcb1_gclk", .id = 36 },
256 .r = { .min = 0, .max = 83000000 },
257 .chg_pid = INT_MIN,
258 },
259 {
260 .clk = { .n = "pwm_gclk", .id = 38 },
261 .r = { .min = 0, .max = 83000000 },
262 .chg_pid = INT_MIN,
263 },
264 {
265 .clk = { .n = "isc_gclk", .id = 46 },
266 .chg_pid = INT_MIN,
267 },
268 {
269 .clk = { .n = "pdmic_gclk", .id = 48 },
270 .chg_pid = INT_MIN,
271 },
272 {
273 .clk = { .n = "i2s0_gclk", .id = 54 },
274 .chg_pid = 5,
275 },
276 {
277 .clk = { .n = "i2s1_gclk", .id = 55 },
278 .chg_pid = 5,
279 },
280 {
281 .clk = { .n = "can0_gclk", .id = 56 },
282 .r = { .min = 0, .max = 80000000 },
283 .chg_pid = INT_MIN,
284 },
285 {
286 .clk = { .n = "can1_gclk", .id = 57 },
287 .r = { .min = 0, .max = 80000000 },
288 .chg_pid = INT_MIN,
289 },
290 {
291 .clk = { .n = "classd_gclk", .id = 59 },
292 .chg_pid = 5,
293 .r = { .min = 0, .max = 100000000 },
294 },
295 };
296
297 static const struct sam_clk sama5d2_progck[] = {
298 { .n = "prog0", .id = 0 },
299 { .n = "prog1", .id = 1 },
300 { .n = "prog2", .id = 2 },
301 };
302
303 static struct pmc_data *pmc;
304
at91_pmc_get_base(void)305 vaddr_t at91_pmc_get_base(void)
306 {
307 assert(pmc);
308
309 return pmc->base;
310 }
311
pmc_setup(const void * fdt,int nodeoffset,const void * data __unused)312 static TEE_Result pmc_setup(const void *fdt, int nodeoffset,
313 const void *data __unused)
314 {
315 size_t size = 0;
316 vaddr_t base = 0;
317 unsigned int i = 0;
318 int bypass = 0;
319 const uint32_t *fdt_prop = NULL;
320 struct pmc_clk *pmc_clk = NULL;
321 const struct sam_clk *sam_clk = NULL;
322 struct clk_range range = CLK_RANGE(0, 0);
323 struct clk *h32mxck = NULL;
324 struct clk *mckdivck = NULL;
325 struct clk *plladivck = NULL;
326 struct clk *usbck = NULL;
327 struct clk *audiopll_pmcck = NULL;
328 struct clk *parents[PARENT_SIZE] = {NULL};
329 struct clk *main_clk = NULL;
330 struct clk *utmi_clk = NULL;
331 struct clk *slow_clk = NULL;
332 struct clk *clk = NULL;
333 struct clk *main_rc_osc = NULL;
334 struct clk *main_osc = NULL;
335 struct clk *main_xtal_clk = NULL;
336 struct clk *audiopll_fracck = NULL;
337 TEE_Result res = TEE_ERROR_GENERIC;
338
339 /*
340 * We want PARENT_SIZE to be MAX(ARRAY_SIZE(sama5d2_systemck),6)
341 * but using this define won't allow static initialization of parents
342 * due to dynamic size.
343 */
344 COMPILE_TIME_ASSERT(ARRAY_SIZE(sama5d2_systemck) == PARENT_SIZE);
345 COMPILE_TIME_ASSERT(PARENT_SIZE >= 6);
346
347 if (dt_map_dev(fdt, nodeoffset, &base, &size) < 0)
348 panic();
349
350 if (_fdt_get_status(fdt, nodeoffset) == DT_STATUS_OK_SEC)
351 matrix_configure_periph_secure(AT91C_ID_PMC);
352
353 res = clk_dt_get_by_name(fdt, nodeoffset, "slow_clk", &slow_clk);
354 if (res)
355 panic();
356
357 res = clk_dt_get_by_name(fdt, nodeoffset, "main_xtal", &main_xtal_clk);
358 if (res)
359 panic();
360
361 pmc = pmc_data_allocate(PMC_MCK_PRES + 1,
362 ARRAY_SIZE(sama5d2_systemck),
363 ARRAY_SIZE(sama5d2_perick) +
364 ARRAY_SIZE(sama5d2_peri32ck),
365 ARRAY_SIZE(sama5d2_gck),
366 ARRAY_SIZE(sama5d2_progck));
367 if (!pmc)
368 panic();
369 pmc->base = base;
370
371 main_rc_osc = pmc_register_main_rc_osc(pmc, "main_rc_osc", 12000000);
372 if (!main_rc_osc)
373 panic();
374
375 fdt_prop = fdt_getprop(fdt, nodeoffset, "atmel,osc-bypass", NULL);
376 if (fdt_prop)
377 bypass = fdt32_to_cpu(*fdt_prop);
378
379 main_osc = pmc_register_main_osc(pmc, "main_osc", main_xtal_clk,
380 bypass);
381 if (!main_osc)
382 panic();
383
384 parents[0] = main_rc_osc;
385 parents[1] = main_osc;
386 main_clk = at91_clk_register_sam9x5_main(pmc, "mainck", parents, 2);
387 if (!main_clk)
388 panic();
389
390 pmc_clk = &pmc->chws[PMC_MAIN];
391 pmc_clk->clk = main_clk;
392 pmc_clk->id = PMC_MAIN;
393
394 clk = at91_clk_register_pll(pmc, "pllack", main_clk, 0,
395 &sama5d3_pll_layout, &plla_charac);
396 if (!clk)
397 panic();
398
399 plladivck = at91_clk_register_plldiv(pmc, "plladivck", clk);
400 if (!plladivck)
401 panic();
402
403 pmc_clk = &pmc->chws[PMC_PLLACK];
404 pmc_clk->clk = plladivck;
405 pmc_clk->id = PMC_PLLACK;
406
407 audiopll_fracck = at91_clk_register_audio_pll_frac(pmc,
408 "audiopll_fracck",
409 main_clk);
410 if (!audiopll_fracck)
411 panic();
412
413 clk = at91_clk_register_audio_pll_pad(pmc, "audiopll_padck",
414 audiopll_fracck);
415 if (!clk)
416 panic();
417
418 audiopll_pmcck = at91_clk_register_audio_pll_pmc(pmc, "audiopll_pmcck",
419 audiopll_fracck);
420 if (!audiopll_pmcck)
421 panic();
422
423 pmc_clk = &pmc->chws[PMC_AUDIOPLLCK];
424 pmc_clk->clk = audiopll_pmcck;
425 pmc_clk->id = PMC_AUDIOPLLCK;
426
427 utmi_clk = at91_clk_register_utmi(pmc, "utmick", main_clk);
428 if (!utmi_clk)
429 panic();
430
431 pmc_clk = &pmc->chws[PMC_UTMI];
432 pmc_clk->clk = utmi_clk;
433 pmc_clk->id = PMC_UTMI;
434
435 parents[0] = slow_clk;
436 parents[1] = main_clk;
437 parents[2] = plladivck;
438 parents[3] = utmi_clk;
439
440 clk = at91_clk_register_master_pres(pmc, "masterck_pres", 4,
441 parents,
442 &at91sam9x5_master_layout,
443 &mck_charac, INT_MIN);
444 if (!clk)
445 panic();
446
447 pmc_clk = &pmc->chws[PMC_MCK_PRES];
448 pmc_clk->clk = clk;
449 pmc_clk->id = PMC_MCK_PRES;
450
451 mckdivck = at91_clk_register_master_div(pmc, "masterck_div",
452 clk,
453 &at91sam9x5_master_layout,
454 &mck_charac);
455 if (!mckdivck)
456 panic();
457
458 pmc_clk = &pmc->chws[PMC_MCK];
459 pmc_clk->clk = mckdivck;
460 pmc_clk->id = PMC_MCK;
461
462 h32mxck = at91_clk_register_h32mx(pmc, "h32mxck", mckdivck);
463 if (!h32mxck)
464 panic();
465
466 pmc_clk = &pmc->chws[PMC_MCK2];
467 pmc_clk->clk = h32mxck;
468 pmc_clk->id = PMC_MCK2;
469
470 parents[0] = plladivck;
471 parents[1] = utmi_clk;
472 usbck = at91sam9x5_clk_register_usb(pmc, "usbck", parents, 2);
473 if (!usbck)
474 panic();
475
476 if (clk_set_parent(usbck, utmi_clk) != TEE_SUCCESS)
477 panic();
478
479 clk_set_rate(usbck, 48000000);
480
481 parents[0] = slow_clk;
482 parents[1] = main_clk;
483 parents[2] = plladivck;
484 parents[3] = utmi_clk;
485 parents[4] = mckdivck;
486 parents[5] = audiopll_pmcck;
487 for (i = 0; i < ARRAY_SIZE(sama5d2_progck); i++) {
488 sam_clk = &sama5d2_progck[i];
489 clk = at91_clk_register_programmable(pmc, sam_clk->n,
490 parents,
491 PROGCK_PARENT_COUNT, i,
492 &sama5d2_prog_layout);
493 if (!clk)
494 panic();
495
496 pmc_clk = &pmc->pchws[i];
497 pmc_clk->clk = clk;
498 pmc_clk->id = sam_clk->id;
499 }
500
501 /* This array order must match the one in sama5d2_systemck */
502 parents[0] = mckdivck;
503 parents[1] = mckdivck;
504 parents[2] = usbck;
505 parents[3] = usbck;
506 parents[4] = pmc->pchws[0].clk;
507 parents[5] = pmc->pchws[1].clk;
508 parents[6] = pmc->pchws[2].clk;
509 parents[7] = mckdivck;
510 for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
511 sam_clk = &sama5d2_systemck[i];
512 clk = at91_clk_register_system(pmc, sam_clk->n,
513 parents[i],
514 sam_clk->id);
515 if (!clk)
516 panic();
517
518 pmc_clk = &pmc->shws[i];
519 pmc_clk->clk = clk;
520 pmc_clk->id = sam_clk->id;
521 }
522
523 for (i = 0; i < ARRAY_SIZE(sama5d2_perick); i++) {
524 sam_clk = &sama5d2_perick[i];
525 clk = at91_clk_register_sam9x5_periph(pmc,
526 &sama5d2_pcr_layout,
527 sam_clk->n,
528 mckdivck,
529 sam_clk->id,
530 &range);
531 if (!clk)
532 panic();
533
534 pmc_clk = &pmc->phws[i];
535 pmc_clk->clk = clk;
536 pmc_clk->id = sam_clk->id;
537 }
538
539 for (i = 0; i < ARRAY_SIZE(sama5d2_peri32ck); i++) {
540 sam_clk = &sama5d2_peri32ck[i].clk;
541 clk = at91_clk_register_sam9x5_periph(pmc,
542 &sama5d2_pcr_layout,
543 sam_clk->n,
544 h32mxck,
545 sam_clk->id,
546 &sama5d2_peri32ck[i].r);
547 if (!clk)
548 panic();
549
550 pmc_clk = &pmc->phws[ARRAY_SIZE(sama5d2_perick) + i];
551 pmc_clk->clk = clk;
552 pmc_clk->id = sam_clk->id;
553 }
554
555 parents[0] = slow_clk;
556 parents[1] = main_clk;
557 parents[2] = plladivck;
558 parents[3] = utmi_clk;
559 parents[4] = mckdivck;
560 parents[5] = audiopll_pmcck;
561 for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
562 sam_clk = &sama5d2_gck[i].clk;
563 clk = at91_clk_register_generated(pmc,
564 &sama5d2_pcr_layout,
565 sam_clk->n,
566 parents, 6,
567 sam_clk->id,
568 &sama5d2_gck[i].r,
569 sama5d2_gck[i].chg_pid);
570 if (!clk)
571 panic();
572
573 pmc_clk = &pmc->ghws[i];
574 pmc_clk->clk = clk;
575 pmc_clk->id = sam_clk->id;
576 }
577
578 parents[0] = pmc_clk_get_by_name(pmc->phws, pmc->nperiph, "i2s0_clk");
579 parents[1] = pmc_clk_get_by_name(pmc->ghws, pmc->ngck, "i2s0_gclk");
580 clk = at91_clk_i2s_mux_register("i2s0_muxclk", parents, 2, 0);
581 if (!clk)
582 panic();
583
584 pmc->chws[PMC_I2S0_MUX].clk = clk;
585 pmc->chws[PMC_I2S0_MUX].id = PMC_I2S0_MUX;
586
587 parents[0] = pmc_clk_get_by_name(pmc->phws, pmc->nperiph, "i2s1_clk");
588 parents[1] = pmc_clk_get_by_name(pmc->ghws, pmc->ngck, "i2s1_gclk");
589 clk = at91_clk_i2s_mux_register("i2s1_muxclk", parents, 2, 1);
590 if (!clk)
591 panic();
592
593 pmc->chws[PMC_I2S1_MUX].clk = clk;
594 pmc->chws[PMC_I2S1_MUX].id = PMC_I2S1_MUX;
595
596 clk_dt_register_clk_provider(fdt, nodeoffset, clk_dt_pmc_get, pmc);
597
598 return TEE_SUCCESS;
599 }
600
601 CLK_DT_DECLARE(sama5d2_clk, "atmel,sama5d2-pmc", pmc_setup);
602