1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. 4 */ 5 6 #include <linux/clk-provider.h> 7 #include <linux/module.h> 8 #include <linux/of_device.h> 9 #include <linux/pm_runtime.h> 10 #include <linux/regmap.h> 11 12 #include <dt-bindings/clock/qcom,sm8450-videocc.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 "common.h" 20 #include "gdsc.h" 21 #include "reset.h" 22 23 enum { 24 DT_BI_TCXO, 25 }; 26 27 enum { 28 P_BI_TCXO, 29 P_VIDEO_CC_PLL0_OUT_MAIN, 30 P_VIDEO_CC_PLL1_OUT_MAIN, 31 }; 32 33 static const struct pll_vco lucid_evo_vco[] = { 34 { 249600000, 2020000000, 0 }, 35 }; 36 37 static const struct alpha_pll_config video_cc_pll0_config = { 38 /* .l includes CAL_L_VAL, L_VAL fields */ 39 .l = 0x0044001e, 40 .alpha = 0x0, 41 .config_ctl_val = 0x20485699, 42 .config_ctl_hi_val = 0x00182261, 43 .config_ctl_hi1_val = 0x32aa299c, 44 .user_ctl_val = 0x00000000, 45 .user_ctl_hi_val = 0x00000805, 46 }; 47 48 static struct clk_alpha_pll video_cc_pll0 = { 49 .offset = 0x0, 50 .vco_table = lucid_evo_vco, 51 .num_vco = ARRAY_SIZE(lucid_evo_vco), 52 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], 53 .clkr = { 54 .hw.init = &(const struct clk_init_data) { 55 .name = "video_cc_pll0", 56 .parent_data = &(const struct clk_parent_data) { 57 .index = DT_BI_TCXO, 58 }, 59 .num_parents = 1, 60 .ops = &clk_alpha_pll_lucid_evo_ops, 61 }, 62 }, 63 }; 64 65 static const struct alpha_pll_config video_cc_pll1_config = { 66 /* .l includes CAL_L_VAL, L_VAL fields */ 67 .l = 0x0044002b, 68 .alpha = 0xc000, 69 .config_ctl_val = 0x20485699, 70 .config_ctl_hi_val = 0x00182261, 71 .config_ctl_hi1_val = 0x32aa299c, 72 .user_ctl_val = 0x00000000, 73 .user_ctl_hi_val = 0x00000805, 74 }; 75 76 static struct clk_alpha_pll video_cc_pll1 = { 77 .offset = 0x1000, 78 .vco_table = lucid_evo_vco, 79 .num_vco = ARRAY_SIZE(lucid_evo_vco), 80 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], 81 .clkr = { 82 .hw.init = &(const struct clk_init_data) { 83 .name = "video_cc_pll1", 84 .parent_data = &(const struct clk_parent_data) { 85 .index = DT_BI_TCXO, 86 }, 87 .num_parents = 1, 88 .ops = &clk_alpha_pll_lucid_evo_ops, 89 }, 90 }, 91 }; 92 93 static const struct parent_map video_cc_parent_map_0[] = { 94 { P_BI_TCXO, 0 }, 95 { P_VIDEO_CC_PLL0_OUT_MAIN, 1 }, 96 }; 97 98 static const struct clk_parent_data video_cc_parent_data_0[] = { 99 { .index = DT_BI_TCXO }, 100 { .hw = &video_cc_pll0.clkr.hw }, 101 }; 102 103 static const struct parent_map video_cc_parent_map_1[] = { 104 { P_BI_TCXO, 0 }, 105 { P_VIDEO_CC_PLL1_OUT_MAIN, 1 }, 106 }; 107 108 static const struct clk_parent_data video_cc_parent_data_1[] = { 109 { .index = DT_BI_TCXO }, 110 { .hw = &video_cc_pll1.clkr.hw }, 111 }; 112 113 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = { 114 F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 115 F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 116 F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 117 F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 118 F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 119 { } 120 }; 121 122 static struct clk_rcg2 video_cc_mvs0_clk_src = { 123 .cmd_rcgr = 0x8000, 124 .mnd_width = 0, 125 .hid_width = 5, 126 .parent_map = video_cc_parent_map_0, 127 .freq_tbl = ftbl_video_cc_mvs0_clk_src, 128 .clkr.hw.init = &(const struct clk_init_data) { 129 .name = "video_cc_mvs0_clk_src", 130 .parent_data = video_cc_parent_data_0, 131 .num_parents = ARRAY_SIZE(video_cc_parent_data_0), 132 .flags = CLK_SET_RATE_PARENT, 133 .ops = &clk_rcg2_shared_ops, 134 }, 135 }; 136 137 static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = { 138 F(840000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 139 F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 140 F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 141 F(1500000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 142 F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 143 { } 144 }; 145 146 static struct clk_rcg2 video_cc_mvs1_clk_src = { 147 .cmd_rcgr = 0x8018, 148 .mnd_width = 0, 149 .hid_width = 5, 150 .parent_map = video_cc_parent_map_1, 151 .freq_tbl = ftbl_video_cc_mvs1_clk_src, 152 .clkr.hw.init = &(const struct clk_init_data) { 153 .name = "video_cc_mvs1_clk_src", 154 .parent_data = video_cc_parent_data_1, 155 .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 156 .flags = CLK_SET_RATE_PARENT, 157 .ops = &clk_rcg2_shared_ops, 158 }, 159 }; 160 161 static struct clk_regmap_div video_cc_mvs0_div_clk_src = { 162 .reg = 0x80b8, 163 .shift = 0, 164 .width = 4, 165 .clkr.hw.init = &(const struct clk_init_data) { 166 .name = "video_cc_mvs0_div_clk_src", 167 .parent_hws = (const struct clk_hw*[]) { 168 &video_cc_mvs0_clk_src.clkr.hw, 169 }, 170 .num_parents = 1, 171 .flags = CLK_SET_RATE_PARENT, 172 .ops = &clk_regmap_div_ro_ops, 173 }, 174 }; 175 176 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = { 177 .reg = 0x806c, 178 .shift = 0, 179 .width = 4, 180 .clkr.hw.init = &(const struct clk_init_data) { 181 .name = "video_cc_mvs0c_div2_div_clk_src", 182 .parent_hws = (const struct clk_hw*[]) { 183 &video_cc_mvs0_clk_src.clkr.hw, 184 }, 185 .num_parents = 1, 186 .flags = CLK_SET_RATE_PARENT, 187 .ops = &clk_regmap_div_ro_ops, 188 }, 189 }; 190 191 static struct clk_regmap_div video_cc_mvs1_div_clk_src = { 192 .reg = 0x80dc, 193 .shift = 0, 194 .width = 4, 195 .clkr.hw.init = &(const struct clk_init_data) { 196 .name = "video_cc_mvs1_div_clk_src", 197 .parent_hws = (const struct clk_hw*[]) { 198 &video_cc_mvs1_clk_src.clkr.hw, 199 }, 200 .num_parents = 1, 201 .flags = CLK_SET_RATE_PARENT, 202 .ops = &clk_regmap_div_ro_ops, 203 }, 204 }; 205 206 static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = { 207 .reg = 0x8094, 208 .shift = 0, 209 .width = 4, 210 .clkr.hw.init = &(const struct clk_init_data) { 211 .name = "video_cc_mvs1c_div2_div_clk_src", 212 .parent_hws = (const struct clk_hw*[]) { 213 &video_cc_mvs1_clk_src.clkr.hw, 214 }, 215 .num_parents = 1, 216 .flags = CLK_SET_RATE_PARENT, 217 .ops = &clk_regmap_div_ro_ops, 218 }, 219 }; 220 221 static struct clk_branch video_cc_mvs0_clk = { 222 .halt_reg = 0x80b0, 223 .halt_check = BRANCH_HALT_SKIP, 224 .hwcg_reg = 0x80b0, 225 .hwcg_bit = 1, 226 .clkr = { 227 .enable_reg = 0x80b0, 228 .enable_mask = BIT(0), 229 .hw.init = &(const struct clk_init_data) { 230 .name = "video_cc_mvs0_clk", 231 .parent_hws = (const struct clk_hw*[]) { 232 &video_cc_mvs0_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 video_cc_mvs0c_clk = { 242 .halt_reg = 0x8064, 243 .halt_check = BRANCH_HALT, 244 .clkr = { 245 .enable_reg = 0x8064, 246 .enable_mask = BIT(0), 247 .hw.init = &(const struct clk_init_data) { 248 .name = "video_cc_mvs0c_clk", 249 .parent_hws = (const struct clk_hw*[]) { 250 &video_cc_mvs0c_div2_div_clk_src.clkr.hw, 251 }, 252 .num_parents = 1, 253 .flags = CLK_SET_RATE_PARENT, 254 .ops = &clk_branch2_ops, 255 }, 256 }, 257 }; 258 259 static struct clk_branch video_cc_mvs1_clk = { 260 .halt_reg = 0x80d4, 261 .halt_check = BRANCH_HALT_SKIP, 262 .hwcg_reg = 0x80d4, 263 .hwcg_bit = 1, 264 .clkr = { 265 .enable_reg = 0x80d4, 266 .enable_mask = BIT(0), 267 .hw.init = &(const struct clk_init_data) { 268 .name = "video_cc_mvs1_clk", 269 .parent_hws = (const struct clk_hw*[]) { 270 &video_cc_mvs1_div_clk_src.clkr.hw, 271 }, 272 .num_parents = 1, 273 .flags = CLK_SET_RATE_PARENT, 274 .ops = &clk_branch2_ops, 275 }, 276 }, 277 }; 278 279 static struct clk_branch video_cc_mvs1c_clk = { 280 .halt_reg = 0x808c, 281 .halt_check = BRANCH_HALT, 282 .clkr = { 283 .enable_reg = 0x808c, 284 .enable_mask = BIT(0), 285 .hw.init = &(const struct clk_init_data) { 286 .name = "video_cc_mvs1c_clk", 287 .parent_hws = (const struct clk_hw*[]) { 288 &video_cc_mvs1c_div2_div_clk_src.clkr.hw, 289 }, 290 .num_parents = 1, 291 .flags = CLK_SET_RATE_PARENT, 292 .ops = &clk_branch2_ops, 293 }, 294 }, 295 }; 296 297 static struct gdsc video_cc_mvs0c_gdsc = { 298 .gdscr = 0x804c, 299 .en_rest_wait_val = 0x2, 300 .en_few_wait_val = 0x2, 301 .clk_dis_wait_val = 0x6, 302 .pd = { 303 .name = "video_cc_mvs0c_gdsc", 304 }, 305 .pwrsts = PWRSTS_OFF_ON, 306 .flags = RETAIN_FF_ENABLE, 307 }; 308 309 static struct gdsc video_cc_mvs0_gdsc = { 310 .gdscr = 0x809c, 311 .en_rest_wait_val = 0x2, 312 .en_few_wait_val = 0x2, 313 .clk_dis_wait_val = 0x6, 314 .pd = { 315 .name = "video_cc_mvs0_gdsc", 316 }, 317 .pwrsts = PWRSTS_OFF_ON, 318 .parent = &video_cc_mvs0c_gdsc.pd, 319 .flags = RETAIN_FF_ENABLE | HW_CTRL, 320 }; 321 322 static struct gdsc video_cc_mvs1c_gdsc = { 323 .gdscr = 0x8074, 324 .en_rest_wait_val = 0x2, 325 .en_few_wait_val = 0x2, 326 .clk_dis_wait_val = 0x6, 327 .pd = { 328 .name = "video_cc_mvs1c_gdsc", 329 }, 330 .pwrsts = PWRSTS_OFF_ON, 331 .flags = RETAIN_FF_ENABLE, 332 }; 333 334 static struct gdsc video_cc_mvs1_gdsc = { 335 .gdscr = 0x80c0, 336 .en_rest_wait_val = 0x2, 337 .en_few_wait_val = 0x2, 338 .clk_dis_wait_val = 0x6, 339 .pd = { 340 .name = "video_cc_mvs1_gdsc", 341 }, 342 .pwrsts = PWRSTS_OFF_ON, 343 .parent = &video_cc_mvs1c_gdsc.pd, 344 .flags = RETAIN_FF_ENABLE | HW_CTRL, 345 }; 346 347 static struct clk_regmap *video_cc_sm8450_clocks[] = { 348 [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr, 349 [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr, 350 [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr, 351 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr, 352 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr, 353 [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr, 354 [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr, 355 [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr, 356 [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr, 357 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr, 358 [VIDEO_CC_PLL0] = &video_cc_pll0.clkr, 359 [VIDEO_CC_PLL1] = &video_cc_pll1.clkr, 360 }; 361 362 static struct gdsc *video_cc_sm8450_gdscs[] = { 363 [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc, 364 [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc, 365 [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc, 366 [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc, 367 }; 368 369 static const struct qcom_reset_map video_cc_sm8450_resets[] = { 370 [CVP_VIDEO_CC_INTERFACE_BCR] = { 0x80e0 }, 371 [CVP_VIDEO_CC_MVS0_BCR] = { 0x8098 }, 372 [CVP_VIDEO_CC_MVS0C_BCR] = { 0x8048 }, 373 [CVP_VIDEO_CC_MVS1_BCR] = { 0x80bc }, 374 [CVP_VIDEO_CC_MVS1C_BCR] = { 0x8070 }, 375 [VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 }, 376 [VIDEO_CC_MVS1C_CLK_ARES] = { 0x808c, 2 }, 377 }; 378 379 static const struct regmap_config video_cc_sm8450_regmap_config = { 380 .reg_bits = 32, 381 .reg_stride = 4, 382 .val_bits = 32, 383 .max_register = 0x9f4c, 384 .fast_io = true, 385 }; 386 387 static struct qcom_cc_desc video_cc_sm8450_desc = { 388 .config = &video_cc_sm8450_regmap_config, 389 .clks = video_cc_sm8450_clocks, 390 .num_clks = ARRAY_SIZE(video_cc_sm8450_clocks), 391 .resets = video_cc_sm8450_resets, 392 .num_resets = ARRAY_SIZE(video_cc_sm8450_resets), 393 .gdscs = video_cc_sm8450_gdscs, 394 .num_gdscs = ARRAY_SIZE(video_cc_sm8450_gdscs), 395 }; 396 397 static const struct of_device_id video_cc_sm8450_match_table[] = { 398 { .compatible = "qcom,sm8450-videocc" }, 399 { } 400 }; 401 MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table); 402 403 static int video_cc_sm8450_probe(struct platform_device *pdev) 404 { 405 struct regmap *regmap; 406 int ret; 407 408 ret = devm_pm_runtime_enable(&pdev->dev); 409 if (ret) 410 return ret; 411 412 ret = pm_runtime_resume_and_get(&pdev->dev); 413 if (ret) 414 return ret; 415 416 regmap = qcom_cc_map(pdev, &video_cc_sm8450_desc); 417 if (IS_ERR(regmap)) { 418 pm_runtime_put(&pdev->dev); 419 return PTR_ERR(regmap); 420 } 421 422 clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config); 423 clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config); 424 425 /* 426 * Keep clocks always enabled: 427 * video_cc_ahb_clk 428 * video_cc_sleep_clk 429 * video_cc_xo_clk 430 */ 431 regmap_update_bits(regmap, 0x80e4, BIT(0), BIT(0)); 432 regmap_update_bits(regmap, 0x8130, BIT(0), BIT(0)); 433 regmap_update_bits(regmap, 0x8114, BIT(0), BIT(0)); 434 435 ret = qcom_cc_really_probe(pdev, &video_cc_sm8450_desc, regmap); 436 437 pm_runtime_put(&pdev->dev); 438 439 return ret; 440 } 441 442 static struct platform_driver video_cc_sm8450_driver = { 443 .probe = video_cc_sm8450_probe, 444 .driver = { 445 .name = "video_cc-sm8450", 446 .of_match_table = video_cc_sm8450_match_table, 447 }, 448 }; 449 450 static int __init video_cc_sm8450_init(void) 451 { 452 return platform_driver_register(&video_cc_sm8450_driver); 453 } 454 subsys_initcall(video_cc_sm8450_init); 455 456 static void __exit video_cc_sm8450_exit(void) 457 { 458 platform_driver_unregister(&video_cc_sm8450_driver); 459 } 460 module_exit(video_cc_sm8450_exit); 461 462 MODULE_DESCRIPTION("QTI VIDEOCC SM8450 Driver"); 463 MODULE_LICENSE("GPL"); 464