[PATCH v2 2/7] clk: sunxi-ng: Implement factors offsets

Chen-Yu Tsai wens at csie.org
Sun Jan 15 21:45:56 PST 2017


On Tue, Jan 10, 2017 at 3:57 PM, Maxime Ripard
<maxime.ripard at free-electrons.com> wrote:
> The factors we've seen so far all had an offset of one. However, on the
> earlier Allwinner SoCs, some factors could have no offset at all, meaning
> that the value computed to reach the rate we want to use was the one we had
> to program in the registers.
>
> Implement an additional field for the factors that can have such an offset
> (linears, not based on a power of two) to specify that offset.
>
> This offset is not linked to the extremums that can be specified in those
> structures too. The minimum and maximum are representing the range of
> values we can use to try to compute the best rate. The offset comes later
> on when we want to set the best value in the registers.
>
> Signed-off-by: Maxime Ripard <maxime.ripard at free-electrons.com>
> ---
>  drivers/clk/sunxi-ng/ccu_div.h  | 10 +++++++++-
>  drivers/clk/sunxi-ng/ccu_mp.c   | 10 +++++++---
>  drivers/clk/sunxi-ng/ccu_mult.c |  4 ++--
>  drivers/clk/sunxi-ng/ccu_mult.h | 20 ++++++++++++++------
>  drivers/clk/sunxi-ng/ccu_nk.c   | 14 ++++++++++----
>  drivers/clk/sunxi-ng/ccu_nkm.c  | 18 +++++++++++++-----
>  drivers/clk/sunxi-ng/ccu_nkmp.c | 17 +++++++++++++----
>  drivers/clk/sunxi-ng/ccu_nm.c   | 13 ++++++++++---
>  8 files changed, 78 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h
> index 06540f7cf41c..08d074451204 100644
> --- a/drivers/clk/sunxi-ng/ccu_div.h
> +++ b/drivers/clk/sunxi-ng/ccu_div.h
> @@ -41,6 +41,7 @@ struct ccu_div_internal {
>         u8                      width;
>
>         u32                     max;
> +       u32                     offset;
>
>         u32                     flags;
>
> @@ -58,20 +59,27 @@ struct ccu_div_internal {
>  #define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table)                   \
>         _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0)
>
> -#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \
> +#define _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _off, _max, _flags) \
>         {                                                               \
>                 .shift  = _shift,                                       \
>                 .width  = _width,                                       \
>                 .flags  = _flags,                                       \
>                 .max    = _max,                                         \
> +               .offset = _off,                                         \
>         }
>
> +#define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags)         \
> +       _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, 1, _max, _flags)
> +
>  #define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags)                   \
>         _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags)
>
>  #define _SUNXI_CCU_DIV_MAX(_shift, _width, _max)                       \
>         _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 0)
>
> +#define _SUNXI_CCU_DIV_OFFSET(_shift, _width, _offset)                 \
> +       _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _offset, 0, 0)
> +
>  #define _SUNXI_CCU_DIV(_shift, _width)                                 \
>         _SUNXI_CCU_DIV_FLAGS(_shift, _width, 0)
>
> diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
> index ebb1b31568a5..22c2ca7a2a22 100644
> --- a/drivers/clk/sunxi-ng/ccu_mp.c
> +++ b/drivers/clk/sunxi-ng/ccu_mp.c
> @@ -89,11 +89,14 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
>
>         m = reg >> cmp->m.shift;
>         m &= (1 << cmp->m.width) - 1;
> +       m += cmp->m.offset;
> +       if (!m)
> +               m++;
>
>         p = reg >> cmp->p.shift;
>         p &= (1 << cmp->p.width) - 1;
>
> -       return (parent_rate >> p) / (m + 1);
> +       return (parent_rate >> p) / m;
>  }
>
>  static int ccu_mp_determine_rate(struct clk_hw *hw,
> @@ -124,9 +127,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
>         reg = readl(cmp->common.base + cmp->common.reg);
>         reg &= ~GENMASK(cmp->m.width + cmp->m.shift - 1, cmp->m.shift);
>         reg &= ~GENMASK(cmp->p.width + cmp->p.shift - 1, cmp->p.shift);
> +       reg |= (m - cmp->m.offset) << cmp->m.shift;
> +       reg |= ilog2(p) << cmp->p.shift;
>
> -       writel(reg | (ilog2(p) << cmp->p.shift) | ((m - 1) << cmp->m.shift),
> -              cmp->common.base + cmp->common.reg);
> +       writel(reg, cmp->common.base + cmp->common.reg);
>
>         spin_unlock_irqrestore(cmp->common.lock, flags);
>
> diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c
> index 826302464650..bf5e11c803f9 100644
> --- a/drivers/clk/sunxi-ng/ccu_mult.c
> +++ b/drivers/clk/sunxi-ng/ccu_mult.c
> @@ -85,7 +85,7 @@ static unsigned long ccu_mult_recalc_rate(struct clk_hw *hw,
>         ccu_mux_helper_adjust_parent_for_prediv(&cm->common, &cm->mux, -1,
>                                                 &parent_rate);
>
> -       return parent_rate * (val + 1);
> +       return parent_rate * (val + cm->mult.offset);
>  }
>
>  static int ccu_mult_determine_rate(struct clk_hw *hw,
> @@ -122,7 +122,7 @@ static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate,
>         reg = readl(cm->common.base + cm->common.reg);
>         reg &= ~GENMASK(cm->mult.width + cm->mult.shift - 1, cm->mult.shift);
>
> -       writel(reg | ((_cm.mult - 1) << cm->mult.shift),
> +       writel(reg | ((_cm.mult - cm->mult.offset) << cm->mult.shift),

Nit, might be worth splitting out the "or" to a separate line.

>                cm->common.base + cm->common.reg);
>
>         spin_unlock_irqrestore(cm->common.lock, flags);
> diff --git a/drivers/clk/sunxi-ng/ccu_mult.h b/drivers/clk/sunxi-ng/ccu_mult.h
> index bd2e38b5a32a..84839641dfdf 100644
> --- a/drivers/clk/sunxi-ng/ccu_mult.h
> +++ b/drivers/clk/sunxi-ng/ccu_mult.h
> @@ -6,20 +6,28 @@
>  #include "ccu_mux.h"
>
>  struct ccu_mult_internal {
> +       u8      offset;
>         u8      shift;
>         u8      width;
>         u8      min;
>  };
>
> -#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min)      \
> -       {                                               \
> -               .shift  = _shift,                       \
> -               .width  = _width,                       \
> -               .min    = _min,                         \
> +#define _SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, _offset, _min)      \
> +       {                                                               \
> +               .min    = _min,                                         \
> +               .offset = _offset,                                      \
> +               .shift  = _shift,                                       \
> +               .width  = _width,                                       \
>         }
>
> +#define _SUNXI_CCU_MULT_MIN(_shift, _width, _min)      \
> +       _SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, 1, _min)
> +
> +#define _SUNXI_CCU_MULT_OFFSET(_shift, _width, _offset)        \
> +       _SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, _offset, 1)
> +
>  #define _SUNXI_CCU_MULT(_shift, _width)                \
> -       _SUNXI_CCU_MULT_MIN(_shift, _width, 1)
> +       _SUNXI_CCU_MULT_OFFSET_MIN(_shift, _width, 1, 1)
>
>  struct ccu_mult {
>         u32                     enable;
> diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c
> index eaf0fdf78d2b..90117d3ead8c 100644
> --- a/drivers/clk/sunxi-ng/ccu_nk.c
> +++ b/drivers/clk/sunxi-ng/ccu_nk.c
> @@ -76,12 +76,17 @@ static unsigned long ccu_nk_recalc_rate(struct clk_hw *hw,
>
>         n = reg >> nk->n.shift;
>         n &= (1 << nk->n.width) - 1;
> +       n += nk->n.offset;
> +       if (!n)
> +               n++;
>
>         k = reg >> nk->k.shift;
>         k &= (1 << nk->k.width) - 1;
> +       k += nk->k.offset;
> +       if (!k)
> +               k++;
>
> -       rate = parent_rate * (n + 1) * (k + 1);
> -
> +       rate = parent_rate * n * k;
>         if (nk->common.features & CCU_FEATURE_FIXED_POSTDIV)
>                 rate /= nk->fixed_post_div;
>
> @@ -135,8 +140,9 @@ static int ccu_nk_set_rate(struct clk_hw *hw, unsigned long rate,
>         reg &= ~GENMASK(nk->n.width + nk->n.shift - 1, nk->n.shift);
>         reg &= ~GENMASK(nk->k.width + nk->k.shift - 1, nk->k.shift);
>
> -       writel(reg | ((_nk.k - 1) << nk->k.shift) | ((_nk.n - 1) << nk->n.shift),
> -              nk->common.base + nk->common.reg);
> +       reg |= (_nk.k - nk->k.offset) << nk->k.shift;
> +       reg |= (_nk.n - nk->n.offset) << nk->n.shift;
> +       writel(reg, nk->common.base + nk->common.reg);
>
>         spin_unlock_irqrestore(nk->common.lock, flags);
>
> diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
> index 9b840a47a94d..3caaf9d603e2 100644
> --- a/drivers/clk/sunxi-ng/ccu_nkm.c
> +++ b/drivers/clk/sunxi-ng/ccu_nkm.c
> @@ -82,14 +82,23 @@ static unsigned long ccu_nkm_recalc_rate(struct clk_hw *hw,
>
>         n = reg >> nkm->n.shift;
>         n &= (1 << nkm->n.width) - 1;
> +       n += nkm->n.offset;
> +       if (!n)
> +               n++;
>
>         k = reg >> nkm->k.shift;
>         k &= (1 << nkm->k.width) - 1;
> +       k += nkm->k.offset;
> +       if (!k)
> +               k++;
>
>         m = reg >> nkm->m.shift;
>         m &= (1 << nkm->m.width) - 1;
> +       m += nkm->m.offset;
> +       if (!m)
> +               m++;
>
> -       return parent_rate * (n + 1) * (k + 1) / (m + 1);
> +       return parent_rate * n  * k / m;
>  }
>
>  static unsigned long ccu_nkm_round_rate(struct ccu_mux_internal *mux,
> @@ -145,10 +154,9 @@ static int ccu_nkm_set_rate(struct clk_hw *hw, unsigned long rate,
>         reg &= ~GENMASK(nkm->k.width + nkm->k.shift - 1, nkm->k.shift);
>         reg &= ~GENMASK(nkm->m.width + nkm->m.shift - 1, nkm->m.shift);
>
> -       reg |= (_nkm.n - 1) << nkm->n.shift;
> -       reg |= (_nkm.k - 1) << nkm->k.shift;
> -       reg |= (_nkm.m - 1) << nkm->m.shift;
> -
> +       reg |= (_nkm.n - nkm->n.offset) << nkm->n.shift;
> +       reg |= (_nkm.k - nkm->k.offset) << nkm->k.shift;
> +       reg |= (_nkm.m - nkm->m.offset) << nkm->m.shift;
>         writel(reg, nkm->common.base + nkm->common.reg);
>
>         spin_unlock_irqrestore(nkm->common.lock, flags);
> diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
> index 684c42da3ebb..da2bba02b845 100644
> --- a/drivers/clk/sunxi-ng/ccu_nkmp.c
> +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
> @@ -88,17 +88,26 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
>
>         n = reg >> nkmp->n.shift;
>         n &= (1 << nkmp->n.width) - 1;
> +       n += nkmp->n.offset;
> +       if (!n)
> +               n++;
>
>         k = reg >> nkmp->k.shift;
>         k &= (1 << nkmp->k.width) - 1;
> +       k += nkmp->k.offset;
> +       if (!k)
> +               k++;
>
>         m = reg >> nkmp->m.shift;
>         m &= (1 << nkmp->m.width) - 1;
> +       m += nkmp->m.offset;
> +       if (!m)
> +               m++;
>
>         p = reg >> nkmp->p.shift;
>         p &= (1 << nkmp->p.width) - 1;
>
> -       return (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
> +       return parent_rate * n * k >> p / m;
>  }
>
>  static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
> @@ -148,9 +157,9 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
>         reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
>         reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
>
> -       reg |= (_nkmp.n - 1) << nkmp->n.shift;
> -       reg |= (_nkmp.k - 1) << nkmp->k.shift;
> -       reg |= (_nkmp.m - 1) << nkmp->m.shift;
> +       reg |= (_nkmp.n - nkmp->n.offset) << nkmp->n.shift;
> +       reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift;
> +       reg |= (_nkmp.m - nkmp->m.offset) << nkmp->m.shift;
>         reg |= ilog2(_nkmp.p) << nkmp->p.shift;
>
>         writel(reg, nkmp->common.base + nkmp->common.reg);
> diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c
> index c9f3b6c982f0..158d74e0215f 100644
> --- a/drivers/clk/sunxi-ng/ccu_nm.c
> +++ b/drivers/clk/sunxi-ng/ccu_nm.c
> @@ -80,11 +80,17 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw,
>
>         n = reg >> nm->n.shift;
>         n &= (1 << nm->n.width) - 1;
> +       n += nm->n.offset;
> +       if (!n)
> +               n++;
>
>         m = reg >> nm->m.shift;
>         m &= (1 << nm->m.width) - 1;
> +       m += nm->m.offset;
> +       if (!m)
> +               m++;
>
> -       return parent_rate * (n + 1) / (m + 1);
> +       return parent_rate * n / m;
>  }
>
>  static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate,
> @@ -129,8 +135,9 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate,
>         reg &= ~GENMASK(nm->n.width + nm->n.shift - 1, nm->n.shift);
>         reg &= ~GENMASK(nm->m.width + nm->m.shift - 1, nm->m.shift);
>
> -       writel(reg | ((_nm.m - 1) << nm->m.shift) | ((_nm.n - 1) << nm->n.shift),
> -              nm->common.base + nm->common.reg);
> +       reg |= (_nm.n - nm->n.offset) << nm->n.shift;
> +       reg |= (_nm.m - nm->m.offset) << nm->m.shift;
> +       writel(reg, nm->common.base + nm->common.reg);
>
>         spin_unlock_irqrestore(nm->common.lock, flags);
>
> --
> git-series 0.8.11

Otherwise,

Acked-by: Chen-Yu Tsai <wens at csie.org>



More information about the linux-arm-kernel mailing list