Loading drivers/clk/qcom/clk-alpha-pll.c +2 −2 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); /* LUCID PLL specific settings and offsets */ #define LUCID_PLL_CAL_VAL 0x44 #define LUCID_PCAL_DONE BIT(26) #define LUCID_PCAL_DONE BIT(27) /* ZONDA PLL specific offsets */ #define ZONDA_PLL_OUT_MASK 0xF Loading Loading @@ -1614,7 +1614,7 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw) int ret; /* Return early if calibration is not needed. */ regmap_read(pll->clkr.regmap, PLL_STATUS(pll), ®val); regmap_read(pll->clkr.regmap, PLL_MODE(pll), ®val); if (regval & LUCID_PCAL_DONE) return 0; Loading drivers/clk/qcom/clk-rcg.h +6 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved. */ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_RCG_H__ #define __QCOM_CLK_RCG_H__ Loading Loading @@ -137,6 +137,8 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @safe_src_index: safe src index value * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @current_freq: last cached frequency when using branches with shared RCGs * @enable_safe_config: When set, the RCG is parked at CXO when it's disabled * @clkr: regmap clock handle * @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG */ Loading @@ -147,6 +149,8 @@ struct clk_rcg2 { u8 safe_src_index; const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; unsigned long current_freq; bool enable_safe_config; struct clk_regmap clkr; u8 cfg_off; }; Loading drivers/clk/qcom/clk-rcg2.c +130 −34 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> Loading @@ -8,6 +8,7 @@ #include <linux/err.h> #include <linux/bug.h> #include <linux/export.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/regmap.h> Loading Loading @@ -59,6 +60,14 @@ enum freq_policy { CEIL, }; static struct freq_tbl cxo_f = { .freq = 19200000, .src = 0, .pre_div = 1, .m = 0, .n = 0, }; static int clk_rcg2_is_enabled(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); Loading Loading @@ -136,6 +145,35 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) return update_config(rcg); } static int clk_rcg2_set_force_enable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret = 0, count = 500; ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, CMD_ROOT_EN); if (ret) return ret; for (; count > 0; count--) { if (clk_rcg2_is_enabled(hw)) return ret; /* Delay for 1usec and retry polling the status bit */ udelay(1); } WARN(1, "%s: rcg didn't turn on.", clk_hw_get_name(hw)); return ret; } static int clk_rcg2_clear_force_enable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, 0); } /* * Calculate m/n:d rate * Loading Loading @@ -167,6 +205,12 @@ clk_rcg2_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; if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { 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) { Loading Loading @@ -309,6 +353,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f; int ret; switch (policy) { case FLOOR: Loading @@ -324,7 +369,22 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, if (!f) return -EINVAL; return clk_rcg2_configure(rcg, f); /* * Return if the RCG is currently disabled. This configuration update * will happen as part of the RCG enable sequence. */ if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { rcg->current_freq = rate; return 0; } ret = clk_rcg2_configure(rcg, f); if (ret) return ret; /* Update current frequency with the requested frequency. */ rcg->current_freq = rate; return ret; } static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, Loading @@ -351,8 +411,75 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw, return __clk_rcg2_set_rate(hw, rate, FLOOR); } 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; if (!rcg->enable_safe_config) return 0; /* * Switch from CXO to the stashed mux selection. Force enable and * disable the RCG while configuring it to safeguard against any update * signal coming from the downstream clock. The current parent has * already been prepared and enabled at this point, and the CXO source * is always on while APPS is online. Therefore, the RCG can safely be * switched. */ rate = rcg->current_freq; f = qcom_find_freq(rcg->freq_tbl, rate); if (!f) return -EINVAL; /* * If CXO is not listed as a supported frequency in the frequency * table, the above API would return the lowest supported frequency * instead. This will lead to incorrect configuration of the RCG. * Check if the RCG rate is CXO and configure it accordingly. */ 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); return 0; } static void clk_rcg2_disable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); 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 * default HW behavior, the RCG will turn on when its corresponding * GDSC is enabled. We might also have cases when the RCG might be left * enabled without the overlying SW knowing about it. This results from * hard to track cases of downstream clocks being left enabled. In both * these cases, scaling the RCG will fail since it's enabled but with * its sources cut off. * * Save mux select and switch to 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 APPS 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_ops = { .is_enabled = clk_rcg2_is_enabled, .enable = clk_rcg2_enable, .disable = clk_rcg2_disable, .get_parent = clk_rcg2_get_parent, .set_parent = clk_rcg2_set_parent, .recalc_rate = clk_rcg2_recalc_rate, Loading Loading @@ -805,37 +932,6 @@ const struct clk_ops clk_gfx3d_ops = { }; EXPORT_SYMBOL_GPL(clk_gfx3d_ops); 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); int ret, count; ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, CMD_ROOT_EN); if (ret) return ret; /* wait for RCG to turn ON */ for (count = 500; count > 0; count--) { if (clk_rcg2_is_enabled(hw)) return 0; udelay(1); } 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); return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, 0); } static int clk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f) { Loading Loading
drivers/clk/qcom/clk-alpha-pll.c +2 −2 Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); /* LUCID PLL specific settings and offsets */ #define LUCID_PLL_CAL_VAL 0x44 #define LUCID_PCAL_DONE BIT(26) #define LUCID_PCAL_DONE BIT(27) /* ZONDA PLL specific offsets */ #define ZONDA_PLL_OUT_MASK 0xF Loading Loading @@ -1614,7 +1614,7 @@ static int alpha_pll_lucid_prepare(struct clk_hw *hw) int ret; /* Return early if calibration is not needed. */ regmap_read(pll->clkr.regmap, PLL_STATUS(pll), ®val); regmap_read(pll->clkr.regmap, PLL_MODE(pll), ®val); if (regval & LUCID_PCAL_DONE) return 0; Loading
drivers/clk/qcom/clk-rcg.h +6 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved. */ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_RCG_H__ #define __QCOM_CLK_RCG_H__ Loading Loading @@ -137,6 +137,8 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @safe_src_index: safe src index value * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table * @current_freq: last cached frequency when using branches with shared RCGs * @enable_safe_config: When set, the RCG is parked at CXO when it's disabled * @clkr: regmap clock handle * @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG */ Loading @@ -147,6 +149,8 @@ struct clk_rcg2 { u8 safe_src_index; const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; unsigned long current_freq; bool enable_safe_config; struct clk_regmap clkr; u8 cfg_off; }; Loading
drivers/clk/qcom/clk-rcg2.c +130 −34 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved. */ #include <linux/kernel.h> Loading @@ -8,6 +8,7 @@ #include <linux/err.h> #include <linux/bug.h> #include <linux/export.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/regmap.h> Loading Loading @@ -59,6 +60,14 @@ enum freq_policy { CEIL, }; static struct freq_tbl cxo_f = { .freq = 19200000, .src = 0, .pre_div = 1, .m = 0, .n = 0, }; static int clk_rcg2_is_enabled(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); Loading Loading @@ -136,6 +145,35 @@ static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) return update_config(rcg); } static int clk_rcg2_set_force_enable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); int ret = 0, count = 500; ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, CMD_ROOT_EN); if (ret) return ret; for (; count > 0; count--) { if (clk_rcg2_is_enabled(hw)) return ret; /* Delay for 1usec and retry polling the status bit */ udelay(1); } WARN(1, "%s: rcg didn't turn on.", clk_hw_get_name(hw)); return ret; } static int clk_rcg2_clear_force_enable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, 0); } /* * Calculate m/n:d rate * Loading Loading @@ -167,6 +205,12 @@ clk_rcg2_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; if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { 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) { Loading Loading @@ -309,6 +353,7 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_rcg2 *rcg = to_clk_rcg2(hw); const struct freq_tbl *f; int ret; switch (policy) { case FLOOR: Loading @@ -324,7 +369,22 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, if (!f) return -EINVAL; return clk_rcg2_configure(rcg, f); /* * Return if the RCG is currently disabled. This configuration update * will happen as part of the RCG enable sequence. */ if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { rcg->current_freq = rate; return 0; } ret = clk_rcg2_configure(rcg, f); if (ret) return ret; /* Update current frequency with the requested frequency. */ rcg->current_freq = rate; return ret; } static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, Loading @@ -351,8 +411,75 @@ static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw, return __clk_rcg2_set_rate(hw, rate, FLOOR); } 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; if (!rcg->enable_safe_config) return 0; /* * Switch from CXO to the stashed mux selection. Force enable and * disable the RCG while configuring it to safeguard against any update * signal coming from the downstream clock. The current parent has * already been prepared and enabled at this point, and the CXO source * is always on while APPS is online. Therefore, the RCG can safely be * switched. */ rate = rcg->current_freq; f = qcom_find_freq(rcg->freq_tbl, rate); if (!f) return -EINVAL; /* * If CXO is not listed as a supported frequency in the frequency * table, the above API would return the lowest supported frequency * instead. This will lead to incorrect configuration of the RCG. * Check if the RCG rate is CXO and configure it accordingly. */ 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); return 0; } static void clk_rcg2_disable(struct clk_hw *hw) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); 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 * default HW behavior, the RCG will turn on when its corresponding * GDSC is enabled. We might also have cases when the RCG might be left * enabled without the overlying SW knowing about it. This results from * hard to track cases of downstream clocks being left enabled. In both * these cases, scaling the RCG will fail since it's enabled but with * its sources cut off. * * Save mux select and switch to 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 APPS 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_ops = { .is_enabled = clk_rcg2_is_enabled, .enable = clk_rcg2_enable, .disable = clk_rcg2_disable, .get_parent = clk_rcg2_get_parent, .set_parent = clk_rcg2_set_parent, .recalc_rate = clk_rcg2_recalc_rate, Loading Loading @@ -805,37 +932,6 @@ const struct clk_ops clk_gfx3d_ops = { }; EXPORT_SYMBOL_GPL(clk_gfx3d_ops); 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); int ret, count; ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, CMD_ROOT_EN); if (ret) return ret; /* wait for RCG to turn ON */ for (count = 500; count > 0; count--) { if (clk_rcg2_is_enabled(hw)) return 0; udelay(1); } 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); return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, CMD_ROOT_EN, 0); } static int clk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f) { Loading