diff options
author | Paul Walmsley <paul@pwsan.com> | 2009-06-19 21:08:26 -0400 |
---|---|---|
committer | paul <paul@twilight.(none)> | 2009-06-19 21:09:31 -0400 |
commit | c9812d042a21eb492a36cfabf9f41107f5ecee3d (patch) | |
tree | f9443de1d4534b0b56bd1b0ff56bfc6d78eb698d /arch/arm | |
parent | 2f135eaf182761bb9a5cbd5138a447b0ad2a1fef (diff) |
OMAP3 clock: add a short delay when lowering CORE clk rate
When changing the SDRAM clock from 166MHz to 83MHz via the CORE DPLL M2
divider, add a short delay before returning to SDRAM to allow the SDRC
time to stabilize. Without this delay, the system is prone to random
panics upon re-entering SDRAM.
This time delay varies based on MPU frequency. At 500MHz MPU frequency at
room temperature, 64 loops seems to work okay; so add another 32 loops for
environmental and process variation.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/clock34xx.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-omap2/sram34xx.S | 20 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/mach/sram.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-omap/sram.c | 8 |
4 files changed, 44 insertions, 18 deletions
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 5458ab3bf65a..4bfa650bb34b 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c | |||
@@ -286,6 +286,20 @@ static struct omap_clk omap34xx_clks[] = { | |||
286 | 286 | ||
287 | #define MIN_SDRC_DLL_LOCK_FREQ 83000000 | 287 | #define MIN_SDRC_DLL_LOCK_FREQ 83000000 |
288 | 288 | ||
289 | #define CYCLES_PER_MHZ 1000000 | ||
290 | |||
291 | /* Scale factor for fixed-point arith in omap3_core_dpll_m2_set_rate() */ | ||
292 | #define SDRC_MPURATE_SCALE 8 | ||
293 | |||
294 | /* 2^SDRC_MPURATE_BASE_SHIFT: MPU MHz that SDRC_MPURATE_LOOPS is defined for */ | ||
295 | #define SDRC_MPURATE_BASE_SHIFT 9 | ||
296 | |||
297 | /* | ||
298 | * SDRC_MPURATE_LOOPS: Number of MPU loops to execute at | ||
299 | * 2^MPURATE_BASE_SHIFT MHz for SDRC to stabilize | ||
300 | */ | ||
301 | #define SDRC_MPURATE_LOOPS 96 | ||
302 | |||
289 | /** | 303 | /** |
290 | * omap3_dpll_recalc - recalculate DPLL rate | 304 | * omap3_dpll_recalc - recalculate DPLL rate |
291 | * @clk: DPLL struct clk | 305 | * @clk: DPLL struct clk |
@@ -709,7 +723,8 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) | |||
709 | { | 723 | { |
710 | u32 new_div = 0; | 724 | u32 new_div = 0; |
711 | u32 unlock_dll = 0; | 725 | u32 unlock_dll = 0; |
712 | unsigned long validrate, sdrcrate; | 726 | u32 c; |
727 | unsigned long validrate, sdrcrate, mpurate; | ||
713 | struct omap_sdrc_params *sp; | 728 | struct omap_sdrc_params *sp; |
714 | 729 | ||
715 | if (!clk || !rate) | 730 | if (!clk || !rate) |
@@ -737,6 +752,17 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) | |||
737 | unlock_dll = 1; | 752 | unlock_dll = 1; |
738 | } | 753 | } |
739 | 754 | ||
755 | /* | ||
756 | * XXX This only needs to be done when the CPU frequency changes | ||
757 | */ | ||
758 | mpurate = arm_fck.rate / CYCLES_PER_MHZ; | ||
759 | c = (mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT; | ||
760 | c += 1; /* for safety */ | ||
761 | c *= SDRC_MPURATE_LOOPS; | ||
762 | c >>= SDRC_MPURATE_SCALE; | ||
763 | if (c == 0) | ||
764 | c = 1; | ||
765 | |||
740 | pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, | 766 | pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, |
741 | validrate); | 767 | validrate); |
742 | pr_debug("clock: SDRC timing params used: %08x %08x %08x\n", | 768 | pr_debug("clock: SDRC timing params used: %08x %08x %08x\n", |
@@ -747,7 +773,7 @@ static int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) | |||
747 | 773 | ||
748 | /* REVISIT: Add SDRC_MR changing to this code also */ | 774 | /* REVISIT: Add SDRC_MR changing to this code also */ |
749 | omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla, | 775 | omap3_configure_core_dpll(sp->rfr_ctrl, sp->actim_ctrla, |
750 | sp->actim_ctrlb, new_div, unlock_dll); | 776 | sp->actim_ctrlb, new_div, unlock_dll, c); |
751 | 777 | ||
752 | return 0; | 778 | return 0; |
753 | } | 779 | } |
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S index 84781a6cd263..8d4a88c30718 100644 --- a/arch/arm/mach-omap2/sram34xx.S +++ b/arch/arm/mach-omap2/sram34xx.S | |||
@@ -42,10 +42,14 @@ | |||
42 | * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 | 42 | * r0 = sdrc_rfr_ctrl r1 = sdrc_actim_ctrla r2 = sdrc_actim_ctrlb r3 = M2 |
43 | * r4 = Unlock SDRC DLL? (1 = yes, 0 = no) -- only unlock DLL for | 43 | * r4 = Unlock SDRC DLL? (1 = yes, 0 = no) -- only unlock DLL for |
44 | * SDRC rates < 83MHz | 44 | * SDRC rates < 83MHz |
45 | * r5 = number of MPU cycles to wait for SDRC to stabilize after | ||
46 | * reprogramming the SDRC when switching to a slower MPU speed | ||
47 | * | ||
45 | */ | 48 | */ |
46 | ENTRY(omap3_sram_configure_core_dpll) | 49 | ENTRY(omap3_sram_configure_core_dpll) |
47 | stmfd sp!, {r1-r12, lr} @ store regs to stack | 50 | stmfd sp!, {r1-r12, lr} @ store regs to stack |
48 | ldr r4, [sp, #52] @ pull extra args off the stack | 51 | ldr r4, [sp, #52] @ pull extra args off the stack |
52 | ldr r5, [sp, #56] @ load extra args from the stack | ||
49 | dsb @ flush buffered writes to interconnect | 53 | dsb @ flush buffered writes to interconnect |
50 | cmp r3, #0x2 | 54 | cmp r3, #0x2 |
51 | blne configure_sdrc | 55 | blne configure_sdrc |
@@ -59,7 +63,11 @@ ENTRY(omap3_sram_configure_core_dpll) | |||
59 | bleq wait_dll_unlock | 63 | bleq wait_dll_unlock |
60 | blne wait_dll_lock | 64 | blne wait_dll_lock |
61 | cmp r3, #0x1 | 65 | cmp r3, #0x1 |
62 | blne configure_sdrc | 66 | beq return_to_sdram |
67 | bl configure_sdrc | ||
68 | mov r12, r5 @ if slowing, wait for SDRC to stabilize | ||
69 | bl wait_clk_stable | ||
70 | return_to_sdram: | ||
63 | isb @ prevent speculative exec past here | 71 | isb @ prevent speculative exec past here |
64 | mov r0, #0 @ return value | 72 | mov r0, #0 @ return value |
65 | ldmfd sp!, {r1-r12, pc} @ restore regs and return | 73 | ldmfd sp!, {r1-r12, pc} @ restore regs and return |
@@ -106,16 +114,6 @@ configure_core_dpll: | |||
106 | wait_clk_stable: | 114 | wait_clk_stable: |
107 | subs r12, r12, #1 | 115 | subs r12, r12, #1 |
108 | bne wait_clk_stable | 116 | bne wait_clk_stable |
109 | nop | ||
110 | nop | ||
111 | nop | ||
112 | nop | ||
113 | nop | ||
114 | nop | ||
115 | nop | ||
116 | nop | ||
117 | nop | ||
118 | nop | ||
119 | bx lr | 117 | bx lr |
120 | enable_sdrc: | 118 | enable_sdrc: |
121 | ldr r11, omap3_cm_iclken1_core | 119 | ldr r11, omap3_cm_iclken1_core |
diff --git a/arch/arm/plat-omap/include/mach/sram.h b/arch/arm/plat-omap/include/mach/sram.h index dca7c16ae903..c32fa0a220dc 100644 --- a/arch/arm/plat-omap/include/mach/sram.h +++ b/arch/arm/plat-omap/include/mach/sram.h | |||
@@ -24,7 +24,7 @@ extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); | |||
24 | extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, | 24 | extern u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, |
25 | u32 sdrc_actim_ctrla, | 25 | u32 sdrc_actim_ctrla, |
26 | u32 sdrc_actim_ctrlb, u32 m2, | 26 | u32 sdrc_actim_ctrlb, u32 m2, |
27 | u32 unlock_dll); | 27 | u32 unlock_dll, u32 f); |
28 | 28 | ||
29 | /* Do not use these */ | 29 | /* Do not use these */ |
30 | extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl); | 30 | extern void omap1_sram_reprogram_clock(u32 ckctl, u32 dpllctl); |
@@ -62,7 +62,7 @@ extern unsigned long omap243x_sram_reprogram_sdrc_sz; | |||
62 | extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl, | 62 | extern u32 omap3_sram_configure_core_dpll(u32 sdrc_rfr_ctrl, |
63 | u32 sdrc_actim_ctrla, | 63 | u32 sdrc_actim_ctrla, |
64 | u32 sdrc_actim_ctrlb, u32 m2, | 64 | u32 sdrc_actim_ctrlb, u32 m2, |
65 | u32 unlock_dll); | 65 | u32 unlock_dll, u32 f); |
66 | extern unsigned long omap3_sram_configure_core_dpll_sz; | 66 | extern unsigned long omap3_sram_configure_core_dpll_sz; |
67 | 67 | ||
68 | #endif | 68 | #endif |
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index a5b9bcd6b108..79c0f0254426 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c | |||
@@ -371,15 +371,17 @@ static inline int omap243x_sram_init(void) | |||
371 | static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl, | 371 | static u32 (*_omap3_sram_configure_core_dpll)(u32 sdrc_rfr_ctrl, |
372 | u32 sdrc_actim_ctrla, | 372 | u32 sdrc_actim_ctrla, |
373 | u32 sdrc_actim_ctrlb, | 373 | u32 sdrc_actim_ctrlb, |
374 | u32 m2, u32 unlock_dll); | 374 | u32 m2, u32 unlock_dll, |
375 | u32 f); | ||
375 | u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla, | 376 | u32 omap3_configure_core_dpll(u32 sdrc_rfr_ctrl, u32 sdrc_actim_ctrla, |
376 | u32 sdrc_actim_ctrlb, u32 m2, u32 unlock_dll) | 377 | u32 sdrc_actim_ctrlb, u32 m2, u32 unlock_dll, |
378 | u32 f) | ||
377 | { | 379 | { |
378 | BUG_ON(!_omap3_sram_configure_core_dpll); | 380 | BUG_ON(!_omap3_sram_configure_core_dpll); |
379 | return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl, | 381 | return _omap3_sram_configure_core_dpll(sdrc_rfr_ctrl, |
380 | sdrc_actim_ctrla, | 382 | sdrc_actim_ctrla, |
381 | sdrc_actim_ctrlb, m2, | 383 | sdrc_actim_ctrlb, m2, |
382 | unlock_dll); | 384 | unlock_dll, f); |
383 | } | 385 | } |
384 | 386 | ||
385 | /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */ | 387 | /* REVISIT: Should this be same as omap34xx_sram_init() after off-idle? */ |