1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/module.h> 8 #include <linux/platform_device.h> 9 #include <linux/regmap.h> 10 11 #include <dt-bindings/clock/qcom,gpucc-sm8250.h> 12 13 #include "common.h" 14 #include "clk-alpha-pll.h" 15 #include "clk-branch.h" 16 #include "clk-pll.h" 17 #include "clk-rcg.h" 18 #include "clk-regmap.h" 19 #include "reset.h" 20 #include "gdsc.h" 21 22 #define CX_GMU_CBCR_SLEEP_MASK 0xf 23 #define CX_GMU_CBCR_SLEEP_SHIFT 4 24 #define CX_GMU_CBCR_WAKE_MASK 0xf 25 #define CX_GMU_CBCR_WAKE_SHIFT 8 26 27 enum { 28 P_BI_TCXO, 29 P_GPLL0_OUT_MAIN, 30 P_GPLL0_OUT_MAIN_DIV, 31 P_GPU_CC_PLL0_OUT_MAIN, 32 P_GPU_CC_PLL1_OUT_MAIN, 33 }; 34 35 static struct pll_vco lucid_vco[] = { 36 { 249600000, 2000000000, 0 }, 37 }; 38 39 static const struct alpha_pll_config gpu_cc_pll1_config = { 40 .l = 0x1a, 41 .alpha = 0xaaa, 42 .config_ctl_val = 0x20485699, 43 .config_ctl_hi_val = 0x00002261, 44 .config_ctl_hi1_val = 0x029a699c, 45 .user_ctl_val = 0x00000000, 46 .user_ctl_hi_val = 0x00000805, 47 .user_ctl_hi1_val = 0x00000000, 48 }; 49 50 static struct clk_alpha_pll gpu_cc_pll1 = { 51 .offset = 0x100, 52 .vco_table = lucid_vco, 53 .num_vco = ARRAY_SIZE(lucid_vco), 54 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], 55 .clkr = { 56 .hw.init = &(struct clk_init_data){ 57 .name = "gpu_cc_pll1", 58 .parent_data = &(const struct clk_parent_data){ 59 .fw_name = "bi_tcxo", 60 }, 61 .num_parents = 1, 62 .ops = &clk_alpha_pll_lucid_ops, 63 }, 64 }, 65 }; 66 67 static const struct parent_map gpu_cc_parent_map_0[] = { 68 { P_BI_TCXO, 0 }, 69 { P_GPU_CC_PLL1_OUT_MAIN, 3 }, 70 { P_GPLL0_OUT_MAIN, 5 }, 71 { P_GPLL0_OUT_MAIN_DIV, 6 }, 72 }; 73 74 static const struct clk_parent_data gpu_cc_parent_data_0[] = { 75 { .fw_name = "bi_tcxo" }, 76 { .hw = &gpu_cc_pll1.clkr.hw }, 77 { .fw_name = "gcc_gpu_gpll0_clk_src" }, 78 { .fw_name = "gcc_gpu_gpll0_div_clk_src" }, 79 }; 80 81 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { 82 F(19200000, P_BI_TCXO, 1, 0, 0), 83 F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), 84 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), 85 { } 86 }; 87 88 static struct clk_rcg2 gpu_cc_gmu_clk_src = { 89 .cmd_rcgr = 0x1120, 90 .mnd_width = 0, 91 .hid_width = 5, 92 .parent_map = gpu_cc_parent_map_0, 93 .freq_tbl = ftbl_gpu_cc_gmu_clk_src, 94 .clkr.hw.init = &(struct clk_init_data){ 95 .name = "gpu_cc_gmu_clk_src", 96 .parent_data = gpu_cc_parent_data_0, 97 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), 98 .flags = CLK_SET_RATE_PARENT, 99 .ops = &clk_rcg2_ops, 100 }, 101 }; 102 103 static struct clk_branch gpu_cc_ahb_clk = { 104 .halt_reg = 0x1078, 105 .halt_check = BRANCH_HALT_DELAY, 106 .clkr = { 107 .enable_reg = 0x1078, 108 .enable_mask = BIT(0), 109 .hw.init = &(struct clk_init_data){ 110 .name = "gpu_cc_ahb_clk", 111 .ops = &clk_branch2_ops, 112 }, 113 }, 114 }; 115 116 static struct clk_branch gpu_cc_crc_ahb_clk = { 117 .halt_reg = 0x107c, 118 .halt_check = BRANCH_HALT_VOTED, 119 .clkr = { 120 .enable_reg = 0x107c, 121 .enable_mask = BIT(0), 122 .hw.init = &(struct clk_init_data){ 123 .name = "gpu_cc_crc_ahb_clk", 124 .ops = &clk_branch2_ops, 125 }, 126 }, 127 }; 128 129 static struct clk_branch gpu_cc_cx_apb_clk = { 130 .halt_reg = 0x1088, 131 .halt_check = BRANCH_HALT_VOTED, 132 .clkr = { 133 .enable_reg = 0x1088, 134 .enable_mask = BIT(0), 135 .hw.init = &(struct clk_init_data){ 136 .name = "gpu_cc_cx_apb_clk", 137 .ops = &clk_branch2_ops, 138 }, 139 }, 140 }; 141 142 static struct clk_branch gpu_cc_cx_gmu_clk = { 143 .halt_reg = 0x1098, 144 .halt_check = BRANCH_HALT, 145 .clkr = { 146 .enable_reg = 0x1098, 147 .enable_mask = BIT(0), 148 .hw.init = &(struct clk_init_data){ 149 .name = "gpu_cc_cx_gmu_clk", 150 .parent_hws = (const struct clk_hw*[]){ 151 &gpu_cc_gmu_clk_src.clkr.hw, 152 }, 153 .num_parents = 1, 154 .flags = CLK_SET_RATE_PARENT, 155 .ops = &clk_branch2_ops, 156 }, 157 }, 158 }; 159 160 static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { 161 .halt_reg = 0x108c, 162 .halt_check = BRANCH_HALT_VOTED, 163 .clkr = { 164 .enable_reg = 0x108c, 165 .enable_mask = BIT(0), 166 .hw.init = &(struct clk_init_data){ 167 .name = "gpu_cc_cx_snoc_dvm_clk", 168 .ops = &clk_branch2_ops, 169 }, 170 }, 171 }; 172 173 static struct clk_branch gpu_cc_cxo_aon_clk = { 174 .halt_reg = 0x1004, 175 .halt_check = BRANCH_HALT_VOTED, 176 .clkr = { 177 .enable_reg = 0x1004, 178 .enable_mask = BIT(0), 179 .hw.init = &(struct clk_init_data){ 180 .name = "gpu_cc_cxo_aon_clk", 181 .ops = &clk_branch2_ops, 182 }, 183 }, 184 }; 185 186 static struct clk_branch gpu_cc_cxo_clk = { 187 .halt_reg = 0x109c, 188 .halt_check = BRANCH_HALT, 189 .clkr = { 190 .enable_reg = 0x109c, 191 .enable_mask = BIT(0), 192 .hw.init = &(struct clk_init_data){ 193 .name = "gpu_cc_cxo_clk", 194 .ops = &clk_branch2_ops, 195 }, 196 }, 197 }; 198 199 static struct clk_branch gpu_cc_gx_gmu_clk = { 200 .halt_reg = 0x1064, 201 .halt_check = BRANCH_HALT, 202 .clkr = { 203 .enable_reg = 0x1064, 204 .enable_mask = BIT(0), 205 .hw.init = &(struct clk_init_data){ 206 .name = "gpu_cc_gx_gmu_clk", 207 .parent_hws = (const struct clk_hw*[]){ 208 &gpu_cc_gmu_clk_src.clkr.hw, 209 }, 210 .num_parents = 1, 211 .flags = CLK_SET_RATE_PARENT, 212 .ops = &clk_branch2_ops, 213 }, 214 }, 215 }; 216 217 static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { 218 .halt_reg = 0x5000, 219 .halt_check = BRANCH_VOTED, 220 .clkr = { 221 .enable_reg = 0x5000, 222 .enable_mask = BIT(0), 223 .hw.init = &(struct clk_init_data){ 224 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", 225 .ops = &clk_branch2_ops, 226 }, 227 }, 228 }; 229 230 static struct gdsc gpu_cx_gdsc = { 231 .gdscr = 0x106c, 232 .gds_hw_ctrl = 0x1540, 233 .pd = { 234 .name = "gpu_cx_gdsc", 235 }, 236 .pwrsts = PWRSTS_OFF_ON, 237 .flags = VOTABLE, 238 }; 239 240 static struct gdsc gpu_gx_gdsc = { 241 .gdscr = 0x100c, 242 .clamp_io_ctrl = 0x1508, 243 .pd = { 244 .name = "gpu_gx_gdsc", 245 .power_on = gdsc_gx_do_nothing_enable, 246 }, 247 .pwrsts = PWRSTS_OFF_ON, 248 .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR, 249 }; 250 251 static struct clk_regmap *gpu_cc_sm8250_clocks[] = { 252 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, 253 [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, 254 [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, 255 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, 256 [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, 257 [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, 258 [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, 259 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, 260 [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, 261 [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, 262 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, 263 }; 264 265 static const struct qcom_reset_map gpu_cc_sm8250_resets[] = { 266 [GPUCC_GPU_CC_ACD_BCR] = { 0x1160 }, 267 [GPUCC_GPU_CC_CX_BCR] = { 0x1068 }, 268 [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 }, 269 [GPUCC_GPU_CC_GMU_BCR] = { 0x111c }, 270 [GPUCC_GPU_CC_GX_BCR] = { 0x1008 }, 271 [GPUCC_GPU_CC_XO_BCR] = { 0x1000 }, 272 }; 273 274 static struct gdsc *gpu_cc_sm8250_gdscs[] = { 275 [GPU_CX_GDSC] = &gpu_cx_gdsc, 276 [GPU_GX_GDSC] = &gpu_gx_gdsc, 277 }; 278 279 static const struct regmap_config gpu_cc_sm8250_regmap_config = { 280 .reg_bits = 32, 281 .reg_stride = 4, 282 .val_bits = 32, 283 .max_register = 0x8008, 284 .fast_io = true, 285 }; 286 287 static const struct qcom_cc_desc gpu_cc_sm8250_desc = { 288 .config = &gpu_cc_sm8250_regmap_config, 289 .clks = gpu_cc_sm8250_clocks, 290 .num_clks = ARRAY_SIZE(gpu_cc_sm8250_clocks), 291 .resets = gpu_cc_sm8250_resets, 292 .num_resets = ARRAY_SIZE(gpu_cc_sm8250_resets), 293 .gdscs = gpu_cc_sm8250_gdscs, 294 .num_gdscs = ARRAY_SIZE(gpu_cc_sm8250_gdscs), 295 }; 296 297 static const struct of_device_id gpu_cc_sm8250_match_table[] = { 298 { .compatible = "qcom,sm8250-gpucc" }, 299 { } 300 }; 301 MODULE_DEVICE_TABLE(of, gpu_cc_sm8250_match_table); 302 303 static int gpu_cc_sm8250_probe(struct platform_device *pdev) 304 { 305 struct regmap *regmap; 306 unsigned int value, mask; 307 308 regmap = qcom_cc_map(pdev, &gpu_cc_sm8250_desc); 309 if (IS_ERR(regmap)) 310 return PTR_ERR(regmap); 311 312 clk_lucid_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); 313 314 /* 315 * Configure gpu_cc_cx_gmu_clk with recommended 316 * wakeup/sleep settings 317 */ 318 mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; 319 mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; 320 value = 0xf << CX_GMU_CBCR_WAKE_SHIFT | 0xf << CX_GMU_CBCR_SLEEP_SHIFT; 321 regmap_update_bits(regmap, 0x1098, mask, value); 322 323 return qcom_cc_really_probe(pdev, &gpu_cc_sm8250_desc, regmap); 324 } 325 326 static struct platform_driver gpu_cc_sm8250_driver = { 327 .probe = gpu_cc_sm8250_probe, 328 .driver = { 329 .name = "sm8250-gpucc", 330 .of_match_table = gpu_cc_sm8250_match_table, 331 }, 332 }; 333 334 static int __init gpu_cc_sm8250_init(void) 335 { 336 return platform_driver_register(&gpu_cc_sm8250_driver); 337 } 338 subsys_initcall(gpu_cc_sm8250_init); 339 340 static void __exit gpu_cc_sm8250_exit(void) 341 { 342 platform_driver_unregister(&gpu_cc_sm8250_driver); 343 } 344 module_exit(gpu_cc_sm8250_exit); 345 346 MODULE_DESCRIPTION("QTI GPU_CC SM8250 Driver"); 347 MODULE_LICENSE("GPL v2"); 348