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

clk: qcom: Add video clock controller driver for SM6350

Add support for the video clock controller found on SM6350 based
devices.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Konrad Dybcio <konradybcio@kernel.org>
Co-developed-by: Luca Weiss <luca.weiss@fairphone.com>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
Link: https://lore.kernel.org/r/20250324-sm6350-videocc-v2-3-cc22386433f4@fairphone.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>

authored by

Konrad Dybcio and committed by
Bjorn Andersson
720b1e8f d7eddaf0

+365
+9
drivers/clk/qcom/Kconfig
··· 1329 1329 Say Y if you want to support video devices and functionality such as 1330 1330 video encode/decode. 1331 1331 1332 + config SM_VIDEOCC_6350 1333 + tristate "SM6350 Video Clock Controller" 1334 + select SM_GCC_6350 1335 + select QCOM_GDSC 1336 + help 1337 + Support for the video clock controller on SM6350 devices. 1338 + Say Y if you want to support video devices and functionality such as 1339 + video encode and decode. 1340 + 1332 1341 config SM_VIDEOCC_7150 1333 1342 tristate "SM7150 Video Clock Controller" 1334 1343 depends on ARM64 || COMPILE_TEST
+1
drivers/clk/qcom/Makefile
··· 164 164 obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o 165 165 obj-$(CONFIG_SM_TCSRCC_8650) += tcsrcc-sm8650.o 166 166 obj-$(CONFIG_SM_TCSRCC_8750) += tcsrcc-sm8750.o 167 + obj-$(CONFIG_SM_VIDEOCC_6350) += videocc-sm6350.o 167 168 obj-$(CONFIG_SM_VIDEOCC_7150) += videocc-sm7150.o 168 169 obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o 169 170 obj-$(CONFIG_SM_VIDEOCC_8250) += videocc-sm8250.o
+355
drivers/clk/qcom/videocc-sm6350.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2021, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org> 5 + * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com> 6 + */ 7 + 8 + #include <linux/clk-provider.h> 9 + #include <linux/module.h> 10 + #include <linux/platform_device.h> 11 + #include <linux/regmap.h> 12 + 13 + #include <dt-bindings/clock/qcom,sm6350-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 "common.h" 20 + #include "gdsc.h" 21 + 22 + enum { 23 + DT_IFACE, 24 + DT_BI_TCXO, 25 + DT_SLEEP_CLK, 26 + }; 27 + 28 + enum { 29 + P_BI_TCXO, 30 + P_CHIP_SLEEP_CLK, 31 + P_VIDEO_PLL0_OUT_EVEN, 32 + }; 33 + 34 + static const struct pll_vco fabia_vco[] = { 35 + { 125000000, 1000000000, 1 }, 36 + }; 37 + 38 + /* 600 MHz */ 39 + static const struct alpha_pll_config video_pll0_config = { 40 + .l = 0x1f, 41 + .alpha = 0x4000, 42 + .config_ctl_val = 0x20485699, 43 + .config_ctl_hi_val = 0x00002067, 44 + .test_ctl_val = 0x40000000, 45 + .test_ctl_hi_val = 0x00000002, 46 + .user_ctl_val = 0x00000101, 47 + .user_ctl_hi_val = 0x00004005, 48 + }; 49 + 50 + static struct clk_alpha_pll video_pll0 = { 51 + .offset = 0x0, 52 + .vco_table = fabia_vco, 53 + .num_vco = ARRAY_SIZE(fabia_vco), 54 + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], 55 + .clkr = { 56 + .hw.init = &(const struct clk_init_data) { 57 + .name = "video_pll0", 58 + .parent_data = &(const struct clk_parent_data) { 59 + .index = DT_BI_TCXO, 60 + }, 61 + .num_parents = 1, 62 + .ops = &clk_alpha_pll_fabia_ops, 63 + }, 64 + }, 65 + }; 66 + 67 + static const struct clk_div_table post_div_table_video_pll0_out_even[] = { 68 + { 0x1, 2 }, 69 + { } 70 + }; 71 + 72 + static struct clk_alpha_pll_postdiv video_pll0_out_even = { 73 + .offset = 0x0, 74 + .post_div_shift = 8, 75 + .post_div_table = post_div_table_video_pll0_out_even, 76 + .num_post_div = ARRAY_SIZE(post_div_table_video_pll0_out_even), 77 + .width = 4, 78 + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], 79 + .clkr.hw.init = &(const struct clk_init_data) { 80 + .name = "video_pll0_out_even", 81 + .parent_hws = (const struct clk_hw*[]) { 82 + &video_pll0.clkr.hw, 83 + }, 84 + .num_parents = 1, 85 + .flags = CLK_SET_RATE_PARENT, 86 + .ops = &clk_alpha_pll_postdiv_fabia_ops, 87 + }, 88 + }; 89 + 90 + static const struct parent_map video_cc_parent_map_0[] = { 91 + { P_BI_TCXO, 0 }, 92 + { P_VIDEO_PLL0_OUT_EVEN, 3 }, 93 + }; 94 + 95 + static const struct clk_parent_data video_cc_parent_data_0[] = { 96 + { .index = DT_BI_TCXO }, 97 + { .hw = &video_pll0_out_even.clkr.hw }, 98 + }; 99 + 100 + static const struct parent_map video_cc_parent_map_1[] = { 101 + { P_CHIP_SLEEP_CLK, 0 }, 102 + }; 103 + 104 + static const struct clk_parent_data video_cc_parent_data_1[] = { 105 + { .index = DT_SLEEP_CLK }, 106 + }; 107 + 108 + static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = { 109 + F(133250000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0), 110 + F(240000000, P_VIDEO_PLL0_OUT_EVEN, 1.5, 0, 0), 111 + F(300000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0), 112 + F(380000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0), 113 + F(460000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0), 114 + { } 115 + }; 116 + 117 + static struct clk_rcg2 video_cc_iris_clk_src = { 118 + .cmd_rcgr = 0x1000, 119 + .mnd_width = 0, 120 + .hid_width = 5, 121 + .parent_map = video_cc_parent_map_0, 122 + .freq_tbl = ftbl_video_cc_iris_clk_src, 123 + .clkr.hw.init = &(const struct clk_init_data) { 124 + .name = "video_cc_iris_clk_src", 125 + .parent_data = video_cc_parent_data_0, 126 + .num_parents = ARRAY_SIZE(video_cc_parent_data_0), 127 + .flags = CLK_SET_RATE_PARENT, 128 + .ops = &clk_rcg2_shared_ops, 129 + }, 130 + }; 131 + 132 + static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = { 133 + F(32764, P_CHIP_SLEEP_CLK, 1, 0, 0), 134 + { } 135 + }; 136 + 137 + static struct clk_rcg2 video_cc_sleep_clk_src = { 138 + .cmd_rcgr = 0x701c, 139 + .mnd_width = 0, 140 + .hid_width = 5, 141 + .parent_map = video_cc_parent_map_1, 142 + .freq_tbl = ftbl_video_cc_sleep_clk_src, 143 + .clkr.hw.init = &(const struct clk_init_data) { 144 + .name = "video_cc_sleep_clk_src", 145 + .parent_data = video_cc_parent_data_1, 146 + .num_parents = ARRAY_SIZE(video_cc_parent_data_1), 147 + .ops = &clk_rcg2_ops, 148 + }, 149 + }; 150 + 151 + static struct clk_branch video_cc_iris_ahb_clk = { 152 + .halt_reg = 0x5004, 153 + .halt_check = BRANCH_VOTED, 154 + .clkr = { 155 + .enable_reg = 0x5004, 156 + .enable_mask = BIT(0), 157 + .hw.init = &(const struct clk_init_data) { 158 + .name = "video_cc_iris_ahb_clk", 159 + .parent_hws = (const struct clk_hw*[]) { 160 + &video_cc_iris_clk_src.clkr.hw, 161 + }, 162 + .num_parents = 1, 163 + .flags = CLK_SET_RATE_PARENT, 164 + .ops = &clk_branch2_ops, 165 + }, 166 + }, 167 + }; 168 + 169 + static struct clk_branch video_cc_mvs0_axi_clk = { 170 + .halt_reg = 0x800c, 171 + .halt_check = BRANCH_HALT, 172 + .clkr = { 173 + .enable_reg = 0x800c, 174 + .enable_mask = BIT(0), 175 + .hw.init = &(const struct clk_init_data) { 176 + .name = "video_cc_mvs0_axi_clk", 177 + .ops = &clk_branch2_ops, 178 + }, 179 + }, 180 + }; 181 + 182 + static struct clk_branch video_cc_mvs0_core_clk = { 183 + .halt_reg = 0x3010, 184 + .halt_check = BRANCH_VOTED, 185 + .hwcg_reg = 0x3010, 186 + .hwcg_bit = 1, 187 + .clkr = { 188 + .enable_reg = 0x3010, 189 + .enable_mask = BIT(0), 190 + .hw.init = &(const struct clk_init_data) { 191 + .name = "video_cc_mvs0_core_clk", 192 + .parent_hws = (const struct clk_hw*[]) { 193 + &video_cc_iris_clk_src.clkr.hw, 194 + }, 195 + .num_parents = 1, 196 + .flags = CLK_SET_RATE_PARENT, 197 + .ops = &clk_branch2_ops, 198 + }, 199 + }, 200 + }; 201 + 202 + static struct clk_branch video_cc_mvsc_core_clk = { 203 + .halt_reg = 0x2014, 204 + .halt_check = BRANCH_HALT, 205 + .clkr = { 206 + .enable_reg = 0x2014, 207 + .enable_mask = BIT(0), 208 + .hw.init = &(const struct clk_init_data) { 209 + .name = "video_cc_mvsc_core_clk", 210 + .parent_hws = (const struct clk_hw*[]) { 211 + &video_cc_iris_clk_src.clkr.hw, 212 + }, 213 + .num_parents = 1, 214 + .flags = CLK_SET_RATE_PARENT, 215 + .ops = &clk_branch2_ops, 216 + }, 217 + }, 218 + }; 219 + 220 + static struct clk_branch video_cc_mvsc_ctl_axi_clk = { 221 + .halt_reg = 0x8004, 222 + .halt_check = BRANCH_HALT, 223 + .clkr = { 224 + .enable_reg = 0x8004, 225 + .enable_mask = BIT(0), 226 + .hw.init = &(const struct clk_init_data) { 227 + .name = "video_cc_mvsc_ctl_axi_clk", 228 + .ops = &clk_branch2_ops, 229 + }, 230 + }, 231 + }; 232 + 233 + static struct clk_branch video_cc_sleep_clk = { 234 + .halt_reg = 0x7034, 235 + .halt_check = BRANCH_HALT, 236 + .clkr = { 237 + .enable_reg = 0x7034, 238 + .enable_mask = BIT(0), 239 + .hw.init = &(const struct clk_init_data) { 240 + .name = "video_cc_sleep_clk", 241 + .parent_hws = (const struct clk_hw*[]) { 242 + &video_cc_sleep_clk_src.clkr.hw, 243 + }, 244 + .num_parents = 1, 245 + .flags = CLK_SET_RATE_PARENT, 246 + .ops = &clk_branch2_ops, 247 + }, 248 + }, 249 + }; 250 + 251 + static struct clk_branch video_cc_venus_ahb_clk = { 252 + .halt_reg = 0x801c, 253 + .halt_check = BRANCH_HALT, 254 + .clkr = { 255 + .enable_reg = 0x801c, 256 + .enable_mask = BIT(0), 257 + .hw.init = &(const struct clk_init_data) { 258 + .name = "video_cc_venus_ahb_clk", 259 + .ops = &clk_branch2_ops, 260 + }, 261 + }, 262 + }; 263 + 264 + static struct gdsc mvsc_gdsc = { 265 + .gdscr = 0x2004, 266 + .en_rest_wait_val = 0x2, 267 + .en_few_wait_val = 0x2, 268 + .clk_dis_wait_val = 0x6, 269 + .pd = { 270 + .name = "mvsc_gdsc", 271 + }, 272 + .pwrsts = PWRSTS_OFF_ON, 273 + }; 274 + 275 + static struct gdsc mvs0_gdsc = { 276 + .gdscr = 0x3004, 277 + .en_rest_wait_val = 0x2, 278 + .en_few_wait_val = 0x2, 279 + .clk_dis_wait_val = 0x6, 280 + .pd = { 281 + .name = "mvs0_gdsc", 282 + }, 283 + .pwrsts = PWRSTS_OFF_ON, 284 + .flags = HW_CTRL_TRIGGER, 285 + }; 286 + 287 + static struct gdsc *video_cc_sm6350_gdscs[] = { 288 + [MVSC_GDSC] = &mvsc_gdsc, 289 + [MVS0_GDSC] = &mvs0_gdsc, 290 + }; 291 + 292 + static struct clk_regmap *video_cc_sm6350_clocks[] = { 293 + [VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr, 294 + [VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr, 295 + [VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr, 296 + [VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr, 297 + [VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr, 298 + [VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr, 299 + [VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr, 300 + [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr, 301 + [VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr, 302 + [VIDEO_PLL0] = &video_pll0.clkr, 303 + [VIDEO_PLL0_OUT_EVEN] = &video_pll0_out_even.clkr, 304 + }; 305 + 306 + static const struct regmap_config video_cc_sm6350_regmap_config = { 307 + .reg_bits = 32, 308 + .reg_stride = 4, 309 + .val_bits = 32, 310 + .max_register = 0xb000, 311 + .fast_io = true, 312 + }; 313 + 314 + static const struct qcom_cc_desc video_cc_sm6350_desc = { 315 + .config = &video_cc_sm6350_regmap_config, 316 + .clks = video_cc_sm6350_clocks, 317 + .num_clks = ARRAY_SIZE(video_cc_sm6350_clocks), 318 + .gdscs = video_cc_sm6350_gdscs, 319 + .num_gdscs = ARRAY_SIZE(video_cc_sm6350_gdscs), 320 + }; 321 + 322 + static const struct of_device_id video_cc_sm6350_match_table[] = { 323 + { .compatible = "qcom,sm6350-videocc" }, 324 + { } 325 + }; 326 + MODULE_DEVICE_TABLE(of, video_cc_sm6350_match_table); 327 + 328 + static int video_cc_sm6350_probe(struct platform_device *pdev) 329 + { 330 + struct regmap *regmap; 331 + 332 + regmap = qcom_cc_map(pdev, &video_cc_sm6350_desc); 333 + if (IS_ERR(regmap)) 334 + return PTR_ERR(regmap); 335 + 336 + clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); 337 + 338 + /* Keep some clocks always-on */ 339 + qcom_branch_set_clk_en(regmap, 0x7018); /* VIDEO_CC_XO_CLK */ 340 + 341 + return qcom_cc_really_probe(&pdev->dev, &video_cc_sm6350_desc, regmap); 342 + } 343 + 344 + static struct platform_driver video_cc_sm6350_driver = { 345 + .probe = video_cc_sm6350_probe, 346 + .driver = { 347 + .name = "video_cc-sm6350", 348 + .of_match_table = video_cc_sm6350_match_table, 349 + }, 350 + }; 351 + 352 + module_platform_driver(video_cc_sm6350_driver); 353 + 354 + MODULE_DESCRIPTION("QTI VIDEO_CC SM6350 Driver"); 355 + MODULE_LICENSE("GPL");