linux/drivers/clk/qcom/gpucc-sdm660.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
   4 * Copyright (c) 2020, AngeloGioacchino Del Regno
   5 *                     <angelogioacchino.delregno@somainline.org>
   6 */
   7
   8#include <linux/bitops.h>
   9#include <linux/clk.h>
  10#include <linux/clk-provider.h>
  11#include <linux/err.h>
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/platform_device.h>
  15#include <linux/of.h>
  16#include <linux/of_device.h>
  17#include <linux/regmap.h>
  18#include <linux/reset-controller.h>
  19#include <dt-bindings/clock/qcom,gpucc-sdm660.h>
  20
  21#include "clk-alpha-pll.h"
  22#include "common.h"
  23#include "clk-regmap.h"
  24#include "clk-pll.h"
  25#include "clk-rcg.h"
  26#include "clk-branch.h"
  27#include "gdsc.h"
  28#include "reset.h"
  29
  30enum {
  31        P_GPU_XO,
  32        P_CORE_BI_PLL_TEST_SE,
  33        P_GPLL0_OUT_MAIN,
  34        P_GPLL0_OUT_MAIN_DIV,
  35        P_GPU_PLL0_PLL_OUT_MAIN,
  36        P_GPU_PLL1_PLL_OUT_MAIN,
  37};
  38
  39static struct clk_branch gpucc_cxo_clk = {
  40        .halt_reg = 0x1020,
  41        .clkr = {
  42                .enable_reg = 0x1020,
  43                .enable_mask = BIT(0),
  44                .hw.init = &(struct clk_init_data){
  45                        .name = "gpucc_cxo_clk",
  46                        .parent_data = &(const struct clk_parent_data){
  47                                .fw_name = "xo",
  48                                .name = "xo"
  49                        },
  50                        .num_parents = 1,
  51                        .ops = &clk_branch2_ops,
  52                        .flags = CLK_IS_CRITICAL,
  53                },
  54        },
  55};
  56
  57static struct pll_vco gpu_vco[] = {
  58        { 1000000000, 2000000000, 0 },
  59        { 500000000,  1000000000, 2 },
  60        { 250000000,   500000000, 3 },
  61};
  62
  63static struct clk_alpha_pll gpu_pll0_pll_out_main = {
  64        .offset = 0x0,
  65        .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
  66        .vco_table = gpu_vco,
  67        .num_vco = ARRAY_SIZE(gpu_vco),
  68        .clkr.hw.init = &(struct clk_init_data){
  69                .name = "gpu_pll0_pll_out_main",
  70                .parent_data =  &(const struct clk_parent_data){
  71                        .hw = &gpucc_cxo_clk.clkr.hw,
  72                },
  73                .num_parents = 1,
  74                .ops = &clk_alpha_pll_ops,
  75        },
  76};
  77
  78static struct clk_alpha_pll gpu_pll1_pll_out_main = {
  79        .offset = 0x40,
  80        .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
  81        .vco_table = gpu_vco,
  82        .num_vco = ARRAY_SIZE(gpu_vco),
  83        .clkr.hw.init = &(struct clk_init_data){
  84                .name = "gpu_pll1_pll_out_main",
  85                .parent_data = &(const struct clk_parent_data){
  86                        .hw = &gpucc_cxo_clk.clkr.hw,
  87                },
  88                .num_parents = 1,
  89                .ops = &clk_alpha_pll_ops,
  90        },
  91};
  92
  93static const struct parent_map gpucc_parent_map_1[] = {
  94        { P_GPU_XO, 0 },
  95        { P_GPU_PLL0_PLL_OUT_MAIN, 1 },
  96        { P_GPU_PLL1_PLL_OUT_MAIN, 3 },
  97        { P_GPLL0_OUT_MAIN, 5 },
  98};
  99
 100static const struct clk_parent_data gpucc_parent_data_1[] = {
 101        { .hw = &gpucc_cxo_clk.clkr.hw },
 102        { .hw = &gpu_pll0_pll_out_main.clkr.hw },
 103        { .hw = &gpu_pll1_pll_out_main.clkr.hw },
 104        { .fw_name = "gcc_gpu_gpll0_clk", .name = "gcc_gpu_gpll0_clk" },
 105};
 106
 107static struct clk_rcg2_gfx3d gfx3d_clk_src = {
 108        .div = 2,
 109        .rcg = {
 110                .cmd_rcgr = 0x1070,
 111                .mnd_width = 0,
 112                .hid_width = 5,
 113                .parent_map = gpucc_parent_map_1,
 114                .clkr.hw.init = &(struct clk_init_data){
 115                        .name = "gfx3d_clk_src",
 116                        .parent_data = gpucc_parent_data_1,
 117                        .num_parents = 4,
 118                        .ops = &clk_gfx3d_ops,
 119                        .flags = CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
 120                },
 121        },
 122        .hws = (struct clk_hw*[]){
 123                &gpucc_cxo_clk.clkr.hw,
 124                &gpu_pll0_pll_out_main.clkr.hw,
 125                &gpu_pll1_pll_out_main.clkr.hw,
 126        }
 127};
 128
 129static struct clk_branch gpucc_gfx3d_clk = {
 130        .halt_reg = 0x1098,
 131        .halt_check = BRANCH_HALT,
 132        .hwcg_reg = 0x1098,
 133        .hwcg_bit = 1,
 134        .clkr = {
 135                .enable_reg = 0x1098,
 136                .enable_mask = BIT(0),
 137                .hw.init = &(struct clk_init_data){
 138                        .name = "gpucc_gfx3d_clk",
 139                        .parent_data = &(const struct clk_parent_data){
 140                                .hw = &gfx3d_clk_src.rcg.clkr.hw,
 141                        },
 142                        .num_parents = 1,
 143                        .ops = &clk_branch2_ops,
 144                        .flags = CLK_SET_RATE_PARENT,
 145                },
 146        },
 147};
 148
 149static const struct parent_map gpucc_parent_map_0[] = {
 150        { P_GPU_XO, 0 },
 151        { P_GPLL0_OUT_MAIN, 5 },
 152        { P_GPLL0_OUT_MAIN_DIV, 6 },
 153};
 154
 155static const struct clk_parent_data gpucc_parent_data_0[] = {
 156        { .hw = &gpucc_cxo_clk.clkr.hw },
 157        { .fw_name = "gcc_gpu_gpll0_clk", .name = "gcc_gpu_gpll0_clk" },
 158        { .fw_name = "gcc_gpu_gpll0_div_clk", .name = "gcc_gpu_gpll0_div_clk" },
 159};
 160
 161static const struct freq_tbl ftbl_rbbmtimer_clk_src[] = {
 162        F(19200000, P_GPU_XO, 1, 0, 0),
 163        { }
 164};
 165
 166static struct clk_rcg2 rbbmtimer_clk_src = {
 167        .cmd_rcgr = 0x10b0,
 168        .mnd_width = 0,
 169        .hid_width = 5,
 170        .parent_map = gpucc_parent_map_0,
 171        .freq_tbl = ftbl_rbbmtimer_clk_src,
 172        .clkr.hw.init = &(struct clk_init_data){
 173                .name = "rbbmtimer_clk_src",
 174                .parent_data = gpucc_parent_data_0,
 175                .num_parents = 3,
 176                .ops = &clk_rcg2_ops,
 177        },
 178};
 179
 180static const struct freq_tbl ftbl_rbcpr_clk_src[] = {
 181        F(19200000, P_GPU_XO, 1, 0, 0),
 182        F(50000000, P_GPLL0_OUT_MAIN_DIV, 6, 0, 0),
 183        { }
 184};
 185
 186static struct clk_rcg2 rbcpr_clk_src = {
 187        .cmd_rcgr = 0x1030,
 188        .mnd_width = 0,
 189        .hid_width = 5,
 190        .parent_map = gpucc_parent_map_0,
 191        .freq_tbl = ftbl_rbcpr_clk_src,
 192        .clkr.hw.init = &(struct clk_init_data){
 193                .name = "rbcpr_clk_src",
 194                .parent_data = gpucc_parent_data_0,
 195                .num_parents = 3,
 196                .ops = &clk_rcg2_ops,
 197        },
 198};
 199
 200static struct clk_branch gpucc_rbbmtimer_clk = {
 201        .halt_reg = 0x10d0,
 202        .halt_check = BRANCH_HALT,
 203        .clkr = {
 204                .enable_reg = 0x10d0,
 205                .enable_mask = BIT(0),
 206                .hw.init = &(struct clk_init_data){
 207                        .name = "gpucc_rbbmtimer_clk",
 208                        .parent_names = (const char *[]){
 209                                "rbbmtimer_clk_src",
 210                        },
 211                        .num_parents = 1,
 212                        .flags = CLK_SET_RATE_PARENT,
 213                        .ops = &clk_branch2_ops,
 214                },
 215        },
 216};
 217
 218static struct clk_branch gpucc_rbcpr_clk = {
 219        .halt_reg = 0x1054,
 220        .halt_check = BRANCH_HALT,
 221        .clkr = {
 222                .enable_reg = 0x1054,
 223                .enable_mask = BIT(0),
 224                .hw.init = &(struct clk_init_data){
 225                        .name = "gpucc_rbcpr_clk",
 226                        .parent_names = (const char *[]){
 227                                "rbcpr_clk_src",
 228                        },
 229                        .num_parents = 1,
 230                        .flags = CLK_SET_RATE_PARENT,
 231                        .ops = &clk_branch2_ops,
 232                },
 233        },
 234};
 235
 236static struct gdsc gpu_cx_gdsc = {
 237        .gdscr = 0x1004,
 238        .gds_hw_ctrl = 0x1008,
 239        .pd = {
 240                .name = "gpu_cx",
 241        },
 242        .pwrsts = PWRSTS_OFF_ON,
 243        .flags = VOTABLE,
 244};
 245
 246static struct gdsc gpu_gx_gdsc = {
 247        .gdscr = 0x1094,
 248        .clamp_io_ctrl = 0x130,
 249        .resets = (unsigned int []){ GPU_GX_BCR },
 250        .reset_count = 1,
 251        .cxcs = (unsigned int []){ 0x1098 },
 252        .cxc_count = 1,
 253        .pd = {
 254                .name = "gpu_gx",
 255        },
 256        .parent = &gpu_cx_gdsc.pd,
 257        .pwrsts = PWRSTS_OFF | PWRSTS_ON | PWRSTS_RET,
 258        .flags = CLAMP_IO | SW_RESET | AON_RESET | NO_RET_PERIPH,
 259};
 260
 261static struct gdsc *gpucc_sdm660_gdscs[] = {
 262        [GPU_CX_GDSC] = &gpu_cx_gdsc,
 263        [GPU_GX_GDSC] = &gpu_gx_gdsc,
 264};
 265
 266static const struct qcom_reset_map gpucc_sdm660_resets[] = {
 267        [GPU_CX_BCR] = { 0x1000 },
 268        [RBCPR_BCR] = { 0x1050 },
 269        [GPU_GX_BCR] = { 0x1090 },
 270        [SPDM_BCR] = { 0x10E0 },
 271};
 272
 273static struct clk_regmap *gpucc_sdm660_clocks[] = {
 274        [GPUCC_CXO_CLK] = &gpucc_cxo_clk.clkr,
 275        [GPU_PLL0_PLL] = &gpu_pll0_pll_out_main.clkr,
 276        [GPU_PLL1_PLL] = &gpu_pll1_pll_out_main.clkr,
 277        [GFX3D_CLK_SRC] = &gfx3d_clk_src.rcg.clkr,
 278        [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr,
 279        [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr,
 280        [GPUCC_RBCPR_CLK] = &gpucc_rbcpr_clk.clkr,
 281        [GPUCC_GFX3D_CLK] = &gpucc_gfx3d_clk.clkr,
 282        [GPUCC_RBBMTIMER_CLK] = &gpucc_rbbmtimer_clk.clkr,
 283};
 284
 285static const struct regmap_config gpucc_660_regmap_config = {
 286        .reg_bits       = 32,
 287        .reg_stride     = 4,
 288        .val_bits       = 32,
 289        .max_register   = 0x9034,
 290        .fast_io        = true,
 291};
 292
 293static const struct qcom_cc_desc gpucc_sdm660_desc = {
 294        .config = &gpucc_660_regmap_config,
 295        .clks = gpucc_sdm660_clocks,
 296        .num_clks = ARRAY_SIZE(gpucc_sdm660_clocks),
 297        .resets = gpucc_sdm660_resets,
 298        .num_resets = ARRAY_SIZE(gpucc_sdm660_resets),
 299        .gdscs = gpucc_sdm660_gdscs,
 300        .num_gdscs = ARRAY_SIZE(gpucc_sdm660_gdscs),
 301};
 302
 303static const struct of_device_id gpucc_sdm660_match_table[] = {
 304        { .compatible = "qcom,gpucc-sdm660" },
 305        { .compatible = "qcom,gpucc-sdm630" },
 306        { }
 307};
 308MODULE_DEVICE_TABLE(of, gpucc_sdm660_match_table);
 309
 310static int gpucc_sdm660_probe(struct platform_device *pdev)
 311{
 312        struct regmap *regmap;
 313        struct alpha_pll_config gpu_pll_config = {
 314                .config_ctl_val = 0x4001055b,
 315                .alpha = 0xaaaaab00,
 316                .alpha_en_mask = BIT(24),
 317                .vco_val = 0x2 << 20,
 318                .vco_mask = 0x3 << 20,
 319                .main_output_mask = 0x1,
 320        };
 321
 322        regmap = qcom_cc_map(pdev, &gpucc_sdm660_desc);
 323        if (IS_ERR(regmap))
 324                return PTR_ERR(regmap);
 325
 326        /* 800MHz configuration for GPU PLL0 */
 327        gpu_pll_config.l = 0x29;
 328        gpu_pll_config.alpha_hi = 0xaa;
 329        clk_alpha_pll_configure(&gpu_pll0_pll_out_main, regmap, &gpu_pll_config);
 330
 331        /* 740MHz configuration for GPU PLL1 */
 332        gpu_pll_config.l = 0x26;
 333        gpu_pll_config.alpha_hi = 0x8a;
 334        clk_alpha_pll_configure(&gpu_pll1_pll_out_main, regmap, &gpu_pll_config);
 335
 336        return qcom_cc_really_probe(pdev, &gpucc_sdm660_desc, regmap);
 337}
 338
 339static struct platform_driver gpucc_sdm660_driver = {
 340        .probe          = gpucc_sdm660_probe,
 341        .driver         = {
 342                .name   = "gpucc-sdm660",
 343                .of_match_table = gpucc_sdm660_match_table,
 344        },
 345};
 346module_platform_driver(gpucc_sdm660_driver);
 347
 348MODULE_DESCRIPTION("Qualcomm SDM630/SDM660 GPUCC Driver");
 349MODULE_LICENSE("GPL v2");
 350