Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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/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
23enum {
24 DT_BI_TCXO,
25};
26
27enum {
28 P_BI_TCXO,
29 P_VIDEO_CC_PLL0_OUT_MAIN,
30 P_VIDEO_CC_PLL1_OUT_MAIN,
31};
32
33static const struct pll_vco lucid_evo_vco[] = {
34 { 249600000, 2020000000, 0 },
35};
36
37static const struct alpha_pll_config video_cc_pll0_config = {
38 /* .l includes CAL_L_VAL, L_VAL fields */
39 .l = 0x0044001e,
40 .alpha = 0x0,
41 .config_ctl_val = 0x20485699,
42 .config_ctl_hi_val = 0x00182261,
43 .config_ctl_hi1_val = 0x32aa299c,
44 .user_ctl_val = 0x00000000,
45 .user_ctl_hi_val = 0x00000805,
46};
47
48static const struct alpha_pll_config sm8475_video_cc_pll0_config = {
49 /* .l includes CAL_L_VAL, L_VAL fields */
50 .l = 0x1e,
51 .alpha = 0x0,
52 .config_ctl_val = 0x20485699,
53 .config_ctl_hi_val = 0x00182261,
54 .config_ctl_hi1_val = 0x82aa299c,
55 .test_ctl_val = 0x00000000,
56 .test_ctl_hi_val = 0x00000003,
57 .test_ctl_hi1_val = 0x00009000,
58 .test_ctl_hi2_val = 0x00000034,
59 .user_ctl_val = 0x00000000,
60 .user_ctl_hi_val = 0x00000005,
61};
62
63static struct clk_alpha_pll video_cc_pll0 = {
64 .offset = 0x0,
65 .config = &video_cc_pll0_config,
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
81static 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
92static 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
107static struct clk_alpha_pll video_cc_pll1 = {
108 .offset = 0x1000,
109 .config = &video_cc_pll1_config,
110 .vco_table = lucid_evo_vco,
111 .num_vco = ARRAY_SIZE(lucid_evo_vco),
112 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
113 .clkr = {
114 .hw.init = &(const struct clk_init_data) {
115 .name = "video_cc_pll1",
116 .parent_data = &(const struct clk_parent_data) {
117 .index = DT_BI_TCXO,
118 },
119 .num_parents = 1,
120 .ops = &clk_alpha_pll_lucid_evo_ops,
121 },
122 },
123};
124
125static const struct parent_map video_cc_parent_map_0[] = {
126 { P_BI_TCXO, 0 },
127 { P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
128};
129
130static const struct clk_parent_data video_cc_parent_data_0[] = {
131 { .index = DT_BI_TCXO },
132 { .hw = &video_cc_pll0.clkr.hw },
133};
134
135static const struct parent_map video_cc_parent_map_1[] = {
136 { P_BI_TCXO, 0 },
137 { P_VIDEO_CC_PLL1_OUT_MAIN, 1 },
138};
139
140static const struct clk_parent_data video_cc_parent_data_1[] = {
141 { .index = DT_BI_TCXO },
142 { .hw = &video_cc_pll1.clkr.hw },
143};
144
145static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
146 F(576000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
147 F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
148 F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
149 F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
150 F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
151 { }
152};
153
154static struct clk_rcg2 video_cc_mvs0_clk_src = {
155 .cmd_rcgr = 0x8000,
156 .mnd_width = 0,
157 .hid_width = 5,
158 .parent_map = video_cc_parent_map_0,
159 .freq_tbl = ftbl_video_cc_mvs0_clk_src,
160 .clkr.hw.init = &(const struct clk_init_data) {
161 .name = "video_cc_mvs0_clk_src",
162 .parent_data = video_cc_parent_data_0,
163 .num_parents = ARRAY_SIZE(video_cc_parent_data_0),
164 .flags = CLK_SET_RATE_PARENT,
165 .ops = &clk_rcg2_shared_ops,
166 },
167};
168
169static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {
170 F(840000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
171 F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
172 F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
173 F(1500000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
174 F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
175 { }
176};
177
178static struct clk_rcg2 video_cc_mvs1_clk_src = {
179 .cmd_rcgr = 0x8018,
180 .mnd_width = 0,
181 .hid_width = 5,
182 .parent_map = video_cc_parent_map_1,
183 .freq_tbl = ftbl_video_cc_mvs1_clk_src,
184 .clkr.hw.init = &(const struct clk_init_data) {
185 .name = "video_cc_mvs1_clk_src",
186 .parent_data = video_cc_parent_data_1,
187 .num_parents = ARRAY_SIZE(video_cc_parent_data_1),
188 .flags = CLK_SET_RATE_PARENT,
189 .ops = &clk_rcg2_shared_ops,
190 },
191};
192
193static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
194 .reg = 0x80b8,
195 .shift = 0,
196 .width = 4,
197 .clkr.hw.init = &(const struct clk_init_data) {
198 .name = "video_cc_mvs0_div_clk_src",
199 .parent_hws = (const struct clk_hw*[]) {
200 &video_cc_mvs0_clk_src.clkr.hw,
201 },
202 .num_parents = 1,
203 .flags = CLK_SET_RATE_PARENT,
204 .ops = &clk_regmap_div_ro_ops,
205 },
206};
207
208static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
209 .reg = 0x806c,
210 .shift = 0,
211 .width = 4,
212 .clkr.hw.init = &(const struct clk_init_data) {
213 .name = "video_cc_mvs0c_div2_div_clk_src",
214 .parent_hws = (const struct clk_hw*[]) {
215 &video_cc_mvs0_clk_src.clkr.hw,
216 },
217 .num_parents = 1,
218 .flags = CLK_SET_RATE_PARENT,
219 .ops = &clk_regmap_div_ro_ops,
220 },
221};
222
223static struct clk_regmap_div video_cc_mvs1_div_clk_src = {
224 .reg = 0x80dc,
225 .shift = 0,
226 .width = 4,
227 .clkr.hw.init = &(const struct clk_init_data) {
228 .name = "video_cc_mvs1_div_clk_src",
229 .parent_hws = (const struct clk_hw*[]) {
230 &video_cc_mvs1_clk_src.clkr.hw,
231 },
232 .num_parents = 1,
233 .flags = CLK_SET_RATE_PARENT,
234 .ops = &clk_regmap_div_ro_ops,
235 },
236};
237
238static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
239 .reg = 0x8094,
240 .shift = 0,
241 .width = 4,
242 .clkr.hw.init = &(const struct clk_init_data) {
243 .name = "video_cc_mvs1c_div2_div_clk_src",
244 .parent_hws = (const struct clk_hw*[]) {
245 &video_cc_mvs1_clk_src.clkr.hw,
246 },
247 .num_parents = 1,
248 .flags = CLK_SET_RATE_PARENT,
249 .ops = &clk_regmap_div_ro_ops,
250 },
251};
252
253static struct clk_branch video_cc_mvs0_clk = {
254 .halt_reg = 0x80b0,
255 .halt_check = BRANCH_HALT_SKIP,
256 .hwcg_reg = 0x80b0,
257 .hwcg_bit = 1,
258 .clkr = {
259 .enable_reg = 0x80b0,
260 .enable_mask = BIT(0),
261 .hw.init = &(const struct clk_init_data) {
262 .name = "video_cc_mvs0_clk",
263 .parent_hws = (const struct clk_hw*[]) {
264 &video_cc_mvs0_div_clk_src.clkr.hw,
265 },
266 .num_parents = 1,
267 .flags = CLK_SET_RATE_PARENT,
268 .ops = &clk_branch2_ops,
269 },
270 },
271};
272
273static struct clk_branch video_cc_mvs0c_clk = {
274 .halt_reg = 0x8064,
275 .halt_check = BRANCH_HALT,
276 .clkr = {
277 .enable_reg = 0x8064,
278 .enable_mask = BIT(0),
279 .hw.init = &(const struct clk_init_data) {
280 .name = "video_cc_mvs0c_clk",
281 .parent_hws = (const struct clk_hw*[]) {
282 &video_cc_mvs0c_div2_div_clk_src.clkr.hw,
283 },
284 .num_parents = 1,
285 .flags = CLK_SET_RATE_PARENT,
286 .ops = &clk_branch2_ops,
287 },
288 },
289};
290
291static struct clk_branch video_cc_mvs1_clk = {
292 .halt_reg = 0x80d4,
293 .halt_check = BRANCH_HALT_SKIP,
294 .hwcg_reg = 0x80d4,
295 .hwcg_bit = 1,
296 .clkr = {
297 .enable_reg = 0x80d4,
298 .enable_mask = BIT(0),
299 .hw.init = &(const struct clk_init_data) {
300 .name = "video_cc_mvs1_clk",
301 .parent_hws = (const struct clk_hw*[]) {
302 &video_cc_mvs1_div_clk_src.clkr.hw,
303 },
304 .num_parents = 1,
305 .flags = CLK_SET_RATE_PARENT,
306 .ops = &clk_branch2_ops,
307 },
308 },
309};
310
311static struct clk_branch video_cc_mvs1c_clk = {
312 .halt_reg = 0x808c,
313 .halt_check = BRANCH_HALT,
314 .clkr = {
315 .enable_reg = 0x808c,
316 .enable_mask = BIT(0),
317 .hw.init = &(const struct clk_init_data) {
318 .name = "video_cc_mvs1c_clk",
319 .parent_hws = (const struct clk_hw*[]) {
320 &video_cc_mvs1c_div2_div_clk_src.clkr.hw,
321 },
322 .num_parents = 1,
323 .flags = CLK_SET_RATE_PARENT,
324 .ops = &clk_branch2_ops,
325 },
326 },
327};
328
329static struct gdsc video_cc_mvs0c_gdsc = {
330 .gdscr = 0x804c,
331 .en_rest_wait_val = 0x2,
332 .en_few_wait_val = 0x2,
333 .clk_dis_wait_val = 0x6,
334 .pd = {
335 .name = "video_cc_mvs0c_gdsc",
336 },
337 .pwrsts = PWRSTS_OFF_ON,
338 .flags = RETAIN_FF_ENABLE,
339};
340
341static struct gdsc video_cc_mvs0_gdsc = {
342 .gdscr = 0x809c,
343 .en_rest_wait_val = 0x2,
344 .en_few_wait_val = 0x2,
345 .clk_dis_wait_val = 0x6,
346 .pd = {
347 .name = "video_cc_mvs0_gdsc",
348 },
349 .pwrsts = PWRSTS_OFF_ON,
350 .parent = &video_cc_mvs0c_gdsc.pd,
351 .flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
352};
353
354static struct gdsc video_cc_mvs1c_gdsc = {
355 .gdscr = 0x8074,
356 .en_rest_wait_val = 0x2,
357 .en_few_wait_val = 0x2,
358 .clk_dis_wait_val = 0x6,
359 .pd = {
360 .name = "video_cc_mvs1c_gdsc",
361 },
362 .pwrsts = PWRSTS_OFF_ON,
363 .flags = RETAIN_FF_ENABLE,
364};
365
366static struct gdsc video_cc_mvs1_gdsc = {
367 .gdscr = 0x80c0,
368 .en_rest_wait_val = 0x2,
369 .en_few_wait_val = 0x2,
370 .clk_dis_wait_val = 0x6,
371 .pd = {
372 .name = "video_cc_mvs1_gdsc",
373 },
374 .pwrsts = PWRSTS_OFF_ON,
375 .parent = &video_cc_mvs1c_gdsc.pd,
376 .flags = HW_CTRL_TRIGGER | RETAIN_FF_ENABLE,
377};
378
379static struct clk_regmap *video_cc_sm8450_clocks[] = {
380 [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
381 [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
382 [VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
383 [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
384 [VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
385 [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr,
386 [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,
387 [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr,
388 [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,
389 [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,
390 [VIDEO_CC_PLL0] = &video_cc_pll0.clkr,
391 [VIDEO_CC_PLL1] = &video_cc_pll1.clkr,
392};
393
394static struct gdsc *video_cc_sm8450_gdscs[] = {
395 [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
396 [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
397 [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc,
398 [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc,
399};
400
401static const struct qcom_reset_map video_cc_sm8450_resets[] = {
402 [CVP_VIDEO_CC_INTERFACE_BCR] = { 0x80e0 },
403 [CVP_VIDEO_CC_MVS0_BCR] = { 0x8098 },
404 [CVP_VIDEO_CC_MVS0C_BCR] = { 0x8048 },
405 [CVP_VIDEO_CC_MVS1_BCR] = { 0x80bc },
406 [CVP_VIDEO_CC_MVS1C_BCR] = { 0x8070 },
407 [VIDEO_CC_MVS0C_CLK_ARES] = { .reg = 0x8064, .bit = 2, .udelay = 1000 },
408 [VIDEO_CC_MVS1C_CLK_ARES] = { .reg = 0x808c, .bit = 2, .udelay = 1000 },
409};
410
411static struct clk_alpha_pll *video_cc_sm8450_plls[] = {
412 &video_cc_pll0,
413 &video_cc_pll1,
414};
415
416static u32 video_cc_sm8450_critical_cbcrs[] = {
417 0x80e4, /* VIDEO_CC_AHB_CLK */
418 0x8114, /* VIDEO_CC_XO_CLK */
419 0x8130, /* VIDEO_CC_SLEEP_CLK */
420};
421
422static const struct regmap_config video_cc_sm8450_regmap_config = {
423 .reg_bits = 32,
424 .reg_stride = 4,
425 .val_bits = 32,
426 .max_register = 0x9f4c,
427 .fast_io = true,
428};
429
430static struct qcom_cc_driver_data video_cc_sm8450_driver_data = {
431 .alpha_plls = video_cc_sm8450_plls,
432 .num_alpha_plls = ARRAY_SIZE(video_cc_sm8450_plls),
433 .clk_cbcrs = video_cc_sm8450_critical_cbcrs,
434 .num_clk_cbcrs = ARRAY_SIZE(video_cc_sm8450_critical_cbcrs),
435};
436
437static const struct qcom_cc_desc video_cc_sm8450_desc = {
438 .config = &video_cc_sm8450_regmap_config,
439 .clks = video_cc_sm8450_clocks,
440 .num_clks = ARRAY_SIZE(video_cc_sm8450_clocks),
441 .resets = video_cc_sm8450_resets,
442 .num_resets = ARRAY_SIZE(video_cc_sm8450_resets),
443 .gdscs = video_cc_sm8450_gdscs,
444 .num_gdscs = ARRAY_SIZE(video_cc_sm8450_gdscs),
445 .use_rpm = true,
446 .driver_data = &video_cc_sm8450_driver_data,
447};
448
449static const struct of_device_id video_cc_sm8450_match_table[] = {
450 { .compatible = "qcom,sm8450-videocc" },
451 { .compatible = "qcom,sm8475-videocc" },
452 { }
453};
454MODULE_DEVICE_TABLE(of, video_cc_sm8450_match_table);
455
456static int video_cc_sm8450_probe(struct platform_device *pdev)
457{
458 if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8475-videocc")) {
459 /* Update VideoCC PLL0 */
460 video_cc_pll0.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
461
462 /* Update VideoCC PLL1 */
463 video_cc_pll1.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE];
464
465 video_cc_pll0.config = &sm8475_video_cc_pll0_config;
466 video_cc_pll1.config = &sm8475_video_cc_pll1_config;
467 }
468
469 return qcom_cc_probe(pdev, &video_cc_sm8450_desc);
470}
471
472static struct platform_driver video_cc_sm8450_driver = {
473 .probe = video_cc_sm8450_probe,
474 .driver = {
475 .name = "video_cc-sm8450",
476 .of_match_table = video_cc_sm8450_match_table,
477 },
478};
479
480module_platform_driver(video_cc_sm8450_driver);
481
482MODULE_DESCRIPTION("QTI VIDEOCC SM8450 / SM8475 Driver");
483MODULE_LICENSE("GPL");