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