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