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/clk-provider.h>
13 #include <linux/regmap.h>
14 #include <linux/reset-controller.h>
16 #include <dt-bindings/clock/qcom,gpucc-msm8998.h>
19 #include "clk-regmap.h"
20 #include "clk-regmap-divider.h"
21 #include "clk-alpha-pll.h"
23 #include "clk-branch.h"
33 /* Instead of going directly to the block, XO is routed through this branch */
34 static struct clk_branch gpucc_cxo_clk
= {
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
){
45 .ops
= &clk_branch2_ops
,
46 .flags
= CLK_IS_CRITICAL
,
51 static const struct pll_vco fabia_vco
[] = {
52 { 249600000, 2000000000, 0 },
53 { 125000000, 1000000000, 1 },
56 static const struct clk_div_table post_div_table_fabia_even
[] = {
64 static struct clk_alpha_pll gpupll0
= {
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
){
71 .parent_hws
= (const struct clk_hw
*[]){ &gpucc_cxo_clk
.clkr
.hw
},
73 .ops
= &clk_alpha_pll_fabia_ops
,
77 static struct clk_alpha_pll_postdiv gpupll0_out_even
= {
80 .post_div_table
= post_div_table_fabia_even
,
81 .num_post_div
= ARRAY_SIZE(post_div_table_fabia_even
),
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
},
88 .flags
= CLK_SET_RATE_PARENT
,
89 .ops
= &clk_alpha_pll_postdiv_fabia_ops
,
93 static const struct parent_map gpu_xo_gpll0_map
[] = {
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" },
103 static const struct parent_map gpu_xo_gpupll0_map
[] = {
105 { P_GPUPLL0_OUT_EVEN
, 1 },
108 static const struct clk_hw
*gpu_xo_gpupll0
[] = {
109 &gpucc_cxo_clk
.clkr
.hw
,
110 &gpupll0_out_even
.clkr
.hw
,
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),
119 static struct clk_rcg2 rbcpr_clk_src
= {
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
,
132 static const struct freq_tbl ftbl_gfx3d_clk_src
[] = {
133 { .src
= P_GPUPLL0_OUT_EVEN
, .pre_div
= 3 },
137 static struct clk_rcg2 gfx3d_clk_src
= {
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
,
151 static const struct freq_tbl ftbl_rbbmtimer_clk_src
[] = {
152 F(19200000, P_XO
, 1, 0, 0),
156 static struct clk_rcg2 rbbmtimer_clk_src
= {
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
,
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),
177 static struct clk_rcg2 gfx3d_isense_clk_src
= {
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
,
190 static struct clk_branch rbcpr_clk
= {
193 .enable_reg
= 0x1054,
194 .enable_mask
= BIT(0),
195 .hw
.init
= &(struct clk_init_data
){
197 .parent_hws
= (const struct clk_hw
*[]){ &rbcpr_clk_src
.clkr
.hw
},
199 .ops
= &clk_branch2_ops
,
200 .flags
= CLK_SET_RATE_PARENT
,
205 static struct clk_branch gfx3d_clk
= {
208 .enable_reg
= 0x1098,
209 .enable_mask
= BIT(0),
210 .hw
.init
= &(struct clk_init_data
){
212 .parent_hws
= (const struct clk_hw
*[]){ &gfx3d_clk_src
.clkr
.hw
},
214 .ops
= &clk_branch2_ops
,
215 .flags
= CLK_SET_RATE_PARENT
,
220 static struct clk_branch rbbmtimer_clk
= {
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
},
229 .ops
= &clk_branch2_ops
,
230 .flags
= CLK_SET_RATE_PARENT
,
235 static struct clk_branch gfx3d_isense_clk
= {
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
},
244 .ops
= &clk_branch2_ops
,
249 static struct gdsc gpu_cx_gdsc
= {
251 .gds_hw_ctrl
= 0x1008,
255 .pwrsts
= PWRSTS_OFF_ON
,
259 static struct gdsc gpu_gx_gdsc
= {
261 .clamp_io_ctrl
= 0x130,
262 .resets
= (unsigned int []){ GPU_GX_BCR
},
264 .cxcs
= (unsigned int []){ 0x1098 },
269 .parent
= &gpu_cx_gdsc
.pd
,
270 .pwrsts
= PWRSTS_OFF_ON
| PWRSTS_RET
,
271 .flags
= CLAMP_IO
| SW_RESET
| AON_RESET
| NO_RET_PERIPH
,
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
,
288 static struct gdsc
*gpucc_msm8998_gdscs
[] = {
289 [GPU_CX_GDSC
] = &gpu_cx_gdsc
,
290 [GPU_GX_GDSC
] = &gpu_gx_gdsc
,
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 },
300 static const struct regmap_config gpucc_msm8998_regmap_config
= {
304 .max_register
= 0x9000,
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
),
318 static const struct of_device_id gpucc_msm8998_match_table
[] = {
319 { .compatible
= "qcom,msm8998-gpucc" },
322 MODULE_DEVICE_TABLE(of
, gpucc_msm8998_match_table
);
324 static int gpucc_msm8998_probe(struct platform_device
*pdev
)
326 struct regmap
*regmap
;
328 regmap
= qcom_cc_map(pdev
, &gpucc_msm8998_desc
);
330 return PTR_ERR(regmap
);
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));
337 return qcom_cc_really_probe(&pdev
->dev
, &gpucc_msm8998_desc
, regmap
);
340 static struct platform_driver gpucc_msm8998_driver
= {
341 .probe
= gpucc_msm8998_probe
,
343 .name
= "gpucc-msm8998",
344 .of_match_table
= gpucc_msm8998_match_table
,
347 module_platform_driver(gpucc_msm8998_driver
);
349 MODULE_DESCRIPTION("QCOM GPUCC MSM8998 Driver");
350 MODULE_LICENSE("GPL v2");