Skip to content

Commit 703db1f

Browse files
committed
clk: qcom: rcg2: Cache CFG register updates for parked RCGs
As GDSCs are turned on and off some associated clocks are momentarily enabled for house keeping purposes. For this, and similar, purposes the "shared RCGs" will park the RCG on a source clock which is known to be available. When the RCG is parked, a safe clock source will be selected and committed, then the original source would be written back and upon enable the change back to the unparked source would be committed. But starting with SM8350 this fails, as the value in CFG is committed by the GDSC handshake and without a ticking parent the GDSC enablement will time out. This becomes a concrete problem if the runtime supended state of a device includes disabling such rcg's parent clock. As the device attempts to power up the domain again the rcg will fail to enable and hence the GDSC enablement will fail, preventing the device from returning from the suspended state. This can be seen in e.g. the display stack during probe on SM8350. To avoid this problem, the software needs to ensure that the RCG is configured to a active parent clock while it is disabled. This is done by caching the CFG register content while the shared RCG is parked on this safe source. Writes to M, N and D registers are committed as they are requested. New helpers for get_parent() and recalc_rate() are extracted from their previous implementations and __clk_rcg2_configure() is modified to allow it to operate on the cached value. Fixes: 7ef6f11 ("clk: qcom: Configure the RCGs to a safe source as needed") Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Reviewed-by: Stephen Boyd <sboyd@kernel.org> Link: https://lore.kernel.org/r/20220426212136.1543984-1-bjorn.andersson@linaro.org
1 parent d65d005 commit 703db1f

2 files changed

Lines changed: 101 additions & 27 deletions

File tree

drivers/clk/qcom/clk-rcg.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ extern const struct clk_ops clk_dyn_rcg_ops;
140140
* @freq_tbl: frequency table
141141
* @clkr: regmap clock handle
142142
* @cfg_off: defines the cfg register offset from the CMD_RCGR + CFG_REG
143+
* @parked_cfg: cached value of the CFG register for parked RCGs
143144
*/
144145
struct clk_rcg2 {
145146
u32 cmd_rcgr;
@@ -150,6 +151,7 @@ struct clk_rcg2 {
150151
const struct freq_tbl *freq_tbl;
151152
struct clk_regmap clkr;
152153
u8 cfg_off;
154+
u32 parked_cfg;
153155
};
154156

155157
#define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr)

drivers/clk/qcom/clk-rcg2.c

Lines changed: 99 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,11 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw)
7373
return (cmd & CMD_ROOT_OFF) == 0;
7474
}
7575

76-
static u8 clk_rcg2_get_parent(struct clk_hw *hw)
76+
static u8 __clk_rcg2_get_parent(struct clk_hw *hw, u32 cfg)
7777
{
7878
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
7979
int num_parents = clk_hw_get_num_parents(hw);
80-
u32 cfg;
81-
int i, ret;
82-
83-
ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
84-
if (ret)
85-
goto err;
80+
int i;
8681

8782
cfg &= CFG_SRC_SEL_MASK;
8883
cfg >>= CFG_SRC_SEL_SHIFT;
@@ -91,12 +86,27 @@ static u8 clk_rcg2_get_parent(struct clk_hw *hw)
9186
if (cfg == rcg->parent_map[i].cfg)
9287
return i;
9388

94-
err:
9589
pr_debug("%s: Clock %s has invalid parent, using default.\n",
9690
__func__, clk_hw_get_name(hw));
9791
return 0;
9892
}
9993

94+
static u8 clk_rcg2_get_parent(struct clk_hw *hw)
95+
{
96+
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
97+
u32 cfg;
98+
int ret;
99+
100+
ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
101+
if (ret) {
102+
pr_debug("%s: Unable to read CFG register for %s\n",
103+
__func__, clk_hw_get_name(hw));
104+
return 0;
105+
}
106+
107+
return __clk_rcg2_get_parent(hw, cfg);
108+
}
109+
100110
static int update_config(struct clk_rcg2 *rcg)
101111
{
102112
int count, ret;
@@ -163,12 +173,10 @@ calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
163173
}
164174

165175
static unsigned long
166-
clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
176+
__clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, u32 cfg)
167177
{
168178
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
169-
u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
170-
171-
regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
179+
u32 hid_div, m = 0, n = 0, mode = 0, mask;
172180

173181
if (rcg->mnd_width) {
174182
mask = BIT(rcg->mnd_width) - 1;
@@ -189,6 +197,17 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
189197
return calc_rate(parent_rate, m, n, mode, hid_div);
190198
}
191199

200+
static unsigned long
201+
clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
202+
{
203+
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
204+
u32 cfg;
205+
206+
regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
207+
208+
return __clk_rcg2_recalc_rate(hw, parent_rate, cfg);
209+
}
210+
192211
static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
193212
struct clk_rate_request *req,
194213
enum freq_policy policy)
@@ -262,7 +281,8 @@ static int clk_rcg2_determine_floor_rate(struct clk_hw *hw,
262281
return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, FLOOR);
263282
}
264283

