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