Re: [PATCH] clk: composite: Also consider .determine_rate for rate + mux composites

From: Stephen Boyd
Date: Fri Oct 15 2021 - 17:27:14 EST


Quoting Martin Blumenstingl (2021-10-15 05:05:59)
> 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@xxxxxxxxx>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
> ---
> Re-sending this as inline patch instead of attaching it.
>
> drivers/clk/clk-composite.c | 10 +++++-----
> 1 file 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) {

What do we do if rate_ops and mux_ops only implement determine_rate? It
will fail right? We can't mesh them together in function. We should
probably fail to let the composite clk be registered if that happens.

> 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);
> --
> 2.33.0
>