xref: /linux/drivers/clk/qcom/videocc-sm8750.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
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,sm8750-videocc.h>
14 
15 #include "clk-alpha-pll.h"
16 #include "clk-branch.h"
17 #include "clk-pll.h"
18 #include "clk-rcg.h"
19 #include "clk-regmap.h"
20 #include "clk-regmap-divider.h"
21 #include "clk-regmap-mux.h"
22 #include "common.h"
23 #include "gdsc.h"
24 #include "reset.h"
25 
26 enum {
27 	DT_BI_TCXO,
28 	DT_BI_TCXO_AO,
29 	DT_SLEEP_CLK,
30 };
31 
32 enum {
33 	P_BI_TCXO,
34 	P_SLEEP_CLK,
35 	P_VIDEO_CC_PLL0_OUT_MAIN,
36 };
37 
38 static const struct pll_vco taycan_elu_vco[] = {
39 	{ 249600000, 2500000000, 0 },
40 };
41 
42 static const struct alpha_pll_config video_cc_pll0_config = {
43 	.l = 0x25,
44 	.alpha = 0x8000,
45 	.config_ctl_val = 0x19660387,
46 	.config_ctl_hi_val = 0x098060a0,
47 	.config_ctl_hi1_val = 0xb416cb20,
48 	.user_ctl_val = 0x00000000,
49 	.user_ctl_hi_val = 0x00000002,
50 };
51 
52 static struct clk_alpha_pll video_cc_pll0 = {
53 	.offset = 0x0,
54 	.config = &video_cc_pll0_config,
55 	.vco_table = taycan_elu_vco,
56 	.num_vco = ARRAY_SIZE(taycan_elu_vco),
57 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
58 	.clkr = {
59 		.hw.init = &(const struct clk_init_data) {
60 			.name = "video_cc_pll0",
61 			.parent_data = &(const struct clk_parent_data) {
62 				.index = DT_BI_TCXO,
63 			},
64 			.num_parents = 1,
65 			.ops = &clk_alpha_pll_taycan_elu_ops,
66 		},
67 	},
68 };
69 
70 static const struct parent_map video_cc_parent_map_0[] = {
71 	{ P_BI_TCXO, 0 },
72 };
73 
74 static const struct clk_parent_data video_cc_parent_data_0_ao[] = {
75 	{ .index = DT_BI_TCXO_AO },
76 };
77 
78 static const struct parent_map video_cc_parent_map_1[] = {
79 	{ P_BI_TCXO, 0 },
80 	{ P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
81 };
82 
83 static const struct clk_parent_data video_cc_parent_data_1[] = {
84 	{ .index = DT_BI_TCXO },
85 	{ .hw = &video_cc_pll0.clkr.hw },
86 };
87 
88 static const struct parent_map video_cc_parent_map_2[] = {
89 	{ P_SLEEP_CLK, 0 },
90 };
91 
92 static const struct clk_parent_data video_cc_parent_data_2_ao[] = {
93 	{ .index = DT_SLEEP_CLK },
94 };
95 
96 static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = {
97 	F(19200000, P_BI_TCXO, 1, 0, 0),
98 	{ }
99 };
100 
101 static struct clk_rcg2 video_cc_ahb_clk_src = {
102 	.cmd_rcgr = 0x8018,
103 	.mnd_width = 0,
104 	.hid_width = 5,
105 	.parent_map = video_cc_parent_map_0,
106 	.freq_tbl = ftbl_video_cc_ahb_clk_src,
107 	.clkr.hw.init = &(const struct clk_init_data) {
108 		.name = "video_cc_ahb_clk_src",
109 		.parent_data = video_cc_parent_data_0_ao,
110 		.num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao),
111 		.flags = CLK_SET_RATE_PARENT,
112 		.ops = &clk_rcg2_ops,
113 	},
114 };
115 
116 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
117 	F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
118 	F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
119 	F(1260000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
120 	F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
121 	F(1600000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
122 	F(1710000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
123 	F(1890000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
124 	{ }
125 };
126 
127 static struct clk_rcg2 video_cc_mvs0_clk_src = {
128 	.cmd_rcgr = 0x8000,
129 	.mnd_width = 0,
130 	.hid_width = 5,
131 	.parent_map = video_cc_parent_map_1,
132 	.freq_tbl = ftbl_video_cc_mvs0_clk_src,
133 	.clkr.hw.init = &(const struct clk_init_data) {
134 		.name = "video_cc_mvs0_clk_src",
135 		.parent_data = video_cc_parent_data_1,
136 		.num_parents = ARRAY_SIZE(video_cc_parent_data_1),
137 		.flags = CLK_SET_RATE_PARENT,
138 		.ops = &clk_rcg2_shared_ops,
139 	},
140 };
141 
142 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
143 	F(32000, P_SLEEP_CLK, 1, 0, 0),
144 	{ }
145 };
146 
147 static struct clk_rcg2 video_cc_sleep_clk_src = {
148 	.cmd_rcgr = 0x80e0,
149 	.mnd_width = 0,
150 	.hid_width = 5,
151 	.parent_map = video_cc_parent_map_2,
152 	.freq_tbl = ftbl_video_cc_sleep_clk_src,
153 	.clkr.hw.init = &(const struct clk_init_data) {
154 		.name = "video_cc_sleep_clk_src",
155 		.parent_data = video_cc_parent_data_2_ao,
156 		.num_parents = ARRAY_SIZE(video_cc_parent_data_2_ao),
157 		.flags = CLK_SET_RATE_PARENT,
158 		.ops = &clk_rcg2_ops,
159 	},
160 };
161 
162 static struct clk_rcg2 video_cc_xo_clk_src = {
163 	.cmd_rcgr = 0x80bc,
164 	.mnd_width = 0,
165 	.hid_width = 5,
166 	.parent_map = video_cc_parent_map_0,
167 	.freq_tbl = ftbl_video_cc_ahb_clk_src,
168 	.clkr.hw.init = &(const struct clk_init_data) {
169 		.name = "video_cc_xo_clk_src",
170 		.parent_data = video_cc_parent_data_0_ao,
171 		.num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao),
172 		.flags = CLK_SET_RATE_PARENT,
173 		.ops = &clk_rcg2_ops,
174 	},
175 };
176 
177 static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
178 	.reg = 0x809c,
179 	.shift = 0,
180 	.width = 4,
181 	.clkr.hw.init = &(const struct clk_init_data) {
182 		.name = "video_cc_mvs0_div_clk_src",
183 		.parent_hws = (const struct clk_hw*[]) {
184 			&video_cc_mvs0_clk_src.clkr.hw,
185 		},
186 		.num_parents = 1,
187 		.flags = CLK_SET_RATE_PARENT,
188 		.ops = &clk_regmap_div_ro_ops,
189 	},
190 };
191 
192 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
193 	.reg = 0x8060,
194 	.shift = 0,
195 	.width = 4,
196 	.clkr.hw.init = &(const struct clk_init_data) {
197 		.name = "video_cc_mvs0c_div2_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_branch video_cc_mvs0_clk = {
208 	.halt_reg = 0x807c,
209 	.halt_check = BRANCH_HALT_VOTED,
210 	.hwcg_reg = 0x807c,
211 	.hwcg_bit = 1,
212 	.clkr = {
213 		.enable_reg = 0x807c,
214 		.enable_mask = BIT(0),
215 		.hw.init = &(const struct clk_init_data) {
216 			.name = "video_cc_mvs0_clk",
217 			.parent_hws = (const struct clk_hw*[]) {
218 				&video_cc_mvs0_div_clk_src.clkr.hw,
219 			},
220 			.num_parents = 1,
221 			.flags = CLK_SET_RATE_PARENT,
222 			.ops = &clk_branch2_ops,
223 		},
224 	},
225 };
226 
227 static struct clk_mem_branch video_cc_mvs0_freerun_clk = {
228 	.mem_enable_reg = 0x8090,
229 	.mem_ack_reg =  0x8090,
230 	.mem_enable_mask = BIT(3),
231 	.mem_enable_ack_mask = GENMASK(11, 10),
232 	.mem_enable_invert = true,
233 	.branch = {
234 		.halt_reg = 0x808c,
235 		.halt_check = BRANCH_HALT,
236 		.clkr = {
237 			.enable_reg = 0x808c,
238 			.enable_mask = BIT(0),
239 			.hw.init = &(const struct clk_init_data) {
240 				.name = "video_cc_mvs0_freerun_clk",
241 				.parent_hws = (const struct clk_hw*[]) {
242 					&video_cc_mvs0_div_clk_src.clkr.hw,
243 				},
244 				.num_parents = 1,
245 				.flags = CLK_SET_RATE_PARENT,
246 				.ops = &clk_branch2_mem_ops,
247 			},
248 		},
249 	},
250 };
251 
252 static struct clk_branch video_cc_mvs0_shift_clk = {
253 	.halt_reg = 0x80d8,
254 	.halt_check = BRANCH_HALT_VOTED,
255 	.hwcg_reg = 0x80d8,
256 	.hwcg_bit = 1,
257 	.clkr = {
258 		.enable_reg = 0x80d8,
259 		.enable_mask = BIT(0),
260 		.hw.init = &(const struct clk_init_data) {
261 			.name = "video_cc_mvs0_shift_clk",
262 			.parent_hws = (const struct clk_hw*[]) {
263 				&video_cc_xo_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 = 0x804c,
274 	.halt_check = BRANCH_HALT,
275 	.clkr = {
276 		.enable_reg = 0x804c,
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_mvs0c_freerun_clk = {
291 	.halt_reg = 0x805c,
292 	.halt_check = BRANCH_HALT,
293 	.clkr = {
294 		.enable_reg = 0x805c,
295 		.enable_mask = BIT(0),
296 		.hw.init = &(const struct clk_init_data) {
297 			.name = "video_cc_mvs0c_freerun_clk",
298 			.parent_hws = (const struct clk_hw*[]) {
299 				&video_cc_mvs0c_div2_div_clk_src.clkr.hw,
300 			},
301 			.num_parents = 1,
302 			.flags = CLK_SET_RATE_PARENT,
303 			.ops = &clk_branch2_ops,
304 		},
305 	},
306 };
307 
308 static struct clk_branch video_cc_mvs0c_shift_clk = {
309 	.halt_reg = 0x80dc,
310 	.halt_check = BRANCH_HALT_VOTED,
311 	.hwcg_reg = 0x80dc,
312 	.hwcg_bit = 1,
313 	.clkr = {
314 		.enable_reg = 0x80dc,
315 		.enable_mask = BIT(0),
316 		.hw.init = &(const struct clk_init_data) {
317 			.name = "video_cc_mvs0c_shift_clk",
318 			.parent_hws = (const struct clk_hw*[]) {
319 				&video_cc_xo_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 = 0x8034,
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 = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
338 };
339 
340 static struct gdsc video_cc_mvs0_gdsc = {
341 	.gdscr = 0x8068,
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 = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL_TRIGGER,
351 };
352 
353 static struct clk_regmap *video_cc_sm8750_clocks[] = {
354 	[VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr,
355 	[VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
356 	[VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
357 	[VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
358 	[VIDEO_CC_MVS0_FREERUN_CLK] = &video_cc_mvs0_freerun_clk.branch.clkr,
359 	[VIDEO_CC_MVS0_SHIFT_CLK] = &video_cc_mvs0_shift_clk.clkr,
360 	[VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
361 	[VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
362 	[VIDEO_CC_MVS0C_FREERUN_CLK] = &video_cc_mvs0c_freerun_clk.clkr,
363 	[VIDEO_CC_MVS0C_SHIFT_CLK] = &video_cc_mvs0c_shift_clk.clkr,
364 	[VIDEO_CC_PLL0] = &video_cc_pll0.clkr,
365 	[VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
366 	[VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,
367 };
368 
369 static struct gdsc *video_cc_sm8750_gdscs[] = {
370 	[VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
371 	[VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
372 };
373 
374 static const struct qcom_reset_map video_cc_sm8750_resets[] = {
375 	[VIDEO_CC_INTERFACE_BCR] = { 0x80a0 },
376 	[VIDEO_CC_MVS0_BCR] = { 0x8064 },
377 	[VIDEO_CC_MVS0C_CLK_ARES] = { 0x804c, 2 },
378 	[VIDEO_CC_MVS0C_BCR] = { 0x8030 },
379 	[VIDEO_CC_MVS0_FREERUN_CLK_ARES] = { 0x808c, 2 },
380 	[VIDEO_CC_MVS0C_FREERUN_CLK_ARES] = { 0x805c, 2 },
381 	[VIDEO_CC_XO_CLK_ARES] = { 0x80d4, 2 },
382 };
383 
384 static const struct regmap_config video_cc_sm8750_regmap_config = {
385 	.reg_bits = 32,
386 	.reg_stride = 4,
387 	.val_bits = 32,
388 	.max_register = 0x9f4c,
389 	.fast_io = true,
390 };
391 
392 static struct clk_alpha_pll *video_cc_sm8750_plls[] = {
393 	&video_cc_pll0,
394 };
395 
396 static u32 video_cc_sm8750_critical_cbcrs[] = {
397 	0x80a4, /* VIDEO_CC_AHB_CLK */
398 	0x80f8, /* VIDEO_CC_SLEEP_CLK */
399 	0x80d4, /* VIDEO_CC_XO_CLK */
400 };
401 
402 static void clk_sm8750_regs_configure(struct device *dev, struct regmap *regmap)
403 {
404 	/* Update DLY_ACCU_RED_SHIFTER_DONE to 0xF for mvs0, mvs0c */
405 	regmap_update_bits(regmap, 0x8074, GENMASK(25, 21), GENMASK(25, 21));
406 	regmap_update_bits(regmap, 0x8040, GENMASK(25, 21), GENMASK(25, 21));
407 
408 	regmap_update_bits(regmap, 0x9f24, BIT(0), BIT(0));
409 }
410 
411 static struct qcom_cc_driver_data video_cc_sm8750_driver_data = {
412 	.alpha_plls = video_cc_sm8750_plls,
413 	.num_alpha_plls = ARRAY_SIZE(video_cc_sm8750_plls),
414 	.clk_cbcrs = video_cc_sm8750_critical_cbcrs,
415 	.num_clk_cbcrs = ARRAY_SIZE(video_cc_sm8750_critical_cbcrs),
416 	.clk_regs_configure = clk_sm8750_regs_configure,
417 };
418 
419 static struct qcom_cc_desc video_cc_sm8750_desc = {
420 	.config = &video_cc_sm8750_regmap_config,
421 	.clks = video_cc_sm8750_clocks,
422 	.num_clks = ARRAY_SIZE(video_cc_sm8750_clocks),
423 	.resets = video_cc_sm8750_resets,
424 	.num_resets = ARRAY_SIZE(video_cc_sm8750_resets),
425 	.gdscs = video_cc_sm8750_gdscs,
426 	.num_gdscs = ARRAY_SIZE(video_cc_sm8750_gdscs),
427 	.use_rpm = true,
428 	.driver_data = &video_cc_sm8750_driver_data,
429 };
430 
431 static const struct of_device_id video_cc_sm8750_match_table[] = {
432 	{ .compatible = "qcom,sm8750-videocc" },
433 	{ }
434 };
435 MODULE_DEVICE_TABLE(of, video_cc_sm8750_match_table);
436 
437 static int video_cc_sm8750_probe(struct platform_device *pdev)
438 {
439 	return qcom_cc_probe(pdev, &video_cc_sm8750_desc);
440 }
441 
442 static struct platform_driver video_cc_sm8750_driver = {
443 	.probe = video_cc_sm8750_probe,
444 	.driver = {
445 		.name = "video_cc-sm8750",
446 		.of_match_table = video_cc_sm8750_match_table,
447 	},
448 };
449 
450 static int __init video_cc_sm8750_init(void)
451 {
452 	return platform_driver_register(&video_cc_sm8750_driver);
453 }
454 subsys_initcall(video_cc_sm8750_init);
455 
456 static void __exit video_cc_sm8750_exit(void)
457 {
458 	platform_driver_unregister(&video_cc_sm8750_driver);
459 }
460 module_exit(video_cc_sm8750_exit);
461 
462 MODULE_DESCRIPTION("QTI VIDEO_CC SM8750 Driver");
463 MODULE_LICENSE("GPL");
464