[PATCH v2 5/9] clk: meson: mpll: add rw operation

Michael Turquette mturquette at baylibre.com
Tue Mar 21 16:19:40 PDT 2017


Quoting Jerome Brunet (2017-03-09 02:41:50)
> This patch adds new callbacks to the meson-mpll driver to control
> and set the pll rate. For this, we also need to add the enable bit and
> sdm enable bit. The corresponding parameters are added to mpll data
> structure.
> 
> Signed-off-by: Jerome Brunet <jbrunet at baylibre.com>

Patch looks good to me. I'm really happy to see the mpll's get sorted
out finally!

Regards,
Mike

> ---
>  drivers/clk/meson/clk-mpll.c | 152 +++++++++++++++++++++++++++++++++++++++++--
>  drivers/clk/meson/clkc.h     |   4 +-
>  drivers/clk/meson/gxbb.c     |  30 +++++++++
>  3 files changed, 180 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c
> index 03af79005ddb..342b85d4e22a 100644
> --- a/drivers/clk/meson/clk-mpll.c
> +++ b/drivers/clk/meson/clk-mpll.c
> @@ -64,16 +64,50 @@
>  #include <linux/clk-provider.h>
>  #include "clkc.h"
>  
> -#define SDM_MAX 16384
> +#define SDM_DEN 16384
> +#define SDM_MIN 1
> +#define SDM_MAX 16383
> +#define N2_MIN 4
> +#define N2_MAX 127
>  
>  #define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw)
>  
> +static unsigned long rate_from_params(unsigned long parent_rate,
> +                                     unsigned long sdm,
> +                                     unsigned long n2)
> +{
> +       return (parent_rate * SDM_DEN) / ((SDM_DEN * n2) + sdm);
> +}
> +
> +static void params_from_rate(unsigned long requested_rate,
> +                            unsigned long parent_rate,
> +                            unsigned long *sdm,
> +                            unsigned long *n2)
> +{
> +       uint64_t div = parent_rate;
> +       unsigned long rem = do_div(div, requested_rate);
> +
> +       if (div < N2_MIN) {
> +               *n2 = N2_MIN;
> +               *sdm = SDM_MIN;
> +       } else if (div > N2_MAX) {
> +               *n2 = N2_MAX;
> +               *sdm = SDM_MAX;
> +       } else {
> +               *n2 = div;
> +               *sdm = DIV_ROUND_UP(rem * SDM_DEN, requested_rate);
> +               if (*sdm < SDM_MIN)
> +                       *sdm = SDM_MIN;
> +               else if (*sdm > SDM_MAX)
> +                       *sdm = SDM_MAX;
> +       }
> +}
> +
>  static unsigned long mpll_recalc_rate(struct clk_hw *hw,
>                 unsigned long parent_rate)
>  {
>         struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
>         struct parm *p;
> -       unsigned long rate = 0;
>         unsigned long reg, sdm, n2;
>  
>         p = &mpll->sdm;
> @@ -84,11 +118,119 @@ static unsigned long mpll_recalc_rate(struct clk_hw *hw,
>         reg = readl(mpll->base + p->reg_off);
>         n2 = PARM_GET(p->width, p->shift, reg);
>  
> -       rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm);
> +       return rate_from_params(parent_rate, sdm, n2);
> +}
> +
> +static long mpll_round_rate(struct clk_hw *hw,
> +                           unsigned long rate,
> +                           unsigned long *parent_rate)
> +{
> +       unsigned long sdm, n2;
> +
> +       params_from_rate(rate, *parent_rate, &sdm, &n2);
> +       return rate_from_params(*parent_rate, sdm, n2);
> +}
> +
> +static int mpll_set_rate(struct clk_hw *hw,
> +                        unsigned long rate,
> +                        unsigned long parent_rate)
> +{
> +       struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
> +       struct parm *p;
> +       unsigned long reg, sdm, n2;
> +       unsigned long flags = 0;
> +
> +       params_from_rate(rate, parent_rate, &sdm, &n2);
> +
> +       if (mpll->lock)
> +               spin_lock_irqsave(mpll->lock, flags);
> +       else
> +               __acquire(mpll->lock);
> +
> +       p = &mpll->sdm;
> +       reg = readl(mpll->base + p->reg_off);
> +       reg = PARM_SET(p->width, p->shift, reg, sdm);
> +       writel(reg, mpll->base + p->reg_off);
> +
> +       p = &mpll->sdm_en;
> +       reg = readl(mpll->base + p->reg_off);
> +       reg = PARM_SET(p->width, p->shift, reg, 1);
> +       writel(reg, mpll->base + p->reg_off);
> +
> +       p = &mpll->n2;
> +       reg = readl(mpll->base + p->reg_off);
> +       reg = PARM_SET(p->width, p->shift, reg, n2);
> +       writel(reg, mpll->base + p->reg_off);
> +
> +       if (mpll->lock)
> +               spin_unlock_irqrestore(mpll->lock, flags);
> +       else
> +               __release(mpll->lock);
>  
> -       return rate;
> +       return 0;
> +}
> +
> +static void mpll_enable_core(struct clk_hw *hw, int enable)
> +{
> +       struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
> +       struct parm *p;
> +       unsigned long reg;
> +       unsigned long flags = 0;
> +
> +       if (mpll->lock)
> +               spin_lock_irqsave(mpll->lock, flags);
> +       else
> +               __acquire(mpll->lock);
> +
> +       p = &mpll->en;
> +       reg = readl(mpll->base + p->reg_off);
> +       reg = PARM_SET(p->width, p->shift, reg, enable ? 1 : 0);
> +       writel(reg, mpll->base + p->reg_off);
> +
> +       if (mpll->lock)
> +               spin_unlock_irqrestore(mpll->lock, flags);
> +       else
> +               __release(mpll->lock);
> +}
> +
> +
> +static int mpll_enable(struct clk_hw *hw)
> +{
> +       mpll_enable_core(hw, 1);
> +
> +       return 0;
> +}
> +
> +static void mpll_disable(struct clk_hw *hw)
> +{
> +       mpll_enable_core(hw, 0);
> +}
> +
> +static int mpll_is_enabled(struct clk_hw *hw)
> +{
> +       struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
> +       struct parm *p;
> +       unsigned long reg;
> +       int en;
> +
> +       p = &mpll->en;
> +       reg = readl(mpll->base + p->reg_off);
> +       en = PARM_GET(p->width, p->shift, reg);
> +
> +       return en;
>  }
>  
>  const struct clk_ops meson_clk_mpll_ro_ops = {
> -       .recalc_rate = mpll_recalc_rate,
> +       .recalc_rate    = mpll_recalc_rate,
> +       .round_rate     = mpll_round_rate,
> +       .is_enabled     = mpll_is_enabled,
> +};
> +
> +const struct clk_ops meson_clk_mpll_ops = {
> +       .recalc_rate    = mpll_recalc_rate,
> +       .round_rate     = mpll_round_rate,
> +       .set_rate       = mpll_set_rate,
> +       .enable         = mpll_enable,
> +       .disable        = mpll_disable,
> +       .is_enabled     = mpll_is_enabled,
>  };
> diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
> index c6be77dd8694..ad254675edd8 100644
> --- a/drivers/clk/meson/clkc.h
> +++ b/drivers/clk/meson/clkc.h
> @@ -92,8 +92,9 @@ struct meson_clk_mpll {
>         struct clk_hw hw;
>         void __iomem *base;
>         struct parm sdm;
> +       struct parm sdm_en;
>         struct parm n2;
> -       /* FIXME ssen gate control? */
> +       struct parm en;
>         spinlock_t *lock;
>  };
>  
> @@ -116,5 +117,6 @@ extern const struct clk_ops meson_clk_pll_ro_ops;
>  extern const struct clk_ops meson_clk_pll_ops;
>  extern const struct clk_ops meson_clk_cpu_ops;
>  extern const struct clk_ops meson_clk_mpll_ro_ops;
> +extern const struct clk_ops meson_clk_mpll_ops;
>  
>  #endif /* __CLKC_H */
> diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
> index 79e9313e6703..79fb8989f8dd 100644
> --- a/drivers/clk/meson/gxbb.c
> +++ b/drivers/clk/meson/gxbb.c
> @@ -441,11 +441,21 @@ static struct meson_clk_mpll gxbb_mpll0 = {
>                 .shift   = 0,
>                 .width   = 14,
>         },
> +       .sdm_en = {
> +               .reg_off = HHI_MPLL_CNTL7,
> +               .shift   = 15,
> +               .width   = 1,
> +       },
>         .n2 = {
>                 .reg_off = HHI_MPLL_CNTL7,
>                 .shift   = 16,
>                 .width   = 9,
>         },
> +       .en = {
> +               .reg_off = HHI_MPLL_CNTL7,
> +               .shift   = 14,
> +               .width   = 1,
> +       },
>         .lock = &clk_lock,
>         .hw.init = &(struct clk_init_data){
>                 .name = "mpll0",
> @@ -461,11 +471,21 @@ static struct meson_clk_mpll gxbb_mpll1 = {
>                 .shift   = 0,
>                 .width   = 14,
>         },
> +       .sdm_en = {
> +               .reg_off = HHI_MPLL_CNTL8,
> +               .shift   = 15,
> +               .width   = 1,
> +       },
>         .n2 = {
>                 .reg_off = HHI_MPLL_CNTL8,
>                 .shift   = 16,
>                 .width   = 9,
>         },
> +       .en = {
> +               .reg_off = HHI_MPLL_CNTL8,
> +               .shift   = 14,
> +               .width   = 1,
> +       },
>         .lock = &clk_lock,
>         .hw.init = &(struct clk_init_data){
>                 .name = "mpll1",
> @@ -481,11 +501,21 @@ static struct meson_clk_mpll gxbb_mpll2 = {
>                 .shift   = 0,
>                 .width   = 14,
>         },
> +       .sdm_en = {
> +               .reg_off = HHI_MPLL_CNTL9,
> +               .shift   = 15,
> +               .width   = 1,
> +       },
>         .n2 = {
>                 .reg_off = HHI_MPLL_CNTL9,
>                 .shift   = 16,
>                 .width   = 9,
>         },
> +       .en = {
> +               .reg_off = HHI_MPLL_CNTL9,
> +               .shift   = 14,
> +               .width   = 1,
> +       },
>         .lock = &clk_lock,
>         .hw.init = &(struct clk_init_data){
>                 .name = "mpll2",
> -- 
> 2.9.3
> 



More information about the linux-amlogic mailing list