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