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/platform_device.h> 9 #include <linux/regmap.h> 10 11 #include <dt-bindings/clock/qcom,sm8450-videocc.h> 12 13 #include "clk-alpha-pll.h" 14 #include "clk-branch.h" 15 #include "clk-rcg.h" 16 #include "clk-regmap.h" 17 #include "clk-regmap-divider.h" 18 #include "common.h" 19 #include "gdsc.h" 20 #include "reset.h" 21 22 enum { 23 DT_BI_TCXO, 24 }; 25 26 enum { 27 P_BI_TCXO, 28 P_VIDEO_CC_PLL0_OUT_MAIN, 29 P_VIDEO_CC_PLL1_OUT_MAIN, 30 }; 31 32 static const struct pll_vco lucid_evo_vco[] = { 33 { 249600000, 2020000000, 0 }, 34 }; 35 36 static const struct alpha_pll_config video_cc_pll0_config = { 37 /* .l includes CAL_L_VAL, L_VAL fields */ 38 .l = 0x0044001e, 39 .alpha = 0x0, 40 .config_ctl_val = 0x20485699, 41 .config_ctl_hi_val = 0x00182261, 42 .config_ctl_hi1_val = 0x32aa299c, 43 .user_ctl_val = 0x00000000, 44 .user_ctl_hi_val = 0x00000805, 45 }; 46 47 static const struct alpha_pll_config sm8475_video_cc_pll0_config = { 48 /* .l includes CAL_L_VAL, L_VAL fields */ 49 .l = 0x1e, 50 .alpha = 0x0, 51 .config_ctl_val = 0x20485699, 52 .config_ctl_hi_val = 0x00182261, 53 .config_ctl_hi1_val = 0x82aa299c, 54 .test_ctl_val = 0x00000000, 55 .test_ctl_hi_val = 0x00000003, 56 .test_ctl_hi1_val = 0x00009000, 57 .test_ctl_hi2_val = 0x00000034, 58 .user_ctl_val = 0x00000000, 59 .user_ctl_hi_val = 0x00000005, 60 }; 61 62 static struct clk_alpha_pll video_cc_pll0 = { 63 .offset = 0x0, 64 .config = &video_cc_pll0_config, 65 .vco_table = lucid_evo_vco, 66 .num_vco = ARRAY_SIZE(lucid_evo_vco), 67 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], 68 .clkr = { 69 .hw.init = &(const struct clk_init_data) { 70 .name = "video_cc_pll0", 71 .parent_data = &(const struct clk_parent_data) { 72 .index = DT_BI_TCXO, 73 }, 74 .num_parents = 1, 75 .ops = &clk_alpha_pll_lucid_evo_ops, 76 }, 77 }, 78 }; 79 80 static const struct alpha_pll_config video_cc_pll1_config = { 81 /* .l includes CAL_L_VAL, L_VAL fields */ 82 .l = 0x0044002b, 83 .alpha = 0xc000, 84 .config_ctl_val = 0x20485699, 85 .config_ctl_hi_val = 0x00182261, 86 .config_ctl_hi1_val = 0x32aa299c, 87 .user_ctl_val = 0x00000000, 88 .user_ctl_hi_val = 0x00000805, 89 }; 90 91 static const struct alpha_pll_config sm8475_video_cc_pll1_config = { 92 /* .l includes CAL_L_VAL, L_VAL fields */ 93 .l = 0x2b, 94 .alpha = 0xc000, 95 .config_ctl_val = 0x20485699, 96 .config_ctl_hi_val = 0x00182261, 97 .config_ctl_hi1_val = 0x82aa299c, 98 .test_ctl_val = 0x00000000, 99 .test_ctl_hi_val = 0x00000003, 100 .test_ctl_hi1_val = 0x00009000, 101 .test_ctl_hi2_val = 0x00000034, 102 .user_ctl_val = 0x00000000, 103 .user_ctl_hi_val = 0x00000005, 104 }; 105 106 static struct clk_alpha_pll video_cc_pll1 = { 107 .offset = 0x1000, 108 .config = &video_cc_pll1_config, 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 = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE, 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 = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE, 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 struct clk_alpha_pll *video_cc_sm8450_plls[] = { 411 &video_cc_pll0, 412 &video_cc_pll1, 413 }; 414 415 static const u32 video_cc_sm8450_critical_cbcrs[] = { 416 0x80e4, /* VIDEO_CC_AHB_CLK */ 417 0x8114, /* VIDEO_CC_XO_CLK */ 418 0x8130, /* VIDEO_CC_SLEEP_CLK */ 419 }; 420 421 static const struct regmap_config video_cc_sm8450_regmap_config = { 422 .reg_bits = 32, 423 .reg_stride = 4, 424 .val_bits = 32, 425 .max_register = 0x9f4c, 426 .fast_io = true, 427 }; 428 429 static const struct qcom_cc_driver_data video_cc_sm8450_driver_data = { 430 .alpha_plls = video_cc_sm8450_plls, 431 .num_alpha_plls = ARRAY_SIZE(video_cc_sm8450_plls), 432 .clk_cbcrs = video_cc_sm8450_critical_cbcrs, 433 .num_clk_cbcrs = ARRAY_SIZE(video_cc_sm8450_critical_cbcrs), 434 }; 435 436 static const struct qcom_cc_desc video_cc_sm8450_desc = { 437 .config = &video_cc_sm8450_regmap_config, 438 .clks = video_cc_sm8450_clocks, 439 .num_clks = ARRAY_SIZE(video_cc_sm8450_clocks), 440 .resets = video_cc_sm8450_resets, 441 .num_resets = ARRAY_SIZE(video_cc_sm8450_resets), 442 .gdscs = video_cc_sm8450_gdscs, 443 .num_gdscs = ARRAY_SIZE(video_cc_sm8450_gdscs), 444 .use_rpm = true, 445 .driver_data = &video_cc_sm8450_driver_data, 446 }; 447 448 static const struct of_device_id video_cc_sm8450_match_table[] = { 449 { .compatible = "qcom,sm8450-videocc" }, 450 { .compatible = "qcom,sm8475-videocc" }, 451 { } 452 }; 453 MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table); 454 455 static int video_cc_sm8450_probe(struct platform_device *pdev) 456 { 457 if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-videocc")) { 458 /* Update VideoCC PLL0 */ 459 video_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; 460 461 /* Update VideoCC PLL1 */ 462 video_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE]; 463 464 video_cc_pll0.config = &sm8475_video_cc_pll0_config; 465 video_cc_pll1.config = &sm8475_video_cc_pll1_config; 466 } 467 468 return qcom_cc_probe(pdev, &video_cc_sm8450_desc); 469 } 470 471 static struct platform_driver video_cc_sm8450_driver = { 472 .probe = video_cc_sm8450_probe, 473 .driver = { 474 .name = "video_cc-sm8450", 475 .of_match_table = video_cc_sm8450_match_table, 476 }, 477 }; 478 479 module_platform_driver(video_cc_sm8450_driver); 480 481 MODULE_DESCRIPTION("QTI VIDEOCC SM8450 / SM8475 Driver"); 482 MODULE_LICENSE("GPL"); 483