1 // SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2 /* 3 * Copyright (C) 2024-2025 Amlogic, Inc. All rights reserved. 4 * Author: Jian Hu <jian.hu@amlogic.com> 5 */ 6 7 #include <linux/clk-provider.h> 8 #include <linux/platform_device.h> 9 #include "clk-regmap.h" 10 #include "clk-pll.h" 11 #include "clk-mpll.h" 12 #include "meson-clkc-utils.h" 13 #include <dt-bindings/clock/amlogic,t7-pll-clkc.h> 14 15 #define GP0PLL_CTRL0 0x00 16 #define GP0PLL_CTRL1 0x04 17 #define GP0PLL_CTRL2 0x08 18 #define GP0PLL_CTRL3 0x0c 19 #define GP0PLL_CTRL4 0x10 20 #define GP0PLL_CTRL5 0x14 21 #define GP0PLL_CTRL6 0x18 22 #define GP0PLL_STS 0x1c 23 24 #define GP1PLL_CTRL0 0x00 25 #define GP1PLL_CTRL1 0x04 26 #define GP1PLL_CTRL2 0x08 27 #define GP1PLL_CTRL3 0x0c 28 #define GP1PLL_STS 0x1c 29 30 #define HIFIPLL_CTRL0 0x00 31 #define HIFIPLL_CTRL1 0x04 32 #define HIFIPLL_CTRL2 0x08 33 #define HIFIPLL_CTRL3 0x0c 34 #define HIFIPLL_CTRL4 0x10 35 #define HIFIPLL_CTRL5 0x14 36 #define HIFIPLL_CTRL6 0x18 37 #define HIFIPLL_STS 0x1c 38 39 #define PCIEPLL_CTRL0 0x00 40 #define PCIEPLL_CTRL1 0x04 41 #define PCIEPLL_CTRL2 0x08 42 #define PCIEPLL_CTRL3 0x0c 43 #define PCIEPLL_CTRL4 0x10 44 #define PCIEPLL_CTRL5 0x14 45 #define PCIEPLL_STS 0x18 46 47 #define MPLL_CTRL0 0x00 48 #define MPLL_CTRL1 0x04 49 #define MPLL_CTRL2 0x08 50 #define MPLL_CTRL3 0x0c 51 #define MPLL_CTRL4 0x10 52 #define MPLL_CTRL5 0x14 53 #define MPLL_CTRL6 0x18 54 #define MPLL_CTRL7 0x1c 55 #define MPLL_CTRL8 0x20 56 #define MPLL_STS 0x24 57 58 #define HDMIPLL_CTRL0 0x00 59 #define HDMIPLL_CTRL1 0x04 60 #define HDMIPLL_CTRL2 0x08 61 #define HDMIPLL_CTRL3 0x0c 62 #define HDMIPLL_CTRL4 0x10 63 #define HDMIPLL_CTRL5 0x14 64 #define HDMIPLL_CTRL6 0x18 65 #define HDMIPLL_STS 0x1c 66 67 #define MCLK_PLL_CNTL0 0x00 68 #define MCLK_PLL_CNTL1 0x04 69 #define MCLK_PLL_CNTL2 0x08 70 #define MCLK_PLL_CNTL3 0x0c 71 #define MCLK_PLL_CNTL4 0x10 72 #define MCLK_PLL_STS 0x14 73 74 static const struct pll_mult_range t7_media_pll_mult_range = { 75 .min = 125, 76 .max = 250, 77 }; 78 79 static const struct reg_sequence t7_gp0_init_regs[] = { 80 { .reg = GP0PLL_CTRL1, .def = 0x00000000 }, 81 { .reg = GP0PLL_CTRL2, .def = 0x00000000 }, 82 { .reg = GP0PLL_CTRL3, .def = 0x48681c00 }, 83 { .reg = GP0PLL_CTRL4, .def = 0x88770290 }, 84 { .reg = GP0PLL_CTRL5, .def = 0x3927200a }, 85 { .reg = GP0PLL_CTRL6, .def = 0x56540000 }, 86 }; 87 88 static struct clk_regmap t7_gp0_pll_dco = { 89 .data = &(struct meson_clk_pll_data){ 90 .en = { 91 .reg_off = GP0PLL_CTRL0, 92 .shift = 28, 93 .width = 1, 94 }, 95 .m = { 96 .reg_off = GP0PLL_CTRL0, 97 .shift = 0, 98 .width = 8, 99 }, 100 .n = { 101 .reg_off = GP0PLL_CTRL0, 102 .shift = 10, 103 .width = 5, 104 }, 105 .l = { 106 .reg_off = GP0PLL_STS, 107 .shift = 31, 108 .width = 1, 109 }, 110 .rst = { 111 .reg_off = GP0PLL_CTRL0, 112 .shift = 29, 113 .width = 1, 114 }, 115 .range = &t7_media_pll_mult_range, 116 .init_regs = t7_gp0_init_regs, 117 .init_count = ARRAY_SIZE(t7_gp0_init_regs), 118 }, 119 .hw.init = &(struct clk_init_data){ 120 .name = "gp0_pll_dco", 121 .ops = &meson_clk_pll_ops, 122 .parent_data = &(const struct clk_parent_data) { 123 .fw_name = "in0", 124 }, 125 .num_parents = 1, 126 }, 127 }; 128 129 static struct clk_regmap t7_gp0_pll = { 130 .data = &(struct clk_regmap_div_data){ 131 .offset = GP0PLL_CTRL0, 132 .shift = 16, 133 .width = 3, 134 .flags = CLK_DIVIDER_POWER_OF_TWO, 135 }, 136 .hw.init = &(struct clk_init_data) { 137 .name = "gp0_pll", 138 .ops = &clk_regmap_divider_ops, 139 .parent_hws = (const struct clk_hw *[]) { 140 &t7_gp0_pll_dco.hw 141 }, 142 .num_parents = 1, 143 .flags = CLK_SET_RATE_PARENT, 144 }, 145 }; 146 147 /* 148 * Compared with GP0 PLL, GP1 PLL is a newly designed PLL with 149 * a DCO range of 1.6GHz to 3.2GHz. 150 */ 151 static const struct pll_mult_range t7_gp1_pll_mult_range = { 152 .min = 67, 153 .max = 133, 154 }; 155 156 static const struct reg_sequence t7_gp1_init_regs[] = { 157 { .reg = GP1PLL_CTRL1, .def = 0x1420500f }, 158 { .reg = GP1PLL_CTRL2, .def = 0x00023001 }, 159 { .reg = GP1PLL_CTRL3, .def = 0x00000000 }, 160 }; 161 162 static struct clk_regmap t7_gp1_pll_dco = { 163 .data = &(struct meson_clk_pll_data){ 164 .en = { 165 .reg_off = GP1PLL_CTRL0, 166 .shift = 28, 167 .width = 1, 168 }, 169 .m = { 170 .reg_off = GP1PLL_CTRL0, 171 .shift = 0, 172 .width = 8, 173 }, 174 .n = { 175 .reg_off = GP1PLL_CTRL0, 176 .shift = 16, 177 .width = 5, 178 }, 179 .l = { 180 .reg_off = GP1PLL_STS, 181 .shift = 31, 182 .width = 1, 183 }, 184 .rst = { 185 .reg_off = GP1PLL_CTRL0, 186 .shift = 29, 187 .width = 1, 188 }, 189 .range = &t7_gp1_pll_mult_range, 190 .init_regs = t7_gp1_init_regs, 191 .init_count = ARRAY_SIZE(t7_gp1_init_regs), 192 }, 193 .hw.init = &(struct clk_init_data){ 194 .name = "gp1_pll_dco", 195 .ops = &meson_clk_pll_ops, 196 .parent_data = &(const struct clk_parent_data) { 197 .fw_name = "in0", 198 }, 199 .num_parents = 1, 200 }, 201 }; 202 203 static struct clk_regmap t7_gp1_pll = { 204 .data = &(struct clk_regmap_div_data){ 205 .offset = GP1PLL_CTRL0, 206 .shift = 12, 207 .width = 3, 208 .flags = CLK_DIVIDER_POWER_OF_TWO, 209 }, 210 .hw.init = &(struct clk_init_data) { 211 .name = "gp1_pll", 212 .ops = &clk_regmap_divider_ops, 213 .parent_hws = (const struct clk_hw *[]) { 214 &t7_gp1_pll_dco.hw 215 }, 216 .num_parents = 1, 217 .flags = CLK_SET_RATE_PARENT, 218 }, 219 }; 220 221 static const struct reg_sequence t7_hifi_init_regs[] = { 222 { .reg = HIFIPLL_CTRL1, .def = 0x00000000 }, 223 { .reg = HIFIPLL_CTRL2, .def = 0x00000000 }, 224 { .reg = HIFIPLL_CTRL3, .def = 0x6a285c00 }, 225 { .reg = HIFIPLL_CTRL4, .def = 0x65771290 }, 226 { .reg = HIFIPLL_CTRL5, .def = 0x3927200a }, 227 { .reg = HIFIPLL_CTRL6, .def = 0x56540000 } 228 }; 229 230 static struct clk_regmap t7_hifi_pll_dco = { 231 .data = &(struct meson_clk_pll_data){ 232 .en = { 233 .reg_off = HIFIPLL_CTRL0, 234 .shift = 28, 235 .width = 1, 236 }, 237 .m = { 238 .reg_off = HIFIPLL_CTRL0, 239 .shift = 0, 240 .width = 8, 241 }, 242 .n = { 243 .reg_off = HIFIPLL_CTRL0, 244 .shift = 10, 245 .width = 5, 246 }, 247 .frac = { 248 .reg_off = HIFIPLL_CTRL1, 249 .shift = 0, 250 .width = 17, 251 }, 252 .l = { 253 .reg_off = HIFIPLL_STS, 254 .shift = 31, 255 .width = 1, 256 }, 257 .rst = { 258 .reg_off = HIFIPLL_CTRL0, 259 .shift = 29, 260 .width = 1, 261 }, 262 .range = &t7_media_pll_mult_range, 263 .init_regs = t7_hifi_init_regs, 264 .init_count = ARRAY_SIZE(t7_hifi_init_regs), 265 .frac_max = 100000, 266 }, 267 .hw.init = &(struct clk_init_data){ 268 .name = "hifi_pll_dco", 269 .ops = &meson_clk_pll_ops, 270 .parent_data = &(const struct clk_parent_data) { 271 .fw_name = "in0", 272 }, 273 .num_parents = 1, 274 }, 275 }; 276 277 static struct clk_regmap t7_hifi_pll = { 278 .data = &(struct clk_regmap_div_data){ 279 .offset = HIFIPLL_CTRL0, 280 .shift = 16, 281 .width = 2, 282 .flags = CLK_DIVIDER_POWER_OF_TWO, 283 }, 284 .hw.init = &(struct clk_init_data) { 285 .name = "hifi_pll", 286 .ops = &clk_regmap_divider_ops, 287 .parent_hws = (const struct clk_hw *[]) { 288 &t7_hifi_pll_dco.hw 289 }, 290 .num_parents = 1, 291 .flags = CLK_SET_RATE_PARENT, 292 }, 293 }; 294 295 /* 296 * The T7 PCIE PLL is fined tuned to deliver a very precise 297 * 100MHz reference clock for the PCIe Analog PHY, and thus requires 298 * a strict register sequence to enable the PLL. 299 */ 300 static const struct reg_sequence t7_pcie_pll_init_regs[] = { 301 { .reg = PCIEPLL_CTRL0, .def = 0x200c04c8 }, 302 { .reg = PCIEPLL_CTRL0, .def = 0x300c04c8 }, 303 { .reg = PCIEPLL_CTRL1, .def = 0x30000000 }, 304 { .reg = PCIEPLL_CTRL2, .def = 0x00001100 }, 305 { .reg = PCIEPLL_CTRL3, .def = 0x10058e00 }, 306 { .reg = PCIEPLL_CTRL4, .def = 0x000100c0 }, 307 { .reg = PCIEPLL_CTRL5, .def = 0x68000048 }, 308 { .reg = PCIEPLL_CTRL5, .def = 0x68000068, .delay_us = 20 }, 309 { .reg = PCIEPLL_CTRL4, .def = 0x008100c0, .delay_us = 20 }, 310 { .reg = PCIEPLL_CTRL0, .def = 0x340c04c8 }, 311 { .reg = PCIEPLL_CTRL0, .def = 0x140c04c8, .delay_us = 20 }, 312 { .reg = PCIEPLL_CTRL2, .def = 0x00001000 } 313 }; 314 315 static struct clk_regmap t7_pcie_pll_dco = { 316 .data = &(struct meson_clk_pll_data){ 317 .en = { 318 .reg_off = PCIEPLL_CTRL0, 319 .shift = 28, 320 .width = 1, 321 }, 322 .m = { 323 .reg_off = PCIEPLL_CTRL0, 324 .shift = 0, 325 .width = 8, 326 }, 327 .n = { 328 .reg_off = PCIEPLL_CTRL0, 329 .shift = 10, 330 .width = 5, 331 }, 332 .l = { 333 .reg_off = PCIEPLL_CTRL0, 334 .shift = 31, 335 .width = 1, 336 }, 337 .rst = { 338 .reg_off = PCIEPLL_CTRL0, 339 .shift = 29, 340 .width = 1, 341 }, 342 .init_regs = t7_pcie_pll_init_regs, 343 .init_count = ARRAY_SIZE(t7_pcie_pll_init_regs), 344 }, 345 .hw.init = &(struct clk_init_data){ 346 .name = "pcie_pll_dco", 347 .ops = &meson_clk_pcie_pll_ops, 348 .parent_data = &(const struct clk_parent_data) { 349 .fw_name = "in0", 350 }, 351 .num_parents = 1, 352 }, 353 }; 354 355 static struct clk_fixed_factor t7_pcie_pll_dco_div2 = { 356 .mult = 1, 357 .div = 2, 358 .hw.init = &(struct clk_init_data){ 359 .name = "pcie_pll_dco_div2", 360 .ops = &clk_fixed_factor_ops, 361 .parent_hws = (const struct clk_hw *[]) { 362 &t7_pcie_pll_dco.hw 363 }, 364 .num_parents = 1, 365 .flags = CLK_SET_RATE_PARENT, 366 }, 367 }; 368 369 static struct clk_regmap t7_pcie_pll_od = { 370 .data = &(struct clk_regmap_div_data){ 371 .offset = PCIEPLL_CTRL0, 372 .shift = 16, 373 .width = 5, 374 /* the divisor is 32 when [16:21] = 0 */ 375 .flags = CLK_DIVIDER_MAX_AT_ZERO, 376 }, 377 .hw.init = &(struct clk_init_data){ 378 .name = "pcie_pll_od", 379 .ops = &clk_regmap_divider_ops, 380 .parent_hws = (const struct clk_hw *[]) { 381 &t7_pcie_pll_dco_div2.hw 382 }, 383 .num_parents = 1, 384 .flags = CLK_SET_RATE_PARENT, 385 }, 386 }; 387 388 static struct clk_fixed_factor t7_pcie_pll = { 389 .mult = 1, 390 .div = 2, 391 .hw.init = &(struct clk_init_data){ 392 .name = "pcie_pll", 393 .ops = &clk_fixed_factor_ops, 394 .parent_hws = (const struct clk_hw *[]) { 395 &t7_pcie_pll_od.hw 396 }, 397 .num_parents = 1, 398 .flags = CLK_SET_RATE_PARENT, 399 }, 400 }; 401 402 static struct clk_fixed_factor t7_mpll_prediv = { 403 .mult = 1, 404 .div = 2, 405 .hw.init = &(struct clk_init_data){ 406 .name = "mpll_prediv", 407 .ops = &clk_fixed_factor_ops, 408 .parent_data = &(const struct clk_parent_data) { 409 .fw_name = "in0", 410 }, 411 .num_parents = 1, 412 }, 413 }; 414 415 static const struct reg_sequence t7_mpll0_init_regs[] = { 416 { .reg = MPLL_CTRL2, .def = 0x40000033 } 417 }; 418 419 static struct clk_regmap t7_mpll0_div = { 420 .data = &(struct meson_clk_mpll_data){ 421 .sdm = { 422 .reg_off = MPLL_CTRL1, 423 .shift = 0, 424 .width = 14, 425 }, 426 .sdm_en = { 427 .reg_off = MPLL_CTRL1, 428 .shift = 30, 429 .width = 1, 430 }, 431 .n2 = { 432 .reg_off = MPLL_CTRL1, 433 .shift = 20, 434 .width = 9, 435 }, 436 .ssen = { 437 .reg_off = MPLL_CTRL1, 438 .shift = 29, 439 .width = 1, 440 }, 441 .init_regs = t7_mpll0_init_regs, 442 .init_count = ARRAY_SIZE(t7_mpll0_init_regs), 443 }, 444 .hw.init = &(struct clk_init_data){ 445 .name = "mpll0_div", 446 .ops = &meson_clk_mpll_ops, 447 .parent_hws = (const struct clk_hw *[]) { 448 &t7_mpll_prediv.hw 449 }, 450 .num_parents = 1, 451 }, 452 }; 453 454 static struct clk_regmap t7_mpll0 = { 455 .data = &(struct clk_regmap_gate_data){ 456 .offset = MPLL_CTRL1, 457 .bit_idx = 31, 458 }, 459 .hw.init = &(struct clk_init_data){ 460 .name = "mpll0", 461 .ops = &clk_regmap_gate_ops, 462 .parent_hws = (const struct clk_hw *[]) { &t7_mpll0_div.hw }, 463 .num_parents = 1, 464 .flags = CLK_SET_RATE_PARENT, 465 }, 466 }; 467 468 static const struct reg_sequence t7_mpll1_init_regs[] = { 469 { .reg = MPLL_CTRL4, .def = 0x40000033 } 470 }; 471 472 static struct clk_regmap t7_mpll1_div = { 473 .data = &(struct meson_clk_mpll_data){ 474 .sdm = { 475 .reg_off = MPLL_CTRL3, 476 .shift = 0, 477 .width = 14, 478 }, 479 .sdm_en = { 480 .reg_off = MPLL_CTRL3, 481 .shift = 30, 482 .width = 1, 483 }, 484 .n2 = { 485 .reg_off = MPLL_CTRL3, 486 .shift = 20, 487 .width = 9, 488 }, 489 .ssen = { 490 .reg_off = MPLL_CTRL3, 491 .shift = 29, 492 .width = 1, 493 }, 494 .init_regs = t7_mpll1_init_regs, 495 .init_count = ARRAY_SIZE(t7_mpll1_init_regs), 496 }, 497 .hw.init = &(struct clk_init_data){ 498 .name = "mpll1_div", 499 .ops = &meson_clk_mpll_ops, 500 .parent_hws = (const struct clk_hw *[]) { 501 &t7_mpll_prediv.hw 502 }, 503 .num_parents = 1, 504 }, 505 }; 506 507 static struct clk_regmap t7_mpll1 = { 508 .data = &(struct clk_regmap_gate_data){ 509 .offset = MPLL_CTRL3, 510 .bit_idx = 31, 511 }, 512 .hw.init = &(struct clk_init_data){ 513 .name = "mpll1", 514 .ops = &clk_regmap_gate_ops, 515 .parent_hws = (const struct clk_hw *[]) { &t7_mpll1_div.hw }, 516 .num_parents = 1, 517 .flags = CLK_SET_RATE_PARENT, 518 }, 519 }; 520 521 static const struct reg_sequence t7_mpll2_init_regs[] = { 522 { .reg = MPLL_CTRL6, .def = 0x40000033 } 523 }; 524 525 static struct clk_regmap t7_mpll2_div = { 526 .data = &(struct meson_clk_mpll_data){ 527 .sdm = { 528 .reg_off = MPLL_CTRL5, 529 .shift = 0, 530 .width = 14, 531 }, 532 .sdm_en = { 533 .reg_off = MPLL_CTRL5, 534 .shift = 30, 535 .width = 1, 536 }, 537 .n2 = { 538 .reg_off = MPLL_CTRL5, 539 .shift = 20, 540 .width = 9, 541 }, 542 .ssen = { 543 .reg_off = MPLL_CTRL5, 544 .shift = 29, 545 .width = 1, 546 }, 547 .init_regs = t7_mpll2_init_regs, 548 .init_count = ARRAY_SIZE(t7_mpll2_init_regs), 549 }, 550 .hw.init = &(struct clk_init_data){ 551 .name = "mpll2_div", 552 .ops = &meson_clk_mpll_ops, 553 .parent_hws = (const struct clk_hw *[]) { 554 &t7_mpll_prediv.hw 555 }, 556 .num_parents = 1, 557 }, 558 }; 559 560 static struct clk_regmap t7_mpll2 = { 561 .data = &(struct clk_regmap_gate_data){ 562 .offset = MPLL_CTRL5, 563 .bit_idx = 31, 564 }, 565 .hw.init = &(struct clk_init_data){ 566 .name = "mpll2", 567 .ops = &clk_regmap_gate_ops, 568 .parent_hws = (const struct clk_hw *[]) { &t7_mpll2_div.hw }, 569 .num_parents = 1, 570 .flags = CLK_SET_RATE_PARENT, 571 }, 572 }; 573 574 static const struct reg_sequence t7_mpll3_init_regs[] = { 575 { .reg = MPLL_CTRL8, .def = 0x40000033 } 576 }; 577 578 static struct clk_regmap t7_mpll3_div = { 579 .data = &(struct meson_clk_mpll_data){ 580 .sdm = { 581 .reg_off = MPLL_CTRL7, 582 .shift = 0, 583 .width = 14, 584 }, 585 .sdm_en = { 586 .reg_off = MPLL_CTRL7, 587 .shift = 30, 588 .width = 1, 589 }, 590 .n2 = { 591 .reg_off = MPLL_CTRL7, 592 .shift = 20, 593 .width = 9, 594 }, 595 .ssen = { 596 .reg_off = MPLL_CTRL7, 597 .shift = 29, 598 .width = 1, 599 }, 600 .init_regs = t7_mpll3_init_regs, 601 .init_count = ARRAY_SIZE(t7_mpll3_init_regs), 602 }, 603 .hw.init = &(struct clk_init_data){ 604 .name = "mpll3_div", 605 .ops = &meson_clk_mpll_ops, 606 .parent_hws = (const struct clk_hw *[]) { 607 &t7_mpll_prediv.hw 608 }, 609 .num_parents = 1, 610 }, 611 }; 612 613 static struct clk_regmap t7_mpll3 = { 614 .data = &(struct clk_regmap_gate_data){ 615 .offset = MPLL_CTRL7, 616 .bit_idx = 31, 617 }, 618 .hw.init = &(struct clk_init_data){ 619 .name = "mpll3", 620 .ops = &clk_regmap_gate_ops, 621 .parent_hws = (const struct clk_hw *[]) { &t7_mpll3_div.hw }, 622 .num_parents = 1, 623 .flags = CLK_SET_RATE_PARENT, 624 }, 625 }; 626 627 static const struct reg_sequence t7_hdmi_init_regs[] = { 628 { .reg = HDMIPLL_CTRL1, .def = 0x00000000 }, 629 { .reg = HDMIPLL_CTRL2, .def = 0x00000000 }, 630 { .reg = HDMIPLL_CTRL3, .def = 0x6a28dc00 }, 631 { .reg = HDMIPLL_CTRL4, .def = 0x65771290 }, 632 { .reg = HDMIPLL_CTRL5, .def = 0x39272000 }, 633 { .reg = HDMIPLL_CTRL6, .def = 0x56540000 } 634 }; 635 636 static struct clk_regmap t7_hdmi_pll_dco = { 637 .data = &(struct meson_clk_pll_data){ 638 .en = { 639 .reg_off = HDMIPLL_CTRL0, 640 .shift = 28, 641 .width = 1, 642 }, 643 .m = { 644 .reg_off = HDMIPLL_CTRL0, 645 .shift = 0, 646 .width = 9, 647 }, 648 .n = { 649 .reg_off = HDMIPLL_CTRL0, 650 .shift = 10, 651 .width = 5, 652 }, 653 .l = { 654 .reg_off = HDMIPLL_CTRL0, 655 .shift = 31, 656 .width = 1, 657 }, 658 .rst = { 659 .reg_off = HDMIPLL_CTRL0, 660 .shift = 29, 661 .width = 1, 662 }, 663 .range = &t7_media_pll_mult_range, 664 .init_regs = t7_hdmi_init_regs, 665 .init_count = ARRAY_SIZE(t7_hdmi_init_regs), 666 }, 667 .hw.init = &(struct clk_init_data){ 668 .name = "hdmi_pll_dco", 669 .ops = &meson_clk_pll_ops, 670 .parent_data = (const struct clk_parent_data []) { 671 { .fw_name = "in0", } 672 }, 673 .num_parents = 1, 674 }, 675 }; 676 677 static struct clk_regmap t7_hdmi_pll_od = { 678 .data = &(struct clk_regmap_div_data){ 679 .offset = HDMIPLL_CTRL0, 680 .shift = 16, 681 .width = 4, 682 .flags = CLK_DIVIDER_POWER_OF_TWO, 683 }, 684 .hw.init = &(struct clk_init_data){ 685 .name = "hdmi_pll_od", 686 .ops = &clk_regmap_divider_ops, 687 .parent_hws = (const struct clk_hw *[]) { 688 &t7_hdmi_pll_dco.hw 689 }, 690 .num_parents = 1, 691 .flags = CLK_SET_RATE_PARENT, 692 }, 693 }; 694 695 static struct clk_regmap t7_hdmi_pll = { 696 .data = &(struct clk_regmap_div_data){ 697 .offset = HDMIPLL_CTRL0, 698 .shift = 20, 699 .width = 2, 700 .flags = CLK_DIVIDER_POWER_OF_TWO, 701 }, 702 .hw.init = &(struct clk_init_data){ 703 .name = "hdmi_pll", 704 .ops = &clk_regmap_divider_ops, 705 .parent_hws = (const struct clk_hw *[]) { 706 &t7_hdmi_pll_od.hw 707 }, 708 .num_parents = 1, 709 .flags = CLK_SET_RATE_PARENT, 710 }, 711 }; 712 713 static const struct pll_mult_range t7_mclk_pll_mult_range = { 714 .min = 67, 715 .max = 133, 716 }; 717 718 static const struct reg_sequence t7_mclk_init_regs[] = { 719 { .reg = MCLK_PLL_CNTL1, .def = 0x1470500f }, 720 { .reg = MCLK_PLL_CNTL2, .def = 0x00023001 }, 721 { .reg = MCLK_PLL_CNTL3, .def = 0x18180000 }, 722 { .reg = MCLK_PLL_CNTL4, .def = 0x00180303 }, 723 }; 724 725 static struct clk_regmap t7_mclk_pll_dco = { 726 .data = &(struct meson_clk_pll_data){ 727 .en = { 728 .reg_off = MCLK_PLL_CNTL0, 729 .shift = 28, 730 .width = 1, 731 }, 732 .m = { 733 .reg_off = MCLK_PLL_CNTL0, 734 .shift = 0, 735 .width = 8, 736 }, 737 .n = { 738 .reg_off = MCLK_PLL_CNTL0, 739 .shift = 16, 740 .width = 5, 741 }, 742 .l = { 743 .reg_off = MCLK_PLL_CNTL0, 744 .shift = 31, 745 .width = 1, 746 }, 747 .rst = { 748 .reg_off = MCLK_PLL_CNTL0, 749 .shift = 29, 750 .width = 1, 751 }, 752 .l_detect = { 753 .reg_off = MCLK_PLL_CNTL2, 754 .shift = 6, 755 .width = 1, 756 }, 757 .range = &t7_mclk_pll_mult_range, 758 .init_regs = t7_mclk_init_regs, 759 .init_count = ARRAY_SIZE(t7_mclk_init_regs), 760 }, 761 .hw.init = &(struct clk_init_data){ 762 .name = "mclk_pll_dco", 763 .ops = &meson_clk_pll_ops, 764 .parent_data = &(const struct clk_parent_data) { 765 .fw_name = "in0", 766 }, 767 .num_parents = 1, 768 }, 769 }; 770 771 /* max div is 16 */ 772 static const struct clk_div_table t7_mclk_div[] = { 773 { .val = 0, .div = 1 }, 774 { .val = 1, .div = 2 }, 775 { .val = 2, .div = 4 }, 776 { .val = 3, .div = 8 }, 777 { .val = 4, .div = 16 }, 778 { /* sentinel */ } 779 }; 780 781 static struct clk_regmap t7_mclk_pre_od = { 782 .data = &(struct clk_regmap_div_data){ 783 .offset = MCLK_PLL_CNTL0, 784 .shift = 12, 785 .width = 3, 786 .table = t7_mclk_div, 787 }, 788 .hw.init = &(struct clk_init_data){ 789 .name = "mclk_pre_od", 790 .ops = &clk_regmap_divider_ops, 791 .parent_hws = (const struct clk_hw *[]) { 792 &t7_mclk_pll_dco.hw 793 }, 794 .num_parents = 1, 795 .flags = CLK_SET_RATE_PARENT, 796 }, 797 }; 798 799 static struct clk_regmap t7_mclk_pll = { 800 .data = &(struct clk_regmap_div_data){ 801 .offset = MCLK_PLL_CNTL4, 802 .shift = 16, 803 .width = 5, 804 .flags = CLK_DIVIDER_ONE_BASED, 805 }, 806 .hw.init = &(struct clk_init_data){ 807 .name = "mclk_pll", 808 .ops = &clk_regmap_divider_ops, 809 .parent_hws = (const struct clk_hw *[]) { 810 &t7_mclk_pre_od.hw 811 }, 812 .num_parents = 1, 813 .flags = CLK_SET_RATE_PARENT, 814 }, 815 }; 816 817 static struct clk_regmap t7_mclk_0_sel = { 818 .data = &(struct clk_regmap_mux_data){ 819 .offset = MCLK_PLL_CNTL4, 820 .mask = 0x3, 821 .shift = 4, 822 }, 823 .hw.init = &(struct clk_init_data){ 824 .name = "mclk_0_sel", 825 .ops = &clk_regmap_mux_ops, 826 .parent_data = (const struct clk_parent_data []) { 827 { .hw = &t7_mclk_pll.hw }, 828 { .fw_name = "in1", }, 829 { .fw_name = "in2", }, 830 }, 831 .num_parents = 3, 832 }, 833 }; 834 835 static struct clk_fixed_factor t7_mclk_0_div2 = { 836 .mult = 1, 837 .div = 2, 838 .hw.init = &(struct clk_init_data){ 839 .name = "mclk_0_div2", 840 .ops = &clk_fixed_factor_ops, 841 .parent_hws = (const struct clk_hw *[]) { &t7_mclk_0_sel.hw }, 842 .num_parents = 1, 843 .flags = CLK_SET_RATE_PARENT, 844 }, 845 }; 846 847 static struct clk_regmap t7_mclk_0_pre = { 848 .data = &(struct clk_regmap_gate_data){ 849 .offset = MCLK_PLL_CNTL4, 850 .bit_idx = 2, 851 }, 852 .hw.init = &(struct clk_init_data) { 853 .name = "mclk_0_pre", 854 .ops = &clk_regmap_gate_ops, 855 .parent_hws = (const struct clk_hw *[]) { 856 &t7_mclk_0_div2.hw 857 }, 858 .num_parents = 1, 859 .flags = CLK_SET_RATE_PARENT, 860 }, 861 }; 862 863 static struct clk_regmap t7_mclk_0 = { 864 .data = &(struct clk_regmap_gate_data){ 865 .offset = MCLK_PLL_CNTL4, 866 .bit_idx = 0, 867 }, 868 .hw.init = &(struct clk_init_data) { 869 .name = "mclk_0", 870 .ops = &clk_regmap_gate_ops, 871 .parent_hws = (const struct clk_hw *[]) { 872 &t7_mclk_0_pre.hw 873 }, 874 .num_parents = 1, 875 .flags = CLK_SET_RATE_PARENT, 876 }, 877 }; 878 879 static struct clk_regmap t7_mclk_1_sel = { 880 .data = &(struct clk_regmap_mux_data){ 881 .offset = MCLK_PLL_CNTL4, 882 .mask = 0x3, 883 .shift = 12, 884 }, 885 .hw.init = &(struct clk_init_data){ 886 .name = "mclk_1_sel", 887 .ops = &clk_regmap_mux_ops, 888 .parent_data = (const struct clk_parent_data []) { 889 { .hw = &t7_mclk_pll.hw }, 890 { .fw_name = "in1", }, 891 { .fw_name = "in2", }, 892 }, 893 .num_parents = 3, 894 }, 895 }; 896 897 static struct clk_fixed_factor t7_mclk_1_div2 = { 898 .mult = 1, 899 .div = 2, 900 .hw.init = &(struct clk_init_data){ 901 .name = "mclk_1_div2", 902 .ops = &clk_fixed_factor_ops, 903 .parent_hws = (const struct clk_hw *[]) { &t7_mclk_1_sel.hw }, 904 .num_parents = 1, 905 .flags = CLK_SET_RATE_PARENT, 906 }, 907 }; 908 909 static struct clk_regmap t7_mclk_1_pre = { 910 .data = &(struct clk_regmap_gate_data){ 911 .offset = MCLK_PLL_CNTL4, 912 .bit_idx = 10, 913 }, 914 .hw.init = &(struct clk_init_data) { 915 .name = "mclk_1_pre", 916 .ops = &clk_regmap_gate_ops, 917 .parent_hws = (const struct clk_hw *[]) { 918 &t7_mclk_1_div2.hw 919 }, 920 .num_parents = 1, 921 .flags = CLK_SET_RATE_PARENT, 922 }, 923 }; 924 925 static struct clk_regmap t7_mclk_1 = { 926 .data = &(struct clk_regmap_gate_data){ 927 .offset = MCLK_PLL_CNTL4, 928 .bit_idx = 8, 929 }, 930 .hw.init = &(struct clk_init_data) { 931 .name = "mclk_1", 932 .ops = &clk_regmap_gate_ops, 933 .parent_hws = (const struct clk_hw *[]) { 934 &t7_mclk_1_pre.hw 935 }, 936 .num_parents = 1, 937 .flags = CLK_SET_RATE_PARENT, 938 }, 939 }; 940 941 static struct clk_hw *t7_gp0_hw_clks[] = { 942 [CLKID_GP0_PLL_DCO] = &t7_gp0_pll_dco.hw, 943 [CLKID_GP0_PLL] = &t7_gp0_pll.hw, 944 }; 945 946 static struct clk_hw *t7_gp1_hw_clks[] = { 947 [CLKID_GP1_PLL_DCO] = &t7_gp1_pll_dco.hw, 948 [CLKID_GP1_PLL] = &t7_gp1_pll.hw, 949 }; 950 951 static struct clk_hw *t7_hifi_hw_clks[] = { 952 [CLKID_HIFI_PLL_DCO] = &t7_hifi_pll_dco.hw, 953 [CLKID_HIFI_PLL] = &t7_hifi_pll.hw, 954 }; 955 956 static struct clk_hw *t7_pcie_hw_clks[] = { 957 [CLKID_PCIE_PLL_DCO] = &t7_pcie_pll_dco.hw, 958 [CLKID_PCIE_PLL_DCO_DIV2] = &t7_pcie_pll_dco_div2.hw, 959 [CLKID_PCIE_PLL_OD] = &t7_pcie_pll_od.hw, 960 [CLKID_PCIE_PLL] = &t7_pcie_pll.hw, 961 }; 962 963 static struct clk_hw *t7_mpll_hw_clks[] = { 964 [CLKID_MPLL_PREDIV] = &t7_mpll_prediv.hw, 965 [CLKID_MPLL0_DIV] = &t7_mpll0_div.hw, 966 [CLKID_MPLL0] = &t7_mpll0.hw, 967 [CLKID_MPLL1_DIV] = &t7_mpll1_div.hw, 968 [CLKID_MPLL1] = &t7_mpll1.hw, 969 [CLKID_MPLL2_DIV] = &t7_mpll2_div.hw, 970 [CLKID_MPLL2] = &t7_mpll2.hw, 971 [CLKID_MPLL3_DIV] = &t7_mpll3_div.hw, 972 [CLKID_MPLL3] = &t7_mpll3.hw, 973 }; 974 975 static struct clk_hw *t7_hdmi_hw_clks[] = { 976 [CLKID_HDMI_PLL_DCO] = &t7_hdmi_pll_dco.hw, 977 [CLKID_HDMI_PLL_OD] = &t7_hdmi_pll_od.hw, 978 [CLKID_HDMI_PLL] = &t7_hdmi_pll.hw, 979 }; 980 981 static struct clk_hw *t7_mclk_hw_clks[] = { 982 [CLKID_MCLK_PLL_DCO] = &t7_mclk_pll_dco.hw, 983 [CLKID_MCLK_PRE] = &t7_mclk_pre_od.hw, 984 [CLKID_MCLK_PLL] = &t7_mclk_pll.hw, 985 [CLKID_MCLK_0_SEL] = &t7_mclk_0_sel.hw, 986 [CLKID_MCLK_0_DIV2] = &t7_mclk_0_div2.hw, 987 [CLKID_MCLK_0_PRE] = &t7_mclk_0_pre.hw, 988 [CLKID_MCLK_0] = &t7_mclk_0.hw, 989 [CLKID_MCLK_1_SEL] = &t7_mclk_1_sel.hw, 990 [CLKID_MCLK_1_DIV2] = &t7_mclk_1_div2.hw, 991 [CLKID_MCLK_1_PRE] = &t7_mclk_1_pre.hw, 992 [CLKID_MCLK_1] = &t7_mclk_1.hw, 993 }; 994 995 static const struct meson_clkc_data t7_gp0_data = { 996 .hw_clks = { 997 .hws = t7_gp0_hw_clks, 998 .num = ARRAY_SIZE(t7_gp0_hw_clks), 999 }, 1000 }; 1001 1002 static const struct meson_clkc_data t7_gp1_data = { 1003 .hw_clks = { 1004 .hws = t7_gp1_hw_clks, 1005 .num = ARRAY_SIZE(t7_gp1_hw_clks), 1006 }, 1007 }; 1008 1009 static const struct meson_clkc_data t7_hifi_data = { 1010 .hw_clks = { 1011 .hws = t7_hifi_hw_clks, 1012 .num = ARRAY_SIZE(t7_hifi_hw_clks), 1013 }, 1014 }; 1015 1016 static const struct meson_clkc_data t7_pcie_data = { 1017 .hw_clks = { 1018 .hws = t7_pcie_hw_clks, 1019 .num = ARRAY_SIZE(t7_pcie_hw_clks), 1020 }, 1021 }; 1022 1023 static const struct reg_sequence t7_mpll_init_regs[] = { 1024 { .reg = MPLL_CTRL0, .def = 0x00000543 } 1025 }; 1026 1027 static const struct meson_clkc_data t7_mpll_data = { 1028 .hw_clks = { 1029 .hws = t7_mpll_hw_clks, 1030 .num = ARRAY_SIZE(t7_mpll_hw_clks), 1031 }, 1032 .init_regs = t7_mpll_init_regs, 1033 .init_count = ARRAY_SIZE(t7_mpll_init_regs), 1034 }; 1035 1036 static const struct meson_clkc_data t7_hdmi_data = { 1037 .hw_clks = { 1038 .hws = t7_hdmi_hw_clks, 1039 .num = ARRAY_SIZE(t7_hdmi_hw_clks), 1040 }, 1041 }; 1042 1043 static const struct meson_clkc_data t7_mclk_data = { 1044 .hw_clks = { 1045 .hws = t7_mclk_hw_clks, 1046 .num = ARRAY_SIZE(t7_mclk_hw_clks), 1047 }, 1048 }; 1049 1050 static const struct of_device_id t7_pll_clkc_match_table[] = { 1051 { .compatible = "amlogic,t7-gp0-pll", .data = &t7_gp0_data, }, 1052 { .compatible = "amlogic,t7-gp1-pll", .data = &t7_gp1_data, }, 1053 { .compatible = "amlogic,t7-hifi-pll", .data = &t7_hifi_data, }, 1054 { .compatible = "amlogic,t7-pcie-pll", .data = &t7_pcie_data, }, 1055 { .compatible = "amlogic,t7-mpll", .data = &t7_mpll_data, }, 1056 { .compatible = "amlogic,t7-hdmi-pll", .data = &t7_hdmi_data, }, 1057 { .compatible = "amlogic,t7-mclk-pll", .data = &t7_mclk_data, }, 1058 {} 1059 }; 1060 MODULE_DEVICE_TABLE(of, t7_pll_clkc_match_table); 1061 1062 static struct platform_driver t7_pll_clkc_driver = { 1063 .probe = meson_clkc_mmio_probe, 1064 .driver = { 1065 .name = "t7-pll-clkc", 1066 .of_match_table = t7_pll_clkc_match_table, 1067 }, 1068 }; 1069 module_platform_driver(t7_pll_clkc_driver); 1070 1071 MODULE_DESCRIPTION("Amlogic T7 PLL Clock Controller driver"); 1072 MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>"); 1073 MODULE_LICENSE("GPL"); 1074 MODULE_IMPORT_NS("CLK_MESON"); 1075