1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
6 #include <linux/clk-provider.h>
7 #include <linux/module.h>
8 #include <linux/platform_device.h>
9 #include <linux/regmap.h>
11 #include <dt-bindings/clock/qcom,gpucc-sdm845.h>
14 #include "clk-alpha-pll.h"
15 #include "clk-branch.h"
18 #include "clk-regmap.h"
21 #define CX_GMU_CBCR_SLEEP_MASK 0xf
22 #define CX_GMU_CBCR_SLEEP_SHIFT 4
23 #define CX_GMU_CBCR_WAKE_MASK 0xf
24 #define CX_GMU_CBCR_WAKE_SHIFT 8
25 #define CLK_DIS_WAIT_SHIFT 12
26 #define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT)
30 P_CORE_BI_PLL_TEST_SE
,
33 P_GPU_CC_PLL1_OUT_EVEN
,
34 P_GPU_CC_PLL1_OUT_MAIN
,
35 P_GPU_CC_PLL1_OUT_ODD
,
38 static const struct parent_map gpu_cc_parent_map_0
[] = {
40 { P_GPU_CC_PLL1_OUT_MAIN
, 3 },
41 { P_GPLL0_OUT_MAIN
, 5 },
42 { P_GPLL0_OUT_MAIN_DIV
, 6 },
43 { P_CORE_BI_PLL_TEST_SE
, 7 },
46 static const char * const gpu_cc_parent_names_0
[] = {
49 "gcc_gpu_gpll0_clk_src",
50 "gcc_gpu_gpll0_div_clk_src",
51 "core_bi_pll_test_se",
54 static const struct alpha_pll_config gpu_cc_pll1_config
= {
59 static struct clk_alpha_pll gpu_cc_pll1
= {
61 .regs
= clk_alpha_pll_regs
[CLK_ALPHA_PLL_TYPE_FABIA
],
63 .hw
.init
= &(struct clk_init_data
){
64 .name
= "gpu_cc_pll1",
65 .parent_names
= (const char *[]){ "bi_tcxo" },
67 .ops
= &clk_alpha_pll_fabia_ops
,
72 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src
[] = {
73 F(19200000, P_BI_TCXO
, 1, 0, 0),
74 F(200000000, P_GPLL0_OUT_MAIN_DIV
, 1.5, 0, 0),
75 F(500000000, P_GPU_CC_PLL1_OUT_MAIN
, 1, 0, 0),
79 static struct clk_rcg2 gpu_cc_gmu_clk_src
= {
83 .parent_map
= gpu_cc_parent_map_0
,
84 .freq_tbl
= ftbl_gpu_cc_gmu_clk_src
,
85 .clkr
.hw
.init
= &(struct clk_init_data
){
86 .name
= "gpu_cc_gmu_clk_src",
87 .parent_names
= gpu_cc_parent_names_0
,
89 .ops
= &clk_rcg2_shared_ops
,
93 static struct clk_branch gpu_cc_cx_gmu_clk
= {
95 .halt_check
= BRANCH_HALT
,
98 .enable_mask
= BIT(0),
99 .hw
.init
= &(struct clk_init_data
){
100 .name
= "gpu_cc_cx_gmu_clk",
101 .parent_names
= (const char *[]){
102 "gpu_cc_gmu_clk_src",
105 .flags
= CLK_SET_RATE_PARENT
,
106 .ops
= &clk_branch2_ops
,
111 static struct clk_branch gpu_cc_cxo_clk
= {
113 .halt_check
= BRANCH_HALT
,
115 .enable_reg
= 0x109c,
116 .enable_mask
= BIT(0),
117 .hw
.init
= &(struct clk_init_data
){
118 .name
= "gpu_cc_cxo_clk",
119 .ops
= &clk_branch2_ops
,
124 static struct gdsc gpu_cx_gdsc
= {
126 .gds_hw_ctrl
= 0x1540,
128 .name
= "gpu_cx_gdsc",
130 .pwrsts
= PWRSTS_OFF_ON
,
135 * On SDM845 the GPU GX domain is *almost* entirely controlled by the GMU
136 * running in the CX domain so the CPU doesn't need to know anything about the
137 * GX domain EXCEPT....
139 * Hardware constraints dictate that the GX be powered down before the CX. If
140 * the GMU crashes it could leave the GX on. In order to successfully bring back
141 * the device the CPU needs to disable the GX headswitch. There being no sane
142 * way to reach in and touch that register from deep inside the GPU driver we
143 * need to set up the infrastructure to be able to ensure that the GPU can
144 * ensure that the GX is off during this super special case. We do this by
145 * defining a GX gdsc with a dummy enable function and a "default" disable
148 * This allows us to attach with genpd_dev_pm_attach_by_name() in the GPU
149 * driver. During power up, nothing will happen from the CPU (and the GMU will
150 * power up normally but during power down this will ensure that the GX domain
151 * is *really* off - this gives us a semi standard way of doing what we need.
153 static int gx_gdsc_enable(struct generic_pm_domain
*domain
)
155 /* Do nothing but give genpd the impression that we were successful */
159 static struct gdsc gpu_gx_gdsc
= {
161 .clamp_io_ctrl
= 0x1508,
163 .name
= "gpu_gx_gdsc",
164 .power_on
= gx_gdsc_enable
,
166 .pwrsts
= PWRSTS_OFF_ON
,
167 .flags
= CLAMP_IO
| AON_RESET
| POLL_CFG_GDSCR
,
170 static struct clk_regmap
*gpu_cc_sdm845_clocks
[] = {
171 [GPU_CC_CXO_CLK
] = &gpu_cc_cxo_clk
.clkr
,
172 [GPU_CC_CX_GMU_CLK
] = &gpu_cc_cx_gmu_clk
.clkr
,
173 [GPU_CC_GMU_CLK_SRC
] = &gpu_cc_gmu_clk_src
.clkr
,
174 [GPU_CC_PLL1
] = &gpu_cc_pll1
.clkr
,
177 static struct gdsc
*gpu_cc_sdm845_gdscs
[] = {
178 [GPU_CX_GDSC
] = &gpu_cx_gdsc
,
179 [GPU_GX_GDSC
] = &gpu_gx_gdsc
,
182 static const struct regmap_config gpu_cc_sdm845_regmap_config
= {
186 .max_register
= 0x8008,
190 static const struct qcom_cc_desc gpu_cc_sdm845_desc
= {
191 .config
= &gpu_cc_sdm845_regmap_config
,
192 .clks
= gpu_cc_sdm845_clocks
,
193 .num_clks
= ARRAY_SIZE(gpu_cc_sdm845_clocks
),
194 .gdscs
= gpu_cc_sdm845_gdscs
,
195 .num_gdscs
= ARRAY_SIZE(gpu_cc_sdm845_gdscs
),
198 static const struct of_device_id gpu_cc_sdm845_match_table
[] = {
199 { .compatible
= "qcom,sdm845-gpucc" },
202 MODULE_DEVICE_TABLE(of
, gpu_cc_sdm845_match_table
);
204 static int gpu_cc_sdm845_probe(struct platform_device
*pdev
)
206 struct regmap
*regmap
;
207 unsigned int value
, mask
;
209 regmap
= qcom_cc_map(pdev
, &gpu_cc_sdm845_desc
);
211 return PTR_ERR(regmap
);
213 clk_fabia_pll_configure(&gpu_cc_pll1
, regmap
, &gpu_cc_pll1_config
);
216 * Configure gpu_cc_cx_gmu_clk with recommended
217 * wakeup/sleep settings
219 mask
= CX_GMU_CBCR_WAKE_MASK
<< CX_GMU_CBCR_WAKE_SHIFT
;
220 mask
|= CX_GMU_CBCR_SLEEP_MASK
<< CX_GMU_CBCR_SLEEP_SHIFT
;
221 value
= 0xf << CX_GMU_CBCR_WAKE_SHIFT
| 0xf << CX_GMU_CBCR_SLEEP_SHIFT
;
222 regmap_update_bits(regmap
, 0x1098, mask
, value
);
224 /* Configure clk_dis_wait for gpu_cx_gdsc */
225 regmap_update_bits(regmap
, 0x106c, CLK_DIS_WAIT_MASK
,
226 8 << CLK_DIS_WAIT_SHIFT
);
228 return qcom_cc_really_probe(pdev
, &gpu_cc_sdm845_desc
, regmap
);
231 static struct platform_driver gpu_cc_sdm845_driver
= {
232 .probe
= gpu_cc_sdm845_probe
,
234 .name
= "sdm845-gpucc",
235 .of_match_table
= gpu_cc_sdm845_match_table
,
239 static int __init
gpu_cc_sdm845_init(void)
241 return platform_driver_register(&gpu_cc_sdm845_driver
);
243 subsys_initcall(gpu_cc_sdm845_init
);
245 static void __exit
gpu_cc_sdm845_exit(void)
247 platform_driver_unregister(&gpu_cc_sdm845_driver
);
249 module_exit(gpu_cc_sdm845_exit
);
251 MODULE_DESCRIPTION("QTI GPUCC SDM845 Driver");
252 MODULE_LICENSE("GPL v2");