^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * arch/arm/mach-lpc32xx/suspend.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Original authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Modified by Kevin Wells <kevin.wells@nxp.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * 2005 (c) MontaVista Software, Inc. This file is licensed under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * the terms of the GNU General Public License version 2. This program
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * is licensed "as is" without any warranty of any kind, whether express
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/assembler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "lpc32xx.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /* Using named register defines makes the code easier to follow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define WORK1_REG r0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define WORK2_REG r1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define SAVED_HCLK_DIV_REG r2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define SAVED_HCLK_PLL_REG r3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define SAVED_DRAM_CLKCTRL_REG r4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define SAVED_PWR_CTRL_REG r5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CLKPWRBASE_REG r6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define EMCBASE_REG r7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define LPC32XX_EMC_STATUS_OFFS 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define LPC32XX_EMC_STATUS_BUSY 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define LPC32XX_EMC_STATUS_SELF_RFSH 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define LPC32XX_CLKPWR_PWR_CTRL_OFFS 0x44
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define LPC32XX_CLKPWR_HCLK_DIV_OFFS 0x40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS 0x58
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define CLKPWR_PCLK_DIV_MASK 0xFFFFFE7F
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) ENTRY(lpc32xx_sys_suspend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) @ Save a copy of the used registers in IRAM, r0 is corrupted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) adr r0, tmp_stack_end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) stmfd r0!, {r3 - r7, sp, lr}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) @ Load a few common register addresses
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) adr WORK1_REG, reg_bases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ldr CLKPWRBASE_REG, [WORK1_REG, #0]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ldr EMCBASE_REG, [WORK1_REG, #4]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ldr SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) orr WORK1_REG, SAVED_PWR_CTRL_REG, #LPC32XX_CLKPWR_SDRAM_SELF_RFSH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) @ Wait for SDRAM busy status to go busy and then idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) @ This guarantees a small windows where DRAM isn't busy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) bne 1b @ Branch while idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) beq 2b @ Branch until idle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) @ Setup self-refresh with support for manual exit of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) @ self-refresh mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) orr WORK2_REG, WORK1_REG, #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) @ Wait for self-refresh acknowledge, clocks to the DRAM device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) @ will automatically stop on start of self-refresh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) cmp WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) bne 3b @ Branch until self-refresh mode starts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) @ Enter direct-run mode from run mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_SELECT_RUN_MODE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) @ Safe disable of DRAM clock in EMC block, prevents DDR sync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) @ issues on restart
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ldr SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) and WORK2_REG, SAVED_HCLK_DIV_REG, #CLKPWR_PCLK_DIV_MASK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) @ Save HCLK PLL state and disable HCLK PLL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ldr SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) bic WORK2_REG, SAVED_HCLK_PLL_REG, #LPC32XX_CLKPWR_HCLKPLL_POWER_UP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) @ Enter stop mode until an enabled event occurs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) orr WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .rept 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) nop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .endr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) @ Clear stop status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) @ Restore original HCLK PLL value and wait for PLL lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) str SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) ldr WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) and WORK2_REG, WORK2_REG, #LPC32XX_CLKPWR_HCLKPLL_PLL_STS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) bne 4b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) @ Re-enter run mode with self-refresh flag cleared, but no DRAM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) @ update yet. DRAM is still in self-refresh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) @ Restore original DRAM clock mode to restore DRAM clocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) str SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) @ Clear self-refresh mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) orr WORK1_REG, SAVED_PWR_CTRL_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) @ Wait for EMC to clear self-refresh mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) bne 5b @ Branch until self-refresh has exited
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) @ restore regs and return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) adr r0, tmp_stack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) ldmfd r0!, {r3 - r7, sp, pc}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) reg_bases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .long IO_ADDRESS(LPC32XX_CLK_PM_BASE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .long IO_ADDRESS(LPC32XX_EMC_BASE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) tmp_stack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .long 0, 0, 0, 0, 0, 0, 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) tmp_stack_end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) ENTRY(lpc32xx_sys_suspend_sz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .word . - lpc32xx_sys_suspend