1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/kernel.h> 8 #include <linux/mod_devicetable.h> 9 #include <linux/module.h> 10 #include <linux/platform_device.h> 11 #include <linux/pm_runtime.h> 12 #include <linux/regmap.h> 13 14 #include <dt-bindings/clock/qcom,gpucc-sc8280xp.h> 15 16 #include "clk-alpha-pll.h" 17 #include "clk-branch.h" 18 #include "clk-rcg.h" 19 #include "clk-regmap-divider.h" 20 #include "common.h" 21 #include "reset.h" 22 #include "gdsc.h" 23 24 /* Need to match the order of clocks in DT binding */ 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_GCC_GPU_GPLL0_CLK_SRC, 34 P_GCC_GPU_GPLL0_DIV_CLK_SRC, 35 P_GPU_CC_PLL0_OUT_MAIN, 36 P_GPU_CC_PLL1_OUT_MAIN, 37 }; 38 39 static const struct clk_parent_data parent_data_tcxo = { .index = DT_BI_TCXO }; 40 41 static const struct pll_vco lucid_5lpe_vco[] = { 42 { 249600000, 1800000000, 0 }, 43 }; 44 45 static struct alpha_pll_config gpu_cc_pll0_config = { 46 .l = 0x1c, 47 .alpha = 0xa555, 48 .config_ctl_val = 0x20485699, 49 .config_ctl_hi_val = 0x00002261, 50 .config_ctl_hi1_val = 0x2a9a699c, 51 .test_ctl_val = 0x00000000, 52 .test_ctl_hi_val = 0x00000000, 53 .test_ctl_hi1_val = 0x01800000, 54 .user_ctl_val = 0x00000000, 55 .user_ctl_hi_val = 0x00000805, 56 .user_ctl_hi1_val = 0x00000000, 57 }; 58 59 static struct clk_alpha_pll gpu_cc_pll0 = { 60 .offset = 0x0, 61 .vco_table = lucid_5lpe_vco, 62 .num_vco = ARRAY_SIZE(lucid_5lpe_vco), 63 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], 64 .clkr = { 65 .hw.init = &(const struct clk_init_data){ 66 .name = "gpu_cc_pll0", 67 .parent_data = &parent_data_tcxo, 68 .num_parents = 1, 69 .ops = &clk_alpha_pll_lucid_5lpe_ops, 70 }, 71 }, 72 }; 73 74 static struct alpha_pll_config gpu_cc_pll1_config = { 75 .l = 0x1A, 76 .alpha = 0xaaa, 77 .config_ctl_val = 0x20485699, 78 .config_ctl_hi_val = 0x00002261, 79 .config_ctl_hi1_val = 0x2a9a699c, 80 .test_ctl_val = 0x00000000, 81 .test_ctl_hi_val = 0x00000000, 82 .test_ctl_hi1_val = 0x01800000, 83 .user_ctl_val = 0x00000000, 84 .user_ctl_hi_val = 0x00000805, 85 .user_ctl_hi1_val = 0x00000000, 86 }; 87 88 static struct clk_alpha_pll gpu_cc_pll1 = { 89 .offset = 0x100, 90 .vco_table = lucid_5lpe_vco, 91 .num_vco = ARRAY_SIZE(lucid_5lpe_vco), 92 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], 93 .clkr = { 94 .hw.init = &(const struct clk_init_data){ 95 .name = "gpu_cc_pll1", 96 .parent_data = &parent_data_tcxo, 97 .num_parents = 1, 98 .ops = &clk_alpha_pll_lucid_5lpe_ops, 99 }, 100 }, 101 }; 102 103 static const struct parent_map gpu_cc_parent_map_0[] = { 104 { P_BI_TCXO, 0 }, 105 { P_GPU_CC_PLL0_OUT_MAIN, 1 }, 106 { P_GPU_CC_PLL1_OUT_MAIN, 3 }, 107 { P_GCC_GPU_GPLL0_CLK_SRC, 5 }, 108 { P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 }, 109 }; 110 111 static const struct clk_parent_data gpu_cc_parent_data_0[] = { 112 { .index = DT_BI_TCXO }, 113 { .hw = &gpu_cc_pll0.clkr.hw }, 114 { .hw = &gpu_cc_pll1.clkr.hw }, 115 { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, 116 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, 117 }; 118 119 static const struct parent_map gpu_cc_parent_map_1[] = { 120 { P_BI_TCXO, 0 }, 121 { P_GPU_CC_PLL1_OUT_MAIN, 3 }, 122 { P_GCC_GPU_GPLL0_CLK_SRC, 5 }, 123 { P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 }, 124 }; 125 126 static const struct clk_parent_data gpu_cc_parent_data_1[] = { 127 { .index = DT_BI_TCXO }, 128 { .hw = &gpu_cc_pll1.clkr.hw }, 129 { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, 130 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, 131 }; 132 133 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { 134 F(19200000, P_BI_TCXO, 1, 0, 0), 135 F(200000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 1.5, 0, 0), 136 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), 137 { } 138 }; 139 140 static struct clk_rcg2 gpu_cc_gmu_clk_src = { 141 .cmd_rcgr = 0x1120, 142 .mnd_width = 0, 143 .hid_width = 5, 144 .parent_map = gpu_cc_parent_map_0, 145 .freq_tbl = ftbl_gpu_cc_gmu_clk_src, 146 .clkr.hw.init = &(const struct clk_init_data){ 147 .name = "gpu_cc_gmu_clk_src", 148 .parent_data = gpu_cc_parent_data_0, 149 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), 150 .ops = &clk_rcg2_shared_ops, 151 }, 152 }; 153 154 static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = { 155 F(200000000, P_GCC_GPU_GPLL0_CLK_SRC, 3, 0, 0), 156 F(300000000, P_GCC_GPU_GPLL0_CLK_SRC, 2, 0, 0), 157 F(400000000, P_GCC_GPU_GPLL0_CLK_SRC, 1.5, 0, 0), 158 { } 159 }; 160 161 static struct clk_rcg2 gpu_cc_hub_clk_src = { 162 .cmd_rcgr = 0x117c, 163 .mnd_width = 0, 164 .hid_width = 5, 165 .parent_map = gpu_cc_parent_map_1, 166 .freq_tbl = ftbl_gpu_cc_hub_clk_src, 167 .clkr.hw.init = &(const struct clk_init_data){ 168 .name = "gpu_cc_hub_clk_src", 169 .parent_data = gpu_cc_parent_data_1, 170 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), 171 .ops = &clk_rcg2_shared_ops, 172 }, 173 }; 174 175 static struct clk_regmap_div gpu_cc_hub_ahb_div_clk_src = { 176 .reg = 0x11c0, 177 .shift = 0, 178 .width = 4, 179 .clkr.hw.init = &(const struct clk_init_data) { 180 .name = "gpu_cc_hub_ahb_div_clk_src", 181 .parent_hws = (const struct clk_hw*[]){ 182 &gpu_cc_hub_clk_src.clkr.hw, 183 }, 184 .num_parents = 1, 185 .flags = CLK_SET_RATE_PARENT, 186 .ops = &clk_regmap_div_ro_ops, 187 }, 188 }; 189 190 static struct clk_regmap_div gpu_cc_hub_cx_int_div_clk_src = { 191 .reg = 0x11bc, 192 .shift = 0, 193 .width = 4, 194 .clkr.hw.init = &(const struct clk_init_data) { 195 .name = "gpu_cc_hub_cx_int_div_clk_src", 196 .parent_hws = (const struct clk_hw*[]){ 197 &gpu_cc_hub_clk_src.clkr.hw, 198 }, 199 .num_parents = 1, 200 .flags = CLK_SET_RATE_PARENT, 201 .ops = &clk_regmap_div_ro_ops, 202 }, 203 }; 204 205 static struct clk_branch gpu_cc_ahb_clk = { 206 .halt_reg = 0x1078, 207 .halt_check = BRANCH_HALT_DELAY, 208 .clkr = { 209 .enable_reg = 0x1078, 210 .enable_mask = BIT(0), 211 .hw.init = &(const struct clk_init_data){ 212 .name = "gpu_cc_ahb_clk", 213 .parent_hws = (const struct clk_hw*[]){ 214 &gpu_cc_hub_ahb_div_clk_src.clkr.hw, 215 }, 216 .num_parents = 1, 217 .flags = CLK_SET_RATE_PARENT, 218 .ops = &clk_branch2_ops, 219 }, 220 }, 221 }; 222 223 static struct clk_branch gpu_cc_crc_ahb_clk = { 224 .halt_reg = 0x107c, 225 .halt_check = BRANCH_HALT_VOTED, 226 .clkr = { 227 .enable_reg = 0x107c, 228 .enable_mask = BIT(0), 229 .hw.init = &(const struct clk_init_data){ 230 .name = "gpu_cc_crc_ahb_clk", 231 .parent_hws = (const struct clk_hw*[]){ 232 &gpu_cc_hub_ahb_div_clk_src.clkr.hw, 233 }, 234 .num_parents = 1, 235 .flags = CLK_SET_RATE_PARENT, 236 .ops = &clk_branch2_ops, 237 }, 238 }, 239 }; 240 241 static struct clk_branch gpu_cc_cx_gmu_clk = { 242 .halt_reg = 0x1098, 243 .halt_check = BRANCH_HALT, 244 .clkr = { 245 .enable_reg = 0x1098, 246 .enable_mask = BIT(0), 247 .hw.init = &(const struct clk_init_data){ 248 .name = "gpu_cc_cx_gmu_clk", 249 .parent_hws = (const struct clk_hw*[]){ 250 &gpu_cc_gmu_clk_src.clkr.hw, 251 }, 252 .num_parents = 1, 253 .flags = CLK_SET_RATE_PARENT, 254 .ops = &clk_branch2_aon_ops, 255 }, 256 }, 257 }; 258 259 static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { 260 .halt_reg = 0x108c, 261 .halt_check = BRANCH_HALT_VOTED, 262 .clkr = { 263 .enable_reg = 0x108c, 264 .enable_mask = BIT(0), 265 .hw.init = &(const struct clk_init_data){ 266 .name = "gpu_cc_cx_snoc_dvm_clk", 267 .ops = &clk_branch2_ops, 268 }, 269 }, 270 }; 271 272 static struct clk_branch gpu_cc_cxo_aon_clk = { 273 .halt_reg = 0x1004, 274 .halt_check = BRANCH_HALT_VOTED, 275 .clkr = { 276 .enable_reg = 0x1004, 277 .enable_mask = BIT(0), 278 .hw.init = &(const struct clk_init_data){ 279 .name = "gpu_cc_cxo_aon_clk", 280 .ops = &clk_branch2_ops, 281 }, 282 }, 283 }; 284 285 static struct clk_branch gpu_cc_gx_gmu_clk = { 286 .halt_reg = 0x1064, 287 .halt_check = BRANCH_HALT, 288 .clkr = { 289 .enable_reg = 0x1064, 290 .enable_mask = BIT(0), 291 .hw.init = &(const struct clk_init_data){ 292 .name = "gpu_cc_gx_gmu_clk", 293 .parent_hws = (const struct clk_hw*[]){ 294 &gpu_cc_gmu_clk_src.clkr.hw, 295 }, 296 .num_parents = 1, 297 .flags = CLK_SET_RATE_PARENT, 298 .ops = &clk_branch2_ops, 299 }, 300 }, 301 }; 302 303 static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { 304 .halt_reg = 0x5000, 305 .halt_check = BRANCH_HALT_VOTED, 306 .clkr = { 307 .enable_reg = 0x5000, 308 .enable_mask = BIT(0), 309 .hw.init = &(const struct clk_init_data){ 310 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", 311 .ops = &clk_branch2_ops, 312 }, 313 }, 314 }; 315 316 static struct clk_branch gpu_cc_hub_aon_clk = { 317 .halt_reg = 0x1178, 318 .halt_check = BRANCH_HALT, 319 .clkr = { 320 .enable_reg = 0x1178, 321 .enable_mask = BIT(0), 322 .hw.init = &(const struct clk_init_data){ 323 .name = "gpu_cc_hub_aon_clk", 324 .parent_hws = (const struct clk_hw*[]){ 325 &gpu_cc_hub_clk_src.clkr.hw, 326 }, 327 .num_parents = 1, 328 .flags = CLK_SET_RATE_PARENT, 329 .ops = &clk_branch2_aon_ops, 330 }, 331 }, 332 }; 333 334 static struct clk_branch gpu_cc_hub_cx_int_clk = { 335 .halt_reg = 0x1204, 336 .halt_check = BRANCH_HALT, 337 .clkr = { 338 .enable_reg = 0x1204, 339 .enable_mask = BIT(0), 340 .hw.init = &(const struct clk_init_data){ 341 .name = "gpu_cc_hub_cx_int_clk", 342 .parent_hws = (const struct clk_hw*[]){ 343 &gpu_cc_hub_cx_int_div_clk_src.clkr.hw, 344 }, 345 .num_parents = 1, 346 .flags = CLK_SET_RATE_PARENT, 347 .ops = &clk_branch2_aon_ops, 348 }, 349 }, 350 }; 351 352 static struct clk_branch gpu_cc_sleep_clk = { 353 .halt_reg = 0x1090, 354 .halt_check = BRANCH_HALT_VOTED, 355 .clkr = { 356 .enable_reg = 0x1090, 357 .enable_mask = BIT(0), 358 .hw.init = &(const struct clk_init_data){ 359 .name = "gpu_cc_sleep_clk", 360 .ops = &clk_branch2_ops, 361 }, 362 }, 363 }; 364 365 static struct clk_regmap *gpu_cc_sc8280xp_clocks[] = { 366 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, 367 [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, 368 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, 369 [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, 370 [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, 371 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, 372 [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, 373 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, 374 [GPU_CC_HUB_AHB_DIV_CLK_SRC] = &gpu_cc_hub_ahb_div_clk_src.clkr, 375 [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr, 376 [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr, 377 [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr, 378 [GPU_CC_HUB_CX_INT_DIV_CLK_SRC] = &gpu_cc_hub_cx_int_div_clk_src.clkr, 379 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, 380 [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, 381 [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, 382 }; 383 384 static struct gdsc cx_gdsc = { 385 .gdscr = 0x106c, 386 .gds_hw_ctrl = 0x1540, 387 .pd = { 388 .name = "cx_gdsc", 389 }, 390 .pwrsts = PWRSTS_OFF_ON, 391 .flags = VOTABLE | RETAIN_FF_ENABLE, 392 }; 393 394 static struct gdsc gx_gdsc = { 395 .gdscr = 0x100c, 396 .clamp_io_ctrl = 0x1508, 397 .pd = { 398 .name = "gx_gdsc", 399 .power_on = gdsc_gx_do_nothing_enable, 400 }, 401 .pwrsts = PWRSTS_OFF_ON, 402 .flags = CLAMP_IO | RETAIN_FF_ENABLE, 403 .supply = "vdd-gfx", 404 }; 405 406 static struct gdsc *gpu_cc_sc8280xp_gdscs[] = { 407 [GPU_CC_CX_GDSC] = &cx_gdsc, 408 [GPU_CC_GX_GDSC] = &gx_gdsc, 409 }; 410 411 static const struct regmap_config gpu_cc_sc8280xp_regmap_config = { 412 .reg_bits = 32, 413 .reg_stride = 4, 414 .val_bits = 32, 415 .max_register = 0x8030, 416 .fast_io = true, 417 }; 418 419 static const struct qcom_cc_desc gpu_cc_sc8280xp_desc = { 420 .config = &gpu_cc_sc8280xp_regmap_config, 421 .clks = gpu_cc_sc8280xp_clocks, 422 .num_clks = ARRAY_SIZE(gpu_cc_sc8280xp_clocks), 423 .gdscs = gpu_cc_sc8280xp_gdscs, 424 .num_gdscs = ARRAY_SIZE(gpu_cc_sc8280xp_gdscs), 425 }; 426 427 static int gpu_cc_sc8280xp_probe(struct platform_device *pdev) 428 { 429 struct regmap *regmap; 430 int ret; 431 432 ret = devm_pm_runtime_enable(&pdev->dev); 433 if (ret) 434 return ret; 435 436 ret = pm_runtime_resume_and_get(&pdev->dev); 437 if (ret) 438 return ret; 439 440 regmap = qcom_cc_map(pdev, &gpu_cc_sc8280xp_desc); 441 if (IS_ERR(regmap)) { 442 pm_runtime_put(&pdev->dev); 443 return PTR_ERR(regmap); 444 } 445 446 clk_lucid_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); 447 clk_lucid_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); 448 449 /* Keep some clocks always-on */ 450 qcom_branch_set_clk_en(regmap, 0x1170); /* GPU_CC_CB_CLK */ 451 qcom_branch_set_clk_en(regmap, 0x109c); /* GPU_CC_CXO_CLK */ 452 453 ret = qcom_cc_really_probe(&pdev->dev, &gpu_cc_sc8280xp_desc, regmap); 454 pm_runtime_put(&pdev->dev); 455 456 return ret; 457 } 458 459 static const struct of_device_id gpu_cc_sc8280xp_match_table[] = { 460 { .compatible = "qcom,sc8280xp-gpucc" }, 461 { } 462 }; 463 MODULE_DEVICE_TABLE(of, gpu_cc_sc8280xp_match_table); 464 465 static struct platform_driver gpu_cc_sc8280xp_driver = { 466 .probe = gpu_cc_sc8280xp_probe, 467 .driver = { 468 .name = "gpu_cc-sc8280xp", 469 .of_match_table = gpu_cc_sc8280xp_match_table, 470 }, 471 }; 472 module_platform_driver(gpu_cc_sc8280xp_driver); 473 474 MODULE_DESCRIPTION("Qualcomm SC8280XP GPU clock controller"); 475 MODULE_LICENSE("GPL"); 476