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/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>
12
13 #include <dt-bindings/clock/qcom,sm8450-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 "clk-regmap-divider.h"
20 #include "common.h"
21 #include "gdsc.h"
22 #include "reset.h"
23
24 enum {
25 DT_BI_TCXO,
26 };
27
28 enum {
29 P_BI_TCXO,
30 P_VIDEO_CC_PLL0_OUT_MAIN,
31 P_VIDEO_CC_PLL1_OUT_MAIN,
32 };
33
34 static const struct pll_vco lucid_evo_vco[] = {
35 { 249600000, 2020000000, 0 },
36 };
37
38 static const struct alpha_pll_config video_cc_pll0_config = {
39 /* .l includes CAL_L_VAL, L_VAL fields */
40 .l = 0x0044001e,
41 .alpha = 0x0,
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,
47 };
48
49 static const struct alpha_pll_config sm8475_video_cc_pll0_config = {
50 /* .l includes CAL_L_VAL, L_VAL fields */
51 .l = 0x1e,
52 .alpha = 0x0,
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,
62 };
63
64 static struct clk_alpha_pll video_cc_pll0 = {
65 .offset = 0x0,
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],
69 .clkr = {
70 .hw.init = &(const struct clk_init_data) {
71 .name = "video_cc_pll0",
72 .parent_data = &(const struct clk_parent_data) {
73 .index = DT_BI_TCXO,
74 },
75 .num_parents = 1,
76 .ops = &clk_alpha_pll_lucid_evo_ops,
77 },
78 },
79 };
80
81 static const struct alpha_pll_config video_cc_pll1_config = {
82 /* .l includes CAL_L_VAL, L_VAL fields */
83 .l = 0x0044002b,
84 .alpha = 0xc000,
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,
90 };
91
92 static const struct alpha_pll_config sm8475_video_cc_pll1_config = {
93 /* .l includes CAL_L_VAL, L_VAL fields */
94 .l = 0x2b,
95 .alpha = 0xc000,
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,
105 };
106
107 static struct clk_alpha_pll video_cc_pll1 = {
108 .offset = 0x1000,
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],
112 .clkr = {
113 .hw.init = &(const struct clk_init_data) {
114 .name = "video_cc_pll1",
115 .parent_data = &(const struct clk_parent_data) {
116 .index = DT_BI_TCXO,
117 },
118 .num_parents = 1,
119 .ops = &clk_alpha_pll_lucid_evo_ops,
120 },
121 },
122 };
123
124 static const struct parent_map video_cc_parent_map_0[] = {
125 { P_BI_TCXO, 0 },
126 { P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
127 };
128
129 static const struct clk_parent_data video_cc_parent_data_0[] = {
130 { .index = DT_BI_TCXO },
131 { .hw = &video_cc_pll0.clkr.hw },
132 };
133
134 static const struct parent_map video_cc_parent_map_1[] = {
135 { P_BI_TCXO, 0 },
136 { P_VIDEO_CC_PLL1_OUT_MAIN, 1 },
137 };
138
139 static const struct clk_parent_data video_cc_parent_data_1[] = {
140 { .index = DT_BI_TCXO },
141 { .hw = &video_cc_pll1.clkr.hw },
142 };
143
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),
150 { }
151 };
152
153 static struct clk_rcg2 video_cc_mvs0_clk_src = {
154 .cmd_rcgr = 0x8000,
155 .mnd_width = 0,
156 .hid_width = 5,
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,
165 },
166 };
167
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),
174 { }
175 };
176
177 static struct clk_rcg2 video_cc_mvs1_clk_src = {
178 .cmd_rcgr = 0x8018,
179 .mnd_width = 0,
180 .hid_width = 5,
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,
189 },
190 };
191
192 static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
193 .reg = 0x80b8,
194 .shift = 0,
195 .width = 4,
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,
200 },
201 .num_parents = 1,
202 .flags = CLK_SET_RATE_PARENT,
203 .ops = &clk_regmap_div_ro_ops,
204 },
205 };
206
207 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
208 .reg = 0x806c,
209 .shift = 0,
210 .width = 4,
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,
215 },
216 .num_parents = 1,
217 .flags = CLK_SET_RATE_PARENT,
218 .ops = &clk_regmap_div_ro_ops,
219 },
220 };
221
222 static struct clk_regmap_div video_cc_mvs1_div_clk_src = {
223 .reg = 0x80dc,
224 .shift = 0,
225 .width = 4,
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,
230 },
231 .num_parents = 1,
232 .flags = CLK_SET_RATE_PARENT,
233 .ops = &clk_regmap_div_ro_ops,
234 },
235 };
236
237 static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
238 .reg = 0x8094,
239 .shift = 0,
240 .width = 4,
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,
245 },
246 .num_parents = 1,
247 .flags = CLK_SET_RATE_PARENT,
248 .ops = &clk_regmap_div_ro_ops,
249 },
250 };
251
252 static struct clk_branch video_cc_mvs0_clk = {
253 .halt_reg = 0x80b0,
254 .halt_check = BRANCH_HALT_SKIP,
255 .hwcg_reg = 0x80b0,
256 .hwcg_bit = 1,
257 .clkr = {
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,
264 },
265 .num_parents = 1,
266 .flags = CLK_SET_RATE_PARENT,
267 .ops = &clk_branch2_ops,
268 },
269 },
270 };
271
272 static struct clk_branch video_cc_mvs0c_clk = {
273 .halt_reg = 0x8064,
274 .halt_check = BRANCH_HALT,
275 .clkr = {
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,
282 },
283 .num_parents = 1,
284 .flags = CLK_SET_RATE_PARENT,
285 .ops = &clk_branch2_ops,
286 },
287 },
288 };
289
290 static struct clk_branch video_cc_mvs1_clk = {
291 .halt_reg = 0x80d4,
292 .halt_check = BRANCH_HALT_SKIP,
293 .hwcg_reg = 0x80d4,
294 .hwcg_bit = 1,
295 .clkr = {
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,
302 },
303 .num_parents = 1,
304 .flags = CLK_SET_RATE_PARENT,
305 .ops = &clk_branch2_ops,
306 },
307 },
308 };
309
310 static struct clk_branch video_cc_mvs1c_clk = {
311 .halt_reg = 0x808c,
312 .halt_check = BRANCH_HALT,
313 .clkr = {
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,
320 },
321 .num_parents = 1,
322 .flags = CLK_SET_RATE_PARENT,
323 .ops = &clk_branch2_ops,
324 },
325 },
326 };
327
328 static struct gdsc video_cc_mvs0c_gdsc = {
329 .gdscr = 0x804c,
330 .en_rest_wait_val = 0x2,
331 .en_few_wait_val = 0x2,
332 .clk_dis_wait_val = 0x6,
333 .pd = {
334 .name = "video_cc_mvs0c_gdsc",
335 },
336 .pwrsts = PWRSTS_OFF_ON,
337 .flags = RETAIN_FF_ENABLE,
338 };
339
340 static struct gdsc video_cc_mvs0_gdsc = {
341 .gdscr = 0x809c,
342 .en_rest_wait_val = 0x2,
343 .en_few_wait_val = 0x2,
344 .clk_dis_wait_val = 0x6,
345 .pd = {
346 .name = "video_cc_mvs0_gdsc",
347 },
348 .pwrsts = PWRSTS_OFF_ON,
349 .parent = &video_cc_mvs0c_gdsc.pd,
350 .flags = RETAIN_FF_ENABLE | HW_CTRL,
351 };
352
353 static struct gdsc video_cc_mvs1c_gdsc = {
354 .gdscr = 0x8074,
355 .en_rest_wait_val = 0x2,
356 .en_few_wait_val = 0x2,
357 .clk_dis_wait_val = 0x6,
358 .pd = {
359 .name = "video_cc_mvs1c_gdsc",
360 },
361 .pwrsts = PWRSTS_OFF_ON,
362 .flags = RETAIN_FF_ENABLE,
363 };
364
365 static struct gdsc video_cc_mvs1_gdsc = {
366 .gdscr = 0x80c0,
367 .en_rest_wait_val = 0x2,
368 .en_few_wait_val = 0x2,
369 .clk_dis_wait_val = 0x6,
370 .pd = {
371 .name = "video_cc_mvs1_gdsc",
372 },
373 .pwrsts = PWRSTS_OFF_ON,
374 .parent = &video_cc_mvs1c_gdsc.pd,
375 .flags = RETAIN_FF_ENABLE | HW_CTRL,
376 };
377
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,
391 };
392
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,
398 };
399
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 },
408 };
409
410 static const struct regmap_config video_cc_sm8450_regmap_config = {
411 .reg_bits = 32,
412 .reg_stride = 4,
413 .val_bits = 32,
414 .max_register = 0x9f4c,
415 .fast_io = true,
416 };
417
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),
426 };
427
428 static const struct of_device_id video_cc_sm8450_match_table[] = {
429 { .compatible = "qcom,sm8450-videocc" },
430 { .compatible = "qcom,sm8475-videocc" },
431 { }
432 };
433 MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table);
434
video_cc_sm8450_probe(struct platform_device * pdev)435 static int video_cc_sm8450_probe(struct platform_device *pdev)
436 {
437 struct regmap *regmap;
438 int ret;
439
440 ret = devm_pm_runtime_enable(&pdev->dev);
441 if (ret)
442 return ret;
443
444 ret = pm_runtime_resume_and_get(&pdev->dev);
445 if (ret)
446 return ret;
447
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);
452 }
453
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];
457
458 /* Update VideoCC PLL1 */
459 video_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
460
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);
463 } else {
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);
466 }
467
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 */
472
473 ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sm8450_desc, regmap);
474
475 pm_runtime_put(&pdev->dev);
476
477 return ret;
478 }
479
480 static struct platform_driver video_cc_sm8450_driver = {
481 .probe = video_cc_sm8450_probe,
482 .driver = {
483 .name = "video_cc-sm8450",
484 .of_match_table = video_cc_sm8450_match_table,
485 },
486 };
487
488 module_platform_driver(video_cc_sm8450_driver);
489
490 MODULE_DESCRIPTION("QTI VIDEOCC SM8450 / SM8475 Driver");
491 MODULE_LICENSE("GPL");
492