From 9c4534f1cf311ca7b9b2de8c9242bfe42bc7eaa2 Mon Sep 17 00:00:00 2001 From: David Collins Date: Mon, 18 Mar 2019 14:09:10 -0700 Subject: [PATCH] clk: qcom: clk-rcg2: correct set rate handling for FORCE_ENABLE_RCG Currently, if clk_set_rate() is called on a disabled clock that has flags = FORCE_ENABLE_RCG, the rate is neither physically set nor properly cached in software. This means that when the clock is later enabled, its rate will not be what was previously requested. Change the handling of FORCE_ENABLE_RCG so that all clk_set_rate() calls are respected regardless of a clock's enable state. In doing so, ensure that FORCE_ENABLE_RCG and enable_safe_config are supported both individually and together. Implement the following behavior: enable_safe_config == true: enable - configure the RCG according to the cached current_freq disable - configure the RCG for CXO (safe) source set_rate - (if prepared) configure the RCG for the requested rate (if not prepared) cache the rate in current_freq flags | FORCE_ENABLE_RCG: enable - set ROOT_EN=1 to force the RCG to be enabled disable - set ROOT_EN=0 set_rate - configure the RCG for the requested rate; if disabled, then set ROOT_EN=1 before the configuration is changed and ROOT_EN=0 after enable_safe_config && (flags | FORCE_ENABLE_RCG): enable - set ROOT_EN=1 and configure the RCG according to the cached current_freq disable - configure the RCG for CXO source and set ROOT_EN=0 set_rate - (if prepared) configure the RCG for the requested rate (if not prepared) cache the rate in current_freq Change-Id: Ib7442e4a4b572ae7c567929044410e09a9886c76 Signed-off-by: David Collins --- drivers/clk/qcom/clk-rcg2.c | 62 +++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 5106d66acf9e..f42946b5f21e 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -175,6 +175,16 @@ static int clk_rcg2_clear_force_enable(struct clk_hw *hw) CMD_ROOT_EN, 0); } +static bool clk_rcg2_is_force_enabled(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + u32 val = 0; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &val); + + return val & CMD_ROOT_EN; +} + static int prepare_enable_rcg_srcs(struct clk *curr, struct clk *new) { int rc = 0; @@ -247,6 +257,7 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f_curr; u32 cfg, src, hid_div, m = 0, n = 0, mode = 0, mask; + unsigned long rrate = 0; regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); src = cfg; @@ -284,7 +295,16 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) hid_div &= mask; } - return calc_rate(parent_rate, m, n, mode, hid_div); + rrate = calc_rate(parent_rate, m, n, mode, hid_div); + + /* + * Check to cover the case when the RCG has been initialized to a + * non-CXO frequency before the clock driver has taken control of it. + */ + if (rcg->enable_safe_config && !rcg->current_freq) + rcg->current_freq = rrate; + + return rrate; } static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, @@ -434,6 +454,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, const struct freq_tbl *f, *f_curr; int ret, curr_src_index, new_src_index; struct clk_hw *curr_src = NULL, *new_src = NULL; + bool force_enabled = false; switch (policy) { case FLOOR: @@ -485,7 +506,11 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, /* The RCG could currently be disabled. Enable its parents. */ ret = prepare_enable_rcg_srcs(curr_src->clk, new_src->clk); - clk_rcg2_set_force_enable(hw); + if (ret) + return ret; + force_enabled = clk_rcg2_is_force_enabled(hw); + if (!force_enabled) + clk_rcg2_set_force_enable(hw); } ret = clk_rcg2_configure(rcg, f); @@ -493,7 +518,8 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, return ret; if (rcg->flags & FORCE_ENABLE_RCG) { - clk_rcg2_clear_force_enable(hw); + if (!force_enabled) + clk_rcg2_clear_force_enable(hw); disable_unprepare_rcg_srcs(curr_src->clk, new_src->clk); } @@ -608,11 +634,10 @@ static int clk_rcg2_enable(struct clk_hw *hw) struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long rate; const struct freq_tbl *f; + int ret; - if (rcg->flags & FORCE_ENABLE_RCG) { + if (rcg->flags & FORCE_ENABLE_RCG) clk_rcg2_set_force_enable(hw); - return 0; - } if (!rcg->enable_safe_config) return 0; @@ -639,24 +664,27 @@ static int clk_rcg2_enable(struct clk_hw *hw) if (rate == cxo_f.freq) f = &cxo_f; - clk_rcg2_set_force_enable(hw); - clk_rcg2_configure(rcg, f); - clk_rcg2_clear_force_enable(hw); + if (!(rcg->flags & FORCE_ENABLE_RCG)) + clk_rcg2_set_force_enable(hw); - return 0; + ret = clk_rcg2_configure(rcg, f); + + if (!(rcg->flags & FORCE_ENABLE_RCG)) + clk_rcg2_clear_force_enable(hw); + + return ret; } static void clk_rcg2_disable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int ret; - if (rcg->flags & FORCE_ENABLE_RCG) { - clk_rcg2_clear_force_enable(hw); + if (!rcg->enable_safe_config) { + if (rcg->flags & FORCE_ENABLE_RCG) + clk_rcg2_clear_force_enable(hw); return; } - - if (!rcg->enable_safe_config) - return; /* * Park the RCG at a safe configuration - sourced off the CXO. This is * needed for 2 reasons: In the case of RCGs sourcing PSCBCs, due to a @@ -674,7 +702,9 @@ static void clk_rcg2_disable(struct clk_hw *hw) * online. Therefore, the RCG can safely be switched. */ clk_rcg2_set_force_enable(hw); - clk_rcg2_configure(rcg, &cxo_f); + ret = clk_rcg2_configure(rcg, &cxo_f); + if (ret) + pr_err("%s: CXO configuration failed\n", clk_hw_get_name(hw)); clk_rcg2_clear_force_enable(hw); }