xref: /linux/drivers/clk/qcom/videocc-milos.c (revision 18fbf5151d2c0bfe433c7428eef03cabf5fdb2fa)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
4  * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com>
5  */
6 
7 #include <linux/clk-provider.h>
8 #include <linux/module.h>
9 #include <linux/platform_device.h>
10 #include <linux/regmap.h>
11 
12 #include <dt-bindings/clock/qcom,milos-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 
23 /* Need to match the order of clocks in DT binding */
24 enum {
25 	DT_BI_TCXO,
26 	DT_BI_TCXO_AO,
27 	DT_SLEEP_CLK,
28 	DT_IFACE,
29 };
30 
31 enum {
32 	P_BI_TCXO,
33 	P_SLEEP_CLK,
34 	P_VIDEO_CC_PLL0_OUT_MAIN,
35 };
36 
37 static const struct pll_vco lucid_ole_vco[] = {
38 	{ 249600000, 2300000000, 0 },
39 };
40 
41 /* 604.8 MHz Configuration */
42 static const struct alpha_pll_config video_cc_pll0_config = {
43 	.l = 0x1f,
44 	.alpha = 0x8000,
45 	.config_ctl_val = 0x20485699,
46 	.config_ctl_hi_val = 0x00182261,
47 	.config_ctl_hi1_val = 0x82aa299c,
48 	.test_ctl_val = 0x00000000,
49 	.test_ctl_hi_val = 0x00000003,
50 	.test_ctl_hi1_val = 0x00009000,
51 	.test_ctl_hi2_val = 0x00000034,
52 	.user_ctl_val = 0x00000000,
53 	.user_ctl_hi_val = 0x00000005,
54 };
55 
56 static struct clk_alpha_pll video_cc_pll0 = {
57 	.offset = 0x0,
58 	.config = &video_cc_pll0_config,
59 	.vco_table = lucid_ole_vco,
60 	.num_vco = ARRAY_SIZE(lucid_ole_vco),
61 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
62 	.clkr = {
63 		.hw.init = &(const struct clk_init_data) {
64 			.name = "video_cc_pll0",
65 			.parent_data = &(const struct clk_parent_data) {
66 				.index = DT_BI_TCXO,
67 			},
68 			.num_parents = 1,
69 			.ops = &clk_alpha_pll_lucid_evo_ops,
70 		},
71 	},
72 };
73 
74 static const struct parent_map video_cc_parent_map_0[] = {
75 	{ P_BI_TCXO, 0 },
76 };
77 
78 static const struct clk_parent_data video_cc_parent_data_0[] = {
79 	{ .index = DT_BI_TCXO },
80 };
81 
82 static const struct clk_parent_data video_cc_parent_data_0_ao[] = {
83 	{ .index = DT_BI_TCXO_AO },
84 };
85 
86 static const struct parent_map video_cc_parent_map_1[] = {
87 	{ P_BI_TCXO, 0 },
88 	{ P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
89 };
90 
91 static const struct clk_parent_data video_cc_parent_data_1[] = {
92 	{ .index = DT_BI_TCXO },
93 	{ .hw = &video_cc_pll0.clkr.hw },
94 };
95 
96 static const struct parent_map video_cc_parent_map_2[] = {
97 	{ P_SLEEP_CLK, 0 },
98 };
99 
100 static const struct clk_parent_data video_cc_parent_data_2_ao[] = {
101 	{ .index = DT_SLEEP_CLK },
102 };
103 
104 static const struct freq_tbl ftbl_video_cc_ahb_clk_src[] = {
105 	F(19200000, P_BI_TCXO, 1, 0, 0),
106 	{ }
107 };
108 
109 static struct clk_rcg2 video_cc_ahb_clk_src = {
110 	.cmd_rcgr = 0x8030,
111 	.mnd_width = 0,
112 	.hid_width = 5,
113 	.parent_map = video_cc_parent_map_0,
114 	.freq_tbl = ftbl_video_cc_ahb_clk_src,
115 	.clkr.hw.init = &(const struct clk_init_data) {
116 		.name = "video_cc_ahb_clk_src",
117 		.parent_data = video_cc_parent_data_0_ao,
118 		.num_parents = ARRAY_SIZE(video_cc_parent_data_0_ao),
119 		.flags = CLK_SET_RATE_PARENT,
120 		.ops = &clk_rcg2_shared_ops,
121 	},
122 };
123 
124 static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
125 	F(604800000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
126 	F(720000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
127 	F(1014000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
128 	F(1098000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
129 	F(1332000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
130 	F(1656000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
131 	{ }
132 };
133 
134 static struct clk_rcg2 video_cc_mvs0_clk_src = {
135 	.cmd_rcgr = 0x8000,
136 	.mnd_width = 0,
137 	.hid_width = 5,
138 	.parent_map = video_cc_parent_map_1,
139 	.freq_tbl = ftbl_video_cc_mvs0_clk_src,
140 	.clkr.hw.init = &(const struct clk_init_data) {
141 		.name = "video_cc_mvs0_clk_src",
142 		.parent_data = video_cc_parent_data_1,
143 		.num_parents = ARRAY_SIZE(video_cc_parent_data_1),
144 		.flags = CLK_SET_RATE_PARENT,
145 		.ops = &clk_rcg2_shared_ops,
146 	},
147 };
148 
149 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
150 	F(32000, P_SLEEP_CLK, 1, 0, 0),
151 	{ }
152 };
153 
154 static struct clk_rcg2 video_cc_sleep_clk_src = {
155 	.cmd_rcgr = 0x8128,
156 	.mnd_width = 0,
157 	.hid_width = 5,
158 	.parent_map = video_cc_parent_map_2,
159 	.freq_tbl = ftbl_video_cc_sleep_clk_src,
160 	.clkr.hw.init = &(const struct clk_init_data) {
161 		.name = "video_cc_sleep_clk_src",
162 		.parent_data = video_cc_parent_data_2_ao,
163 		.num_parents = ARRAY_SIZE(video_cc_parent_data_2_ao),
164 		.flags = CLK_SET_RATE_PARENT,
165 		.ops = &clk_rcg2_ops,
166 	},
167 };
168 
169 static struct clk_rcg2 video_cc_xo_clk_src = {
170 	.cmd_rcgr = 0x810c,
171 	.mnd_width = 0,
172 	.hid_width = 5,
173 	.parent_map = video_cc_parent_map_0,
174 	.freq_tbl = ftbl_video_cc_ahb_clk_src,
175 	.clkr.hw.init = &(const struct clk_init_data) {
176 		.name = "video_cc_xo_clk_src",
177 		.parent_data = video_cc_parent_data_0,
178 		.num_parents = ARRAY_SIZE(video_cc_parent_data_0),
179 		.flags = CLK_SET_RATE_PARENT,
180 		.ops = &clk_rcg2_ops,
181 	},
182 };
183 
184 static struct clk_regmap_div video_cc_mvs0_div_clk_src = {
185 	.reg = 0x80c4,
186 	.shift = 0,
187 	.width = 4,
188 	.clkr.hw.init = &(const struct clk_init_data) {
189 		.name = "video_cc_mvs0_div_clk_src",
190 		.parent_hws = (const struct clk_hw*[]) {
191 			&video_cc_mvs0_clk_src.clkr.hw,
192 		},
193 		.num_parents = 1,
194 		.flags = CLK_SET_RATE_PARENT,
195 		.ops = &clk_regmap_div_ro_ops,
196 	},
197 };
198 
199 static struct clk_regmap_div video_cc_mvs0c_div2_div_clk_src = {
200 	.reg = 0x8070,
201 	.shift = 0,
202 	.width = 4,
203 	.clkr.hw.init = &(const struct clk_init_data) {
204 		.name = "video_cc_mvs0c_div2_div_clk_src",
205 		.parent_hws = (const struct clk_hw*[]) {
206 			&video_cc_mvs0_clk_src.clkr.hw,
207 		},
208 		.num_parents = 1,
209 		.flags = CLK_SET_RATE_PARENT,
210 		.ops = &clk_regmap_div_ro_ops,
211 	},
212 };
213 
214 static struct clk_branch video_cc_mvs0_clk = {
215 	.halt_reg = 0x80b8,
216 	.halt_check = BRANCH_HALT_VOTED,
217 	.hwcg_reg = 0x80b8,
218 	.hwcg_bit = 1,
219 	.clkr = {
220 		.enable_reg = 0x80b8,
221 		.enable_mask = BIT(0),
222 		.hw.init = &(const struct clk_init_data) {
223 			.name = "video_cc_mvs0_clk",
224 			.parent_hws = (const struct clk_hw*[]) {
225 				&video_cc_mvs0_div_clk_src.clkr.hw,
226 			},
227 			.num_parents = 1,
228 			.flags = CLK_SET_RATE_PARENT,
229 			.ops = &clk_branch2_ops,
230 		},
231 	},
232 };
233 
234 static struct clk_branch video_cc_mvs0_shift_clk = {
235 	.halt_reg = 0x8144,
236 	.halt_check = BRANCH_HALT_VOTED,
237 	.hwcg_reg = 0x8144,
238 	.hwcg_bit = 1,
239 	.clkr = {
240 		.enable_reg = 0x8144,
241 		.enable_mask = BIT(0),
242 		.hw.init = &(const struct clk_init_data) {
243 			.name = "video_cc_mvs0_shift_clk",
244 			.parent_hws = (const struct clk_hw*[]) {
245 				&video_cc_xo_clk_src.clkr.hw,
246 			},
247 			.num_parents = 1,
248 			.flags = CLK_SET_RATE_PARENT,
249 			.ops = &clk_branch2_ops,
250 		},
251 	},
252 };
253 
254 static struct clk_branch video_cc_mvs0c_clk = {
255 	.halt_reg = 0x8064,
256 	.halt_check = BRANCH_HALT,
257 	.clkr = {
258 		.enable_reg = 0x8064,
259 		.enable_mask = BIT(0),
260 		.hw.init = &(const struct clk_init_data) {
261 			.name = "video_cc_mvs0c_clk",
262 			.parent_hws = (const struct clk_hw*[]) {
263 				&video_cc_mvs0c_div2_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_shift_clk = {
273 	.halt_reg = 0x8148,
274 	.halt_check = BRANCH_HALT_VOTED,
275 	.hwcg_reg = 0x8148,
276 	.hwcg_bit = 1,
277 	.clkr = {
278 		.enable_reg = 0x8148,
279 		.enable_mask = BIT(0),
280 		.hw.init = &(const struct clk_init_data) {
281 			.name = "video_cc_mvs0c_shift_clk",
282 			.parent_hws = (const struct clk_hw*[]) {
283 				&video_cc_xo_clk_src.clkr.hw,
284 			},
285 			.num_parents = 1,
286 			.flags = CLK_SET_RATE_PARENT,
287 			.ops = &clk_branch2_ops,
288 		},
289 	},
290 };
291 
292 static struct gdsc video_cc_mvs0c_gdsc = {
293 	.gdscr = 0x804c,
294 	.en_rest_wait_val = 0x2,
295 	.en_few_wait_val = 0x2,
296 	.clk_dis_wait_val = 0x6,
297 	.pd = {
298 		.name = "video_cc_mvs0c_gdsc",
299 	},
300 	.pwrsts = PWRSTS_OFF_ON,
301 	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
302 };
303 
304 static struct gdsc video_cc_mvs0_gdsc = {
305 	.gdscr = 0x80a4,
306 	.en_rest_wait_val = 0x2,
307 	.en_few_wait_val = 0x2,
308 	.clk_dis_wait_val = 0x6,
309 	.pd = {
310 		.name = "video_cc_mvs0_gdsc",
311 	},
312 	.pwrsts = PWRSTS_OFF_ON,
313 	.parent = &video_cc_mvs0c_gdsc.pd,
314 	.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | HW_CTRL_TRIGGER,
315 };
316 
317 static struct clk_regmap *video_cc_milos_clocks[] = {
318 	[VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr,
319 	[VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
320 	[VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
321 	[VIDEO_CC_MVS0_DIV_CLK_SRC] = &video_cc_mvs0_div_clk_src.clkr,
322 	[VIDEO_CC_MVS0_SHIFT_CLK] = &video_cc_mvs0_shift_clk.clkr,
323 	[VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
324 	[VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC] = &video_cc_mvs0c_div2_div_clk_src.clkr,
325 	[VIDEO_CC_MVS0C_SHIFT_CLK] = &video_cc_mvs0c_shift_clk.clkr,
326 	[VIDEO_CC_PLL0] = &video_cc_pll0.clkr,
327 	[VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
328 	[VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,
329 };
330 
331 static struct gdsc *video_cc_milos_gdscs[] = {
332 	[VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
333 	[VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
334 };
335 
336 static const struct qcom_reset_map video_cc_milos_resets[] = {
337 	[VIDEO_CC_INTERFACE_BCR] = { 0x80f0 },
338 	[VIDEO_CC_MVS0_BCR] = { 0x80a0 },
339 	[VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 },
340 	[VIDEO_CC_MVS0C_BCR] = { 0x8048 },
341 };
342 
343 static struct clk_alpha_pll *video_cc_milos_plls[] = {
344 	&video_cc_pll0,
345 };
346 
347 static const u32 video_cc_milos_critical_cbcrs[] = {
348 	0x80f4, /* VIDEO_CC_AHB_CLK */
349 	0x8140, /* VIDEO_CC_SLEEP_CLK */
350 	0x8124, /* VIDEO_CC_XO_CLK */
351 };
352 
353 static const struct regmap_config video_cc_milos_regmap_config = {
354 	.reg_bits = 32,
355 	.reg_stride = 4,
356 	.val_bits = 32,
357 	.max_register = 0x9f50,
358 	.fast_io = true,
359 };
360 
361 static const struct qcom_cc_driver_data video_cc_milos_driver_data = {
362 	.alpha_plls = video_cc_milos_plls,
363 	.num_alpha_plls = ARRAY_SIZE(video_cc_milos_plls),
364 	.clk_cbcrs = video_cc_milos_critical_cbcrs,
365 	.num_clk_cbcrs = ARRAY_SIZE(video_cc_milos_critical_cbcrs),
366 };
367 
368 static const struct qcom_cc_desc video_cc_milos_desc = {
369 	.config = &video_cc_milos_regmap_config,
370 	.clks = video_cc_milos_clocks,
371 	.num_clks = ARRAY_SIZE(video_cc_milos_clocks),
372 	.resets = video_cc_milos_resets,
373 	.num_resets = ARRAY_SIZE(video_cc_milos_resets),
374 	.gdscs = video_cc_milos_gdscs,
375 	.num_gdscs = ARRAY_SIZE(video_cc_milos_gdscs),
376 	.use_rpm = true,
377 	.driver_data = &video_cc_milos_driver_data,
378 };
379 
380 static const struct of_device_id video_cc_milos_match_table[] = {
381 	{ .compatible = "qcom,milos-videocc" },
382 	{ }
383 };
384 MODULE_DEVICE_TABLE(of, video_cc_milos_match_table);
385 
386 static int video_cc_milos_probe(struct platform_device *pdev)
387 {
388 	return qcom_cc_probe(pdev, &video_cc_milos_desc);
389 }
390 
391 static struct platform_driver video_cc_milos_driver = {
392 	.probe = video_cc_milos_probe,
393 	.driver = {
394 		.name = "video_cc-milos",
395 		.of_match_table = video_cc_milos_match_table,
396 	},
397 };
398 
399 module_platform_driver(video_cc_milos_driver);
400 
401 MODULE_DESCRIPTION("QTI VIDEO_CC Milos Driver");
402 MODULE_LICENSE("GPL");
403