0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/bitops.h>
0008 #include <linux/err.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/clk-provider.h>
0014 #include <linux/regmap.h>
0015 #include <linux/reset-controller.h>
0016
0017 #include <dt-bindings/clock/qcom,gpucc-msm8998.h>
0018
0019 #include "common.h"
0020 #include "clk-regmap.h"
0021 #include "clk-regmap-divider.h"
0022 #include "clk-alpha-pll.h"
0023 #include "clk-rcg.h"
0024 #include "clk-branch.h"
0025 #include "reset.h"
0026 #include "gdsc.h"
0027
0028 enum {
0029 P_XO,
0030 P_GPLL0,
0031 P_GPUPLL0_OUT_EVEN,
0032 };
0033
0034
0035 static struct clk_branch gpucc_cxo_clk = {
0036 .halt_reg = 0x1020,
0037 .clkr = {
0038 .enable_reg = 0x1020,
0039 .enable_mask = BIT(0),
0040 .hw.init = &(struct clk_init_data){
0041 .name = "gpucc_cxo_clk",
0042 .parent_data = &(const struct clk_parent_data){
0043 .fw_name = "xo"
0044 },
0045 .num_parents = 1,
0046 .ops = &clk_branch2_ops,
0047 .flags = CLK_IS_CRITICAL,
0048 },
0049 },
0050 };
0051
0052 static struct pll_vco fabia_vco[] = {
0053 { 249600000, 2000000000, 0 },
0054 { 125000000, 1000000000, 1 },
0055 };
0056
0057 static const struct clk_div_table post_div_table_fabia_even[] = {
0058 { 0x0, 1 },
0059 { 0x1, 2 },
0060 { 0x3, 4 },
0061 { 0x7, 8 },
0062 { }
0063 };
0064
0065 static struct clk_alpha_pll gpupll0 = {
0066 .offset = 0x0,
0067 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
0068 .vco_table = fabia_vco,
0069 .num_vco = ARRAY_SIZE(fabia_vco),
0070 .clkr.hw.init = &(struct clk_init_data){
0071 .name = "gpupll0",
0072 .parent_hws = (const struct clk_hw *[]){ &gpucc_cxo_clk.clkr.hw },
0073 .num_parents = 1,
0074 .ops = &clk_alpha_pll_fabia_ops,
0075 },
0076 };
0077
0078 static struct clk_alpha_pll_postdiv gpupll0_out_even = {
0079 .offset = 0x0,
0080 .post_div_shift = 8,
0081 .post_div_table = post_div_table_fabia_even,
0082 .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
0083 .width = 4,
0084 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
0085 .clkr.hw.init = &(struct clk_init_data){
0086 .name = "gpupll0_out_even",
0087 .parent_hws = (const struct clk_hw *[]){ &gpupll0.clkr.hw },
0088 .num_parents = 1,
0089 .flags = CLK_SET_RATE_PARENT,
0090 .ops = &clk_alpha_pll_postdiv_fabia_ops,
0091 },
0092 };
0093
0094 static const struct parent_map gpu_xo_gpll0_map[] = {
0095 { P_XO, 0 },
0096 { P_GPLL0, 5 },
0097 };
0098
0099 static const struct clk_parent_data gpu_xo_gpll0[] = {
0100 { .hw = &gpucc_cxo_clk.clkr.hw },
0101 { .fw_name = "gpll0" },
0102 };
0103
0104 static const struct parent_map gpu_xo_gpupll0_map[] = {
0105 { P_XO, 0 },
0106 { P_GPUPLL0_OUT_EVEN, 1 },
0107 };
0108
0109 static const struct clk_parent_data gpu_xo_gpupll0[] = {
0110 { .hw = &gpucc_cxo_clk.clkr.hw },
0111 { .hw = &gpupll0_out_even.clkr.hw },
0112 };
0113
0114 static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
0115 F(19200000, P_XO, 1, 0, 0),
0116 F(50000000, P_GPLL0, 12, 0, 0),
0117 { }
0118 };
0119
0120 static struct clk_rcg2 rbcpr_clk_src = {
0121 .cmd_rcgr = 0x1030,
0122 .hid_width = 5,
0123 .parent_map = gpu_xo_gpll0_map,
0124 .freq_tbl = ftbl_rbcpr_clk_src,
0125 .clkr.hw.init = &(struct clk_init_data){
0126 .name = "rbcpr_clk_src",
0127 .parent_data = gpu_xo_gpll0,
0128 .num_parents = ARRAY_SIZE(gpu_xo_gpll0),
0129 .ops = &clk_rcg2_ops,
0130 },
0131 };
0132
0133 static const struct freq_tbl ftbl_gfx3d_clk_src[] = {
0134 { .src = P_GPUPLL0_OUT_EVEN, .pre_div = 3 },
0135 { }
0136 };
0137
0138 static struct clk_rcg2 gfx3d_clk_src = {
0139 .cmd_rcgr = 0x1070,
0140 .hid_width = 5,
0141 .parent_map = gpu_xo_gpupll0_map,
0142 .freq_tbl = ftbl_gfx3d_clk_src,
0143 .clkr.hw.init = &(struct clk_init_data){
0144 .name = "gfx3d_clk_src",
0145 .parent_data = gpu_xo_gpupll0,
0146 .num_parents = ARRAY_SIZE(gpu_xo_gpupll0),
0147 .ops = &clk_rcg2_ops,
0148 .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
0149 },
0150 };
0151
0152 static const struct freq_tbl ftbl_rbbmtimer_clk_src[] = {
0153 F(19200000, P_XO, 1, 0, 0),
0154 { }
0155 };
0156
0157 static struct clk_rcg2 rbbmtimer_clk_src = {
0158 .cmd_rcgr = 0x10b0,
0159 .hid_width = 5,
0160 .parent_map = gpu_xo_gpll0_map,
0161 .freq_tbl = ftbl_rbbmtimer_clk_src,
0162 .clkr.hw.init = &(struct clk_init_data){
0163 .name = "rbbmtimer_clk_src",
0164 .parent_data = gpu_xo_gpll0,
0165 .num_parents = ARRAY_SIZE(gpu_xo_gpll0),
0166 .ops = &clk_rcg2_ops,
0167 },
0168 };
0169
0170 static const struct freq_tbl ftbl_gfx3d_isense_clk_src[] = {
0171 F(19200000, P_XO, 1, 0, 0),
0172 F(40000000, P_GPLL0, 15, 0, 0),
0173 F(200000000, P_GPLL0, 3, 0, 0),
0174 F(300000000, P_GPLL0, 2, 0, 0),
0175 { }
0176 };
0177
0178 static struct clk_rcg2 gfx3d_isense_clk_src = {
0179 .cmd_rcgr = 0x1100,
0180 .hid_width = 5,
0181 .parent_map = gpu_xo_gpll0_map,
0182 .freq_tbl = ftbl_gfx3d_isense_clk_src,
0183 .clkr.hw.init = &(struct clk_init_data){
0184 .name = "gfx3d_isense_clk_src",
0185 .parent_data = gpu_xo_gpll0,
0186 .num_parents = ARRAY_SIZE(gpu_xo_gpll0),
0187 .ops = &clk_rcg2_ops,
0188 },
0189 };
0190
0191 static struct clk_branch rbcpr_clk = {
0192 .halt_reg = 0x1054,
0193 .clkr = {
0194 .enable_reg = 0x1054,
0195 .enable_mask = BIT(0),
0196 .hw.init = &(struct clk_init_data){
0197 .name = "rbcpr_clk",
0198 .parent_hws = (const struct clk_hw *[]){ &rbcpr_clk_src.clkr.hw },
0199 .num_parents = 1,
0200 .ops = &clk_branch2_ops,
0201 .flags = CLK_SET_RATE_PARENT,
0202 },
0203 },
0204 };
0205
0206 static struct clk_branch gfx3d_clk = {
0207 .halt_reg = 0x1098,
0208 .clkr = {
0209 .enable_reg = 0x1098,
0210 .enable_mask = BIT(0),
0211 .hw.init = &(struct clk_init_data){
0212 .name = "gfx3d_clk",
0213 .parent_hws = (const struct clk_hw *[]){ &gfx3d_clk_src.clkr.hw },
0214 .num_parents = 1,
0215 .ops = &clk_branch2_ops,
0216 .flags = CLK_SET_RATE_PARENT,
0217 },
0218 },
0219 };
0220
0221 static struct clk_branch rbbmtimer_clk = {
0222 .halt_reg = 0x10d0,
0223 .clkr = {
0224 .enable_reg = 0x10d0,
0225 .enable_mask = BIT(0),
0226 .hw.init = &(struct clk_init_data){
0227 .name = "rbbmtimer_clk",
0228 .parent_hws = (const struct clk_hw *[]){ &rbbmtimer_clk_src.clkr.hw },
0229 .num_parents = 1,
0230 .ops = &clk_branch2_ops,
0231 .flags = CLK_SET_RATE_PARENT,
0232 },
0233 },
0234 };
0235
0236 static struct clk_branch gfx3d_isense_clk = {
0237 .halt_reg = 0x1124,
0238 .clkr = {
0239 .enable_reg = 0x1124,
0240 .enable_mask = BIT(0),
0241 .hw.init = &(struct clk_init_data){
0242 .name = "gfx3d_isense_clk",
0243 .parent_hws = (const struct clk_hw *[]){ &gfx3d_isense_clk_src.clkr.hw },
0244 .num_parents = 1,
0245 .ops = &clk_branch2_ops,
0246 },
0247 },
0248 };
0249
0250 static struct gdsc gpu_cx_gdsc = {
0251 .gdscr = 0x1004,
0252 .gds_hw_ctrl = 0x1008,
0253 .pd = {
0254 .name = "gpu_cx",
0255 },
0256 .pwrsts = PWRSTS_OFF_ON,
0257 .flags = VOTABLE,
0258 };
0259
0260 static struct gdsc gpu_gx_gdsc = {
0261 .gdscr = 0x1094,
0262 .clamp_io_ctrl = 0x130,
0263 .resets = (unsigned int []){ GPU_GX_BCR },
0264 .reset_count = 1,
0265 .cxcs = (unsigned int []){ 0x1098 },
0266 .cxc_count = 1,
0267 .pd = {
0268 .name = "gpu_gx",
0269 },
0270 .parent = &gpu_cx_gdsc.pd,
0271 .pwrsts = PWRSTS_OFF_ON | PWRSTS_RET,
0272 .flags = CLAMP_IO | SW_RESET | AON_RESET | NO_RET_PERIPH,
0273 };
0274
0275 static struct clk_regmap *gpucc_msm8998_clocks[] = {
0276 [GPUPLL0] = &gpupll0.clkr,
0277 [GPUPLL0_OUT_EVEN] = &gpupll0_out_even.clkr,
0278 [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
0279 [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
0280 [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
0281 [GFX3D_ISENSE_CLK_SRC] = &gfx3d_isense_clk_src.clkr,
0282 [RBCPR_CLK] = &rbcpr_clk.clkr,
0283 [GFX3D_CLK] = &gfx3d_clk.clkr,
0284 [RBBMTIMER_CLK] = &rbbmtimer_clk.clkr,
0285 [GFX3D_ISENSE_CLK] = &gfx3d_isense_clk.clkr,
0286 [GPUCC_CXO_CLK] = &gpucc_cxo_clk.clkr,
0287 };
0288
0289 static struct gdsc *gpucc_msm8998_gdscs[] = {
0290 [GPU_CX_GDSC] = &gpu_cx_gdsc,
0291 [GPU_GX_GDSC] = &gpu_gx_gdsc,
0292 };
0293
0294 static const struct qcom_reset_map gpucc_msm8998_resets[] = {
0295 [GPU_CX_BCR] = { 0x1000 },
0296 [RBCPR_BCR] = { 0x1050 },
0297 [GPU_GX_BCR] = { 0x1090 },
0298 [GPU_ISENSE_BCR] = { 0x1120 },
0299 };
0300
0301 static const struct regmap_config gpucc_msm8998_regmap_config = {
0302 .reg_bits = 32,
0303 .reg_stride = 4,
0304 .val_bits = 32,
0305 .max_register = 0x9000,
0306 .fast_io = true,
0307 };
0308
0309 static const struct qcom_cc_desc gpucc_msm8998_desc = {
0310 .config = &gpucc_msm8998_regmap_config,
0311 .clks = gpucc_msm8998_clocks,
0312 .num_clks = ARRAY_SIZE(gpucc_msm8998_clocks),
0313 .resets = gpucc_msm8998_resets,
0314 .num_resets = ARRAY_SIZE(gpucc_msm8998_resets),
0315 .gdscs = gpucc_msm8998_gdscs,
0316 .num_gdscs = ARRAY_SIZE(gpucc_msm8998_gdscs),
0317 };
0318
0319 static const struct of_device_id gpucc_msm8998_match_table[] = {
0320 { .compatible = "qcom,msm8998-gpucc" },
0321 { }
0322 };
0323 MODULE_DEVICE_TABLE(of, gpucc_msm8998_match_table);
0324
0325 static int gpucc_msm8998_probe(struct platform_device *pdev)
0326 {
0327 struct regmap *regmap;
0328
0329 regmap = qcom_cc_map(pdev, &gpucc_msm8998_desc);
0330 if (IS_ERR(regmap))
0331 return PTR_ERR(regmap);
0332
0333
0334 regmap_write_bits(regmap, gfx3d_clk.clkr.enable_reg, BIT(13), BIT(13));
0335
0336 regmap_write_bits(regmap, gfx3d_clk.clkr.enable_reg, BIT(0), BIT(0));
0337
0338 return qcom_cc_really_probe(pdev, &gpucc_msm8998_desc, regmap);
0339 }
0340
0341 static struct platform_driver gpucc_msm8998_driver = {
0342 .probe = gpucc_msm8998_probe,
0343 .driver = {
0344 .name = "gpucc-msm8998",
0345 .of_match_table = gpucc_msm8998_match_table,
0346 },
0347 };
0348 module_platform_driver(gpucc_msm8998_driver);
0349
0350 MODULE_DESCRIPTION("QCOM GPUCC MSM8998 Driver");
0351 MODULE_LICENSE("GPL v2");