Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
4 * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.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,milos-gpucc.h>
14
15#include "clk-alpha-pll.h"
16#include "clk-branch.h"
17#include "clk-pll.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 "common.h"
23#include "gdsc.h"
24#include "reset.h"
25
26/* Need to match the order of clocks in DT binding */
27enum {
28 DT_BI_TCXO,
29 DT_GPLL0_OUT_MAIN,
30 DT_GPLL0_OUT_MAIN_DIV,
31};
32
33enum {
34 P_BI_TCXO,
35 P_GPLL0_OUT_MAIN,
36 P_GPLL0_OUT_MAIN_DIV,
37 P_GPU_CC_PLL0_OUT_EVEN,
38 P_GPU_CC_PLL0_OUT_MAIN,
39 P_GPU_CC_PLL0_OUT_ODD,
40};
41
42static const struct pll_vco lucid_ole_vco[] = {
43 { 249600000, 2300000000, 0 },
44};
45
46/* 700.0 MHz Configuration */
47static const struct alpha_pll_config gpu_cc_pll0_config = {
48 .l = 0x24,
49 .alpha = 0x7555,
50 .config_ctl_val = 0x20485699,
51 .config_ctl_hi_val = 0x00182261,
52 .config_ctl_hi1_val = 0x82aa299c,
53 .test_ctl_val = 0x00000000,
54 .test_ctl_hi_val = 0x00000003,
55 .test_ctl_hi1_val = 0x00009000,
56 .test_ctl_hi2_val = 0x00000034,
57 .user_ctl_val = 0x00000400,
58 .user_ctl_hi_val = 0x00000005,
59};
60
61static struct clk_alpha_pll gpu_cc_pll0 = {
62 .offset = 0x0,
63 .config = &gpu_cc_pll0_config,
64 .vco_table = lucid_ole_vco,
65 .num_vco = ARRAY_SIZE(lucid_ole_vco),
66 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
67 .clkr = {
68 .hw.init = &(const struct clk_init_data) {
69 .name = "gpu_cc_pll0",
70 .parent_data = &(const struct clk_parent_data) {
71 .index = DT_BI_TCXO,
72 },
73 .num_parents = 1,
74 .ops = &clk_alpha_pll_lucid_evo_ops,
75 },
76 },
77};
78
79static const struct clk_div_table post_div_table_gpu_cc_pll0_out_even[] = {
80 { 0x1, 2 },
81 { }
82};
83
84static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = {
85 .offset = 0x0,
86 .post_div_shift = 10,
87 .post_div_table = post_div_table_gpu_cc_pll0_out_even,
88 .num_post_div = ARRAY_SIZE(post_div_table_gpu_cc_pll0_out_even),
89 .width = 4,
90 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
91 .clkr.hw.init = &(const struct clk_init_data) {
92 .name = "gpu_cc_pll0_out_even",
93 .parent_hws = (const struct clk_hw*[]) {
94 &gpu_cc_pll0.clkr.hw,
95 },
96 .num_parents = 1,
97 .flags = CLK_SET_RATE_PARENT,
98 .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
99 },
100};
101
102static const struct parent_map gpu_cc_parent_map_0[] = {
103 { P_BI_TCXO, 0 },
104 { P_GPLL0_OUT_MAIN, 5 },
105 { P_GPLL0_OUT_MAIN_DIV, 6 },
106};
107
108static const struct clk_parent_data gpu_cc_parent_data_0[] = {
109 { .index = DT_BI_TCXO },
110 { .index = DT_GPLL0_OUT_MAIN },
111 { .index = DT_GPLL0_OUT_MAIN_DIV },
112};
113
114static const struct parent_map gpu_cc_parent_map_1[] = {
115 { P_BI_TCXO, 0 },
116 { P_GPU_CC_PLL0_OUT_MAIN, 1 },
117 { P_GPU_CC_PLL0_OUT_EVEN, 2 },
118 { P_GPU_CC_PLL0_OUT_ODD, 3 },
119 { P_GPLL0_OUT_MAIN, 5 },
120 { P_GPLL0_OUT_MAIN_DIV, 6 },
121};
122
123static const struct clk_parent_data gpu_cc_parent_data_1[] = {
124 { .index = DT_BI_TCXO },
125 { .hw = &gpu_cc_pll0.clkr.hw },
126 { .hw = &gpu_cc_pll0_out_even.clkr.hw },
127 { .hw = &gpu_cc_pll0.clkr.hw },
128 { .index = DT_GPLL0_OUT_MAIN },
129 { .index = DT_GPLL0_OUT_MAIN_DIV },
130};
131
132static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = {
133 F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
134 { }
135};
136
137static struct clk_rcg2 gpu_cc_ff_clk_src = {
138 .cmd_rcgr = 0x9474,
139 .mnd_width = 0,
140 .hid_width = 5,
141 .parent_map = gpu_cc_parent_map_0,
142 .freq_tbl = ftbl_gpu_cc_ff_clk_src,
143 .clkr.hw.init = &(const struct clk_init_data) {
144 .name = "gpu_cc_ff_clk_src",
145 .parent_data = gpu_cc_parent_data_0,
146 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
147 .flags = CLK_SET_RATE_PARENT,
148 .ops = &clk_rcg2_shared_ops,
149 },
150};
151
152static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
153 F(19200000, P_BI_TCXO, 1, 0, 0),
154 F(350000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0),
155 F(650000000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0),
156 F(687500000, P_GPU_CC_PLL0_OUT_EVEN, 1, 0, 0),
157 { }
158};
159
160static struct clk_rcg2 gpu_cc_gmu_clk_src = {
161 .cmd_rcgr = 0x9318,
162 .mnd_width = 0,
163 .hid_width = 5,
164 .parent_map = gpu_cc_parent_map_1,
165 .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
166 .clkr.hw.init = &(const struct clk_init_data) {
167 .name = "gpu_cc_gmu_clk_src",
168 .parent_data = gpu_cc_parent_data_1,
169 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
170 .flags = CLK_SET_RATE_PARENT,
171 .ops = &clk_rcg2_shared_ops,
172 },
173};
174
175static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = {
176 F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
177 F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
178 F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0),
179 { }
180};
181
182static struct clk_rcg2 gpu_cc_hub_clk_src = {
183 .cmd_rcgr = 0x93ec,
184 .mnd_width = 0,
185 .hid_width = 5,
186 .parent_map = gpu_cc_parent_map_1,
187 .freq_tbl = ftbl_gpu_cc_hub_clk_src,
188 .clkr.hw.init = &(const struct clk_init_data) {
189 .name = "gpu_cc_hub_clk_src",
190 .parent_data = gpu_cc_parent_data_1,
191 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
192 .flags = CLK_SET_RATE_PARENT,
193 .ops = &clk_rcg2_shared_ops,
194 },
195};
196
197static struct clk_regmap_div gpu_cc_hub_div_clk_src = {
198 .reg = 0x942c,
199 .shift = 0,
200 .width = 4,
201 .clkr.hw.init = &(const struct clk_init_data) {
202 .name = "gpu_cc_hub_div_clk_src",
203 .parent_hws = (const struct clk_hw*[]) {
204 &gpu_cc_hub_clk_src.clkr.hw,
205 },
206 .num_parents = 1,
207 .flags = CLK_SET_RATE_PARENT,
208 .ops = &clk_regmap_div_ro_ops,
209 },
210};
211
212static struct clk_branch gpu_cc_ahb_clk = {
213 .halt_reg = 0x90bc,
214 .halt_check = BRANCH_HALT_DELAY,
215 .clkr = {
216 .enable_reg = 0x90bc,
217 .enable_mask = BIT(0),
218 .hw.init = &(const struct clk_init_data) {
219 .name = "gpu_cc_ahb_clk",
220 .parent_hws = (const struct clk_hw*[]) {
221 &gpu_cc_hub_div_clk_src.clkr.hw,
222 },
223 .num_parents = 1,
224 .flags = CLK_SET_RATE_PARENT,
225 .ops = &clk_branch2_ops,
226 },
227 },
228};
229
230static struct clk_branch gpu_cc_cx_accu_shift_clk = {
231 .halt_reg = 0x910c,
232 .halt_check = BRANCH_HALT_VOTED,
233 .clkr = {
234 .enable_reg = 0x910c,
235 .enable_mask = BIT(0),
236 .hw.init = &(const struct clk_init_data) {
237 .name = "gpu_cc_cx_accu_shift_clk",
238 .ops = &clk_branch2_ops,
239 },
240 },
241};
242
243static struct clk_branch gpu_cc_cx_ff_clk = {
244 .halt_reg = 0x90ec,
245 .halt_check = BRANCH_HALT,
246 .clkr = {
247 .enable_reg = 0x90ec,
248 .enable_mask = BIT(0),
249 .hw.init = &(const struct clk_init_data) {
250 .name = "gpu_cc_cx_ff_clk",
251 .parent_hws = (const struct clk_hw*[]) {
252 &gpu_cc_ff_clk_src.clkr.hw,
253 },
254 .num_parents = 1,
255 .flags = CLK_SET_RATE_PARENT,
256 .ops = &clk_branch2_ops,
257 },
258 },
259};
260
261static struct clk_branch gpu_cc_cx_gmu_clk = {
262 .halt_reg = 0x90d4,
263 .halt_check = BRANCH_HALT_VOTED,
264 .clkr = {
265 .enable_reg = 0x90d4,
266 .enable_mask = BIT(0),
267 .hw.init = &(const struct clk_init_data) {
268 .name = "gpu_cc_cx_gmu_clk",
269 .parent_hws = (const struct clk_hw*[]) {
270 &gpu_cc_gmu_clk_src.clkr.hw,
271 },
272 .num_parents = 1,
273 .flags = CLK_SET_RATE_PARENT,
274 .ops = &clk_branch2_aon_ops,
275 },
276 },
277};
278
279static struct clk_branch gpu_cc_cxo_clk = {
280 .halt_reg = 0x90e4,
281 .halt_check = BRANCH_HALT,
282 .clkr = {
283 .enable_reg = 0x90e4,
284 .enable_mask = BIT(0),
285 .hw.init = &(const struct clk_init_data) {
286 .name = "gpu_cc_cxo_clk",
287 .ops = &clk_branch2_ops,
288 },
289 },
290};
291
292static struct clk_branch gpu_cc_dpm_clk = {
293 .halt_reg = 0x9110,
294 .halt_check = BRANCH_HALT,
295 .clkr = {
296 .enable_reg = 0x9110,
297 .enable_mask = BIT(0),
298 .hw.init = &(const struct clk_init_data) {
299 .name = "gpu_cc_dpm_clk",
300 .ops = &clk_branch2_ops,
301 },
302 },
303};
304
305static struct clk_branch gpu_cc_freq_measure_clk = {
306 .halt_reg = 0x900c,
307 .halt_check = BRANCH_HALT,
308 .clkr = {
309 .enable_reg = 0x900c,
310 .enable_mask = BIT(0),
311 .hw.init = &(const struct clk_init_data) {
312 .name = "gpu_cc_freq_measure_clk",
313 .ops = &clk_branch2_ops,
314 },
315 },
316};
317
318static struct clk_branch gpu_cc_gx_accu_shift_clk = {
319 .halt_reg = 0x9070,
320 .halt_check = BRANCH_HALT_VOTED,
321 .clkr = {
322 .enable_reg = 0x9070,
323 .enable_mask = BIT(0),
324 .hw.init = &(const struct clk_init_data) {
325 .name = "gpu_cc_gx_accu_shift_clk",
326 .ops = &clk_branch2_ops,
327 },
328 },
329};
330
331static struct clk_branch gpu_cc_gx_acd_ahb_ff_clk = {
332 .halt_reg = 0x9068,
333 .halt_check = BRANCH_HALT,
334 .clkr = {
335 .enable_reg = 0x9068,
336 .enable_mask = BIT(0),
337 .hw.init = &(const struct clk_init_data) {
338 .name = "gpu_cc_gx_acd_ahb_ff_clk",
339 .parent_hws = (const struct clk_hw*[]) {
340 &gpu_cc_ff_clk_src.clkr.hw,
341 },
342 .num_parents = 1,
343 .flags = CLK_SET_RATE_PARENT,
344 .ops = &clk_branch2_ops,
345 },
346 },
347};
348
349static struct clk_branch gpu_cc_gx_gmu_clk = {
350 .halt_reg = 0x9060,
351 .halt_check = BRANCH_HALT,
352 .clkr = {
353 .enable_reg = 0x9060,
354 .enable_mask = BIT(0),
355 .hw.init = &(const struct clk_init_data) {
356 .name = "gpu_cc_gx_gmu_clk",
357 .parent_hws = (const struct clk_hw*[]) {
358 &gpu_cc_gmu_clk_src.clkr.hw,
359 },
360 .num_parents = 1,
361 .flags = CLK_SET_RATE_PARENT,
362 .ops = &clk_branch2_ops,
363 },
364 },
365};
366
367static struct clk_branch gpu_cc_gx_rcg_ahb_ff_clk = {
368 .halt_reg = 0x906c,
369 .halt_check = BRANCH_HALT_VOTED,
370 .clkr = {
371 .enable_reg = 0x906c,
372 .enable_mask = BIT(0),
373 .hw.init = &(const struct clk_init_data) {
374 .name = "gpu_cc_gx_rcg_ahb_ff_clk",
375 .parent_hws = (const struct clk_hw*[]) {
376 &gpu_cc_ff_clk_src.clkr.hw,
377 },
378 .num_parents = 1,
379 .flags = CLK_SET_RATE_PARENT,
380 .ops = &clk_branch2_ops,
381 },
382 },
383};
384
385static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
386 .halt_reg = 0x7000,
387 .halt_check = BRANCH_HALT_VOTED,
388 .clkr = {
389 .enable_reg = 0x7000,
390 .enable_mask = BIT(0),
391 .hw.init = &(const struct clk_init_data) {
392 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
393 .ops = &clk_branch2_ops,
394 },
395 },
396};
397
398static struct clk_branch gpu_cc_hub_aon_clk = {
399 .halt_reg = 0x93e8,
400 .halt_check = BRANCH_HALT_VOTED,
401 .clkr = {
402 .enable_reg = 0x93e8,
403 .enable_mask = BIT(0),
404 .hw.init = &(const struct clk_init_data) {
405 .name = "gpu_cc_hub_aon_clk",
406 .parent_hws = (const struct clk_hw*[]) {
407 &gpu_cc_hub_clk_src.clkr.hw,
408 },
409 .num_parents = 1,
410 .flags = CLK_SET_RATE_PARENT,
411 .ops = &clk_branch2_aon_ops,
412 },
413 },
414};
415
416static struct clk_branch gpu_cc_hub_cx_int_clk = {
417 .halt_reg = 0x90e8,
418 .halt_check = BRANCH_HALT_VOTED,
419 .clkr = {
420 .enable_reg = 0x90e8,
421 .enable_mask = BIT(0),
422 .hw.init = &(const struct clk_init_data) {
423 .name = "gpu_cc_hub_cx_int_clk",
424 .parent_hws = (const struct clk_hw*[]) {
425 &gpu_cc_hub_clk_src.clkr.hw,
426 },
427 .num_parents = 1,
428 .flags = CLK_SET_RATE_PARENT,
429 .ops = &clk_branch2_aon_ops,
430 },
431 },
432};
433
434static struct clk_branch gpu_cc_memnoc_gfx_clk = {
435 .halt_reg = 0x90f4,
436 .halt_check = BRANCH_HALT_VOTED,
437 .clkr = {
438 .enable_reg = 0x90f4,
439 .enable_mask = BIT(0),
440 .hw.init = &(const struct clk_init_data) {
441 .name = "gpu_cc_memnoc_gfx_clk",
442 .ops = &clk_branch2_ops,
443 },
444 },
445};
446
447static struct gdsc gpu_cc_cx_gdsc = {
448 .gdscr = 0x9080,
449 .gds_hw_ctrl = 0x9094,
450 .en_rest_wait_val = 0x2,
451 .en_few_wait_val = 0x2,
452 .clk_dis_wait_val = 0x8,
453 .pd = {
454 .name = "gpu_cc_cx_gdsc",
455 },
456 .pwrsts = PWRSTS_OFF_ON,
457 .flags = RETAIN_FF_ENABLE | VOTABLE,
458};
459
460static struct clk_regmap *gpu_cc_milos_clocks[] = {
461 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
462 [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr,
463 [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr,
464 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
465 [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
466 [GPU_CC_DPM_CLK] = &gpu_cc_dpm_clk.clkr,
467 [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr,
468 [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr,
469 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
470 [GPU_CC_GX_ACCU_SHIFT_CLK] = &gpu_cc_gx_accu_shift_clk.clkr,
471 [GPU_CC_GX_ACD_AHB_FF_CLK] = &gpu_cc_gx_acd_ahb_ff_clk.clkr,
472 [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
473 [GPU_CC_GX_RCG_AHB_FF_CLK] = &gpu_cc_gx_rcg_ahb_ff_clk.clkr,
474 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
475 [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,
476 [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,
477 [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,
478 [GPU_CC_HUB_DIV_CLK_SRC] = &gpu_cc_hub_div_clk_src.clkr,
479 [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr,
480 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
481 [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
482};
483
484static struct gdsc *gpu_cc_milos_gdscs[] = {
485 [GPU_CC_CX_GDSC] = &gpu_cc_cx_gdsc,
486};
487
488static const struct qcom_reset_map gpu_cc_milos_resets[] = {
489 [GPU_CC_CB_BCR] = { 0x93a0 },
490 [GPU_CC_CX_BCR] = { 0x907c },
491 [GPU_CC_FAST_HUB_BCR] = { 0x93e4 },
492 [GPU_CC_FF_BCR] = { 0x9470 },
493 [GPU_CC_GMU_BCR] = { 0x9314 },
494 [GPU_CC_GX_BCR] = { 0x905c },
495 [GPU_CC_RBCPR_BCR] = { 0x91e0 },
496 [GPU_CC_XO_BCR] = { 0x9000 },
497};
498
499static struct clk_alpha_pll *gpu_cc_milos_plls[] = {
500 &gpu_cc_pll0,
501};
502
503static u32 gpu_cc_milos_critical_cbcrs[] = {
504 0x93a4, /* GPU_CC_CB_CLK */
505 0x9008, /* GPU_CC_CXO_AON_CLK */
506 0x9010, /* GPU_CC_DEMET_CLK */
507 0x9064, /* GPU_CC_GX_AHB_FF_CLK */
508 0x93a8, /* GPU_CC_RSCC_HUB_AON_CLK */
509 0x9004, /* GPU_CC_RSCC_XO_AON_CLK */
510 0x90cc, /* GPU_CC_SLEEP_CLK */
511};
512
513static const struct regmap_config gpu_cc_milos_regmap_config = {
514 .reg_bits = 32,
515 .reg_stride = 4,
516 .val_bits = 32,
517 .max_register = 0x95e8,
518 .fast_io = true,
519};
520
521static struct qcom_cc_driver_data gpu_cc_milos_driver_data = {
522 .alpha_plls = gpu_cc_milos_plls,
523 .num_alpha_plls = ARRAY_SIZE(gpu_cc_milos_plls),
524 .clk_cbcrs = gpu_cc_milos_critical_cbcrs,
525 .num_clk_cbcrs = ARRAY_SIZE(gpu_cc_milos_critical_cbcrs),
526};
527
528static const struct qcom_cc_desc gpu_cc_milos_desc = {
529 .config = &gpu_cc_milos_regmap_config,
530 .clks = gpu_cc_milos_clocks,
531 .num_clks = ARRAY_SIZE(gpu_cc_milos_clocks),
532 .resets = gpu_cc_milos_resets,
533 .num_resets = ARRAY_SIZE(gpu_cc_milos_resets),
534 .gdscs = gpu_cc_milos_gdscs,
535 .num_gdscs = ARRAY_SIZE(gpu_cc_milos_gdscs),
536 .use_rpm = true,
537 .driver_data = &gpu_cc_milos_driver_data,
538};
539
540static const struct of_device_id gpu_cc_milos_match_table[] = {
541 { .compatible = "qcom,milos-gpucc" },
542 { }
543};
544MODULE_DEVICE_TABLE(of, gpu_cc_milos_match_table);
545
546static int gpu_cc_milos_probe(struct platform_device *pdev)
547{
548 return qcom_cc_probe(pdev, &gpu_cc_milos_desc);
549}
550
551static struct platform_driver gpu_cc_milos_driver = {
552 .probe = gpu_cc_milos_probe,
553 .driver = {
554 .name = "gpu_cc-milos",
555 .of_match_table = gpu_cc_milos_match_table,
556 },
557};
558
559module_platform_driver(gpu_cc_milos_driver);
560
561MODULE_DESCRIPTION("QTI GPU_CC Milos Driver");
562MODULE_LICENSE("GPL");