xref: /optee_os/core/drivers/clk/sam/sama5d2_clk.c (revision 90dee57ac37038a25e865d2e9218d7877ab6cff9)
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 
305 vaddr_t at91_pmc_get_base(void)
306 {
307 	assert(pmc);
308 
309 	return pmc->base;
310 }
311 
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, DT_MAP_AUTO) < 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_SAMA5D2_CORE_CLK_COUNT,
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 	pmc_clk = &pmc->chws[PMC_AUDIOPLL_FRACCK];
414 	pmc_clk->clk = audiopll_fracck;
415 	pmc_clk->id = PMC_AUDIOPLL_FRACCK;
416 
417 	clk = at91_clk_register_audio_pll_pad(pmc, "audiopll_padck",
418 					      audiopll_fracck);
419 	if (!clk)
420 		panic();
421 
422 	audiopll_pmcck = at91_clk_register_audio_pll_pmc(pmc, "audiopll_pmcck",
423 							 audiopll_fracck);
424 	if (!audiopll_pmcck)
425 		panic();
426 
427 	pmc_clk = &pmc->chws[PMC_AUDIOPLLCK];
428 	pmc_clk->clk = audiopll_pmcck;
429 	pmc_clk->id = PMC_AUDIOPLLCK;
430 
431 	utmi_clk = at91_clk_register_utmi(pmc, "utmick", main_clk);
432 	if (!utmi_clk)
433 		panic();
434 
435 	pmc_clk = &pmc->chws[PMC_UTMI];
436 	pmc_clk->clk = utmi_clk;
437 	pmc_clk->id = PMC_UTMI;
438 
439 	parents[0] = slow_clk;
440 	parents[1] = main_clk;
441 	parents[2] = plladivck;
442 	parents[3] = utmi_clk;
443 
444 	clk = at91_clk_register_master_pres(pmc, "masterck_pres", 4,
445 					    parents,
446 					    &at91sam9x5_master_layout,
447 					    &mck_charac, INT_MIN);
448 	if (!clk)
449 		panic();
450 
451 	pmc_clk = &pmc->chws[PMC_MCK_PRES];
452 	pmc_clk->clk = clk;
453 	pmc_clk->id = PMC_MCK_PRES;
454 
455 	mckdivck = at91_clk_register_master_div(pmc, "masterck_div",
456 						clk,
457 						&at91sam9x5_master_layout,
458 						&mck_charac);
459 	if (!mckdivck)
460 		panic();
461 
462 	pmc_clk = &pmc->chws[PMC_MCK];
463 	pmc_clk->clk = mckdivck;
464 	pmc_clk->id = PMC_MCK;
465 
466 	h32mxck = at91_clk_register_h32mx(pmc, "h32mxck", mckdivck);
467 	if (!h32mxck)
468 		panic();
469 
470 	pmc_clk = &pmc->chws[PMC_MCK2];
471 	pmc_clk->clk = h32mxck;
472 	pmc_clk->id = PMC_MCK2;
473 
474 	parents[0] = plladivck;
475 	parents[1] = utmi_clk;
476 	usbck = at91sam9x5_clk_register_usb(pmc, "usbck", parents, 2);
477 	if (!usbck)
478 		panic();
479 
480 	pmc_clk = &pmc->chws[PMC_USBCK];
481 	pmc_clk->clk = usbck;
482 	pmc_clk->id = PMC_USBCK;
483 
484 	if (clk_set_parent(usbck, utmi_clk) != TEE_SUCCESS)
485 		panic();
486 
487 	clk_set_rate(usbck, 48000000);
488 
489 	parents[0] = slow_clk;
490 	parents[1] = main_clk;
491 	parents[2] = plladivck;
492 	parents[3] = utmi_clk;
493 	parents[4] = mckdivck;
494 	parents[5] = audiopll_pmcck;
495 	for (i = 0; i < ARRAY_SIZE(sama5d2_progck); i++) {
496 		sam_clk = &sama5d2_progck[i];
497 		clk = at91_clk_register_programmable(pmc, sam_clk->n,
498 						     parents,
499 						     PROGCK_PARENT_COUNT, i,
500 						     &sama5d2_prog_layout);
501 		if (!clk)
502 			panic();
503 
504 		pmc_clk = &pmc->pchws[i];
505 		pmc_clk->clk = clk;
506 		pmc_clk->id = sam_clk->id;
507 	}
508 
509 	/* This array order must match the one in sama5d2_systemck */
510 	parents[0] = mckdivck;
511 	parents[1] = mckdivck;
512 	parents[2] = usbck;
513 	parents[3] = usbck;
514 	parents[4] = pmc->pchws[0].clk;
515 	parents[5] = pmc->pchws[1].clk;
516 	parents[6] = pmc->pchws[2].clk;
517 	parents[7] = mckdivck;
518 	for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
519 		sam_clk = &sama5d2_systemck[i];
520 		clk = at91_clk_register_system(pmc, sam_clk->n,
521 					       parents[i],
522 					       sam_clk->id);
523 		if (!clk)
524 			panic();
525 
526 		pmc_clk = &pmc->shws[i];
527 		pmc_clk->clk = clk;
528 		pmc_clk->id = sam_clk->id;
529 	}
530 
531 	for (i = 0; i < ARRAY_SIZE(sama5d2_perick); i++) {
532 		sam_clk = &sama5d2_perick[i];
533 		clk = at91_clk_register_sam9x5_periph(pmc,
534 						      &sama5d2_pcr_layout,
535 						      sam_clk->n,
536 						      mckdivck,
537 						      sam_clk->id,
538 						      &range);
539 		if (!clk)
540 			panic();
541 
542 		pmc_clk = &pmc->phws[i];
543 		pmc_clk->clk = clk;
544 		pmc_clk->id = sam_clk->id;
545 	}
546 
547 	for (i = 0; i < ARRAY_SIZE(sama5d2_peri32ck); i++) {
548 		sam_clk = &sama5d2_peri32ck[i].clk;
549 		clk = at91_clk_register_sam9x5_periph(pmc,
550 						      &sama5d2_pcr_layout,
551 						      sam_clk->n,
552 						      h32mxck,
553 						      sam_clk->id,
554 						      &sama5d2_peri32ck[i].r);
555 		if (!clk)
556 			panic();
557 
558 		pmc_clk = &pmc->phws[ARRAY_SIZE(sama5d2_perick) + i];
559 		pmc_clk->clk = clk;
560 		pmc_clk->id = sam_clk->id;
561 	}
562 
563 	parents[0] = slow_clk;
564 	parents[1] = main_clk;
565 	parents[2] = plladivck;
566 	parents[3] = utmi_clk;
567 	parents[4] = mckdivck;
568 	parents[5] = audiopll_pmcck;
569 	for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
570 		sam_clk = &sama5d2_gck[i].clk;
571 		clk = at91_clk_register_generated(pmc,
572 						  &sama5d2_pcr_layout,
573 						  sam_clk->n,
574 						  parents, 6,
575 						  sam_clk->id,
576 						  &sama5d2_gck[i].r,
577 						  sama5d2_gck[i].chg_pid);
578 		if (!clk)
579 			panic();
580 
581 		pmc_clk = &pmc->ghws[i];
582 		pmc_clk->clk = clk;
583 		pmc_clk->id = sam_clk->id;
584 	}
585 
586 	parents[0] = pmc_clk_get_by_name(pmc->phws, pmc->nperiph, "i2s0_clk");
587 	parents[1] = pmc_clk_get_by_name(pmc->ghws, pmc->ngck, "i2s0_gclk");
588 	clk = at91_clk_i2s_mux_register("i2s0_muxclk", parents, 2, 0);
589 	if (!clk)
590 		panic();
591 
592 	pmc->chws[PMC_I2S0_MUX].clk = clk;
593 	pmc->chws[PMC_I2S0_MUX].id = PMC_I2S0_MUX;
594 
595 	parents[0] = pmc_clk_get_by_name(pmc->phws, pmc->nperiph, "i2s1_clk");
596 	parents[1] = pmc_clk_get_by_name(pmc->ghws, pmc->ngck, "i2s1_gclk");
597 	clk = at91_clk_i2s_mux_register("i2s1_muxclk", parents, 2, 1);
598 	if (!clk)
599 		panic();
600 
601 	pmc->chws[PMC_I2S1_MUX].clk = clk;
602 	pmc->chws[PMC_I2S1_MUX].id = PMC_I2S1_MUX;
603 
604 	clk_dt_register_clk_provider(fdt, nodeoffset, clk_dt_pmc_get, pmc);
605 
606 	pmc_register_pm();
607 
608 	return TEE_SUCCESS;
609 }
610 
611 CLK_DT_DECLARE(sama5d2_clk, "atmel,sama5d2-pmc", pmc_setup);
612