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 | |
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(dev: &pdev->dev); |
442 | if (ret) |
443 | return ret; |
444 | |
445 | ret = pm_runtime_resume_and_get(dev: &pdev->dev); |
446 | if (ret) |
447 | return ret; |
448 | |
449 | regmap = qcom_cc_map(pdev, desc: &gpucc_sm6375_desc); |
450 | if (IS_ERR(ptr: regmap)) { |
451 | pm_runtime_put(dev: &pdev->dev); |
452 | return PTR_ERR(ptr: 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, desc: &gpucc_sm6375_desc, regmap); |
459 | pm_runtime_put(dev: &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 | |