Message ID | 1572524473-19344-5-git-send-email-tdas@codeaurora.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | Add GPU & Video Clock controller driver for SC7180 | expand |
Quoting Taniya Das (2019-10-31 05:21:10) > diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c > new file mode 100644 > index 0000000..0d893e6 > --- /dev/null > +++ b/drivers/clk/qcom/gpucc-sc7180.c > @@ -0,0 +1,274 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (c) 2019, The Linux Foundation. All rights reserved. > + */ > + > +#include <linux/clk-provider.h> > +#include <linux/err.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/of_device.h> Are these of includes used? > +#include <linux/regmap.h> > + > +#include <dt-bindings/clock/qcom,gpucc-sc7180.h> > + > +#include "clk-alpha-pll.h" > +#include "clk-branch.h" > +#include "clk-rcg.h" > +#include "clk-regmap.h" > +#include "common.h" > +#include "gdsc.h" > + > +#define CX_GMU_CBCR_SLEEP_MASK 0xF > +#define CX_GMU_CBCR_SLEEP_SHIFT 4 > +#define CX_GMU_CBCR_WAKE_MASK 0xF > +#define CX_GMU_CBCR_WAKE_SHIFT 8 > +#define CLK_DIS_WAIT_SHIFT 12 > +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) > + > +enum { > + P_BI_TCXO, > + P_CORE_BI_PLL_TEST_SE, > + P_GPLL0_OUT_MAIN, > + P_GPLL0_OUT_MAIN_DIV, > + P_GPU_CC_PLL1_OUT_EVEN, > + P_GPU_CC_PLL1_OUT_MAIN, > + P_GPU_CC_PLL1_OUT_ODD, > +}; > + > +static struct pll_vco fabia_vco[] = { const? > + { 249600000, 2000000000, 0 }, > +}; > + > +static struct clk_alpha_pll gpu_cc_pll1 = { > + .offset = 0x100, > + .vco_table = fabia_vco, > + .num_vco = ARRAY_SIZE(fabia_vco), > + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], > + .clkr = { > + .hw.init = &(struct clk_init_data){ > + .name = "gpu_cc_pll1", > + .parent_data = &(const struct clk_parent_data){ > + .fw_name = "bi_tcxo", > + .name = "bi_tcxo", Do we need both? This is new so it should just work with .fw_name right? > + }, > + .num_parents = 1, > + .ops = &clk_alpha_pll_fabia_ops, > + }, > + }, > +}; > + > +static const struct parent_map gpu_cc_parent_map_0[] = { > + { P_BI_TCXO, 0 }, > + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, > + { P_GPLL0_OUT_MAIN, 5 }, > + { P_GPLL0_OUT_MAIN_DIV, 6 }, > + { P_CORE_BI_PLL_TEST_SE, 7 }, > +}; > + > +static const struct clk_parent_data gpu_cc_parent_data_0[] = { > + { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, > + { .hw = &gpu_cc_pll1.clkr.hw }, > + { .fw_name = "gcc_gpu_gpll0_clk_src", .name = "gcc_gpu_gpll0_clk_src" }, > + { .fw_name = "gcc_gpu_gpll0_div_clk_src", > + .name = "gcc_gpu_gpll0_div_clk_src" }, > + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, > +}; Same for these. > + > +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { > + F(19200000, P_BI_TCXO, 1, 0, 0), > + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), > + { } > +}; [..] > + > + > +static int gpu_cc_sc7180_probe(struct platform_device *pdev) > +{ > + struct regmap *regmap; > + struct alpha_pll_config gpu_cc_pll_config = {}; > + unsigned int value, mask; > + > + regmap = qcom_cc_map(pdev, &gpu_cc_sc7180_desc); > + if (IS_ERR(regmap)) > + return PTR_ERR(regmap); > + > + /* 360MHz Configuration */ > + gpu_cc_pll_config.l = 0x12; > + gpu_cc_pll_config.alpha = 0xC000; > + gpu_cc_pll_config.config_ctl_val = 0x20485699; > + gpu_cc_pll_config.config_ctl_hi_val = 0x00002067; > + gpu_cc_pll_config.user_ctl_val = 0x00000001; > + gpu_cc_pll_config.user_ctl_hi_val = 0x00004805; > + gpu_cc_pll_config.test_ctl_hi_val = 0x40000000; Is there a reason this is built on the stack? Save space or something? > + > + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll_config); > + > + /* Recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ > + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; > + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; > + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; mask and value can just be big constants? I'm not sure anyone cares to tweak this later, but I guess it's fine this way too. > + regmap_update_bits(regmap, 0x1098, mask, value); > + > + /* gpu_cc_ahb_clk */ What are we doing to gpu_cc_ahb_clk?? > + regmap_update_bits(regmap, 0x1078, 0x1, 0x1); > + > + /* Configure clk_dis_wait for gpu_cx_gdsc */ > + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, > + 8 << CLK_DIS_WAIT_SHIFT); > + > + return qcom_cc_really_probe(pdev, &gpu_cc_sc7180_desc, regmap); > +} > + > +static struct platform_driver gpu_cc_sc7180_driver = { > + .probe = gpu_cc_sc7180_probe, > + .driver = { > + .name = "sc7180-gpucc", > + .of_match_table = gpu_cc_sc7180_match_table, > + }, > +}; > + > +static int __init gpu_cc_sc7180_init(void) > +{ > + return platform_driver_register(&gpu_cc_sc7180_driver); > +} > +core_initcall(gpu_cc_sc7180_init); Does it need to be core initcal? Maybe module_platform_driver() works just as well? > + > +static void __exit gpu_cc_sc7180_exit(void) > +{ > + platform_driver_unregister(&gpu_cc_sc7180_driver); > +} > +module_exit(gpu_cc_sc7180_exit); > + > +MODULE_DESCRIPTION("QTI GPU_CC SC7180 Driver"); > +MODULE_LICENSE("GPL v2");
Hi Stephen, Thanks for the review. On 11/6/2019 6:00 AM, Stephen Boyd wrote: > Quoting Taniya Das (2019-10-31 05:21:10) >> diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c >> new file mode 100644 >> index 0000000..0d893e6 >> --- /dev/null >> +++ b/drivers/clk/qcom/gpucc-sc7180.c >> @@ -0,0 +1,274 @@ >> +// SPDX-License-Identifier: GPL-2.0-only >> +/* >> + * Copyright (c) 2019, The Linux Foundation. All rights reserved. >> + */ >> + >> +#include <linux/clk-provider.h> >> +#include <linux/err.h> >> +#include <linux/kernel.h> >> +#include <linux/module.h> >> +#include <linux/of.h> >> +#include <linux/of_device.h> > > Are these of includes used? > yes, would clean up these headers. >> +#include <linux/regmap.h> >> + >> +#include <dt-bindings/clock/qcom,gpucc-sc7180.h> >> + >> +#include "clk-alpha-pll.h" >> +#include "clk-branch.h" >> +#include "clk-rcg.h" >> +#include "clk-regmap.h" >> +#include "common.h" >> +#include "gdsc.h" >> + >> +#define CX_GMU_CBCR_SLEEP_MASK 0xF >> +#define CX_GMU_CBCR_SLEEP_SHIFT 4 >> +#define CX_GMU_CBCR_WAKE_MASK 0xF >> +#define CX_GMU_CBCR_WAKE_SHIFT 8 >> +#define CLK_DIS_WAIT_SHIFT 12 >> +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) >> + >> +enum { >> + P_BI_TCXO, >> + P_CORE_BI_PLL_TEST_SE, >> + P_GPLL0_OUT_MAIN, >> + P_GPLL0_OUT_MAIN_DIV, >> + P_GPU_CC_PLL1_OUT_EVEN, >> + P_GPU_CC_PLL1_OUT_MAIN, >> + P_GPU_CC_PLL1_OUT_ODD, >> +}; >> + >> +static struct pll_vco fabia_vco[] = { > > const? > Will take care. >> + { 249600000, 2000000000, 0 }, >> +}; >> + >> +static struct clk_alpha_pll gpu_cc_pll1 = { >> + .offset = 0x100, >> + .vco_table = fabia_vco, >> + .num_vco = ARRAY_SIZE(fabia_vco), >> + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], >> + .clkr = { >> + .hw.init = &(struct clk_init_data){ >> + .name = "gpu_cc_pll1", >> + .parent_data = &(const struct clk_parent_data){ >> + .fw_name = "bi_tcxo", >> + .name = "bi_tcxo", > > Do we need both? This is new so it should just work with .fw_name right? > yes, will clean this up. >> + }, >> + .num_parents = 1, >> + .ops = &clk_alpha_pll_fabia_ops, >> + }, >> + }, >> +}; >> + >> +static const struct parent_map gpu_cc_parent_map_0[] = { >> + { P_BI_TCXO, 0 }, >> + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, >> + { P_GPLL0_OUT_MAIN, 5 }, >> + { P_GPLL0_OUT_MAIN_DIV, 6 }, >> + { P_CORE_BI_PLL_TEST_SE, 7 }, >> +}; >> + >> +static const struct clk_parent_data gpu_cc_parent_data_0[] = { >> + { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, >> + { .hw = &gpu_cc_pll1.clkr.hw }, >> + { .fw_name = "gcc_gpu_gpll0_clk_src", .name = "gcc_gpu_gpll0_clk_src" }, >> + { .fw_name = "gcc_gpu_gpll0_div_clk_src", >> + .name = "gcc_gpu_gpll0_div_clk_src" }, >> + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, >> +}; > > Same for these. > >> + >> +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { >> + F(19200000, P_BI_TCXO, 1, 0, 0), >> + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), >> + { } >> +}; > [..] >> + >> + >> +static int gpu_cc_sc7180_probe(struct platform_device *pdev) >> +{ >> + struct regmap *regmap; >> + struct alpha_pll_config gpu_cc_pll_config = {}; >> + unsigned int value, mask; >> + >> + regmap = qcom_cc_map(pdev, &gpu_cc_sc7180_desc); >> + if (IS_ERR(regmap)) >> + return PTR_ERR(regmap); >> + >> + /* 360MHz Configuration */ >> + gpu_cc_pll_config.l = 0x12; >> + gpu_cc_pll_config.alpha = 0xC000; >> + gpu_cc_pll_config.config_ctl_val = 0x20485699; >> + gpu_cc_pll_config.config_ctl_hi_val = 0x00002067; >> + gpu_cc_pll_config.user_ctl_val = 0x00000001; >> + gpu_cc_pll_config.user_ctl_hi_val = 0x00004805; >> + gpu_cc_pll_config.test_ctl_hi_val = 0x40000000; > > Is there a reason this is built on the stack? Save space or something? > I have done as we had discussed during the dispcc review for SDM845 https://patchwork.kernel.org/patch/10446073/ >>> >> +static const struct alpha_pll_config disp_cc_pll0_config = { >> + .l = 0x2c, >> + .alpha = 0xcaaa, >> +}; > > Any reason this can't be put on the stack in the probe function? > I would move it. >>> In case you think I should move it outside I can do that too. >> + >> + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll_config); >> + >> + /* Recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ >> + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; >> + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; >> + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; > > mask and value can just be big constants? I'm not sure anyone cares to > tweak this later, but I guess it's fine this way too. > >> + regmap_update_bits(regmap, 0x1098, mask, value); >> + >> + /* gpu_cc_ahb_clk */ > > What are we doing to gpu_cc_ahb_clk?? > I was marking this CRITICAL clock, but I checked the HW specs and it is always left ON from HW, so will remove it. >> + regmap_update_bits(regmap, 0x1078, 0x1, 0x1); >> + >> + /* Configure clk_dis_wait for gpu_cx_gdsc */ >> + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, >> + 8 << CLK_DIS_WAIT_SHIFT); >> + >> + return qcom_cc_really_probe(pdev, &gpu_cc_sc7180_desc, regmap); >> +} >> + >> +static struct platform_driver gpu_cc_sc7180_driver = { >> + .probe = gpu_cc_sc7180_probe, >> + .driver = { >> + .name = "sc7180-gpucc", >> + .of_match_table = gpu_cc_sc7180_match_table, >> + }, >> +}; >> + >> +static int __init gpu_cc_sc7180_init(void) >> +{ >> + return platform_driver_register(&gpu_cc_sc7180_driver); >> +} >> +core_initcall(gpu_cc_sc7180_init); > > Does it need to be core initcal? Maybe module_platform_driver() works > just as well? > I will leave it to subsys_initcall. >> + >> +static void __exit gpu_cc_sc7180_exit(void) >> +{ >> + platform_driver_unregister(&gpu_cc_sc7180_driver); >> +} >> +module_exit(gpu_cc_sc7180_exit); >> + >> +MODULE_DESCRIPTION("QTI GPU_CC SC7180 Driver"); >> +MODULE_LICENSE("GPL v2");
Quoting Taniya Das (2019-11-15 00:11:28) > Hi Stephen, > > Thanks for the review. > > On 11/6/2019 6:00 AM, Stephen Boyd wrote: > > Quoting Taniya Das (2019-10-31 05:21:10) > >> diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c > >> new file mode 100644 > >> index 0000000..0d893e6 > >> --- /dev/null > >> +++ b/drivers/clk/qcom/gpucc-sc7180.c > >> @@ -0,0 +1,274 @@ > >> +// SPDX-License-Identifier: GPL-2.0-only > >> +/* > >> + * Copyright (c) 2019, The Linux Foundation. All rights reserved. > >> + */ > >> + > >> +#include <linux/clk-provider.h> > >> +#include <linux/err.h> > >> +#include <linux/kernel.h> > >> +#include <linux/module.h> > >> +#include <linux/of.h> > >> +#include <linux/of_device.h> > > > > Are these of includes used? > > > > yes, would clean up these headers. > Maybe they're used. I'm not sure. > >> + regmap = qcom_cc_map(pdev, &gpu_cc_sc7180_desc); > >> + if (IS_ERR(regmap)) > >> + return PTR_ERR(regmap); > >> + > >> + /* 360MHz Configuration */ > >> + gpu_cc_pll_config.l = 0x12; > >> + gpu_cc_pll_config.alpha = 0xC000; > >> + gpu_cc_pll_config.config_ctl_val = 0x20485699; > >> + gpu_cc_pll_config.config_ctl_hi_val = 0x00002067; > >> + gpu_cc_pll_config.user_ctl_val = 0x00000001; > >> + gpu_cc_pll_config.user_ctl_hi_val = 0x00004805; > >> + gpu_cc_pll_config.test_ctl_hi_val = 0x40000000; > > > > Is there a reason this is built on the stack? Save space or something? > > > > I have done as we had discussed during the dispcc review for SDM845 > https://patchwork.kernel.org/patch/10446073/ > >>> > >> +static const struct alpha_pll_config disp_cc_pll0_config = { > >> + .l = 0x2c, > >> + .alpha = 0xcaaa, > >> +}; > > > > Any reason this can't be put on the stack in the probe function? > > > I would move it. > >>> > > In case you think I should move it outside I can do that too. No I was just wondering what prompted it.
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 91706d8..c898e62 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -236,6 +236,14 @@ config SC_GCC_7180 Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, UFS, SDCC, etc. +config SC_GPUCC_7180 + tristate "SC7180 Graphics Clock Controller" + select SC_GCC_7180 + help + Support for the graphics clock controller on SC7180 devices. + Say Y if you want to support graphics controller devices and + functionality such as 3D graphics. + config SDM_CAMCC_845 tristate "SDM845 Camera Clock Controller" select SDM_GCC_845 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 6fb356a..b89a292 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o +obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_DISPCC_845) += dispcc-sdm845.o obj-$(CONFIG_SDM_GCC_660) += gcc-sdm660.o diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c new file mode 100644 index 0000000..0d893e6 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sc7180.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019, The Linux Foundation. All rights reserved. + */ + +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#include <dt-bindings/clock/qcom,gpucc-sc7180.h> + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "gdsc.h" + +#define CX_GMU_CBCR_SLEEP_MASK 0xF +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xF +#define CX_GMU_CBCR_WAKE_SHIFT 8 +#define CLK_DIS_WAIT_SHIFT 12 +#define CLK_DIS_WAIT_MASK (0xf << CLK_DIS_WAIT_SHIFT) + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_data = &(const struct clk_parent_data){ + .fw_name = "bi_tcxo", + .name = "bi_tcxo", + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fabia_ops, + }, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .fw_name = "bi_tcxo", .name = "bi_tcxo" }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .fw_name = "gcc_gpu_gpll0_clk_src", .name = "gcc_gpu_gpll0_clk_src" }, + { .fw_name = "gcc_gpu_gpll0_div_clk_src", + .name = "gcc_gpu_gpll0_div_clk_src" }, + { .fw_name = "core_bi_pll_test_se", .name = "core_bi_pll_test_se" }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_data = &(const struct clk_parent_data){ + .hw = &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc cx_gdsc = { + .gdscr = 0x106c, + .gds_hw_ctrl = 0x1540, + .pd = { + .name = "cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE, +}; + +static struct gdsc *gpu_cc_sc7180_gdscs[] = { + [CX_GDSC] = &cx_gdsc, +}; + +static struct clk_regmap *gpu_cc_sc7180_clocks[] = { + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, +}; + +static const struct regmap_config gpu_cc_sc7180_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8008, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sc7180_desc = { + .config = &gpu_cc_sc7180_regmap_config, + .clks = gpu_cc_sc7180_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sc7180_clocks), + .gdscs = gpu_cc_sc7180_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sc7180_gdscs), +}; + +static const struct of_device_id gpu_cc_sc7180_match_table[] = { + { .compatible = "qcom,sc7180-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sc7180_match_table); + +static int gpu_cc_sc7180_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct alpha_pll_config gpu_cc_pll_config = {}; + unsigned int value, mask; + + regmap = qcom_cc_map(pdev, &gpu_cc_sc7180_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* 360MHz Configuration */ + gpu_cc_pll_config.l = 0x12; + gpu_cc_pll_config.alpha = 0xC000; + gpu_cc_pll_config.config_ctl_val = 0x20485699; + gpu_cc_pll_config.config_ctl_hi_val = 0x00002067; + gpu_cc_pll_config.user_ctl_val = 0x00000001; + gpu_cc_pll_config.user_ctl_hi_val = 0x00004805; + gpu_cc_pll_config.test_ctl_hi_val = 0x40000000; + + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll_config); + + /* Recommended WAKEUP/SLEEP settings for the gpu_cc_cx_gmu_clk */ + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, 0x1098, mask, value); + + /* gpu_cc_ahb_clk */ + regmap_update_bits(regmap, 0x1078, 0x1, 0x1); + + /* Configure clk_dis_wait for gpu_cx_gdsc */ + regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK, + 8 << CLK_DIS_WAIT_SHIFT); + + return qcom_cc_really_probe(pdev, &gpu_cc_sc7180_desc, regmap); +} + +static struct platform_driver gpu_cc_sc7180_driver = { + .probe = gpu_cc_sc7180_probe, + .driver = { + .name = "sc7180-gpucc", + .of_match_table = gpu_cc_sc7180_match_table, + }, +}; + +static int __init gpu_cc_sc7180_init(void) +{ + return platform_driver_register(&gpu_cc_sc7180_driver); +} +core_initcall(gpu_cc_sc7180_init); + +static void __exit gpu_cc_sc7180_exit(void) +{ + platform_driver_unregister(&gpu_cc_sc7180_driver); +} +module_exit(gpu_cc_sc7180_exit); + +MODULE_DESCRIPTION("QTI GPU_CC SC7180 Driver"); +MODULE_LICENSE("GPL v2");
Add support for the graphics clock controller found on SC7180 based devices. This would allow graphics drivers to probe and control their clocks. Signed-off-by: Taniya Das <tdas@codeaurora.org> --- drivers/clk/qcom/Kconfig | 8 ++ drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gpucc-sc7180.c | 274 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 drivers/clk/qcom/gpucc-sc7180.c -- Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member of the Code Aurora Forum, hosted by the Linux Foundation.