From e21cc1fb80e1b220628f565bb003f6682cadea16 Mon Sep 17 00:00:00 2001 From: Praveenkumar I Date: Tue, 13 Jun 2017 15:30:39 +0530 Subject: [PATCH 1002/1011] clk: qcom: add support for hw controlled RCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current driver generates stack trace during RCG update if the RCG is off and new parent source is also disabled. For hardware controlled RCG’s, clock is forced on during update process and goes back to off status once switch is completed. Since the new parent is in disabled state so update bit won’t be cleared. The check for update bit can be skipped in this case. Signed-off-by: Abhishek Sahu Signed-off-by: Praveenkumar I Signed-off-by: Alexandru Gagniuc --- drivers/clk/qcom/clk-rcg.h | 4 ++++ drivers/clk/qcom/clk-rcg2.c | 29 ++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -135,6 +135,7 @@ extern const struct clk_ops clk_dyn_rcg_ * @mnd_width: number of bits in m/n/d values * @hid_width: number of bits in half integer divider * @safe_src_index: safe src index value + * @flags: RCG2 specific clock flags * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @clkr: regmap clock handle @@ -145,6 +146,9 @@ struct clk_rcg2 { u8 mnd_width; u8 hid_width; u8 safe_src_index; + +#define CLK_RCG2_HW_CONTROLLED BIT(0) + u8 flags; const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; struct clk_regmap clkr; --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -98,7 +98,7 @@ err: return 0; } -static int update_config(struct clk_rcg2 *rcg) +static int update_config(struct clk_rcg2 *rcg, bool check_update_clear) { int count, ret; u32 cmd; @@ -110,6 +110,9 @@ static int update_config(struct clk_rcg2 if (ret) return ret; + if (!check_update_clear) + return 0; + /* Wait for update to take effect */ for (count = 500; count > 0; count--) { ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd); @@ -128,14 +131,19 @@ static int clk_rcg2_set_parent(struct cl { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret; + bool check_update_clear = true; u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT; + if ((rcg->flags & CLK_RCG2_HW_CONTROLLED) && + !clk_hw_is_enabled(clk_hw_get_parent_by_index(hw, index))) + check_update_clear = false; + ret = regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), CFG_SRC_SEL_MASK, cfg); if (ret) return ret; - return update_config(rcg); + return update_config(rcg, check_update_clear); } /* @@ -312,12 +320,19 @@ static int __clk_rcg2_configure(struct c static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) { int ret; + bool check_update_clear = true; + struct clk_hw *hw = &rcg->clkr.hw; + int index = qcom_find_src_index(hw, rcg->parent_map, f->src); ret = __clk_rcg2_configure(rcg, f); if (ret) return ret; - return update_config(rcg); + if ((rcg->flags & CLK_RCG2_HW_CONTROLLED) && + !clk_hw_is_enabled(clk_hw_get_parent_by_index(hw, index))) + check_update_clear = false; + + return update_config(rcg, check_update_clear); } static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, @@ -448,7 +463,7 @@ static int clk_rcg2_set_duty_cycle(struc if (ret) return ret; - return update_config(rcg); + return update_config(rcg, true); } const struct clk_ops clk_rcg2_ops = { @@ -910,7 +925,7 @@ static int clk_gfx3d_set_rate_and_parent if (ret) return ret; - return update_config(rcg); + return update_config(rcg, true); } static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1022,7 +1037,7 @@ static int clk_rcg2_shared_enable(struct if (ret) return ret; - ret = update_config(rcg); + ret = update_config(rcg, true); if (ret) return ret; @@ -1053,7 +1068,7 @@ static void clk_rcg2_shared_disable(stru regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, rcg->safe_src_index << CFG_SRC_SEL_SHIFT); - update_config(rcg); + update_config(rcg, true); clk_rcg2_clear_force_enable(hw);