1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #include <linux/clk-provider.h>
7 #include <linux/module.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/of.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm_runtime.h>
12 #include <linux/regmap.h>
13
14 #include <dt-bindings/clock/qcom,sa8775p-videocc.h>
15
16 #include "clk-alpha-pll.h"
17 #include "clk-branch.h"
18 #include "clk-pll.h"
19 #include "clk-rcg.h"
20 #include "clk-regmap.h"
21 #include "clk-regmap-divider.h"
22 #include "clk-regmap-mux.h"
23 #include "common.h"
24 #include "gdsc.h"
25 #include "reset.h"
26
27 enum {
28 DT_IFACE,
29 DT_BI_TCXO,
30 DT_BI_TCXO_AO,
31 DT_SLEEP_CLK,
32 };
33
34 enum {
35 P_BI_TCXO,
36 P_BI_TCXO_AO,
37 P_SLEEP_CLK,
38 P_VIDEO_PLL0_OUT_MAIN,
39 P_VIDEO_PLL1_OUT_MAIN,
40 };
41
42 static const struct pll_vco lucid_evo_vco[] = {
43 { 249600000, 2020000000, 0 },
44 };
45
46 static const struct alpha_pll_config video_pll0_config = {
47 .l = 0x39,
48 .alpha = 0x3000,
49 .config_ctl_val = 0x20485699,
50 .config_ctl_hi_val = 0x00182261,
51 .config_ctl_hi1_val = 0x32aa299c,
52 .user_ctl_val = 0x00000000,
53 .user_ctl_hi_val = 0x00400805,
54 };
55
56 static struct clk_alpha_pll video_pll0 = {
57 .offset = 0x0,
58 .vco_table = lucid_evo_vco,
59 .num_vco = ARRAY_SIZE(lucid_evo_vco),
60 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
61 .clkr = {
62 .hw.init = &(const struct clk_init_data) {
63 .name = "video_pll0",
64 .parent_data = &(const struct clk_parent_data) {
65 .index = DT_BI_TCXO,
66 },
67 .num_parents = 1,
68 .ops = &clk_alpha_pll_lucid_evo_ops,
69 },
70 },
71 };
72
73 static const struct alpha_pll_config video_pll1_config = {
74 .l = 0x39,
75 .alpha = 0x3000,
76 .config_ctl_val = 0x20485699,
77 .config_ctl_hi_val = 0x00182261,
78 .config_ctl_hi1_val = 0x32aa299c,
79 .user_ctl_val = 0x00000000,
80 .user_ctl_hi_val = 0x00400805,
81 };
82
83 static struct clk_alpha_pll video_pll1 = {
84 .offset = 0x1000,
85 .vco_table = lucid_evo_vco,
86 .num_vco = ARRAY_SIZE(lucid_evo_vco),
87 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
88 .clkr = {
89 .hw.init = &(const struct clk_init_data) {
90 .name = "video_pll1",
91 .parent_data = &(const struct clk_parent_data) {
92 .index = DT_BI_TCXO,
93 },
94 .num_parents = 1,
95 .ops = &clk_alpha_pll_lucid_evo_ops,
96 },
97 },
98 };
99
100 static const struct parent_map video_cc_parent_map_0_ao[] = {
101 { P_BI_TCXO_AO, 0 },
102 };
103
104 static const struct clk_parent_data video_cc_parent_data_0_ao[] = {
105 { .index = DT_BI_TCXO_AO },
106 };
107
108 static const struct parent_map video_cc_parent_map_1[] = {
109 { P_BI_TCXO, 0 },
110 { P_VIDEO_PLL0_OUT_MAIN, 1 },
111 };
112
113 static const struct clk_parent_data video_cc_parent_data_1[] = {
114 { .index = DT_BI_TCXO },
115 { .hw = &video_pll0.clkr.hw },
116 };
117
118 static const struct parent_map video_cc_parent_map_2[] = {
119 { P_BI_TCXO, 0 },
120 { P_VIDEO_PLL1_OUT_MAIN, 1 },
121 };
122
123 static const struct clk_parent_data video_cc_parent_data_2[] = {
124 { .index = DT_BI_TCXO },
125 { .hw = &video_pll1.clkr.hw },
126 };
127
128 static const struct parent_map video_cc_parent_map_3[] = {
129 { P_SLEEP_CLK, 0 },
130 };
131
132 static const struct clk_parent_data video_cc_parent_data_3[] = {
133 { .index = DT_SLEEP_CLK },
134 };
135
136 static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = {
137 F(19200000, P_BI_TCXO_AO, 1, 0, 0),
138 { }
139 };
140
141 static struct clk_rcg2 video_cc_ahb_clk_src = {
142 .cmd_rcgr = 0x8030,
143 .mnd_width = 0,
144 .hid_width = 5,
145 .parent_map = video_cc_parent_map_0_ao,
146 .freq_tbl = ftbl_video_cc_ahb_clk_src,
147 .clkr.hw.init = &(const struct clk_init_data) {
148 .name = "video_cc_ahb_clk_src",
149 .parent_data = video_cc_parent_data_0_ao,
150 .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao),
151 .flags = CLK_SET_RATE_PARENT,
152 .ops = &clk_rcg2_shared_ops,
153 },
154 };
155
156 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
157 F(1098000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
158 F(1332000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
159 F(1599000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
160 F(1680000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0),
161 { }
162 };
163
164 static struct clk_rcg2 video_cc_mvs0_clk_src = {
165 .cmd_rcgr = 0x8000,
166 .mnd_width = 0,
167 .hid_width = 5,
168 .parent_map = video_cc_parent_map_1,
169 .freq_tbl = ftbl_video_cc_mvs0_clk_src,
170 .clkr.hw.init = &(const struct clk_init_data) {
171 .name = "video_cc_mvs0_clk_src",
172 .parent_data = video_cc_parent_data_1,
173 .num_parents = ARRAY_SIZE(video_cc_parent_data_1),
174 .flags = CLK_SET_RATE_PARENT,
175 .ops = &clk_rcg2_shared_ops,
176 },
177 };
178
179 static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {
180 F(1098000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
181 F(1332000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
182 F(1600000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
183 F(1800000000, P_VIDEO_PLL1_OUT_MAIN, 1, 0, 0),
184 { }
185 };
186
187 static struct clk_rcg2 video_cc_mvs1_clk_src = {
188 .cmd_rcgr = 0x8018,
189 .mnd_width = 0,
190 .hid_width = 5,
191 .parent_map = video_cc_parent_map_2,
192 .freq_tbl = ftbl_video_cc_mvs1_clk_src,
193 .clkr.hw.init = &(const struct clk_init_data) {
194 .name = "video_cc_mvs1_clk_src",
195 .parent_data = video_cc_parent_data_2,
196 .num_parents = ARRAY_SIZE(video_cc_parent_data_2),
197 .flags = CLK_SET_RATE_PARENT,
198 .ops = &clk_rcg2_shared_ops,
199 },
200 };
201
202 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
203 F(32000, P_SLEEP_CLK, 1, 0, 0),
204 { }
205 };
206
207 static struct clk_rcg2 video_cc_sleep_clk_src = {
208 .cmd_rcgr = 0x812c,
209 .mnd_width = 0,
210 .hid_width = 5,
211 .parent_map = video_cc_parent_map_3,
212 .freq_tbl = ftbl_video_cc_sleep_clk_src,
213 .clkr.hw.init = &(const struct clk_init_data) {
214 .name = "video_cc_sleep_clk_src",
215 .parent_data = video_cc_parent_data_3,
216 .num_parents = ARRAY_SIZE(video_cc_parent_data_3),
217 .flags = CLK_SET_RATE_PARENT,
218 .ops = &clk_rcg2_shared_ops,
219 },
220 };
221
222 static struct clk_rcg2 video_cc_xo_clk_src = {
223 .cmd_rcgr = 0x8110,
224 .mnd_width = 0,
225 .hid_width = 5,
226 .parent_map = video_cc_parent_map_0_ao,
227 .freq_tbl = ftbl_video_cc_ahb_clk_src,
228 .clkr.hw.init = &(const struct clk_init_data) {
229 .name = "video_cc_xo_clk_src",
230 .parent_data = video_cc_parent_data_0_ao,
231 .num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao),
232 .flags = CLK_SET_RATE_PARENT,
233 .ops = &clk_rcg2_shared_ops,
234 },
235 };
236
237 static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
238 .reg = 0x80b8,
239 .shift = 0,
240 .width = 4,
241 .clkr.hw.init = &(const struct clk_init_data) {
242 .name = "video_cc_mvs0_div_clk_src",
243 .parent_hws = (const struct clk_hw*[]) {
244 &video_cc_mvs0_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_regmap_div video_cc_mvs0c_div2_div_clk_src = {
253 .reg = 0x806c,
254 .shift = 0,
255 .width = 4,
256 .clkr.hw.init = &(const struct clk_init_data) {
257 .name = "video_cc_mvs0c_div2_div_clk_src",
258 .parent_hws = (const struct clk_hw*[]) {
259 &video_cc_mvs0_clk_src.clkr.hw,
260 },
261 .num_parents = 1,
262 .flags = CLK_SET_RATE_PARENT,
263 .ops = &clk_regmap_div_ro_ops,
264 },
265 };
266
267 static struct clk_regmap_div video_cc_mvs1_div_clk_src = {
268 .reg = 0x80dc,
269 .shift = 0,
270 .width = 4,
271 .clkr.hw.init = &(const struct clk_init_data) {
272 .name = "video_cc_mvs1_div_clk_src",
273 .parent_hws = (const struct clk_hw*[]) {
274 &video_cc_mvs1_clk_src.clkr.hw,
275 },
276 .num_parents = 1,
277 .flags = CLK_SET_RATE_PARENT,
278 .ops = &clk_regmap_div_ro_ops,
279 },
280 };
281
282 static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
283 .reg = 0x8094,
284 .shift = 0,
285 .width = 4,
286 .clkr.hw.init = &(const struct clk_init_data) {
287 .name = "video_cc_mvs1c_div2_div_clk_src",
288 .parent_hws = (const struct clk_hw*[]) {
289 &video_cc_mvs1_clk_src.clkr.hw,
290 },
291 .num_parents = 1,
292 .flags = CLK_SET_RATE_PARENT,
293 .ops = &clk_regmap_div_ro_ops,
294 },
295 };
296
297 static struct clk_regmap_div video_cc_sm_div_clk_src = {
298 .reg = 0x8108,
299 .shift = 0,
300 .width = 4,
301 .clkr.hw.init = &(const struct clk_init_data) {
302 .name = "video_cc_sm_div_clk_src",
303 .ops = &clk_regmap_div_ro_ops,
304 },
305 };
306
307 static struct clk_branch video_cc_mvs0_clk = {
308 .halt_reg = 0x80b0,
309 .halt_check = BRANCH_HALT_VOTED,
310 .hwcg_reg = 0x80b0,
311 .hwcg_bit = 1,
312 .clkr = {
313 .enable_reg = 0x80b0,
314 .enable_mask = BIT(0),
315 .hw.init = &(const struct clk_init_data) {
316 .name = "video_cc_mvs0_clk",
317 .parent_hws = (const struct clk_hw*[]) {
318 &video_cc_mvs0_div_clk_src.clkr.hw,
319 },
320 .num_parents = 1,
321 .flags = CLK_SET_RATE_PARENT,
322 .ops = &clk_branch2_ops,
323 },
324 },
325 };
326
327 static struct clk_branch video_cc_mvs0c_clk = {
328 .halt_reg = 0x8064,
329 .halt_check = BRANCH_HALT,
330 .clkr = {
331 .enable_reg = 0x8064,
332 .enable_mask = BIT(0),
333 .hw.init = &(const struct clk_init_data) {
334 .name = "video_cc_mvs0c_clk",
335 .parent_hws = (const struct clk_hw*[]) {
336 &video_cc_mvs0c_div2_div_clk_src.clkr.hw,
337 },
338 .num_parents = 1,
339 .flags = CLK_SET_RATE_PARENT,
340 .ops = &clk_branch2_ops,
341 },
342 },
343 };
344
345 static struct clk_branch video_cc_mvs1_clk = {
346 .halt_reg = 0x80d4,
347 .halt_check = BRANCH_HALT_VOTED,
348 .hwcg_reg = 0x80d4,
349 .hwcg_bit = 1,
350 .clkr = {
351 .enable_reg = 0x80d4,
352 .enable_mask = BIT(0),
353 .hw.init = &(const struct clk_init_data) {
354 .name = "video_cc_mvs1_clk",
355 .parent_hws = (const struct clk_hw*[]) {
356 &video_cc_mvs1_div_clk_src.clkr.hw,
357 },
358 .num_parents = 1,
359 .flags = CLK_SET_RATE_PARENT,
360 .ops = &clk_branch2_ops,
361 },
362 },
363 };
364
365 static struct clk_branch video_cc_mvs1c_clk = {
366 .halt_reg = 0x808c,
367 .halt_check = BRANCH_HALT,
368 .clkr = {
369 .enable_reg = 0x808c,
370 .enable_mask = BIT(0),
371 .hw.init = &(const struct clk_init_data) {
372 .name = "video_cc_mvs1c_clk",
373 .parent_hws = (const struct clk_hw*[]) {
374 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,
375 },
376 .num_parents = 1,
377 .flags = CLK_SET_RATE_PARENT,
378 .ops = &clk_branch2_ops,
379 },
380 },
381 };
382
383 static struct clk_branch video_cc_pll_lock_monitor_clk = {
384 .halt_reg = 0x9000,
385 .halt_check = BRANCH_HALT,
386 .clkr = {
387 .enable_reg = 0x9000,
388 .enable_mask = BIT(0),
389 .hw.init = &(const struct clk_init_data) {
390 .name = "video_cc_pll_lock_monitor_clk",
391 .parent_hws = (const struct clk_hw*[]) {
392 &video_cc_xo_clk_src.clkr.hw,
393 },
394 .num_parents = 1,
395 .flags = CLK_SET_RATE_PARENT,
396 .ops = &clk_branch2_ops,
397 },
398 },
399 };
400
401 static struct clk_branch video_cc_sm_obs_clk = {
402 .halt_reg = 0x810c,
403 .halt_check = BRANCH_HALT_SKIP,
404 .clkr = {
405 .enable_reg = 0x810c,
406 .enable_mask = BIT(0),
407 .hw.init = &(const struct clk_init_data) {
408 .name = "video_cc_sm_obs_clk",
409 .parent_hws = (const struct clk_hw*[]) {
410 &video_cc_sm_div_clk_src.clkr.hw,
411 },
412 .num_parents = 1,
413 .flags = CLK_SET_RATE_PARENT,
414 .ops = &clk_branch2_ops,
415 },
416 },
417 };
418
419 static struct gdsc video_cc_mvs0c_gdsc = {
420 .gdscr = 0x804c,
421 .en_rest_wait_val = 0x2,
422 .en_few_wait_val = 0x2,
423 .clk_dis_wait_val = 0x6,
424 .pd = {
425 .name = "video_cc_mvs0c_gdsc",
426 },
427 .pwrsts = PWRSTS_OFF_ON,
428 .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR,
429 };
430
431 static struct gdsc video_cc_mvs0_gdsc = {
432 .gdscr = 0x809c,
433 .en_rest_wait_val = 0x2,
434 .en_few_wait_val = 0x2,
435 .clk_dis_wait_val = 0x6,
436 .pd = {
437 .name = "video_cc_mvs0_gdsc",
438 },
439 .pwrsts = PWRSTS_OFF_ON,
440 .parent = &video_cc_mvs0c_gdsc.pd,
441 .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR | HW_CTRL_TRIGGER,
442 };
443
444 static struct gdsc video_cc_mvs1c_gdsc = {
445 .gdscr = 0x8074,
446 .en_rest_wait_val = 0x2,
447 .en_few_wait_val = 0x2,
448 .clk_dis_wait_val = 0x6,
449 .pd = {
450 .name = "video_cc_mvs1c_gdsc",
451 },
452 .pwrsts = PWRSTS_OFF_ON,
453 .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR,
454 };
455
456 static struct gdsc video_cc_mvs1_gdsc = {
457 .gdscr = 0x80c0,
458 .en_rest_wait_val = 0x2,
459 .en_few_wait_val = 0x2,
460 .clk_dis_wait_val = 0x6,
461 .pd = {
462 .name = "video_cc_mvs1_gdsc",
463 },
464 .pwrsts = PWRSTS_OFF_ON,
465 .parent = &video_cc_mvs1c_gdsc.pd,
466 .flags = RETAIN_FF_ENABLE | POLL_CFG_GDSCR | HW_CTRL_TRIGGER,
467 };
468
469 static struct clk_regmap *video_cc_sa8775p_clocks[] = {
470 [VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr,
471 [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
472 [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
473 [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
474 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
475 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
476 [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr,
477 [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,
478 [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr,
479 [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,
480 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,
481 [VIDEO_CC_PLL_LOCK_MONITOR_CLK] = &video_cc_pll_lock_monitor_clk.clkr,
482 [VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
483 [VIDEO_CC_SM_DIV_CLK_SRC] = &video_cc_sm_div_clk_src.clkr,
484 [VIDEO_CC_SM_OBS_CLK] = &video_cc_sm_obs_clk.clkr,
485 [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,
486 [VIDEO_PLL0] = &video_pll0.clkr,
487 [VIDEO_PLL1] = &video_pll1.clkr,
488 };
489
490 static struct gdsc *video_cc_sa8775p_gdscs[] = {
491 [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
492 [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
493 [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc,
494 [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc,
495 };
496
497 static const struct qcom_reset_map video_cc_sa8775p_resets[] = {
498 [VIDEO_CC_INTERFACE_BCR] = { 0x80e8 },
499 [VIDEO_CC_MVS0_BCR] = { 0x8098 },
500 [VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 },
501 [VIDEO_CC_MVS0C_BCR] = { 0x8048 },
502 [VIDEO_CC_MVS1_BCR] = { 0x80bc },
503 [VIDEO_CC_MVS1C_CLK_ARES] = { 0x808c, 2 },
504 [VIDEO_CC_MVS1C_BCR] = { 0x8070 },
505 };
506
507 static const struct regmap_config video_cc_sa8775p_regmap_config = {
508 .reg_bits = 32,
509 .reg_stride = 4,
510 .val_bits = 32,
511 .max_register = 0xb000,
512 .fast_io = true,
513 };
514
515 static struct qcom_cc_desc video_cc_sa8775p_desc = {
516 .config = &video_cc_sa8775p_regmap_config,
517 .clks = video_cc_sa8775p_clocks,
518 .num_clks = ARRAY_SIZE(video_cc_sa8775p_clocks),
519 .resets = video_cc_sa8775p_resets,
520 .num_resets = ARRAY_SIZE(video_cc_sa8775p_resets),
521 .gdscs = video_cc_sa8775p_gdscs,
522 .num_gdscs = ARRAY_SIZE(video_cc_sa8775p_gdscs),
523 };
524
525 static const struct of_device_id video_cc_sa8775p_match_table[] = {
526 { .compatible = "qcom,sa8775p-videocc" },
527 { }
528 };
529 MODULE_DEVICE_TABLE(of, video_cc_sa8775p_match_table);
530
video_cc_sa8775p_probe(struct platform_device * pdev)531 static int video_cc_sa8775p_probe(struct platform_device *pdev)
532 {
533 struct regmap *regmap;
534 int ret;
535
536 ret = devm_pm_runtime_enable(&pdev->dev);
537 if (ret)
538 return ret;
539
540 ret = pm_runtime_resume_and_get(&pdev->dev);
541 if (ret)
542 return ret;
543
544 regmap = qcom_cc_map(pdev, &video_cc_sa8775p_desc);
545 if (IS_ERR(regmap)) {
546 pm_runtime_put(&pdev->dev);
547 return PTR_ERR(regmap);
548 }
549
550 clk_lucid_evo_pll_configure(&video_pll0, regmap, &video_pll0_config);
551 clk_lucid_evo_pll_configure(&video_pll1, regmap, &video_pll1_config);
552
553 /* Keep some clocks always enabled */
554 qcom_branch_set_clk_en(regmap, 0x80ec); /* VIDEO_CC_AHB_CLK */
555 qcom_branch_set_clk_en(regmap, 0x8144); /* VIDEO_CC_SLEEP_CLK */
556 qcom_branch_set_clk_en(regmap, 0x8128); /* VIDEO_CC_XO_CLK */
557
558 ret = qcom_cc_really_probe(&pdev->dev, &video_cc_sa8775p_desc, regmap);
559
560 pm_runtime_put(&pdev->dev);
561
562 return ret;
563 }
564
565 static struct platform_driver video_cc_sa8775p_driver = {
566 .probe = video_cc_sa8775p_probe,
567 .driver = {
568 .name = "videocc-sa8775p",
569 .of_match_table = video_cc_sa8775p_match_table,
570 },
571 };
572
573 module_platform_driver(video_cc_sa8775p_driver);
574
575 MODULE_DESCRIPTION("QTI VIDEOCC SA8775P Driver");
576 MODULE_LICENSE("GPL");
577