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-sm8550: Add video clock controller driver for SM8550

Add support for the video clock controller for video clients to be able
to request for videocc clocks on SM8550 platform.

Co-developed-by: Taniya Das <quic_tdas@quicinc.com>
Signed-off-by: Taniya Das <quic_tdas@quicinc.com>
Signed-off-by: Jagadeesh Kona <quic_jkona@quicinc.com>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230524145203.13153-4-quic_jkona@quicinc.com

authored by

Jagadeesh Kona and committed by
Bjorn Andersson
f53153a3 c7d91f26

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