1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 * Copyright (c) 2023, Linaro Limited 5 */ 6 7 #include <linux/clk-provider.h> 8 #include <linux/mod_devicetable.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/regmap.h> 12 13 #include <dt-bindings/clock/qcom,sm6115-gpucc.h> 14 15 #include "clk-alpha-pll.h" 16 #include "clk-branch.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 "clk-regmap-phy-mux.h" 22 #include "gdsc.h" 23 #include "reset.h" 24 25 enum { 26 DT_BI_TCXO, 27 DT_GCC_GPU_GPLL0_CLK_SRC, 28 DT_GCC_GPU_GPLL0_DIV_CLK_SRC, 29 }; 30 31 enum { 32 P_BI_TCXO, 33 P_GPLL0_OUT_MAIN, 34 P_GPLL0_OUT_MAIN_DIV, 35 P_GPU_CC_PLL0_OUT_AUX2, 36 P_GPU_CC_PLL0_OUT_MAIN, 37 P_GPU_CC_PLL1_OUT_AUX, 38 P_GPU_CC_PLL1_OUT_MAIN, 39 }; 40 41 static const struct pll_vco default_vco[] = { 42 { 1000000000, 2000000000, 0 }, 43 }; 44 45 static const struct pll_vco pll1_vco[] = { 46 { 500000000, 1000000000, 2 }, 47 }; 48 49 static const struct alpha_pll_config gpu_cc_pll0_config = { 50 .l = 0x3e, 51 .alpha = 0, 52 .alpha_hi = 0x80, 53 .vco_val = 0x0 << 20, 54 .vco_mask = GENMASK(21, 20), 55 .alpha_en_mask = BIT(24), 56 .main_output_mask = BIT(0), 57 .aux_output_mask = BIT(1), 58 .aux2_output_mask = BIT(2), 59 .config_ctl_val = 0x4001055b, 60 .test_ctl_hi1_val = 0x1, 61 }; 62 63 /* 1200MHz configuration */ 64 static struct clk_alpha_pll gpu_cc_pll0 = { 65 .offset = 0x0, 66 .vco_table = default_vco, 67 .num_vco = ARRAY_SIZE(default_vco), 68 .flags = SUPPORTS_DYNAMIC_UPDATE, 69 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 70 .clkr = { 71 .hw.init = &(struct clk_init_data){ 72 .name = "gpu_cc_pll0", 73 .parent_data = &(const struct clk_parent_data){ 74 .index = DT_BI_TCXO, 75 }, 76 .num_parents = 1, 77 .ops = &clk_alpha_pll_ops, 78 }, 79 }, 80 }; 81 82 static const struct clk_div_table post_div_table_gpu_cc_pll0_out_aux2[] = { 83 { 0x0, 1 }, 84 { } 85 }; 86 87 static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_aux2 = { 88 .offset = 0x0, 89 .post_div_shift = 8, 90 .post_div_table = post_div_table_gpu_cc_pll0_out_aux2, 91 .num_post_div = ARRAY_SIZE(post_div_table_gpu_cc_pll0_out_aux2), 92 .width = 4, 93 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 94 .clkr.hw.init = &(struct clk_init_data){ 95 .name = "gpu_cc_pll0_out_aux2", 96 .parent_hws = (const struct clk_hw*[]) { 97 &gpu_cc_pll0.clkr.hw, 98 }, 99 .num_parents = 1, 100 .flags = CLK_SET_RATE_PARENT, 101 .ops = &clk_alpha_pll_postdiv_ops, 102 }, 103 }; 104 105 /* 640MHz configuration */ 106 static const struct alpha_pll_config gpu_cc_pll1_config = { 107 .l = 0x21, 108 .alpha = 0x55555555, 109 .alpha_hi = 0x55, 110 .alpha_en_mask = BIT(24), 111 .vco_val = 0x2 << 20, 112 .vco_mask = GENMASK(21, 20), 113 .main_output_mask = BIT(0), 114 .aux_output_mask = BIT(1), 115 .config_ctl_val = 0x4001055b, 116 .test_ctl_hi1_val = 0x1, 117 }; 118 119 static struct clk_alpha_pll gpu_cc_pll1 = { 120 .offset = 0x100, 121 .vco_table = pll1_vco, 122 .num_vco = ARRAY_SIZE(pll1_vco), 123 .flags = SUPPORTS_DYNAMIC_UPDATE, 124 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 125 .clkr = { 126 .hw.init = &(struct clk_init_data){ 127 .name = "gpu_cc_pll1", 128 .parent_data = &(const struct clk_parent_data){ 129 .index = DT_BI_TCXO, 130 }, 131 .num_parents = 1, 132 .ops = &clk_alpha_pll_ops, 133 }, 134 }, 135 }; 136 137 static const struct clk_div_table post_div_table_gpu_cc_pll1_out_aux[] = { 138 { 0x0, 1 }, 139 { } 140 }; 141 142 static struct clk_alpha_pll_postdiv gpu_cc_pll1_out_aux = { 143 .offset = 0x100, 144 .post_div_shift = 15, 145 .post_div_table = post_div_table_gpu_cc_pll1_out_aux, 146 .num_post_div = ARRAY_SIZE(post_div_table_gpu_cc_pll1_out_aux), 147 .width = 3, 148 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT], 149 .clkr.hw.init = &(struct clk_init_data){ 150 .name = "gpu_cc_pll1_out_aux", 151 .parent_hws = (const struct clk_hw*[]) { 152 &gpu_cc_pll1.clkr.hw, 153 }, 154 .num_parents = 1, 155 .flags = CLK_SET_RATE_PARENT, 156 .ops = &clk_alpha_pll_postdiv_ops, 157 }, 158 }; 159 160 static const struct parent_map gpu_cc_parent_map_0[] = { 161 { P_BI_TCXO, 0 }, 162 { P_GPU_CC_PLL0_OUT_MAIN, 1 }, 163 { P_GPU_CC_PLL1_OUT_MAIN, 3 }, 164 { P_GPLL0_OUT_MAIN, 5 }, 165 { P_GPLL0_OUT_MAIN_DIV, 6 }, 166 }; 167 168 static const struct clk_parent_data gpu_cc_parent_data_0[] = { 169 { .index = P_BI_TCXO }, 170 { .hw = &gpu_cc_pll0.clkr.hw }, 171 { .hw = &gpu_cc_pll1.clkr.hw }, 172 { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, 173 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, 174 }; 175 176 static const struct parent_map gpu_cc_parent_map_1[] = { 177 { P_BI_TCXO, 0 }, 178 { P_GPU_CC_PLL0_OUT_AUX2, 2 }, 179 { P_GPU_CC_PLL1_OUT_AUX, 3 }, 180 { P_GPLL0_OUT_MAIN, 5 }, 181 }; 182 183 static const struct clk_parent_data gpu_cc_parent_data_1[] = { 184 { .index = P_BI_TCXO }, 185 { .hw = &gpu_cc_pll0_out_aux2.clkr.hw }, 186 { .hw = &gpu_cc_pll1_out_aux.clkr.hw }, 187 { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, 188 }; 189 190 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { 191 F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), 192 { } 193 }; 194 195 static struct clk_rcg2 gpu_cc_gmu_clk_src = { 196 .cmd_rcgr = 0x1120, 197 .mnd_width = 0, 198 .hid_width = 5, 199 .parent_map = gpu_cc_parent_map_0, 200 .freq_tbl = ftbl_gpu_cc_gmu_clk_src, 201 .clkr.hw.init = &(struct clk_init_data){ 202 .name = "gpu_cc_gmu_clk_src", 203 .parent_data = gpu_cc_parent_data_0, 204 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), 205 .flags = CLK_SET_RATE_PARENT, 206 .ops = &clk_rcg2_shared_ops, 207 }, 208 }; 209 210 static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { 211 F(320000000, P_GPU_CC_PLL1_OUT_AUX, 2, 0, 0), 212 F(465000000, P_GPU_CC_PLL1_OUT_AUX, 2, 0, 0), 213 F(600000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), 214 F(745000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), 215 F(820000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), 216 F(900000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), 217 F(950000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), 218 F(980000000, P_GPU_CC_PLL0_OUT_AUX2, 2, 0, 0), 219 { } 220 }; 221 222 static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { 223 .cmd_rcgr = 0x101c, 224 .mnd_width = 0, 225 .hid_width = 5, 226 .parent_map = gpu_cc_parent_map_1, 227 .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, 228 .clkr.hw.init = &(struct clk_init_data){ 229 .name = "gpu_cc_gx_gfx3d_clk_src", 230 .parent_data = gpu_cc_parent_data_1, 231 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), 232 .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, 233 .ops = &clk_rcg2_ops, 234 }, 235 }; 236 237 static struct clk_branch gpu_cc_ahb_clk = { 238 .halt_reg = 0x1078, 239 .halt_check = BRANCH_HALT_DELAY, 240 .clkr = { 241 .enable_reg = 0x1078, 242 .enable_mask = BIT(0), 243 .hw.init = &(struct clk_init_data){ 244 .name = "gpu_cc_ahb_clk", 245 .flags = CLK_IS_CRITICAL, 246 .ops = &clk_branch2_ops, 247 }, 248 }, 249 }; 250 251 static struct clk_branch gpu_cc_crc_ahb_clk = { 252 .halt_reg = 0x107c, 253 .halt_check = BRANCH_HALT_DELAY, 254 .clkr = { 255 .enable_reg = 0x107c, 256 .enable_mask = BIT(0), 257 .hw.init = &(struct clk_init_data){ 258 .name = "gpu_cc_crc_ahb_clk", 259 .ops = &clk_branch2_ops, 260 }, 261 }, 262 }; 263 264 static struct clk_branch gpu_cc_cx_gfx3d_clk = { 265 .halt_reg = 0x10a4, 266 .halt_check = BRANCH_HALT_DELAY, 267 .clkr = { 268 .enable_reg = 0x10a4, 269 .enable_mask = BIT(0), 270 .hw.init = &(struct clk_init_data){ 271 .name = "gpu_cc_cx_gfx3d_clk", 272 .parent_data = &(const struct clk_parent_data){ 273 .hw = &gpu_cc_gx_gfx3d_clk_src.clkr.hw, 274 }, 275 .num_parents = 1, 276 .flags = CLK_SET_RATE_PARENT, 277 .ops = &clk_branch2_ops, 278 }, 279 }, 280 }; 281 282 static struct clk_branch gpu_cc_cx_gmu_clk = { 283 .halt_reg = 0x1098, 284 .halt_check = BRANCH_HALT, 285 .clkr = { 286 .enable_reg = 0x1098, 287 .enable_mask = BIT(0), 288 .hw.init = &(struct clk_init_data){ 289 .name = "gpu_cc_cx_gmu_clk", 290 .parent_data = &(const struct clk_parent_data){ 291 .hw = &gpu_cc_gmu_clk_src.clkr.hw, 292 }, 293 .num_parents = 1, 294 .flags = CLK_SET_RATE_PARENT, 295 .ops = &clk_branch2_ops, 296 }, 297 }, 298 }; 299 300 static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { 301 .halt_reg = 0x108c, 302 .halt_check = BRANCH_HALT_DELAY, 303 .clkr = { 304 .enable_reg = 0x108c, 305 .enable_mask = BIT(0), 306 .hw.init = &(struct clk_init_data){ 307 .name = "gpu_cc_cx_snoc_dvm_clk", 308 .ops = &clk_branch2_ops, 309 }, 310 }, 311 }; 312 313 static struct clk_branch gpu_cc_cxo_aon_clk = { 314 .halt_reg = 0x1004, 315 .halt_check = BRANCH_HALT_DELAY, 316 .clkr = { 317 .enable_reg = 0x1004, 318 .enable_mask = BIT(0), 319 .hw.init = &(struct clk_init_data){ 320 .name = "gpu_cc_cxo_aon_clk", 321 .ops = &clk_branch2_ops, 322 }, 323 }, 324 }; 325 326 static struct clk_branch gpu_cc_cxo_clk = { 327 .halt_reg = 0x109c, 328 .halt_check = BRANCH_HALT, 329 .clkr = { 330 .enable_reg = 0x109c, 331 .enable_mask = BIT(0), 332 .hw.init = &(struct clk_init_data){ 333 .name = "gpu_cc_cxo_clk", 334 .ops = &clk_branch2_ops, 335 }, 336 }, 337 }; 338 339 static struct clk_branch gpu_cc_gx_cxo_clk = { 340 .halt_reg = 0x1060, 341 .halt_check = BRANCH_HALT_DELAY, 342 .clkr = { 343 .enable_reg = 0x1060, 344 .enable_mask = BIT(0), 345 .hw.init = &(struct clk_init_data){ 346 .name = "gpu_cc_gx_cxo_clk", 347 .flags = CLK_IS_CRITICAL, 348 .ops = &clk_branch2_ops, 349 }, 350 }, 351 }; 352 353 static struct clk_branch gpu_cc_gx_gfx3d_clk = { 354 .halt_reg = 0x1054, 355 .halt_check = BRANCH_HALT_SKIP, 356 .clkr = { 357 .enable_reg = 0x1054, 358 .enable_mask = BIT(0), 359 .hw.init = &(struct clk_init_data){ 360 .name = "gpu_cc_gx_gfx3d_clk", 361 .parent_data = &(const struct clk_parent_data){ 362 .hw = &gpu_cc_gx_gfx3d_clk_src.clkr.hw, 363 }, 364 .num_parents = 1, 365 .flags = CLK_SET_RATE_PARENT, 366 .ops = &clk_branch2_ops, 367 }, 368 }, 369 }; 370 371 static struct clk_branch gpu_cc_sleep_clk = { 372 .halt_reg = 0x1090, 373 .halt_check = BRANCH_HALT_DELAY, 374 .clkr = { 375 .enable_reg = 0x1090, 376 .enable_mask = BIT(0), 377 .hw.init = &(struct clk_init_data){ 378 .name = "gpu_cc_sleep_clk", 379 .ops = &clk_branch2_ops, 380 }, 381 }, 382 }; 383 384 static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { 385 .halt_reg = 0x5000, 386 .halt_check = BRANCH_VOTED, 387 .clkr = { 388 .enable_reg = 0x5000, 389 .enable_mask = BIT(0), 390 .hw.init = &(struct clk_init_data){ 391 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", 392 .ops = &clk_branch2_ops, 393 }, 394 }, 395 }; 396 397 static struct gdsc gpu_cx_gdsc = { 398 .gdscr = 0x106c, 399 .gds_hw_ctrl = 0x1540, 400 .pd = { 401 .name = "gpu_cx_gdsc", 402 }, 403 .pwrsts = PWRSTS_OFF_ON, 404 .flags = VOTABLE, 405 }; 406 407 static struct gdsc gpu_gx_gdsc = { 408 .gdscr = 0x100c, 409 .clamp_io_ctrl = 0x1508, 410 .resets = (unsigned int []){ GPU_GX_BCR }, 411 .reset_count = 1, 412 .pd = { 413 .name = "gpu_gx_gdsc", 414 }, 415 .parent = &gpu_cx_gdsc.pd, 416 .pwrsts = PWRSTS_OFF_ON, 417 .flags = CLAMP_IO | SW_RESET | VOTABLE, 418 }; 419 420 static struct clk_regmap *gpu_cc_sm6115_clocks[] = { 421 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, 422 [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, 423 [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, 424 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, 425 [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, 426 [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, 427 [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, 428 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, 429 [GPU_CC_GX_CXO_CLK] = &gpu_cc_gx_cxo_clk.clkr, 430 [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, 431 [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, 432 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, 433 [GPU_CC_PLL0_OUT_AUX2] = &gpu_cc_pll0_out_aux2.clkr, 434 [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, 435 [GPU_CC_PLL1_OUT_AUX] = &gpu_cc_pll1_out_aux.clkr, 436 [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, 437 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, 438 }; 439 440 static const struct qcom_reset_map gpu_cc_sm6115_resets[] = { 441 [GPU_GX_BCR] = { 0x1008 }, 442 }; 443 444 static struct gdsc *gpu_cc_sm6115_gdscs[] = { 445 [GPU_CX_GDSC] = &gpu_cx_gdsc, 446 [GPU_GX_GDSC] = &gpu_gx_gdsc, 447 }; 448 449 static const struct regmap_config gpu_cc_sm6115_regmap_config = { 450 .reg_bits = 32, 451 .reg_stride = 4, 452 .val_bits = 32, 453 .max_register = 0x9000, 454 .fast_io = true, 455 }; 456 457 static const struct qcom_cc_desc gpu_cc_sm6115_desc = { 458 .config = &gpu_cc_sm6115_regmap_config, 459 .clks = gpu_cc_sm6115_clocks, 460 .num_clks = ARRAY_SIZE(gpu_cc_sm6115_clocks), 461 .resets = gpu_cc_sm6115_resets, 462 .num_resets = ARRAY_SIZE(gpu_cc_sm6115_resets), 463 .gdscs = gpu_cc_sm6115_gdscs, 464 .num_gdscs = ARRAY_SIZE(gpu_cc_sm6115_gdscs), 465 }; 466 467 static const struct of_device_id gpu_cc_sm6115_match_table[] = { 468 { .compatible = "qcom,sm6115-gpucc" }, 469 { } 470 }; 471 MODULE_DEVICE_TABLE(of, gpu_cc_sm6115_match_table); 472 473 static int gpu_cc_sm6115_probe(struct platform_device *pdev) 474 { 475 struct regmap *regmap; 476 477 regmap = qcom_cc_map(pdev, &gpu_cc_sm6115_desc); 478 if (IS_ERR(regmap)) 479 return PTR_ERR(regmap); 480 481 clk_alpha_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); 482 clk_alpha_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); 483 484 /* Set recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ 485 qcom_branch_set_wakeup(regmap, gpu_cc_cx_gmu_clk, 0xf); 486 qcom_branch_set_sleep(regmap, gpu_cc_cx_gmu_clk, 0xf); 487 488 qcom_branch_set_force_mem_core(regmap, gpu_cc_gx_gfx3d_clk, true); 489 qcom_branch_set_force_periph_on(regmap, gpu_cc_gx_gfx3d_clk, true); 490 491 return qcom_cc_really_probe(&pdev->dev, &gpu_cc_sm6115_desc, regmap); 492 } 493 494 static struct platform_driver gpu_cc_sm6115_driver = { 495 .probe = gpu_cc_sm6115_probe, 496 .driver = { 497 .name = "sm6115-gpucc", 498 .of_match_table = gpu_cc_sm6115_match_table, 499 }, 500 }; 501 module_platform_driver(gpu_cc_sm6115_driver); 502 503 MODULE_DESCRIPTION("QTI GPU_CC SM6115 Driver"); 504 MODULE_LICENSE("GPL"); 505