xref: /linux/drivers/clk/qcom/gpucc-msm8998.c (revision a3a02a52bcfcbcc4a637d4b68bf1bc391c9fad02)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019, Jeffrey Hugo
4  */
5 
6 #include <linux/kernel.h>
7 #include <linux/bitops.h>
8 #include <linux/err.h>
9 #include <linux/platform_device.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/clk-provider.h>
13 #include <linux/regmap.h>
14 #include <linux/reset-controller.h>
15 
16 #include <dt-bindings/clock/qcom,gpucc-msm8998.h>
17 
18 #include "common.h"
19 #include "clk-regmap.h"
20 #include "clk-regmap-divider.h"
21 #include "clk-alpha-pll.h"
22 #include "clk-rcg.h"
23 #include "clk-branch.h"
24 #include "reset.h"
25 #include "gdsc.h"
26 
27 enum {
28 	P_XO,
29 	P_GPLL0,
30 	P_GPUPLL0_OUT_EVEN,
31 };
32 
33 /* Instead of going directly to the block, XO is routed through this branch */
34 static struct clk_branch gpucc_cxo_clk = {
35 	.halt_reg = 0x1020,
36 	.clkr = {
37 		.enable_reg = 0x1020,
38 		.enable_mask = BIT(0),
39 		.hw.init = &(struct clk_init_data){
40 			.name = "gpucc_cxo_clk",
41 			.parent_data = &(const struct clk_parent_data){
42 				.fw_name = "xo"
43 			},
44 			.num_parents = 1,
45 			.ops = &clk_branch2_ops,
46 			.flags = CLK_IS_CRITICAL,
47 		},
48 	},
49 };
50 
51 static const struct pll_vco fabia_vco[] = {
52 	{ 249600000, 2000000000, 0 },
53 	{ 125000000, 1000000000, 1 },
54 };
55 
56 static const struct clk_div_table post_div_table_fabia_even[] = {
57 	{ 0x0, 1 },
58 	{ 0x1, 2 },
59 	{ 0x3, 4 },
60 	{ 0x7, 8 },
61 	{ }
62 };
63 
64 static struct clk_alpha_pll gpupll0 = {
65 	.offset = 0x0,
66 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
67 	.vco_table = fabia_vco,
68 	.num_vco = ARRAY_SIZE(fabia_vco),
69 	.clkr.hw.init = &(struct clk_init_data){
70 		.name = "gpupll0",
71 		.parent_hws = (const struct clk_hw *[]){ &gpucc_cxo_clk.clkr.hw },
72 		.num_parents = 1,
73 		.ops = &clk_alpha_pll_fabia_ops,
74 	},
75 };
76 
77 static struct clk_alpha_pll_postdiv gpupll0_out_even = {
78 	.offset = 0x0,
79 	.post_div_shift = 8,
80 	.post_div_table = post_div_table_fabia_even,
81 	.num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
82 	.width = 4,
83 	.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
84 	.clkr.hw.init = &(struct clk_init_data){
85 		.name = "gpupll0_out_even",
86 		.parent_hws = (const struct clk_hw *[]){ &gpupll0.clkr.hw },
87 		.num_parents = 1,
88 		.flags = CLK_SET_RATE_PARENT,
89 		.ops = &clk_alpha_pll_postdiv_fabia_ops,
90 	},
91 };
92 
93 static const struct parent_map gpu_xo_gpll0_map[] = {
94 	{ P_XO, 0 },
95 	{ P_GPLL0, 5 },
96 };
97 
98 static const struct clk_parent_data gpu_xo_gpll0[] = {
99 	{ .hw = &gpucc_cxo_clk.clkr.hw },
100 	{ .fw_name = "gpll0", .name = "gcc_gpu_gpll0_clk" },
101 };
102 
103 static const struct parent_map gpu_xo_gpupll0_map[] = {
104 	{ P_XO, 0 },
105 	{ P_GPUPLL0_OUT_EVEN, 1 },
106 };
107 
108 static const struct clk_hw *gpu_xo_gpupll0[] = {
109 	&gpucc_cxo_clk.clkr.hw,
110 	&gpupll0_out_even.clkr.hw,
111 };
112 
113 static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
114 	F(19200000, P_XO, 1, 0, 0),
115 	F(50000000, P_GPLL0, 12, 0, 0),
116 	{ }
117 };
118 
119 static struct clk_rcg2 rbcpr_clk_src = {
120 	.cmd_rcgr = 0x1030,
121 	.hid_width = 5,
122 	.parent_map = gpu_xo_gpll0_map,
123 	.freq_tbl = ftbl_rbcpr_clk_src,
124 	.clkr.hw.init = &(struct clk_init_data){
125 		.name = "rbcpr_clk_src",
126 		.parent_data = gpu_xo_gpll0,
127 		.num_parents = ARRAY_SIZE(gpu_xo_gpll0),
128 		.ops = &clk_rcg2_ops,
129 	},
130 };
131 
132 static const struct freq_tbl ftbl_gfx3d_clk_src[] = {
133 	{ .src = P_GPUPLL0_OUT_EVEN, .pre_div = 3 },
134 	{ }
135 };
136 
137 static struct clk_rcg2 gfx3d_clk_src = {
138 	.cmd_rcgr = 0x1070,
139 	.hid_width = 5,
140 	.parent_map = gpu_xo_gpupll0_map,
141 	.freq_tbl = ftbl_gfx3d_clk_src,
142 	.clkr.hw.init = &(struct clk_init_data){
143 		.name = "gfx3d_clk_src",
144 		.parent_hws = gpu_xo_gpupll0,
145 		.num_parents = ARRAY_SIZE(gpu_xo_gpupll0),
146 		.ops = &clk_rcg2_ops,
147 		.flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
148 	},
149 };
150 
151 static const struct freq_tbl ftbl_rbbmtimer_clk_src[] = {
152 	F(19200000, P_XO, 1, 0, 0),
153 	{ }
154 };
155 
156 static struct clk_rcg2 rbbmtimer_clk_src = {
157 	.cmd_rcgr = 0x10b0,
158 	.hid_width = 5,
159 	.parent_map = gpu_xo_gpll0_map,
160 	.freq_tbl = ftbl_rbbmtimer_clk_src,
161 	.clkr.hw.init = &(struct clk_init_data){
162 		.name = "rbbmtimer_clk_src",
163 		.parent_data = gpu_xo_gpll0,
164 		.num_parents = ARRAY_SIZE(gpu_xo_gpll0),
165 		.ops = &clk_rcg2_ops,
166 	},
167 };
168 
169 static const struct freq_tbl ftbl_gfx3d_isense_clk_src[] = {
170 	F(19200000, P_XO, 1, 0, 0),
171 	F(40000000, P_GPLL0, 15, 0, 0),
172 	F(200000000, P_GPLL0, 3, 0, 0),
173 	F(300000000, P_GPLL0, 2, 0, 0),
174 	{ }
175 };
176 
177 static struct clk_rcg2 gfx3d_isense_clk_src = {
178 	.cmd_rcgr = 0x1100,
179 	.hid_width = 5,
180 	.parent_map = gpu_xo_gpll0_map,
181 	.freq_tbl = ftbl_gfx3d_isense_clk_src,
182 	.clkr.hw.init = &(struct clk_init_data){
183 		.name = "gfx3d_isense_clk_src",
184 		.parent_data = gpu_xo_gpll0,
185 		.num_parents = ARRAY_SIZE(gpu_xo_gpll0),
186 		.ops = &clk_rcg2_ops,
187 	},
188 };
189 
190 static struct clk_branch rbcpr_clk = {
191 	.halt_reg = 0x1054,
192 	.clkr = {
193 		.enable_reg = 0x1054,
194 		.enable_mask = BIT(0),
195 		.hw.init = &(struct clk_init_data){
196 			.name = "rbcpr_clk",
197 			.parent_hws = (const struct clk_hw *[]){ &rbcpr_clk_src.clkr.hw },
198 			.num_parents = 1,
199 			.ops = &clk_branch2_ops,
200 			.flags = CLK_SET_RATE_PARENT,
201 		},
202 	},
203 };
204 
205 static struct clk_branch gfx3d_clk = {
206 	.halt_reg = 0x1098,
207 	.clkr = {
208 		.enable_reg = 0x1098,
209 		.enable_mask = BIT(0),
210 		.hw.init = &(struct clk_init_data){
211 			.name = "gfx3d_clk",
212 			.parent_hws = (const struct clk_hw *[]){ &gfx3d_clk_src.clkr.hw },
213 			.num_parents = 1,
214 			.ops = &clk_branch2_ops,
215 			.flags = CLK_SET_RATE_PARENT,
216 		},
217 	},
218 };
219 
220 static struct clk_branch rbbmtimer_clk = {
221 	.halt_reg = 0x10d0,
222 	.clkr = {
223 		.enable_reg = 0x10d0,
224 		.enable_mask = BIT(0),
225 		.hw.init = &(struct clk_init_data){
226 			.name = "rbbmtimer_clk",
227 			.parent_hws = (const struct clk_hw *[]){ &rbbmtimer_clk_src.clkr.hw },
228 			.num_parents = 1,
229 			.ops = &clk_branch2_ops,
230 			.flags = CLK_SET_RATE_PARENT,
231 		},
232 	},
233 };
234 
235 static struct clk_branch gfx3d_isense_clk = {
236 	.halt_reg = 0x1124,
237 	.clkr = {
238 		.enable_reg = 0x1124,
239 		.enable_mask = BIT(0),
240 		.hw.init = &(struct clk_init_data){
241 			.name = "gfx3d_isense_clk",
242 			.parent_hws = (const struct clk_hw *[]){ &gfx3d_isense_clk_src.clkr.hw },
243 			.num_parents = 1,
244 			.ops = &clk_branch2_ops,
245 		},
246 	},
247 };
248 
249 static struct gdsc gpu_cx_gdsc = {
250 	.gdscr = 0x1004,
251 	.gds_hw_ctrl = 0x1008,
252 	.pd = {
253 		.name = "gpu_cx",
254 	},
255 	.pwrsts = PWRSTS_OFF_ON,
256 	.flags = VOTABLE,
257 };
258 
259 static struct gdsc gpu_gx_gdsc = {
260 	.gdscr = 0x1094,
261 	.clamp_io_ctrl = 0x130,
262 	.resets = (unsigned int []){ GPU_GX_BCR },
263 	.reset_count = 1,
264 	.cxcs = (unsigned int []){ 0x1098 },
265 	.cxc_count = 1,
266 	.pd = {
267 		.name = "gpu_gx",
268 	},
269 	.parent = &gpu_cx_gdsc.pd,
270 	.pwrsts = PWRSTS_OFF_ON | PWRSTS_RET,
271 	.flags = CLAMP_IO | SW_RESET | AON_RESET | NO_RET_PERIPH,
272 };
273 
274 static struct clk_regmap *gpucc_msm8998_clocks[] = {
275 	[GPUPLL0] = &gpupll0.clkr,
276 	[GPUPLL0_OUT_EVEN] = &gpupll0_out_even.clkr,
277 	[RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
278 	[GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
279 	[RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
280 	[GFX3D_ISENSE_CLK_SRC] = &gfx3d_isense_clk_src.clkr,
281 	[RBCPR_CLK] = &rbcpr_clk.clkr,
282 	[GFX3D_CLK] = &gfx3d_clk.clkr,
283 	[RBBMTIMER_CLK] = &rbbmtimer_clk.clkr,
284 	[GFX3D_ISENSE_CLK] = &gfx3d_isense_clk.clkr,
285 	[GPUCC_CXO_CLK] = &gpucc_cxo_clk.clkr,
286 };
287 
288 static struct gdsc *gpucc_msm8998_gdscs[] = {
289 	[GPU_CX_GDSC] = &gpu_cx_gdsc,
290 	[GPU_GX_GDSC] = &gpu_gx_gdsc,
291 };
292 
293 static const struct qcom_reset_map gpucc_msm8998_resets[] = {
294 	[GPU_CX_BCR] = { 0x1000 },
295 	[RBCPR_BCR] = { 0x1050 },
296 	[GPU_GX_BCR] = { 0x1090 },
297 	[GPU_ISENSE_BCR] = { 0x1120 },
298 };
299 
300 static const struct regmap_config gpucc_msm8998_regmap_config = {
301 	.reg_bits	= 32,
302 	.reg_stride	= 4,
303 	.val_bits	= 32,
304 	.max_register	= 0x9000,
305 	.fast_io	= true,
306 };
307 
308 static const struct qcom_cc_desc gpucc_msm8998_desc = {
309 	.config = &gpucc_msm8998_regmap_config,
310 	.clks = gpucc_msm8998_clocks,
311 	.num_clks = ARRAY_SIZE(gpucc_msm8998_clocks),
312 	.resets = gpucc_msm8998_resets,
313 	.num_resets = ARRAY_SIZE(gpucc_msm8998_resets),
314 	.gdscs = gpucc_msm8998_gdscs,
315 	.num_gdscs = ARRAY_SIZE(gpucc_msm8998_gdscs),
316 };
317 
318 static const struct of_device_id gpucc_msm8998_match_table[] = {
319 	{ .compatible = "qcom,msm8998-gpucc" },
320 	{ }
321 };
322 MODULE_DEVICE_TABLE(of, gpucc_msm8998_match_table);
323 
324 static int gpucc_msm8998_probe(struct platform_device *pdev)
325 {
326 	struct regmap *regmap;
327 
328 	regmap = qcom_cc_map(pdev, &gpucc_msm8998_desc);
329 	if (IS_ERR(regmap))
330 		return PTR_ERR(regmap);
331 
332 	/* force periph logic on to avoid perf counter corruption */
333 	regmap_write_bits(regmap, gfx3d_clk.clkr.enable_reg, BIT(13), BIT(13));
334 	/* tweak droop detector (GPUCC_GPU_DD_WRAP_CTRL) to reduce leakage */
335 	regmap_write_bits(regmap, gfx3d_clk.clkr.enable_reg, BIT(0), BIT(0));
336 
337 	return qcom_cc_really_probe(&pdev->dev, &gpucc_msm8998_desc, regmap);
338 }
339 
340 static struct platform_driver gpucc_msm8998_driver = {
341 	.probe		= gpucc_msm8998_probe,
342 	.driver		= {
343 		.name	= "gpucc-msm8998",
344 		.of_match_table = gpucc_msm8998_match_table,
345 	},
346 };
347 module_platform_driver(gpucc_msm8998_driver);
348 
349 MODULE_DESCRIPTION("QCOM GPUCC MSM8998 Driver");
350 MODULE_LICENSE("GPL v2");
351