[PATCH 09/15] ARM: mxs: Add clock support

Shawn Guo shawn.gsc at gmail.com
Fri Dec 3 00:07:25 EST 2010


2010/12/2 Uwe Kleine-König <u.kleine-koenig at pengutronix.de>:
> On Fri, Nov 26, 2010 at 02:49:08PM +0800, Shawn Guo wrote:
>> +
>> +/*
>> + * ref_clk
>> + */
>> +#define _CLK_GET_RATE_REF(name, sr, ss)                                      \
>> +static unsigned long name##_get_rate(struct clk *clk)                        \
>> +{                                                                    \
>> +     unsigned long parent_rate;                                      \
>> +     u32 reg, div;                                                   \
>> +                                                                     \
>> +     reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##sr);         \
>> +     div = (reg >> BP_CLKCTRL_##sr##_##ss##FRAC) & 0x3f;             \
>> +     parent_rate = clk_get_rate(clk->parent);                        \
>> +                                                                     \
>> +     return parent_rate * 18 / div;                                  \
>> +}
>> +
>> +_CLK_GET_RATE_REF(ref_cpu_clk, FRAC, CPU)
>> +_CLK_GET_RATE_REF(ref_emi_clk, FRAC, EMI)
>> +_CLK_GET_RATE_REF(ref_pix_clk, FRAC, PIX)
>> +_CLK_GET_RATE_REF(ref_io_clk, FRAC, IO)
>> +
>> +#define _DEFINE_CLOCK_REF(name, er, es)                                      \
>> +     static struct clk name = {                                      \
>> +             .enable_reg     = CLKCTRL_BASE_ADDR + HW_CLKCTRL_##er,  \
>> +             .enable_shift   = BP_CLKCTRL_##er##_CLKGATE##es,        \
>> +             .get_rate       = name##_get_rate,                      \
>> +             .enable         = _raw_clk_enable,                      \
>> +             .disable        = _raw_clk_disable,                     \
>> +             .parent         = &pll_clk,                             \
>> +     }
>> +
>> +_DEFINE_CLOCK_REF(ref_cpu_clk, FRAC, CPU);
> What happens if get_clock_rate(ref_cpu_clk) is called?:
>
>        ref_cpu_clk_get_rate
>                reg = something
>                div = something else
>                parent_rate = clk_get_rate(clk->parent)
>                        = pll_clk_get_rate()
>                        = 480000000;
>                return parent_rate * 18 / div
>                        = (480000000 * 18) / div
>                        = 0x202fbf000 / div
>                        = ...
>
> Note that 0x202fbf000 is too big for an unsigned long so (AFAIK) this is
> truncated to 0x02fbf000 / div which is wrong.
>
> The same overflow happens in at least one set_rate function, too.
>
> Either you have to switch to long long or (IMHO preferable) use shifted
> values.
>
Excellent catch.  It solved another issue that I ran into, which
caused by imprecise mdelay.

Thanks a million, Uwe.

-- 
Regards,
Shawn



More information about the linux-arm-kernel mailing list