1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
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/pm_runtime.h>
11 #include <linux/regmap.h>
13 #include <dt-bindings/clock/qcom,sm8450-videocc.h>
15 #include "clk-alpha-pll.h"
16 #include "clk-branch.h"
18 #include "clk-regmap.h"
19 #include "clk-regmap-divider.h"
30 P_VIDEO_CC_PLL0_OUT_MAIN
,
31 P_VIDEO_CC_PLL1_OUT_MAIN
,
34 static const struct pll_vco lucid_evo_vco
[] = {
35 { 249600000, 2020000000, 0 },
38 static const struct alpha_pll_config video_cc_pll0_config
= {
39 /* .l includes CAL_L_VAL, L_VAL fields */
42 .config_ctl_val
= 0x20485699,
43 .config_ctl_hi_val
= 0x00182261,
44 .config_ctl_hi1_val
= 0x32aa299c,
45 .user_ctl_val
= 0x00000000,
46 .user_ctl_hi_val
= 0x00000805,
49 static const struct alpha_pll_config sm8475_video_cc_pll0_config
= {
50 /* .l includes CAL_L_VAL, L_VAL fields */
53 .config_ctl_val
= 0x20485699,
54 .config_ctl_hi_val
= 0x00182261,
55 .config_ctl_hi1_val
= 0x82aa299c,
56 .test_ctl_val
= 0x00000000,
57 .test_ctl_hi_val
= 0x00000003,
58 .test_ctl_hi1_val
= 0x00009000,
59 .test_ctl_hi2_val
= 0x00000034,
60 .user_ctl_val
= 0x00000000,
61 .user_ctl_hi_val
= 0x00000005,
64 static struct clk_alpha_pll video_cc_pll0
= {
66 .vco_table
= lucid_evo_vco
,
67 .num_vco
= ARRAY_SIZE(lucid_evo_vco
),
68 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID_EVO
],
70 .hw
.init
= &(const struct clk_init_data
) {
71 .name
= "video_cc_pll0",
72 .parent_data
= &(const struct clk_parent_data
) {
76 .ops
= &clk_alpha_pll_lucid_evo_ops
,
81 static const struct alpha_pll_config video_cc_pll1_config
= {
82 /* .l includes CAL_L_VAL, L_VAL fields */
85 .config_ctl_val
= 0x20485699,
86 .config_ctl_hi_val
= 0x00182261,
87 .config_ctl_hi1_val
= 0x32aa299c,
88 .user_ctl_val
= 0x00000000,
89 .user_ctl_hi_val
= 0x00000805,
92 static const struct alpha_pll_config sm8475_video_cc_pll1_config
= {
93 /* .l includes CAL_L_VAL, L_VAL fields */
96 .config_ctl_val
= 0x20485699,
97 .config_ctl_hi_val
= 0x00182261,
98 .config_ctl_hi1_val
= 0x82aa299c,
99 .test_ctl_val
= 0x00000000,
100 .test_ctl_hi_val
= 0x00000003,
101 .test_ctl_hi1_val
= 0x00009000,
102 .test_ctl_hi2_val
= 0x00000034,
103 .user_ctl_val
= 0x00000000,
104 .user_ctl_hi_val
= 0x00000005,
107 static struct clk_alpha_pll video_cc_pll1
= {
109 .vco_table
= lucid_evo_vco
,
110 .num_vco
= ARRAY_SIZE(lucid_evo_vco
),
111 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID_EVO
],
113 .hw
.init
= &(const struct clk_init_data
) {
114 .name
= "video_cc_pll1",
115 .parent_data
= &(const struct clk_parent_data
) {
119 .ops
= &clk_alpha_pll_lucid_evo_ops
,
124 static const struct parent_map video_cc_parent_map_0
[] = {
126 { P_VIDEO_CC_PLL0_OUT_MAIN
, 1 },
129 static const struct clk_parent_data video_cc_parent_data_0
[] = {
130 { .index
= DT_BI_TCXO
},
131 { .hw
= &video_cc_pll0
.clkr
.hw
},
134 static const struct parent_map video_cc_parent_map_1
[] = {
136 { P_VIDEO_CC_PLL1_OUT_MAIN
, 1 },
139 static const struct clk_parent_data video_cc_parent_data_1
[] = {
140 { .index
= DT_BI_TCXO
},
141 { .hw
= &video_cc_pll1
.clkr
.hw
},
144 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src
[] = {
145 F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN
, 1, 0, 0),
146 F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN
, 1, 0, 0),
147 F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN
, 1, 0, 0),
148 F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN
, 1, 0, 0),
149 F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN
, 1, 0, 0),
153 static struct clk_rcg2 video_cc_mvs0_clk_src
= {
157 .parent_map
= video_cc_parent_map_0
,
158 .freq_tbl
= ftbl_video_cc_mvs0_clk_src
,
159 .clkr
.hw
.init
= &(const struct clk_init_data
) {
160 .name
= "video_cc_mvs0_clk_src",
161 .parent_data
= video_cc_parent_data_0
,
162 .num_parents
= ARRAY_SIZE(video_cc_parent_data_0
),
163 .flags
= CLK_SET_RATE_PARENT
,
164 .ops
= &clk_rcg2_shared_ops
,
168 static const struct freq_tbl ftbl_video_cc_mvs1_clk_src
[] = {
169 F(840000000, P_VIDEO_CC_PLL1_OUT_MAIN
, 1, 0, 0),
170 F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN
, 1, 0, 0),
171 F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN
, 1, 0, 0),
172 F(1500000000, P_VIDEO_CC_PLL1_OUT_MAIN
, 1, 0, 0),
173 F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN
, 1, 0, 0),
177 static struct clk_rcg2 video_cc_mvs1_clk_src
= {
181 .parent_map
= video_cc_parent_map_1
,
182 .freq_tbl
= ftbl_video_cc_mvs1_clk_src
,
183 .clkr
.hw
.init
= &(const struct clk_init_data
) {
184 .name
= "video_cc_mvs1_clk_src",
185 .parent_data
= video_cc_parent_data_1
,
186 .num_parents
= ARRAY_SIZE(video_cc_parent_data_1
),
187 .flags
= CLK_SET_RATE_PARENT
,
188 .ops
= &clk_rcg2_shared_ops
,
192 static struct clk_regmap_div video_cc_mvs0_div_clk_src
= {
196 .clkr
.hw
.init
= &(const struct clk_init_data
) {
197 .name
= "video_cc_mvs0_div_clk_src",
198 .parent_hws
= (const struct clk_hw
*[]) {
199 &video_cc_mvs0_clk_src
.clkr
.hw
,
202 .flags
= CLK_SET_RATE_PARENT
,
203 .ops
= &clk_regmap_div_ro_ops
,
207 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src
= {
211 .clkr
.hw
.init
= &(const struct clk_init_data
) {
212 .name
= "video_cc_mvs0c_div2_div_clk_src",
213 .parent_hws
= (const struct clk_hw
*[]) {
214 &video_cc_mvs0_clk_src
.clkr
.hw
,
217 .flags
= CLK_SET_RATE_PARENT
,
218 .ops
= &clk_regmap_div_ro_ops
,
222 static struct clk_regmap_div video_cc_mvs1_div_clk_src
= {
226 .clkr
.hw
.init
= &(const struct clk_init_data
) {
227 .name
= "video_cc_mvs1_div_clk_src",
228 .parent_hws
= (const struct clk_hw
*[]) {
229 &video_cc_mvs1_clk_src
.clkr
.hw
,
232 .flags
= CLK_SET_RATE_PARENT
,
233 .ops
= &clk_regmap_div_ro_ops
,
237 static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src
= {
241 .clkr
.hw
.init
= &(const struct clk_init_data
) {
242 .name
= "video_cc_mvs1c_div2_div_clk_src",
243 .parent_hws
= (const struct clk_hw
*[]) {
244 &video_cc_mvs1_clk_src
.clkr
.hw
,
247 .flags
= CLK_SET_RATE_PARENT
,
248 .ops
= &clk_regmap_div_ro_ops
,
252 static struct clk_branch video_cc_mvs0_clk
= {
254 .halt_check
= BRANCH_HALT_SKIP
,
258 .enable_reg
= 0x80b0,
259 .enable_mask
= BIT(0),
260 .hw
.init
= &(const struct clk_init_data
) {
261 .name
= "video_cc_mvs0_clk",
262 .parent_hws
= (const struct clk_hw
*[]) {
263 &video_cc_mvs0_div_clk_src
.clkr
.hw
,
266 .flags
= CLK_SET_RATE_PARENT
,
267 .ops
= &clk_branch2_ops
,
272 static struct clk_branch video_cc_mvs0c_clk
= {
274 .halt_check
= BRANCH_HALT
,
276 .enable_reg
= 0x8064,
277 .enable_mask
= BIT(0),
278 .hw
.init
= &(const struct clk_init_data
) {
279 .name
= "video_cc_mvs0c_clk",
280 .parent_hws
= (const struct clk_hw
*[]) {
281 &video_cc_mvs0c_div2_div_clk_src
.clkr
.hw
,
284 .flags
= CLK_SET_RATE_PARENT
,
285 .ops
= &clk_branch2_ops
,
290 static struct clk_branch video_cc_mvs1_clk
= {
292 .halt_check
= BRANCH_HALT_SKIP
,
296 .enable_reg
= 0x80d4,
297 .enable_mask
= BIT(0),
298 .hw
.init
= &(const struct clk_init_data
) {
299 .name
= "video_cc_mvs1_clk",
300 .parent_hws
= (const struct clk_hw
*[]) {
301 &video_cc_mvs1_div_clk_src
.clkr
.hw
,
304 .flags
= CLK_SET_RATE_PARENT
,
305 .ops
= &clk_branch2_ops
,
310 static struct clk_branch video_cc_mvs1c_clk
= {
312 .halt_check
= BRANCH_HALT
,
314 .enable_reg
= 0x808c,
315 .enable_mask
= BIT(0),
316 .hw
.init
= &(const struct clk_init_data
) {
317 .name
= "video_cc_mvs1c_clk",
318 .parent_hws
= (const struct clk_hw
*[]) {
319 &video_cc_mvs1c_div2_div_clk_src
.clkr
.hw
,
322 .flags
= CLK_SET_RATE_PARENT
,
323 .ops
= &clk_branch2_ops
,
328 static struct gdsc video_cc_mvs0c_gdsc
= {
330 .en_rest_wait_val
= 0x2,
331 .en_few_wait_val
= 0x2,
332 .clk_dis_wait_val
= 0x6,
334 .name
= "video_cc_mvs0c_gdsc",
336 .pwrsts
= PWRSTS_OFF_ON
,
337 .flags
= RETAIN_FF_ENABLE
,
340 static struct gdsc video_cc_mvs0_gdsc
= {
342 .en_rest_wait_val
= 0x2,
343 .en_few_wait_val
= 0x2,
344 .clk_dis_wait_val
= 0x6,
346 .name
= "video_cc_mvs0_gdsc",
348 .pwrsts
= PWRSTS_OFF_ON
,
349 .parent
= &video_cc_mvs0c_gdsc
.pd
,
350 .flags
= RETAIN_FF_ENABLE
| HW_CTRL
,
353 static struct gdsc video_cc_mvs1c_gdsc
= {
355 .en_rest_wait_val
= 0x2,
356 .en_few_wait_val
= 0x2,
357 .clk_dis_wait_val
= 0x6,
359 .name
= "video_cc_mvs1c_gdsc",
361 .pwrsts
= PWRSTS_OFF_ON
,
362 .flags
= RETAIN_FF_ENABLE
,
365 static struct gdsc video_cc_mvs1_gdsc
= {
367 .en_rest_wait_val
= 0x2,
368 .en_few_wait_val
= 0x2,
369 .clk_dis_wait_val
= 0x6,
371 .name
= "video_cc_mvs1_gdsc",
373 .pwrsts
= PWRSTS_OFF_ON
,
374 .parent
= &video_cc_mvs1c_gdsc
.pd
,
375 .flags
= RETAIN_FF_ENABLE
| HW_CTRL
,
378 static struct clk_regmap
*video_cc_sm8450_clocks
[] = {
379 [VIDEO_CC_MVS0_CLK
] = &video_cc_mvs0_clk
.clkr
,
380 [VIDEO_CC_MVS0_CLK_SRC
] = &video_cc_mvs0_clk_src
.clkr
,
381 [VIDEO_CC_MVS0_DIV_CLK_SRC
] = &video_cc_mvs0_div_clk_src
.clkr
,
382 [VIDEO_CC_MVS0C_CLK
] = &video_cc_mvs0c_clk
.clkr
,
383 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC
] = &video_cc_mvs0c_div2_div_clk_src
.clkr
,
384 [VIDEO_CC_MVS1_CLK
] = &video_cc_mvs1_clk
.clkr
,
385 [VIDEO_CC_MVS1_CLK_SRC
] = &video_cc_mvs1_clk_src
.clkr
,
386 [VIDEO_CC_MVS1_DIV_CLK_SRC
] = &video_cc_mvs1_div_clk_src
.clkr
,
387 [VIDEO_CC_MVS1C_CLK
] = &video_cc_mvs1c_clk
.clkr
,
388 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC
] = &video_cc_mvs1c_div2_div_clk_src
.clkr
,
389 [VIDEO_CC_PLL0
] = &video_cc_pll0
.clkr
,
390 [VIDEO_CC_PLL1
] = &video_cc_pll1
.clkr
,
393 static struct gdsc
*video_cc_sm8450_gdscs
[] = {
394 [VIDEO_CC_MVS0C_GDSC
] = &video_cc_mvs0c_gdsc
,
395 [VIDEO_CC_MVS0_GDSC
] = &video_cc_mvs0_gdsc
,
396 [VIDEO_CC_MVS1C_GDSC
] = &video_cc_mvs1c_gdsc
,
397 [VIDEO_CC_MVS1_GDSC
] = &video_cc_mvs1_gdsc
,
400 static const struct qcom_reset_map video_cc_sm8450_resets
[] = {
401 [CVP_VIDEO_CC_INTERFACE_BCR
] = { 0x80e0 },
402 [CVP_VIDEO_CC_MVS0_BCR
] = { 0x8098 },
403 [CVP_VIDEO_CC_MVS0C_BCR
] = { 0x8048 },
404 [CVP_VIDEO_CC_MVS1_BCR
] = { 0x80bc },
405 [CVP_VIDEO_CC_MVS1C_BCR
] = { 0x8070 },
406 [VIDEO_CC_MVS0C_CLK_ARES
] = { .reg
= 0x8064, .bit
= 2, .udelay
= 1000 },
407 [VIDEO_CC_MVS1C_CLK_ARES
] = { .reg
= 0x808c, .bit
= 2, .udelay
= 1000 },
410 static const struct regmap_config video_cc_sm8450_regmap_config
= {
414 .max_register
= 0x9f4c,
418 static struct qcom_cc_desc video_cc_sm8450_desc
= {
419 .config
= &video_cc_sm8450_regmap_config
,
420 .clks
= video_cc_sm8450_clocks
,
421 .num_clks
= ARRAY_SIZE(video_cc_sm8450_clocks
),
422 .resets
= video_cc_sm8450_resets
,
423 .num_resets
= ARRAY_SIZE(video_cc_sm8450_resets
),
424 .gdscs
= video_cc_sm8450_gdscs
,
425 .num_gdscs
= ARRAY_SIZE(video_cc_sm8450_gdscs
),
428 static const struct of_device_id video_cc_sm8450_match_table
[] = {
429 { .compatible
= "qcom,sm8450-videocc" },
430 { .compatible
= "qcom,sm8475-videocc" },
433 MODULE_DEVICE_TABLE(of
, video_cc_sm8450_match_table
);
435 static int video_cc_sm8450_probe(struct platform_device
*pdev
)
437 struct regmap
*regmap
;
440 ret
= devm_pm_runtime_enable(&pdev
->dev
);
444 ret
= pm_runtime_resume_and_get(&pdev
->dev
);
448 regmap
= qcom_cc_map(pdev
, &video_cc_sm8450_desc
);
449 if (IS_ERR(regmap
)) {
450 pm_runtime_put(&pdev
->dev
);
451 return PTR_ERR(regmap
);
454 if (of_device_is_compatible(pdev
->dev
.of_node
, "qcom,sm8475-videocc")) {
455 /* Update VideoCC PLL0 */
456 video_cc_pll0
.regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID_OLE
];
458 /* Update VideoCC PLL1 */
459 video_cc_pll1
.regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_LUCID_OLE
];
461 clk_lucid_ole_pll_configure(&video_cc_pll0
, regmap
, &sm8475_video_cc_pll0_config
);
462 clk_lucid_ole_pll_configure(&video_cc_pll1
, regmap
, &sm8475_video_cc_pll1_config
);
464 clk_lucid_evo_pll_configure(&video_cc_pll0
, regmap
, &video_cc_pll0_config
);
465 clk_lucid_evo_pll_configure(&video_cc_pll1
, regmap
, &video_cc_pll1_config
);
468 /* Keep some clocks always-on */
469 qcom_branch_set_clk_en(regmap
, 0x80e4); /* VIDEO_CC_AHB_CLK */
470 qcom_branch_set_clk_en(regmap
, 0x8130); /* VIDEO_CC_SLEEP_CLK */
471 qcom_branch_set_clk_en(regmap
, 0x8114); /* VIDEO_CC_XO_CLK */
473 ret
= qcom_cc_really_probe(&pdev
->dev
, &video_cc_sm8450_desc
, regmap
);
475 pm_runtime_put(&pdev
->dev
);
480 static struct platform_driver video_cc_sm8450_driver
= {
481 .probe
= video_cc_sm8450_probe
,
483 .name
= "video_cc-sm8450",
484 .of_match_table
= video_cc_sm8450_match_table
,
488 module_platform_driver(video_cc_sm8450_driver
);
490 MODULE_DESCRIPTION("QTI VIDEOCC SM8450 / SM8475 Driver");
491 MODULE_LICENSE("GPL");