1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2019, Jeffrey Hugo
6 #include <linux/kernel.h>
7 #include <linux/bitops.h>
9 #include <linux/platform_device.h>
10 #include <linux/module.h>
12 #include <linux/of_device.h>
13 #include <linux/clk-provider.h>
14 #include <linux/regmap.h>
15 #include <linux/reset-controller.h>
17 #include <dt-bindings/clock/qcom,gpucc-msm8998.h>
20 #include "clk-regmap.h"
21 #include "clk-regmap-divider.h"
22 #include "clk-alpha-pll.h"
24 #include "clk-branch.h"
34 /* Instead of going directly to the block, XO is routed through this branch */
35 static struct clk_branch gpucc_cxo_clk
= {
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
){
47 .ops
= &clk_branch2_ops
,
48 .flags
= CLK_IS_CRITICAL
,
53 static const struct clk_div_table post_div_table_fabia_even
[] = {
61 static struct clk_alpha_pll gpupll0
= {
63 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_FABIA
],
64 .clkr
.hw
.init
= &(struct clk_init_data
){
66 .parent_hws
= (const struct clk_hw
*[]){ &gpucc_cxo_clk
.clkr
.hw
},
68 .ops
= &clk_alpha_pll_fixed_fabia_ops
,
72 static struct clk_alpha_pll_postdiv gpupll0_out_even
= {
75 .post_div_table
= post_div_table_fabia_even
,
76 .num_post_div
= ARRAY_SIZE(post_div_table_fabia_even
),
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
},
83 .ops
= &clk_alpha_pll_postdiv_fabia_ops
,
87 static const struct parent_map gpu_xo_gpll0_map
[] = {
92 static const struct clk_parent_data gpu_xo_gpll0
[] = {
93 { .hw
= &gpucc_cxo_clk
.clkr
.hw
},
94 { .fw_name
= "gpll0", .name
= "gpll0" },
97 static const struct parent_map gpu_xo_gpupll0_map
[] = {
99 { P_GPUPLL0_OUT_EVEN
, 1 },
102 static const struct clk_parent_data gpu_xo_gpupll0
[] = {
103 { .hw
= &gpucc_cxo_clk
.clkr
.hw
},
104 { .hw
= &gpupll0_out_even
.clkr
.hw
},
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),
113 static struct clk_rcg2 rbcpr_clk_src
= {
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
,
122 .ops
= &clk_rcg2_ops
,
126 static const struct freq_tbl ftbl_gfx3d_clk_src
[] = {
127 { .src
= P_GPUPLL0_OUT_EVEN
, .pre_div
= 3 },
131 static struct clk_rcg2 gfx3d_clk_src
= {
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
,
140 .ops
= &clk_rcg2_ops
,
141 .flags
= CLK_SET_RATE_PARENT
| CLK_OPS_PARENT_ENABLE
,
145 static const struct freq_tbl ftbl_rbbmtimer_clk_src
[] = {
146 F(19200000, P_XO
, 1, 0, 0),
150 static struct clk_rcg2 rbbmtimer_clk_src
= {
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
,
159 .ops
= &clk_rcg2_ops
,
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),
171 static struct clk_rcg2 gfx3d_isense_clk_src
= {
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
,
180 .ops
= &clk_rcg2_ops
,
184 static struct clk_branch rbcpr_clk
= {
187 .enable_reg
= 0x1054,
188 .enable_mask
= BIT(0),
189 .hw
.init
= &(struct clk_init_data
){
191 .parent_hws
= (const struct clk_hw
*[]){ &rbcpr_clk_src
.clkr
.hw
},
193 .ops
= &clk_branch2_ops
,
194 .flags
= CLK_SET_RATE_PARENT
,
199 static struct clk_branch gfx3d_clk
= {
202 .enable_reg
= 0x1098,
203 .enable_mask
= BIT(0),
204 .hw
.init
= &(struct clk_init_data
){
206 .parent_hws
= (const struct clk_hw
*[]){ &gfx3d_clk_src
.clkr
.hw
},
208 .ops
= &clk_branch2_ops
,
209 .flags
= CLK_SET_RATE_PARENT
,
214 static struct clk_branch rbbmtimer_clk
= {
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
},
223 .ops
= &clk_branch2_ops
,
224 .flags
= CLK_SET_RATE_PARENT
,
229 static struct clk_branch gfx3d_isense_clk
= {
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
},
238 .ops
= &clk_branch2_ops
,
243 static struct gdsc gpu_cx_gdsc
= {
245 .gds_hw_ctrl
= 0x1008,
249 .pwrsts
= PWRSTS_OFF_ON
,
253 static struct gdsc gpu_gx_gdsc
= {
255 .clamp_io_ctrl
= 0x130,
259 .parent
= &gpu_cx_gdsc
.pd
,
260 .pwrsts
= PWRSTS_OFF_ON
,
261 .flags
= CLAMP_IO
| AON_RESET
,
264 static struct clk_regmap
*gpucc_msm8998_clocks
[] = {
265 [GPUPLL0
] = &gpupll0
.clkr
,
266 [GPUPLL0_OUT_EVEN
] = &gpupll0_out_even
.clkr
,
267 [RBCPR_CLK_SRC
] = &rbcpr_clk_src
.clkr
,
268 [GFX3D_CLK_SRC
] = &gfx3d_clk_src
.clkr
,
269 [RBBMTIMER_CLK_SRC
] = &rbbmtimer_clk_src
.clkr
,
270 [GFX3D_ISENSE_CLK_SRC
] = &gfx3d_isense_clk_src
.clkr
,
271 [RBCPR_CLK
] = &rbcpr_clk
.clkr
,
272 [GFX3D_CLK
] = &gfx3d_clk
.clkr
,
273 [RBBMTIMER_CLK
] = &rbbmtimer_clk
.clkr
,
274 [GFX3D_ISENSE_CLK
] = &gfx3d_isense_clk
.clkr
,
275 [GPUCC_CXO_CLK
] = &gpucc_cxo_clk
.clkr
,
278 static struct gdsc
*gpucc_msm8998_gdscs
[] = {
279 [GPU_CX_GDSC
] = &gpu_cx_gdsc
,
280 [GPU_GX_GDSC
] = &gpu_gx_gdsc
,
283 static const struct qcom_reset_map gpucc_msm8998_resets
[] = {
284 [GPU_CX_BCR
] = { 0x1000 },
285 [RBCPR_BCR
] = { 0x1050 },
286 [GPU_GX_BCR
] = { 0x1090 },
287 [GPU_ISENSE_BCR
] = { 0x1120 },
290 static const struct regmap_config gpucc_msm8998_regmap_config
= {
294 .max_register
= 0x9000,
298 static const struct qcom_cc_desc gpucc_msm8998_desc
= {
299 .config
= &gpucc_msm8998_regmap_config
,
300 .clks
= gpucc_msm8998_clocks
,
301 .num_clks
= ARRAY_SIZE(gpucc_msm8998_clocks
),
302 .resets
= gpucc_msm8998_resets
,
303 .num_resets
= ARRAY_SIZE(gpucc_msm8998_resets
),
304 .gdscs
= gpucc_msm8998_gdscs
,
305 .num_gdscs
= ARRAY_SIZE(gpucc_msm8998_gdscs
),
308 static const struct of_device_id gpucc_msm8998_match_table
[] = {
309 { .compatible
= "qcom,msm8998-gpucc" },
312 MODULE_DEVICE_TABLE(of
, gpucc_msm8998_match_table
);
314 static int gpucc_msm8998_probe(struct platform_device
*pdev
)
316 struct regmap
*regmap
;
318 regmap
= qcom_cc_map(pdev
, &gpucc_msm8998_desc
);
320 return PTR_ERR(regmap
);
322 /* force periph logic on to avoid perf counter corruption */
323 regmap_write_bits(regmap
, gfx3d_clk
.clkr
.enable_reg
, BIT(13), BIT(13));
324 /* tweak droop detector (GPUCC_GPU_DD_WRAP_CTRL) to reduce leakage */
325 regmap_write_bits(regmap
, gfx3d_clk
.clkr
.enable_reg
, BIT(0), BIT(0));
327 return qcom_cc_really_probe(pdev
, &gpucc_msm8998_desc
, regmap
);
330 static struct platform_driver gpucc_msm8998_driver
= {
331 .probe
= gpucc_msm8998_probe
,
333 .name
= "gpucc-msm8998",
334 .of_match_table
= gpucc_msm8998_match_table
,
337 module_platform_driver(gpucc_msm8998_driver
);
339 MODULE_DESCRIPTION("QCOM GPUCC MSM8998 Driver");
340 MODULE_LICENSE("GPL v2");