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 TEE_Result pmc_setup(const void *fdt, int nodeoffset, 304 const void *data __unused) 305 { 306 size_t size = 0; 307 vaddr_t base = 0; 308 unsigned int i = 0; 309 int bypass = 0; 310 const uint32_t *fdt_prop = NULL; 311 struct pmc_clk *pmc_clk = NULL; 312 struct pmc_data *pmc = NULL; 313 const struct sam_clk *sam_clk = NULL; 314 struct clk_range range = CLK_RANGE(0, 0); 315 struct clk *h32mxck = NULL; 316 struct clk *mckdivck = NULL; 317 struct clk *plladivck = NULL; 318 struct clk *usbck = NULL; 319 struct clk *audiopll_pmcck = NULL; 320 struct clk *parents[PARENT_SIZE] = {NULL}; 321 struct clk *main_clk = NULL; 322 struct clk *utmi_clk = NULL; 323 struct clk *slow_clk = NULL; 324 struct clk *clk = NULL; 325 struct clk *main_rc_osc = NULL; 326 struct clk *main_osc = NULL; 327 struct clk *main_xtal_clk = NULL; 328 struct clk *audiopll_fracck = NULL; 329 TEE_Result res = TEE_ERROR_GENERIC; 330 331 /* 332 * We want PARENT_SIZE to be MAX(ARRAY_SIZE(sama5d2_systemck),6) 333 * but using this define won't allow static initialization of parents 334 * due to dynamic size. 335 */ 336 COMPILE_TIME_ASSERT(ARRAY_SIZE(sama5d2_systemck) == PARENT_SIZE); 337 COMPILE_TIME_ASSERT(PARENT_SIZE >= 6); 338 339 if (dt_map_dev(fdt, nodeoffset, &base, &size) < 0) 340 panic(); 341 342 if (_fdt_get_status(fdt, nodeoffset) == DT_STATUS_OK_SEC) 343 matrix_configure_periph_secure(AT91C_ID_PMC); 344 345 slow_clk = clk_dt_get_by_name(fdt, nodeoffset, "slow_clk", &res); 346 if (res) 347 panic(); 348 349 main_xtal_clk = clk_dt_get_by_name(fdt, nodeoffset, "main_xtal", &res); 350 if (res) 351 panic(); 352 353 pmc = pmc_data_allocate(PMC_MCK_PRES + 1, 354 ARRAY_SIZE(sama5d2_systemck), 355 ARRAY_SIZE(sama5d2_perick) + 356 ARRAY_SIZE(sama5d2_peri32ck), 357 ARRAY_SIZE(sama5d2_gck), 358 ARRAY_SIZE(sama5d2_progck)); 359 if (!pmc) 360 panic(); 361 pmc->base = base; 362 363 main_rc_osc = pmc_register_main_rc_osc(pmc, "main_rc_osc", 12000000); 364 if (!main_rc_osc) 365 panic(); 366 367 fdt_prop = fdt_getprop(fdt, nodeoffset, "atmel,osc-bypass", NULL); 368 if (fdt_prop) 369 bypass = fdt32_to_cpu(*fdt_prop); 370 371 main_osc = pmc_register_main_osc(pmc, "main_osc", main_xtal_clk, 372 bypass); 373 if (!main_osc) 374 panic(); 375 376 parents[0] = main_rc_osc; 377 parents[1] = main_osc; 378 main_clk = at91_clk_register_sam9x5_main(pmc, "mainck", parents, 2); 379 if (!main_clk) 380 panic(); 381 382 pmc_clk = &pmc->chws[PMC_MAIN]; 383 pmc_clk->clk = main_clk; 384 pmc_clk->id = PMC_MAIN; 385 386 clk = at91_clk_register_pll(pmc, "pllack", main_clk, 0, 387 &sama5d3_pll_layout, &plla_charac); 388 if (!clk) 389 panic(); 390 391 plladivck = at91_clk_register_plldiv(pmc, "plladivck", clk); 392 if (!plladivck) 393 panic(); 394 395 pmc_clk = &pmc->chws[PMC_PLLACK]; 396 pmc_clk->clk = plladivck; 397 pmc_clk->id = PMC_PLLACK; 398 399 audiopll_fracck = at91_clk_register_audio_pll_frac(pmc, 400 "audiopll_fracck", 401 main_clk); 402 if (!audiopll_fracck) 403 panic(); 404 405 clk = at91_clk_register_audio_pll_pad(pmc, "audiopll_padck", 406 audiopll_fracck); 407 if (!clk) 408 panic(); 409 410 audiopll_pmcck = at91_clk_register_audio_pll_pmc(pmc, "audiopll_pmcck", 411 audiopll_fracck); 412 if (!audiopll_pmcck) 413 panic(); 414 415 pmc_clk = &pmc->chws[PMC_AUDIOPLLCK]; 416 pmc_clk->clk = audiopll_pmcck; 417 pmc_clk->id = PMC_AUDIOPLLCK; 418 419 utmi_clk = at91_clk_register_utmi(pmc, "utmick", main_clk); 420 if (!utmi_clk) 421 panic(); 422 423 pmc_clk = &pmc->chws[PMC_UTMI]; 424 pmc_clk->clk = utmi_clk; 425 pmc_clk->id = PMC_UTMI; 426 427 parents[0] = slow_clk; 428 parents[1] = main_clk; 429 parents[2] = plladivck; 430 parents[3] = utmi_clk; 431 432 clk = at91_clk_register_master_pres(pmc, "masterck_pres", 4, 433 parents, 434 &at91sam9x5_master_layout, 435 &mck_charac, INT_MIN); 436 if (!clk) 437 panic(); 438 439 pmc_clk = &pmc->chws[PMC_MCK_PRES]; 440 pmc_clk->clk = clk; 441 pmc_clk->id = PMC_MCK_PRES; 442 443 mckdivck = at91_clk_register_master_div(pmc, "masterck_div", 444 clk, 445 &at91sam9x5_master_layout, 446 &mck_charac); 447 if (!mckdivck) 448 panic(); 449 450 pmc_clk = &pmc->chws[PMC_MCK]; 451 pmc_clk->clk = mckdivck; 452 pmc_clk->id = PMC_MCK; 453 454 h32mxck = at91_clk_register_h32mx(pmc, "h32mxck", mckdivck); 455 if (!h32mxck) 456 panic(); 457 458 pmc_clk = &pmc->chws[PMC_MCK2]; 459 pmc_clk->clk = h32mxck; 460 pmc_clk->id = PMC_MCK2; 461 462 parents[0] = plladivck; 463 parents[1] = utmi_clk; 464 usbck = at91sam9x5_clk_register_usb(pmc, "usbck", parents, 2); 465 if (!usbck) 466 panic(); 467 468 if (clk_set_parent(usbck, utmi_clk) != TEE_SUCCESS) 469 panic(); 470 471 clk_set_rate(usbck, 48000000); 472 473 parents[0] = slow_clk; 474 parents[1] = main_clk; 475 parents[2] = plladivck; 476 parents[3] = utmi_clk; 477 parents[4] = mckdivck; 478 parents[5] = audiopll_pmcck; 479 for (i = 0; i < ARRAY_SIZE(sama5d2_progck); i++) { 480 sam_clk = &sama5d2_progck[i]; 481 clk = at91_clk_register_programmable(pmc, sam_clk->n, 482 parents, 483 PROGCK_PARENT_COUNT, i, 484 &sama5d2_prog_layout); 485 if (!clk) 486 panic(); 487 488 pmc_clk = &pmc->pchws[i]; 489 pmc_clk->clk = clk; 490 pmc_clk->id = sam_clk->id; 491 } 492 493 /* This array order must match the one in sama5d2_systemck */ 494 parents[0] = mckdivck; 495 parents[1] = mckdivck; 496 parents[2] = usbck; 497 parents[3] = usbck; 498 parents[4] = pmc->pchws[0].clk; 499 parents[5] = pmc->pchws[1].clk; 500 parents[6] = pmc->pchws[2].clk; 501 parents[7] = mckdivck; 502 for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) { 503 sam_clk = &sama5d2_systemck[i]; 504 clk = at91_clk_register_system(pmc, sam_clk->n, 505 parents[i], 506 sam_clk->id); 507 if (!clk) 508 panic(); 509 510 pmc_clk = &pmc->shws[i]; 511 pmc_clk->clk = clk; 512 pmc_clk->id = sam_clk->id; 513 } 514 515 for (i = 0; i < ARRAY_SIZE(sama5d2_perick); i++) { 516 sam_clk = &sama5d2_perick[i]; 517 clk = at91_clk_register_sam9x5_periph(pmc, 518 &sama5d2_pcr_layout, 519 sam_clk->n, 520 mckdivck, 521 sam_clk->id, 522 &range); 523 if (!clk) 524 panic(); 525 526 pmc_clk = &pmc->phws[i]; 527 pmc_clk->clk = clk; 528 pmc_clk->id = sam_clk->id; 529 } 530 531 for (i = 0; i < ARRAY_SIZE(sama5d2_peri32ck); i++) { 532 sam_clk = &sama5d2_peri32ck[i].clk; 533 clk = at91_clk_register_sam9x5_periph(pmc, 534 &sama5d2_pcr_layout, 535 sam_clk->n, 536 h32mxck, 537 sam_clk->id, 538 &sama5d2_peri32ck[i].r); 539 if (!clk) 540 panic(); 541 542 pmc_clk = &pmc->phws[ARRAY_SIZE(sama5d2_perick) + i]; 543 pmc_clk->clk = clk; 544 pmc_clk->id = sam_clk->id; 545 } 546 547 parents[0] = slow_clk; 548 parents[1] = main_clk; 549 parents[2] = plladivck; 550 parents[3] = utmi_clk; 551 parents[4] = mckdivck; 552 parents[5] = audiopll_pmcck; 553 for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) { 554 sam_clk = &sama5d2_gck[i].clk; 555 clk = at91_clk_register_generated(pmc, 556 &sama5d2_pcr_layout, 557 sam_clk->n, 558 parents, 6, 559 sam_clk->id, 560 &sama5d2_gck[i].r, 561 sama5d2_gck[i].chg_pid); 562 if (!clk) 563 panic(); 564 565 pmc_clk = &pmc->ghws[i]; 566 pmc_clk->clk = clk; 567 pmc_clk->id = sam_clk->id; 568 } 569 570 parents[0] = pmc_clk_get_by_name(pmc->phws, pmc->nperiph, "i2s0_clk"); 571 parents[1] = pmc_clk_get_by_name(pmc->ghws, pmc->ngck, "i2s0_gclk"); 572 clk = at91_clk_i2s_mux_register("i2s0_muxclk", parents, 2, 0); 573 if (!clk) 574 panic(); 575 576 pmc->chws[PMC_I2S0_MUX].clk = clk; 577 pmc->chws[PMC_I2S0_MUX].id = PMC_I2S0_MUX; 578 579 parents[0] = pmc_clk_get_by_name(pmc->phws, pmc->nperiph, "i2s1_clk"); 580 parents[1] = pmc_clk_get_by_name(pmc->ghws, pmc->ngck, "i2s1_gclk"); 581 clk = at91_clk_i2s_mux_register("i2s1_muxclk", parents, 2, 1); 582 if (!clk) 583 panic(); 584 585 pmc->chws[PMC_I2S1_MUX].clk = clk; 586 pmc->chws[PMC_I2S1_MUX].id = PMC_I2S1_MUX; 587 588 clk_dt_register_clk_provider(fdt, nodeoffset, clk_dt_pmc_get, pmc); 589 590 return TEE_SUCCESS; 591 } 592 593 CLK_DT_DECLARE(sama5d2_clk, "atmel,sama5d2-pmc", pmc_setup); 594