1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2021, 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/pm_runtime.h> 12 #include <linux/regmap.h> 13 14 #include <dt-bindings/clock/qcom,sm6375-gpucc.h> 15 16 #include "clk-alpha-pll.h" 17 #include "clk-branch.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 "clk-regmap-phy-mux.h" 23 #include "gdsc.h" 24 #include "reset.h" 25 26 enum { 27 DT_BI_TCXO, 28 DT_GCC_GPU_GPLL0_CLK_SRC, 29 DT_GCC_GPU_GPLL0_DIV_CLK_SRC, 30 DT_GCC_GPU_SNOC_DVM_GFX_CLK, 31 }; 32 33 enum { 34 P_BI_TCXO, 35 P_GCC_GPU_GPLL0_CLK_SRC, 36 P_GCC_GPU_GPLL0_DIV_CLK_SRC, 37 P_GPU_CC_PLL0_OUT_EVEN, 38 P_GPU_CC_PLL0_OUT_MAIN, 39 P_GPU_CC_PLL0_OUT_ODD, 40 P_GPU_CC_PLL1_OUT_EVEN, 41 P_GPU_CC_PLL1_OUT_MAIN, 42 P_GPU_CC_PLL1_OUT_ODD, 43 }; 44 45 static const struct pll_vco lucid_vco[] = { 46 { 249600000, 2000000000, 0 }, 47 }; 48 49 /* 532MHz Configuration */ 50 static const struct alpha_pll_config gpucc_pll0_config = { 51 .l = 0x1b, 52 .alpha = 0xb555, 53 .config_ctl_val = 0x20485699, 54 .config_ctl_hi_val = 0x00002261, 55 .config_ctl_hi1_val = 0x329a299c, 56 .user_ctl_val = 0x00000001, 57 .user_ctl_hi_val = 0x00000805, 58 .user_ctl_hi1_val = 0x00000000, 59 }; 60 61 static struct clk_alpha_pll gpucc_pll0 = { 62 .offset = 0x0, 63 .vco_table = lucid_vco, 64 .num_vco = ARRAY_SIZE(lucid_vco), 65 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], 66 .clkr = { 67 .hw.init = &(struct clk_init_data){ 68 .name = "gpucc_pll0", 69 .parent_data = &(const struct clk_parent_data){ 70 .index = P_BI_TCXO, 71 }, 72 .num_parents = 1, 73 .ops = &clk_alpha_pll_lucid_ops, 74 }, 75 }, 76 }; 77 78 /* 514MHz Configuration */ 79 static const struct alpha_pll_config gpucc_pll1_config = { 80 .l = 0x1a, 81 .alpha = 0xc555, 82 .config_ctl_val = 0x20485699, 83 .config_ctl_hi_val = 0x00002261, 84 .config_ctl_hi1_val = 0x329a299c, 85 .user_ctl_val = 0x00000001, 86 .user_ctl_hi_val = 0x00000805, 87 .user_ctl_hi1_val = 0x00000000, 88 }; 89 90 static struct clk_alpha_pll gpucc_pll1 = { 91 .offset = 0x100, 92 .vco_table = lucid_vco, 93 .num_vco = ARRAY_SIZE(lucid_vco), 94 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], 95 .clkr = { 96 .hw.init = &(struct clk_init_data){ 97 .name = "gpucc_pll1", 98 .parent_data = &(const struct clk_parent_data){ 99 .index = P_BI_TCXO, 100 }, 101 .num_parents = 1, 102 .ops = &clk_alpha_pll_lucid_ops, 103 }, 104 }, 105 }; 106 107 static const struct parent_map gpucc_parent_map_0[] = { 108 { P_BI_TCXO, 0 }, 109 { P_GPU_CC_PLL0_OUT_MAIN, 1 }, 110 { P_GPU_CC_PLL1_OUT_MAIN, 3 }, 111 { P_GCC_GPU_GPLL0_CLK_SRC, 5 }, 112 { P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 }, 113 }; 114 115 static const struct clk_parent_data gpucc_parent_data_0[] = { 116 { .index = P_BI_TCXO }, 117 { .hw = &gpucc_pll0.clkr.hw }, 118 { .hw = &gpucc_pll1.clkr.hw }, 119 { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, 120 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC }, 121 }; 122 123 static const struct parent_map gpucc_parent_map_1[] = { 124 { P_BI_TCXO, 0 }, 125 { P_GPU_CC_PLL0_OUT_EVEN, 1 }, 126 { P_GPU_CC_PLL0_OUT_ODD, 2 }, 127 { P_GPU_CC_PLL1_OUT_EVEN, 3 }, 128 { P_GPU_CC_PLL1_OUT_ODD, 4 }, 129 { P_GCC_GPU_GPLL0_CLK_SRC, 5 }, 130 }; 131 132 static const struct clk_parent_data gpucc_parent_data_1[] = { 133 { .index = P_BI_TCXO }, 134 { .hw = &gpucc_pll0.clkr.hw }, 135 { .hw = &gpucc_pll0.clkr.hw }, 136 { .hw = &gpucc_pll1.clkr.hw }, 137 { .hw = &gpucc_pll1.clkr.hw }, 138 { .index = DT_GCC_GPU_GPLL0_CLK_SRC }, 139 }; 140 141 static const struct freq_tbl ftbl_gpucc_gmu_clk_src[] = { 142 F(200000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 1.5, 0, 0), 143 { } 144 }; 145 146 static struct clk_rcg2 gpucc_gmu_clk_src = { 147 .cmd_rcgr = 0x1120, 148 .mnd_width = 0, 149 .hid_width = 5, 150 .parent_map = gpucc_parent_map_0, 151 .freq_tbl = ftbl_gpucc_gmu_clk_src, 152 .clkr.hw.init = &(struct clk_init_data){ 153 .name = "gpucc_gmu_clk_src", 154 .parent_data = gpucc_parent_data_0, 155 .num_parents = ARRAY_SIZE(gpucc_parent_data_0), 156 .ops = &clk_rcg2_shared_ops, 157 }, 158 }; 159 160 static const struct freq_tbl ftbl_gpucc_gx_gfx3d_clk_src[] = { 161 F(266000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 162 F(390000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 163 F(490000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 164 F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 165 F(770000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 166 F(840000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 167 F(900000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0), 168 { } 169 }; 170 171 static struct clk_rcg2 gpucc_gx_gfx3d_clk_src = { 172 .cmd_rcgr = 0x101c, 173 .mnd_width = 0, 174 .hid_width = 5, 175 .parent_map = gpucc_parent_map_1, 176 .freq_tbl = ftbl_gpucc_gx_gfx3d_clk_src, 177 .clkr.hw.init = &(struct clk_init_data){ 178 .name = "gpucc_gx_gfx3d_clk_src", 179 .parent_data = gpucc_parent_data_1, 180 .num_parents = ARRAY_SIZE(gpucc_parent_data_1), 181 .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, 182 .ops = &clk_rcg2_ops, 183 }, 184 }; 185 186 static struct clk_branch gpucc_ahb_clk = { 187 .halt_reg = 0x1078, 188 .halt_check = BRANCH_HALT_DELAY, 189 .clkr = { 190 .enable_reg = 0x1078, 191 .enable_mask = BIT(0), 192 .hw.init = &(struct clk_init_data){ 193 .name = "gpucc_ahb_clk", 194 .flags = CLK_IS_CRITICAL, 195 .ops = &clk_branch2_ops, 196 }, 197 }, 198 }; 199 200 static struct clk_branch gpucc_cx_gfx3d_clk = { 201 .halt_reg = 0x10a4, 202 .halt_check = BRANCH_HALT_DELAY, 203 .clkr = { 204 .enable_reg = 0x10a4, 205 .enable_mask = BIT(0), 206 .hw.init = &(struct clk_init_data){ 207 .name = "gpucc_cx_gfx3d_clk", 208 .parent_hws = (const struct clk_hw*[]) { 209 &gpucc_gx_gfx3d_clk_src.clkr.hw, 210 }, 211 .num_parents = 1, 212 .flags = CLK_SET_RATE_PARENT, 213 .ops = &clk_branch2_ops, 214 }, 215 }, 216 }; 217 218 static struct clk_branch gpucc_cx_gfx3d_slv_clk = { 219 .halt_reg = 0x10a8, 220 .halt_check = BRANCH_HALT_DELAY, 221 .clkr = { 222 .enable_reg = 0x10a8, 223 .enable_mask = BIT(0), 224 .hw.init = &(struct clk_init_data){ 225 .name = "gpucc_cx_gfx3d_slv_clk", 226 .parent_hws = (const struct clk_hw*[]) { 227 &gpucc_gx_gfx3d_clk_src.clkr.hw, 228 }, 229 .num_parents = 1, 230 .flags = CLK_SET_RATE_PARENT, 231 .ops = &clk_branch2_ops, 232 }, 233 }, 234 }; 235 236 static struct clk_branch gpucc_cx_gmu_clk = { 237 .halt_reg = 0x1098, 238 .halt_check = BRANCH_HALT, 239 .clkr = { 240 .enable_reg = 0x1098, 241 .enable_mask = BIT(0), 242 .hw.init = &(struct clk_init_data){ 243 .name = "gpucc_cx_gmu_clk", 244 .parent_hws = (const struct clk_hw*[]) { 245 &gpucc_gmu_clk_src.clkr.hw, 246 }, 247 .num_parents = 1, 248 .flags = CLK_SET_RATE_PARENT, 249 .ops = &clk_branch2_ops, 250 }, 251 }, 252 }; 253 254 static struct clk_branch gpucc_cx_snoc_dvm_clk = { 255 .halt_reg = 0x108c, 256 .halt_check = BRANCH_HALT_DELAY, 257 .clkr = { 258 .enable_reg = 0x108c, 259 .enable_mask = BIT(0), 260 .hw.init = &(struct clk_init_data){ 261 .name = "gpucc_cx_snoc_dvm_clk", 262 .parent_data = &(const struct clk_parent_data){ 263 .index = DT_GCC_GPU_SNOC_DVM_GFX_CLK, 264 }, 265 .num_parents = 1, 266 .ops = &clk_branch2_ops, 267 }, 268 }, 269 }; 270 271 static struct clk_branch gpucc_cxo_aon_clk = { 272 .halt_reg = 0x1004, 273 .halt_check = BRANCH_HALT_DELAY, 274 .clkr = { 275 .enable_reg = 0x1004, 276 .enable_mask = BIT(0), 277 .hw.init = &(struct clk_init_data){ 278 .name = "gpucc_cxo_aon_clk", 279 .ops = &clk_branch2_ops, 280 }, 281 }, 282 }; 283 284 static struct clk_branch gpucc_cxo_clk = { 285 .halt_reg = 0x109c, 286 .halt_check = BRANCH_HALT, 287 .clkr = { 288 .enable_reg = 0x109c, 289 .enable_mask = BIT(0), 290 .hw.init = &(struct clk_init_data){ 291 .name = "gpucc_cxo_clk", 292 .ops = &clk_branch2_ops, 293 }, 294 }, 295 }; 296 297 static struct clk_branch gpucc_gx_cxo_clk = { 298 .halt_reg = 0x1060, 299 .halt_check = BRANCH_HALT_DELAY, 300 .clkr = { 301 .enable_reg = 0x1060, 302 .enable_mask = BIT(0), 303 .hw.init = &(struct clk_init_data){ 304 .name = "gpucc_gx_cxo_clk", 305 .flags = CLK_IS_CRITICAL, 306 .ops = &clk_branch2_ops, 307 }, 308 }, 309 }; 310 311 static struct clk_branch gpucc_gx_gfx3d_clk = { 312 .halt_reg = 0x1054, 313 .halt_check = BRANCH_HALT_DELAY, 314 .clkr = { 315 .enable_reg = 0x1054, 316 .enable_mask = BIT(0), 317 .hw.init = &(struct clk_init_data){ 318 .name = "gpucc_gx_gfx3d_clk", 319 .parent_hws = (const struct clk_hw*[]) { 320 &gpucc_gx_gfx3d_clk_src.clkr.hw, 321 }, 322 .num_parents = 1, 323 .flags = CLK_SET_RATE_PARENT, 324 .ops = &clk_branch2_ops, 325 }, 326 }, 327 }; 328 329 static struct clk_branch gpucc_gx_gmu_clk = { 330 .halt_reg = 0x1064, 331 .halt_check = BRANCH_HALT, 332 .clkr = { 333 .enable_reg = 0x1064, 334 .enable_mask = BIT(0), 335 .hw.init = &(struct clk_init_data){ 336 .name = "gpucc_gx_gmu_clk", 337 .parent_hws = (const struct clk_hw*[]) { 338 &gpucc_gmu_clk_src.clkr.hw, 339 }, 340 .num_parents = 1, 341 .flags = CLK_SET_RATE_PARENT, 342 .ops = &clk_branch2_ops, 343 }, 344 }, 345 }; 346 347 static struct clk_branch gpucc_sleep_clk = { 348 .halt_reg = 0x1090, 349 .halt_check = BRANCH_HALT_VOTED, 350 .clkr = { 351 .enable_reg = 0x1090, 352 .enable_mask = BIT(0), 353 .hw.init = &(struct clk_init_data){ 354 .name = "gpucc_sleep_clk", 355 .ops = &clk_branch2_ops, 356 }, 357 }, 358 }; 359 360 static struct gdsc gpu_cx_gdsc = { 361 .gdscr = 0x106c, 362 .gds_hw_ctrl = 0x1540, 363 .clk_dis_wait_val = 8, 364 .pd = { 365 .name = "gpu_cx_gdsc", 366 }, 367 .pwrsts = PWRSTS_OFF_ON, 368 .flags = VOTABLE, 369 }; 370 371 static struct gdsc gpu_gx_gdsc = { 372 .gdscr = 0x100c, 373 .clamp_io_ctrl = 0x1508, 374 .resets = (unsigned int []){ GPU_GX_BCR, GPU_ACD_BCR, GPU_GX_ACD_MISC_BCR }, 375 .reset_count = 3, 376 .pd = { 377 .name = "gpu_gx_gdsc", 378 }, 379 .pwrsts = PWRSTS_OFF_ON, 380 .flags = CLAMP_IO | SW_RESET | AON_RESET, 381 }; 382 383 static struct clk_regmap *gpucc_sm6375_clocks[] = { 384 [GPU_CC_AHB_CLK] = &gpucc_ahb_clk.clkr, 385 [GPU_CC_CX_GFX3D_CLK] = &gpucc_cx_gfx3d_clk.clkr, 386 [GPU_CC_CX_GFX3D_SLV_CLK] = &gpucc_cx_gfx3d_slv_clk.clkr, 387 [GPU_CC_CX_GMU_CLK] = &gpucc_cx_gmu_clk.clkr, 388 [GPU_CC_CX_SNOC_DVM_CLK] = &gpucc_cx_snoc_dvm_clk.clkr, 389 [GPU_CC_CXO_AON_CLK] = &gpucc_cxo_aon_clk.clkr, 390 [GPU_CC_CXO_CLK] = &gpucc_cxo_clk.clkr, 391 [GPU_CC_GMU_CLK_SRC] = &gpucc_gmu_clk_src.clkr, 392 [GPU_CC_GX_CXO_CLK] = &gpucc_gx_cxo_clk.clkr, 393 [GPU_CC_GX_GFX3D_CLK] = &gpucc_gx_gfx3d_clk.clkr, 394 [GPU_CC_GX_GFX3D_CLK_SRC] = &gpucc_gx_gfx3d_clk_src.clkr, 395 [GPU_CC_GX_GMU_CLK] = &gpucc_gx_gmu_clk.clkr, 396 [GPU_CC_PLL0] = &gpucc_pll0.clkr, 397 [GPU_CC_PLL1] = &gpucc_pll1.clkr, 398 [GPU_CC_SLEEP_CLK] = &gpucc_sleep_clk.clkr, 399 }; 400 401 static const struct qcom_reset_map gpucc_sm6375_resets[] = { 402 [GPU_GX_BCR] = { 0x1008 }, 403 [GPU_ACD_BCR] = { 0x1160 }, 404 [GPU_GX_ACD_MISC_BCR] = { 0x8004 }, 405 }; 406 407 static struct gdsc *gpucc_sm6375_gdscs[] = { 408 [GPU_CX_GDSC] = &gpu_cx_gdsc, 409 [GPU_GX_GDSC] = &gpu_gx_gdsc, 410 }; 411 412 static const struct regmap_config gpucc_sm6375_regmap_config = { 413 .reg_bits = 32, 414 .reg_stride = 4, 415 .val_bits = 32, 416 .max_register = 0x9000, 417 .fast_io = true, 418 }; 419 420 static const struct qcom_cc_desc gpucc_sm6375_desc = { 421 .config = &gpucc_sm6375_regmap_config, 422 .clks = gpucc_sm6375_clocks, 423 .num_clks = ARRAY_SIZE(gpucc_sm6375_clocks), 424 .resets = gpucc_sm6375_resets, 425 .num_resets = ARRAY_SIZE(gpucc_sm6375_resets), 426 .gdscs = gpucc_sm6375_gdscs, 427 .num_gdscs = ARRAY_SIZE(gpucc_sm6375_gdscs), 428 }; 429 430 static const struct of_device_id gpucc_sm6375_match_table[] = { 431 { .compatible = "qcom,sm6375-gpucc" }, 432 { } 433 }; 434 MODULE_DEVICE_TABLE(of, gpucc_sm6375_match_table); 435 436 static int gpucc_sm6375_probe(struct platform_device *pdev) 437 { 438 struct regmap *regmap; 439 int ret; 440 441 ret = devm_pm_runtime_enable(&pdev->dev); 442 if (ret) 443 return ret; 444 445 ret = pm_runtime_resume_and_get(&pdev->dev); 446 if (ret) 447 return ret; 448 449 regmap = qcom_cc_map(pdev, &gpucc_sm6375_desc); 450 if (IS_ERR(regmap)) { 451 pm_runtime_put(&pdev->dev); 452 return PTR_ERR(regmap); 453 } 454 455 clk_lucid_pll_configure(&gpucc_pll0, regmap, &gpucc_pll0_config); 456 clk_lucid_pll_configure(&gpucc_pll1, regmap, &gpucc_pll1_config); 457 458 ret = qcom_cc_really_probe(&pdev->dev, &gpucc_sm6375_desc, regmap); 459 pm_runtime_put(&pdev->dev); 460 461 return ret; 462 } 463 464 static struct platform_driver gpucc_sm6375_driver = { 465 .probe = gpucc_sm6375_probe, 466 .driver = { 467 .name = "gpucc-sm6375", 468 .of_match_table = gpucc_sm6375_match_table, 469 }, 470 }; 471 module_platform_driver(gpucc_sm6375_driver); 472 473 MODULE_DESCRIPTION("QTI GPUCC SM6375 Driver"); 474 MODULE_LICENSE("GPL"); 475