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