xref: /openbmc/linux/drivers/clk/qcom/gpucc-sm6375.c (revision a96cbb14)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
4  * Copyright (c) 2023, Linaro Limited
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/pm_runtime.h>
12 #include <linux/regmap.h>
13 
14 #include <dt-bindings/clock/qcom,sm6375-gpucc.h>
15 
16 #include "clk-alpha-pll.h"
17 #include "clk-branch.h"
18 #include "clk-rcg.h"
19 #include "clk-regmap.h"
20 #include "clk-regmap-divider.h"
21 #include "clk-regmap-mux.h"
22 #include "clk-regmap-phy-mux.h"
23 #include "gdsc.h"
24 #include "reset.h"
25 
26 enum {
27 	DT_BI_TCXO,
28 	DT_GCC_GPU_GPLL0_CLK_SRC,
29 	DT_GCC_GPU_GPLL0_DIV_CLK_SRC,
30 	DT_GCC_GPU_SNOC_DVM_GFX_CLK,
31 };
32 
33 enum {
34 	P_BI_TCXO,
35 	P_GCC_GPU_GPLL0_CLK_SRC,
36 	P_GCC_GPU_GPLL0_DIV_CLK_SRC,
37 	P_GPU_CC_PLL0_OUT_EVEN,
38 	P_GPU_CC_PLL0_OUT_MAIN,
39 	P_GPU_CC_PLL0_OUT_ODD,
40 	P_GPU_CC_PLL1_OUT_EVEN,
41 	P_GPU_CC_PLL1_OUT_MAIN,
42 	P_GPU_CC_PLL1_OUT_ODD,
43 };
44 
45 static struct pll_vco lucid_vco[] = {
46 	{ 249600000, 2000000000, 0 },
47 };
48 
49 /* 532MHz Configuration */
50 static const struct alpha_pll_config gpucc_pll0_config = {
51 	.l = 0x1b,
52 	.alpha = 0xb555,
53 	.config_ctl_val = 0x20485699,
54 	.config_ctl_hi_val = 0x00002261,
55 	.config_ctl_hi1_val = 0x329a299c,
56 	.user_ctl_val = 0x00000001,
57 	.user_ctl_hi_val = 0x00000805,
58 	.user_ctl_hi1_val = 0x00000000,
59 };
60 
61 static struct clk_alpha_pll gpucc_pll0 = {
62 	.offset = 0x0,
63 	.vco_table = lucid_vco,
64 	.num_vco = ARRAY_SIZE(lucid_vco),
65 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
66 	.clkr = {
67 		.hw.init = &(struct clk_init_data){
68 			.name = "gpucc_pll0",
69 			.parent_data = &(const struct clk_parent_data){
70 				.index = P_BI_TCXO,
71 			},
72 			.num_parents = 1,
73 			.ops = &clk_alpha_pll_lucid_ops,
74 		},
75 	},
76 };
77 
78 /* 514MHz Configuration */
79 static const struct alpha_pll_config gpucc_pll1_config = {
80 	.l = 0x1a,
81 	.alpha = 0xc555,
82 	.config_ctl_val = 0x20485699,
83 	.config_ctl_hi_val = 0x00002261,
84 	.config_ctl_hi1_val = 0x329a299c,
85 	.user_ctl_val = 0x00000001,
86 	.user_ctl_hi_val = 0x00000805,
87 	.user_ctl_hi1_val = 0x00000000,
88 };
89 
90 static struct clk_alpha_pll gpucc_pll1 = {
91 	.offset = 0x100,
92 	.vco_table = lucid_vco,
93 	.num_vco = ARRAY_SIZE(lucid_vco),
94 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
95 	.clkr = {
96 		.hw.init = &(struct clk_init_data){
97 			.name = "gpucc_pll1",
98 			.parent_data = &(const struct clk_parent_data){
99 				.index = P_BI_TCXO,
100 			},
101 			.num_parents = 1,
102 			.ops = &clk_alpha_pll_lucid_ops,
103 		},
104 	},
105 };
106 
107 static const struct parent_map gpucc_parent_map_0[] = {
108 	{ P_BI_TCXO, 0 },
109 	{ P_GPU_CC_PLL0_OUT_MAIN, 1 },
110 	{ P_GPU_CC_PLL1_OUT_MAIN, 3 },
111 	{ P_GCC_GPU_GPLL0_CLK_SRC, 5 },
112 	{ P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 },
113 };
114 
115 static const struct clk_parent_data gpucc_parent_data_0[] = {
116 	{ .index = P_BI_TCXO },
117 	{ .hw = &gpucc_pll0.clkr.hw },
118 	{ .hw = &gpucc_pll1.clkr.hw },
119 	{ .index = DT_GCC_GPU_GPLL0_CLK_SRC },
120 	{ .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC },
121 };
122 
123 static const struct parent_map gpucc_parent_map_1[] = {
124 	{ P_BI_TCXO, 0 },
125 	{ P_GPU_CC_PLL0_OUT_EVEN, 1 },
126 	{ P_GPU_CC_PLL0_OUT_ODD, 2 },
127 	{ P_GPU_CC_PLL1_OUT_EVEN, 3 },
128 	{ P_GPU_CC_PLL1_OUT_ODD, 4 },
129 	{ P_GCC_GPU_GPLL0_CLK_SRC, 5 },
130 };
131 
132 static const struct clk_parent_data gpucc_parent_data_1[] = {
133 	{ .index = P_BI_TCXO },
134 	{ .hw = &gpucc_pll0.clkr.hw },
135 	{ .hw = &gpucc_pll0.clkr.hw },
136 	{ .hw = &gpucc_pll1.clkr.hw },
137 	{ .hw = &gpucc_pll1.clkr.hw },
138 	{ .index = DT_GCC_GPU_GPLL0_CLK_SRC },
139 };
140 
141 static const struct freq_tbl ftbl_gpucc_gmu_clk_src[] = {
142 	F(200000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 1.5, 0, 0),
143 	{ }
144 };
145 
146 static struct clk_rcg2 gpucc_gmu_clk_src = {
147 	.cmd_rcgr = 0x1120,
148 	.mnd_width = 0,
149 	.hid_width = 5,
150 	.parent_map = gpucc_parent_map_0,
151 	.freq_tbl = ftbl_gpucc_gmu_clk_src,
152 	.clkr.hw.init = &(struct clk_init_data){
153 		.name = "gpucc_gmu_clk_src",
154 		.parent_data = gpucc_parent_data_0,
155 		.num_parents = ARRAY_SIZE(gpucc_parent_data_0),
156 		.ops = &clk_rcg2_shared_ops,
157 	},
158 };
159 
160 static const struct freq_tbl ftbl_gpucc_gx_gfx3d_clk_src[] = {
161 	F(266000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
162 	F(390000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
163 	F(490000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
164 	F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
165 	F(770000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
166 	F(840000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
167 	F(900000000, P_GPU_CC_PLL0_OUT_EVEN, 2, 0, 0),
168 	{ }
169 };
170 
171 static struct clk_rcg2 gpucc_gx_gfx3d_clk_src = {
172 	.cmd_rcgr = 0x101c,
173 	.mnd_width = 0,
174 	.hid_width = 5,
175 	.parent_map = gpucc_parent_map_1,
176 	.freq_tbl = ftbl_gpucc_gx_gfx3d_clk_src,
177 	.clkr.hw.init = &(struct clk_init_data){
178 		.name = "gpucc_gx_gfx3d_clk_src",
179 		.parent_data = gpucc_parent_data_1,
180 		.num_parents = ARRAY_SIZE(gpucc_parent_data_1),
181 		.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
182 		.ops = &clk_rcg2_ops,
183 	},
184 };
185 
186 static struct clk_branch gpucc_ahb_clk = {
187 	.halt_reg = 0x1078,
188 	.halt_check = BRANCH_HALT_DELAY,
189 	.clkr = {
190 		.enable_reg = 0x1078,
191 		.enable_mask = BIT(0),
192 		.hw.init = &(struct clk_init_data){
193 			.name = "gpucc_ahb_clk",
194 			.flags = CLK_IS_CRITICAL,
195 			.ops = &clk_branch2_ops,
196 		},
197 	},
198 };
199 
200 static struct clk_branch gpucc_cx_gfx3d_clk = {
201 	.halt_reg = 0x10a4,
202 	.halt_check = BRANCH_HALT_DELAY,
203 	.clkr = {
204 		.enable_reg = 0x10a4,
205 		.enable_mask = BIT(0),
206 		.hw.init = &(struct clk_init_data){
207 			.name = "gpucc_cx_gfx3d_clk",
208 			.parent_hws = (const struct clk_hw*[]) {
209 				&gpucc_gx_gfx3d_clk_src.clkr.hw,
210 			},
211 			.num_parents = 1,
212 			.flags = CLK_SET_RATE_PARENT,
213 			.ops = &clk_branch2_ops,
214 		},
215 	},
216 };
217 
218 static struct clk_branch gpucc_cx_gfx3d_slv_clk = {
219 	.halt_reg = 0x10a8,
220 	.halt_check = BRANCH_HALT_DELAY,
221 	.clkr = {
222 		.enable_reg = 0x10a8,
223 		.enable_mask = BIT(0),
224 		.hw.init = &(struct clk_init_data){
225 			.name = "gpucc_cx_gfx3d_slv_clk",
226 			.parent_hws = (const struct clk_hw*[]) {
227 				&gpucc_gx_gfx3d_clk_src.clkr.hw,
228 			},
229 			.num_parents = 1,
230 			.flags = CLK_SET_RATE_PARENT,
231 			.ops = &clk_branch2_ops,
232 		},
233 	},
234 };
235 
236 static struct clk_branch gpucc_cx_gmu_clk = {
237 	.halt_reg = 0x1098,
238 	.halt_check = BRANCH_HALT,
239 	.clkr = {
240 		.enable_reg = 0x1098,
241 		.enable_mask = BIT(0),
242 		.hw.init = &(struct clk_init_data){
243 			.name = "gpucc_cx_gmu_clk",
244 			.parent_hws = (const struct clk_hw*[]) {
245 				&gpucc_gmu_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 gpucc_cx_snoc_dvm_clk = {
255 	.halt_reg = 0x108c,
256 	.halt_check = BRANCH_HALT_DELAY,
257 	.clkr = {
258 		.enable_reg = 0x108c,
259 		.enable_mask = BIT(0),
260 		.hw.init = &(struct clk_init_data){
261 			.name = "gpucc_cx_snoc_dvm_clk",
262 			.parent_data = &(const struct clk_parent_data){
263 				.index = DT_GCC_GPU_SNOC_DVM_GFX_CLK,
264 			},
265 			.num_parents = 1,
266 			.ops = &clk_branch2_ops,
267 		},
268 	},
269 };
270 
271 static struct clk_branch gpucc_cxo_aon_clk = {
272 	.halt_reg = 0x1004,
273 	.halt_check = BRANCH_HALT_DELAY,
274 	.clkr = {
275 		.enable_reg = 0x1004,
276 		.enable_mask = BIT(0),
277 		.hw.init = &(struct clk_init_data){
278 			.name = "gpucc_cxo_aon_clk",
279 			.ops = &clk_branch2_ops,
280 		},
281 	},
282 };
283 
284 static struct clk_branch gpucc_cxo_clk = {
285 	.halt_reg = 0x109c,
286 	.halt_check = BRANCH_HALT,
287 	.clkr = {
288 		.enable_reg = 0x109c,
289 		.enable_mask = BIT(0),
290 		.hw.init = &(struct clk_init_data){
291 			.name = "gpucc_cxo_clk",
292 			.ops = &clk_branch2_ops,
293 		},
294 	},
295 };
296 
297 static struct clk_branch gpucc_gx_cxo_clk = {
298 	.halt_reg = 0x1060,
299 	.halt_check = BRANCH_HALT_DELAY,
300 	.clkr = {
301 		.enable_reg = 0x1060,
302 		.enable_mask = BIT(0),
303 		.hw.init = &(struct clk_init_data){
304 			.name = "gpucc_gx_cxo_clk",
305 			.flags = CLK_IS_CRITICAL,
306 			.ops = &clk_branch2_ops,
307 		},
308 	},
309 };
310 
311 static struct clk_branch gpucc_gx_gfx3d_clk = {
312 	.halt_reg = 0x1054,
313 	.halt_check = BRANCH_HALT_DELAY,
314 	.clkr = {
315 		.enable_reg = 0x1054,
316 		.enable_mask = BIT(0),
317 		.hw.init = &(struct clk_init_data){
318 			.name = "gpucc_gx_gfx3d_clk",
319 			.parent_hws = (const struct clk_hw*[]) {
320 				&gpucc_gx_gfx3d_clk_src.clkr.hw,
321 			},
322 			.num_parents = 1,
323 			.flags = CLK_SET_RATE_PARENT,
324 			.ops = &clk_branch2_ops,
325 		},
326 	},
327 };
328 
329 static struct clk_branch gpucc_gx_gmu_clk = {
330 	.halt_reg = 0x1064,
331 	.halt_check = BRANCH_HALT,
332 	.clkr = {
333 		.enable_reg = 0x1064,
334 		.enable_mask = BIT(0),
335 		.hw.init = &(struct clk_init_data){
336 			.name = "gpucc_gx_gmu_clk",
337 			.parent_hws = (const struct clk_hw*[]) {
338 				&gpucc_gmu_clk_src.clkr.hw,
339 			},
340 			.num_parents = 1,
341 			.flags = CLK_SET_RATE_PARENT,
342 			.ops = &clk_branch2_ops,
343 		},
344 	},
345 };
346 
347 static struct clk_branch gpucc_sleep_clk = {
348 	.halt_reg = 0x1090,
349 	.halt_check = BRANCH_HALT_VOTED,
350 	.clkr = {
351 		.enable_reg = 0x1090,
352 		.enable_mask = BIT(0),
353 		.hw.init = &(struct clk_init_data){
354 			.name = "gpucc_sleep_clk",
355 			.ops = &clk_branch2_ops,
356 		},
357 	},
358 };
359 
360 static struct gdsc gpu_cx_gdsc = {
361 	.gdscr = 0x106c,
362 	.gds_hw_ctrl = 0x1540,
363 	.clk_dis_wait_val = 8,
364 	.pd = {
365 		.name = "gpu_cx_gdsc",
366 	},
367 	.pwrsts = PWRSTS_OFF_ON,
368 	.flags = VOTABLE,
369 };
370 
371 static struct gdsc gpu_gx_gdsc = {
372 	.gdscr = 0x100c,
373 	.clamp_io_ctrl = 0x1508,
374 	.resets = (unsigned int []){ GPU_GX_BCR, GPU_ACD_BCR, GPU_GX_ACD_MISC_BCR },
375 	.reset_count = 3,
376 	.pd = {
377 		.name = "gpu_gx_gdsc",
378 	},
379 	.pwrsts = PWRSTS_OFF_ON,
380 	.flags = CLAMP_IO | SW_RESET | AON_RESET,
381 };
382 
383 static struct clk_regmap *gpucc_sm6375_clocks[] = {
384 	[GPU_CC_AHB_CLK] = &gpucc_ahb_clk.clkr,
385 	[GPU_CC_CX_GFX3D_CLK] = &gpucc_cx_gfx3d_clk.clkr,
386 	[GPU_CC_CX_GFX3D_SLV_CLK] = &gpucc_cx_gfx3d_slv_clk.clkr,
387 	[GPU_CC_CX_GMU_CLK] = &gpucc_cx_gmu_clk.clkr,
388 	[GPU_CC_CX_SNOC_DVM_CLK] = &gpucc_cx_snoc_dvm_clk.clkr,
389 	[GPU_CC_CXO_AON_CLK] = &gpucc_cxo_aon_clk.clkr,
390 	[GPU_CC_CXO_CLK] = &gpucc_cxo_clk.clkr,
391 	[GPU_CC_GMU_CLK_SRC] = &gpucc_gmu_clk_src.clkr,
392 	[GPU_CC_GX_CXO_CLK] = &gpucc_gx_cxo_clk.clkr,
393 	[GPU_CC_GX_GFX3D_CLK] = &gpucc_gx_gfx3d_clk.clkr,
394 	[GPU_CC_GX_GFX3D_CLK_SRC] = &gpucc_gx_gfx3d_clk_src.clkr,
395 	[GPU_CC_GX_GMU_CLK] = &gpucc_gx_gmu_clk.clkr,
396 	[GPU_CC_PLL0] = &gpucc_pll0.clkr,
397 	[GPU_CC_PLL1] = &gpucc_pll1.clkr,
398 	[GPU_CC_SLEEP_CLK] = &gpucc_sleep_clk.clkr,
399 };
400 
401 static const struct qcom_reset_map gpucc_sm6375_resets[] = {
402 	[GPU_GX_BCR] = { 0x1008 },
403 	[GPU_ACD_BCR] = { 0x1160 },
404 	[GPU_GX_ACD_MISC_BCR] = { 0x8004 },
405 };
406 
407 static struct gdsc *gpucc_sm6375_gdscs[] = {
408 	[GPU_CX_GDSC] = &gpu_cx_gdsc,
409 	[GPU_GX_GDSC] = &gpu_gx_gdsc,
410 };
411 
412 static const struct regmap_config gpucc_sm6375_regmap_config = {
413 	.reg_bits = 32,
414 	.reg_stride = 4,
415 	.val_bits = 32,
416 	.max_register = 0x9000,
417 	.fast_io = true,
418 };
419 
420 static const struct qcom_cc_desc gpucc_sm6375_desc = {
421 	.config = &gpucc_sm6375_regmap_config,
422 	.clks = gpucc_sm6375_clocks,
423 	.num_clks = ARRAY_SIZE(gpucc_sm6375_clocks),
424 	.resets = gpucc_sm6375_resets,
425 	.num_resets = ARRAY_SIZE(gpucc_sm6375_resets),
426 	.gdscs = gpucc_sm6375_gdscs,
427 	.num_gdscs = ARRAY_SIZE(gpucc_sm6375_gdscs),
428 };
429 
430 static const struct of_device_id gpucc_sm6375_match_table[] = {
431 	{ .compatible = "qcom,sm6375-gpucc" },
432 	{ }
433 };
434 MODULE_DEVICE_TABLE(of, gpucc_sm6375_match_table);
435 
gpucc_sm6375_probe(struct platform_device * pdev)436 static int gpucc_sm6375_probe(struct platform_device *pdev)
437 {
438 	struct regmap *regmap;
439 	int ret;
440 
441 	ret = devm_pm_runtime_enable(&pdev->dev);
442 	if (ret)
443 		return ret;
444 
445 	ret = pm_runtime_resume_and_get(&pdev->dev);
446 	if (ret)
447 		return ret;
448 
449 	regmap = qcom_cc_map(pdev, &gpucc_sm6375_desc);
450 	if (IS_ERR(regmap)) {
451 		pm_runtime_put(&pdev->dev);
452 		return PTR_ERR(regmap);
453 	}
454 
455 	clk_lucid_pll_configure(&gpucc_pll0, regmap, &gpucc_pll0_config);
456 	clk_lucid_pll_configure(&gpucc_pll1, regmap, &gpucc_pll1_config);
457 
458 	ret = qcom_cc_really_probe(pdev, &gpucc_sm6375_desc, regmap);
459 	pm_runtime_put(&pdev->dev);
460 
461 	return ret;
462 }
463 
464 static struct platform_driver gpucc_sm6375_driver = {
465 	.probe = gpucc_sm6375_probe,
466 	.driver = {
467 		.name = "gpucc-sm6375",
468 		.of_match_table = gpucc_sm6375_match_table,
469 	},
470 };
471 module_platform_driver(gpucc_sm6375_driver);
472 
473 MODULE_DESCRIPTION("QTI GPUCC SM6375 Driver");
474 MODULE_LICENSE("GPL");
475