diff options
author | Nancy Chen <Nancy.Chen@freescale.com> | 2010-05-19 15:04:59 -0500 |
---|---|---|
committer | Frank Li <Frank.Li@freescale.com> | 2010-05-21 09:22:43 +0800 |
commit | f6139683e1b8d9cf3d50676d4f6bcc2d74a004a6 (patch) | |
tree | 962832ea52762194fe2f2b0b1c31b62fb938f508 /arch | |
parent | 149d1d0ec65cc718a341d43e3be9687fb36d84f5 (diff) |
ENGR00123514 MX28: System hangs when set different cpu freq continuously
MX28: System hangs when set different cpu freq continuously.
Signed-off-by: Nancy Chen <Nancy.Chen@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-mx28/clock.c | 30 |
1 files changed, 28 insertions, 2 deletions
diff --git a/arch/arm/mach-mx28/clock.c b/arch/arm/mach-mx28/clock.c index 40ad38da1f06..ae6f49d4ae41 100644 --- a/arch/arm/mach-mx28/clock.c +++ b/arch/arm/mach-mx28/clock.c @@ -496,6 +496,7 @@ static unsigned long cpu_round_rate(struct clk *clk, unsigned long rate) return rate; } +static struct clk h_clk; static int cpu_set_rate(struct clk *clk, unsigned long rate) { unsigned long root_rate = @@ -505,7 +506,7 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) u32 c = clkctrl_cpu; u32 clkctrl_frac = 1; u32 val; - u32 reg_val; + u32 reg_val, hclk_reg; if (rate < 24000) return -EINVAL; @@ -536,7 +537,31 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) if ((abs(d) > 100) || (clkctrl_frac < 18) || (clkctrl_frac > 35)) return -EINVAL; - } + } + + /* Set safe hbus clock divider. A divider of 3 ensure that + * the Vddd voltage required for the cpuclk is sufficiently + * high for the hbus clock. + */ + hclk_reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS); + if ((hclk_reg & BP_CLKCTRL_HBUS_DIV) != 3) { + hclk_reg &= ~(BM_CLKCTRL_HBUS_DIV); + hclk_reg |= BF_CLKCTRL_HBUS_DIV(3); + + /* change hclk divider to safe value for any ref_cpu + * value. + */ + __raw_writel(hclk_reg, CLKCTRL_BASE_ADDR + + HW_CLKCTRL_HBUS); + } + + for (i = 10000; i; i--) + if (!clk_is_busy(&h_clk)) + break; + if (!i) { + printk(KERN_ERR "couldn't set up HCLK divisor\n"); + return -ETIMEDOUT; + } /* Set Frac div */ val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0); @@ -546,6 +571,7 @@ static int cpu_set_rate(struct clk *clk, unsigned long rate) /* Do not gate */ __raw_writel(BM_CLKCTRL_FRAC0_CLKGATECPU, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0_CLR); + /* write clkctrl_cpu */ reg_val = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU); reg_val &= ~0x3F; |