xref: /linux/drivers/clk/qcom/videocc-sm7150.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4  * Copyright (c) 2024, Danila Tikhonov <danila@jiaxyga.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,sm7150-videocc.h>
13 
14 #include "common.h"
15 #include "clk-alpha-pll.h"
16 #include "clk-branch.h"
17 #include "clk-rcg.h"
18 #include "clk-regmap.h"
19 #include "clk-pll.h"
20 #include "gdsc.h"
21 
22 enum {
23 	DT_BI_TCXO,
24 	DT_BI_TCXO_AO,
25 };
26 
27 enum {
28 	P_BI_TCXO,
29 	P_VIDEOCC_PLL0_OUT_EVEN,
30 	P_VIDEOCC_PLL0_OUT_MAIN,
31 	P_VIDEOCC_PLL0_OUT_ODD,
32 };
33 
34 static const struct pll_vco fabia_vco[] = {
35 	{ 249600000, 2000000000, 0 },
36 	{ 125000000, 1000000000, 1 },
37 };
38 
39 static struct alpha_pll_config videocc_pll0_config = {
40 	.l = 0x19,
41 	.alpha = 0x0,
42 	.config_ctl_val = 0x20485699,
43 	.config_ctl_hi_val = 0x00002067,
44 	.user_ctl_val = 0x00000001,
45 	.user_ctl_hi_val = 0x00004805,
46 	.test_ctl_hi_val = 0x40000000,
47 };
48 
49 static struct clk_alpha_pll videocc_pll0 = {
50 	.offset = 0x42c,
51 	.vco_table = fabia_vco,
52 	.num_vco = ARRAY_SIZE(fabia_vco),
53 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
54 	.clkr = {
55 		.hw.init = &(const struct clk_init_data) {
56 			.name = "videocc_pll0",
57 			.parent_data = &(const struct clk_parent_data) {
58 				.index = DT_BI_TCXO,
59 			},
60 			.num_parents = 1,
61 			.ops = &clk_alpha_pll_fabia_ops,
62 		},
63 	},
64 };
65 
66 static const struct parent_map videocc_parent_map_0[] = {
67 	{ P_BI_TCXO, 0 },
68 	{ P_VIDEOCC_PLL0_OUT_MAIN, 1 },
69 	{ P_VIDEOCC_PLL0_OUT_EVEN, 2 },
70 	{ P_VIDEOCC_PLL0_OUT_ODD, 3 },
71 };
72 
73 static const struct clk_parent_data videocc_parent_data_0[] = {
74 	{ .index = DT_BI_TCXO },
75 	{ .hw = &videocc_pll0.clkr.hw },
76 	{ .hw = &videocc_pll0.clkr.hw },
77 	{ .hw = &videocc_pll0.clkr.hw },
78 };
79 
80 static const struct parent_map videocc_parent_map_1[] = {
81 	{ P_BI_TCXO, 0 },
82 };
83 
84 static const struct clk_parent_data videocc_parent_data_1[] = {
85 	{ .index = DT_BI_TCXO_AO },
86 };
87 
88 static const struct freq_tbl ftbl_videocc_iris_clk_src[] = {
89 	F(240000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
90 	F(338000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
91 	F(365000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
92 	F(444000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
93 	F(533000000, P_VIDEOCC_PLL0_OUT_MAIN, 2, 0, 0),
94 	{ }
95 };
96 
97 static struct clk_rcg2 videocc_iris_clk_src = {
98 	.cmd_rcgr = 0x7f0,
99 	.mnd_width = 0,
100 	.hid_width = 5,
101 	.parent_map = videocc_parent_map_0,
102 	.freq_tbl = ftbl_videocc_iris_clk_src,
103 	.clkr.hw.init = &(const struct clk_init_data) {
104 		.name = "videocc_iris_clk_src",
105 		.parent_data = videocc_parent_data_0,
106 		.num_parents = ARRAY_SIZE(videocc_parent_data_0),
107 		.flags = CLK_SET_RATE_PARENT,
108 		.ops = &clk_rcg2_shared_ops,
109 	},
110 };
111 
112 static const struct freq_tbl ftbl_videocc_xo_clk_src[] = {
113 	F(19200000, P_BI_TCXO, 1, 0, 0),
114 	{ }
115 };
116 
117 static struct clk_rcg2 videocc_xo_clk_src = {
118 	.cmd_rcgr = 0xa98,
119 	.mnd_width = 0,
120 	.hid_width = 5,
121 	.parent_map = videocc_parent_map_1,
122 	.freq_tbl = ftbl_videocc_xo_clk_src,
123 	.clkr.hw.init = &(const struct clk_init_data) {
124 		.name = "videocc_xo_clk_src",
125 		.parent_data = videocc_parent_data_1,
126 		.num_parents = ARRAY_SIZE(videocc_parent_data_1),
127 		.ops = &clk_rcg2_ops,
128 	},
129 };
130 
131 static struct clk_branch videocc_iris_ahb_clk = {
132 	.halt_reg = 0x8f4,
133 	.halt_check = BRANCH_VOTED,
134 	.clkr = {
135 		.enable_reg = 0x8f4,
136 		.enable_mask = BIT(0),
137 		.hw.init = &(const struct clk_init_data) {
138 			.name = "videocc_iris_ahb_clk",
139 			.parent_data = &(const struct clk_parent_data) {
140 				.hw = &videocc_iris_clk_src.clkr.hw,
141 			},
142 			.num_parents = 1,
143 			.flags = CLK_SET_RATE_PARENT,
144 			.ops = &clk_branch2_ops,
145 		},
146 	},
147 };
148 
149 static struct clk_branch videocc_mvs0_axi_clk = {
150 	.halt_reg = 0x9ec,
151 	.halt_check = BRANCH_HALT,
152 	.clkr = {
153 		.enable_reg = 0x9ec,
154 		.enable_mask = BIT(0),
155 		.hw.init = &(const struct clk_init_data) {
156 			.name = "videocc_mvs0_axi_clk",
157 			.ops = &clk_branch2_ops,
158 		},
159 	},
160 };
161 
162 static struct clk_branch videocc_mvs0_core_clk = {
163 	.halt_reg = 0x890,
164 	.halt_check = BRANCH_VOTED,
165 	.clkr = {
166 		.enable_reg = 0x890,
167 		.enable_mask = BIT(0),
168 		.hw.init = &(const struct clk_init_data) {
169 			.name = "videocc_mvs0_core_clk",
170 			.parent_data = &(const struct clk_parent_data) {
171 				.hw = &videocc_iris_clk_src.clkr.hw,
172 			},
173 			.num_parents = 1,
174 			.flags = CLK_SET_RATE_PARENT,
175 			.ops = &clk_branch2_ops,
176 		},
177 	},
178 };
179 
180 static struct clk_branch videocc_mvs1_axi_clk = {
181 	.halt_reg = 0xa0c,
182 	.halt_check = BRANCH_HALT,
183 	.clkr = {
184 		.enable_reg = 0xa0c,
185 		.enable_mask = BIT(0),
186 		.hw.init = &(const struct clk_init_data) {
187 			.name = "videocc_mvs1_axi_clk",
188 			.ops = &clk_branch2_ops,
189 		},
190 	},
191 };
192 
193 static struct clk_branch videocc_mvs1_core_clk = {
194 	.halt_reg = 0x8d0,
195 	.halt_check = BRANCH_VOTED,
196 	.clkr = {
197 		.enable_reg = 0x8d0,
198 		.enable_mask = BIT(0),
199 		.hw.init = &(const struct clk_init_data) {
200 			.name = "videocc_mvs1_core_clk",
201 			.parent_data = &(const struct clk_parent_data) {
202 				.hw = &videocc_iris_clk_src.clkr.hw,
203 			},
204 			.num_parents = 1,
205 			.flags = CLK_SET_RATE_PARENT,
206 			.ops = &clk_branch2_ops,
207 		},
208 	},
209 };
210 
211 static struct clk_branch videocc_mvsc_core_clk = {
212 	.halt_reg = 0x850,
213 	.halt_check = BRANCH_HALT,
214 	.clkr = {
215 		.enable_reg = 0x850,
216 		.enable_mask = BIT(0),
217 		.hw.init = &(const struct clk_init_data) {
218 			.name = "videocc_mvsc_core_clk",
219 			.parent_data = &(const struct clk_parent_data) {
220 				.hw = &videocc_iris_clk_src.clkr.hw,
221 			},
222 			.num_parents = 1,
223 			.flags = CLK_SET_RATE_PARENT,
224 			.ops = &clk_branch2_ops,
225 		},
226 	},
227 };
228 
229 static struct clk_branch videocc_mvsc_ctl_axi_clk = {
230 	.halt_reg = 0x9cc,
231 	.halt_check = BRANCH_HALT,
232 	.clkr = {
233 		.enable_reg = 0x9cc,
234 		.enable_mask = BIT(0),
235 		.hw.init = &(const struct clk_init_data) {
236 			.name = "videocc_mvsc_ctl_axi_clk",
237 			.ops = &clk_branch2_ops,
238 		},
239 	},
240 };
241 
242 static struct clk_branch videocc_venus_ahb_clk = {
243 	.halt_reg = 0xa6c,
244 	.halt_check = BRANCH_HALT,
245 	.clkr = {
246 		.enable_reg = 0xa6c,
247 		.enable_mask = BIT(0),
248 		.hw.init = &(const struct clk_init_data) {
249 			.name = "videocc_venus_ahb_clk",
250 			.ops = &clk_branch2_ops,
251 		},
252 	},
253 };
254 
255 static struct gdsc venus_gdsc = {
256 	.gdscr = 0x814,
257 	.pd = {
258 		.name = "venus_gdsc",
259 	},
260 	.cxcs = (unsigned int []){ 0x850, 0x9cc },
261 	.cxc_count = 2,
262 	.pwrsts = PWRSTS_OFF_ON,
263 	.flags = POLL_CFG_GDSCR,
264 };
265 
266 static struct gdsc vcodec0_gdsc = {
267 	.gdscr = 0x874,
268 	.pd = {
269 		.name = "vcodec0_gdsc",
270 	},
271 	.cxcs = (unsigned int []){ 0x890, 0x9ec },
272 	.cxc_count = 2,
273 	.flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR,
274 	.pwrsts = PWRSTS_OFF_ON,
275 };
276 
277 static struct gdsc vcodec1_gdsc = {
278 	.gdscr = 0x8b4,
279 	.pd = {
280 		.name = "vcodec1_gdsc",
281 	},
282 	.cxcs = (unsigned int []){ 0x8d0, 0xa0c },
283 	.cxc_count = 2,
284 	.flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR,
285 	.pwrsts = PWRSTS_OFF_ON,
286 };
287 
288 static struct clk_regmap *videocc_sm7150_clocks[] = {
289 	[VIDEOCC_PLL0] = &videocc_pll0.clkr,
290 	[VIDEOCC_IRIS_AHB_CLK] = &videocc_iris_ahb_clk.clkr,
291 	[VIDEOCC_IRIS_CLK_SRC] = &videocc_iris_clk_src.clkr,
292 	[VIDEOCC_MVS0_AXI_CLK] = &videocc_mvs0_axi_clk.clkr,
293 	[VIDEOCC_MVS0_CORE_CLK] = &videocc_mvs0_core_clk.clkr,
294 	[VIDEOCC_MVS1_AXI_CLK] = &videocc_mvs1_axi_clk.clkr,
295 	[VIDEOCC_MVS1_CORE_CLK] = &videocc_mvs1_core_clk.clkr,
296 	[VIDEOCC_MVSC_CORE_CLK] = &videocc_mvsc_core_clk.clkr,
297 	[VIDEOCC_MVSC_CTL_AXI_CLK] = &videocc_mvsc_ctl_axi_clk.clkr,
298 	[VIDEOCC_VENUS_AHB_CLK] = &videocc_venus_ahb_clk.clkr,
299 	[VIDEOCC_XO_CLK_SRC] = &videocc_xo_clk_src.clkr,
300 };
301 
302 static struct gdsc *videocc_sm7150_gdscs[] = {
303 	[VENUS_GDSC] = &venus_gdsc,
304 	[VCODEC0_GDSC] = &vcodec0_gdsc,
305 	[VCODEC1_GDSC] = &vcodec1_gdsc,
306 };
307 
308 static const struct regmap_config videocc_sm7150_regmap_config = {
309 	.reg_bits	= 32,
310 	.reg_stride	= 4,
311 	.val_bits	= 32,
312 	.max_register	= 0xb94,
313 	.fast_io	= true,
314 };
315 
316 static const struct qcom_cc_desc videocc_sm7150_desc = {
317 	.config = &videocc_sm7150_regmap_config,
318 	.clks = videocc_sm7150_clocks,
319 	.num_clks = ARRAY_SIZE(videocc_sm7150_clocks),
320 	.gdscs = videocc_sm7150_gdscs,
321 	.num_gdscs = ARRAY_SIZE(videocc_sm7150_gdscs),
322 };
323 
324 static const struct of_device_id videocc_sm7150_match_table[] = {
325 	{ .compatible = "qcom,sm7150-videocc" },
326 	{ }
327 };
328 MODULE_DEVICE_TABLE(of, videocc_sm7150_match_table);
329 
330 static int videocc_sm7150_probe(struct platform_device *pdev)
331 {
332 	struct regmap *regmap;
333 
334 	regmap = qcom_cc_map(pdev, &videocc_sm7150_desc);
335 	if (IS_ERR(regmap))
336 		return PTR_ERR(regmap);
337 
338 	clk_fabia_pll_configure(&videocc_pll0, regmap, &videocc_pll0_config);
339 
340 	/* Keep some clocks always-on */
341 	qcom_branch_set_clk_en(regmap, 0x984); /* VIDEOCC_XO_CLK */
342 
343 	return qcom_cc_really_probe(&pdev->dev, &videocc_sm7150_desc, regmap);
344 }
345 
346 static struct platform_driver videocc_sm7150_driver = {
347 	.probe = videocc_sm7150_probe,
348 	.driver = {
349 		.name = "videocc-sm7150",
350 		.of_match_table = videocc_sm7150_match_table,
351 	},
352 };
353 module_platform_driver(videocc_sm7150_driver);
354 
355 MODULE_DESCRIPTION("Qualcomm SM7150 Video Clock Controller");
356 MODULE_LICENSE("GPL");
357