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