1 // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 /* 3 * Amlogic S4 PLL Clock Controller Driver 4 * 5 * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved 6 * Author: Yu Tu <yu.tu@amlogic.com> 7 */ 8 9 #include <linux/clk-provider.h> 10 #include <linux/of_device.h> 11 #include <linux/platform_device.h> 12 13 #include "clk-mpll.h" 14 #include "clk-pll.h" 15 #include "clk-regmap.h" 16 #include "s4-pll.h" 17 #include "meson-clkc-utils.h" 18 #include <dt-bindings/clock/amlogic,s4-pll-clkc.h> 19 20 static DEFINE_SPINLOCK(meson_clk_lock); 21 22 /* 23 * These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode. 24 * The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable 25 * in the kernel phase. Write of fixed PLL-related register will cause the system to crash. 26 * Meanwhile, these clock won't ever change at runtime. 27 * For the above reasons, we can only use ro_ops for fixed PLL related clocks. 28 */ 29 static struct clk_regmap s4_fixed_pll_dco = { 30 .data = &(struct meson_clk_pll_data){ 31 .en = { 32 .reg_off = ANACTRL_FIXPLL_CTRL0, 33 .shift = 28, 34 .width = 1, 35 }, 36 .m = { 37 .reg_off = ANACTRL_FIXPLL_CTRL0, 38 .shift = 0, 39 .width = 8, 40 }, 41 .frac = { 42 .reg_off = ANACTRL_FIXPLL_CTRL1, 43 .shift = 0, 44 .width = 17, 45 }, 46 .n = { 47 .reg_off = ANACTRL_FIXPLL_CTRL0, 48 .shift = 10, 49 .width = 5, 50 }, 51 .l = { 52 .reg_off = ANACTRL_FIXPLL_CTRL0, 53 .shift = 31, 54 .width = 1, 55 }, 56 .rst = { 57 .reg_off = ANACTRL_FIXPLL_CTRL0, 58 .shift = 29, 59 .width = 1, 60 }, 61 }, 62 .hw.init = &(struct clk_init_data){ 63 .name = "fixed_pll_dco", 64 .ops = &meson_clk_pll_ro_ops, 65 .parent_data = (const struct clk_parent_data []) { 66 { .fw_name = "xtal", } 67 }, 68 .num_parents = 1, 69 }, 70 }; 71 72 static struct clk_regmap s4_fixed_pll = { 73 .data = &(struct clk_regmap_div_data){ 74 .offset = ANACTRL_FIXPLL_CTRL0, 75 .shift = 16, 76 .width = 2, 77 .flags = CLK_DIVIDER_POWER_OF_TWO, 78 }, 79 .hw.init = &(struct clk_init_data){ 80 .name = "fixed_pll", 81 .ops = &clk_regmap_divider_ro_ops, 82 .parent_hws = (const struct clk_hw *[]) { 83 &s4_fixed_pll_dco.hw 84 }, 85 .num_parents = 1, 86 /* 87 * This clock won't ever change at runtime so 88 * CLK_SET_RATE_PARENT is not required 89 */ 90 }, 91 }; 92 93 static struct clk_fixed_factor s4_fclk_div2_div = { 94 .mult = 1, 95 .div = 2, 96 .hw.init = &(struct clk_init_data){ 97 .name = "fclk_div2_div", 98 .ops = &clk_fixed_factor_ops, 99 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, 100 .num_parents = 1, 101 }, 102 }; 103 104 static struct clk_regmap s4_fclk_div2 = { 105 .data = &(struct clk_regmap_gate_data){ 106 .offset = ANACTRL_FIXPLL_CTRL1, 107 .bit_idx = 24, 108 }, 109 .hw.init = &(struct clk_init_data){ 110 .name = "fclk_div2", 111 .ops = &clk_regmap_gate_ro_ops, 112 .parent_hws = (const struct clk_hw *[]) { 113 &s4_fclk_div2_div.hw 114 }, 115 .num_parents = 1, 116 }, 117 }; 118 119 static struct clk_fixed_factor s4_fclk_div3_div = { 120 .mult = 1, 121 .div = 3, 122 .hw.init = &(struct clk_init_data){ 123 .name = "fclk_div3_div", 124 .ops = &clk_fixed_factor_ops, 125 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, 126 .num_parents = 1, 127 }, 128 }; 129 130 static struct clk_regmap s4_fclk_div3 = { 131 .data = &(struct clk_regmap_gate_data){ 132 .offset = ANACTRL_FIXPLL_CTRL1, 133 .bit_idx = 20, 134 }, 135 .hw.init = &(struct clk_init_data){ 136 .name = "fclk_div3", 137 .ops = &clk_regmap_gate_ro_ops, 138 .parent_hws = (const struct clk_hw *[]) { 139 &s4_fclk_div3_div.hw 140 }, 141 .num_parents = 1, 142 }, 143 }; 144 145 static struct clk_fixed_factor s4_fclk_div4_div = { 146 .mult = 1, 147 .div = 4, 148 .hw.init = &(struct clk_init_data){ 149 .name = "fclk_div4_div", 150 .ops = &clk_fixed_factor_ops, 151 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, 152 .num_parents = 1, 153 }, 154 }; 155 156 static struct clk_regmap s4_fclk_div4 = { 157 .data = &(struct clk_regmap_gate_data){ 158 .offset = ANACTRL_FIXPLL_CTRL1, 159 .bit_idx = 21, 160 }, 161 .hw.init = &(struct clk_init_data){ 162 .name = "fclk_div4", 163 .ops = &clk_regmap_gate_ro_ops, 164 .parent_hws = (const struct clk_hw *[]) { 165 &s4_fclk_div4_div.hw 166 }, 167 .num_parents = 1, 168 }, 169 }; 170 171 static struct clk_fixed_factor s4_fclk_div5_div = { 172 .mult = 1, 173 .div = 5, 174 .hw.init = &(struct clk_init_data){ 175 .name = "fclk_div5_div", 176 .ops = &clk_fixed_factor_ops, 177 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, 178 .num_parents = 1, 179 }, 180 }; 181 182 static struct clk_regmap s4_fclk_div5 = { 183 .data = &(struct clk_regmap_gate_data){ 184 .offset = ANACTRL_FIXPLL_CTRL1, 185 .bit_idx = 22, 186 }, 187 .hw.init = &(struct clk_init_data){ 188 .name = "fclk_div5", 189 .ops = &clk_regmap_gate_ro_ops, 190 .parent_hws = (const struct clk_hw *[]) { 191 &s4_fclk_div5_div.hw 192 }, 193 .num_parents = 1, 194 }, 195 }; 196 197 static struct clk_fixed_factor s4_fclk_div7_div = { 198 .mult = 1, 199 .div = 7, 200 .hw.init = &(struct clk_init_data){ 201 .name = "fclk_div7_div", 202 .ops = &clk_fixed_factor_ops, 203 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw }, 204 .num_parents = 1, 205 }, 206 }; 207 208 static struct clk_regmap s4_fclk_div7 = { 209 .data = &(struct clk_regmap_gate_data){ 210 .offset = ANACTRL_FIXPLL_CTRL1, 211 .bit_idx = 23, 212 }, 213 .hw.init = &(struct clk_init_data){ 214 .name = "fclk_div7", 215 .ops = &clk_regmap_gate_ro_ops, 216 .parent_hws = (const struct clk_hw *[]) { 217 &s4_fclk_div7_div.hw 218 }, 219 .num_parents = 1, 220 }, 221 }; 222 223 static struct clk_fixed_factor s4_fclk_div2p5_div = { 224 .mult = 2, 225 .div = 5, 226 .hw.init = &(struct clk_init_data){ 227 .name = "fclk_div2p5_div", 228 .ops = &clk_fixed_factor_ops, 229 .parent_hws = (const struct clk_hw *[]) { 230 &s4_fixed_pll.hw 231 }, 232 .num_parents = 1, 233 }, 234 }; 235 236 static struct clk_regmap s4_fclk_div2p5 = { 237 .data = &(struct clk_regmap_gate_data){ 238 .offset = ANACTRL_FIXPLL_CTRL1, 239 .bit_idx = 25, 240 }, 241 .hw.init = &(struct clk_init_data){ 242 .name = "fclk_div2p5", 243 .ops = &clk_regmap_gate_ro_ops, 244 .parent_hws = (const struct clk_hw *[]) { 245 &s4_fclk_div2p5_div.hw 246 }, 247 .num_parents = 1, 248 }, 249 }; 250 251 static const struct pll_mult_range s4_gp0_pll_mult_range = { 252 .min = 125, 253 .max = 250, 254 }; 255 256 /* 257 * Internal gp0 pll emulation configuration parameters 258 */ 259 static const struct reg_sequence s4_gp0_init_regs[] = { 260 { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 }, 261 { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 }, 262 { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 }, 263 { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 }, 264 { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x39272000 }, 265 { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 } 266 }; 267 268 static struct clk_regmap s4_gp0_pll_dco = { 269 .data = &(struct meson_clk_pll_data){ 270 .en = { 271 .reg_off = ANACTRL_GP0PLL_CTRL0, 272 .shift = 28, 273 .width = 1, 274 }, 275 .m = { 276 .reg_off = ANACTRL_GP0PLL_CTRL0, 277 .shift = 0, 278 .width = 8, 279 }, 280 .n = { 281 .reg_off = ANACTRL_GP0PLL_CTRL0, 282 .shift = 10, 283 .width = 5, 284 }, 285 .l = { 286 .reg_off = ANACTRL_GP0PLL_CTRL0, 287 .shift = 31, 288 .width = 1, 289 }, 290 .rst = { 291 .reg_off = ANACTRL_GP0PLL_CTRL0, 292 .shift = 29, 293 .width = 1, 294 }, 295 .range = &s4_gp0_pll_mult_range, 296 .init_regs = s4_gp0_init_regs, 297 .init_count = ARRAY_SIZE(s4_gp0_init_regs), 298 }, 299 .hw.init = &(struct clk_init_data){ 300 .name = "gp0_pll_dco", 301 .ops = &meson_clk_pll_ops, 302 .parent_data = (const struct clk_parent_data []) { 303 { .fw_name = "xtal", } 304 }, 305 .num_parents = 1, 306 }, 307 }; 308 309 static struct clk_regmap s4_gp0_pll = { 310 .data = &(struct clk_regmap_div_data){ 311 .offset = ANACTRL_GP0PLL_CTRL0, 312 .shift = 16, 313 .width = 3, 314 .flags = (CLK_DIVIDER_POWER_OF_TWO | 315 CLK_DIVIDER_ROUND_CLOSEST), 316 }, 317 .hw.init = &(struct clk_init_data){ 318 .name = "gp0_pll", 319 .ops = &clk_regmap_divider_ops, 320 .parent_hws = (const struct clk_hw *[]) { 321 &s4_gp0_pll_dco.hw 322 }, 323 .num_parents = 1, 324 .flags = CLK_SET_RATE_PARENT, 325 }, 326 }; 327 328 /* 329 * Internal hifi pll emulation configuration parameters 330 */ 331 static const struct reg_sequence s4_hifi_init_regs[] = { 332 { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00010e56 }, 333 { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 }, 334 { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 }, 335 { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 }, 336 { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x39272000 }, 337 { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 } 338 }; 339 340 static struct clk_regmap s4_hifi_pll_dco = { 341 .data = &(struct meson_clk_pll_data){ 342 .en = { 343 .reg_off = ANACTRL_HIFIPLL_CTRL0, 344 .shift = 28, 345 .width = 1, 346 }, 347 .m = { 348 .reg_off = ANACTRL_HIFIPLL_CTRL0, 349 .shift = 0, 350 .width = 8, 351 }, 352 .n = { 353 .reg_off = ANACTRL_HIFIPLL_CTRL0, 354 .shift = 10, 355 .width = 5, 356 }, 357 .l = { 358 .reg_off = ANACTRL_HIFIPLL_CTRL0, 359 .shift = 31, 360 .width = 1, 361 }, 362 .rst = { 363 .reg_off = ANACTRL_HIFIPLL_CTRL0, 364 .shift = 29, 365 .width = 1, 366 }, 367 .range = &s4_gp0_pll_mult_range, 368 .init_regs = s4_hifi_init_regs, 369 .init_count = ARRAY_SIZE(s4_hifi_init_regs), 370 .flags = CLK_MESON_PLL_ROUND_CLOSEST, 371 }, 372 .hw.init = &(struct clk_init_data){ 373 .name = "hifi_pll_dco", 374 .ops = &meson_clk_pll_ops, 375 .parent_data = (const struct clk_parent_data []) { 376 { .fw_name = "xtal", } 377 }, 378 .num_parents = 1, 379 }, 380 }; 381 382 static struct clk_regmap s4_hifi_pll = { 383 .data = &(struct clk_regmap_div_data){ 384 .offset = ANACTRL_HIFIPLL_CTRL0, 385 .shift = 16, 386 .width = 2, 387 .flags = (CLK_DIVIDER_POWER_OF_TWO | 388 CLK_DIVIDER_ROUND_CLOSEST), 389 }, 390 .hw.init = &(struct clk_init_data){ 391 .name = "hifi_pll", 392 .ops = &clk_regmap_divider_ops, 393 .parent_hws = (const struct clk_hw *[]) { 394 &s4_hifi_pll_dco.hw 395 }, 396 .num_parents = 1, 397 .flags = CLK_SET_RATE_PARENT, 398 }, 399 }; 400 401 static struct clk_regmap s4_hdmi_pll_dco = { 402 .data = &(struct meson_clk_pll_data){ 403 .en = { 404 .reg_off = ANACTRL_HDMIPLL_CTRL0, 405 .shift = 28, 406 .width = 1, 407 }, 408 .m = { 409 .reg_off = ANACTRL_HDMIPLL_CTRL0, 410 .shift = 0, 411 .width = 8, 412 }, 413 .n = { 414 .reg_off = ANACTRL_HDMIPLL_CTRL0, 415 .shift = 10, 416 .width = 5, 417 }, 418 .l = { 419 .reg_off = ANACTRL_HDMIPLL_CTRL0, 420 .shift = 31, 421 .width = 1, 422 }, 423 .rst = { 424 .reg_off = ANACTRL_HDMIPLL_CTRL0, 425 .shift = 29, 426 .width = 1, 427 }, 428 .range = &s4_gp0_pll_mult_range, 429 }, 430 .hw.init = &(struct clk_init_data){ 431 .name = "hdmi_pll_dco", 432 .ops = &meson_clk_pll_ops, 433 .parent_data = (const struct clk_parent_data []) { 434 { .fw_name = "xtal", } 435 }, 436 .num_parents = 1, 437 }, 438 }; 439 440 static struct clk_regmap s4_hdmi_pll_od = { 441 .data = &(struct clk_regmap_div_data){ 442 .offset = ANACTRL_HDMIPLL_CTRL0, 443 .shift = 16, 444 .width = 4, 445 .flags = CLK_DIVIDER_POWER_OF_TWO, 446 }, 447 .hw.init = &(struct clk_init_data){ 448 .name = "hdmi_pll_od", 449 .ops = &clk_regmap_divider_ops, 450 .parent_hws = (const struct clk_hw *[]) { 451 &s4_hdmi_pll_dco.hw 452 }, 453 .num_parents = 1, 454 .flags = CLK_SET_RATE_PARENT, 455 }, 456 }; 457 458 static struct clk_regmap s4_hdmi_pll = { 459 .data = &(struct clk_regmap_div_data){ 460 .offset = ANACTRL_HDMIPLL_CTRL0, 461 .shift = 20, 462 .width = 2, 463 .flags = CLK_DIVIDER_POWER_OF_TWO, 464 }, 465 .hw.init = &(struct clk_init_data){ 466 .name = "hdmi_pll", 467 .ops = &clk_regmap_divider_ops, 468 .parent_hws = (const struct clk_hw *[]) { 469 &s4_hdmi_pll_od.hw 470 }, 471 .num_parents = 1, 472 .flags = CLK_SET_RATE_PARENT, 473 }, 474 }; 475 476 static struct clk_fixed_factor s4_mpll_50m_div = { 477 .mult = 1, 478 .div = 80, 479 .hw.init = &(struct clk_init_data){ 480 .name = "mpll_50m_div", 481 .ops = &clk_fixed_factor_ops, 482 .parent_hws = (const struct clk_hw *[]) { 483 &s4_fixed_pll_dco.hw 484 }, 485 .num_parents = 1, 486 }, 487 }; 488 489 static struct clk_regmap s4_mpll_50m = { 490 .data = &(struct clk_regmap_mux_data){ 491 .offset = ANACTRL_FIXPLL_CTRL3, 492 .mask = 0x1, 493 .shift = 5, 494 }, 495 .hw.init = &(struct clk_init_data){ 496 .name = "mpll_50m", 497 .ops = &clk_regmap_mux_ro_ops, 498 .parent_data = (const struct clk_parent_data []) { 499 { .fw_name = "xtal", }, 500 { .hw = &s4_mpll_50m_div.hw }, 501 }, 502 .num_parents = 2, 503 }, 504 }; 505 506 static struct clk_fixed_factor s4_mpll_prediv = { 507 .mult = 1, 508 .div = 2, 509 .hw.init = &(struct clk_init_data){ 510 .name = "mpll_prediv", 511 .ops = &clk_fixed_factor_ops, 512 .parent_hws = (const struct clk_hw *[]) { 513 &s4_fixed_pll_dco.hw 514 }, 515 .num_parents = 1, 516 }, 517 }; 518 519 static const struct reg_sequence s4_mpll0_init_regs[] = { 520 { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 } 521 }; 522 523 static struct clk_regmap s4_mpll0_div = { 524 .data = &(struct meson_clk_mpll_data){ 525 .sdm = { 526 .reg_off = ANACTRL_MPLL_CTRL1, 527 .shift = 0, 528 .width = 14, 529 }, 530 .sdm_en = { 531 .reg_off = ANACTRL_MPLL_CTRL1, 532 .shift = 30, 533 .width = 1, 534 }, 535 .n2 = { 536 .reg_off = ANACTRL_MPLL_CTRL1, 537 .shift = 20, 538 .width = 9, 539 }, 540 .ssen = { 541 .reg_off = ANACTRL_MPLL_CTRL1, 542 .shift = 29, 543 .width = 1, 544 }, 545 .lock = &meson_clk_lock, 546 .init_regs = s4_mpll0_init_regs, 547 .init_count = ARRAY_SIZE(s4_mpll0_init_regs), 548 }, 549 .hw.init = &(struct clk_init_data){ 550 .name = "mpll0_div", 551 .ops = &meson_clk_mpll_ops, 552 .parent_hws = (const struct clk_hw *[]) { 553 &s4_mpll_prediv.hw 554 }, 555 .num_parents = 1, 556 }, 557 }; 558 559 static struct clk_regmap s4_mpll0 = { 560 .data = &(struct clk_regmap_gate_data){ 561 .offset = ANACTRL_MPLL_CTRL1, 562 .bit_idx = 31, 563 }, 564 .hw.init = &(struct clk_init_data){ 565 .name = "mpll0", 566 .ops = &clk_regmap_gate_ops, 567 .parent_hws = (const struct clk_hw *[]) { &s4_mpll0_div.hw }, 568 .num_parents = 1, 569 .flags = CLK_SET_RATE_PARENT, 570 }, 571 }; 572 573 static const struct reg_sequence s4_mpll1_init_regs[] = { 574 { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 } 575 }; 576 577 static struct clk_regmap s4_mpll1_div = { 578 .data = &(struct meson_clk_mpll_data){ 579 .sdm = { 580 .reg_off = ANACTRL_MPLL_CTRL3, 581 .shift = 0, 582 .width = 14, 583 }, 584 .sdm_en = { 585 .reg_off = ANACTRL_MPLL_CTRL3, 586 .shift = 30, 587 .width = 1, 588 }, 589 .n2 = { 590 .reg_off = ANACTRL_MPLL_CTRL3, 591 .shift = 20, 592 .width = 9, 593 }, 594 .ssen = { 595 .reg_off = ANACTRL_MPLL_CTRL3, 596 .shift = 29, 597 .width = 1, 598 }, 599 .lock = &meson_clk_lock, 600 .init_regs = s4_mpll1_init_regs, 601 .init_count = ARRAY_SIZE(s4_mpll1_init_regs), 602 }, 603 .hw.init = &(struct clk_init_data){ 604 .name = "mpll1_div", 605 .ops = &meson_clk_mpll_ops, 606 .parent_hws = (const struct clk_hw *[]) { 607 &s4_mpll_prediv.hw 608 }, 609 .num_parents = 1, 610 }, 611 }; 612 613 static struct clk_regmap s4_mpll1 = { 614 .data = &(struct clk_regmap_gate_data){ 615 .offset = ANACTRL_MPLL_CTRL3, 616 .bit_idx = 31, 617 }, 618 .hw.init = &(struct clk_init_data){ 619 .name = "mpll1", 620 .ops = &clk_regmap_gate_ops, 621 .parent_hws = (const struct clk_hw *[]) { &s4_mpll1_div.hw }, 622 .num_parents = 1, 623 .flags = CLK_SET_RATE_PARENT, 624 }, 625 }; 626 627 static const struct reg_sequence s4_mpll2_init_regs[] = { 628 { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 } 629 }; 630 631 static struct clk_regmap s4_mpll2_div = { 632 .data = &(struct meson_clk_mpll_data){ 633 .sdm = { 634 .reg_off = ANACTRL_MPLL_CTRL5, 635 .shift = 0, 636 .width = 14, 637 }, 638 .sdm_en = { 639 .reg_off = ANACTRL_MPLL_CTRL5, 640 .shift = 30, 641 .width = 1, 642 }, 643 .n2 = { 644 .reg_off = ANACTRL_MPLL_CTRL5, 645 .shift = 20, 646 .width = 9, 647 }, 648 .ssen = { 649 .reg_off = ANACTRL_MPLL_CTRL5, 650 .shift = 29, 651 .width = 1, 652 }, 653 .lock = &meson_clk_lock, 654 .init_regs = s4_mpll2_init_regs, 655 .init_count = ARRAY_SIZE(s4_mpll2_init_regs), 656 }, 657 .hw.init = &(struct clk_init_data){ 658 .name = "mpll2_div", 659 .ops = &meson_clk_mpll_ops, 660 .parent_hws = (const struct clk_hw *[]) { 661 &s4_mpll_prediv.hw 662 }, 663 .num_parents = 1, 664 }, 665 }; 666 667 static struct clk_regmap s4_mpll2 = { 668 .data = &(struct clk_regmap_gate_data){ 669 .offset = ANACTRL_MPLL_CTRL5, 670 .bit_idx = 31, 671 }, 672 .hw.init = &(struct clk_init_data){ 673 .name = "mpll2", 674 .ops = &clk_regmap_gate_ops, 675 .parent_hws = (const struct clk_hw *[]) { &s4_mpll2_div.hw }, 676 .num_parents = 1, 677 .flags = CLK_SET_RATE_PARENT, 678 }, 679 }; 680 681 static const struct reg_sequence s4_mpll3_init_regs[] = { 682 { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 } 683 }; 684 685 static struct clk_regmap s4_mpll3_div = { 686 .data = &(struct meson_clk_mpll_data){ 687 .sdm = { 688 .reg_off = ANACTRL_MPLL_CTRL7, 689 .shift = 0, 690 .width = 14, 691 }, 692 .sdm_en = { 693 .reg_off = ANACTRL_MPLL_CTRL7, 694 .shift = 30, 695 .width = 1, 696 }, 697 .n2 = { 698 .reg_off = ANACTRL_MPLL_CTRL7, 699 .shift = 20, 700 .width = 9, 701 }, 702 .ssen = { 703 .reg_off = ANACTRL_MPLL_CTRL7, 704 .shift = 29, 705 .width = 1, 706 }, 707 .lock = &meson_clk_lock, 708 .init_regs = s4_mpll3_init_regs, 709 .init_count = ARRAY_SIZE(s4_mpll3_init_regs), 710 }, 711 .hw.init = &(struct clk_init_data){ 712 .name = "mpll3_div", 713 .ops = &meson_clk_mpll_ops, 714 .parent_hws = (const struct clk_hw *[]) { 715 &s4_mpll_prediv.hw 716 }, 717 .num_parents = 1, 718 }, 719 }; 720 721 static struct clk_regmap s4_mpll3 = { 722 .data = &(struct clk_regmap_gate_data){ 723 .offset = ANACTRL_MPLL_CTRL7, 724 .bit_idx = 31, 725 }, 726 .hw.init = &(struct clk_init_data){ 727 .name = "mpll3", 728 .ops = &clk_regmap_gate_ops, 729 .parent_hws = (const struct clk_hw *[]) { &s4_mpll3_div.hw }, 730 .num_parents = 1, 731 .flags = CLK_SET_RATE_PARENT, 732 }, 733 }; 734 735 /* Array of all clocks provided by this provider */ 736 static struct clk_hw *s4_pll_hw_clks[] = { 737 [CLKID_FIXED_PLL_DCO] = &s4_fixed_pll_dco.hw, 738 [CLKID_FIXED_PLL] = &s4_fixed_pll.hw, 739 [CLKID_FCLK_DIV2_DIV] = &s4_fclk_div2_div.hw, 740 [CLKID_FCLK_DIV2] = &s4_fclk_div2.hw, 741 [CLKID_FCLK_DIV3_DIV] = &s4_fclk_div3_div.hw, 742 [CLKID_FCLK_DIV3] = &s4_fclk_div3.hw, 743 [CLKID_FCLK_DIV4_DIV] = &s4_fclk_div4_div.hw, 744 [CLKID_FCLK_DIV4] = &s4_fclk_div4.hw, 745 [CLKID_FCLK_DIV5_DIV] = &s4_fclk_div5_div.hw, 746 [CLKID_FCLK_DIV5] = &s4_fclk_div5.hw, 747 [CLKID_FCLK_DIV7_DIV] = &s4_fclk_div7_div.hw, 748 [CLKID_FCLK_DIV7] = &s4_fclk_div7.hw, 749 [CLKID_FCLK_DIV2P5_DIV] = &s4_fclk_div2p5_div.hw, 750 [CLKID_FCLK_DIV2P5] = &s4_fclk_div2p5.hw, 751 [CLKID_GP0_PLL_DCO] = &s4_gp0_pll_dco.hw, 752 [CLKID_GP0_PLL] = &s4_gp0_pll.hw, 753 [CLKID_HIFI_PLL_DCO] = &s4_hifi_pll_dco.hw, 754 [CLKID_HIFI_PLL] = &s4_hifi_pll.hw, 755 [CLKID_HDMI_PLL_DCO] = &s4_hdmi_pll_dco.hw, 756 [CLKID_HDMI_PLL_OD] = &s4_hdmi_pll_od.hw, 757 [CLKID_HDMI_PLL] = &s4_hdmi_pll.hw, 758 [CLKID_MPLL_50M_DIV] = &s4_mpll_50m_div.hw, 759 [CLKID_MPLL_50M] = &s4_mpll_50m.hw, 760 [CLKID_MPLL_PREDIV] = &s4_mpll_prediv.hw, 761 [CLKID_MPLL0_DIV] = &s4_mpll0_div.hw, 762 [CLKID_MPLL0] = &s4_mpll0.hw, 763 [CLKID_MPLL1_DIV] = &s4_mpll1_div.hw, 764 [CLKID_MPLL1] = &s4_mpll1.hw, 765 [CLKID_MPLL2_DIV] = &s4_mpll2_div.hw, 766 [CLKID_MPLL2] = &s4_mpll2.hw, 767 [CLKID_MPLL3_DIV] = &s4_mpll3_div.hw, 768 [CLKID_MPLL3] = &s4_mpll3.hw, 769 }; 770 771 static struct clk_regmap *const s4_pll_clk_regmaps[] = { 772 &s4_fixed_pll_dco, 773 &s4_fixed_pll, 774 &s4_fclk_div2, 775 &s4_fclk_div3, 776 &s4_fclk_div4, 777 &s4_fclk_div5, 778 &s4_fclk_div7, 779 &s4_fclk_div2p5, 780 &s4_gp0_pll_dco, 781 &s4_gp0_pll, 782 &s4_hifi_pll_dco, 783 &s4_hifi_pll, 784 &s4_hdmi_pll_dco, 785 &s4_hdmi_pll_od, 786 &s4_hdmi_pll, 787 &s4_mpll_50m, 788 &s4_mpll0_div, 789 &s4_mpll0, 790 &s4_mpll1_div, 791 &s4_mpll1, 792 &s4_mpll2_div, 793 &s4_mpll2, 794 &s4_mpll3_div, 795 &s4_mpll3, 796 }; 797 798 static const struct reg_sequence s4_init_regs[] = { 799 { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 }, 800 }; 801 802 static struct regmap_config clkc_regmap_config = { 803 .reg_bits = 32, 804 .val_bits = 32, 805 .reg_stride = 4, 806 .max_register = ANACTRL_HDMIPLL_CTRL0, 807 }; 808 809 static struct meson_clk_hw_data s4_pll_clks = { 810 .hws = s4_pll_hw_clks, 811 .num = ARRAY_SIZE(s4_pll_hw_clks), 812 }; 813 814 static int meson_s4_pll_probe(struct platform_device *pdev) 815 { 816 struct device *dev = &pdev->dev; 817 struct regmap *regmap; 818 void __iomem *base; 819 int ret, i; 820 821 base = devm_platform_ioremap_resource(pdev, 0); 822 if (IS_ERR(base)) 823 return dev_err_probe(dev, PTR_ERR(base), 824 "can't ioremap resource\n"); 825 826 regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config); 827 if (IS_ERR(regmap)) 828 return dev_err_probe(dev, PTR_ERR(regmap), 829 "can't init regmap mmio region\n"); 830 831 ret = regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_regs)); 832 if (ret) 833 return dev_err_probe(dev, ret, 834 "Failed to init registers\n"); 835 836 /* Populate regmap for the regmap backed clocks */ 837 for (i = 0; i < ARRAY_SIZE(s4_pll_clk_regmaps); i++) 838 s4_pll_clk_regmaps[i]->map = regmap; 839 840 /* Register clocks */ 841 for (i = 0; i < s4_pll_clks.num; i++) { 842 /* array might be sparse */ 843 if (!s4_pll_clks.hws[i]) 844 continue; 845 846 ret = devm_clk_hw_register(dev, s4_pll_clks.hws[i]); 847 if (ret) 848 return dev_err_probe(dev, ret, 849 "clock[%d] registration failed\n", i); 850 } 851 852 return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, 853 &s4_pll_clks); 854 } 855 856 static const struct of_device_id clkc_match_table[] = { 857 { 858 .compatible = "amlogic,s4-pll-clkc", 859 }, 860 {} 861 }; 862 MODULE_DEVICE_TABLE(of, clkc_match_table); 863 864 static struct platform_driver s4_driver = { 865 .probe = meson_s4_pll_probe, 866 .driver = { 867 .name = "s4-pll-clkc", 868 .of_match_table = clkc_match_table, 869 }, 870 }; 871 module_platform_driver(s4_driver); 872 873 MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); 874 MODULE_AUTHOR("Yu Tu <yu.tu@amlogic.com>"); 875 MODULE_LICENSE("GPL"); 876