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