Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clk: qcom: videocc-sm8450: Add video clock controller driver for SM8450

Add support for the video clock controller driver for peripheral clock
clients to be able to request for video cc clocks.

Signed-off-by: Taniya Das <quic_tdas@quicinc.com>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230524140656.7076-3-quic_tdas@quicinc.com

authored by

Taniya Das and committed by
Bjorn Andersson
441fe711 cc8d2cf5

+473
+9
drivers/clk/qcom/Kconfig
··· 971 971 Support for the Glitch Free Mux (GFM) Low power audio 972 972 subsystem (LPASS) clocks found on SM8250 SoCs. 973 973 974 + config SM_VIDEOCC_8450 975 + tristate "SM8450 Video Clock Controller" 976 + select SM_GCC_8450 977 + select QCOM_GDSC 978 + help 979 + Support for the video clock controller on Qualcomm Technologies, Inc. 980 + SM8450 devices. 981 + Say Y if you want to support video devices and functionality such as 982 + video encode/decode. 974 983 endif
+1
drivers/clk/qcom/Makefile
··· 128 128 obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o 129 129 obj-$(CONFIG_SM_VIDEOCC_8250) += videocc-sm8250.o 130 130 obj-$(CONFIG_SM_VIDEOCC_8350) += videocc-sm8350.o 131 + obj-$(CONFIG_SM_VIDEOCC_8450) += videocc-sm8450.o 131 132 obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o 132 133 obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o 133 134 obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
+463
drivers/clk/qcom/videocc-sm8450.c
··· 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/module.h> 8 + #include <linux/of_device.h> 9 + #include <linux/pm_runtime.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 struct clk_alpha_pll video_cc_pll0 = { 49 + .offset = 0x0, 50 + .vco_table = lucid_evo_vco, 51 + .num_vco = ARRAY_SIZE(lucid_evo_vco), 52 + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], 53 + .clkr = { 54 + .hw.init = &(const struct clk_init_data) { 55 + .name = "video_cc_pll0", 56 + .parent_data = &(const struct clk_parent_data) { 57 + .index = DT_BI_TCXO, 58 + }, 59 + .num_parents = 1, 60 + .ops = &clk_alpha_pll_lucid_evo_ops, 61 + }, 62 + }, 63 + }; 64 + 65 + static const struct alpha_pll_config video_cc_pll1_config = { 66 + /* .l includes CAL_L_VAL, L_VAL fields */ 67 + .l = 0x0044002b, 68 + .alpha = 0xc000, 69 + .config_ctl_val = 0x20485699, 70 + .config_ctl_hi_val = 0x00182261, 71 + .config_ctl_hi1_val = 0x32aa299c, 72 + .user_ctl_val = 0x00000000, 73 + .user_ctl_hi_val = 0x00000805, 74 + }; 75 + 76 + static struct clk_alpha_pll video_cc_pll1 = { 77 + .offset = 0x1000, 78 + .vco_table = lucid_evo_vco, 79 + .num_vco = ARRAY_SIZE(lucid_evo_vco), 80 + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], 81 + .clkr = { 82 + .hw.init = &(const struct clk_init_data) { 83 + .name = "video_cc_pll1", 84 + .parent_data = &(const struct clk_parent_data) { 85 + .index = DT_BI_TCXO, 86 + }, 87 + .num_parents = 1, 88 + .ops = &clk_alpha_pll_lucid_evo_ops, 89 + }, 90 + }, 91 + }; 92 + 93 + static const struct parent_map video_cc_parent_map_0[] = { 94 + { P_BI_TCXO, 0 }, 95 + { P_VIDEO_CC_PLL0_OUT_MAIN, 1 }, 96 + }; 97 + 98 + static const struct clk_parent_data video_cc_parent_data_0[] = { 99 + { .index = DT_BI_TCXO }, 100 + { .hw = &video_cc_pll0.clkr.hw }, 101 + }; 102 + 103 + static const struct parent_map video_cc_parent_map_1[] = { 104 + { P_BI_TCXO, 0 }, 105 + { P_VIDEO_CC_PLL1_OUT_MAIN, 1 }, 106 + }; 107 + 108 + static const struct clk_parent_data video_cc_parent_data_1[] = { 109 + { .index = DT_BI_TCXO }, 110 + { .hw = &video_cc_pll1.clkr.hw }, 111 + }; 112 + 113 + static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = { 114 + F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 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(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 118 + F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0), 119 + { } 120 + }; 121 + 122 + static struct clk_rcg2 video_cc_mvs0_clk_src = { 123 + .cmd_rcgr = 0x8000, 124 + .mnd_width = 0, 125 + .hid_width = 5, 126 + .parent_map = video_cc_parent_map_0, 127 + .freq_tbl = ftbl_video_cc_mvs0_clk_src, 128 + .clkr.hw.init = &(const struct clk_init_data) { 129 + .name = "video_cc_mvs0_clk_src", 130 + .parent_data = video_cc_parent_data_0, 131 + .num_parents = ARRAY_SIZE(video_cc_parent_data_0), 132 + .flags = CLK_SET_RATE_PARENT, 133 + .ops = &clk_rcg2_shared_ops, 134 + }, 135 + }; 136 + 137 + static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = { 138 + F(840000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 139 + F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 140 + F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 141 + F(1500000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 142 + F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0), 143 + { } 144 + }; 145 + 146 + static struct clk_rcg2 video_cc_mvs1_clk_src = { 147 + .cmd_rcgr = 0x8018, 148 + .mnd_width = 0, 149 + .hid_width = 5, 150 + .parent_map = video_cc_parent_map_1, 151 + .freq_tbl = ftbl_video_cc_mvs1_clk_src, 152 + .clkr.hw.init = &(const struct clk_init_data) { 153 + .name = "video_cc_mvs1_clk_src", 154 + .parent_data = video_cc_parent_data_1, 155 + .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 156 + .flags = CLK_SET_RATE_PARENT, 157 + .ops = &clk_rcg2_shared_ops, 158 + }, 159 + }; 160 + 161 + static struct clk_regmap_div video_cc_mvs0_div_clk_src = { 162 + .reg = 0x80b8, 163 + .shift = 0, 164 + .width = 4, 165 + .clkr.hw.init = &(const struct clk_init_data) { 166 + .name = "video_cc_mvs0_div_clk_src", 167 + .parent_hws = (const struct clk_hw*[]) { 168 + &video_cc_mvs0_clk_src.clkr.hw, 169 + }, 170 + .num_parents = 1, 171 + .flags = CLK_SET_RATE_PARENT, 172 + .ops = &clk_regmap_div_ro_ops, 173 + }, 174 + }; 175 + 176 + static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = { 177 + .reg = 0x806c, 178 + .shift = 0, 179 + .width = 4, 180 + .clkr.hw.init = &(const struct clk_init_data) { 181 + .name = "video_cc_mvs0c_div2_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_mvs1_div_clk_src = { 192 + .reg = 0x80dc, 193 + .shift = 0, 194 + .width = 4, 195 + .clkr.hw.init = &(const struct clk_init_data) { 196 + .name = "video_cc_mvs1_div_clk_src", 197 + .parent_hws = (const struct clk_hw*[]) { 198 + &video_cc_mvs1_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_regmap_div video_cc_mvs1c_div2_div_clk_src = { 207 + .reg = 0x8094, 208 + .shift = 0, 209 + .width = 4, 210 + .clkr.hw.init = &(const struct clk_init_data) { 211 + .name = "video_cc_mvs1c_div2_div_clk_src", 212 + .parent_hws = (const struct clk_hw*[]) { 213 + &video_cc_mvs1_clk_src.clkr.hw, 214 + }, 215 + .num_parents = 1, 216 + .flags = CLK_SET_RATE_PARENT, 217 + .ops = &clk_regmap_div_ro_ops, 218 + }, 219 + }; 220 + 221 + static struct clk_branch video_cc_mvs0_clk = { 222 + .halt_reg = 0x80b0, 223 + .halt_check = BRANCH_HALT_SKIP, 224 + .hwcg_reg = 0x80b0, 225 + .hwcg_bit = 1, 226 + .clkr = { 227 + .enable_reg = 0x80b0, 228 + .enable_mask = BIT(0), 229 + .hw.init = &(const struct clk_init_data) { 230 + .name = "video_cc_mvs0_clk", 231 + .parent_hws = (const struct clk_hw*[]) { 232 + &video_cc_mvs0_div_clk_src.clkr.hw, 233 + }, 234 + .num_parents = 1, 235 + .flags = CLK_SET_RATE_PARENT, 236 + .ops = &clk_branch2_ops, 237 + }, 238 + }, 239 + }; 240 + 241 + static struct clk_branch video_cc_mvs0c_clk = { 242 + .halt_reg = 0x8064, 243 + .halt_check = BRANCH_HALT, 244 + .clkr = { 245 + .enable_reg = 0x8064, 246 + .enable_mask = BIT(0), 247 + .hw.init = &(const struct clk_init_data) { 248 + .name = "video_cc_mvs0c_clk", 249 + .parent_hws = (const struct clk_hw*[]) { 250 + &video_cc_mvs0c_div2_div_clk_src.clkr.hw, 251 + }, 252 + .num_parents = 1, 253 + .flags = CLK_SET_RATE_PARENT, 254 + .ops = &clk_branch2_ops, 255 + }, 256 + }, 257 + }; 258 + 259 + static struct clk_branch video_cc_mvs1_clk = { 260 + .halt_reg = 0x80d4, 261 + .halt_check = BRANCH_HALT_SKIP, 262 + .hwcg_reg = 0x80d4, 263 + .hwcg_bit = 1, 264 + .clkr = { 265 + .enable_reg = 0x80d4, 266 + .enable_mask = BIT(0), 267 + .hw.init = &(const struct clk_init_data) { 268 + .name = "video_cc_mvs1_clk", 269 + .parent_hws = (const struct clk_hw*[]) { 270 + &video_cc_mvs1_div_clk_src.clkr.hw, 271 + }, 272 + .num_parents = 1, 273 + .flags = CLK_SET_RATE_PARENT, 274 + .ops = &clk_branch2_ops, 275 + }, 276 + }, 277 + }; 278 + 279 + static struct clk_branch video_cc_mvs1c_clk = { 280 + .halt_reg = 0x808c, 281 + .halt_check = BRANCH_HALT, 282 + .clkr = { 283 + .enable_reg = 0x808c, 284 + .enable_mask = BIT(0), 285 + .hw.init = &(const struct clk_init_data) { 286 + .name = "video_cc_mvs1c_clk", 287 + .parent_hws = (const struct clk_hw*[]) { 288 + &video_cc_mvs1c_div2_div_clk_src.clkr.hw, 289 + }, 290 + .num_parents = 1, 291 + .flags = CLK_SET_RATE_PARENT, 292 + .ops = &clk_branch2_ops, 293 + }, 294 + }, 295 + }; 296 + 297 + static struct gdsc video_cc_mvs0c_gdsc = { 298 + .gdscr = 0x804c, 299 + .en_rest_wait_val = 0x2, 300 + .en_few_wait_val = 0x2, 301 + .clk_dis_wait_val = 0x6, 302 + .pd = { 303 + .name = "video_cc_mvs0c_gdsc", 304 + }, 305 + .pwrsts = PWRSTS_OFF_ON, 306 + .flags = RETAIN_FF_ENABLE, 307 + }; 308 + 309 + static struct gdsc video_cc_mvs0_gdsc = { 310 + .gdscr = 0x809c, 311 + .en_rest_wait_val = 0x2, 312 + .en_few_wait_val = 0x2, 313 + .clk_dis_wait_val = 0x6, 314 + .pd = { 315 + .name = "video_cc_mvs0_gdsc", 316 + }, 317 + .pwrsts = PWRSTS_OFF_ON, 318 + .parent = &video_cc_mvs0c_gdsc.pd, 319 + .flags = RETAIN_FF_ENABLE | HW_CTRL, 320 + }; 321 + 322 + static struct gdsc video_cc_mvs1c_gdsc = { 323 + .gdscr = 0x8074, 324 + .en_rest_wait_val = 0x2, 325 + .en_few_wait_val = 0x2, 326 + .clk_dis_wait_val = 0x6, 327 + .pd = { 328 + .name = "video_cc_mvs1c_gdsc", 329 + }, 330 + .pwrsts = PWRSTS_OFF_ON, 331 + .flags = RETAIN_FF_ENABLE, 332 + }; 333 + 334 + static struct gdsc video_cc_mvs1_gdsc = { 335 + .gdscr = 0x80c0, 336 + .en_rest_wait_val = 0x2, 337 + .en_few_wait_val = 0x2, 338 + .clk_dis_wait_val = 0x6, 339 + .pd = { 340 + .name = "video_cc_mvs1_gdsc", 341 + }, 342 + .pwrsts = PWRSTS_OFF_ON, 343 + .parent = &video_cc_mvs1c_gdsc.pd, 344 + .flags = RETAIN_FF_ENABLE | HW_CTRL, 345 + }; 346 + 347 + static struct clk_regmap *video_cc_sm8450_clocks[] = { 348 + [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr, 349 + [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr, 350 + [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr, 351 + [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr, 352 + [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr, 353 + [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr, 354 + [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr, 355 + [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr, 356 + [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr, 357 + [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr, 358 + [VIDEO_CC_PLL0] = &video_cc_pll0.clkr, 359 + [VIDEO_CC_PLL1] = &video_cc_pll1.clkr, 360 + }; 361 + 362 + static struct gdsc *video_cc_sm8450_gdscs[] = { 363 + [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc, 364 + [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc, 365 + [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc, 366 + [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc, 367 + }; 368 + 369 + static const struct qcom_reset_map video_cc_sm8450_resets[] = { 370 + [CVP_VIDEO_CC_INTERFACE_BCR] = { 0x80e0 }, 371 + [CVP_VIDEO_CC_MVS0_BCR] = { 0x8098 }, 372 + [CVP_VIDEO_CC_MVS0C_BCR] = { 0x8048 }, 373 + [CVP_VIDEO_CC_MVS1_BCR] = { 0x80bc }, 374 + [CVP_VIDEO_CC_MVS1C_BCR] = { 0x8070 }, 375 + [VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 }, 376 + [VIDEO_CC_MVS1C_CLK_ARES] = { 0x808c, 2 }, 377 + }; 378 + 379 + static const struct regmap_config video_cc_sm8450_regmap_config = { 380 + .reg_bits = 32, 381 + .reg_stride = 4, 382 + .val_bits = 32, 383 + .max_register = 0x9f4c, 384 + .fast_io = true, 385 + }; 386 + 387 + static struct qcom_cc_desc video_cc_sm8450_desc = { 388 + .config = &video_cc_sm8450_regmap_config, 389 + .clks = video_cc_sm8450_clocks, 390 + .num_clks = ARRAY_SIZE(video_cc_sm8450_clocks), 391 + .resets = video_cc_sm8450_resets, 392 + .num_resets = ARRAY_SIZE(video_cc_sm8450_resets), 393 + .gdscs = video_cc_sm8450_gdscs, 394 + .num_gdscs = ARRAY_SIZE(video_cc_sm8450_gdscs), 395 + }; 396 + 397 + static const struct of_device_id video_cc_sm8450_match_table[] = { 398 + { .compatible = "qcom,sm8450-videocc" }, 399 + { } 400 + }; 401 + MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table); 402 + 403 + static int video_cc_sm8450_probe(struct platform_device *pdev) 404 + { 405 + struct regmap *regmap; 406 + int ret; 407 + 408 + ret = devm_pm_runtime_enable(&pdev->dev); 409 + if (ret) 410 + return ret; 411 + 412 + ret = pm_runtime_resume_and_get(&pdev->dev); 413 + if (ret) 414 + return ret; 415 + 416 + regmap = qcom_cc_map(pdev, &video_cc_sm8450_desc); 417 + if (IS_ERR(regmap)) { 418 + pm_runtime_put(&pdev->dev); 419 + return PTR_ERR(regmap); 420 + } 421 + 422 + clk_lucid_evo_pll_configure(&video_cc_pll0, regmap, &video_cc_pll0_config); 423 + clk_lucid_evo_pll_configure(&video_cc_pll1, regmap, &video_cc_pll1_config); 424 + 425 + /* 426 + * Keep clocks always enabled: 427 + * video_cc_ahb_clk 428 + * video_cc_sleep_clk 429 + * video_cc_xo_clk 430 + */ 431 + regmap_update_bits(regmap, 0x80e4, BIT(0), BIT(0)); 432 + regmap_update_bits(regmap, 0x8130, BIT(0), BIT(0)); 433 + regmap_update_bits(regmap, 0x8114, BIT(0), BIT(0)); 434 + 435 + ret = qcom_cc_really_probe(pdev, &video_cc_sm8450_desc, regmap); 436 + 437 + pm_runtime_put(&pdev->dev); 438 + 439 + return ret; 440 + } 441 + 442 + static struct platform_driver video_cc_sm8450_driver = { 443 + .probe = video_cc_sm8450_probe, 444 + .driver = { 445 + .name = "video_cc-sm8450", 446 + .of_match_table = video_cc_sm8450_match_table, 447 + }, 448 + }; 449 + 450 + static int __init video_cc_sm8450_init(void) 451 + { 452 + return platform_driver_register(&video_cc_sm8450_driver); 453 + } 454 + subsys_initcall(video_cc_sm8450_init); 455 + 456 + static void __exit video_cc_sm8450_exit(void) 457 + { 458 + platform_driver_unregister(&video_cc_sm8450_driver); 459 + } 460 + module_exit(video_cc_sm8450_exit); 461 + 462 + MODULE_DESCRIPTION("QTI VIDEOCC SM8450 Driver"); 463 + MODULE_LICENSE("GPL");