1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/module.h> 8 #include <linux/of.h> 9 #include <linux/platform_device.h> 10 #include <linux/regmap.h> 11 12 #include <dt-bindings/clock/qcom,qcs615-gpucc.h> 13 14 #include "clk-alpha-pll.h" 15 #include "clk-branch.h" 16 #include "clk-pll.h" 17 #include "clk-rcg.h" 18 #include "clk-regmap.h" 19 #include "clk-regmap-divider.h" 20 #include "clk-regmap-mux.h" 21 #include "common.h" 22 #include "gdsc.h" 23 #include "reset.h" 24 25 enum { 26 DT_BI_TCXO, 27 DT_GPLL0_OUT_MAIN, 28 DT_GPLL0_OUT_MAIN_DIV, 29 }; 30 31 enum { 32 P_BI_TCXO, 33 P_GPLL0_OUT_MAIN, 34 P_GPLL0_OUT_MAIN_DIV, 35 P_GPU_CC_PLL0_2X_CLK, 36 P_CRC_DIV_PLL0_OUT_AUX2, 37 P_GPU_CC_PLL0_OUT_MAIN, 38 P_GPU_CC_PLL1_OUT_AUX, 39 P_CRC_DIV_PLL1_OUT_AUX2, 40 P_GPU_CC_PLL1_OUT_MAIN, 41 }; 42 43 static const struct pll_vco gpu_cc_pll0_vco[] = { 44 { 1000000000, 2100000000, 0 }, 45 }; 46 47 static struct pll_vco gpu_cc_pll1_vco[] = { 48 { 500000000, 1000000000, 2 }, 49 }; 50 51 /* 1020MHz configuration VCO - 0 */ 52 static struct alpha_pll_config gpu_cc_pll0_config = { 53 .l = 0x35, 54 .config_ctl_val = 0x4001055b, 55 .test_ctl_hi_val = 0x1, 56 .test_ctl_hi_mask = 0x1, 57 .alpha_hi = 0x20, 58 .alpha = 0x00, 59 .alpha_en_mask = BIT(24), 60 .vco_val = 0x0, 61 .vco_mask = GENMASK(21, 20), 62 .aux2_output_mask = BIT(2), 63 }; 64 65 static struct clk_alpha_pll gpu_cc_pll0 = { 66 .offset = 0x0, 67 .config = &gpu_cc_pll0_config, 68 .vco_table = gpu_cc_pll0_vco, 69 .num_vco = ARRAY_SIZE(gpu_cc_pll0_vco), 70 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 71 .clkr = { 72 .hw.init = &(const struct clk_init_data) { 73 .name = "gpu_cc_pll0", 74 .parent_data = &(const struct clk_parent_data) { 75 .index = DT_BI_TCXO, 76 }, 77 .num_parents = 1, 78 .ops = &clk_alpha_pll_slew_ops, 79 }, 80 }, 81 }; 82 83 /* 930MHz configuration VCO - 2 */ 84 static struct alpha_pll_config gpu_cc_pll1_config = { 85 .l = 0x30, 86 .config_ctl_val = 0x4001055b, 87 .test_ctl_hi_val = 0x1, 88 .test_ctl_hi_mask = 0x1, 89 .alpha_hi = 0x70, 90 .alpha = 0x00, 91 .alpha_en_mask = BIT(24), 92 .vco_val = BIT(21), 93 .vco_mask = GENMASK(21, 20), 94 .aux2_output_mask = BIT(2), 95 }; 96 97 static struct clk_alpha_pll gpu_cc_pll1 = { 98 .offset = 0x100, 99 .config = &gpu_cc_pll1_config, 100 .vco_table = gpu_cc_pll1_vco, 101 .num_vco = ARRAY_SIZE(gpu_cc_pll1_vco), 102 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 103 .clkr = { 104 .hw.init = &(const struct clk_init_data) { 105 .name = "gpu_cc_pll1", 106 .parent_data = &(const struct clk_parent_data) { 107 .index = DT_BI_TCXO, 108 }, 109 .num_parents = 1, 110 .ops = &clk_alpha_pll_slew_ops, 111 }, 112 } 113 }; 114 115 /* Clock Ramp Controller */ 116 static struct clk_fixed_factor crc_div_pll0 = { 117 .mult = 1, 118 .div = 2, 119 .hw.init = &(struct clk_init_data){ 120 .name = "crc_div_pll0", 121 .parent_data = &(const struct clk_parent_data){ 122 .hw = &gpu_cc_pll0.clkr.hw, 123 }, 124 .num_parents = 1, 125 .flags = CLK_SET_RATE_PARENT, 126 .ops = &clk_fixed_factor_ops, 127 }, 128 }; 129 130 /* Clock Ramp Controller */ 131 static struct clk_fixed_factor crc_div_pll1 = { 132 .mult = 1, 133 .div = 2, 134 .hw.init = &(struct clk_init_data){ 135 .name = "crc_div_pll1", 136 .parent_data = &(const struct clk_parent_data){ 137 .hw = &gpu_cc_pll1.clkr.hw, 138 }, 139 .num_parents = 1, 140 .flags = CLK_SET_RATE_PARENT, 141 .ops = &clk_fixed_factor_ops, 142 }, 143 }; 144 145 static const struct parent_map gpu_cc_parent_map_0[] = { 146 { P_BI_TCXO, 0 }, 147 { P_GPU_CC_PLL0_OUT_MAIN, 1 }, 148 { P_GPU_CC_PLL1_OUT_MAIN, 3 }, 149 { P_GPLL0_OUT_MAIN, 5 }, 150 { P_GPLL0_OUT_MAIN_DIV, 6 }, 151 }; 152 153 static const struct clk_parent_data gpu_cc_parent_data_0[] = { 154 { .index = DT_BI_TCXO }, 155 { .hw = &gpu_cc_pll0.clkr.hw }, 156 { .hw = &gpu_cc_pll1.clkr.hw }, 157 { .index = DT_GPLL0_OUT_MAIN }, 158 { .index = DT_GPLL0_OUT_MAIN_DIV }, 159 }; 160 161 static const struct parent_map gpu_cc_parent_map_1[] = { 162 { P_BI_TCXO, 0 }, 163 { P_GPU_CC_PLL0_2X_CLK, 1 }, 164 { P_CRC_DIV_PLL0_OUT_AUX2, 2 }, 165 { P_GPU_CC_PLL1_OUT_AUX, 3 }, 166 { P_CRC_DIV_PLL1_OUT_AUX2, 4 }, 167 { P_GPLL0_OUT_MAIN, 5 }, 168 }; 169 170 static const struct clk_parent_data gpu_cc_parent_data_1[] = { 171 { .index = DT_BI_TCXO }, 172 { .hw = &gpu_cc_pll0.clkr.hw }, 173 { .hw = &crc_div_pll0.hw }, 174 { .hw = &gpu_cc_pll1.clkr.hw }, 175 { .hw = &crc_div_pll1.hw }, 176 { .index = DT_GPLL0_OUT_MAIN }, 177 }; 178 179 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { 180 F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), 181 { } 182 }; 183 184 static struct clk_rcg2 gpu_cc_gmu_clk_src = { 185 .cmd_rcgr = 0x1120, 186 .mnd_width = 0, 187 .hid_width = 5, 188 .parent_map = gpu_cc_parent_map_0, 189 .freq_tbl = ftbl_gpu_cc_gmu_clk_src, 190 .clkr.hw.init = &(const struct clk_init_data) { 191 .name = "gpu_cc_gmu_clk_src", 192 .parent_data = gpu_cc_parent_data_0, 193 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), 194 .ops = &clk_rcg2_shared_ops, 195 }, 196 }; 197 198 static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { 199 F(290000000, P_CRC_DIV_PLL1_OUT_AUX2, 1, 0, 0), 200 F(350000000, P_CRC_DIV_PLL1_OUT_AUX2, 1, 0, 0), 201 F(435000000, P_CRC_DIV_PLL1_OUT_AUX2, 1, 0, 0), 202 F(500000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 203 F(550000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 204 F(650000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 205 F(700000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 206 F(745000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 207 F(845000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 208 F(895000000, P_CRC_DIV_PLL0_OUT_AUX2, 1, 0, 0), 209 { } 210 }; 211 212 static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { 213 .cmd_rcgr = 0x101c, 214 .mnd_width = 0, 215 .hid_width = 5, 216 .parent_map = gpu_cc_parent_map_1, 217 .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, 218 .clkr.hw.init = &(const struct clk_init_data) { 219 .name = "gpu_cc_gx_gfx3d_clk_src", 220 .parent_data = gpu_cc_parent_data_1, 221 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), 222 .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, 223 .ops = &clk_rcg2_shared_ops, 224 }, 225 }; 226 227 static struct clk_branch gpu_cc_crc_ahb_clk = { 228 .halt_reg = 0x107c, 229 .halt_check = BRANCH_HALT_VOTED, 230 .clkr = { 231 .enable_reg = 0x107c, 232 .enable_mask = BIT(0), 233 .hw.init = &(const struct clk_init_data) { 234 .name = "gpu_cc_crc_ahb_clk", 235 .ops = &clk_branch2_ops, 236 }, 237 }, 238 }; 239 240 static struct clk_branch gpu_cc_cx_gfx3d_clk = { 241 .halt_reg = 0x10a4, 242 .halt_check = BRANCH_HALT_DELAY, 243 .clkr = { 244 .enable_reg = 0x10a4, 245 .enable_mask = BIT(0), 246 .hw.init = &(const struct clk_init_data) { 247 .name = "gpu_cc_cx_gfx3d_clk", 248 .parent_hws = (const struct clk_hw*[]) { 249 &gpu_cc_gx_gfx3d_clk_src.clkr.hw, 250 }, 251 .num_parents = 1, 252 .flags = CLK_SET_RATE_PARENT, 253 .ops = &clk_branch2_ops, 254 }, 255 }, 256 }; 257 258 static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { 259 .halt_reg = 0x10a8, 260 .halt_check = BRANCH_HALT_DELAY, 261 .clkr = { 262 .enable_reg = 0x10a8, 263 .enable_mask = BIT(0), 264 .hw.init = &(const struct clk_init_data) { 265 .name = "gpu_cc_cx_gfx3d_slv_clk", 266 .parent_hws = (const struct clk_hw*[]) { 267 &gpu_cc_gx_gfx3d_clk_src.clkr.hw, 268 }, 269 .num_parents = 1, 270 .flags = CLK_SET_RATE_PARENT, 271 .ops = &clk_branch2_ops, 272 }, 273 }, 274 }; 275 276 static struct clk_branch gpu_cc_cx_gmu_clk = { 277 .halt_reg = 0x1098, 278 .halt_check = BRANCH_HALT, 279 .clkr = { 280 .enable_reg = 0x1098, 281 .enable_mask = BIT(0), 282 .hw.init = &(const struct clk_init_data) { 283 .name = "gpu_cc_cx_gmu_clk", 284 .parent_hws = (const struct clk_hw*[]) { 285 &gpu_cc_gmu_clk_src.clkr.hw, 286 }, 287 .num_parents = 1, 288 .flags = CLK_SET_RATE_PARENT, 289 .ops = &clk_branch2_ops, 290 }, 291 }, 292 }; 293 294 static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { 295 .halt_reg = 0x108c, 296 .halt_check = BRANCH_HALT_VOTED, 297 .clkr = { 298 .enable_reg = 0x108c, 299 .enable_mask = BIT(0), 300 .hw.init = &(const struct clk_init_data) { 301 .name = "gpu_cc_cx_snoc_dvm_clk", 302 .ops = &clk_branch2_ops, 303 }, 304 }, 305 }; 306 307 static struct clk_branch gpu_cc_cxo_aon_clk = { 308 .halt_reg = 0x1004, 309 .halt_check = BRANCH_HALT_VOTED, 310 .clkr = { 311 .enable_reg = 0x1004, 312 .enable_mask = BIT(0), 313 .hw.init = &(struct clk_init_data){ 314 .name = "gpu_cc_cxo_aon_clk", 315 .ops = &clk_branch2_ops, 316 }, 317 }, 318 }; 319 320 static struct clk_branch gpu_cc_cxo_clk = { 321 .halt_reg = 0x109c, 322 .halt_check = BRANCH_HALT, 323 .clkr = { 324 .enable_reg = 0x109c, 325 .enable_mask = BIT(0), 326 .hw.init = &(const struct clk_init_data) { 327 .name = "gpu_cc_cxo_clk", 328 .ops = &clk_branch2_ops, 329 }, 330 }, 331 }; 332 333 static struct clk_branch gpu_cc_gx_gfx3d_clk = { 334 .halt_reg = 0x1054, 335 .halt_check = BRANCH_HALT_SKIP, 336 .clkr = { 337 .enable_reg = 0x1054, 338 .enable_mask = BIT(0), 339 .hw.init = &(const struct clk_init_data) { 340 .name = "gpu_cc_gx_gfx3d_clk", 341 .parent_hws = (const struct clk_hw*[]) { 342 &gpu_cc_gx_gfx3d_clk_src.clkr.hw, 343 }, 344 .num_parents = 1, 345 .flags = CLK_SET_RATE_PARENT, 346 .ops = &clk_branch2_ops, 347 }, 348 }, 349 }; 350 351 static struct clk_branch gpu_cc_gx_gmu_clk = { 352 .halt_reg = 0x1064, 353 .halt_check = BRANCH_HALT, 354 .clkr = { 355 .enable_reg = 0x1064, 356 .enable_mask = BIT(0), 357 .hw.init = &(const struct clk_init_data) { 358 .name = "gpu_cc_gx_gmu_clk", 359 .parent_hws = (const struct clk_hw*[]) { 360 &gpu_cc_gmu_clk_src.clkr.hw, 361 }, 362 .num_parents = 1, 363 .flags = CLK_SET_RATE_PARENT, 364 .ops = &clk_branch2_ops, 365 }, 366 }, 367 }; 368 369 static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { 370 .halt_reg = 0x5000, 371 .halt_check = BRANCH_VOTED, 372 .clkr = { 373 .enable_reg = 0x5000, 374 .enable_mask = BIT(0), 375 .hw.init = &(const struct clk_init_data) { 376 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", 377 .ops = &clk_branch2_ops, 378 }, 379 }, 380 }; 381 382 static struct clk_branch gpu_cc_sleep_clk = { 383 .halt_reg = 0x1090, 384 .halt_check = BRANCH_HALT_VOTED, 385 .clkr = { 386 .enable_reg = 0x1090, 387 .enable_mask = BIT(0), 388 .hw.init = &(const struct clk_init_data) { 389 .name = "gpu_cc_sleep_clk", 390 .ops = &clk_branch2_ops, 391 }, 392 }, 393 }; 394 395 static struct clk_hw *gpu_cc_qcs615_hws[] = { 396 [CRC_DIV_PLL0] = &crc_div_pll0.hw, 397 [CRC_DIV_PLL1] = &crc_div_pll1.hw, 398 }; 399 400 static struct gdsc cx_gdsc = { 401 .gdscr = 0x106c, 402 .gds_hw_ctrl = 0x1540, 403 .en_rest_wait_val = 0x2, 404 .en_few_wait_val = 0x2, 405 .clk_dis_wait_val = 0x8, 406 .pd = { 407 .name = "cx_gdsc", 408 }, 409 .pwrsts = PWRSTS_OFF_ON, 410 .flags = POLL_CFG_GDSCR, 411 }; 412 413 static struct gdsc gx_gdsc = { 414 .gdscr = 0x100c, 415 .en_rest_wait_val = 0x2, 416 .en_few_wait_val = 0x2, 417 .clk_dis_wait_val = 0x2, 418 .pd = { 419 .name = "gx_gdsc", 420 }, 421 .pwrsts = PWRSTS_OFF_ON, 422 .flags = POLL_CFG_GDSCR, 423 }; 424 425 static struct clk_regmap *gpu_cc_qcs615_clocks[] = { 426 [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, 427 [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, 428 [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, 429 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, 430 [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, 431 [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, 432 [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, 433 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, 434 [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, 435 [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, 436 [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, 437 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, 438 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, 439 [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, 440 [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, 441 }; 442 443 static struct gdsc *gpu_cc_qcs615_gdscs[] = { 444 [CX_GDSC] = &cx_gdsc, 445 [GX_GDSC] = &gx_gdsc, 446 }; 447 448 static const struct qcom_reset_map gpu_cc_qcs615_resets[] = { 449 [GPU_CC_CX_BCR] = { 0x1068 }, 450 [GPU_CC_GFX3D_AON_BCR] = { 0x10a0 }, 451 [GPU_CC_GMU_BCR] = { 0x111c }, 452 [GPU_CC_GX_BCR] = { 0x1008 }, 453 [GPU_CC_XO_BCR] = { 0x1000 }, 454 }; 455 456 static struct clk_alpha_pll *gpu_cc_qcs615_plls[] = { 457 &gpu_cc_pll0, 458 &gpu_cc_pll1, 459 }; 460 461 static const u32 gpu_cc_qcs615_critical_cbcrs[] = { 462 0x1078, /* GPU_CC_AHB_CLK */ 463 }; 464 465 static const struct regmap_config gpu_cc_qcs615_regmap_config = { 466 .reg_bits = 32, 467 .reg_stride = 4, 468 .val_bits = 32, 469 .max_register = 0x7008, 470 .fast_io = true, 471 }; 472 473 static void clk_qcs615_regs_crc_configure(struct device *dev, struct regmap *regmap) 474 { 475 /* Recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ 476 regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg, 0xff0, 0xff0); 477 478 /* 479 * After POR, Clock Ramp Controller(CRC) will be in bypass mode. 480 * Software needs to do the following operation to enable the CRC 481 * for GFX3D clock and divide the input clock by div by 2. 482 */ 483 regmap_update_bits(regmap, 0x1028, 0x00015011, 0x00015011); 484 regmap_update_bits(regmap, 0x1024, 0x00800000, 0x00800000); 485 } 486 487 static const struct qcom_cc_driver_data gpu_cc_qcs615_driver_data = { 488 .alpha_plls = gpu_cc_qcs615_plls, 489 .num_alpha_plls = ARRAY_SIZE(gpu_cc_qcs615_plls), 490 .clk_cbcrs = gpu_cc_qcs615_critical_cbcrs, 491 .num_clk_cbcrs = ARRAY_SIZE(gpu_cc_qcs615_critical_cbcrs), 492 .clk_regs_configure = clk_qcs615_regs_crc_configure, 493 }; 494 495 static const struct qcom_cc_desc gpu_cc_qcs615_desc = { 496 .config = &gpu_cc_qcs615_regmap_config, 497 .clks = gpu_cc_qcs615_clocks, 498 .num_clks = ARRAY_SIZE(gpu_cc_qcs615_clocks), 499 .clk_hws = gpu_cc_qcs615_hws, 500 .num_clk_hws = ARRAY_SIZE(gpu_cc_qcs615_hws), 501 .resets = gpu_cc_qcs615_resets, 502 .num_resets = ARRAY_SIZE(gpu_cc_qcs615_resets), 503 .gdscs = gpu_cc_qcs615_gdscs, 504 .num_gdscs = ARRAY_SIZE(gpu_cc_qcs615_gdscs), 505 .driver_data = &gpu_cc_qcs615_driver_data, 506 }; 507 508 static const struct of_device_id gpu_cc_qcs615_match_table[] = { 509 { .compatible = "qcom,qcs615-gpucc" }, 510 { } 511 }; 512 MODULE_DEVICE_TABLE(of, gpu_cc_qcs615_match_table); 513 514 static int gpu_cc_qcs615_probe(struct platform_device *pdev) 515 { 516 return qcom_cc_probe(pdev, &gpu_cc_qcs615_desc); 517 } 518 519 static struct platform_driver gpu_cc_qcs615_driver = { 520 .probe = gpu_cc_qcs615_probe, 521 .driver = { 522 .name = "gpucc-qcs615", 523 .of_match_table = gpu_cc_qcs615_match_table, 524 }, 525 }; 526 527 module_platform_driver(gpu_cc_qcs615_driver); 528 529 MODULE_DESCRIPTION("QTI GPUCC QCS615 Driver"); 530 MODULE_LICENSE("GPL"); 531