Skip to content

Commit c9d24fe

Browse files
andredkrzk
authored andcommitted
clk: samsung: fix sysreg save/restore when PM is enabled for CMU
Currently, sysreg registers of a CMU that has PM and automatic clock gating enabled are not saved / restored during runtime PM (RPM) or s2idle. During normal suspend, they are accessed too late, after the CMU (and potentially power domain) have been shut down, causing an SError. The reason is that these registers are registered to be saved/restored via a syscore suspend handler which doesn't run during RPM or s2idle. During normal suspend, this handler runs after the CMU has been shut down. This registration happens as part of samsung_clk_extended_sleep_init() via samsung_en_dyn_root_clk_gating(). When PM is enabled for a CMU, registers must be saved/restored via exynos_arm64_cmu_suspend() / exynos_arm64_cmu_resume() respectively instead. These use their own data structures and are unrelated to anything that samsung_clk_extended_sleep_init() does. Calling it unconditionally from samsung_en_dyn_root_clk_gating() therefore isn't useful. Update the code to prepare sysreg save / restore in a similar way to how it handles other clock registers in the PM case already. exynos_arm64_cmu_suspend() / exynos_arm64_cmu_resume() already handle sysreg save/restore, just the setup was incorrect. Fixes: 298fac4 ("clk: samsung: Implement automatic clock gating mode for CMUs") Signed-off-by: André Draszik <andre.draszik@linaro.org> Reviewed-by: Peter Griffin <peter.griffin@linaro.org> Link: https://patch.msgid.link/20260109-clk-samsung-autoclk-updates-v1-2-2394dcf242a9@linaro.org Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
1 parent aafaa4d commit c9d24fe

3 files changed

Lines changed: 41 additions & 13 deletions

File tree

drivers/clk/samsung/clk-exynos-arm64.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,40 +174,60 @@ static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
174174
const struct samsung_cmu_info *cmu)
175175
{
176176
struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
177-
int i;
177+
int i, ret;
178178

179179
data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs,
180180
cmu->nr_clk_regs);
181181
if (!data->clk_save)
182182
return -ENOMEM;
183183

184184
data->nr_clk_save = cmu->nr_clk_regs;
185+
186+
if (cmu->nr_sysreg_clk_regs) {
187+
data->clk_sysreg_save =
188+
samsung_clk_alloc_reg_dump(cmu->sysreg_clk_regs,
189+
cmu->nr_sysreg_clk_regs);
190+
if (!data->clk_sysreg_save) {
191+
ret = -ENOMEM;
192+
goto free_clk_save;
193+
}
194+
195+
data->nr_clk_sysreg = cmu->nr_sysreg_clk_regs;
196+
}
197+
185198
data->clk_suspend = cmu->suspend_regs;
186199
data->nr_clk_suspend = cmu->nr_suspend_regs;
200+
187201
data->nr_pclks = of_clk_get_parent_count(dev->of_node);
188202
if (!data->nr_pclks)
189203
return 0;
190204

191205
data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks,
192206
GFP_KERNEL);
193207
if (!data->pclks) {
194-
kfree(data->clk_save);
195-
return -ENOMEM;
208+
ret = -ENOMEM;
209+
goto free_sysreg_save;
196210
}
197211

198212
for (i = 0; i < data->nr_pclks; i++) {
199213
struct clk *clk = of_clk_get(dev->of_node, i);
200214

201215
if (IS_ERR(clk)) {
202-
kfree(data->clk_save);
203216
while (--i >= 0)
204217
clk_put(data->pclks[i]);
205-
return PTR_ERR(clk);
218+
ret = PTR_ERR(clk);
219+
goto free_sysreg_save;
206220
}
207221
data->pclks[i] = clk;
208222
}
209223

210224
return 0;
225+
226+
free_sysreg_save:
227+
kfree(data->clk_sysreg_save);
228+
free_clk_save:
229+
kfree(data->clk_save);
230+
return ret;
211231
}
212232

213233
/**
@@ -305,7 +325,7 @@ int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
305325
samsung_cmu_register_clocks(data->ctx, cmu, np);
306326
samsung_clk_of_add_provider(dev->of_node, data->ctx);
307327
/* sysreg DT nodes reference a clock in this CMU */
308-
samsung_en_dyn_root_clk_gating(np, data->ctx, cmu);
328+
samsung_en_dyn_root_clk_gating(np, data->ctx, cmu, true);
309329
pm_runtime_put_sync(dev);
310330

311331
return 0;

drivers/clk/samsung/clk.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,8 @@ void __init samsung_cmu_register_clocks(struct samsung_clk_provider *ctx,
496496
/* Enable Dynamic Root Clock Gating (DRCG) of bus components */
497497
void samsung_en_dyn_root_clk_gating(struct device_node *np,
498498
struct samsung_clk_provider *ctx,
499-
const struct samsung_cmu_info *cmu)
499+
const struct samsung_cmu_info *cmu,
500+
bool cmu_has_pm)
500501
{
501502
if (!ctx->auto_clock_gate)
502503
return;
@@ -513,10 +514,16 @@ void samsung_en_dyn_root_clk_gating(struct device_node *np,
513514
regmap_write_bits(ctx->sysreg, ctx->memclk_offset,
514515
MEMCLK_EN, 0x0);
515516

516-
samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
517-
cmu->sysreg_clk_regs,
518-
cmu->nr_sysreg_clk_regs,
519-
NULL, 0);
517+
if (!cmu_has_pm)
518+
/*
519+
* When a CMU has PM support, clocks are saved/restored
520+
* via its PM handlers, so only register them with the
521+
* syscore suspend / resume paths if PM is not in use.
522+
*/
523+
samsung_clk_extended_sleep_init(NULL, ctx->sysreg,
524+
cmu->sysreg_clk_regs,
525+
cmu->nr_sysreg_clk_regs,
526+
NULL, 0);
520527
}
521528
}
522529

@@ -548,7 +555,7 @@ struct samsung_clk_provider * __init samsung_cmu_register_one(
548555
samsung_clk_of_add_provider(np, ctx);
549556

550557
/* sysreg DT nodes reference a clock in this CMU */
551-
samsung_en_dyn_root_clk_gating(np, ctx, cmu);
558+
samsung_en_dyn_root_clk_gating(np, ctx, cmu, false);
552559

553560
return ctx;
554561
}

drivers/clk/samsung/clk.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,8 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
476476

477477
void samsung_en_dyn_root_clk_gating(struct device_node *np,
478478
struct samsung_clk_provider *ctx,
479-
const struct samsung_cmu_info *cmu);
479+
const struct samsung_cmu_info *cmu,
480+
bool cmu_has_pm);
480481

481482
struct clk_hw *samsung_register_auto_gate(struct device *dev,
482483
struct device_node *np, const char *name,

0 commit comments

Comments
 (0)