root/drivers/clk/qcom/gpucc-sdm845.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gx_gdsc_enable
  2. gpu_cc_sdm845_probe
  3. gpu_cc_sdm845_init
  4. gpu_cc_sdm845_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
   4  */
   5 
   6 #include <linux/clk-provider.h>
   7 #include <linux/module.h>
   8 #include <linux/platform_device.h>
   9 #include <linux/regmap.h>
  10 
  11 #include <dt-bindings/clock/qcom,gpucc-sdm845.h>
  12 
  13 #include "common.h"
  14 #include "clk-alpha-pll.h"
  15 #include "clk-branch.h"
  16 #include "clk-pll.h"
  17 #include "clk-rcg.h"
  18 #include "clk-regmap.h"
  19 #include "gdsc.h"
  20 
  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)
  27 
  28 enum {
  29         P_BI_TCXO,
  30         P_CORE_BI_PLL_TEST_SE,
  31         P_GPLL0_OUT_MAIN,
  32         P_GPLL0_OUT_MAIN_DIV,
  33         P_GPU_CC_PLL1_OUT_EVEN,
  34         P_GPU_CC_PLL1_OUT_MAIN,
  35         P_GPU_CC_PLL1_OUT_ODD,
  36 };
  37 
  38 static const struct parent_map gpu_cc_parent_map_0[] = {
  39         { P_BI_TCXO, 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 },
  44 };
  45 
  46 static const char * const gpu_cc_parent_names_0[] = {
  47         "bi_tcxo",
  48         "gpu_cc_pll1",
  49         "gcc_gpu_gpll0_clk_src",
  50         "gcc_gpu_gpll0_div_clk_src",
  51         "core_bi_pll_test_se",
  52 };
  53 
  54 static const struct alpha_pll_config gpu_cc_pll1_config = {
  55         .l = 0x1a,
  56         .alpha = 0xaab,
  57 };
  58 
  59 static struct clk_alpha_pll gpu_cc_pll1 = {
  60         .offset = 0x100,
  61         .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
  62         .clkr = {
  63                 .hw.init = &(struct clk_init_data){
  64                         .name = "gpu_cc_pll1",
  65                         .parent_names = (const char *[]){ "bi_tcxo" },
  66                         .num_parents = 1,
  67                         .ops = &clk_alpha_pll_fabia_ops,
  68                 },
  69         },
  70 };
  71 
  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),
  76         { }
  77 };
  78 
  79 static struct clk_rcg2 gpu_cc_gmu_clk_src = {
  80         .cmd_rcgr = 0x1120,
  81         .mnd_width = 0,
  82         .hid_width = 5,
  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,
  88                 .num_parents = 5,
  89                 .ops = &clk_rcg2_shared_ops,
  90         },
  91 };
  92 
  93 static struct clk_branch gpu_cc_cx_gmu_clk = {
  94         .halt_reg = 0x1098,
  95         .halt_check = BRANCH_HALT,
  96         .clkr = {
  97                 .enable_reg = 0x1098,
  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",
 103                         },
 104                         .num_parents = 1,
 105                         .flags = CLK_SET_RATE_PARENT,
 106                         .ops = &clk_branch2_ops,
 107                 },
 108         },
 109 };
 110 
 111 static struct clk_branch gpu_cc_cxo_clk = {
 112         .halt_reg = 0x109c,
 113         .halt_check = BRANCH_HALT,
 114         .clkr = {
 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,
 120                 },
 121         },
 122 };
 123 
 124 static struct gdsc gpu_cx_gdsc = {
 125         .gdscr = 0x106c,
 126         .gds_hw_ctrl = 0x1540,
 127         .pd = {
 128                 .name = "gpu_cx_gdsc",
 129         },
 130         .pwrsts = PWRSTS_OFF_ON,
 131         .flags = VOTABLE,
 132 };
 133 
 134 /*
 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....
 138  *
 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
 146  * function.
 147  *
 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.
 152  */
 153 static int gx_gdsc_enable(struct generic_pm_domain *domain)
 154 {
 155         /* Do nothing but give genpd the impression that we were successful */
 156         return 0;
 157 }
 158 
 159 static struct gdsc gpu_gx_gdsc = {
 160         .gdscr = 0x100c,
 161         .clamp_io_ctrl = 0x1508,
 162         .pd = {
 163                 .name = "gpu_gx_gdsc",
 164                 .power_on = gx_gdsc_enable,
 165         },
 166         .pwrsts = PWRSTS_OFF_ON,
 167         .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
 168 };
 169 
 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,
 175 };
 176 
 177 static struct gdsc *gpu_cc_sdm845_gdscs[] = {
 178         [GPU_CX_GDSC] = &gpu_cx_gdsc,
 179         [GPU_GX_GDSC] = &gpu_gx_gdsc,
 180 };
 181 
 182 static const struct regmap_config gpu_cc_sdm845_regmap_config = {
 183         .reg_bits       = 32,
 184         .reg_stride     = 4,
 185         .val_bits       = 32,
 186         .max_register   = 0x8008,
 187         .fast_io        = true,
 188 };
 189 
 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),
 196 };
 197 
 198 static const struct of_device_id gpu_cc_sdm845_match_table[] = {
 199         { .compatible = "qcom,sdm845-gpucc" },
 200         { }
 201 };
 202 MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
 203 
 204 static int gpu_cc_sdm845_probe(struct platform_device *pdev)
 205 {
 206         struct regmap *regmap;
 207         unsigned int value, mask;
 208 
 209         regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc);
 210         if (IS_ERR(regmap))
 211                 return PTR_ERR(regmap);
 212 
 213         clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
 214 
 215         /*
 216          * Configure gpu_cc_cx_gmu_clk with recommended
 217          * wakeup/sleep settings
 218          */
 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);
 223 
 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);
 227 
 228         return qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
 229 }
 230 
 231 static struct platform_driver gpu_cc_sdm845_driver = {
 232         .probe = gpu_cc_sdm845_probe,
 233         .driver = {
 234                 .name = "sdm845-gpucc",
 235                 .of_match_table = gpu_cc_sdm845_match_table,
 236         },
 237 };
 238 
 239 static int __init gpu_cc_sdm845_init(void)
 240 {
 241         return platform_driver_register(&gpu_cc_sdm845_driver);
 242 }
 243 subsys_initcall(gpu_cc_sdm845_init);
 244 
 245 static void __exit gpu_cc_sdm845_exit(void)
 246 {
 247         platform_driver_unregister(&gpu_cc_sdm845_driver);
 248 }
 249 module_exit(gpu_cc_sdm845_exit);
 250 
 251 MODULE_DESCRIPTION("QTI GPUCC SDM845 Driver");
 252 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */