1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 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,sm8750-videocc.h> 13 14 #include "clk-alpha-pll.h" 15 #include "clk-branch.h" 16 #include "clk-pll.h" 17 #include "clk-rcg.h" 18 #include "clk-regmap.h" 19 #include "clk-regmap-divider.h" 20 #include "clk-regmap-mux.h" 21 #include "common.h" 22 #include "gdsc.h" 23 #include "reset.h" 24 25 enum { 26 DT_BI_TCXO, 27 DT_BI_TCXO_AO, 28 DT_SLEEP_CLK, 29 }; 30 31 enum { 32 P_BI_TCXO, 33 P_SLEEP_CLK, 34 P_VIDEO_CC_PLL0_OUT_MAIN, 35 }; 36 37 static const struct pll_vco taycan_elu_vco[] = { 38 { 249600000, 2500000000, 0 }, 39 }; 40 41 static const struct alpha_pll_config video_cc_pll0_config = { 42 .l = 0x25, 43 .alpha = 0x8000, 44 .config_ctl_val = 0x19660387, 45 .config_ctl_hi_val = 0x098060a0, 46 .config_ctl_hi1_val = 0xb416cb20, 47 .user_ctl_val = 0x00000000, 48 .user_ctl_hi_val = 0x00000002, 49 }; 50 51 static struct clk_alpha_pll video_cc_pll0 = { 52 .offset = 0x0, 53 .config = &video_cc_pll0_config, 54 .vco_table = taycan_elu_vco, 55 .num_vco = ARRAY_SIZE(taycan_elu_vco), 56 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU], 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_taycan_elu_ops, 65 }, 66 }, 67 }; 68 69 static const struct parent_map video_cc_parent_map_0[] = { 70 { P_BI_TCXO, 0 }, 71 }; 72 73 static const struct clk_parent_data video_cc_parent_data_0_ao[] = { 74 { .index = DT_BI_TCXO_AO }, 75 }; 76 77 static const struct parent_map video_cc_parent_map_1[] = { 78 { P_BI_TCXO, 0 }, 79 { P_VIDEO_CC_PLL0_OUT_MAIN, 1 }, 80 }; 81 82 static const struct clk_parent_data video_cc_parent_data_1[] = { 83 { .index = DT_BI_TCXO }, 84 { .hw = &video_cc_pll0.clkr.hw }, 85 }; 86 87 static const struct parent_map video_cc_parent_map_2[] = { 88 { P_SLEEP_CLK, 0 }, 89 }; 90 91 static const struct clk_parent_data video_cc_parent_data_2_ao[] = { 92 { .index = DT_SLEEP_CLK }, 93 }; 94 95 static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = { 96 F(19200000, P_BI_TCXO, 1, 0, 0), 97 { } 98 }; 99 100 static struct clk_rcg2 video_cc_ahb_clk_src = { 101 .cmd_rcgr = 0x8018, 102 .mnd_width = 0, 103 .hid_width = 5, 104 .parent_map = video_cc_parent_map_0, 105 .freq_tbl = ftbl_video_cc_ahb_clk_src, 106 .clkr.hw.init = &(const struct clk_init_data) { 107 .name = "video_cc_ahb_clk_src", 108 .parent_data = video_cc_parent_data_0_ao, 109 .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao), 110 .flags = CLK_SET_RATE_PARENT, 111 .ops = &clk_rcg2_ops, 112 }, 113 }; 114 115 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = { 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(1260000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 119 F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 120 F(1600000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 121 F(1710000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 122 F(1890000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 123 { } 124 }; 125 126 static struct clk_rcg2 video_cc_mvs0_clk_src = { 127 .cmd_rcgr = 0x8000, 128 .mnd_width = 0, 129 .hid_width = 5, 130 .parent_map = video_cc_parent_map_1, 131 .freq_tbl = ftbl_video_cc_mvs0_clk_src, 132 .clkr.hw.init = &(const struct clk_init_data) { 133 .name = "video_cc_mvs0_clk_src", 134 .parent_data = video_cc_parent_data_1, 135 .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 136 .flags = CLK_SET_RATE_PARENT, 137 .ops = &clk_rcg2_shared_ops, 138 }, 139 }; 140 141 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = { 142 F(32000, P_SLEEP_CLK, 1, 0, 0), 143 { } 144 }; 145 146 static struct clk_rcg2 video_cc_sleep_clk_src = { 147 .cmd_rcgr = 0x80e0, 148 .mnd_width = 0, 149 .hid_width = 5, 150 .parent_map = video_cc_parent_map_2, 151 .freq_tbl = ftbl_video_cc_sleep_clk_src, 152 .clkr.hw.init = &(const struct clk_init_data) { 153 .name = "video_cc_sleep_clk_src", 154 .parent_data = video_cc_parent_data_2_ao, 155 .num_parents = ARRAY_SIZE(video_cc_parent_data_2_ao), 156 .flags = CLK_SET_RATE_PARENT, 157 .ops = &clk_rcg2_ops, 158 }, 159 }; 160 161 static struct clk_rcg2 video_cc_xo_clk_src = { 162 .cmd_rcgr = 0x80bc, 163 .mnd_width = 0, 164 .hid_width = 5, 165 .parent_map = video_cc_parent_map_0, 166 .freq_tbl = ftbl_video_cc_ahb_clk_src, 167 .clkr.hw.init = &(const struct clk_init_data) { 168 .name = "video_cc_xo_clk_src", 169 .parent_data = video_cc_parent_data_0_ao, 170 .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao), 171 .flags = CLK_SET_RATE_PARENT, 172 .ops = &clk_rcg2_ops, 173 }, 174 }; 175 176 static struct clk_regmap_div video_cc_mvs0_div_clk_src = { 177 .reg = 0x809c, 178 .shift = 0, 179 .width = 4, 180 .clkr.hw.init = &(const struct clk_init_data) { 181 .name = "video_cc_mvs0_div_clk_src", 182 .parent_hws = (const struct clk_hw*[]) { 183 &video_cc_mvs0_clk_src.clkr.hw, 184 }, 185 .num_parents = 1, 186 .flags = CLK_SET_RATE_PARENT, 187 .ops = &clk_regmap_div_ro_ops, 188 }, 189 }; 190 191 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = { 192 .reg = 0x8060, 193 .shift = 0, 194 .width = 4, 195 .clkr.hw.init = &(const struct clk_init_data) { 196 .name = "video_cc_mvs0c_div2_div_clk_src", 197 .parent_hws = (const struct clk_hw*[]) { 198 &video_cc_mvs0_clk_src.clkr.hw, 199 }, 200 .num_parents = 1, 201 .flags = CLK_SET_RATE_PARENT, 202 .ops = &clk_regmap_div_ro_ops, 203 }, 204 }; 205 206 static struct clk_branch video_cc_mvs0_clk = { 207 .halt_reg = 0x807c, 208 .halt_check = BRANCH_HALT_VOTED, 209 .hwcg_reg = 0x807c, 210 .hwcg_bit = 1, 211 .clkr = { 212 .enable_reg = 0x807c, 213 .enable_mask = BIT(0), 214 .hw.init = &(const struct clk_init_data) { 215 .name = "video_cc_mvs0_clk", 216 .parent_hws = (const struct clk_hw*[]) { 217 &video_cc_mvs0_div_clk_src.clkr.hw, 218 }, 219 .num_parents = 1, 220 .flags = CLK_SET_RATE_PARENT, 221 .ops = &clk_branch2_ops, 222 }, 223 }, 224 }; 225 226 static struct clk_mem_branch video_cc_mvs0_freerun_clk = { 227 .mem_enable_reg = 0x8090, 228 .mem_ack_reg = 0x8090, 229 .mem_enable_mask = BIT(3), 230 .mem_enable_ack_mask = GENMASK(11, 10), 231 .mem_enable_invert = true, 232 .branch = { 233 .halt_reg = 0x808c, 234 .halt_check = BRANCH_HALT, 235 .clkr = { 236 .enable_reg = 0x808c, 237 .enable_mask = BIT(0), 238 .hw.init = &(const struct clk_init_data) { 239 .name = "video_cc_mvs0_freerun_clk", 240 .parent_hws = (const struct clk_hw*[]) { 241 &video_cc_mvs0_div_clk_src.clkr.hw, 242 }, 243 .num_parents = 1, 244 .flags = CLK_SET_RATE_PARENT, 245 .ops = &clk_branch2_mem_ops, 246 }, 247 }, 248 }, 249 }; 250 251 static struct clk_branch video_cc_mvs0_shift_clk = { 252 .halt_reg = 0x80d8, 253 .halt_check = BRANCH_HALT_VOTED, 254 .hwcg_reg = 0x80d8, 255 .hwcg_bit = 1, 256 .clkr = { 257 .enable_reg = 0x80d8, 258 .enable_mask = BIT(0), 259 .hw.init = &(const struct clk_init_data) { 260 .name = "video_cc_mvs0_shift_clk", 261 .parent_hws = (const struct clk_hw*[]) { 262 &video_cc_xo_clk_src.clkr.hw, 263 }, 264 .num_parents = 1, 265 .flags = CLK_SET_RATE_PARENT, 266 .ops = &clk_branch2_ops, 267 }, 268 }, 269 }; 270 271 static struct clk_branch video_cc_mvs0c_clk = { 272 .halt_reg = 0x804c, 273 .halt_check = BRANCH_HALT, 274 .clkr = { 275 .enable_reg = 0x804c, 276 .enable_mask = BIT(0), 277 .hw.init = &(const struct clk_init_data) { 278 .name = "video_cc_mvs0c_clk", 279 .parent_hws = (const struct clk_hw*[]) { 280 &video_cc_mvs0c_div2_div_clk_src.clkr.hw, 281 }, 282 .num_parents = 1, 283 .flags = CLK_SET_RATE_PARENT, 284 .ops = &clk_branch2_ops, 285 }, 286 }, 287 }; 288 289 static struct clk_branch video_cc_mvs0c_freerun_clk = { 290 .halt_reg = 0x805c, 291 .halt_check = BRANCH_HALT, 292 .clkr = { 293 .enable_reg = 0x805c, 294 .enable_mask = BIT(0), 295 .hw.init = &(const struct clk_init_data) { 296 .name = "video_cc_mvs0c_freerun_clk", 297 .parent_hws = (const struct clk_hw*[]) { 298 &video_cc_mvs0c_div2_div_clk_src.clkr.hw, 299 }, 300 .num_parents = 1, 301 .flags = CLK_SET_RATE_PARENT, 302 .ops = &clk_branch2_ops, 303 }, 304 }, 305 }; 306 307 static struct clk_branch video_cc_mvs0c_shift_clk = { 308 .halt_reg = 0x80dc, 309 .halt_check = BRANCH_HALT_VOTED, 310 .hwcg_reg = 0x80dc, 311 .hwcg_bit = 1, 312 .clkr = { 313 .enable_reg = 0x80dc, 314 .enable_mask = BIT(0), 315 .hw.init = &(const struct clk_init_data) { 316 .name = "video_cc_mvs0c_shift_clk", 317 .parent_hws = (const struct clk_hw*[]) { 318 &video_cc_xo_clk_src.clkr.hw, 319 }, 320 .num_parents = 1, 321 .flags = CLK_SET_RATE_PARENT, 322 .ops = &clk_branch2_ops, 323 }, 324 }, 325 }; 326 327 static struct gdsc video_cc_mvs0c_gdsc = { 328 .gdscr = 0x8034, 329 .en_rest_wait_val = 0x2, 330 .en_few_wait_val = 0x2, 331 .clk_dis_wait_val = 0x6, 332 .pd = { 333 .name = "video_cc_mvs0c_gdsc", 334 }, 335 .pwrsts = PWRSTS_OFF_ON, 336 .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, 337 }; 338 339 static struct gdsc video_cc_mvs0_gdsc = { 340 .gdscr = 0x8068, 341 .en_rest_wait_val = 0x2, 342 .en_few_wait_val = 0x2, 343 .clk_dis_wait_val = 0x6, 344 .pd = { 345 .name = "video_cc_mvs0_gdsc", 346 }, 347 .pwrsts = PWRSTS_OFF_ON, 348 .parent = &video_cc_mvs0c_gdsc.pd, 349 .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL_TRIGGER, 350 }; 351 352 static struct clk_regmap *video_cc_sm8750_clocks[] = { 353 [VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr, 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_MVS0_FREERUN_CLK] = &video_cc_mvs0_freerun_clk.branch.clkr, 358 [VIDEO_CC_MVS0_SHIFT_CLK] = &video_cc_mvs0_shift_clk.clkr, 359 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr, 360 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr, 361 [VIDEO_CC_MVS0C_FREERUN_CLK] = &video_cc_mvs0c_freerun_clk.clkr, 362 [VIDEO_CC_MVS0C_SHIFT_CLK] = &video_cc_mvs0c_shift_clk.clkr, 363 [VIDEO_CC_PLL0] = &video_cc_pll0.clkr, 364 [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr, 365 [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr, 366 }; 367 368 static struct gdsc *video_cc_sm8750_gdscs[] = { 369 [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc, 370 [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc, 371 }; 372 373 static const struct qcom_reset_map video_cc_sm8750_resets[] = { 374 [VIDEO_CC_INTERFACE_BCR] = { 0x80a0 }, 375 [VIDEO_CC_MVS0_BCR] = { 0x8064 }, 376 [VIDEO_CC_MVS0C_CLK_ARES] = { 0x804c, 2 }, 377 [VIDEO_CC_MVS0C_BCR] = { 0x8030 }, 378 [VIDEO_CC_MVS0_FREERUN_CLK_ARES] = { 0x808c, 2 }, 379 [VIDEO_CC_MVS0C_FREERUN_CLK_ARES] = { 0x805c, 2 }, 380 [VIDEO_CC_XO_CLK_ARES] = { 0x80d4, 2 }, 381 }; 382 383 static const struct regmap_config video_cc_sm8750_regmap_config = { 384 .reg_bits = 32, 385 .reg_stride = 4, 386 .val_bits = 32, 387 .max_register = 0x9f4c, 388 .fast_io = true, 389 }; 390 391 static struct clk_alpha_pll *video_cc_sm8750_plls[] = { 392 &video_cc_pll0, 393 }; 394 395 static const u32 video_cc_sm8750_critical_cbcrs[] = { 396 0x80a4, /* VIDEO_CC_AHB_CLK */ 397 0x80f8, /* VIDEO_CC_SLEEP_CLK */ 398 0x80d4, /* VIDEO_CC_XO_CLK */ 399 }; 400 401 static void clk_sm8750_regs_configure(struct device *dev, struct regmap *regmap) 402 { 403 /* Update DLY_ACCU_RED_SHIFTER_DONE to 0xF for mvs0, mvs0c */ 404 regmap_update_bits(regmap, 0x8074, GENMASK(25, 21), GENMASK(25, 21)); 405 regmap_update_bits(regmap, 0x8040, GENMASK(25, 21), GENMASK(25, 21)); 406 407 regmap_update_bits(regmap, 0x9f24, BIT(0), BIT(0)); 408 } 409 410 static const struct qcom_cc_driver_data video_cc_sm8750_driver_data = { 411 .alpha_plls = video_cc_sm8750_plls, 412 .num_alpha_plls = ARRAY_SIZE(video_cc_sm8750_plls), 413 .clk_cbcrs = video_cc_sm8750_critical_cbcrs, 414 .num_clk_cbcrs = ARRAY_SIZE(video_cc_sm8750_critical_cbcrs), 415 .clk_regs_configure = clk_sm8750_regs_configure, 416 }; 417 418 static const struct qcom_cc_desc video_cc_sm8750_desc = { 419 .config = &video_cc_sm8750_regmap_config, 420 .clks = video_cc_sm8750_clocks, 421 .num_clks = ARRAY_SIZE(video_cc_sm8750_clocks), 422 .resets = video_cc_sm8750_resets, 423 .num_resets = ARRAY_SIZE(video_cc_sm8750_resets), 424 .gdscs = video_cc_sm8750_gdscs, 425 .num_gdscs = ARRAY_SIZE(video_cc_sm8750_gdscs), 426 .use_rpm = true, 427 .driver_data = &video_cc_sm8750_driver_data, 428 }; 429 430 static const struct of_device_id video_cc_sm8750_match_table[] = { 431 { .compatible = "qcom,sm8750-videocc" }, 432 { } 433 }; 434 MODULE_DEVICE_TABLE(of, video_cc_sm8750_match_table); 435 436 static int video_cc_sm8750_probe(struct platform_device *pdev) 437 { 438 return qcom_cc_probe(pdev, &video_cc_sm8750_desc); 439 } 440 441 static struct platform_driver video_cc_sm8750_driver = { 442 .probe = video_cc_sm8750_probe, 443 .driver = { 444 .name = "video_cc-sm8750", 445 .of_match_table = video_cc_sm8750_match_table, 446 }, 447 }; 448 449 static int __init video_cc_sm8750_init(void) 450 { 451 return platform_driver_register(&video_cc_sm8750_driver); 452 } 453 subsys_initcall(video_cc_sm8750_init); 454 455 static void __exit video_cc_sm8750_exit(void) 456 { 457 platform_driver_unregister(&video_cc_sm8750_driver); 458 } 459 module_exit(video_cc_sm8750_exit); 460 461 MODULE_DESCRIPTION("QTI VIDEO_CC SM8750 Driver"); 462 MODULE_LICENSE("GPL"); 463