diff options
author | Haavard Skinnemoen <hskinnemoen@atmel.com> | 2008-02-24 13:51:38 +0100 |
---|---|---|
committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-07-02 11:05:01 +0200 |
commit | 02a00cf672a37292c31bbdde191712bfa40a4f1d (patch) | |
tree | 5588f7cd600056861fe1313abe7b47b9c051eab6 /arch/avr32/mach-at32ap/pm-at32ap700x.S | |
parent | aa8e87ca619a3d1944874e85d74fda90607c73b9 (diff) |
avr32: Power Management support ("standby" and "mem" modes)
Implement Standby support. In this mode, we'll suspend all drivers,
put the SDRAM in self-refresh mode and switch off the HSB bus
("frozen" mode.)
Implement Suspend-to-mem support. In this mode, we suspend all
drivers, put the SDRAM into self-refresh mode and switch off all
internal clocks except the 32 kHz oscillator ("stop" mode.)
The lowest-level suspend code runs from a small portion of SRAM
allocated at startup time. This gets rid of a small potential race
with the SDRAM where we might try to enter self-refresh mode in the
middle of an icache burst. We also relocate all interrupt and
exception handlers to SRAM during the small window when we enter and
exit the low-power modes.
We don't need to do any special tricks to start and stop the PLL. The
main clock is automatically gated by hardware until the PLL is stable.
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/mach-at32ap/pm-at32ap700x.S')
-rw-r--r-- | arch/avr32/mach-at32ap/pm-at32ap700x.S | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S index 949e2485e27..0a53ad314ff 100644 --- a/arch/avr32/mach-at32ap/pm-at32ap700x.S +++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S @@ -12,6 +12,12 @@ #include <asm/thread_info.h> #include <asm/arch/pm.h> +#include "pm.h" +#include "sdramc.h" + +/* Same as 0xfff00000 but fits in a 21 bit signed immediate */ +#define PM_BASE -0x100000 + .section .bss, "wa", @nobits .global disable_idle_sleep .type disable_idle_sleep, @object @@ -64,3 +70,105 @@ cpu_idle_skip_sleep: unmask_interrupts retal r12 .size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep + +#ifdef CONFIG_PM + .section .init.text, "ax", @progbits + + .global pm_exception + .type pm_exception, @function +pm_exception: + /* + * Exceptions are masked when we switch to this handler, so + * we'll only get "unrecoverable" exceptions (offset 0.) + */ + sub r12, pc, . - .Lpanic_msg + lddpc pc, .Lpanic_addr + + .align 2 +.Lpanic_addr: + .long panic +.Lpanic_msg: + .asciz "Unrecoverable exception during suspend\n" + .size pm_exception, . - pm_exception + + .global pm_irq0 + .type pm_irq0, @function +pm_irq0: + /* Disable interrupts and return after the sleep instruction */ + mfsr r9, SYSREG_RSR_INT0 + mtsr SYSREG_RAR_INT0, r8 + sbr r9, SYSREG_GM_OFFSET + mtsr SYSREG_RSR_INT0, r9 + rete + + /* + * void cpu_enter_standby(unsigned long sdramc_base) + * + * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers + * are suspended and interrupts are disabled. Interrupts + * marked as 'wakeup' event sources may still come along and + * get us out of here. + * + * The SDRAM will be put into self-refresh mode (which does + * not require a clock from the CPU), and the CPU will be put + * into "frozen" mode (HSB bus stopped). The SDRAM controller + * will automatically bring the SDRAM into normal mode on the + * first access, and the power manager will automatically + * start the HSB and CPU clocks upon a wakeup event. + * + * This code uses the same "skip sleep" technique as above. + * It is very important that we jump directly to + * cpu_after_sleep after the sleep instruction since that's + * where we'll end up if the interrupt handler decides that we + * need to skip the sleep instruction. + */ + .global pm_standby + .type pm_standby, @function +pm_standby: + /* + * interrupts are already masked at this point, and EVBA + * points to pm_exception above. + */ + ld.w r10, r12[SDRAMC_LPR] + sub r8, pc, . - 1f /* return address for irq handler */ + mov r11, SDRAMC_LPR_LPCB_SELF_RFR + bfins r10, r11, 0, 2 /* LPCB <- self Refresh */ + sync 0 /* flush write buffer */ + st.w r12[SDRAMC_LPR], r11 /* put SDRAM in self-refresh mode */ + ld.w r11, r12[SDRAMC_LPR] + unmask_interrupts + sleep CPU_SLEEP_FROZEN +1: mask_interrupts + retal r12 + .size pm_standby, . - pm_standby + + .global pm_suspend_to_ram + .type pm_suspend_to_ram, @function +pm_suspend_to_ram: + /* + * interrupts are already masked at this point, and EVBA + * points to pm_exception above. + */ + mov r11, 0 + cache r11[2], 8 /* clean all dcache lines */ + sync 0 /* flush write buffer */ + ld.w r10, r12[SDRAMC_LPR] + sub r8, pc, . - 1f /* return address for irq handler */ + mov r11, SDRAMC_LPR_LPCB_SELF_RFR + bfins r10, r11, 0, 2 /* LPCB <- self refresh */ + st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */ + ld.w r11, r12[SDRAMC_LPR] + + unmask_interrupts + sleep CPU_SLEEP_STOP +1: mask_interrupts + + retal r12 + .size pm_suspend_to_ram, . - pm_suspend_to_ram + + .global pm_sram_end + .type pm_sram_end, @function +pm_sram_end: + .size pm_sram_end, 0 + +#endif /* CONFIG_PM */ |