linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
@ 2018-08-11  1:53 Taniya Das
  2018-08-11  1:53 ` [PATCH v4 1/2] " Taniya Das
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Taniya Das @ 2018-08-11  1:53 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel, Taniya Das

 [v4]
  * Add recalc_clk_ops to calculate the clock frequency reading the current
    perf state, also add CLK_GET_RATE_NOCACHE flag.
  * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'.
  * cleanup return from function 'com_cc_register_rcg_dfs'.

 [v3]
  * Rename clk_rcg2_calculate_m_and_n with clk_rcg2_calculate_freq, as this
    function would now calculate the frequency.
  * Rename dfs_freq_tbl to freq_tbl.
  * Remove the logic to remove duplicate frequencies.
  * Remove recalc_rate & set_rate clock ops.
  * clk_rcg2_dfs_ops clock ops is static.
  * Override the clock ops only if DFS mode is enabled.
  * qcom_cc_register_rcg_dfs uses regmap instead of device.
  * Few cleanups : Remove DFS probing after registering clocks.
    sizeof(*init), sizeof(*freq_tbl).

 [v2]
  * Move the dfs register function 'qcom_cc_register_rcg_dfs'
    to clk-rcg2.c instead of common.c
  * At boot read the DFS enable register and override the clk_ops
    to be used for dfs or non-dfs RCGs.
  * Remove flag 'dfs_enabled'.
  * Remove functions 'clk_rcg2_dfs_determine_rate_lazy'
  * Remove 'struct dfs_table *dfs_entry'
  * Remove '_freq_tbl_determine_dfs_rate'
  * Combine the function 'clk_index_pre_div_and_mode' and 'calculate_m_and_n'
    to a single function and named it 'clk_rcg2_calculate_m_and_n'.
  * Remove taking M/N/PERF offsets as function arguments.
  * Add clocks in gcc-sdm845.c the DFS clock array to register.

 [v1]
   * Update SPDX for files.
   * Add new clk_ops for DFS mode which would be used if dfs is enabled,
     else fall back to the clk_rcg2_shared_ops.
   * Use kcalloc in place kzalloc.
   * Fixed the return type for 'clk_parent_index_pre_div_and_mode' which
     is now renamed to 'clk_index_pre_div_and_mode'.
   * Removed return of -EPERM from 'clk_rcg2_set_rate' and new dfs
     clk_ops is introduced.
   * Pass frequency table entry structure to function calculate_m_and_n.
   * Remove desc from qcom_cc_register_rcg_dfs and instead pass array of
     clk_rcg2.
   * Add a dfs_enable flag to identify if dfs mode is enabled.

In the cases where a RCG requires a Dynamic Frequency switch support
requires to register which would at runtime read the clock perf level
registers to identify the frequencies supported and update the frequency
table accordingly.

Taniya Das (2):
  clk: qcom: Add support for RCG to register for DFS
  clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845

 drivers/clk/qcom/clk-rcg.h    |   2 +
 drivers/clk/qcom/clk-rcg2.c   | 224 ++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/qcom/gcc-sdm845.c |  25 +++++
 3 files changed, 251 insertions(+)

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v4 1/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-11  1:53 [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Taniya Das
@ 2018-08-11  1:53 ` Taniya Das
  2018-08-11  1:53 ` [PATCH v4 2/2] clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845 Taniya Das
  2018-08-18  2:12 ` [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Stephen Boyd
  2 siblings, 0 replies; 11+ messages in thread
From: Taniya Das @ 2018-08-11  1:53 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel, Taniya Das

Dynamic Frequency switch is a feature of clock controller by which request
from peripherals allows automatic switching frequency of input clock
without SW intervention. There are various performance levels associated
with a root clock. When the input performance state changes, the source
clocks and division ratios of the new performance state are loaded on to
RCG via HW and the RCG switches to new clock frequency when the RCG is in
DFS HW enabled mode.

Register the root clock generators(RCG) to switch to use the dfs clock ops
in the cases where DFS is enabled. The clk_round_rate() called by the clock
consumer would invoke the dfs determine clock ops and would read the DFS
performance level registers to identify all the frequencies supported and
update the frequency table. The DFS clock consumers would maintain these
frequency mapping and request the desired performance levels.

Signed-off-by: Taniya Das <tdas@codeaurora.org>
---
 drivers/clk/qcom/clk-rcg.h  |   2 +
 drivers/clk/qcom/clk-rcg2.c | 224 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 226 insertions(+)

diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index dbd5a9e..e6300e0 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -163,4 +163,6 @@ struct clk_rcg2 {
 extern const struct clk_ops clk_gfx3d_ops;
 extern const struct clk_ops clk_rcg2_shared_ops;
 
+extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
+			     struct clk_rcg2 **rcgs, int num_clks);
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 52208d4..55a5b58 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -12,6 +12,7 @@
 #include <linux/delay.h>
 #include <linux/regmap.h>
 #include <linux/math64.h>
+#include <linux/slab.h>
 
 #include <asm/div64.h>
 
@@ -40,6 +41,14 @@
 #define N_REG			0xc
 #define D_REG			0x10
 
+/* Dynamic Frequency Scaling */
+#define MAX_PERF_LEVEL		8
+#define SE_CMD_DFSR_OFFSET	0x14
+#define SE_CMD_DFS_EN		BIT(0)
+#define SE_PERF_DFSR(level)	(0x1c + 0x4 * (level))
+#define SE_PERF_M_DFSR(level)	(0x5c + 0x4 * (level))
+#define SE_PERF_N_DFSR(level)	(0x9c + 0x4 * (level))
+
 enum freq_policy {
 	FLOOR,
 	CEIL,
@@ -929,3 +938,218 @@ 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);
+
+/* Common APIs to be used for DFS based RCGR */
+static unsigned long clk_rcg2_calculate_freq(struct clk_hw *hw,
+		int level, struct freq_tbl *f)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	struct clk_hw *p;
+	unsigned long prate = 0;
+	u32 val, mask, cfg, m_off, n_off, offset, mode;
+	int i, ret, num_parents;
+
+	offset = SE_PERF_DFSR(level);
+	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg);
+	if (ret)
+		return ret;
+
+	mask = BIT(rcg->hid_width) - 1;
+	f->pre_div = cfg & mask ? (cfg & mask) : 1;
+
+	mode = cfg & CFG_MODE_MASK;
+	mode >>= CFG_MODE_SHIFT;
+
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	num_parents = clk_hw_get_num_parents(hw);
+	for (i = 0; i < num_parents; i++) {
+		if (cfg == rcg->parent_map[i].cfg) {
+			f->src = rcg->parent_map[i].src;
+			p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i);
+			prate = clk_hw_get_rate(p);
+		}
+	}
+
+	if (mode) {
+		/* Calculate M & N values */
+		m_off = SE_PERF_M_DFSR(level);
+		n_off = SE_PERF_N_DFSR(level);
+
+		mask = BIT(rcg->mnd_width) - 1;
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_off,
+					&val);
+		if (ret) {
+			pr_err("Failed to read M offset register\n");
+			return ret;
+		}
+		val &= mask;
+		f->m = val;
+
+		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_off,
+					&val);
+		if (ret) {
+			pr_err("Failed to read N offset register\n");
+			return ret;
+		}
+		/* val ~(N-M) */
+		val = ~val;
+		val &= mask;
+		val += f->m;
+		f->n = val;
+	}
+
+	return calc_rate(prate, f->m, f->n, mode, f->pre_div);
+}
+
+static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg)
+{
+	struct freq_tbl *freq_tbl;
+	unsigned long calc_freq;
+	int i;
+
+	freq_tbl = kcalloc(MAX_PERF_LEVEL, sizeof(*freq_tbl),
+				GFP_KERNEL);
+	if (!freq_tbl)
+		return -ENOMEM;
+
+	for (i = 0; i < MAX_PERF_LEVEL; i++) {
+		calc_freq = clk_rcg2_calculate_freq(&rcg->clkr.hw,
+							i, &freq_tbl[i]);
+		if (calc_freq < 0) {
+			kfree(freq_tbl);
+			return calc_freq;
+		}
+
+		freq_tbl[i].freq = calc_freq;
+	}
+	rcg->freq_tbl = freq_tbl;
+
+	return 0;
+}
+
+static int clk_rcg2_dfs_determine_rate(struct clk_hw *hw,
+				   struct clk_rate_request *req)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	int ret;
+
+	if (!rcg->freq_tbl) {
+		ret = clk_rcg2_dfs_populate_freq_table(rcg);
+		if (ret) {
+			pr_err("Failed to update DFS tables for %s\n",
+					clk_hw_get_name(hw));
+			return ret;
+		}
+	}
+
+	return clk_rcg2_shared_ops.determine_rate(hw, req);
+}
+
+static unsigned long
+clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
+	int num_parents, i;
+	unsigned long prate;
+
+	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
+				SE_CMD_DFSR_OFFSET, &cfg);
+	level = (GENMASK(4, 1) & cfg) >> 1;
+
+	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
+				SE_PERF_DFSR(level), &cfg);
+	if (rcg->mnd_width) {
+		mask = BIT(rcg->mnd_width) - 1;
+		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
+				SE_PERF_M_DFSR(level), &m);
+		m &= mask;
+		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
+				SE_PERF_N_DFSR(level), &n);
+		n =  ~n;
+		n &= mask;
+		n += m;
+		mode = cfg & CFG_MODE_MASK;
+		mode >>= CFG_MODE_SHIFT;
+	}
+
+	mask = BIT(rcg->hid_width) - 1;
+	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
+	hid_div &= mask;
+	cfg &= CFG_SRC_SEL_MASK;
+	cfg >>= CFG_SRC_SEL_SHIFT;
+
+	num_parents = clk_hw_get_num_parents(hw);
+	for (i = 0; i < num_parents; i++) {
+		if (cfg == rcg->parent_map[i].cfg) {
+			prate = clk_hw_get_rate(
+				clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
+			if (parent_rate != prate)
+				parent_rate = prate;
+		}
+	}
+
+
+	return calc_rate(parent_rate, m, n, mode, hid_div);
+}
+
+static const struct clk_ops clk_rcg2_dfs_ops = {
+	.is_enabled = clk_rcg2_is_enabled,
+	.get_parent = clk_rcg2_get_parent,
+	.determine_rate = clk_rcg2_dfs_determine_rate,
+	.recalc_rate = clk_rcg2_dfs_recalc_rate,
+};
+
+static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
+{
+	struct clk_init_data *init;
+	u32 val;
+	int ret;
+
+	ret = regmap_read(regmap, rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET,
+			  &val);
+	if (ret)
+		return -EINVAL;
+
+	if (!(val & SE_CMD_DFS_EN))
+		return 0;
+
+	init = kzalloc(sizeof(*init), GFP_KERNEL);
+	if (!init)
+		return -ENOMEM;
+
+	init->name = rcg->clkr.hw.init->name;
+	init->flags = rcg->clkr.hw.init->flags;
+	init->parent_names = rcg->clkr.hw.init->parent_names;
+	init->num_parents = rcg->clkr.hw.init->num_parents;
+	init->flags = CLK_GET_RATE_NOCACHE;
+	init->ops = &clk_rcg2_dfs_ops;
+
+	rcg->clkr.hw.init = init;
+	rcg->freq_tbl = NULL;
+
+	pr_debug("DFS registered for clk %s\n", init->name);
+
+	return 0;
+}
+
+int qcom_cc_register_rcg_dfs(struct regmap *regmap,
+			    struct clk_rcg2 **rcgs, int num_clks)
+{
+	int i, ret;
+
+	for (i = 0; i < num_clks; i++) {
+		ret = clk_rcg2_enable_dfs(rcgs[i], regmap);
+		if (ret) {
+			const char *name = rcgs[i]->clkr.hw.init->name;
+
+			pr_err("DFS register failed for clk %s\n", name);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_cc_register_rcg_dfs);
-- 
Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member
of the Code Aurora Forum, hosted by the  Linux Foundation.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v4 2/2] clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845
  2018-08-11  1:53 [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Taniya Das
  2018-08-11  1:53 ` [PATCH v4 1/2] " Taniya Das
@ 2018-08-11  1:53 ` Taniya Das
  2018-08-18  2:12 ` [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Stephen Boyd
  2 siblings, 0 replies; 11+ messages in thread
From: Taniya Das @ 2018-08-11  1:53 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel, Taniya Das

QUPv3 clocks support DFS and thus register the RCGs which require support
for the same.

Signed-off-by: Taniya Das <tdas@codeaurora.org>
---
 drivers/clk/qcom/gcc-sdm845.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index fa1a196..fef6732 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -3458,9 +3458,29 @@ enum {
 };
 MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
 
+static struct clk_rcg2 *gcc_dfs_clocks[] = {
+	&gcc_qupv3_wrap0_s0_clk_src,
+	&gcc_qupv3_wrap0_s1_clk_src,
+	&gcc_qupv3_wrap0_s2_clk_src,
+	&gcc_qupv3_wrap0_s3_clk_src,
+	&gcc_qupv3_wrap0_s4_clk_src,
+	&gcc_qupv3_wrap0_s5_clk_src,
+	&gcc_qupv3_wrap0_s6_clk_src,
+	&gcc_qupv3_wrap0_s7_clk_src,
+	&gcc_qupv3_wrap1_s0_clk_src,
+	&gcc_qupv3_wrap1_s1_clk_src,
+	&gcc_qupv3_wrap1_s2_clk_src,
+	&gcc_qupv3_wrap1_s3_clk_src,
+	&gcc_qupv3_wrap1_s4_clk_src,
+	&gcc_qupv3_wrap1_s5_clk_src,
+	&gcc_qupv3_wrap1_s6_clk_src,
+	&gcc_qupv3_wrap1_s7_clk_src,
+};
+
 static int gcc_sdm845_probe(struct platform_device *pdev)
 {
 	struct regmap *regmap;
+	int ret;
 
 	regmap = qcom_cc_map(pdev, &gcc_sdm845_desc);
 	if (IS_ERR(regmap))
@@ -3470,6 +3490,11 @@ static int gcc_sdm845_probe(struct platform_device *pdev)
 	regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3);
 	regmap_update_bits(regmap, 0x71028, 0x3, 0x3);
 
+	ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+					ARRAY_SIZE(gcc_dfs_clocks));
+	if (ret)
+		return ret;
+
 	return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap);
 }
 
-- 
Qualcomm INDIA, on behalf of Qualcomm Innovation Center, Inc.is a member
of the Code Aurora Forum, hosted by the  Linux Foundation.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-11  1:53 [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Taniya Das
  2018-08-11  1:53 ` [PATCH v4 1/2] " Taniya Das
  2018-08-11  1:53 ` [PATCH v4 2/2] clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845 Taniya Das
@ 2018-08-18  2:12 ` Stephen Boyd
  2018-08-18 18:01   ` Taniya Das
  2 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2018-08-18  2:12 UTC (permalink / raw)
  To: Michael Turquette, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel, Taniya Das

Quoting Taniya Das (2018-08-10 18:53:54)
>  [v4]
>   * Add recalc_clk_ops to calculate the clock frequency reading the current
>     perf state, also add CLK_GET_RATE_NOCACHE flag.
>   * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'.
>   * cleanup return from function 'com_cc_register_rcg_dfs'.

I want to squash this in. I have only compile tested it. Let me know
what you think.

----8<---
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index e6300e05d5df..e5eca8a1abe4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -163,6 +163,15 @@ 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;
 
+struct clk_rcg_dfs_data {
+	struct clk_rcg2 *rcg;
+	struct clk_init_data *init;
+};
+
+#define DEFINE_RCG_DFS(r) \
+	{ .rcg = &r##_src, .init = &r##_init }
+
 extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
-			     struct clk_rcg2 **rcgs, int num_clks);
+				    const struct clk_rcg_dfs_data *rcgs,
+				    size_t len);
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 55a5b58cbb15..bbe2a1916296 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -1051,48 +1051,24 @@ static unsigned long
 clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
-	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
-	int num_parents, i;
-	unsigned long prate;
-
-	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_CMD_DFSR_OFFSET, &cfg);
-	level = (GENMASK(4, 1) & cfg) >> 1;
-
-	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_PERF_DFSR(level), &cfg);
-	if (rcg->mnd_width) {
-		mask = BIT(rcg->mnd_width) - 1;
-		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_PERF_M_DFSR(level), &m);
-		m &= mask;
-		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_PERF_N_DFSR(level), &n);
-		n =  ~n;
-		n &= mask;
-		n += m;
-		mode = cfg & CFG_MODE_MASK;
-		mode >>= CFG_MODE_SHIFT;
-	}
+	int ret;
+	u32 level;
 
-	mask = BIT(rcg->hid_width) - 1;
-	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
-	hid_div &= mask;
-	cfg &= CFG_SRC_SEL_MASK;
-	cfg >>= CFG_SRC_SEL_SHIFT;
+	regmap_read(rcg->clkr.regmap,
+		    rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
+	level &= GENMASK(4, 1);
+	level >>= 1;
 
-	num_parents = clk_hw_get_num_parents(hw);
-	for (i = 0; i < num_parents; i++) {
-		if (cfg == rcg->parent_map[i].cfg) {
-			prate = clk_hw_get_rate(
-				clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
-			if (parent_rate != prate)
-				parent_rate = prate;
+	if (!rcg->freq_tbl) {
+		ret = clk_rcg2_dfs_populate_freq_table(rcg);
+		if (ret) {
+			pr_err("Failed to update DFS tables for %s\n",
+					clk_hw_get_name(hw));
+			return ret;
 		}
 	}
 
-
-	return calc_rate(parent_rate, m, n, mode, hid_div);
+	return rcg->freq_tbl[level].freq;
 }
 
 static const struct clk_ops clk_rcg2_dfs_ops = {
@@ -1102,9 +1078,11 @@ static const struct clk_ops clk_rcg2_dfs_ops = {
 	.recalc_rate = clk_rcg2_dfs_recalc_rate,
 };
 
-static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
+static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
+			       struct regmap *regmap)
 {
-	struct clk_init_data *init;
+	struct clk_rcg2 *rcg = data->rcg;
+	struct clk_init_data *init = data->init;
 	u32 val;
 	int ret;
 
@@ -1116,18 +1094,13 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
 	if (!(val & SE_CMD_DFS_EN))
 		return 0;
 
-	init = kzalloc(sizeof(*init), GFP_KERNEL);
-	if (!init)
-		return -ENOMEM;
-
-	init->name = rcg->clkr.hw.init->name;
-	init->flags = rcg->clkr.hw.init->flags;
-	init->parent_names = rcg->clkr.hw.init->parent_names;
-	init->num_parents = rcg->clkr.hw.init->num_parents;
-	init->flags = CLK_GET_RATE_NOCACHE;
+	/*
+	 * Rate changes with consumer writing a register in
+	 * their own I/O region
+	 */
+	init->flags |= CLK_GET_RATE_NOCACHE;
 	init->ops = &clk_rcg2_dfs_ops;
 
-	rcg->clkr.hw.init = init;
 	rcg->freq_tbl = NULL;
 
 	pr_debug("DFS registered for clk %s\n", init->name);
@@ -1136,14 +1109,14 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
 }
 
 int qcom_cc_register_rcg_dfs(struct regmap *regmap,
-			    struct clk_rcg2 **rcgs, int num_clks)
+			     const struct clk_rcg_dfs_data *rcgs, size_t len)
 {
 	int i, ret;
 
-	for (i = 0; i < num_clks; i++) {
-		ret = clk_rcg2_enable_dfs(rcgs[i], regmap);
+	for (i = 0; i < len; i++) {
+		ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
 		if (ret) {
-			const char *name = rcgs[i]->clkr.hw.init->name;
+			const char *name = rcgs[i].init->name;
 
 			pr_err("DFS register failed for clk %s\n", name);
 			return ret;
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index fef6732bd7d8..42ab01d33b52 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -396,18 +396,27 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
 	{ }
 };
 
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_init = {
+	.name = "gcc_qupv3_wrap0_s0_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
+};
+
 static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
 	.cmd_rcgr = 0x17034,
 	.mnd_width = 16,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s0_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_init = {
+	.name = "gcc_qupv3_wrap0_s1_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
@@ -416,12 +425,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s1_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_init = {
+	.name = "gcc_qupv3_wrap0_s2_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
@@ -430,12 +441,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s2_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_init = {
+	.name = "gcc_qupv3_wrap0_s3_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
@@ -444,12 +457,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s3_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_init = {
+	.name = "gcc_qupv3_wrap0_s4_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
@@ -458,12 +473,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s4_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_init = {
+	.name = "gcc_qupv3_wrap0_s5_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
@@ -472,12 +489,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s5_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_init = {
+	.name = "gcc_qupv3_wrap0_s6_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
@@ -486,12 +505,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s6_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s7_clk_init = {
+	.name = "gcc_qupv3_wrap0_s7_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
@@ -500,12 +521,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s7_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_init = {
+	.name = "gcc_qupv3_wrap1_s0_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
@@ -514,12 +537,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s0_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_init = {
+	.name = "gcc_qupv3_wrap1_s1_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
@@ -528,12 +553,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s1_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_init = {
+	.name = "gcc_qupv3_wrap1_s2_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
@@ -542,12 +569,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s2_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_init = {
+	.name = "gcc_qupv3_wrap1_s3_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
@@ -556,12 +585,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s3_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_init = {
+	.name = "gcc_qupv3_wrap1_s4_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
@@ -570,12 +601,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s4_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_init = {
+	.name = "gcc_qupv3_wrap1_s5_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
@@ -584,12 +617,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s5_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_init = {
+	.name = "gcc_qupv3_wrap1_s6_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
@@ -598,12 +633,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s6_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_init = {
+	.name = "gcc_qupv3_wrap1_s7_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
@@ -612,12 +649,7 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s7_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_init,
 };
 
 static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
@@ -3458,23 +3490,23 @@ static const struct of_device_id gcc_sdm845_match_table[] = {
 };
 MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
 
-static struct clk_rcg2 *gcc_dfs_clocks[] = {
-	&gcc_qupv3_wrap0_s0_clk_src,
-	&gcc_qupv3_wrap0_s1_clk_src,
-	&gcc_qupv3_wrap0_s2_clk_src,
-	&gcc_qupv3_wrap0_s3_clk_src,
-	&gcc_qupv3_wrap0_s4_clk_src,
-	&gcc_qupv3_wrap0_s5_clk_src,
-	&gcc_qupv3_wrap0_s6_clk_src,
-	&gcc_qupv3_wrap0_s7_clk_src,
-	&gcc_qupv3_wrap1_s0_clk_src,
-	&gcc_qupv3_wrap1_s1_clk_src,
-	&gcc_qupv3_wrap1_s2_clk_src,
-	&gcc_qupv3_wrap1_s3_clk_src,
-	&gcc_qupv3_wrap1_s4_clk_src,
-	&gcc_qupv3_wrap1_s5_clk_src,
-	&gcc_qupv3_wrap1_s6_clk_src,
-	&gcc_qupv3_wrap1_s7_clk_src,
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk),
 };
 
 static int gcc_sdm845_probe(struct platform_device *pdev)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-18  2:12 ` [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Stephen Boyd
@ 2018-08-18 18:01   ` Taniya Das
  2018-08-21 11:36     ` Taniya Das
  0 siblings, 1 reply; 11+ messages in thread
From: Taniya Das @ 2018-08-18 18:01 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel

Hello Stephen,

I will test these changes and get back.

On 8/18/2018 7:42 AM, Stephen Boyd wrote:
> Quoting Taniya Das (2018-08-10 18:53:54)
>>   [v4]
>>    * Add recalc_clk_ops to calculate the clock frequency reading the current
>>      perf state, also add CLK_GET_RATE_NOCACHE flag.
>>    * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'.
>>    * cleanup return from function 'com_cc_register_rcg_dfs'.
> 
> I want to squash this in. I have only compile tested it. Let me know
> what you think.
> 
> ----8<---
> diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
> index e6300e05d5df..e5eca8a1abe4 100644
> --- a/drivers/clk/qcom/clk-rcg.h
> +++ b/drivers/clk/qcom/clk-rcg.h
> @@ -163,6 +163,15 @@ 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;
>   
> +struct clk_rcg_dfs_data {
> +	struct clk_rcg2 *rcg;
> +	struct clk_init_data *init;
> +};
> +
> +#define DEFINE_RCG_DFS(r) \
> +	{ .rcg = &r##_src, .init = &r##_init }
> +
>   extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
> -			     struct clk_rcg2 **rcgs, int num_clks);
> +				    const struct clk_rcg_dfs_data *rcgs,
> +				    size_t len);
>   #endif
> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
> index 55a5b58cbb15..bbe2a1916296 100644
> --- a/drivers/clk/qcom/clk-rcg2.c
> +++ b/drivers/clk/qcom/clk-rcg2.c
> @@ -1051,48 +1051,24 @@ static unsigned long
>   clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
>   {
>   	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
> -	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
> -	int num_parents, i;
> -	unsigned long prate;
> -
> -	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> -				SE_CMD_DFSR_OFFSET, &cfg);
> -	level = (GENMASK(4, 1) & cfg) >> 1;
> -
> -	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> -				SE_PERF_DFSR(level), &cfg);
> -	if (rcg->mnd_width) {
> -		mask = BIT(rcg->mnd_width) - 1;
> -		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> -				SE_PERF_M_DFSR(level), &m);
> -		m &= mask;
> -		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> -				SE_PERF_N_DFSR(level), &n);
> -		n =  ~n;
> -		n &= mask;
> -		n += m;
> -		mode = cfg & CFG_MODE_MASK;
> -		mode >>= CFG_MODE_SHIFT;
> -	}
> +	int ret;
> +	u32 level;
>   
> -	mask = BIT(rcg->hid_width) - 1;
> -	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
> -	hid_div &= mask;
> -	cfg &= CFG_SRC_SEL_MASK;
> -	cfg >>= CFG_SRC_SEL_SHIFT;
> +	regmap_read(rcg->clkr.regmap,
> +		    rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
> +	level &= GENMASK(4, 1);
> +	level >>= 1;
>   
> -	num_parents = clk_hw_get_num_parents(hw);
> -	for (i = 0; i < num_parents; i++) {
> -		if (cfg == rcg->parent_map[i].cfg) {
> -			prate = clk_hw_get_rate(
> -				clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
> -			if (parent_rate != prate)
> -				parent_rate = prate;
> +	if (!rcg->freq_tbl) {
> +		ret = clk_rcg2_dfs_populate_freq_table(rcg);
> +		if (ret) {
> +			pr_err("Failed to update DFS tables for %s\n",
> +					clk_hw_get_name(hw));
> +			return ret;
>   		}
>   	}
>   
> -
> -	return calc_rate(parent_rate, m, n, mode, hid_div);
> +	return rcg->freq_tbl[level].freq;
>   }
>   
>   static const struct clk_ops clk_rcg2_dfs_ops = {
> @@ -1102,9 +1078,11 @@ static const struct clk_ops clk_rcg2_dfs_ops = {
>   	.recalc_rate = clk_rcg2_dfs_recalc_rate,
>   };
>   
> -static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
> +static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
> +			       struct regmap *regmap)
>   {
> -	struct clk_init_data *init;
> +	struct clk_rcg2 *rcg = data->rcg;
> +	struct clk_init_data *init = data->init;
>   	u32 val;
>   	int ret;
>   
> @@ -1116,18 +1094,13 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
>   	if (!(val & SE_CMD_DFS_EN))
>   		return 0;
>   
> -	init = kzalloc(sizeof(*init), GFP_KERNEL);
> -	if (!init)
> -		return -ENOMEM;
> -
> -	init->name = rcg->clkr.hw.init->name;
> -	init->flags = rcg->clkr.hw.init->flags;
> -	init->parent_names = rcg->clkr.hw.init->parent_names;
> -	init->num_parents = rcg->clkr.hw.init->num_parents;
> -	init->flags = CLK_GET_RATE_NOCACHE;
> +	/*
> +	 * Rate changes with consumer writing a register in
> +	 * their own I/O region
> +	 */
> +	init->flags |= CLK_GET_RATE_NOCACHE;
>   	init->ops = &clk_rcg2_dfs_ops;
>   
> -	rcg->clkr.hw.init = init;
>   	rcg->freq_tbl = NULL;
>   
>   	pr_debug("DFS registered for clk %s\n", init->name);
> @@ -1136,14 +1109,14 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
>   }
>   
>   int qcom_cc_register_rcg_dfs(struct regmap *regmap,
> -			    struct clk_rcg2 **rcgs, int num_clks)
> +			     const struct clk_rcg_dfs_data *rcgs, size_t len)
>   {
>   	int i, ret;
>   
> -	for (i = 0; i < num_clks; i++) {
> -		ret = clk_rcg2_enable_dfs(rcgs[i], regmap);
> +	for (i = 0; i < len; i++) {
> +		ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
>   		if (ret) {
> -			const char *name = rcgs[i]->clkr.hw.init->name;
> +			const char *name = rcgs[i].init->name;
>   
>   			pr_err("DFS register failed for clk %s\n", name);
>   			return ret;
> diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
> index fef6732bd7d8..42ab01d33b52 100644
> --- a/drivers/clk/qcom/gcc-sdm845.c
> +++ b/drivers/clk/qcom/gcc-sdm845.c
> @@ -396,18 +396,27 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
>   	{ }
>   };
>   
> +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s0_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
> +};
> +
>   static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
>   	.cmd_rcgr = 0x17034,
>   	.mnd_width = 16,
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s0_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s1_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
> @@ -416,12 +425,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s1_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s2_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
> @@ -430,12 +441,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s2_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s3_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
> @@ -444,12 +457,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s3_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s4_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
> @@ -458,12 +473,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s4_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s5_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
> @@ -472,12 +489,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s5_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s6_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s6_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
> @@ -486,12 +505,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s6_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_init = {
> +	.name = "gcc_qupv3_wrap0_s7_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
> @@ -500,12 +521,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap0_s7_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s0_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
> @@ -514,12 +537,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s0_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s1_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
> @@ -528,12 +553,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s1_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s2_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
> @@ -542,12 +569,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s2_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s3_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
> @@ -556,12 +585,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s3_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s4_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
> @@ -570,12 +601,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s4_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s5_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
> @@ -584,12 +617,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s5_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s6_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
> @@ -598,12 +633,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s6_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_init,
> +};
> +
> +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_init = {
> +	.name = "gcc_qupv3_wrap1_s7_clk_src",
> +	.parent_names = gcc_parent_names_0,
> +	.num_parents = 4,
> +	.ops = &clk_rcg2_shared_ops,
>   };
>   
>   static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
> @@ -612,12 +649,7 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
>   	.hid_width = 5,
>   	.parent_map = gcc_parent_map_0,
>   	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
> -	.clkr.hw.init = &(struct clk_init_data){
> -		.name = "gcc_qupv3_wrap1_s7_clk_src",
> -		.parent_names = gcc_parent_names_0,
> -		.num_parents = 4,
> -		.ops = &clk_rcg2_shared_ops,
> -	},
> +	.clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_init,
>   };
>   
>   static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
> @@ -3458,23 +3490,23 @@ static const struct of_device_id gcc_sdm845_match_table[] = {
>   };
>   MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
>   
> -static struct clk_rcg2 *gcc_dfs_clocks[] = {
> -	&gcc_qupv3_wrap0_s0_clk_src,
> -	&gcc_qupv3_wrap0_s1_clk_src,
> -	&gcc_qupv3_wrap0_s2_clk_src,
> -	&gcc_qupv3_wrap0_s3_clk_src,
> -	&gcc_qupv3_wrap0_s4_clk_src,
> -	&gcc_qupv3_wrap0_s5_clk_src,
> -	&gcc_qupv3_wrap0_s6_clk_src,
> -	&gcc_qupv3_wrap0_s7_clk_src,
> -	&gcc_qupv3_wrap1_s0_clk_src,
> -	&gcc_qupv3_wrap1_s1_clk_src,
> -	&gcc_qupv3_wrap1_s2_clk_src,
> -	&gcc_qupv3_wrap1_s3_clk_src,
> -	&gcc_qupv3_wrap1_s4_clk_src,
> -	&gcc_qupv3_wrap1_s5_clk_src,
> -	&gcc_qupv3_wrap1_s6_clk_src,
> -	&gcc_qupv3_wrap1_s7_clk_src,
> +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk),
> +	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk),
>   };
>   
>   static int gcc_sdm845_probe(struct platform_device *pdev)
> 

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

--

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-18 18:01   ` Taniya Das
@ 2018-08-21 11:36     ` Taniya Das
  2018-08-21 15:30       ` Stephen Boyd
  0 siblings, 1 reply; 11+ messages in thread
From: Taniya Das @ 2018-08-21 11:36 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel

Hello Stephen,

Thanks for the changes, I have tested the changes and would require the 
change mentioned below for this to work.

On 8/18/2018 11:31 PM, Taniya Das wrote:
> Hello Stephen,
> 
> I will test these changes and get back.
> 
> On 8/18/2018 7:42 AM, Stephen Boyd wrote:
>> Quoting Taniya Das (2018-08-10 18:53:54)
>>>   [v4]
>>>    * Add recalc_clk_ops to calculate the clock frequency reading the 
>>> current
>>>      perf state, also add CLK_GET_RATE_NOCACHE flag.
>>>    * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'.
>>>    * cleanup return from function 'com_cc_register_rcg_dfs'.
>>
>> I want to squash this in. I have only compile tested it. Let me know
>> what you think.
>>
>> ----8<---
>> diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
>> index e6300e05d5df..e5eca8a1abe4 100644
>> --- a/drivers/clk/qcom/clk-rcg.h
>> +++ b/drivers/clk/qcom/clk-rcg.h
>> @@ -163,6 +163,15 @@ 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;
>> +struct clk_rcg_dfs_data {
>> +    struct clk_rcg2 *rcg;
>> +    struct clk_init_data *init;
>> +};
>> +
>> +#define DEFINE_RCG_DFS(r) \
>> +    { .rcg = &r##_src, .init = &r##_init }
>> +
>>   extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
>> -                 struct clk_rcg2 **rcgs, int num_clks);
>> +                    const struct clk_rcg_dfs_data *rcgs,
>> +                    size_t len);
>>   #endif
>> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
>> index 55a5b58cbb15..bbe2a1916296 100644
>> --- a/drivers/clk/qcom/clk-rcg2.c
>> +++ b/drivers/clk/qcom/clk-rcg2.c
>> @@ -1051,48 +1051,24 @@ static unsigned long
>>   clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
>>   {
>>       struct clk_rcg2 *rcg = to_clk_rcg2(hw);
>> -    u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
>> -    int num_parents, i;
>> -    unsigned long prate;
>> -
>> -    regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>> -                SE_CMD_DFSR_OFFSET, &cfg);
>> -    level = (GENMASK(4, 1) & cfg) >> 1;
>> -
>> -    regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>> -                SE_PERF_DFSR(level), &cfg);
>> -    if (rcg->mnd_width) {
>> -        mask = BIT(rcg->mnd_width) - 1;
>> -        regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>> -                SE_PERF_M_DFSR(level), &m);
>> -        m &= mask;
>> -        regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>> -                SE_PERF_N_DFSR(level), &n);
>> -        n =  ~n;
>> -        n &= mask;
>> -        n += m;
>> -        mode = cfg & CFG_MODE_MASK;
>> -        mode >>= CFG_MODE_SHIFT;
>> -    }
>> +    int ret;
>> +    u32 level;
>> -    mask = BIT(rcg->hid_width) - 1;
>> -    hid_div = cfg >> CFG_SRC_DIV_SHIFT;
>> -    hid_div &= mask;
>> -    cfg &= CFG_SRC_SEL_MASK;
>> -    cfg >>= CFG_SRC_SEL_SHIFT;
>> +    regmap_read(rcg->clkr.regmap,
>> +            rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
>> +    level &= GENMASK(4, 1);
>> +    level >>= 1;
>> -    num_parents = clk_hw_get_num_parents(hw);
>> -    for (i = 0; i < num_parents; i++) {
>> -        if (cfg == rcg->parent_map[i].cfg) {
>> -            prate = clk_hw_get_rate(
>> -                clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
>> -            if (parent_rate != prate)
>> -                parent_rate = prate;
>> +    if (!rcg->freq_tbl) {
>> +        ret = clk_rcg2_dfs_populate_freq_table(rcg);

This function would retrieve the parent_rate and if the parent_rate is 
not ready then it would fail to boot up.

So we have to make sure the parents are registered before these RCGs. 
That also was one reason for me to not populate the frequency table at 
recalc.

We would need this patch to make this work.

  /* GCC clock registers */
-#define GCC_AGGRE_NOC_PCIE_TBU_CLK                             0
-#define GCC_AGGRE_UFS_CARD_AXI_CLK                             1
-#define GCC_AGGRE_UFS_PHY_AXI_CLK                              2
-#define GCC_AGGRE_USB3_PRIM_AXI_CLK                            3
+#define GPLL0                                                  0
+#define GPLL0_OUT_EVEN                                         1
+#define GPLL0_OUT_MAIN                                         2
+#define GPLL4                                                  3
  #define GCC_AGGRE_USB3_SEC_AXI_CLK                             4
  #define GCC_BOOT_ROM_AHB_CLK                                   5
  #define GCC_CAMERA_AHB_CLK                                     6
@@ -172,9 +172,9 @@
  #define GCC_VIDEO_AHB_CLK                                      162
  #define GCC_VIDEO_AXI_CLK                                      163
  #define GCC_VIDEO_XO_CLK                                       164
-#define GPLL0                                                  165
-#define GPLL0_OUT_EVEN                                         166
-#define GPLL0_OUT_MAIN                                         167
+#define GCC_AGGRE_NOC_PCIE_TBU_CLK                             165
+#define GCC_AGGRE_UFS_CARD_AXI_CLK                             166
+#define GCC_AGGRE_UFS_PHY_AXI_CLK                              167
  #define GCC_GPU_IREF_CLK                                       168
  #define GCC_SDCC1_AHB_CLK                                      169
  #define GCC_SDCC1_APPS_CLK                                     170
@@ -191,7 +191,7 @@
  #define GCC_VS_CTRL_CLK                                        181
  #define GCC_VS_CTRL_CLK_SRC                                    182
  #define GCC_VSENSOR_CLK_SRC                                    183
-#define GPLL4                                                  184
+#define GCC_AGGRE_USB3_PRIM_AXI_CLK                            184


>> +        if (ret) {
>> +            pr_err("Failed to update DFS tables for %s\n",
>> +                    clk_hw_get_name(hw));
>> +            return ret;
>>           }
>>       }
>> -
>> -    return calc_rate(parent_rate, m, n, mode, hid_div);
>> +    return rcg->freq_tbl[level].freq;
>>   }
>>   static const struct clk_ops clk_rcg2_dfs_ops = {
>> @@ -1102,9 +1078,11 @@ static const struct clk_ops clk_rcg2_dfs_ops = {
>>       .recalc_rate = clk_rcg2_dfs_recalc_rate,
>>   };
>> -static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap 
>> *regmap)
>> +static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
>> +                   struct regmap *regmap)
>>   {
>> -    struct clk_init_data *init;
>> +    struct clk_rcg2 *rcg = data->rcg;
>> +    struct clk_init_data *init = data->init;
>>       u32 val;
>>       int ret;
>> @@ -1116,18 +1094,13 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 
>> *rcg, struct regmap *regmap)
>>       if (!(val & SE_CMD_DFS_EN))
>>           return 0;
>> -    init = kzalloc(sizeof(*init), GFP_KERNEL);
>> -    if (!init)
>> -        return -ENOMEM;
>> -
>> -    init->name = rcg->clkr.hw.init->name;
>> -    init->flags = rcg->clkr.hw.init->flags;
>> -    init->parent_names = rcg->clkr.hw.init->parent_names;
>> -    init->num_parents = rcg->clkr.hw.init->num_parents;
>> -    init->flags = CLK_GET_RATE_NOCACHE;
>> +    /*
>> +     * Rate changes with consumer writing a register in
>> +     * their own I/O region
>> +     */
>> +    init->flags |= CLK_GET_RATE_NOCACHE;
>>       init->ops = &clk_rcg2_dfs_ops;
>> -    rcg->clkr.hw.init = init;
>>       rcg->freq_tbl = NULL;
>>       pr_debug("DFS registered for clk %s\n", init->name);
>> @@ -1136,14 +1109,14 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 
>> *rcg, struct regmap *regmap)
>>   }
>>   int qcom_cc_register_rcg_dfs(struct regmap *regmap,
>> -                struct clk_rcg2 **rcgs, int num_clks)
>> +                 const struct clk_rcg_dfs_data *rcgs, size_t len)
>>   {
>>       int i, ret;
>> -    for (i = 0; i < num_clks; i++) {
>> -        ret = clk_rcg2_enable_dfs(rcgs[i], regmap);
>> +    for (i = 0; i < len; i++) {
>> +        ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
>>           if (ret) {
>> -            const char *name = rcgs[i]->clkr.hw.init->name;
>> +            const char *name = rcgs[i].init->name;
>>               pr_err("DFS register failed for clk %s\n", name);
>>               return ret;
>> diff --git a/drivers/clk/qcom/gcc-sdm845.c 
>> b/drivers/clk/qcom/gcc-sdm845.c
>> index fef6732bd7d8..42ab01d33b52 100644
>> --- a/drivers/clk/qcom/gcc-sdm845.c
>> +++ b/drivers/clk/qcom/gcc-sdm845.c
>> @@ -396,18 +396,27 @@ static const struct freq_tbl 
>> ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
>>       { }
>>   };
>> +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s0_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>> +};
>> +
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
>>       .cmd_rcgr = 0x17034,
>>       .mnd_width = 16,
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s0_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s1_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
>> @@ -416,12 +425,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s1_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s1_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s2_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
>> @@ -430,12 +441,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s2_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s2_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s3_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
>> @@ -444,12 +457,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s3_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s3_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s4_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
>> @@ -458,12 +473,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s4_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s4_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s5_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
>> @@ -472,12 +489,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s5_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s5_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s6_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s6_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
>> @@ -486,12 +505,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s6_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s6_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_init = {
>> +    .name = "gcc_qupv3_wrap0_s7_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
>> @@ -500,12 +521,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap0_s7_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap0_s7_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s0_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
>> @@ -514,12 +537,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s0_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s0_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s1_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
>> @@ -528,12 +553,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s1_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s1_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s2_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
>> @@ -542,12 +569,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s2_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s2_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s3_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
>> @@ -556,12 +585,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s3_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s3_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s4_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
>> @@ -570,12 +601,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s4_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s4_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s5_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
>> @@ -584,12 +617,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s5_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s5_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s6_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
>> @@ -598,12 +633,14 @@ static struct clk_rcg2 
>> gcc_qupv3_wrap1_s6_clk_src = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s6_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_init,
>> +};
>> +
>> +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_init = {
>> +    .name = "gcc_qupv3_wrap1_s7_clk_src",
>> +    .parent_names = gcc_parent_names_0,
>> +    .num_parents = 4,
>> +    .ops = &clk_rcg2_shared_ops,
>>   };
>>   static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
>> @@ -612,12 +649,7 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src 
>> = {
>>       .hid_width = 5,
>>       .parent_map = gcc_parent_map_0,
>>       .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
>> -    .clkr.hw.init = &(struct clk_init_data){
>> -        .name = "gcc_qupv3_wrap1_s7_clk_src",
>> -        .parent_names = gcc_parent_names_0,
>> -        .num_parents = 4,
>> -        .ops = &clk_rcg2_shared_ops,
>> -    },
>> +    .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_init,
>>   };
>>   static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
>> @@ -3458,23 +3490,23 @@ static const struct of_device_id 
>> gcc_sdm845_match_table[] = {
>>   };
>>   MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
>> -static struct clk_rcg2 *gcc_dfs_clocks[] = {
>> -    &gcc_qupv3_wrap0_s0_clk_src,
>> -    &gcc_qupv3_wrap0_s1_clk_src,
>> -    &gcc_qupv3_wrap0_s2_clk_src,
>> -    &gcc_qupv3_wrap0_s3_clk_src,
>> -    &gcc_qupv3_wrap0_s4_clk_src,
>> -    &gcc_qupv3_wrap0_s5_clk_src,
>> -    &gcc_qupv3_wrap0_s6_clk_src,
>> -    &gcc_qupv3_wrap0_s7_clk_src,
>> -    &gcc_qupv3_wrap1_s0_clk_src,
>> -    &gcc_qupv3_wrap1_s1_clk_src,
>> -    &gcc_qupv3_wrap1_s2_clk_src,
>> -    &gcc_qupv3_wrap1_s3_clk_src,
>> -    &gcc_qupv3_wrap1_s4_clk_src,
>> -    &gcc_qupv3_wrap1_s5_clk_src,
>> -    &gcc_qupv3_wrap1_s6_clk_src,
>> -    &gcc_qupv3_wrap1_s7_clk_src,
>> +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk),
>> +    DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk),
>>   };
>>   static int gcc_sdm845_probe(struct platform_device *pdev)
>>
> 

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

--

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-21 11:36     ` Taniya Das
@ 2018-08-21 15:30       ` Stephen Boyd
  2018-08-22 10:28         ` Taniya Das
  0 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2018-08-21 15:30 UTC (permalink / raw)
  To: Michael Turquette, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel

Quoting Taniya Das (2018-08-21 04:36:20)
> On 8/18/2018 11:31 PM, Taniya Das wrote:
> > Hello Stephen,
> > 
> > I will test these changes and get back.
> > 
> > On 8/18/2018 7:42 AM, Stephen Boyd wrote:
> >> Quoting Taniya Das (2018-08-10 18:53:54)
> >>>   [v4]
> >>>    * Add recalc_clk_ops to calculate the clock frequency reading the 
> >>> current
> >>>      perf state, also add CLK_GET_RATE_NOCACHE flag.
> >>>    * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'.
> >>>    * cleanup return from function 'com_cc_register_rcg_dfs'.
> >>
> >> I want to squash this in. I have only compile tested it. Let me know
> >> what you think.
> >>
> >> ----8<---
> >> diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
> >> index e6300e05d5df..e5eca8a1abe4 100644
> >> --- a/drivers/clk/qcom/clk-rcg.h
> >> +++ b/drivers/clk/qcom/clk-rcg.h
> >> @@ -163,6 +163,15 @@ 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;
> >> +struct clk_rcg_dfs_data {
> >> +    struct clk_rcg2 *rcg;
> >> +    struct clk_init_data *init;
> >> +};
> >> +
> >> +#define DEFINE_RCG_DFS(r) \
> >> +    { .rcg = &r##_src, .init = &r##_init }
> >> +
> >>   extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
> >> -                 struct clk_rcg2 **rcgs, int num_clks);
> >> +                    const struct clk_rcg_dfs_data *rcgs,
> >> +                    size_t len);
> >>   #endif
> >> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
> >> index 55a5b58cbb15..bbe2a1916296 100644
> >> --- a/drivers/clk/qcom/clk-rcg2.c
> >> +++ b/drivers/clk/qcom/clk-rcg2.c
> >> @@ -1051,48 +1051,24 @@ static unsigned long
> >>   clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> >>   {
> >>       struct clk_rcg2 *rcg = to_clk_rcg2(hw);
> >> -    u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
> >> -    int num_parents, i;
> >> -    unsigned long prate;
> >> -
> >> -    regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> >> -                SE_CMD_DFSR_OFFSET, &cfg);
> >> -    level = (GENMASK(4, 1) & cfg) >> 1;
> >> -
> >> -    regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> >> -                SE_PERF_DFSR(level), &cfg);
> >> -    if (rcg->mnd_width) {
> >> -        mask = BIT(rcg->mnd_width) - 1;
> >> -        regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> >> -                SE_PERF_M_DFSR(level), &m);
> >> -        m &= mask;
> >> -        regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
> >> -                SE_PERF_N_DFSR(level), &n);
> >> -        n =  ~n;
> >> -        n &= mask;
> >> -        n += m;
> >> -        mode = cfg & CFG_MODE_MASK;
> >> -        mode >>= CFG_MODE_SHIFT;
> >> -    }
> >> +    int ret;
> >> +    u32 level;
> >> -    mask = BIT(rcg->hid_width) - 1;
> >> -    hid_div = cfg >> CFG_SRC_DIV_SHIFT;
> >> -    hid_div &= mask;
> >> -    cfg &= CFG_SRC_SEL_MASK;
> >> -    cfg >>= CFG_SRC_SEL_SHIFT;
> >> +    regmap_read(rcg->clkr.regmap,
> >> +            rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
> >> +    level &= GENMASK(4, 1);
> >> +    level >>= 1;
> >> -    num_parents = clk_hw_get_num_parents(hw);
> >> -    for (i = 0; i < num_parents; i++) {
> >> -        if (cfg == rcg->parent_map[i].cfg) {
> >> -            prate = clk_hw_get_rate(
> >> -                clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
> >> -            if (parent_rate != prate)
> >> -                parent_rate = prate;
> >> +    if (!rcg->freq_tbl) {
> >> +        ret = clk_rcg2_dfs_populate_freq_table(rcg);
> 
> This function would retrieve the parent_rate and if the parent_rate is 
> not ready then it would fail to boot up.
> 
> So we have to make sure the parents are registered before these RCGs. 
> That also was one reason for me to not populate the frequency table at 
> recalc.
> 
> We would need this patch to make this work.

Hmmmm. Ok. That won't work then. recalc_rate() better not try to
populate the frequency table then or it will not work. So I suppose it
needs to fallback to reading the registers and assuming the parent_rate
coming in is the actual frequency of it's parent until the frequency
table pointer is non-NULL. Would that work?

BTW, does DFS switch parents without software knowing about it? What
happens in that case? Does the QUP driver make sure that the new parent
of this RCG is properly enabled so that it can switch to it when needed?
I'm still trying to understand this whole design. Who takes care of the
voltage requirements in this case? The QUP driver as well?


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-21 15:30       ` Stephen Boyd
@ 2018-08-22 10:28         ` Taniya Das
  2018-08-23 18:25           ` Stephen Boyd
  0 siblings, 1 reply; 11+ messages in thread
From: Taniya Das @ 2018-08-22 10:28 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel



On 8/21/2018 9:00 PM, Stephen Boyd wrote:
> Quoting Taniya Das (2018-08-21 04:36:20)
>> On 8/18/2018 11:31 PM, Taniya Das wrote:
>>> Hello Stephen,
>>>
>>> I will test these changes and get back.
>>>
>>> On 8/18/2018 7:42 AM, Stephen Boyd wrote:
>>>> Quoting Taniya Das (2018-08-10 18:53:54)
>>>>>    [v4]
>>>>>     * Add recalc_clk_ops to calculate the clock frequency reading the
>>>>> current
>>>>>       perf state, also add CLK_GET_RATE_NOCACHE flag.
>>>>>     * Cleanup 'goto' during mode check in 'clk_rcg2_calculate_freq'.
>>>>>     * cleanup return from function 'com_cc_register_rcg_dfs'.
>>>>
>>>> I want to squash this in. I have only compile tested it. Let me know
>>>> what you think.
>>>>
>>>> ----8<---
>>>> diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
>>>> index e6300e05d5df..e5eca8a1abe4 100644
>>>> --- a/drivers/clk/qcom/clk-rcg.h
>>>> +++ b/drivers/clk/qcom/clk-rcg.h
>>>> @@ -163,6 +163,15 @@ 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;
>>>> +struct clk_rcg_dfs_data {
>>>> +    struct clk_rcg2 *rcg;
>>>> +    struct clk_init_data *init;
>>>> +};
>>>> +
>>>> +#define DEFINE_RCG_DFS(r) \
>>>> +    { .rcg = &r##_src, .init = &r##_init }
>>>> +
>>>>    extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
>>>> -                 struct clk_rcg2 **rcgs, int num_clks);
>>>> +                    const struct clk_rcg_dfs_data *rcgs,
>>>> +                    size_t len);
>>>>    #endif
>>>> diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
>>>> index 55a5b58cbb15..bbe2a1916296 100644
>>>> --- a/drivers/clk/qcom/clk-rcg2.c
>>>> +++ b/drivers/clk/qcom/clk-rcg2.c
>>>> @@ -1051,48 +1051,24 @@ static unsigned long
>>>>    clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
>>>>    {
>>>>        struct clk_rcg2 *rcg = to_clk_rcg2(hw);
>>>> -    u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
>>>> -    int num_parents, i;
>>>> -    unsigned long prate;
>>>> -
>>>> -    regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>>>> -                SE_CMD_DFSR_OFFSET, &cfg);
>>>> -    level = (GENMASK(4, 1) & cfg) >> 1;
>>>> -
>>>> -    regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>>>> -                SE_PERF_DFSR(level), &cfg);
>>>> -    if (rcg->mnd_width) {
>>>> -        mask = BIT(rcg->mnd_width) - 1;
>>>> -        regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>>>> -                SE_PERF_M_DFSR(level), &m);
>>>> -        m &= mask;
>>>> -        regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
>>>> -                SE_PERF_N_DFSR(level), &n);
>>>> -        n =  ~n;
>>>> -        n &= mask;
>>>> -        n += m;
>>>> -        mode = cfg & CFG_MODE_MASK;
>>>> -        mode >>= CFG_MODE_SHIFT;
>>>> -    }
>>>> +    int ret;
>>>> +    u32 level;
>>>> -    mask = BIT(rcg->hid_width) - 1;
>>>> -    hid_div = cfg >> CFG_SRC_DIV_SHIFT;
>>>> -    hid_div &= mask;
>>>> -    cfg &= CFG_SRC_SEL_MASK;
>>>> -    cfg >>= CFG_SRC_SEL_SHIFT;
>>>> +    regmap_read(rcg->clkr.regmap,
>>>> +            rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
>>>> +    level &= GENMASK(4, 1);
>>>> +    level >>= 1;
>>>> -    num_parents = clk_hw_get_num_parents(hw);
>>>> -    for (i = 0; i < num_parents; i++) {
>>>> -        if (cfg == rcg->parent_map[i].cfg) {
>>>> -            prate = clk_hw_get_rate(
>>>> -                clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
>>>> -            if (parent_rate != prate)
>>>> -                parent_rate = prate;
>>>> +    if (!rcg->freq_tbl) {
>>>> +        ret = clk_rcg2_dfs_populate_freq_table(rcg);
>>
>> This function would retrieve the parent_rate and if the parent_rate is
>> not ready then it would fail to boot up.
>>
>> So we have to make sure the parents are registered before these RCGs.
>> That also was one reason for me to not populate the frequency table at
>> recalc.
>>
>> We would need this patch to make this work.
> 
> Hmmmm. Ok. That won't work then. recalc_rate() better not try to
> populate the frequency table then or it will not work. So I suppose it
> needs to fallback to reading the registers and assuming the parent_rate
> coming in is the actual frequency of it's parent until the frequency
> table pointer is non-NULL. Would that work?
> 
Yes that would work.

> BTW, does DFS switch parents without software knowing about it? 
DFS would not switch until a HW request is sent, but SW would be unware 
of the switch except the current_perf_state being updated with the 
requested level.

What
> happens in that case? Does the QUP driver make sure that the new parent
> of this RCG is properly enabled so that it can switch to it when needed?

I am not sure if they poll for any of their QUP HW state to make sure 
the switch is complete.

> I'm still trying to understand this whole design. Who takes care of the
> voltage requirements in this case? The QUP driver as well?
> 

When the QUP driver requires to switch to new performance level, the 
first request would be to set_rate()(QUP driver would get the list of 
supported frequencies using the clk_round_rate()) which in QCOM clock 
driver would take care of setting the required voltage for the new 
parent switch.
Then the QUP driver would request the HW for a new perf switch which 
would result to a DFS switch for the QUP clocks.

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

--

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-22 10:28         ` Taniya Das
@ 2018-08-23 18:25           ` Stephen Boyd
  2018-08-27 21:04             ` Stephen Boyd
  0 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2018-08-23 18:25 UTC (permalink / raw)
  To: Michael Turquette, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel

Quoting Taniya Das (2018-08-22 03:28:31)
> 
> > 
> > Hmmmm. Ok. That won't work then. recalc_rate() better not try to
> > populate the frequency table then or it will not work. So I suppose it
> > needs to fallback to reading the registers and assuming the parent_rate
> > coming in is the actual frequency of it's parent until the frequency
> > table pointer is non-NULL. Would that work?
> > 
> Yes that would work.

Ok.

> 
> > BTW, does DFS switch parents without software knowing about it? 
> DFS would not switch until a HW request is sent, but SW would be unware 
> of the switch except the current_perf_state being updated with the 
> requested level.
> 
> What
> > happens in that case? Does the QUP driver make sure that the new parent
> > of this RCG is properly enabled so that it can switch to it when needed?
> 
> I am not sure if they poll for any of their QUP HW state to make sure 
> the switch is complete.
> 
> > I'm still trying to understand this whole design. Who takes care of the
> > voltage requirements in this case? The QUP driver as well?
> > 
> 
> When the QUP driver requires to switch to new performance level, the 
> first request would be to set_rate()(QUP driver would get the list of 
> supported frequencies using the clk_round_rate()) which in QCOM clock 
> driver would take care of setting the required voltage for the new 
> parent switch.

It would also make sure that the new parent is enabled if the QUP clk is
enabled. That's another concern. Does the PLL turn on automatically when
the RCG switches to it?

> Then the QUP driver would request the HW for a new perf switch which 
> would result to a DFS switch for the QUP clocks.

It sounds like the QUP driver does half of the work via the clk APIs and
then the other half through the DFS register. Maybe the QUP driver
should be registering a clk as well for its DFS register so it can all
be clk API calls here. Something to consider. Anyway, that's not
important to this patch so here's the updated patch.

---8<----
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index e6300e05d5df..e5eca8a1abe4 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -163,6 +163,15 @@ 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;
 
+struct clk_rcg_dfs_data {
+	struct clk_rcg2 *rcg;
+	struct clk_init_data *init;
+};
+
+#define DEFINE_RCG_DFS(r) \
+	{ .rcg = &r##_src, .init = &r##_init }
+
 extern int qcom_cc_register_rcg_dfs(struct regmap *regmap,
-			     struct clk_rcg2 **rcgs, int num_clks);
+				    const struct clk_rcg_dfs_data *rcgs,
+				    size_t len);
 #endif
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 55a5b58cbb15..d5d77f9ad170 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -940,25 +940,21 @@ const struct clk_ops clk_rcg2_shared_ops = {
 EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
 
 /* Common APIs to be used for DFS based RCGR */
-static unsigned long clk_rcg2_calculate_freq(struct clk_hw *hw,
-		int level, struct freq_tbl *f)
+static void clk_rcg2_dfs_populate_freq(struct clk_hw *hw, unsigned int l,
+				       struct freq_tbl *f)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
 	struct clk_hw *p;
 	unsigned long prate = 0;
-	u32 val, mask, cfg, m_off, n_off, offset, mode;
-	int i, ret, num_parents;
+	u32 val, mask, cfg, mode;
+	int i, num_parents;
 
-	offset = SE_PERF_DFSR(level);
-	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + offset, &cfg);
-	if (ret)
-		return ret;
+	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(l), &cfg);
 
 	mask = BIT(rcg->hid_width) - 1;
-	f->pre_div = cfg & mask ? (cfg & mask) : 1;
-
-	mode = cfg & CFG_MODE_MASK;
-	mode >>= CFG_MODE_SHIFT;
+	f->pre_div = 1;
+	if (cfg & mask)
+		f->pre_div = cfg & mask;
 
 	cfg &= CFG_SRC_SEL_MASK;
 	cfg >>= CFG_SRC_SEL_SHIFT;
@@ -972,60 +968,39 @@ static unsigned long clk_rcg2_calculate_freq(struct clk_hw *hw,
 		}
 	}
 
+	mode = cfg & CFG_MODE_MASK;
+	mode >>= CFG_MODE_SHIFT;
 	if (mode) {
-		/* Calculate M & N values */
-		m_off = SE_PERF_M_DFSR(level);
-		n_off = SE_PERF_N_DFSR(level);
-
 		mask = BIT(rcg->mnd_width) - 1;
-		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + m_off,
-					&val);
-		if (ret) {
-			pr_err("Failed to read M offset register\n");
-			return ret;
-		}
+		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_M_DFSR(l),
+			    &val);
 		val &= mask;
 		f->m = val;
 
-		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + n_off,
-					&val);
-		if (ret) {
-			pr_err("Failed to read N offset register\n");
-			return ret;
-		}
-		/* val ~(N-M) */
+		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_N_DFSR(l),
+			    &val);
 		val = ~val;
 		val &= mask;
 		val += f->m;
 		f->n = val;
 	}
 
