xref: /linux/drivers/clk/qcom/videocc-sm8450.c (revision 7f4f3b14e8079ecde096bd734af10e30d40c27b7)
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 
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