[RESEND PATCH 2/5] clk: samsung: Add support to register rate_table for PLL3xxx

Yadwinder Singh Brar yadi.brar01 at gmail.com
Mon May 27 02:35:06 EDT 2013


Hi Tomasz,

On Sat, May 25, 2013 at 3:34 AM, Tomasz Figa <tomasz.figa at gmail.com> wrote:
> Hi,
>
> Please see my comments inline.
>
> On Friday 24 of May 2013 16:01:15 Vikas Sajjan wrote:
>> From: Yadwinder Singh Brar <yadi.brar at samsung.com>
>>
>> This patch defines a common rate_table which will contain recommended p,
>> m, s and k values for supported rates that needs to be changed for
>> changing corresponding PLL's rate.
>> It also sorts the rate table while registering the PLL rate table.
>> So that this sorted table can be used for making the searching of
>> "required rate" efficient.
>>
>> Signed-off-by: Yadwinder Singh Brar <yadi.brar at samsung.com>
>> ---
>>  drivers/clk/samsung/clk-exynos4.c    |    8 ++++----
>>  drivers/clk/samsung/clk-exynos5250.c |   14 +++++++-------
>>  drivers/clk/samsung/clk-pll.c        |   35
>> ++++++++++++++++++++++++++++++++-- drivers/clk/samsung/clk-pll.h
>> |   27 ++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 15
>> deletions(-)
>>
>> diff --git a/drivers/clk/samsung/clk-exynos4.c
>> b/drivers/clk/samsung/clk-exynos4.c index cf7d4e7..beff8a1 100644
>> --- a/drivers/clk/samsung/clk-exynos4.c
>> +++ b/drivers/clk/samsung/clk-exynos4.c
>> @@ -1021,13 +1021,13 @@ void __init exynos4_clk_init(struct device_node
>> *np, enum exynos4_soc exynos4_so reg_base + VPLL_CON0, pll_4650c);
>>       } else {
>>               apll = samsung_clk_register_pll35xx("fout_apll",
> "fin_pll",
>> -                                     reg_base + APLL_LOCK);
>> +                                     reg_base + APLL_LOCK, NULL, 0);
>>               mpll = samsung_clk_register_pll35xx("fout_mpll",
> "fin_pll",
>> -                                     reg_base + E4X12_MPLL_LOCK);
>> +                                     reg_base + E4X12_MPLL_LOCK, NULL,
> 0);
>>               epll = samsung_clk_register_pll36xx("fout_epll",
> "fin_pll",
>> -                                     reg_base + EPLL_LOCK);
>> +                                     reg_base + EPLL_LOCK, NULL, 0);
>>               vpll = samsung_clk_register_pll36xx("fout_vpll",
> "fin_pll",
>> -                                     reg_base + VPLL_LOCK);
>> +                                     reg_base + VPLL_LOCK, NULL, 0);
>>       }
>>
>>       samsung_clk_add_lookup(apll, fout_apll);
>> diff --git a/drivers/clk/samsung/clk-exynos5250.c
>> b/drivers/clk/samsung/clk-exynos5250.c index 687b580..ddf10ca 100644
>> --- a/drivers/clk/samsung/clk-exynos5250.c
>> +++ b/drivers/clk/samsung/clk-exynos5250.c
>> @@ -491,19 +491,19 @@ void __init exynos5250_clk_init(struct device_node
>> *np) ext_clk_match);
>>
>>       apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
>> -                     reg_base);
>> +                     reg_base, NULL, 0);
>>       mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
>> -                     reg_base + 0x4000);
>> +                     reg_base + 0x4000, NULL, 0);
>>       bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll",
>> -                     reg_base + 0x20010);
>> +                     reg_base + 0x20010, NULL, 0);
>>       gpll = samsung_clk_register_pll35xx("fout_gpll", "fin_pll",
>> -                     reg_base + 0x10050);
>> +                     reg_base + 0x10050, NULL, 0);
>>       cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll",
>> -                     reg_base + 0x10020);
>> +                     reg_base + 0x10020, NULL, 0);
>>       epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
>> -                     reg_base + 0x10030);
>> +                     reg_base + 0x10030, NULL, 0);
>>       vpll = samsung_clk_register_pll36xx("fout_vpll", "mout_vpllsrc",
>> -                     reg_base + 0x10040);
>> +                     reg_base + 0x10040, NULL, 0);
>>
>>       samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks,
>>                       ARRAY_SIZE(exynos5250_fixed_rate_clks));
>> diff --git a/drivers/clk/samsung/clk-pll.c
>> b/drivers/clk/samsung/clk-pll.c index 01f17cf..b8c0260 100644
>> --- a/drivers/clk/samsung/clk-pll.c
>> +++ b/drivers/clk/samsung/clk-pll.c
>> @@ -10,12 +10,15 @@
>>  */
>>
>>  #include <linux/errno.h>
>> +#include <linux/sort.h>
>>  #include "clk.h"
>>  #include "clk-pll.h"
>>
>>  struct samsung_clk_pll {
>>       struct clk_hw           hw;
>>       const void __iomem      *base;
>> +     struct samsung_pll_rate_table *rate_table;
>> +     unsigned int rate_count;
>>  };
>>
>>  #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
>> @@ -25,6 +28,14 @@ struct samsung_clk_pll {
>>  #define pll_writel(pll, val, offset)                                 \
>>               __raw_writel(val, (void __iomem *)(pll->base + (offset)));
>>
>> +static int samsung_compare_rate(const void *_a, const void *_b)
>> +{
>> +     const struct samsung_pll_rate_table *a = _a;
>> +     const struct samsung_pll_rate_table *b = _b;
>> +
>> +     return a->rate - b->rate;
>> +}
>> +
>>  /*
>>   * PLL35xx Clock Type
>>   */
>> @@ -62,7 +73,9 @@ static const struct clk_ops samsung_pll35xx_clk_ops =
>> { };
>>
>>  struct clk * __init samsung_clk_register_pll35xx(const char *name,
>> -                     const char *pname, const void __iomem *base)
>> +                     const char *pname, const void __iomem *base,
>> +                     struct samsung_pll_rate_table *rate_table,
>> +                     const unsigned int rate_count)
>>  {
>>       struct samsung_clk_pll *pll;
>>       struct clk *clk;
>> @@ -82,6 +95,14 @@ struct clk * __init
>> samsung_clk_register_pll35xx(const char *name,
>>
>>       pll->hw.init = &init;
>>       pll->base = base;
>> +     pll->rate_table = rate_table;
>> +     pll->rate_count = rate_count;
>> +
>> +     if (pll->rate_table && pll->rate_count) {
>
> You seem to assume here that the exact set of rates is known at
> compilation time. In other words, you assume that all boards have the same
> PLL input (xtal) frequency.
>

Hmm .. not exactly same. I assumed that while registering a particular PLL,
required rates and parent of that PLL will be known(as in existing scenarios).
So we can provide a table containing valid supported rates with
recommended p, m, s values while registering  a particular PLL instance.
That table can also be provided at compilation time or can be initialized
before registering PLL depending upon SoC and parent.

> We have similar patches available in our internal tree that work in a bit
> different way:
>
> 1) they assume that passed array is already sorted, which is a good
> assumption, because you have full control of this array - it's a part of
> the clock driver and if it's incorrect it's your fault - you don't deal
> with data input by user
>

but the sorting is just one time job and we will be on safer side.

> 2) passed array don't have defined rates, but rather only all the relevant
> PLL coefficients; the frequency for each entry is calculated at
> registration time, based on rate of parent clock
>
> 3) the table is NULL terminated, without the need to pass its size, but
> it's just a matter of preference
>
>> +             sort(pll->rate_table, pll->rate_count,
>> +                     sizeof(struct samsung_pll_rate_table),
>> +                     samsung_compare_rate, NULL);
>> +     }
>>
>>       clk = clk_register(NULL, &pll->hw);
>>       if (IS_ERR(clk)) {
>> @@ -137,7 +158,9 @@ static const struct clk_ops samsung_pll36xx_clk_ops
>> = { };
>>
>>  struct clk * __init samsung_clk_register_pll36xx(const char *name,
>> -                     const char *pname, const void __iomem *base)
>> +                     const char *pname, const void __iomem *base,
>> +                     struct samsung_pll_rate_table *rate_table,
>> +                     const unsigned int rate_count)
>>  {
>>       struct samsung_clk_pll *pll;
>>       struct clk *clk;
>> @@ -157,6 +180,14 @@ struct clk * __init
>> samsung_clk_register_pll36xx(const char *name,
>>
>>       pll->hw.init = &init;
>>       pll->base = base;
>> +     pll->rate_table = rate_table;
>> +     pll->rate_count = rate_count;
>> +
>> +     if (pll->rate_table && pll->rate_count) {
>> +             sort(pll->rate_table, pll->rate_count,
>> +                     sizeof(struct samsung_pll_rate_table),
>> +                     samsung_compare_rate, NULL);
>> +     }
>>
>>       clk = clk_register(NULL, &pll->hw);
>>       if (IS_ERR(clk)) {
>> diff --git a/drivers/clk/samsung/clk-pll.h
>> b/drivers/clk/samsung/clk-pll.h index 1329522..b5e12430 100644
>> --- a/drivers/clk/samsung/clk-pll.h
>> +++ b/drivers/clk/samsung/clk-pll.h
>> @@ -12,6 +12,25 @@
>>  #ifndef __SAMSUNG_CLK_PLL_H
>>  #define __SAMSUNG_CLK_PLL_H
>>
>> +#define PLL_35XX_RATE(_rate, _m, _p, _s)                     \
>> +     {                                                       \
>> +             .rate = _rate,                                  \
>> +             .pll_con0 = ((_m) << 16 | (_p) << 8 | (_s)),    \
>> +     }
>> +
>> +#define PLL_36XX_RATE(_rate, _m, _p, _s, _k)                 \
>> +     {                                                       \
>> +             .rate = _rate,                                  \
>> +             .pll_con0 = ((_m) << 16 | (_p) << 8 | (_s)),    \
>> +             .pll_con1 = _k,                                 \
>> +     }
>> +
>> +struct samsung_pll_rate_table {
>> +     unsigned  int rate;
>> +     u32 pll_con0;
>> +     u32 pll_con1;
>
> I don't like this struct. What about PLLs that don't have con0 or con1,
> but rather a completely weird register strukture like PLL_P_REG,
> PLL_M_REG, PLL_S_REG? The structure has generic name, which suggests that
> it should be able to handle any future Samsung PLLs as well.
>

We have derived  this struct looking at existing PLL3xxx and PLL4xxx registers.

> I'd suggest storing all coefficients as separate fields of the struct,
> e.g.
>
> struct samsung_pll_rate_table {
>         unsigned  int rate;
>         /* ... */
>         unsigned int p;
>         unsigned int m;
>         unsigned int s;
>         /* ... */
> };
>

Hmm .. it will fine, we can use it.

Regards,
Yadwinder

> Best regards,
> Tomasz
>
>> +};
>> +
>>  enum pll45xx_type {
>>       pll_4500,
>>       pll_4502,
>> @@ -25,9 +44,13 @@ enum pll46xx_type {
>>  };
>>
>>  extern struct clk * __init samsung_clk_register_pll35xx(const char
>> *name, -                      const char *pname, const void __iomem
> *base);
>> +                     const char *pname, const void __iomem *base,
>> +                     struct samsung_pll_rate_table *rate_table,
>> +                     const unsigned int rate_count);
>>  extern struct clk * __init samsung_clk_register_pll36xx(const char
>> *name, -                      const char *pname, const void __iomem
> *base);
>> +                     const char *pname, const void __iomem *base,
>> +                     struct samsung_pll_rate_table *rate_table,
>> +                     const unsigned int rate_count);
>>  extern struct clk * __init samsung_clk_register_pll45xx(const char
>> *name, const char *pname, const void __iomem *con_reg,
>>                       enum pll45xx_type type);



More information about the linux-arm-kernel mailing list