mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
clk: fix CLK_SET_RATE_GATE with clock rate protection
CLK_SET_RATE_GATE should prevent any operation which may result in a rate change or glitch while the clock is prepared/enabled. IOW, the following sequence is not allowed anymore with CLK_SET_RATE_GATE: * clk_get() * clk_prepare_enable() * clk_get_rate() * clk_set_rate() At the moment this is enforced on the leaf clock of the operation, not along the tree. This problematic because, if a PLL has the CLK_RATE_GATE, it won't be enforced if the clk_set_rate() is called on its child clocks. Using clock rate protection, we can now enforce CLK_SET_RATE_GATE along the clock tree Acked-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Quentin Schulz <quentin.schulz@free-electrons.com> Tested-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Signed-off-by: Michael Turquette <mturquette@baylibre.com> Link: lkml.kernel.org/r/20180619134051.16726-3-jbrunet@baylibre.com
This commit is contained in:
parent
ce397d215c
commit
9461f7b33d
1 changed files with 13 additions and 3 deletions
|
@ -691,6 +691,9 @@ static void clk_core_unprepare(struct clk_core *core)
|
|||
"Unpreparing critical %s\n", core->name))
|
||||
return;
|
||||
|
||||
if (core->flags & CLK_SET_RATE_GATE)
|
||||
clk_core_rate_unprotect(core);
|
||||
|
||||
if (--core->prepare_count > 0)
|
||||
return;
|
||||
|
||||
|
@ -765,6 +768,16 @@ static int clk_core_prepare(struct clk_core *core)
|
|||
|
||||
core->prepare_count++;
|
||||
|
||||
/*
|
||||
* CLK_SET_RATE_GATE is a special case of clock protection
|
||||
* Instead of a consumer claiming exclusive rate control, it is
|
||||
* actually the provider which prevents any consumer from making any
|
||||
* operation which could result in a rate change or rate glitch while
|
||||
* the clock is prepared.
|
||||
*/
|
||||
if (core->flags & CLK_SET_RATE_GATE)
|
||||
clk_core_rate_protect(core);
|
||||
|
||||
return 0;
|
||||
unprepare:
|
||||
clk_core_unprepare(core->parent);
|
||||
|
@ -1888,9 +1901,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
|||
if (clk_core_rate_is_protected(core))
|
||||
return -EBUSY;
|
||||
|
||||
if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
|
||||
return -EBUSY;
|
||||
|
||||
/* calculate new rates and get the topmost changed clock */
|
||||
top = clk_calc_new_rates(core, req_rate);
|
||||
if (!top)
|
||||
|
|
Loading…
Reference in a new issue