From 0311d36738bb193c7c85e169b0d9dac7314468a3 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 27 Apr 2018 11:01:20 +0530 Subject: [PATCH 1/2] clk: qcom: Retrieve pre_div from freq_tbl for shared RCG There could be cases where a simultaneous clk_disable and clk_set_rate on the same rcg could result in a wrong recalc rate. So for shared rcgs get the pre_div value based on the current frequency from the frequency table. Change-Id: Ia5730e43965b2d0ba19da05fca47825514f98865 Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rcg2.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index d96dd1884b9c..2482b2f237bc 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -245,9 +245,11 @@ static unsigned long 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, hid_div, m = 0, n = 0, mode = 0, mask; - if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { + if (rcg->enable_safe_config && (!clk_hw_is_prepared(hw) + || !clk_hw_is_enabled(hw))) { if (!rcg->current_freq) rcg->current_freq = cxo_f.freq; return rcg->current_freq; @@ -267,9 +269,17 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) mode >>= CFG_MODE_SHIFT; } - mask = BIT(rcg->hid_width) - 1; - hid_div = cfg >> CFG_SRC_DIV_SHIFT; - hid_div &= mask; + if (rcg->enable_safe_config) { + f_curr = qcom_find_freq(rcg->freq_tbl, rcg->current_freq); + if (!f_curr) + return -EINVAL; + + hid_div = f_curr->pre_div; + } else { + mask = BIT(rcg->hid_width) - 1; + hid_div = cfg >> CFG_SRC_DIV_SHIFT; + hid_div &= mask; + } return calc_rate(parent_rate, m, n, mode, hid_div); } From 90823f3cf3aa8c03a24555da30844a818de73e48 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Tue, 30 Oct 2018 11:44:15 +0530 Subject: [PATCH 2/2] clk: qcom: clk-rcg2: Read RCG source before calculating clk rate If the clock rate is set previously to hlos and enable safe config is true. In that case we need to check the rcg source to make sure recalc will return correct rate. Rate calculation is done based on selected source rather than 19.2 MHZ. Also, we are setting correct src value for XO based on the parent map of a particular clock. Change-Id: Id6d2923136a0848d55cff37fb5ef2e3b092af27a Signed-off-by: Shefali Jain --- drivers/clk/qcom/clk-rcg2.c | 41 ++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 2482b2f237bc..2512f144c10b 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -69,6 +69,16 @@ static struct freq_tbl cxo_f = { .n = 0, }; +static void update_src_map(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + int i, num_parents = clk_hw_get_num_parents(hw); + + for (i = 0; i < num_parents; i++) + if (!rcg->parent_map[i].cfg) + cxo_f.src = rcg->parent_map[i].src; +} + static int clk_rcg2_is_enabled(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); @@ -246,17 +256,20 @@ 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, hid_div, m = 0, n = 0, mode = 0, mask; + u32 cfg, src, hid_div, m = 0, n = 0, mode = 0, mask; + + regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); + src = cfg; + src &= CFG_SRC_SEL_MASK; + src >>= CFG_SRC_SEL_SHIFT; if (rcg->enable_safe_config && (!clk_hw_is_prepared(hw) - || !clk_hw_is_enabled(hw))) { + || !clk_hw_is_enabled(hw)) && !src) { if (!rcg->current_freq) rcg->current_freq = cxo_f.freq; return rcg->current_freq; } - regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg); - if (rcg->mnd_width) { mask = BIT(rcg->mnd_width) - 1; regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m); @@ -269,7 +282,7 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) mode >>= CFG_MODE_SHIFT; } - if (rcg->enable_safe_config) { + if (rcg->enable_safe_config && !src) { f_curr = qcom_find_freq(rcg->freq_tbl, rcg->current_freq); if (!f_curr) return -EINVAL; @@ -440,6 +453,12 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, if (!f) return -EINVAL; + /* + * Set the correct source value for CXO as per + * as per defined parent map. + */ + update_src_map(hw); + /* * Return if the RCG is currently disabled. This configuration update * will happen as part of the RCG enable sequence. @@ -523,6 +542,12 @@ static int clk_rcg2_enable(struct clk_hw *hw) unsigned long rate; const struct freq_tbl *f; + /* + * Set the correct source value for CXO as per + * as per defined parent map. + */ + update_src_map(hw); + if (rcg->flags & FORCE_ENABLE_RCG) { clk_rcg2_set_force_enable(hw); return 0; @@ -564,6 +589,12 @@ static void clk_rcg2_disable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); + /* + * Set the correct source value for CXO as per + * as per defined parent map. + */ + update_src_map(hw); + if (rcg->flags & FORCE_ENABLE_RCG) { clk_rcg2_clear_force_enable(hw); return;