-	return calc_rate(prate, f->m, f->n, mode, f->pre_div);
+	f->freq = calc_rate(prate, f->m, f->n, mode, f->pre_div);
 }
 
 static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg)
 {
 	struct freq_tbl *freq_tbl;
-	unsigned long calc_freq;
 	int i;
 
-	freq_tbl = kcalloc(MAX_PERF_LEVEL, sizeof(*freq_tbl),
-				GFP_KERNEL);
+	freq_tbl = kcalloc(MAX_PERF_LEVEL, sizeof(*freq_tbl), GFP_KERNEL);
 	if (!freq_tbl)
 		return -ENOMEM;
-
-	for (i = 0; i < MAX_PERF_LEVEL; i++) {
-		calc_freq = clk_rcg2_calculate_freq(&rcg->clkr.hw,
-							i, &freq_tbl[i]);
-		if (calc_freq < 0) {
-			kfree(freq_tbl);
-			return calc_freq;
-		}
-
-		freq_tbl[i].freq = calc_freq;
-	}
 	rcg->freq_tbl = freq_tbl;
 
+	for (i = 0; i < MAX_PERF_LEVEL; i++)
+		clk_rcg2_dfs_populate_freq(&rcg->clkr.hw, i, freq_tbl + i);
+
 	return 0;
 }
 
