2018-07-12 17:10:51

by Amit Nischal

[permalink] [raw]
Subject: [PATCH v2 0/4] Add QCOM graphics clock controller driver for SDM845

Changes in v2:
Addressed review comments given by Stephen: https://lkml.org/lkml/2018/6/6/294
* Introduce clk_rcg2_gfx3d_determine_rate ops to return the best parent
as 'gpucc_pll0_even' and best parent rate as twice of the requested rate
always. This will eliminate the need of frequency table as source and
div-2 are fixed for gfx3d_clk_src.
Also modified the clk_rcg2_set_rate ops to configure the fixed source and
div.
* Add support to check if requested rate falls within allowed set_rate range.
This will not let the source gpucc_pll0 to go out of the supported range
and also client can request the rate within the range.
* Fixed comment text in probe function and added module description for GPUCC
driver.

The graphics clock driver depends upon the below change.
https://lkml.org/lkml/2018/6/23/108

Changes in v1:
This patch series adds support for graphics clock controller for SDM845.
Below is the brief description for each change:

1. For some of the GDSCs, there is requirement to enable/disable the
few clocks before turning on/off the gdsc power domain. This patch
will add support to enable/disable the clock associated with the
gdsc along with power domain on/off callbacks.

2. To turn on the gpu_gx_gdsc, there is a hardware requirement to
turn on the root clock (GFX3D RCG) first which would be the turn
on signal for the gdsc along with the SW_COLLAPSE. As per the
current implementation of clk_rcg2_shared_ops, it clears the
root_enable bit in the enable() clock ops. But due to the above
said requirement for GFX3D shared RCG, root_enable bit would be
already set by gdsc driver and rcg2_shared_ops should not clear
the root unless the disable() is called.

This patch add support for the same by reusing the existing
clk_rcg2_shared_ops and deriving "clk_rcg2_gfx3d_ops" clk_ops
for GFX3D clock to take care of the root set/clear requirement.

3. Add device tree bindings for graphics clock controller for SDM845.

4. Add graphics clock controller (GPUCC) driver for SDM845.

[v1] : https://lkml.org/lkml/2018/6/6/294

Amit Nischal (4):
clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC
clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845
dt-bindings: clock: Introduce QCOM Graphics clock bindings
clk: qcom: Add graphics clock controller driver for SDM845

.../devicetree/bindings/clock/qcom,gpucc.txt | 18 +
drivers/clk/qcom/Kconfig | 9 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/clk-rcg.h | 1 +
drivers/clk/qcom/clk-rcg2.c | 87 +++-
drivers/clk/qcom/gdsc.c | 44 +++
drivers/clk/qcom/gdsc.h | 5 +
drivers/clk/qcom/gpucc-sdm845.c | 438 +++++++++++++++++++++
include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++
9 files changed, 639 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt
create mode 100644 drivers/clk/qcom/gpucc-sdm845.c
create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h

--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation



2018-07-12 17:11:06

by Amit Nischal

[permalink] [raw]
Subject: [PATCH v2 2/4] clk: qcom: Add clk_rcg2_gfx3d_ops for SDM845

To turn on the gpu_gx_gdsc, there is a hardware requirement to
turn on the root clock (GFX3D RCG) first which would be the turn
on signal for the gdsc along with the SW_COLLAPSE. As per the
current implementation of clk_rcg2_shared_ops, it clears the
root_enable bit in the enable() clock op. But due to the above
said requirement for GFX3D shared RCG, root_enable bit would be
already set by gdsc driver and clk_rcg2_shared_enable()should
not clear the root unless the disable is called.

Add support for the same by reusing the existing clk_rcg2_shared_ops
and deriving "clk_rcg2_gfx3d_ops" clk_ops for GFX3D clock to take
care of the root set/clear requirement.

Signed-off-by: Amit Nischal <[email protected]>
---
drivers/clk/qcom/clk-rcg.h | 1 +
drivers/clk/qcom/clk-rcg2.c | 87 +++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index b209a2f..c8c9558 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -160,5 +160,6 @@ struct clk_rcg2 {
extern const struct clk_ops clk_pixel_ops;
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_rcg2_shared_ops;
+extern const struct clk_ops clk_rcg2_gfx3d_ops;

#endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 52208d4..667edd9 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -866,7 +866,7 @@ static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw,
return clk_rcg2_shared_set_rate(hw, rate, parent_rate);
}

