* [PATCH 1/2] clk: qcom: clear hardware clock control bit of RCG
2017-10-31 7:19 [PATCH 0/2] clk: qcom: MISC RCG changes for upcoming targets Amit Nischal
@ 2017-10-31 7:19 ` Amit Nischal
2017-10-31 7:19 ` [PATCH 2/2] clk: qcom: Modify RCG shared ops to support freq_tbl without XO entry Amit Nischal
1 sibling, 0 replies; 5+ messages in thread
From: Amit Nischal @ 2017-10-31 7:19 UTC (permalink / raw)
To: Stephen Boyd, Michael Turquette
Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal
For upcoming targets, the hardware clock control bit is set for most of
root clocks which needs to be cleared for software to be able to control
those root clocks. For older targets like MSM8996, this bit is reserved
bit and having POR value as 0 so this patch will work for the older
targets too. So update the configuration mask to take care of the same to
clear hardware clock control bit.
Signed-off-by: Amit Nischal <anischal@codeaurora.org>
---
drivers/clk/qcom/clk-rcg2.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 1a0985a..ac9ce61 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -42,6 +42,7 @@
#define CFG_MODE_SHIFT 12
#define CFG_MODE_MASK (0x3 << CFG_MODE_SHIFT)
#define CFG_MODE_DUAL_EDGE (0x2 << CFG_MODE_SHIFT)
+#define CFG_HW_CLK_CTRL_MASK BIT(20)
#define M_REG 0x8
#define N_REG 0xc
@@ -276,7 +277,7 @@ static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
}
mask = BIT(rcg->hid_width) - 1;
- mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK;
+ mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK;
cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
if (rcg->mnd_width && f->n && (f->m != f->n))
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] clk: qcom: Modify RCG shared ops to support freq_tbl without XO entry
2017-10-31 7:19 [PATCH 0/2] clk: qcom: MISC RCG changes for upcoming targets Amit Nischal
2017-10-31 7:19 ` [PATCH 1/2] clk: qcom: clear hardware clock control bit of RCG Amit Nischal
@ 2017-10-31 7:19 ` Amit Nischal
2017-11-02 6:46 ` Stephen Boyd
1 sibling, 1 reply; 5+ messages in thread
From: Amit Nischal @ 2017-10-31 7:19 UTC (permalink / raw)
To: Stephen Boyd, Michael Turquette
Cc: Andy Gross, David Brown, Rajendra Nayak, Odelu Kukatla,
linux-arm-msm, linux-soc, linux-clk, linux-kernel, Amit Nischal
There could be some clock sources where there is no entry corresponding
XO in their frequency table, for such sources rcg2_shared_ops would
wrongly configure the RCG registers during enable/disable, which leads
to mismatch between the hardware and software rate so modify the shared
ops to handle such cases.
Signed-off-by: Amit Nischal <anischal@codeaurora.org>
---
drivers/clk/qcom/clk-rcg2.c | 79 +++++++++++++++++++++++++++++++++++++++------
1 file changed, 70 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index ac9ce61..8f7ca0c 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -48,6 +48,14 @@
#define N_REG 0xc
#define D_REG 0x10
+static struct freq_tbl cxo_f = {
+ .freq = 19200000,
+ .src = 0,
+ .pre_div = 1,
+ .m = 0,
+ .n = 0,
+};
+
enum freq_policy {
FLOOR,
CEIL,
@@ -359,7 +367,7 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw,
};
EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
-static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate)
+static int clk_rcg2_set_force_enable(struct clk_hw *hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
const char *name = clk_hw_get_name(hw);
@@ -373,22 +381,41 @@ static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate)
/* wait for RCG to turn ON */
for (count = 500; count > 0; count--) {
- ret = clk_rcg2_is_enabled(hw);
- if (ret)
- break;
+ if (clk_rcg2_is_enabled(hw))
+ return 0;
+
+ /* Delay for 1usec and retry polling the status bit */
udelay(1);
}
if (!count)
pr_err("%s: RCG did not turn on\n", name);
+ return -ETIMEDOUT;
+}
+
+static int clk_rcg2_clear_force_enable(struct clk_hw *hw)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+
+ /* clear force enable RCG */
+ return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
+ CMD_ROOT_EN, 0);
+}
+
+static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate)
+{
+ int ret;
+
+ ret = clk_rcg2_set_force_enable(hw);
+ if (ret)
+ return ret;
+
/* set clock rate */
ret = __clk_rcg2_set_rate(hw, rate, CEIL);
if (ret)
return ret;
- /* clear force enable RCG */
- return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
- CMD_ROOT_EN, 0);
+ return clk_rcg2_clear_force_enable(hw);
}
static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -399,6 +426,11 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
/* cache the rate */
rcg->current_freq = rate;
+ /*
+ * Return if the RCG is currently disabled. This configuration
+ * update will happen as part of the RCG enable sequence.
+ */
+
if (!__clk_is_enabled(hw->clk))
return 0;
@@ -410,6 +442,12 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ if (!__clk_is_enabled(hw->clk)) {
+ if (!rcg->current_freq)
+ rcg->current_freq = cxo_f.freq;
+ return rcg->current_freq;
+ }
+
return rcg->current_freq = clk_rcg2_recalc_rate(hw, parent_rate);
}
@@ -417,6 +455,20 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ if (rcg->current_freq == cxo_f.freq) {
+ clk_rcg2_set_force_enable(hw);
+ clk_rcg2_configure(rcg, &cxo_f);
+ clk_rcg2_clear_force_enable(hw);
+
+ return 0;
+ }
+
+ /*
+ * Switch from CXO to the stashed mux selection. The current
+ * parent has already been prepared and enabled at this point,
+ * and the CXO source is always on while application processor
+ * subsystem is online. Therefore, the RCG can safely be switched.
+ */
return clk_rcg2_shared_force_enable(hw, rcg->current_freq);
}
@@ -424,8 +476,17 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- /* switch to XO, which is the lowest entry in the freq table */
- clk_rcg2_shared_set_rate(hw, rcg->freq_tbl[0].freq, 0);
+ /*
+ * Park the RCG at a safe configuration - sourced off the CXO.
+ * Force enable and disable the RCG while configuring it to
+ * safeguard against any update signal coming from the downstream
+ * clock. The current parent is still prepared and enabled at this
+ * point, and the CXO source is always on while application processor
+ * subsystem is online. Therefore, the RCG can safely be switched.
+ */
+ clk_rcg2_set_force_enable(hw);
+ clk_rcg2_configure(rcg, &cxo_f);
+ clk_rcg2_clear_force_enable(hw);
}
const struct clk_ops clk_rcg2_shared_ops = {
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply related [flat|nested] 5+ messages in thread