@@ -1044,55 +1019,54 @@ static int clk_rcg2_dfs_determine_rate(struct clk_hw *hw,
 		}
 	}
 
-	return clk_rcg2_shared_ops.determine_rate(hw, req);
+	return clk_rcg2_determine_rate(hw, req);
 }
 
 static unsigned long
 clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
 {
 	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
-	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask, level;
-	int num_parents, i;
-	unsigned long prate;
+	u32 level, mask, cfg, m = 0, n = 0, mode, pre_div;
 
-	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_CMD_DFSR_OFFSET, &cfg);
-	level = (GENMASK(4, 1) & cfg) >> 1;
+	regmap_read(rcg->clkr.regmap,
+		    rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
+	level &= GENMASK(4, 1);
+	level >>= 1;
 
-	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_PERF_DFSR(level), &cfg);
-	if (rcg->mnd_width) {
+	if (rcg->freq_tbl)
+		return rcg->freq_tbl[level].freq;
+
+	/*
+	 * Assume that parent_rate is actually the parent because
+	 * we can't do any better at figuring it out when the table
+	 * hasn't been populated yet. We only populate the table
+	 * in determine_rate because we can't guarantee the parents
+	 * will be registered with the framework until then.
+	 */
+	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(level),
+		    &cfg);
+
+	mask = BIT(rcg->hid_width) - 1;
+	pre_div = 1;
+	if (cfg & mask)
+		pre_div = cfg & mask;
+
+	mode = cfg & CFG_MODE_MASK;
+	mode >>= CFG_MODE_SHIFT;
+	if (mode) {
 		mask = BIT(rcg->mnd_width) - 1;
-		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_PERF_M_DFSR(level), &m);
+		regmap_read(rcg->clkr.regmap,
+			    rcg->cmd_rcgr + SE_PERF_M_DFSR(level), &m);
 		m &= mask;
