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