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