Skip to content

Commit 3f7df5b

Browse files
Jeffrey Hugobebarino
authored andcommitted
clk: qcom: Add MSM8998 GPU Clock Controller (GPUCC) driver
The GPUCC manages the clocks for the Adreno GPU found on MSM8998. Signed-off-by: Jeffrey Hugo <[email protected]> Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Stephen Boyd <[email protected]>
1 parent efd164b commit 3f7df5b

File tree

3 files changed

+348
-0
lines changed

3 files changed

+348
-0
lines changed

drivers/clk/qcom/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,15 @@ config MSM_GCC_8998
220220
Say Y if you want to use peripheral devices such as UART, SPI,
221221
i2c, USB, UFS, SD/eMMC, PCIe, etc.
222222

223+
config MSM_GPUCC_8998
224+
tristate "MSM8998 Graphics Clock Controller"
225+
select MSM_GCC_8998
226+
select QCOM_GDSC
227+
help
228+
Support for the graphics clock controller on MSM8998 devices.
229+
Say Y if you want to support graphics controller devices and
230+
functionality such as 3D graphics.
231+
223232
config QCS_GCC_404
224233
tristate "QCS404 Global Clock Controller"
225234
help

drivers/clk/qcom/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ obj-$(CONFIG_MSM_GCC_8994) += gcc-msm8994.o
3333
obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o
3434
obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
3535
obj-$(CONFIG_MSM_GCC_8998) += gcc-msm8998.o
36+
obj-$(CONFIG_MSM_GPUCC_8998) += gpucc-msm8998.o
3637
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
3738
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
3839
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o

drivers/clk/qcom/gpucc-msm8998.c

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

0 commit comments

Comments
 (0)