475 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2021, The Linux Foundation. All rights reserved.4 */5 6#include <linux/clk-provider.h>7#include <linux/kernel.h>8#include <linux/module.h>9#include <linux/platform_device.h>10#include <linux/pm_runtime.h>11#include <linux/regmap.h>12 13#include <dt-bindings/clock/qcom,gpucc-sc8280xp.h>14 15#include "clk-alpha-pll.h"16#include "clk-branch.h"17#include "clk-rcg.h"18#include "clk-regmap-divider.h"19#include "common.h"20#include "reset.h"21#include "gdsc.h"22 23/* Need to match the order of clocks in DT binding */24enum {25 DT_BI_TCXO,26 DT_GCC_GPU_GPLL0_CLK_SRC,27 DT_GCC_GPU_GPLL0_DIV_CLK_SRC,28};29 30enum {31 P_BI_TCXO,32 P_GCC_GPU_GPLL0_CLK_SRC,33 P_GCC_GPU_GPLL0_DIV_CLK_SRC,34 P_GPU_CC_PLL0_OUT_MAIN,35 P_GPU_CC_PLL1_OUT_MAIN,36};37 38static const struct clk_parent_data parent_data_tcxo = { .index = DT_BI_TCXO };39 40static const struct pll_vco lucid_5lpe_vco[] = {41 { 249600000, 1800000000, 0 },42};43 44static struct alpha_pll_config gpu_cc_pll0_config = {45 .l = 0x1c,46 .alpha = 0xa555,47 .config_ctl_val = 0x20485699,48 .config_ctl_hi_val = 0x00002261,49 .config_ctl_hi1_val = 0x2a9a699c,50 .test_ctl_val = 0x00000000,51 .test_ctl_hi_val = 0x00000000,52 .test_ctl_hi1_val = 0x01800000,53 .user_ctl_val = 0x00000000,54 .user_ctl_hi_val = 0x00000805,55 .user_ctl_hi1_val = 0x00000000,56};57 58static struct clk_alpha_pll gpu_cc_pll0 = {59 .offset = 0x0,60 .vco_table = lucid_5lpe_vco,61 .num_vco = ARRAY_SIZE(lucid_5lpe_vco),62 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],63 .clkr = {64 .hw.init = &(const struct clk_init_data){65 .name = "gpu_cc_pll0",66 .parent_data = &parent_data_tcxo,67 .num_parents = 1,68 .ops = &clk_alpha_pll_lucid_5lpe_ops,69 },70 },71};72 73static struct alpha_pll_config gpu_cc_pll1_config = {74 .l = 0x1A,75 .alpha = 0xaaa,76 .config_ctl_val = 0x20485699,77 .config_ctl_hi_val = 0x00002261,78 .config_ctl_hi1_val = 0x2a9a699c,79 .test_ctl_val = 0x00000000,80 .test_ctl_hi_val = 0x00000000,81 .test_ctl_hi1_val = 0x01800000,82 .user_ctl_val = 0x00000000,83 .user_ctl_hi_val = 0x00000805,84 .user_ctl_hi1_val = 0x00000000,85};86 87static struct clk_alpha_pll gpu_cc_pll1 = {88 .offset = 0x100,89 .vco_table = lucid_5lpe_vco,90 .num_vco = ARRAY_SIZE(lucid_5lpe_vco),91 .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],92 .clkr = {93 .hw.init = &(const struct clk_init_data){94 .name = "gpu_cc_pll1",95 .parent_data = &parent_data_tcxo,96 .num_parents = 1,97 .ops = &clk_alpha_pll_lucid_5lpe_ops,98 },99 },100};101 102static const struct parent_map gpu_cc_parent_map_0[] = {103 { P_BI_TCXO, 0 },104 { P_GPU_CC_PLL0_OUT_MAIN, 1 },105 { P_GPU_CC_PLL1_OUT_MAIN, 3 },106 { P_GCC_GPU_GPLL0_CLK_SRC, 5 },107 { P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 },108};109 110static const struct clk_parent_data gpu_cc_parent_data_0[] = {111 { .index = DT_BI_TCXO },112 { .hw = &gpu_cc_pll0.clkr.hw },113 { .hw = &gpu_cc_pll1.clkr.hw },114 { .index = DT_GCC_GPU_GPLL0_CLK_SRC },115 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC },116};117 118static const struct parent_map gpu_cc_parent_map_1[] = {119 { P_BI_TCXO, 0 },120 { P_GPU_CC_PLL1_OUT_MAIN, 3 },121 { P_GCC_GPU_GPLL0_CLK_SRC, 5 },122 { P_GCC_GPU_GPLL0_DIV_CLK_SRC, 6 },123};124 125static const struct clk_parent_data gpu_cc_parent_data_1[] = {126 { .index = DT_BI_TCXO },127 { .hw = &gpu_cc_pll1.clkr.hw },128 { .index = DT_GCC_GPU_GPLL0_CLK_SRC },129 { .index = DT_GCC_GPU_GPLL0_DIV_CLK_SRC },130};131 132static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {133 F(19200000, P_BI_TCXO, 1, 0, 0),134 F(200000000, P_GCC_GPU_GPLL0_DIV_CLK_SRC, 1.5, 0, 0),135 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),136 { }137};138 139static struct clk_rcg2 gpu_cc_gmu_clk_src = {140 .cmd_rcgr = 0x1120,141 .mnd_width = 0,142 .hid_width = 5,143 .parent_map = gpu_cc_parent_map_0,144 .freq_tbl = ftbl_gpu_cc_gmu_clk_src,145 .clkr.hw.init = &(const struct clk_init_data){146 .name = "gpu_cc_gmu_clk_src",147 .parent_data = gpu_cc_parent_data_0,148 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),149 .ops = &clk_rcg2_shared_ops,150 },151};152 153static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = {154 F(200000000, P_GCC_GPU_GPLL0_CLK_SRC, 3, 0, 0),155 F(300000000, P_GCC_GPU_GPLL0_CLK_SRC, 2, 0, 0),156 F(400000000, P_GCC_GPU_GPLL0_CLK_SRC, 1.5, 0, 0),157 { }158};159 160static struct clk_rcg2 gpu_cc_hub_clk_src = {161 .cmd_rcgr = 0x117c,162 .mnd_width = 0,163 .hid_width = 5,164 .parent_map = gpu_cc_parent_map_1,165 .freq_tbl = ftbl_gpu_cc_hub_clk_src,166 .clkr.hw.init = &(const struct clk_init_data){167 .name = "gpu_cc_hub_clk_src",168 .parent_data = gpu_cc_parent_data_1,169 .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),170 .ops = &clk_rcg2_shared_ops,171 },172};173 174static struct clk_regmap_div gpu_cc_hub_ahb_div_clk_src = {175 .reg = 0x11c0,176 .shift = 0,177 .width = 4,178 .clkr.hw.init = &(const struct clk_init_data) {179 .name = "gpu_cc_hub_ahb_div_clk_src",180 .parent_hws = (const struct clk_hw*[]){181 &gpu_cc_hub_clk_src.clkr.hw,182 },183 .num_parents = 1,184 .flags = CLK_SET_RATE_PARENT,185 .ops = &clk_regmap_div_ro_ops,186 },187};188 189static struct clk_regmap_div gpu_cc_hub_cx_int_div_clk_src = {190 .reg = 0x11bc,191 .shift = 0,192 .width = 4,193 .clkr.hw.init = &(const struct clk_init_data) {194 .name = "gpu_cc_hub_cx_int_div_clk_src",195 .parent_hws = (const struct clk_hw*[]){196 &gpu_cc_hub_clk_src.clkr.hw,197 },198 .num_parents = 1,199 .flags = CLK_SET_RATE_PARENT,200 .ops = &clk_regmap_div_ro_ops,201 },202};203 204static struct clk_branch gpu_cc_ahb_clk = {205 .halt_reg = 0x1078,206 .halt_check = BRANCH_HALT_DELAY,207 .clkr = {208 .enable_reg = 0x1078,209 .enable_mask = BIT(0),210 .hw.init = &(const struct clk_init_data){211 .name = "gpu_cc_ahb_clk",212 .parent_hws = (const struct clk_hw*[]){213 &gpu_cc_hub_ahb_div_clk_src.clkr.hw,214 },215 .num_parents = 1,216 .flags = CLK_SET_RATE_PARENT,217 .ops = &clk_branch2_ops,218 },219 },220};221 222static struct clk_branch gpu_cc_crc_ahb_clk = {223 .halt_reg = 0x107c,224 .halt_check = BRANCH_HALT_VOTED,225 .clkr = {226 .enable_reg = 0x107c,227 .enable_mask = BIT(0),228 .hw.init = &(const struct clk_init_data){229 .name = "gpu_cc_crc_ahb_clk",230 .parent_hws = (const struct clk_hw*[]){231 &gpu_cc_hub_ahb_div_clk_src.clkr.hw,232 },233 .num_parents = 1,234 .flags = CLK_SET_RATE_PARENT,235 .ops = &clk_branch2_ops,236 },237 },238};239 240static struct clk_branch gpu_cc_cx_gmu_clk = {241 .halt_reg = 0x1098,242 .halt_check = BRANCH_HALT,243 .clkr = {244 .enable_reg = 0x1098,245 .enable_mask = BIT(0),246 .hw.init = &(const struct clk_init_data){247 .name = "gpu_cc_cx_gmu_clk",248 .parent_hws = (const struct clk_hw*[]){249 &gpu_cc_gmu_clk_src.clkr.hw,250 },251 .num_parents = 1,252 .flags = CLK_SET_RATE_PARENT,253 .ops = &clk_branch2_aon_ops,254 },255 },256};257 258static struct clk_branch gpu_cc_cx_snoc_dvm_clk = {259 .halt_reg = 0x108c,260 .halt_check = BRANCH_HALT_VOTED,261 .clkr = {262 .enable_reg = 0x108c,263 .enable_mask = BIT(0),264 .hw.init = &(const struct clk_init_data){265 .name = "gpu_cc_cx_snoc_dvm_clk",266 .ops = &clk_branch2_ops,267 },268 },269};270 271static struct clk_branch gpu_cc_cxo_aon_clk = {272 .halt_reg = 0x1004,273 .halt_check = BRANCH_HALT_VOTED,274 .clkr = {275 .enable_reg = 0x1004,276 .enable_mask = BIT(0),277 .hw.init = &(const struct clk_init_data){278 .name = "gpu_cc_cxo_aon_clk",279 .ops = &clk_branch2_ops,280 },281 },282};283 284static struct clk_branch gpu_cc_gx_gmu_clk = {285 .halt_reg = 0x1064,286 .halt_check = BRANCH_HALT,287 .clkr = {288 .enable_reg = 0x1064,289 .enable_mask = BIT(0),290 .hw.init = &(const struct clk_init_data){291 .name = "gpu_cc_gx_gmu_clk",292 .parent_hws = (const struct clk_hw*[]){293 &gpu_cc_gmu_clk_src.clkr.hw,294 },295 .num_parents = 1,296 .flags = CLK_SET_RATE_PARENT,297 .ops = &clk_branch2_ops,298 },299 },300};301 302static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {303 .halt_reg = 0x5000,304 .halt_check = BRANCH_HALT_VOTED,305 .clkr = {306 .enable_reg = 0x5000,307 .enable_mask = BIT(0),308 .hw.init = &(const struct clk_init_data){309 .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",310 .ops = &clk_branch2_ops,311 },312 },313};314 315static struct clk_branch gpu_cc_hub_aon_clk = {316 .halt_reg = 0x1178,317 .halt_check = BRANCH_HALT,318 .clkr = {319 .enable_reg = 0x1178,320 .enable_mask = BIT(0),321 .hw.init = &(const struct clk_init_data){322 .name = "gpu_cc_hub_aon_clk",323 .parent_hws = (const struct clk_hw*[]){324 &gpu_cc_hub_clk_src.clkr.hw,325 },326 .num_parents = 1,327 .flags = CLK_SET_RATE_PARENT,328 .ops = &clk_branch2_aon_ops,329 },330 },331};332 333static struct clk_branch gpu_cc_hub_cx_int_clk = {334 .halt_reg = 0x1204,335 .halt_check = BRANCH_HALT,336 .clkr = {337 .enable_reg = 0x1204,338 .enable_mask = BIT(0),339 .hw.init = &(const struct clk_init_data){340 .name = "gpu_cc_hub_cx_int_clk",341 .parent_hws = (const struct clk_hw*[]){342 &gpu_cc_hub_cx_int_div_clk_src.clkr.hw,343 },344 .num_parents = 1,345 .flags = CLK_SET_RATE_PARENT,346 .ops = &clk_branch2_aon_ops,347 },348 },349};350 351static struct clk_branch gpu_cc_sleep_clk = {352 .halt_reg = 0x1090,353 .halt_check = BRANCH_HALT_VOTED,354 .clkr = {355 .enable_reg = 0x1090,356 .enable_mask = BIT(0),357 .hw.init = &(const struct clk_init_data){358 .name = "gpu_cc_sleep_clk",359 .ops = &clk_branch2_ops,360 },361 },362};363 364static struct clk_regmap *gpu_cc_sc8280xp_clocks[] = {365 [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,366 [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,367 [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,368 [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr,369 [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,370 [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,371 [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,372 [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,373 [GPU_CC_HUB_AHB_DIV_CLK_SRC] = &gpu_cc_hub_ahb_div_clk_src.clkr,374 [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,375 [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,376 [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,377 [GPU_CC_HUB_CX_INT_DIV_CLK_SRC] = &gpu_cc_hub_cx_int_div_clk_src.clkr,378 [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,379 [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,380 [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr,381};382 383static struct gdsc cx_gdsc = {384 .gdscr = 0x106c,385 .gds_hw_ctrl = 0x1540,386 .pd = {387 .name = "cx_gdsc",388 },389 .pwrsts = PWRSTS_OFF_ON,390 .flags = VOTABLE | RETAIN_FF_ENABLE,391};392 393static struct gdsc gx_gdsc = {394 .gdscr = 0x100c,395 .clamp_io_ctrl = 0x1508,396 .pd = {397 .name = "gx_gdsc",398 .power_on = gdsc_gx_do_nothing_enable,399 },400 .pwrsts = PWRSTS_OFF_ON,401 .flags = CLAMP_IO | RETAIN_FF_ENABLE,402 .supply = "vdd-gfx",403};404 405static struct gdsc *gpu_cc_sc8280xp_gdscs[] = {406 [GPU_CC_CX_GDSC] = &cx_gdsc,407 [GPU_CC_GX_GDSC] = &gx_gdsc,408};409 410static const struct regmap_config gpu_cc_sc8280xp_regmap_config = {411 .reg_bits = 32,412 .reg_stride = 4,413 .val_bits = 32,414 .max_register = 0x8030,415 .fast_io = true,416};417 418static struct qcom_cc_desc gpu_cc_sc8280xp_desc = {419 .config = &gpu_cc_sc8280xp_regmap_config,420 .clks = gpu_cc_sc8280xp_clocks,421 .num_clks = ARRAY_SIZE(gpu_cc_sc8280xp_clocks),422 .gdscs = gpu_cc_sc8280xp_gdscs,423 .num_gdscs = ARRAY_SIZE(gpu_cc_sc8280xp_gdscs),424};425 426static int gpu_cc_sc8280xp_probe(struct platform_device *pdev)427{428 struct regmap *regmap;429 int ret;430 431 ret = devm_pm_runtime_enable(&pdev->dev);432 if (ret)433 return ret;434 435 ret = pm_runtime_resume_and_get(&pdev->dev);436 if (ret)437 return ret;438 439 regmap = qcom_cc_map(pdev, &gpu_cc_sc8280xp_desc);440 if (IS_ERR(regmap)) {441 pm_runtime_put(&pdev->dev);442 return PTR_ERR(regmap);443 }444 445 clk_lucid_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);446 clk_lucid_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);447 448 /* Keep some clocks always-on */449 qcom_branch_set_clk_en(regmap, 0x1170); /* GPU_CC_CB_CLK */450 qcom_branch_set_clk_en(regmap, 0x109c); /* GPU_CC_CXO_CLK */451 452 ret = qcom_cc_really_probe(&pdev->dev, &gpu_cc_sc8280xp_desc, regmap);453 pm_runtime_put(&pdev->dev);454 455 return ret;456}457 458static const struct of_device_id gpu_cc_sc8280xp_match_table[] = {459 { .compatible = "qcom,sc8280xp-gpucc" },460 { }461};462MODULE_DEVICE_TABLE(of, gpu_cc_sc8280xp_match_table);463 464static struct platform_driver gpu_cc_sc8280xp_driver = {465 .probe = gpu_cc_sc8280xp_probe,466 .driver = {467 .name = "gpu_cc-sc8280xp",468 .of_match_table = gpu_cc_sc8280xp_match_table,469 },470};471module_platform_driver(gpu_cc_sc8280xp_driver);472 473MODULE_DESCRIPTION("Qualcomm SC8280XP GPU clock controller");474MODULE_LICENSE("GPL");475