265-
static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
284+
static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f,
285+
u32 *_cfg)
266286
{
267287
u32 cfg, mask, d_val, not2d_val, n_minus_m;
268288
struct clk_hw *hw = &rcg->clkr.hw;
@@ -304,15 +324,27 @@ static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
304324
cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
305325
if (rcg->mnd_width && f->n && (f->m != f->n))
306326
cfg |= CFG_MODE_DUAL_EDGE;
307-
return regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg),
308-
mask, cfg);
327+
328+
*_cfg &= ~mask;
329+
*_cfg |= cfg;
330+
331+
return 0;
309332
}
310333

311334
static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
312335
{
336+
u32 cfg;
313337
int ret;
314338

315-
ret = __clk_rcg2_configure(rcg, f);
339+
ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
340+
if (ret)
341+
return ret;
342+
343+
ret = __clk_rcg2_configure(rcg, f, &cfg);
344+
if (ret)
345+
return ret;
346+
347+
ret = regmap_write(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), cfg);
316348
if (ret)
317349
return ret;
318350

@@ -979,11 +1011,12 @@ static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
9791011
return -EINVAL;
9801012

9811013
/*
982-
* In case clock is disabled, update the CFG, M, N and D registers
983-
* and don't hit the update bit of CMD register.
1014+
* In case clock is disabled, update the M, N and D registers, cache
1015+
* the CFG value in parked_cfg and don't hit the update bit of CMD
1016+
* register.
9841017
*/
985-
if (!__clk_is_enabled(hw->clk))
986-
return __clk_rcg2_configure(rcg, f);
1018+
if (!clk_hw_is_enabled(hw))
1019+
return __clk_rcg2_configure(rcg, f, &rcg->parked_cfg);
9871020

9881021
return clk_rcg2_shared_force_enable_clear(hw, f);
9891022
}
@@ -1007,6 +1040,11 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw)
10071040
if (ret)
10081041
return ret;
10091042

1043+
/* Write back the stored configuration corresponding to current rate */
1044+
ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, rcg->parked_cfg);
1045+
if (ret)
1046+
return ret;
1047+
10101048
ret = update_config(rcg);
10111049
if (ret)
10121050
return ret;
@@ -1017,13 +1055,12 @@ static int clk_rcg2_shared_enable(struct clk_hw *hw)
10171055
static void clk_rcg2_shared_disable(struct clk_hw *hw)
10181056
{
10191057
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1020-
u32 cfg;
10211058

10221059
/*
10231060
* Store current configuration as switching to safe source would clear
10241061
* the SRC and DIV of CFG register
10251062
*/
1026-
regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
1063+
regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &rcg->parked_cfg);
10271064

10281065
/*
10291066
* Park the RCG at a safe configuration - sourced off of safe source.
@@ -1041,17 +1078,52 @@ static void clk_rcg2_shared_disable(struct clk_hw *hw)
10411078
update_config(rcg);
10421079

10431080
clk_rcg2_clear_force_enable(hw);
1081+
}
10441082

1045-
/* Write back the stored configuration corresponding to current rate */
1046-
regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
1083+
static u8 clk_rcg2_shared_get_parent(struct clk_hw *hw)
1084+
{
1085+
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1086+
1087+
/* If the shared rcg is parked use the cached cfg instead */
1088+
if (!clk_hw_is_enabled(hw))
1089+
return __clk_rcg2_get_parent(hw, rcg->parked_cfg);
1090+
1091+
return clk_rcg2_get_parent(hw);
1092+
}
1093+
1094+
static int clk_rcg2_shared_set_parent(struct clk_hw *hw, u8 index)
1095+
{
1096+
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1097+
1098+
/* If the shared rcg is parked only update the cached cfg */
1099+
if (!clk_hw_is_enabled(hw)) {
1100+
rcg->parked_cfg &= ~CFG_SRC_SEL_MASK;
1101+
rcg->parked_cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
1102+
1103+
return 0;
1104+
}
1105+
1106+
return clk_rcg2_set_parent(hw, index);
1107+
}
1108+
1109+
static unsigned long
1110+
clk_rcg2_shared_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
1111+
{
1112+
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1113+
1114+
/* If the shared rcg is parked use the cached cfg instead */
1115+
if (!clk_hw_is_enabled(hw))
1116+
return __clk_rcg2_recalc_rate(hw, parent_rate, rcg->parked_cfg);
1117+
1118+
return clk_rcg2_recalc_rate(hw, parent_rate);
10471119
}
10481120

10491121
const struct clk_ops clk_rcg2_shared_ops = {
10501122
.enable = clk_rcg2_shared_enable,
10511123
.disable = clk_rcg2_shared_disable,
1052-
.get_parent = clk_rcg2_get_parent,
1053-
.set_parent = clk_rcg2_set_parent,
1054-
.recalc_rate = clk_rcg2_recalc_rate,
1124+
.get_parent = clk_rcg2_shared_get_parent,
1125+
.set_parent = clk_rcg2_shared_set_parent,
1126+
.recalc_rate = clk_rcg2_shared_recalc_rate,
10551127
.determine_rate = clk_rcg2_determine_rate,
10561128
.set_rate = clk_rcg2_shared_set_rate,
10571129
.set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,

0 commit comments

Comments
 (0)