diff options
author | Jerome Brunet <jbrunet@baylibre.com> | 2018-06-19 15:40:51 +0200 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2018-06-19 10:03:38 -0700 |
commit | 9461f7b33d11cbbf5ce79c3c03d0da9d42dfce92 (patch) | |
tree | 5a595804ecd64012231e6304739ff7205ce80f27 /drivers | |
parent | ce397d215ccd07b8ae3f71db689aedb85d56ab40 (diff) | |
download | talos-obmc-linux-9461f7b33d11cbbf5ce79c3c03d0da9d42dfce92.tar.gz talos-obmc-linux-9461f7b33d11cbbf5ce79c3c03d0da9d42dfce92.zip |
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
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 9760b526ca31..97c09243fb21 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -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) |