[PATCH 1/4] clk: st: STiH410: Fix pdiv and fdiv divisor when setting rate

Mike Turquette mturquette at linaro.org
Tue Jan 20 09:37:55 PST 2015


Quoting Peter Griffin (2015-01-20 07:32:41)
> Debugging eMMC on upstream kernels it has been noticed that when the
> targetpack configures MMC0 clock to 200Mhz (required to switch to
> HS200) then everything works OK. However if the kernel sets the
> clock rate using clk_set_rate, then the eMMC card initialisation
> fails with timeouts. Lower clock speeds (the default being 50Mhz)
> work ok, but they we fail to get good eMMC transfer rates.
> 
> Looking through the vendor kernel clock driver reveals Giuseppe
> had already fixed this issue, but the patch hasn't made its way
> upstream.
> 
> The issue is fixed by changing the logic to manage the pdiv and
> fdiv divisors used for setting the rate inside the flexgen driver code.
> 
> Pdiv is mainly targeted for low freq results, while fdiv should be
> used for divs =< 64. The other way can lead to 'duty cycle'
> issues.
> 
> I have changed the original patch to keep the original behaviour
> in cases where the div is >64 which matches the original comment
> and patch description more closely. Although no clocks appear to hit
> this case currently when booting an upstream kernel.
> 
> Signed-off-by: Peter Griffin <peter.griffin at linaro.org>
> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro at st.com>

Applied to clk-next.

Regards,
Mike

> ---
>  drivers/clk/st/clk-flexgen.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c
> index 2282cef..3a484b3 100644
> --- a/drivers/clk/st/clk-flexgen.c
> +++ b/drivers/clk/st/clk-flexgen.c
> @@ -138,16 +138,27 @@ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
>         struct flexgen *flexgen = to_flexgen(hw);
>         struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
>         struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
> -       unsigned long primary_div = 0;
> +       unsigned long div = 0;
>         int ret = 0;
>  
>         pdiv_hw->clk = hw->clk;
>         fdiv_hw->clk = hw->clk;
>  
> -       primary_div = clk_best_div(parent_rate, rate);
> +       div = clk_best_div(parent_rate, rate);
>  
> -       clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
> -       ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * primary_div);
> +       /*
> +       * pdiv is mainly targeted for low freq results, while fdiv
> +       * should be used for div <= 64. The other way round can
> +       * lead to 'duty cycle' issues.
> +       */
> +
> +       if (div <= 64) {
> +               clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
> +               ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
> +       } else {
> +               clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
> +               ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
> +       }
>  
>         return ret;
>  }
> -- 
> 1.9.1
> 



More information about the linux-arm-kernel mailing list