-		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr +
-				SE_PERF_N_DFSR(level), &n);
-		n =  ~n;
+
+		regmap_read(rcg->clkr.regmap,
+			    rcg->cmd_rcgr + SE_PERF_N_DFSR(level), &n);
+		n = ~n;
 		n &= mask;
 		n += m;
-		mode = cfg & CFG_MODE_MASK;
-		mode >>= CFG_MODE_SHIFT;
 	}
 
-	mask = BIT(rcg->hid_width) - 1;
-	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
-	hid_div &= mask;
-	cfg &= CFG_SRC_SEL_MASK;
-	cfg >>= CFG_SRC_SEL_SHIFT;
-
-	num_parents = clk_hw_get_num_parents(hw);
-	for (i = 0; i < num_parents; i++) {
-		if (cfg == rcg->parent_map[i].cfg) {
-			prate = clk_hw_get_rate(
-				clk_hw_get_parent_by_index(&rcg->clkr.hw, i));
-			if (parent_rate != prate)
-				parent_rate = prate;
-		}
-	}
-
-
-	return calc_rate(parent_rate, m, n, mode, hid_div);
+	return calc_rate(parent_rate, m, n, mode, pre_div);
 }
 
 static const struct clk_ops clk_rcg2_dfs_ops = {
@@ -1102,32 +1076,28 @@ static const struct clk_ops clk_rcg2_dfs_ops = {
 	.recalc_rate = clk_rcg2_dfs_recalc_rate,
 };
 
-static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
+static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
+			       struct regmap *regmap)
 {
-	struct clk_init_data *init;
+	struct clk_rcg2 *rcg = data->rcg;
+	struct clk_init_data *init = data->init;
 	u32 val;
 	int ret;
 
-	ret = regmap_read(regmap, rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET,
-			  &val);
+	ret = regmap_read(regmap, rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &val);
 	if (ret)
 		return -EINVAL;
 
 	if (!(val & SE_CMD_DFS_EN))
 		return 0;
 
-	init = kzalloc(sizeof(*init), GFP_KERNEL);
-	if (!init)
-		return -ENOMEM;
-
-	init->name = rcg->clkr.hw.init->name;
-	init->flags = rcg->clkr.hw.init->flags;
-	init->parent_names = rcg->clkr.hw.init->parent_names;
-	init->num_parents = rcg->clkr.hw.init->num_parents;
-	init->flags = CLK_GET_RATE_NOCACHE;
+	/*
+	 * Rate changes with consumer writing a register in
+	 * their own I/O region
+	 */
+	init->flags |= CLK_GET_RATE_NOCACHE;
 	init->ops = &clk_rcg2_dfs_ops;
 
-	rcg->clkr.hw.init = init;
 	rcg->freq_tbl = NULL;
 
 	pr_debug("DFS registered for clk %s\n", init->name);
@@ -1136,14 +1106,14 @@ static int clk_rcg2_enable_dfs(struct clk_rcg2 *rcg, struct regmap *regmap)
 }
 
 int qcom_cc_register_rcg_dfs(struct regmap *regmap,
-			    struct clk_rcg2 **rcgs, int num_clks)
+			     const struct clk_rcg_dfs_data *rcgs, size_t len)
 {
 	int i, ret;
 
-	for (i = 0; i < num_clks; i++) {
-		ret = clk_rcg2_enable_dfs(rcgs[i], regmap);
+	for (i = 0; i < len; i++) {
+		ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
 		if (ret) {
-			const char *name = rcgs[i]->clkr.hw.init->name;
+			const char *name = rcgs[i].init->name;
 
 			pr_err("DFS register failed for clk %s\n", name);
 			return ret;
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index fef6732bd7d8..42ab01d33b52 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -396,18 +396,27 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
 	{ }
 };
 
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_init = {
+	.name = "gcc_qupv3_wrap0_s0_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
+};
+
 static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
 	.cmd_rcgr = 0x17034,
 	.mnd_width = 16,
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s0_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_init = {
+	.name = "gcc_qupv3_wrap0_s1_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
@@ -416,12 +425,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s1_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_init = {
+	.name = "gcc_qupv3_wrap0_s2_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
@@ -430,12 +441,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s2_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_init = {
+	.name = "gcc_qupv3_wrap0_s3_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
@@ -444,12 +457,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s3_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_init = {
+	.name = "gcc_qupv3_wrap0_s4_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
@@ -458,12 +473,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s4_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_init = {
+	.name = "gcc_qupv3_wrap0_s5_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
@@ -472,12 +489,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s5_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_init = {
+	.name = "gcc_qupv3_wrap0_s6_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
@@ -486,12 +505,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s6_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s7_clk_init = {
+	.name = "gcc_qupv3_wrap0_s7_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
@@ -500,12 +521,14 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap0_s7_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_init = {
+	.name = "gcc_qupv3_wrap1_s0_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
@@ -514,12 +537,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s0_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_init = {
+	.name = "gcc_qupv3_wrap1_s1_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
@@ -528,12 +553,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s1_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_init = {
+	.name = "gcc_qupv3_wrap1_s2_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
@@ -542,12 +569,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s2_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_init = {
+	.name = "gcc_qupv3_wrap1_s3_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
@@ -556,12 +585,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s3_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_init = {
+	.name = "gcc_qupv3_wrap1_s4_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
@@ -570,12 +601,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s4_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_init = {
+	.name = "gcc_qupv3_wrap1_s5_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
@@ -584,12 +617,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s5_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_init = {
+	.name = "gcc_qupv3_wrap1_s6_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
@@ -598,12 +633,14 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s6_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_init = {
+	.name = "gcc_qupv3_wrap1_s7_clk_src",
+	.parent_names = gcc_parent_names_0,
+	.num_parents = 4,
+	.ops = &clk_rcg2_shared_ops,
 };
 
 static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
@@ -612,12 +649,7 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
 	.hid_width = 5,
 	.parent_map = gcc_parent_map_0,
 	.freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
-	.clkr.hw.init = &(struct clk_init_data){
-		.name = "gcc_qupv3_wrap1_s7_clk_src",
-		.parent_names = gcc_parent_names_0,
-		.num_parents = 4,
-		.ops = &clk_rcg2_shared_ops,
-	},
+	.clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_init,
 };
 
 static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
@@ -3458,23 +3490,23 @@ static const struct of_device_id gcc_sdm845_match_table[] = {
 };
 MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table);
 
-static struct clk_rcg2 *gcc_dfs_clocks[] = {
-	&gcc_qupv3_wrap0_s0_clk_src,
-	&gcc_qupv3_wrap0_s1_clk_src,
-	&gcc_qupv3_wrap0_s2_clk_src,
-	&gcc_qupv3_wrap0_s3_clk_src,
-	&gcc_qupv3_wrap0_s4_clk_src,
-	&gcc_qupv3_wrap0_s5_clk_src,
-	&gcc_qupv3_wrap0_s6_clk_src,
-	&gcc_qupv3_wrap0_s7_clk_src,
-	&gcc_qupv3_wrap1_s0_clk_src,
-	&gcc_qupv3_wrap1_s1_clk_src,
-	&gcc_qupv3_wrap1_s2_clk_src,
-	&gcc_qupv3_wrap1_s3_clk_src,
-	&gcc_qupv3_wrap1_s4_clk_src,
-	&gcc_qupv3_wrap1_s5_clk_src,
-	&gcc_qupv3_wrap1_s6_clk_src,
-	&gcc_qupv3_wrap1_s7_clk_src,
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk),
+	DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk),
 };
 
 static int gcc_sdm845_probe(struct platform_device *pdev)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-23 18:25           ` Stephen Boyd
@ 2018-08-27 21:04             ` Stephen Boyd
  2018-08-28  9:06               ` Taniya Das
  0 siblings, 1 reply; 11+ messages in thread
From: Stephen Boyd @ 2018-08-27 21:04 UTC (permalink / raw)
  To: Michael Turquette, Taniya Das
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel

Quoting Stephen Boyd (2018-08-23 11:25:41)
> Quoting Taniya Das (2018-08-22 03:28:31)
> > 
> > > 
> > > Hmmmm. Ok. That won't work then. recalc_rate() better not try to
> > > populate the frequency table then or it will not work. So I suppose it
> > > needs to fallback to reading the registers and assuming the parent_rate
> > > coming in is the actual frequency of it's parent until the frequency
> > > table pointer is non-NULL. Would that work?
> > > 
> > Yes that would work.
> 
> Ok.
> 
> > 
> > > BTW, does DFS switch parents without software knowing about it? 
> > DFS would not switch until a HW request is sent, but SW would be unware 
> > of the switch except the current_perf_state being updated with the 
> > requested level.
> > 
> > What
> > > happens in that case? Does the QUP driver make sure that the new parent
> > > of this RCG is properly enabled so that it can switch to it when needed?
> > 
> > I am not sure if they poll for any of their QUP HW state to make sure 
> > the switch is complete.
> > 
> > > I'm still trying to understand this whole design. Who takes care of the
> > > voltage requirements in this case? The QUP driver as well?
> > > 
> > 
> > When the QUP driver requires to switch to new performance level, the 
> > first request would be to set_rate()(QUP driver would get the list of 
> > supported frequencies using the clk_round_rate()) which in QCOM clock 
> > driver would take care of setting the required voltage for the new 
> > parent switch.
> 
> It would also make sure that the new parent is enabled if the QUP clk is
> enabled. That's another concern. Does the PLL turn on automatically when
> the RCG switches to it?
> 
> > Then the QUP driver would request the HW for a new perf switch which 
> > would result to a DFS switch for the QUP clocks.
> 
> It sounds like the QUP driver does half of the work via the clk APIs and
> then the other half through the DFS register. Maybe the QUP driver
> should be registering a clk as well for its DFS register so it can all
> be clk API calls here. Something to consider. Anyway, that's not
> important to this patch so here's the updated patch.

I've squashed this in and applied the patches.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS
  2018-08-27 21:04             ` Stephen Boyd
@ 2018-08-28  9:06               ` Taniya Das
  0 siblings, 0 replies; 11+ messages in thread
From: Taniya Das @ 2018-08-28  9:06 UTC (permalink / raw)
  To: Stephen Boyd, Michael Turquette
  Cc: Andy Gross, David Brown, Rajendra Nayak, Amit Nischal,
	linux-arm-msm, linux-soc, linux-clk, linux-kernel



On 8/28/2018 2:34 AM, Stephen Boyd wrote:
> Quoting Stephen Boyd (2018-08-23 11:25:41)
>> Quoting Taniya Das (2018-08-22 03:28:31)
>>>
>>>>
>>>> Hmmmm. Ok. That won't work then. recalc_rate() better not try to
>>>> populate the frequency table then or it will not work. So I suppose it
>>>> needs to fallback to reading the registers and assuming the parent_rate
>>>> coming in is the actual frequency of it's parent until the frequency
>>>> table pointer is non-NULL. Would that work?
>>>>
>>> Yes that would work.
>>
>> Ok.
>>
>>>
>>>> BTW, does DFS switch parents without software knowing about it?
>>> DFS would not switch until a HW request is sent, but SW would be unware
>>> of the switch except the current_perf_state being updated with the
>>> requested level.
>>>
>>> What
>>>> happens in that case? Does the QUP driver make sure that the new parent
>>>> of this RCG is properly enabled so that it can switch to it when needed?
>>>
>>> I am not sure if they poll for any of their QUP HW state to make sure
>>> the switch is complete.
>>>
>>>> I'm still trying to understand this whole design. Who takes care of the
>>>> voltage requirements in this case? The QUP driver as well?
>>>>
>>>
>>> When the QUP driver requires to switch to new performance level, the
>>> first request would be to set_rate()(QUP driver would get the list of
>>> supported frequencies using the clk_round_rate()) which in QCOM clock
>>> driver would take care of setting the required voltage for the new
>>> parent switch.
>>
>> It would also make sure that the new parent is enabled if the QUP clk is
>> enabled. That's another concern. Does the PLL turn on automatically when
>> the RCG switches to it?
>>
>>> Then the QUP driver would request the HW for a new perf switch which
>>> would result to a DFS switch for the QUP clocks.
>>
>> It sounds like the QUP driver does half of the work via the clk APIs and
>> then the other half through the DFS register. Maybe the QUP driver
>> should be registering a clk as well for its DFS register so it can all
>> be clk API calls here. Something to consider. Anyway, that's not
>> important to this patch so here's the updated patch.
> 
> I've squashed this in and applied the patches.
> 
Thanks Stephen.
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation.

--

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2018-08-28  9:06 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-11  1:53 [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Taniya Das
2018-08-11  1:53 ` [PATCH v4 1/2] " Taniya Das
2018-08-11  1:53 ` [PATCH v4 2/2] clk: qcom: gcc: Register QUPv3 RCGs for DFS on SDM845 Taniya Das
2018-08-18  2:12 ` [PATCH v4 0/2] clk: qcom: Add support for RCG to register for DFS Stephen Boyd
2018-08-18 18:01   ` Taniya Das
2018-08-21 11:36     ` Taniya Das
2018-08-21 15:30       ` Stephen Boyd
2018-08-22 10:28         ` Taniya Das
2018-08-23 18:25           ` Stephen Boyd
2018-08-27 21:04             ` Stephen Boyd
2018-08-28  9:06               ` Taniya Das

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).