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