xref: /linux/drivers/clk/qcom/videocc-sm6350.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
4  * Copyright (c) 2021, Konrad Dybcio <konrad.dybcio@somainline.org>
5  * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com>
6  */
7 
8 #include <linux/clk-provider.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/regmap.h>
12 
13 #include <dt-bindings/clock/qcom,sm6350-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 "common.h"
20 #include "gdsc.h"
21 
22 enum {
23 	DT_IFACE,
24 	DT_BI_TCXO,
25 	DT_SLEEP_CLK,
26 };
27 
28 enum {
29 	P_BI_TCXO,
30 	P_CHIP_SLEEP_CLK,
31 	P_VIDEO_PLL0_OUT_EVEN,
32 };
33 
34 static const struct pll_vco fabia_vco[] = {
35 	{ 125000000, 1000000000, 1 },
36 };
37 
38 /* 600 MHz */
39 static const struct alpha_pll_config video_pll0_config = {
40 	.l = 0x1f,
41 	.alpha = 0x4000,
42 	.config_ctl_val = 0x20485699,
43 	.config_ctl_hi_val = 0x00002067,
44 	.test_ctl_val = 0x40000000,
45 	.test_ctl_hi_val = 0x00000002,
46 	.user_ctl_val = 0x00000101,
47 	.user_ctl_hi_val = 0x00004005,
48 };
49 
50 static struct clk_alpha_pll video_pll0 = {
51 	.offset = 0x0,
52 	.vco_table = fabia_vco,
53 	.num_vco = ARRAY_SIZE(fabia_vco),
54 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
55 	.clkr = {
56 		.hw.init = &(const struct clk_init_data) {
57 			.name = "video_pll0",
58 			.parent_data = &(const struct clk_parent_data) {
59 				.index = DT_BI_TCXO,
60 			},
61 			.num_parents = 1,
62 			.ops = &clk_alpha_pll_fabia_ops,
63 		},
64 	},
65 };
66 
67 static const struct clk_div_table post_div_table_video_pll0_out_even[] = {
68 	{ 0x1, 2 },
69 	{ }
70 };
71 
72 static struct clk_alpha_pll_postdiv video_pll0_out_even = {
73 	.offset = 0x0,
74 	.post_div_shift = 8,
75 	.post_div_table = post_div_table_video_pll0_out_even,
76 	.num_post_div = ARRAY_SIZE(post_div_table_video_pll0_out_even),
77 	.width = 4,
78 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
79 	.clkr.hw.init = &(const struct clk_init_data) {
80 		.name = "video_pll0_out_even",
81 		.parent_hws = (const struct clk_hw*[]) {
82 			&video_pll0.clkr.hw,
83 		},
84 		.num_parents = 1,
85 		.flags = CLK_SET_RATE_PARENT,
86 		.ops = &clk_alpha_pll_postdiv_fabia_ops,
87 	},
88 };
89 
90 static const struct parent_map video_cc_parent_map_0[] = {
91 	{ P_BI_TCXO, 0 },
92 	{ P_VIDEO_PLL0_OUT_EVEN, 3 },
93 };
94 
95 static const struct clk_parent_data video_cc_parent_data_0[] = {
96 	{ .index = DT_BI_TCXO },
97 	{ .hw = &video_pll0_out_even.clkr.hw },
98 };
99 
100 static const struct parent_map video_cc_parent_map_1[] = {
101 	{ P_CHIP_SLEEP_CLK, 0 },
102 };
103 
104 static const struct clk_parent_data video_cc_parent_data_1[] = {
105 	{ .index = DT_SLEEP_CLK },
106 };
107 
108 static const struct freq_tbl ftbl_video_cc_iris_clk_src[] = {
109 	F(133250000, P_VIDEO_PLL0_OUT_EVEN, 2, 0, 0),
110 	F(240000000, P_VIDEO_PLL0_OUT_EVEN, 1.5, 0, 0),
111 	F(300000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0),
112 	F(380000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0),
113 	F(460000000, P_VIDEO_PLL0_OUT_EVEN, 1, 0, 0),
114 	{ }
115 };
116 
117 static struct clk_rcg2 video_cc_iris_clk_src = {
118 	.cmd_rcgr = 0x1000,
119 	.mnd_width = 0,
120 	.hid_width = 5,
121 	.parent_map = video_cc_parent_map_0,
122 	.freq_tbl = ftbl_video_cc_iris_clk_src,
123 	.clkr.hw.init = &(const struct clk_init_data) {
124 		.name = "video_cc_iris_clk_src",
125 		.parent_data = video_cc_parent_data_0,
126 		.num_parents = ARRAY_SIZE(video_cc_parent_data_0),
127 		.flags = CLK_SET_RATE_PARENT,
128 		.ops = &clk_rcg2_shared_ops,
129 	},
130 };
131 
132 static const struct freq_tbl ftbl_video_cc_sleep_clk_src[] = {
133 	F(32764, P_CHIP_SLEEP_CLK, 1, 0, 0),
134 	{ }
135 };
136 
137 static struct clk_rcg2 video_cc_sleep_clk_src = {
138 	.cmd_rcgr = 0x701c,
139 	.mnd_width = 0,
140 	.hid_width = 5,
141 	.parent_map = video_cc_parent_map_1,
142 	.freq_tbl = ftbl_video_cc_sleep_clk_src,
143 	.clkr.hw.init = &(const struct clk_init_data) {
144 		.name = "video_cc_sleep_clk_src",
145 		.parent_data = video_cc_parent_data_1,
146 		.num_parents = ARRAY_SIZE(video_cc_parent_data_1),
147 		.ops = &clk_rcg2_ops,
148 	},
149 };
150 
151 static struct clk_branch video_cc_iris_ahb_clk = {
152 	.halt_reg = 0x5004,
153 	.halt_check = BRANCH_VOTED,
154 	.clkr = {
155 		.enable_reg = 0x5004,
156 		.enable_mask = BIT(0),
157 		.hw.init = &(const struct clk_init_data) {
158 			.name = "video_cc_iris_ahb_clk",
159 			.parent_hws = (const struct clk_hw*[]) {
160 				&video_cc_iris_clk_src.clkr.hw,
161 			},
162 			.num_parents = 1,
163 			.flags = CLK_SET_RATE_PARENT,
164 			.ops = &clk_branch2_ops,
165 		},
166 	},
167 };
168 
169 static struct clk_branch video_cc_mvs0_axi_clk = {
170 	.halt_reg = 0x800c,
171 	.halt_check = BRANCH_HALT,
172 	.clkr = {
173 		.enable_reg = 0x800c,
174 		.enable_mask = BIT(0),
175 		.hw.init = &(const struct clk_init_data) {
176 			.name = "video_cc_mvs0_axi_clk",
177 			.ops = &clk_branch2_ops,
178 		},
179 	},
180 };
181 
182 static struct clk_branch video_cc_mvs0_core_clk = {
183 	.halt_reg = 0x3010,
184 	.halt_check = BRANCH_VOTED,
185 	.hwcg_reg = 0x3010,
186 	.hwcg_bit = 1,
187 	.clkr = {
188 		.enable_reg = 0x3010,
189 		.enable_mask = BIT(0),
190 		.hw.init = &(const struct clk_init_data) {
191 			.name = "video_cc_mvs0_core_clk",
192 			.parent_hws = (const struct clk_hw*[]) {
193 				&video_cc_iris_clk_src.clkr.hw,
194 			},
195 			.num_parents = 1,
196 			.flags = CLK_SET_RATE_PARENT,
197 			.ops = &clk_branch2_ops,
198 		},
199 	},
200 };
201 
202 static struct clk_branch video_cc_mvsc_core_clk = {
203 	.halt_reg = 0x2014,
204 	.halt_check = BRANCH_HALT,
205 	.clkr = {
206 		.enable_reg = 0x2014,
207 		.enable_mask = BIT(0),
208 		.hw.init = &(const struct clk_init_data) {
209 			.name = "video_cc_mvsc_core_clk",
210 			.parent_hws = (const struct clk_hw*[]) {
211 				&video_cc_iris_clk_src.clkr.hw,
212 			},
213 			.num_parents = 1,
214 			.flags = CLK_SET_RATE_PARENT,
215 			.ops = &clk_branch2_ops,
216 		},
217 	},
218 };
219 
220 static struct clk_branch video_cc_mvsc_ctl_axi_clk = {
221 	.halt_reg = 0x8004,
222 	.halt_check = BRANCH_HALT,
223 	.clkr = {
224 		.enable_reg = 0x8004,
225 		.enable_mask = BIT(0),
226 		.hw.init = &(const struct clk_init_data) {
227 			.name = "video_cc_mvsc_ctl_axi_clk",
228 			.ops = &clk_branch2_ops,
229 		},
230 	},
231 };
232 
233 static struct clk_branch video_cc_sleep_clk = {
234 	.halt_reg = 0x7034,
235 	.halt_check = BRANCH_HALT,
236 	.clkr = {
237 		.enable_reg = 0x7034,
238 		.enable_mask = BIT(0),
239 		.hw.init = &(const struct clk_init_data) {
240 			.name = "video_cc_sleep_clk",
241 			.parent_hws = (const struct clk_hw*[]) {
242 				&video_cc_sleep_clk_src.clkr.hw,
243 			},
244 			.num_parents = 1,
245 			.flags = CLK_SET_RATE_PARENT,
246 			.ops = &clk_branch2_ops,
247 		},
248 	},
249 };
250 
251 static struct clk_branch video_cc_venus_ahb_clk = {
252 	.halt_reg = 0x801c,
253 	.halt_check = BRANCH_HALT,
254 	.clkr = {
255 		.enable_reg = 0x801c,
256 		.enable_mask = BIT(0),
257 		.hw.init = &(const struct clk_init_data) {
258 			.name = "video_cc_venus_ahb_clk",
259 			.ops = &clk_branch2_ops,
260 		},
261 	},
262 };
263 
264 static struct gdsc mvsc_gdsc = {
265 	.gdscr = 0x2004,
266 	.en_rest_wait_val = 0x2,
267 	.en_few_wait_val = 0x2,
268 	.clk_dis_wait_val = 0x6,
269 	.pd = {
270 		.name = "mvsc_gdsc",
271 	},
272 	.pwrsts = PWRSTS_OFF_ON,
273 };
274 
275 static struct gdsc mvs0_gdsc = {
276 	.gdscr = 0x3004,
277 	.en_rest_wait_val = 0x2,
278 	.en_few_wait_val = 0x2,
279 	.clk_dis_wait_val = 0x6,
280 	.pd = {
281 		.name = "mvs0_gdsc",
282 	},
283 	.pwrsts = PWRSTS_OFF_ON,
284 	.flags = HW_CTRL_TRIGGER,
285 };
286 
287 static struct gdsc *video_cc_sm6350_gdscs[] = {
288 	[MVSC_GDSC] = &mvsc_gdsc,
289 	[MVS0_GDSC] = &mvs0_gdsc,
290 };
291 
292 static struct clk_regmap *video_cc_sm6350_clocks[] = {
293 	[VIDEO_CC_IRIS_AHB_CLK] = &video_cc_iris_ahb_clk.clkr,
294 	[VIDEO_CC_IRIS_CLK_SRC] = &video_cc_iris_clk_src.clkr,
295 	[VIDEO_CC_MVS0_AXI_CLK] = &video_cc_mvs0_axi_clk.clkr,
296 	[VIDEO_CC_MVS0_CORE_CLK] = &video_cc_mvs0_core_clk.clkr,
297 	[VIDEO_CC_MVSC_CORE_CLK] = &video_cc_mvsc_core_clk.clkr,
298 	[VIDEO_CC_MVSC_CTL_AXI_CLK] = &video_cc_mvsc_ctl_axi_clk.clkr,
299 	[VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr,
300 	[VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
301 	[VIDEO_CC_VENUS_AHB_CLK] = &video_cc_venus_ahb_clk.clkr,
302 	[VIDEO_PLL0] = &video_pll0.clkr,
303 	[VIDEO_PLL0_OUT_EVEN] = &video_pll0_out_even.clkr,
304 };
305 
306 static const struct regmap_config video_cc_sm6350_regmap_config = {
307 	.reg_bits = 32,
308 	.reg_stride = 4,
309 	.val_bits = 32,
310 	.max_register = 0xb000,
311 	.fast_io = true,
312 };
313 
314 static const struct qcom_cc_desc video_cc_sm6350_desc = {
315 	.config = &video_cc_sm6350_regmap_config,
316 	.clks = video_cc_sm6350_clocks,
317 	.num_clks = ARRAY_SIZE(video_cc_sm6350_clocks),
318 	.gdscs = video_cc_sm6350_gdscs,
319 	.num_gdscs = ARRAY_SIZE(video_cc_sm6350_gdscs),
320 };
321 
322 static const struct of_device_id video_cc_sm6350_match_table[] = {
323 	{ .compatible = "qcom,sm6350-videocc" },
324 	{ }
325 };
326 MODULE_DEVICE_TABLE(of, video_cc_sm6350_match_table);
327 
328 static int video_cc_sm6350_probe(struct platform_device *pdev)
329 {
330 	struct regmap *regmap;
331 
332 	regmap = qcom_cc_map(pdev, &video_cc_sm6350_desc);
333 	if (IS_ERR(regmap))
334 		return PTR_ERR(regmap);
335 
336 	clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config);
337 
338 	/* Keep some clocks always-on */
339 	qcom_branch_set_clk_en(regmap, 0x7018); /* VIDEO_CC_XO_CLK */
340 
341 	return qcom_cc_really_probe(&pdev->dev, &video_cc_sm6350_desc, regmap);
342 }
343 
344 static struct platform_driver video_cc_sm6350_driver = {
345 	.probe = video_cc_sm6350_probe,
346 	.driver = {
347 		.name = "video_cc-sm6350",
348 		.of_match_table = video_cc_sm6350_match_table,
349 	},
350 };
351 
352 module_platform_driver(video_cc_sm6350_driver);
353 
354 MODULE_DESCRIPTION("QTI VIDEO_CC SM6350 Driver");
355 MODULE_LICENSE("GPL");
356