diff options
author | Martin Blumenstingl <martin.blumenstingl@googlemail.com> | 2021-10-16 13:50:21 +0300 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2021-10-18 22:59:42 +0300 |
commit | 675c496d0f92b481ebe4abf4fb06eadad7789de6 (patch) | |
tree | 42b481c35a14031ad56e3d4a8e97dd2cd9bfcc4c /drivers/clk | |
parent | 6880fa6c56601bb8ed59df6c30fd390cc5f6dd8f (diff) | |
download | linux-675c496d0f92b481ebe4abf4fb06eadad7789de6.tar.xz |
clk: composite: Also consider .determine_rate for rate + mux composites
Commit 69a00fb3d69706 ("clk: divider: Implement and wire up
.determine_rate by default") switches clk_divider_ops to implement
.determine_rate by default. This breaks composite clocks with multiple
parents because clk-composite.c does not use the special handling for
mux + divider combinations anymore (that was restricted to rate clocks
which only implement .round_rate, but not .determine_rate).
Alex reports:
This breaks lot of clocks for Rockchip which intensively uses
composites, i.e. those clocks will always stay at the initial parent,
which in some cases is the XTAL clock and I strongly guess it is the
same for other platforms, which use composite clocks having more than
one parent (e.g. mediatek, ti ...)
Example (RK3399)
clk_sdio is set (initialized) with XTAL (24 MHz) as parent in u-boot.
It will always stay at this parent, even if the mmc driver sets a rate
of 200 MHz (fails, as the nature of things), which should switch it
to any of its possible parent PLLs defined in
mux_pll_src_cpll_gpll_npll_ppll_upll_24m_p (see clk-rk3399.c) - which
never happens.
Restore the original behavior by changing the priority of the conditions
inside clk-composite.c. Now the special rate + mux case (with rate_ops
having a .round_rate - which is still the case for the default
clk_divider_ops) is preferred over rate_ops which have .determine_rate
defined (and not further considering the mux).
Fixes: 69a00fb3d69706 ("clk: divider: Implement and wire up .determine_rate by default")
Reported-by: Alex Bee <knaerzche@gmail.com>
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Link: https://lore.kernel.org/r/20211016105022.303413-2-martin.blumenstingl@googlemail.com
Tested-by: Alex Bee <knaerzche@gmail.com>
Tested-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/clk-composite.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 0506046a5f4b..510a9965633b 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -58,11 +58,8 @@ static int clk_composite_determine_rate(struct clk_hw *hw, long rate; int i; - if (rate_hw && rate_ops && rate_ops->determine_rate) { - __clk_hw_set_clk(rate_hw, hw); - return rate_ops->determine_rate(rate_hw, req); - } else if (rate_hw && rate_ops && rate_ops->round_rate && - mux_hw && mux_ops && mux_ops->set_parent) { + if (rate_hw && rate_ops && rate_ops->round_rate && + mux_hw && mux_ops && mux_ops->set_parent) { req->best_parent_hw = NULL; if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { @@ -107,6 +104,9 @@ static int clk_composite_determine_rate(struct clk_hw *hw, req->rate = best_rate; return 0; + } else if (rate_hw && rate_ops && rate_ops->determine_rate) { + __clk_hw_set_clk(rate_hw, hw); + return rate_ops->determine_rate(rate_hw, req); } else if (mux_hw && mux_ops && mux_ops->determine_rate) { __clk_hw_set_clk(mux_hw, hw); return mux_ops->determine_rate(mux_hw, req); |