1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2021, The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/clk-provider.h>
7#include <linux/module.h>
8#include <linux/platform_device.h>
9#include <linux/regmap.h>
10
11#include <dt-bindings/clock/qcom,gpucc-sc7280.h>
12
13#include "clk-alpha-pll.h"
14#include "clk-branch.h"
15#include "clk-rcg.h"
16#include "clk-regmap-divider.h"
17#include "common.h"
18#include "reset.h"
19#include "gdsc.h"
20
21enum {
22	P_BI_TCXO,
23	P_GCC_GPU_GPLL0_CLK_SRC,
24	P_GCC_GPU_GPLL0_DIV_CLK_SRC,
25	P_GPU_CC_PLL0_OUT_MAIN,
26	P_GPU_CC_PLL1_OUT_MAIN,
27};
28
29static const struct pll_vco lucid_vco[] = {
30	{ 249600000, 2000000000, 0 },
31};
32
33static struct clk_alpha_pll gpu_cc_pll0 = {
34	.offset = 0x0,
35	.vco_table = lucid_vco,
36	.num_vco = ARRAY_SIZE(lucid_vco),
37	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
38	.clkr = {
39		.hw.init = &(struct clk_init_data){
40			.name = "gpu_cc_pll0",
41			.parent_data = &(const struct clk_parent_data){
42				.fw_name = "bi_tcxo",
43			},
44			.num_parents = 1,
45			.ops = &clk_alpha_pll_lucid_ops,
46		},
47	},
48};
49
50/* 500MHz Configuration */
51static const struct alpha_pll_config gpu_cc_pll1_config = {
52	.l = 0x1A,
53	.alpha = 0xAAA,
54	.config_ctl_val = 0x20485699,
55	.config_ctl_hi_val = 0x00002261,
56	.config_ctl_hi1_val = 0x329A299C,
57	.user_ctl_val = 0x00000001,
58	.user_ctl_hi_val = 0x00000805,
59	.user_ctl_hi1_val = 0x00000000,
60};
61
62static struct clk_alpha_pll gpu_cc_pll1 = {
63	.offset = 0x100,
64	.vco_table = lucid_vco,
65	.num_vco = ARRAY_SIZE(lucid_vco),
66	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
67	.clkr = {
68		.hw.init = &(struct clk_init_data){
69			.name = "gpu_cc_pll1",
70			.parent_data = &(const struct clk_parent_data){
71				.fw_name = "bi_tcxo",
72			},
73			.num_parents = 1,
74			.ops = &clk_alpha_pll_lucid_ops,
75		},
76	},
77};
78
79static const struct parent_map gpu_cc_parent_map_0[] = {
80	{ P_BI_TCXO, 0 },
81	{ P_GPU_CC_PLL0_OUT_MAIN, 1 },
82	{ P_GPU_CC_PLL1_OUT_MAIN, 3 },
83	{ P_GCC_GPU_GPLL0_CLK_SRC, 5 },
84	{ P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 },
85};
86
87static const struct clk_parent_data gpu_cc_parent_data_0[] = {
88	{ .fw_name = "bi_tcxo" },
89	{ .hw = &gpu_cc_pll0.clkr.hw },
90	{ .hw = &gpu_cc_pll1.clkr.hw },
91	{ .fw_name = "gcc_gpu_gpll0_clk_src" },
92	{ .fw_name = "gcc_gpu_gpll0_div_clk_src" },
93};
94
95static const struct parent_map gpu_cc_parent_map_1[] = {
96	{ P_BI_TCXO, 0 },
97	{ P_GPU_CC_PLL1_OUT_MAIN, 3 },
98	{ P_GCC_GPU_GPLL0_CLK_SRC, 5 },
99	{ P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 },
100};
101
102static const struct clk_parent_data gpu_cc_parent_data_1[] = {
103	{ .fw_name = "bi_tcxo", },
104	{ .hw = &gpu_cc_pll1.clkr.hw },
105	{ .fw_name = "gcc_gpu_gpll0_clk_src", },
106	{ .fw_name = "gcc_gpu_gpll0_div_clk_src", },
107};
108
109static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
110	F(19200000, P_BI_TCXO, 1, 0, 0),
111	F(200000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 1.5, 0, 0),
112	F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
113	{ }
114};
115
116static struct clk_rcg2 gpu_cc_gmu_clk_src = {
117	.cmd_rcgr = 0x1120,
118	.mnd_width = 0,
119	.hid_width = 5,
120	.parent_map = gpu_cc_parent_map_0,
121	.freq_tbl = ftbl_gpu_cc_gmu_clk_src,
122	.clkr.hw.init = &(struct clk_init_data){
123		.name = "gpu_cc_gmu_clk_src",
124		.parent_data = gpu_cc_parent_data_0,
125		.num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
126		.ops = &clk_rcg2_shared_ops,
127	},
128};
129
130static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = {
131	F(150000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 2, 0, 0),
132	F(240000000, P_GCC_GPU_GPLL0_CLK_SRC, 2.5, 0, 0),
133	F(300000000, P_GCC_GPU_GPLL0_CLK_SRC, 2, 0, 0),
134	{ }
135};
136
137static struct clk_rcg2 gpu_cc_hub_clk_src = {
138	.cmd_rcgr = 0x117c,
139	.mnd_width = 0,
140	.hid_width = 5,
141	.parent_map = gpu_cc_parent_map_1,
142	.freq_tbl = ftbl_gpu_cc_hub_clk_src,
143	.clkr.hw.init = &(struct clk_init_data){
144		.name = "gpu_cc_hub_clk_src",
145		.parent_data = gpu_cc_parent_data_1,
146		.num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
147		.ops = &clk_rcg2_shared_ops,
148	},
149};
150
151static struct clk_regmap_div gpu_cc_hub_ahb_div_clk_src = {
152	.reg = 0x11c0,
153	.shift = 0,
154	.width = 4,
155	.clkr.hw.init = &(struct clk_init_data) {
156		.name = "gpu_cc_hub_ahb_div_clk_src",
157		.parent_hws = (const struct clk_hw*[]){
158			&gpu_cc_hub_clk_src.clkr.hw,
159		},
160		.num_parents = 1,
161		.flags = CLK_SET_RATE_PARENT,
162		.ops = &clk_regmap_div_ro_ops,
163	},
164};
165
166static struct clk_regmap_div gpu_cc_hub_cx_int_div_clk_src = {
167	.reg = 0x11bc,
168	.shift = 0,
169	.width = 4,
170	.clkr.hw.init = &(struct clk_init_data) {
171		.name = "gpu_cc_hub_cx_int_div_clk_src",
172		.parent_hws = (const struct clk_hw*[]){
173			&gpu_cc_hub_clk_src.clkr.hw,
174		},
175		.num_parents = 1,
176		.flags = CLK_SET_RATE_PARENT,
177		.ops = &clk_regmap_div_ro_ops,
178	},
179};
180
181static struct clk_branch gpu_cc_ahb_clk = {
182	.halt_reg = 0x1078,
183	.halt_check = BRANCH_HALT_DELAY,
184	.clkr = {
185		.enable_reg = 0x1078,
186		.enable_mask = BIT(0),
187		.hw.init = &(struct clk_init_data){
188			.name = "gpu_cc_ahb_clk",
189			.parent_hws = (const struct clk_hw*[]){
190				&gpu_cc_hub_ahb_div_clk_src.clkr.hw,
191			},
192			.num_parents = 1,
193			.flags = CLK_SET_RATE_PARENT,
194			.ops = &clk_branch2_ops,
195		},
196	},
197};
198
199static struct clk_branch gpu_cc_crc_ahb_clk = {
200	.halt_reg = 0x107c,
201	.halt_check = BRANCH_HALT_VOTED,
202	.clkr = {
203		.enable_reg = 0x107c,
204		.enable_mask = BIT(0),
205		.hw.init = &(struct clk_init_data){
206			.name = "gpu_cc_crc_ahb_clk",
207			.parent_hws = (const struct clk_hw*[]){
208				&gpu_cc_hub_ahb_div_clk_src.clkr.hw,
209			},
210			.num_parents = 1,
211			.flags = CLK_SET_RATE_PARENT,
212			.ops = &clk_branch2_ops,
213		},
214	},
215};
216
217static struct clk_branch gpu_cc_cx_gmu_clk = {
218	.halt_reg = 0x1098,
219	.halt_check = BRANCH_HALT,
220	.clkr = {
221		.enable_reg = 0x1098,
222		.enable_mask = BIT(0),
223		.hw.init = &(struct clk_init_data){
224			.name = "gpu_cc_cx_gmu_clk",
225			.parent_hws = (const struct clk_hw*[]){
226				&gpu_cc_gmu_clk_src.clkr.hw,
227			},
228			.num_parents = 1,
229			.flags = CLK_SET_RATE_PARENT,
230			.ops = &clk_branch2_aon_ops,
231		},
232	},
233};
234
235static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {
236	.halt_reg = 0x108c,
237	.halt_check = BRANCH_HALT_VOTED,
238	.clkr = {
239		.enable_reg = 0x108c,
240		.enable_mask = BIT(0),
241		.hw.init = &(struct clk_init_data){
242			.name = "gpu_cc_cx_snoc_dvm_clk",
243			.ops = &clk_branch2_ops,
244		},
245	},
246};
247
248static struct clk_branch gpu_cc_cxo_aon_clk = {
249	.halt_reg = 0x1004,
250	.halt_check = BRANCH_HALT_VOTED,
251	.clkr = {
252		.enable_reg = 0x1004,
253		.enable_mask = BIT(0),
254		.hw.init = &(struct clk_init_data){
255			.name = "gpu_cc_cxo_aon_clk",
256			.ops = &clk_branch2_ops,
257		},
258	},
259};
260
261static struct clk_branch gpu_cc_cxo_clk = {
262	.halt_reg = 0x109c,
263	.halt_check = BRANCH_HALT,
264	.clkr = {
265		.enable_reg = 0x109c,
266		.enable_mask = BIT(0),
267		.hw.init = &(struct clk_init_data){
268			.name = "gpu_cc_cxo_clk",
269			.ops = &clk_branch2_aon_ops,
270		},
271	},
272};
273
274static struct clk_branch gpu_cc_gx_gmu_clk = {
275	.halt_reg = 0x1064,
276	.halt_check = BRANCH_HALT,
277	.clkr = {
278		.enable_reg = 0x1064,
279		.enable_mask = BIT(0),
280		.hw.init = &(struct clk_init_data){
281			.name = "gpu_cc_gx_gmu_clk",
282			.parent_hws = (const struct clk_hw*[]){
283				&gpu_cc_gmu_clk_src.clkr.hw,
284			},
285			.num_parents = 1,
286			.flags = CLK_SET_RATE_PARENT,
287			.ops = &clk_branch2_ops,
288		},
289	},
290};
291
292static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
293	.halt_reg = 0x5000,
294	.halt_check = BRANCH_VOTED,
295	.clkr = {
296		.enable_reg = 0x5000,
297		.enable_mask = BIT(0),
298		.hw.init = &(struct clk_init_data){
299			.name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
300			.ops = &clk_branch2_ops,
301		},
302	},
303};
304
305static struct clk_branch gpu_cc_hub_aon_clk = {
306	.halt_reg = 0x1178,
307	.halt_check = BRANCH_HALT,
308	.clkr = {
309		.enable_reg = 0x1178,
310		.enable_mask = BIT(0),
311		.hw.init = &(struct clk_init_data){
312			.name = "gpu_cc_hub_aon_clk",
313			.parent_hws = (const struct clk_hw*[]){
314				&gpu_cc_hub_clk_src.clkr.hw,
315			},
316			.num_parents = 1,
317			.flags = CLK_SET_RATE_PARENT,
318			.ops = &clk_branch2_aon_ops,
319		},
320	},
321};
322
323static struct clk_branch gpu_cc_hub_cx_int_clk = {
324	.halt_reg = 0x1204,
325	.halt_check = BRANCH_HALT,
326	.clkr = {
327		.enable_reg = 0x1204,
328		.enable_mask = BIT(0),
329		.hw.init = &(struct clk_init_data){
330			.name = "gpu_cc_hub_cx_int_clk",
331			.parent_hws = (const struct clk_hw*[]){
332				&gpu_cc_hub_cx_int_div_clk_src.clkr.hw,
333			},
334			.num_parents = 1,
335			.flags = CLK_SET_RATE_PARENT,
336			.ops = &clk_branch2_aon_ops,
337		},
338	},
339};
340
341static struct clk_branch gpu_cc_mnd1x_0_gfx3d_clk = {
342	.halt_reg = 0x802c,
343	.halt_check = BRANCH_HALT_SKIP,
344	.clkr = {
345		.enable_reg = 0x802c,
346		.enable_mask = BIT(0),
347		.hw.init = &(struct clk_init_data){
348			.name = "gpu_cc_mnd1x_0_gfx3d_clk",
349			.ops = &clk_branch2_ops,
350		},
351	},
352};
353
354static struct clk_branch gpu_cc_mnd1x_1_gfx3d_clk = {
355	.halt_reg = 0x8030,
356	.halt_check = BRANCH_HALT_SKIP,
357	.clkr = {
358		.enable_reg = 0x8030,
359		.enable_mask = BIT(0),
360		.hw.init = &(struct clk_init_data){
361			.name = "gpu_cc_mnd1x_1_gfx3d_clk",
362			.ops = &clk_branch2_ops,
363		},
364	},
365};
366
367static struct clk_branch gpu_cc_sleep_clk = {
368	.halt_reg = 0x1090,
369	.halt_check = BRANCH_HALT_VOTED,
370	.clkr = {
371		.enable_reg = 0x1090,
372		.enable_mask = BIT(0),
373		.hw.init = &(struct clk_init_data){
374			.name = "gpu_cc_sleep_clk",
375			.ops = &clk_branch2_ops,
376		},
377	},
378};
379
380static struct gdsc cx_gdsc = {
381	.gdscr = 0x106c,
382	.gds_hw_ctrl = 0x1540,
383	.pd = {
384		.name = "cx_gdsc",
385	},
386	.pwrsts = PWRSTS_OFF_ON,
387	.flags = VOTABLE | RETAIN_FF_ENABLE,
388};
389
390static struct gdsc gx_gdsc = {
391	.gdscr = 0x100c,
392	.clamp_io_ctrl = 0x1508,
393	.pd = {
394		.name = "gx_gdsc",
395		.power_on = gdsc_gx_do_nothing_enable,
396	},
397	.pwrsts = PWRSTS_OFF_ON,
398	.flags = CLAMP_IO | RETAIN_FF_ENABLE,
399};
400
401static struct gdsc *gpu_cc_sc7180_gdscs[] = {
402	[GPU_CC_CX_GDSC] = &cx_gdsc,
403	[GPU_CC_GX_GDSC] = &gx_gdsc,
404};
405
406static struct clk_regmap *gpu_cc_sc7280_clocks[] = {
407	[GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
408	[GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
409	[GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
410	[GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,
411	[GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
412	[GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
413	[GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
414	[GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
415	[GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
416	[GPU_CC_HUB_AHB_DIV_CLK_SRC] = &gpu_cc_hub_ahb_div_clk_src.clkr,
417	[GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,
418	[GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,
419	[GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,
420	[GPU_CC_HUB_CX_INT_DIV_CLK_SRC] = &gpu_cc_hub_cx_int_div_clk_src.clkr,
421	[GPU_CC_MND1X_0_GFX3D_CLK] = &gpu_cc_mnd1x_0_gfx3d_clk.clkr,
422	[GPU_CC_MND1X_1_GFX3D_CLK] = &gpu_cc_mnd1x_1_gfx3d_clk.clkr,
423	[GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
424	[GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
425	[GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr,
426};
427
428static const struct regmap_config gpu_cc_sc7280_regmap_config = {
429	.reg_bits = 32,
430	.reg_stride = 4,
431	.val_bits = 32,
432	.max_register = 0x8030,
433	.fast_io = true,
434};
435
436static const struct qcom_cc_desc gpu_cc_sc7280_desc = {
437	.config = &gpu_cc_sc7280_regmap_config,
438	.clks = gpu_cc_sc7280_clocks,
439	.num_clks = ARRAY_SIZE(gpu_cc_sc7280_clocks),
440	.gdscs = gpu_cc_sc7180_gdscs,
441	.num_gdscs = ARRAY_SIZE(gpu_cc_sc7180_gdscs),
442};
443
444static const struct of_device_id gpu_cc_sc7280_match_table[] = {
445	{ .compatible = "qcom,sc7280-gpucc" },
446	{ }
447};
448MODULE_DEVICE_TABLE(of, gpu_cc_sc7280_match_table);
449
450static int gpu_cc_sc7280_probe(struct platform_device *pdev)
451{
452	struct regmap *regmap;
453
454	regmap = qcom_cc_map(pdev, &gpu_cc_sc7280_desc);
455	if (IS_ERR(regmap))
456		return PTR_ERR(regmap);
457
458	clk_lucid_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
459
460	/* Keep some clocks always-on */
461	qcom_branch_set_clk_en(regmap, 0x1170); /* GPU_CC_CB_CLK */
462	qcom_branch_set_clk_en(regmap, 0x1098); /* GPUCC_CX_GMU_CLK */
463	regmap_update_bits(regmap, 0x1098, BIT(13), BIT(13));
464
465	return qcom_cc_really_probe(pdev, &gpu_cc_sc7280_desc, regmap);
466}
467
468static struct platform_driver gpu_cc_sc7280_driver = {
469	.probe = gpu_cc_sc7280_probe,
470	.driver = {
471		.name = "gpu_cc-sc7280",
472		.of_match_table = gpu_cc_sc7280_match_table,
473	},
474};
475
476module_platform_driver(gpu_cc_sc7280_driver);
477
478MODULE_DESCRIPTION("QTI GPU_CC SC7280 Driver");
479MODULE_LICENSE("GPL v2");
480