-static int clk_rcg2_shared_enable(struct clk_hw *hw)
+static int __clk_rcg2_shared_enable(struct clk_hw *hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
int ret;
@@ -879,7 +879,14 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw)
if (ret)
return ret;

- ret = update_config(rcg);
+ return update_config(rcg);
+}
+
+static int clk_rcg2_shared_enable(struct clk_hw *hw)
+{
+ int ret;
+
+ ret = __clk_rcg2_shared_enable(hw);
if (ret)
return ret;

@@ -929,3 +936,79 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw)
.set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,
};
EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
+
+static int clk_rcg2_gfx3d_enable(struct clk_hw *hw)
+{
+ return __clk_rcg2_shared_enable(hw);
+}
+
+static int clk_rcg2_gfx3d_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_rate_request parent_req = { };
+ struct clk_hw *p;
+ unsigned long rate = req->rate;
+ int ret;
+
+ if (rate < req->min_rate || rate > req->max_rate)
+ return -EINVAL;
+
+ /* Get fixed parent - GPU_CC_PLL0_OUT_EVEN */
+ p = clk_hw_get_parent_by_index(hw, 1);
+
+ /* Parent should always run at twice of the requested rate */
+ parent_req.rate = 2 * req->rate;
+
+ ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
+ if (ret)
+ return ret;
+
+ req->best_parent_hw = p;
+ req->best_parent_rate = parent_req.rate;
+ req->rate = parent_req.rate / 2;
+
+ return 0;
+}
+
+static int clk_rcg2_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ int ret;
+ u32 cfg;
+
+ /* Configure fixed SRC and DIV */
+ cfg = rcg->parent_map[1].cfg << CFG_SRC_SEL_SHIFT;
+ cfg |= 0x3 << CFG_SRC_DIV_SHIFT;
+
+ ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
+ if (ret)
+ return ret;
+
+ /*
+ * In case clock is disabled, update the SRC and DIV only
+ * and return without configuration update.
+ */
+ if (!__clk_is_enabled(hw->clk))
+ return 0;
+
+ return update_config(rcg);
+}
+
+static int clk_rcg2_gfx3d_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate, u8 index)
+{
+ return clk_rcg2_gfx3d_set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops clk_rcg2_gfx3d_ops = {
+ .enable = clk_rcg2_gfx3d_enable,
+ .disable = clk_rcg2_shared_disable,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .determine_rate = clk_rcg2_gfx3d_determine_rate,
+ .set_rate = clk_rcg2_gfx3d_set_rate,
+ .set_rate_and_parent = clk_rcg2_gfx3d_set_rate_and_parent,
+};
+EXPORT_SYMBOL_GPL(clk_rcg2_gfx3d_ops);
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


2018-07-12 17:11:12

by Amit Nischal

[permalink] [raw]
Subject: [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845

Add support for the graphics clock controller found on SDM845
based devices. This would allow graphics drivers to probe and
control their clocks.

Signed-off-by: Amit Nischal <[email protected]>
---
drivers/clk/qcom/Kconfig | 9 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/gpucc-sdm845.c | 438 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 448 insertions(+)
create mode 100644 drivers/clk/qcom/gpucc-sdm845.c

diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 9c3480d..193c2f5 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -235,6 +235,15 @@ config SDM_GCC_845
Say Y if you want to use peripheral devices such as UART, SPI,
i2C, USB, UFS, SDDC, PCIe, etc.

+config SDM_GPUCC_845
+ tristate "SDM845 Graphics Clock Controller"
+ depends on COMMON_CLK_QCOM
+ select SDM_GCC_845
+ help
+ Support for the graphics clock controller on SDM845 devices.
+ Say Y if you want to support graphics controller devices and
+ functionality such as 3D graphics.
+
config SDM_VIDEOCC_845
tristate "SDM845 Video Clock Controller"
depends on COMMON_CLK_QCOM
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 32d17c2..8aa2bc9 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -40,5 +40,6 @@ obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
+obj-$(CONFIG_SDM_GPUCC_845) += gpucc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c
new file mode 100644
index 0000000..7a11b70
--- /dev/null
+++ b/drivers/clk/qcom/gpucc-sdm845.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,gpucc-sdm845.h>
+
+#include "common.h"
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.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_PLL0_OUT_EVEN,
+ P_GPU_CC_PLL0_OUT_MAIN,
+ P_GPU_CC_PLL0_OUT_ODD,
+ P_GPU_CC_PLL1_OUT_EVEN,
+ P_GPU_CC_PLL1_OUT_MAIN,
+ P_GPU_CC_PLL1_OUT_ODD,
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL0_OUT_MAIN, 1 },
+ { 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 char * const gpu_cc_parent_names_0[] = {
+ "bi_tcxo",
+ "gpu_cc_pll0",
+ "gpu_cc_pll1",
+ "gcc_gpu_gpll0_clk_src",
+ "gcc_gpu_gpll0_div_clk_src",
+ "core_bi_pll_test_se",
+};
+
+static const struct parent_map gpu_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL0_OUT_EVEN, 1 },
+ { P_GPU_CC_PLL0_OUT_ODD, 2 },
+ { P_GPU_CC_PLL1_OUT_EVEN, 3 },
+ { P_GPU_CC_PLL1_OUT_ODD, 4 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_CORE_BI_PLL_TEST_SE, 7 },
+};
+
+static const char * const gpu_cc_parent_names_1[] = {
+ "bi_tcxo",
+ "gpu_cc_pll0_out_even",
+ "gpu_cc_pll0_out_odd",
+ "gpu_cc_pll1_out_even",
+ "gpu_cc_pll1_out_odd",
+ "gcc_gpu_gpll0_clk_src",
+ "core_bi_pll_test_se",
+};
+
+static const struct alpha_pll_config gpu_cc_pll0_config = {
+ .l = 0x1d,
+ .alpha = 0x2aaa,
+};
+
+static const struct alpha_pll_config gpu_cc_pll1_config = {
+ .l = 0x1a,
+ .alpha = 0xaab,
+};
+
+static struct clk_alpha_pll gpu_cc_pll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll0",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_fabia_even[] = {
+ { 0x0, 1 },
+};
+
+static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_fabia_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_fabia_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll0_out_even",
+ .parent_names = (const char *[]){ "gpu_cc_pll0" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_fabia_ops,
+ },
+};
+
+static struct clk_alpha_pll gpu_cc_pll1 = {
+ .offset = 0x100,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll1",
+ .parent_names = (const char *[]){ "bi_tcxo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fabia_ops,
+ },
+ },
+};
+
+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),
+ F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 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_names = gpu_cc_parent_names_0,
+ .num_parents = 6,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = {
+ .cmd_rcgr = 0x101c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_1,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gfx3d_clk_src",
+ .parent_names = gpu_cc_parent_names_1,
+ .num_parents = 7,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_gfx3d_ops,
+ },
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+ .halt_reg = 0x107c,
+ .halt_check = BRANCH_HALT,
+ .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_apb_clk = {
+ .halt_reg = 0x1088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1088,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_apb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gfx3d_clk = {
+ .halt_reg = 0x10a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_gfx3d_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gx_gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = {
+ .halt_reg = 0x10a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_gfx3d_slv_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gx_gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .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_names = (const char *[]){
+ "gpu_cc_gmu_clk_src",
+ },
+ .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,
+ .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_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 clk_branch gpu_cc_gx_gfx3d_clk = {
+ .halt_reg = 0x1054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gfx3d_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gx_gfx3d_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_gmu_clk = {
+ .halt_reg = 0x1064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gmu_clk",
+ .parent_names = (const char *[]){
+ "gpu_cc_gmu_clk_src",
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc gpu_cx_gdsc = {
+ .gdscr = 0x106c,
+ .gds_hw_ctrl = 0x1540,
+ .pd = {
+ .name = "gpu_cx_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
+static struct gdsc gpu_gx_gdsc = {
+ .gdscr = 0x100c,
+ .clamp_io_ctrl = 0x1508,
+ .pd = {
+ .name = "gpu_gx_gdsc",
+ },
+ .clk_hws = {
+ &gpu_cc_gx_gfx3d_clk_src.clkr.hw,
+ },
+ .clk_count = 1,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = CLAMP_IO | AON_RESET | POLL_CFG_GDSCR,
+};
+
+static struct clk_regmap *gpu_cc_sdm845_clocks[] = {
+ [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+ [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr,
+ [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr,
+ [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_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_CLK] = &gpu_cc_cxo_clk.clkr,
+ [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+ [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
+ [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr,
+ [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
+ [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+ [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr,
+ [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
+};
+
+static struct gdsc *gpu_cc_sdm845_gdscs[] = {
+ [GPU_CX_GDSC] = &gpu_cx_gdsc,
+ [GPU_GX_GDSC] = &gpu_gx_gdsc,
+};
+
+static const struct regmap_config gpu_cc_sdm845_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_sdm845_desc = {
+ .config = &gpu_cc_sdm845_regmap_config,
+ .clks = gpu_cc_sdm845_clocks,
+ .num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks),
+ .gdscs = gpu_cc_sdm845_gdscs,
+ .num_gdscs = ARRAY_SIZE(gpu_cc_sdm845_gdscs),
+};
+
+static const struct of_device_id gpu_cc_sdm845_match_table[] = {
+ { .compatible = "qcom,sdm845-gpucc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table);
+
+static int gpu_cc_sdm845_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ unsigned int value, mask;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);
+ clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+ /*
+ * Configure gpu_cc_cx_gmu_clk with recommended
+ * wakeup/sleep settings
+ */
+ 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);
+
+ ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap);
+ if (ret)
+ return ret;
+
+ /* Configure clk_dis_wait for gpu_cx_gdsc */
+ regmap_update_bits(regmap, 0x106c, CLK_DIS_WAIT_MASK,
+ 8 << CLK_DIS_WAIT_SHIFT);
+
+ /* Set supported range of frequencies for gfx3d clock */
+ clk_hw_set_rate_range(&gpu_cc_gx_gfx3d_clk_src.clkr.hw, 180000000,
+ 710000000);
+
+ return 0;
+}
+
+static struct platform_driver gpu_cc_sdm845_driver = {
+ .probe = gpu_cc_sdm845_probe,
+ .driver = {
+ .name = "sdm845-gpucc",
+ .of_match_table = gpu_cc_sdm845_match_table,
+ },
+};
+
+static int __init gpu_cc_sdm845_init(void)
+{
+ return platform_driver_register(&gpu_cc_sdm845_driver);
+}
+subsys_initcall(gpu_cc_sdm845_init);
+
+static void __exit gpu_cc_sdm845_exit(void)
+{
+ platform_driver_unregister(&gpu_cc_sdm845_driver);
+}
+module_exit(gpu_cc_sdm845_exit);
+
+MODULE_DESCRIPTION("QTI GPUCC SDM845 Driver");
+MODULE_LICENSE("GPL v2");
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


2018-07-12 17:11:38

by Amit Nischal

[permalink] [raw]
Subject: [PATCH v2 1/4] clk: qcom: gdsc: Add support to enable/disable the clocks with GDSC

For some of the GDSCs, there is a requirement to enable/disable the
few clocks before turning on/off the gdsc power domain. Add support
for the same by specifying a list of clk_hw pointers per gdsc and
enable/disable them along with power domain on/off callbacks.

Signed-off-by: Amit Nischal <[email protected]>
---
drivers/clk/qcom/gdsc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/qcom/gdsc.h | 5 +++++
2 files changed, 49 insertions(+)

diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index a077133..b6adca1 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -12,6 +12,8 @@
*/

#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/jiffies.h>
@@ -208,11 +210,41 @@ static inline void gdsc_assert_reset_aon(struct gdsc *sc)
regmap_update_bits(sc->regmap, sc->clamp_io_ctrl,
GMEM_RESET_MASK, 0);
}
+
+static int gdsc_clk_prepare_enable(struct gdsc *sc)
+{
+ int i, ret;
+
+ for (i = 0; i < sc->clk_count; i++) {
+ ret = clk_prepare_enable(sc->clk_hws[i]->clk);
+ if (ret) {
+ for (i--; i >= 0; i--)
+ clk_disable_unprepare(sc->clk_hws[i]->clk);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void gdsc_clk_disable_unprepare(struct gdsc *sc)
+{
+ int i;
+
+ for (i = 0; i < sc->clk_count; i++)
+ clk_disable_unprepare(sc->clk_hws[i]->clk);
+}
+
static int gdsc_enable(struct generic_pm_domain *domain)
{
struct gdsc *sc = domain_to_gdsc(domain);
int ret;

+ if (sc->clk_count) {
+ ret = gdsc_clk_prepare_enable(sc);
+ if (ret)
+ return ret;
+ }
+
if (sc->pwrsts == PWRSTS_ON)
return gdsc_deassert_reset(sc);

@@ -260,6 +292,9 @@ static int gdsc_enable(struct generic_pm_domain *domain)
udelay(1);
}

+ if (sc->clk_count)
+ gdsc_clk_disable_unprepare(sc);
+
return 0;
}

@@ -268,6 +303,12 @@ static int gdsc_disable(struct generic_pm_domain *domain)
struct gdsc *sc = domain_to_gdsc(domain);
int ret;

+ if (sc->clk_count) {
+ ret = gdsc_clk_prepare_enable(sc);
+ if (ret)
+ return ret;
+ }
+
if (sc->pwrsts == PWRSTS_ON)
return gdsc_assert_reset(sc);

@@ -299,6 +340,9 @@ static int gdsc_disable(struct generic_pm_domain *domain)
if (sc->flags & CLAMP_IO)
gdsc_assert_clamp_io(sc);

+ if (sc->clk_count)
+ gdsc_clk_disable_unprepare(sc);
+
return 0;
}

diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h
index bd1f2c7..59957d7 100644
--- a/drivers/clk/qcom/gdsc.h
+++ b/drivers/clk/qcom/gdsc.h
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/pm_domain.h>

+struct clk_hw;
struct regmap;
struct reset_controller_dev;

@@ -32,6 +33,8 @@
* @resets: ids of resets associated with this gdsc
* @reset_count: number of @resets
* @rcdev: reset controller
+ * @clk_count: number of associated clocks
+ * @clk_hws: clk_hw pointers for associated clocks with gdsc
*/
struct gdsc {
struct generic_pm_domain pd;
@@ -60,6 +63,8 @@ struct gdsc {
struct reset_controller_dev *rcdev;
unsigned int *resets;
unsigned int reset_count;
+ unsigned int clk_count;
+ struct clk_hw *clk_hws[];
};

struct gdsc_desc {
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


2018-07-12 17:11:47

by Amit Nischal

[permalink] [raw]
Subject: [PATCH v2 3/4] dt-bindings: clock: Introduce QCOM Graphics clock bindings

Add device tree bindings for graphics clock controller for
Qualcomm Technology Inc's SDM845 SoCs.

Signed-off-by: Amit Nischal <[email protected]>
---
.../devicetree/bindings/clock/qcom,gpucc.txt | 18 ++++++++++
include/dt-bindings/clock/qcom,gpucc-sdm845.h | 38 ++++++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/qcom,gpucc.txt
create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h

diff --git a/Documentation/devicetree/bindings/clock/qcom,gpucc.txt b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
new file mode 100644
index 0000000..93752db
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,gpucc.txt
@@ -0,0 +1,18 @@
+Qualcomm Graphics Clock & Reset Controller Binding
+--------------------------------------------------
+
+Required properties :
+- compatible : shall contain "qcom,sdm845-gpucc".
+- reg : shall contain base register location and length.
+- #clock-cells : from common clock binding, shall contain 1.
+- #reset-cells : from common reset binding, shall contain 1.
+- #power-domain-cells : from generic power domain binding, shall contain 1.
+
+Example:
+ gpucc: clock-controller@5090000 {
+ compatible = "qcom,sdm845-gpucc";
+ reg = <0x5090000 0x9000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
new file mode 100644
index 0000000..b9cbce5
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H
+#define _DT_BINDINGS_CLK_SDM_GPU_CC_SDM845_H
+
+/* GPU_CC clock registers */
+#define GPU_CC_CRC_AHB_CLK 0
+#define GPU_CC_CX_APB_CLK 1
+#define GPU_CC_CX_GFX3D_CLK 2
+#define GPU_CC_CX_GFX3D_SLV_CLK 3
+#define GPU_CC_CX_GMU_CLK 4
+#define GPU_CC_CX_SNOC_DVM_CLK 5
+#define GPU_CC_CXO_CLK 6
+#define GPU_CC_GMU_CLK_SRC 7
+#define GPU_CC_GX_GMU_CLK 8
+#define GPU_CC_GX_GFX3D_CLK_SRC 9
+#define GPU_CC_GX_GFX3D_CLK 10
+#define GPU_CC_PLL0 11
+#define GPU_CC_PLL0_OUT_EVEN 12
+#define GPU_CC_PLL1 13
+
+/* GPU_CC Resets */
+#define GPUCC_GPU_CC_ACD_BCR 0
+#define GPUCC_GPU_CC_CX_BCR 1
+#define GPUCC_GPU_CC_GFX3D_AON_BCR 2
+#define GPUCC_GPU_CC_GMU_BCR 3
+#define GPUCC_GPU_CC_GX_BCR 4
+#define GPUCC_GPU_CC_SPDM_BCR 5
+#define GPUCC_GPU_CC_XO_BCR 6
+
+/* GPU_CC GDSCRs */
+#define GPU_CX_GDSC 0
+#define GPU_GX_GDSC 1
+
+#endif
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation


2018-07-14 00:49:16

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845

Hi Amit,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on agross/for-next]
[also build test ERROR on v4.18-rc4 next-20180713]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Amit-Nischal/Add-QCOM-graphics-clock-controller-driver-for-SDM845/20180714-080708
base: https://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git for-next
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 8.1.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.1.0 make.cross ARCH=xtensa

All error/warnings (new ones prefixed by >>):

>> drivers/clk/qcom/gpucc-sdm845.c:136:2: error: implicit declaration of function 'F' [-Werror=implicit-function-declaration]
F(19200000, P_BI_TCXO, 1, 0, 0),
^
>> drivers/clk/qcom/gpucc-sdm845.c:136:2: error: initializer element is not constant
drivers/clk/qcom/gpucc-sdm845.c:136:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].freq')
drivers/clk/qcom/gpucc-sdm845.c:137:2: error: initializer element is not constant
F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
^
drivers/clk/qcom/gpucc-sdm845.c:137:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].src')
drivers/clk/qcom/gpucc-sdm845.c:138:2: error: initializer element is not constant
F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
^
drivers/clk/qcom/gpucc-sdm845.c:138:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].pre_div')
>> drivers/clk/qcom/gpucc-sdm845.c:139:2: warning: braces around scalar initializer
{ }
^
drivers/clk/qcom/gpucc-sdm845.c:139:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].m')
cc1: some warnings being treated as errors

vim +/F +136 drivers/clk/qcom/gpucc-sdm845.c

134
135 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
> 136 F(19200000, P_BI_TCXO, 1, 0, 0),
137 F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
138 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
> 139 { }
140 };
141

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (2.44 kB)
.config.gz (52.90 kB)
Download all attachments

2018-07-14 03:22:12

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 4/4] clk: qcom: Add graphics clock controller driver for SDM845

Hi Amit,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on agross/for-next]
[also build test ERROR on v4.18-rc4 next-20180713]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Amit-Nischal/Add-QCOM-graphics-clock-controller-driver-for-SDM845/20180714-080708
base: https://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git for-next
config: i386-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

>> drivers/clk/qcom/gpucc-sdm845.c:136:2: error: implicit declaration of function 'F'; did you mean 'FS'? [-Werror=implicit-function-declaration]
F(19200000, P_BI_TCXO, 1, 0, 0),
^
FS
drivers/clk/qcom/gpucc-sdm845.c:136:2: error: initializer element is not constant
drivers/clk/qcom/gpucc-sdm845.c:136:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].freq')
drivers/clk/qcom/gpucc-sdm845.c:137:2: error: initializer element is not constant
F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
^
drivers/clk/qcom/gpucc-sdm845.c:137:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].src')
drivers/clk/qcom/gpucc-sdm845.c:138:2: error: initializer element is not constant
F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
^
drivers/clk/qcom/gpucc-sdm845.c:138:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].pre_div')
drivers/clk/qcom/gpucc-sdm845.c:139:2: warning: braces around scalar initializer
{ }
^
drivers/clk/qcom/gpucc-sdm845.c:139:2: note: (near initialization for 'ftbl_gpu_cc_gmu_clk_src[0].m')
cc1: some warnings being treated as errors

vim +136 drivers/clk/qcom/gpucc-sdm845.c

134
135 static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
> 136 F(19200000, P_BI_TCXO, 1, 0, 0),
137 F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0),
138 F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0),
139 { }
140 };
141

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (2.29 kB)
.config.gz (62.64 kB)
Download all attachments