Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2019, Jeffrey Hugo
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 /* Instead of going directly to the block, XO is routed through this branch */
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     /* force periph logic on to avoid perf counter corruption */
0334     regmap_write_bits(regmap, gfx3d_clk.clkr.enable_reg, BIT(13), BIT(13));
0335     /* tweak droop detector (GPUCC_GPU_DD_WRAP_CTRL) to reduce leakage */
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");