1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4 */
5 #include <linux/clk-provider.h>
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
8 #include <linux/pm_runtime.h>
9 #include <linux/regmap.h>
10
11 #include <dt-bindings/clock/qcom,sm8750-gpucc.h>
12
13 #include "clk-alpha-pll.h"
14 #include "clk-branch.h"
15 #include "clk-rcg.h"
16 #include "clk-regmap.h"
17 #include "clk-regmap-divider.h"
18 #include "clk-regmap-mux.h"
19 #include "gdsc.h"
20 #include "reset.h"
21
22 enum {
23 DT_BI_TCXO,
24 DT_GPLL0_OUT_MAIN,
25 DT_GPLL0_OUT_MAIN_DIV,
26 };
27
28 enum {
29 P_BI_TCXO,
30 P_GPLL0_OUT_MAIN,
31 P_GPLL0_OUT_MAIN_DIV,
32 P_GPU_CC_PLL0_OUT_EVEN,
33 P_GPU_CC_PLL0_OUT_MAIN,
34 P_GPU_CC_PLL0_OUT_ODD,
35 };
36
37 static const struct pll_vco taycan_elu_vco[] = {
38 { 249600000, 2500000000, 0 },
39 };
40
41 static const struct alpha_pll_config gpu_cc_pll0_config = {
42 .l = 0x34,
43 .alpha = 0x1555,
44 .config_ctl_val = 0x19660387,
45 .config_ctl_hi_val = 0x098060a0,
46 .config_ctl_hi1_val = 0xb416cb20,
47 .user_ctl_val = 0x00000400,
48 .user_ctl_hi_val = 0x00000002,
49 };
50
51 static struct clk_alpha_pll gpu_cc_pll0 = {
52 .offset = 0x0,
53 .config = &gpu_cc_pll0_config,
54 .vco_table = taycan_elu_vco,
55 .num_vco = ARRAY_SIZE(taycan_elu_vco),
56 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
57 .clkr = {
58 .hw.init = &(const struct clk_init_data) {
59 .name = "gpu_cc_pll0",
60 .parent_data = &(const struct clk_parent_data) {
61 .index = DT_BI_TCXO,
62 },
63 .num_parents = 1,
64 .ops = &clk_alpha_pll_taycan_elu_ops,
65 },
66 },
67 };
68
69 static const struct clk_div_table post_div_table_gpu_cc_pll0_out_even[] = {
70 { 0x1, 2 },
71 { }
72 };
73
74 static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = {
75 .offset = 0x0,
76 .post_div_shift = 10,
77 .post_div_table = post_div_table_gpu_cc_pll0_out_even,
78 .num_post_div = ARRAY_SIZE(post_div_table_gpu_cc_pll0_out_even),
79 .width = 4,
80 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_ELU],
81 .clkr.hw.init = &(const struct clk_init_data) {
82 .name = "gpu_cc_pll0_out_even",
83 .parent_hws = (const struct clk_hw*[]) {
84 &gpu_cc_pll0.clkr.hw,
85 },
86 .num_parents = 1,
87 .flags = CLK_SET_RATE_PARENT,
88 .ops = &clk_alpha_pll_postdiv_taycan_elu_ops,
89 },
90 };
91
92 static const struct parent_map gpu_cc_parent_map_1[] = {
93 { P_BI_TCXO, 0 },
94 { P_GPU_CC_PLL0_OUT_MAIN, 1 },
95 { P_GPU_CC_PLL0_OUT_EVEN, 2 },
96 { P_GPU_CC_PLL0_OUT_ODD, 3 },
97 { P_GPLL0_OUT_MAIN, 5 },
98 { P_GPLL0_OUT_MAIN_DIV, 6 },
99 };
100
101 static const struct clk_parent_data gpu_cc_parent_data_1[] = {
102 { .index = DT_BI_TCXO },
103 { .hw = &gpu_cc_pll0.clkr.hw },
104 { .hw = &gpu_cc_pll0_out_even.clkr.hw },
105 { .hw = &gpu_cc_pll0.clkr.hw },
106 { .index = DT_GPLL0_OUT_MAIN },
107 { .index = DT_GPLL0_OUT_MAIN_DIV },
108 };
109
110 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
111 F(19200000, P_BI_TCXO, 1, 0, 0),
112 F(500000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0),
113 F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0),
114 F(687500000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0),
115 { }
116 };
117
118 static struct clk_rcg2 gpu_cc_gmu_clk_src = {
119 .cmd_rcgr = 0x9318,
120 .mnd_width = 0,
121 .hid_width = 5,
122 .parent_map = gpu_cc_parent_map_1,
123 .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
124 .clkr.hw.init = &(const struct clk_init_data) {
125 .name = "gpu_cc_gmu_clk_src",
126 .parent_data = gpu_cc_parent_data_1,
127 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
128 .flags = CLK_SET_RATE_PARENT,
129 .ops = &clk_rcg2_shared_ops,
130 },
131 };
132
133 static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = {
134 F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
135 F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
136 F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0),
137 { }
138 };
139
140 static struct clk_rcg2 gpu_cc_hub_clk_src = {
141 .cmd_rcgr = 0x93ec,
142 .mnd_width = 0,
143 .hid_width = 5,
144 .parent_map = gpu_cc_parent_map_1,
145 .freq_tbl = ftbl_gpu_cc_hub_clk_src,
146 .clkr.hw.init = &(const struct clk_init_data) {
147 .name = "gpu_cc_hub_clk_src",
148 .parent_data = gpu_cc_parent_data_1,
149 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
150 .flags = CLK_SET_RATE_PARENT,
151 .ops = &clk_rcg2_shared_ops,
152 },
153 };
154
155 static struct clk_regmap_div gpu_cc_hub_div_clk_src = {
156 .reg = 0x942c,
157 .shift = 0,
158 .width = 4,
159 .clkr.hw.init = &(const struct clk_init_data) {
160 .name = "gpu_cc_hub_div_clk_src",
161 .parent_hws = (const struct clk_hw*[]) {
162 &gpu_cc_hub_clk_src.clkr.hw,
163 },
164 .num_parents = 1,
165 .flags = CLK_SET_RATE_PARENT,
166 .ops = &clk_regmap_div_ro_ops,
167 },
168 };
169
170 static struct clk_branch gpu_cc_ahb_clk = {
171 .halt_reg = 0x90bc,
172 .halt_check = BRANCH_HALT_DELAY,
173 .clkr = {
174 .enable_reg = 0x90bc,
175 .enable_mask = BIT(0),
176 .hw.init = &(const struct clk_init_data) {
177 .name = "gpu_cc_ahb_clk",
178 .parent_hws = (const struct clk_hw*[]) {
179 &gpu_cc_hub_div_clk_src.clkr.hw,
180 },
181 .num_parents = 1,
182 .flags = CLK_SET_RATE_PARENT,
183 .ops = &clk_branch2_ops,
184 },
185 },
186 };
187
188 static struct clk_branch gpu_cc_cx_accu_shift_clk = {
189 .halt_reg = 0x910c,
190 .halt_check = BRANCH_HALT_VOTED,
191 .clkr = {
192 .enable_reg = 0x910c,
193 .enable_mask = BIT(0),
194 .hw.init = &(const struct clk_init_data) {
195 .name = "gpu_cc_cx_accu_shift_clk",
196 .ops = &clk_branch2_ops,
197 },
198 },
199 };
200
201 static struct clk_branch gpu_cc_cx_gmu_clk = {
202 .halt_reg = 0x90d4,
203 .halt_check = BRANCH_HALT_VOTED,
204 .clkr = {
205 .enable_reg = 0x90d4,
206 .enable_mask = BIT(0),
207 .hw.init = &(const struct clk_init_data) {
208 .name = "gpu_cc_cx_gmu_clk",
209 .parent_hws = (const struct clk_hw*[]) {
210 &gpu_cc_gmu_clk_src.clkr.hw,
211 },
212 .num_parents = 1,
213 .flags = CLK_SET_RATE_PARENT,
214 .ops = &clk_branch2_aon_ops,
215 },
216 },
217 };
218
219 static struct clk_branch gpu_cc_cxo_clk = {
220 .halt_reg = 0x90e4,
221 .halt_check = BRANCH_HALT,
222 .clkr = {
223 .enable_reg = 0x90e4,
224 .enable_mask = BIT(0),
225 .hw.init = &(const struct clk_init_data) {
226 .name = "gpu_cc_cxo_clk",
227 .ops = &clk_branch2_ops,
228 },
229 },
230 };
231
232 static struct clk_branch gpu_cc_demet_clk = {
233 .halt_reg = 0x9010,
234 .halt_check = BRANCH_HALT_VOTED,
235 .clkr = {
236 .enable_reg = 0x9010,
237 .enable_mask = BIT(0),
238 .hw.init = &(const struct clk_init_data) {
239 .name = "gpu_cc_demet_clk",
240 .ops = &clk_branch2_ops,
241 },
242 },
243 };
244
245 static struct clk_branch gpu_cc_dpm_clk = {
246 .halt_reg = 0x9110,
247 .halt_check = BRANCH_HALT,
248 .clkr = {
249 .enable_reg = 0x9110,
250 .enable_mask = BIT(0),
251 .hw.init = &(const struct clk_init_data) {
252 .name = "gpu_cc_dpm_clk",
253 .ops = &clk_branch2_ops,
254 },
255 },
256 };
257
258 static struct clk_branch gpu_cc_freq_measure_clk = {
259 .halt_reg = 0x900c,
260 .halt_check = BRANCH_HALT,
261 .clkr = {
262 .enable_reg = 0x900c,
263 .enable_mask = BIT(0),
264 .hw.init = &(const struct clk_init_data) {
265 .name = "gpu_cc_freq_measure_clk",
266 .ops = &clk_branch2_ops,
267 },
268 },
269 };
270
271 static struct clk_branch gpu_cc_gx_accu_shift_clk = {
272 .halt_reg = 0x9070,
273 .halt_check = BRANCH_HALT_VOTED,
274 .clkr = {
275 .enable_reg = 0x9070,
276 .enable_mask = BIT(0),
277 .hw.init = &(const struct clk_init_data) {
278 .name = "gpu_cc_gx_accu_shift_clk",
279 .ops = &clk_branch2_ops,
280 },
281 },
282 };
283
284 static struct clk_branch gpu_cc_gx_gmu_clk = {
285 .halt_reg = 0x9060,
286 .halt_check = BRANCH_HALT,
287 .clkr = {
288 .enable_reg = 0x9060,
289 .enable_mask = BIT(0),
290 .hw.init = &(const struct clk_init_data) {
291 .name = "gpu_cc_gx_gmu_clk",
292 .parent_hws = (const struct clk_hw*[]) {
293 &gpu_cc_gmu_clk_src.clkr.hw,
294 },
295 .num_parents = 1,
296 .flags = CLK_SET_RATE_PARENT,
297 .ops = &clk_branch2_ops,
298 },
299 },
300 };
301
302 static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
303 .halt_reg = 0x7000,
304 .halt_check = BRANCH_HALT_VOTED,
305 .clkr = {
306 .enable_reg = 0x7000,
307 .enable_mask = BIT(0),
308 .hw.init = &(const struct clk_init_data) {
309 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
310 .ops = &clk_branch2_ops,
311 },
312 },
313 };
314
315 static struct clk_branch gpu_cc_hub_aon_clk = {
316 .halt_reg = 0x93e8,
317 .halt_check = BRANCH_HALT_VOTED,
318 .clkr = {
319 .enable_reg = 0x93e8,
320 .enable_mask = BIT(0),
321 .hw.init = &(const struct clk_init_data) {
322 .name = "gpu_cc_hub_aon_clk",
323 .parent_hws = (const struct clk_hw*[]) {
324 &gpu_cc_hub_clk_src.clkr.hw,
325 },
326 .num_parents = 1,
327 .flags = CLK_SET_RATE_PARENT,
328 .ops = &clk_branch2_aon_ops,
329 },
330 },
331 };
332
333 static struct clk_branch gpu_cc_hub_cx_int_clk = {
334 .halt_reg = 0x90e8,
335 .halt_check = BRANCH_HALT_VOTED,
336 .clkr = {
337 .enable_reg = 0x90e8,
338 .enable_mask = BIT(0),
339 .hw.init = &(const struct clk_init_data) {
340 .name = "gpu_cc_hub_cx_int_clk",
341 .parent_hws = (const struct clk_hw*[]) {
342 &gpu_cc_hub_clk_src.clkr.hw,
343 },
344 .num_parents = 1,
345 .flags = CLK_SET_RATE_PARENT,
346 .ops = &clk_branch2_aon_ops,
347 },
348 },
349 };
350
351 static struct clk_branch gpu_cc_memnoc_gfx_clk = {
352 .halt_reg = 0x90f4,
353 .halt_check = BRANCH_HALT_VOTED,
354 .clkr = {
355 .enable_reg = 0x90f4,
356 .enable_mask = BIT(0),
357 .hw.init = &(const struct clk_init_data) {
358 .name = "gpu_cc_memnoc_gfx_clk",
359 .ops = &clk_branch2_ops,
360 },
361 },
362 };
363
364 static struct gdsc gpu_cc_cx_gdsc = {
365 .gdscr = 0x9080,
366 .gds_hw_ctrl = 0x9094,
367 .en_rest_wait_val = 0x2,
368 .en_few_wait_val = 0x2,
369 .clk_dis_wait_val = 0x8,
370 .pd = {
371 .name = "gpu_cc_cx_gdsc",
372 },
373 .pwrsts = PWRSTS_OFF_ON,
374 .flags = RETAIN_FF_ENABLE | VOTABLE,
375 };
376
377 static struct clk_regmap *gpu_cc_sm8750_clocks[] = {
378 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
379 [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr,
380 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
381 [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
382 [GPU_CC_DEMET_CLK] = &gpu_cc_demet_clk.clkr,
383 [GPU_CC_DPM_CLK] = &gpu_cc_dpm_clk.clkr,
384 [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr,
385 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
386 [GPU_CC_GX_ACCU_SHIFT_CLK] = &gpu_cc_gx_accu_shift_clk.clkr,
387 [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
388 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
389 [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,
390 [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,
391 [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,
392 [GPU_CC_HUB_DIV_CLK_SRC] = &gpu_cc_hub_div_clk_src.clkr,
393 [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr,
394 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
395 [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
396 };
397
398 static struct gdsc *gpu_cc_sm8750_gdscs[] = {
399 [GPU_CC_CX_GDSC] = &gpu_cc_cx_gdsc,
400 };
401
402 static const struct qcom_reset_map gpu_cc_sm8750_resets[] = {
403 [GPU_CC_GPU_CC_XO_BCR] = { 0x9000 },
404 [GPU_CC_GPU_CC_GX_BCR] = { 0x905c },
405 [GPU_CC_GPU_CC_CX_BCR] = { 0x907c },
406 [GPU_CC_GPU_CC_GMU_BCR] = { 0x9314 },
407 [GPU_CC_GPU_CC_CB_BCR] = { 0x93a0 },
408 [GPU_CC_GPU_CC_FAST_HUB_BCR] = { 0x93e4 },
409 };
410
411 static const struct regmap_config gpu_cc_sm8750_regmap_config = {
412 .reg_bits = 32,
413 .reg_stride = 4,
414 .val_bits = 32,
415 .max_register = 0x9800,
416 .fast_io = true,
417 };
418
419 static struct clk_alpha_pll *gpu_cc_alpha_plls[] = {
420 &gpu_cc_pll0,
421 };
422
423 static const u32 gpu_cc_sm8750_critical_cbcrs[] = {
424 0x9004, /* GPU_CC_RSCC_XO_AON_CLK */
425 0x9008, /* GPU_CC_CXO_AON_CLK */
426 0x9064, /* GPU_CC_GX_AHB_FF_CLK */
427 0x90cc, /* GPU_CC_SLEEP_CLK */
428 0x93a4, /* GPU_CC_CB_CLK */
429 0x93a8, /* GPU_CC_RSCC_HUB_AON_CLK */
430 };
431
432 static const struct qcom_cc_driver_data gpu_cc_sm8750_driver_data = {
433 .alpha_plls = gpu_cc_alpha_plls,
434 .num_alpha_plls = ARRAY_SIZE(gpu_cc_alpha_plls),
435 .clk_cbcrs = gpu_cc_sm8750_critical_cbcrs,
436 .num_clk_cbcrs = ARRAY_SIZE(gpu_cc_sm8750_critical_cbcrs),
437 };
438
439 static const struct qcom_cc_desc gpu_cc_sm8750_desc = {
440 .config = &gpu_cc_sm8750_regmap_config,
441 .clks = gpu_cc_sm8750_clocks,
442 .num_clks = ARRAY_SIZE(gpu_cc_sm8750_clocks),
443 .resets = gpu_cc_sm8750_resets,
444 .num_resets = ARRAY_SIZE(gpu_cc_sm8750_resets),
445 .gdscs = gpu_cc_sm8750_gdscs,
446 .num_gdscs = ARRAY_SIZE(gpu_cc_sm8750_gdscs),
447 .use_rpm = true,
448 .driver_data = &gpu_cc_sm8750_driver_data,
449 };
450
451 static const struct of_device_id gpu_cc_sm8750_match_table[] = {
452 { .compatible = "qcom,sm8750-gpucc" },
453 { }
454 };
455 MODULE_DEVICE_TABLE(of, gpu_cc_sm8750_match_table);
456
gpu_cc_sm8750_probe(struct platform_device * pdev)457 static int gpu_cc_sm8750_probe(struct platform_device *pdev)
458 {
459 return qcom_cc_probe(pdev, &gpu_cc_sm8750_desc);
460 }
461
462 static struct platform_driver gpu_cc_sm8750_driver = {
463 .probe = gpu_cc_sm8750_probe,
464 .driver = {
465 .name = "sm8750-gpucc",
466 .of_match_table = gpu_cc_sm8750_match_table,
467 },
468 };
469 module_platform_driver(gpu_cc_sm8750_driver);
470
471 MODULE_DESCRIPTION("QTI GPU_CC SM8750 Driver");
472 MODULE_LICENSE("GPL");
473