.text
ENTRY(lpc32xx_sys_suspend)
@ Save a copy of the used registers in IRAM, r0 is corrupted
adr r0, tmp_stack_end
stmfd r0!, {r3 - r7, sp, lr}
@ Load a few common register addresses
adr WORK1_REG, reg_bases
ldr CLKPWRBASE_REG, [WORK1_REG,
ldr EMCBASE_REG, [WORK1_REG,
ldr SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
orr WORK1_REG, SAVED_PWR_CTRL_REG,
@ Wait for SDRAM busy status to go busy and then idle
@ This guarantees a small windows where DRAM isn't busy
1:
ldr WORK2_REG, [EMCBASE_REG,
and WORK2_REG, WORK2_REG,
cmp WORK2_REG,
bne 1b @ Branch while idle
2:
ldr WORK2_REG, [EMCBASE_REG,
and WORK2_REG, WORK2_REG,
cmp WORK2_REG,
beq 2b @ Branch until idle
@ Setup self-refresh with support for manual exit of
@ self-refresh mode
str WORK1_REG, [CLKPWRBASE_REG,
orr WORK2_REG, WORK1_REG,
str WORK2_REG, [CLKPWRBASE_REG,
str WORK1_REG, [CLKPWRBASE_REG,
@ Wait for self-refresh acknowledge, clocks to the DRAM device
@ will automatically stop on start of self-refresh
3:
ldr WORK2_REG, [EMCBASE_REG,
and WORK2_REG, WORK2_REG,
cmp WORK2_REG,
bne 3b @ Branch until self-refresh mode starts
@ Enter direct-run mode from run mode
bic WORK1_REG, WORK1_REG,
str WORK1_REG, [CLKPWRBASE_REG,
@ Safe disable of DRAM clock in EMC block, prevents DDR sync
@ issues on restart
ldr SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
and WORK2_REG, SAVED_HCLK_DIV_REG,
str WORK2_REG, [CLKPWRBASE_REG,
@ Save HCLK PLL state and disable HCLK PLL
ldr SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
bic WORK2_REG, SAVED_HCLK_PLL_REG,
str WORK2_REG, [CLKPWRBASE_REG,
@ Enter stop mode until an enabled event occurs
orr WORK1_REG, WORK1_REG,
str WORK1_REG, [CLKPWRBASE_REG,
.rept 9
nop
.endr
@ Clear stop status
bic WORK1_REG, WORK1_REG,
@ Restore original HCLK PLL value and wait for PLL lock
str SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
4:
ldr WORK2_REG, [CLKPWRBASE_REG,
and WORK2_REG, WORK2_REG,
bne 4b
@ Re-enter run mode with self-refresh flag cleared, but no DRAM
@ update yet. DRAM is still in self-refresh
str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
@ Restore original DRAM clock mode to restore DRAM clocks
str SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
@ Clear self-refresh mode
orr WORK1_REG, SAVED_PWR_CTRL_REG,\
str WORK1_REG, [CLKPWRBASE_REG,
str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
@ Wait for EMC to clear self-refresh mode
5:
ldr WORK2_REG, [EMCBASE_REG,
and WORK2_REG, WORK2_REG,
bne 5b @ Branch until self-refresh has exited
@ restore regs and return
adr r0, tmp_stack
ldmfd r0!, {r3 - r7, sp, pc}
reg_bases:
.long IO_ADDRESS(LPC32XX_CLK_PM_BASE)
.long IO_ADDRESS(LPC32XX_EMC_BASE)
tmp_stack:
.long 0, 0, 0, 0, 0, 0, 0
tmp_stack_end:
ENTRY(lpc32xx_sys_suspend_sz)
.word . - lpc32xx_sys_suspend