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