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