diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-03 14:31:24 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-03 14:31:24 -0700 |
commit | be82ae0238b0453afcf4a76f0512b7dde34ba500 (patch) | |
tree | aaa3f5f11fd51fd73365ee1a2164aad9a03de060 /arch/arm/mach-lpc32xx/suspend.S | |
parent | 4b4fd27c0b5ec638a1f06ced9226fd95229dbbf0 (diff) | |
parent | 7b70c4275f28702b76b273c8534c38f8313812e9 (diff) | |
download | talos-obmc-linux-be82ae0238b0453afcf4a76f0512b7dde34ba500.tar.gz talos-obmc-linux-be82ae0238b0453afcf4a76f0512b7dde34ba500.zip |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (291 commits)
ARM: AMBA: Add pclk support to AMBA bus infrastructure
ARM: 6278/2: fix regression in RealView after the introduction of pclk
ARM: 6277/1: mach-shmobile: Allow users to select HZ, default to 128
ARM: 6276/1: mach-shmobile: remove duplicate NR_IRQS_LEGACY
ARM: 6246/1: mmci: support larger MMCIDATALENGTH register
ARM: 6245/1: mmci: enable hardware flow control on Ux500 variants
ARM: 6244/1: mmci: add variant data and default MCICLOCK support
ARM: 6243/1: mmci: pass power_mode to the translate_vdd callback
ARM: 6274/1: add global control registers definition header file for nuc900
mx2_camera: fix type of dma buffer virtual address pointer
mx2_camera: Add soc_camera support for i.MX25/i.MX27
arm/imx/gpio: add spinlock protection
ARM: Add support for the LPC32XX arch
ARM: LPC32XX: Arch config menu supoport and makefiles
ARM: LPC32XX: Phytec 3250 platform support
ARM: LPC32XX: Misc support functions
ARM: LPC32XX: Serial support code
ARM: LPC32XX: System suspend support
ARM: LPC32XX: GPIO, timer, and IRQ drivers
ARM: LPC32XX: Clock driver
...
Diffstat (limited to 'arch/arm/mach-lpc32xx/suspend.S')
-rw-r--r-- | arch/arm/mach-lpc32xx/suspend.S | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/arch/arm/mach-lpc32xx/suspend.S b/arch/arm/mach-lpc32xx/suspend.S new file mode 100644 index 000000000000..374f9f07fe48 --- /dev/null +++ b/arch/arm/mach-lpc32xx/suspend.S @@ -0,0 +1,151 @@ +/* + * arch/arm/mach-lpc32xx/suspend.S + * + * Original authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com> + * Modified by Kevin Wells <kevin.wells@nxp.com> + * + * 2005 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <mach/platform.h> +#include <mach/hardware.h> + +/* Using named register defines makes the code easier to follow */ +#define WORK1_REG r0 +#define WORK2_REG r1 +#define SAVED_HCLK_DIV_REG r2 +#define SAVED_HCLK_PLL_REG r3 +#define SAVED_DRAM_CLKCTRL_REG r4 +#define SAVED_PWR_CTRL_REG r5 +#define CLKPWRBASE_REG r6 +#define EMCBASE_REG r7 + +#define LPC32XX_EMC_STATUS_OFFS 0x04 +#define LPC32XX_EMC_STATUS_BUSY 0x1 +#define LPC32XX_EMC_STATUS_SELF_RFSH 0x4 + +#define LPC32XX_CLKPWR_PWR_CTRL_OFFS 0x44 +#define LPC32XX_CLKPWR_HCLK_DIV_OFFS 0x40 +#define LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS 0x58 + +#define CLKPWR_PCLK_DIV_MASK 0xFFFFFE7F + + .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, #0] + ldr EMCBASE_REG, [WORK1_REG, #4] + + ldr SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\ + #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + orr WORK1_REG, SAVED_PWR_CTRL_REG, #LPC32XX_CLKPWR_SDRAM_SELF_RFSH + + @ 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, #LPC32XX_EMC_STATUS_OFFS] + and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY + cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY + bne 1b @ Branch while idle +2: + ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS] + and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY + cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY + beq 2b @ Branch until idle + + @ Setup self-refresh with support for manual exit of + @ self-refresh mode + str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + orr WORK2_REG, WORK1_REG, #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH + str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + + @ Wait for self-refresh acknowledge, clocks to the DRAM device + @ will automatically stop on start of self-refresh +3: + ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS] + and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH + cmp WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH + bne 3b @ Branch until self-refresh mode starts + + @ Enter direct-run mode from run mode + bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_SELECT_RUN_MODE + str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + + @ Safe disable of DRAM clock in EMC block, prevents DDR sync + @ issues on restart + ldr SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\ + #LPC32XX_CLKPWR_HCLK_DIV_OFFS] + and WORK2_REG, SAVED_HCLK_DIV_REG, #CLKPWR_PCLK_DIV_MASK + str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLK_DIV_OFFS] + + @ Save HCLK PLL state and disable HCLK PLL + ldr SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\ + #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS] + bic WORK2_REG, SAVED_HCLK_PLL_REG, #LPC32XX_CLKPWR_HCLKPLL_POWER_UP + str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS] + + @ Enter stop mode until an enabled event occurs + orr WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL + str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + .rept 9 + nop + .endr + + @ Clear stop status + bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL + + @ Restore original HCLK PLL value and wait for PLL lock + str SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\ + #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS] +4: + ldr WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS] + and WORK2_REG, WORK2_REG, #LPC32XX_CLKPWR_HCLKPLL_PLL_STS + 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,\ + #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + + @ Restore original DRAM clock mode to restore DRAM clocks + str SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\ + #LPC32XX_CLKPWR_HCLK_DIV_OFFS] + + @ Clear self-refresh mode + orr WORK1_REG, SAVED_PWR_CTRL_REG,\ + #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH + str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\ + #LPC32XX_CLKPWR_PWR_CTRL_OFFS] + + @ Wait for EMC to clear self-refresh mode +5: + ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS] + and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH + 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 |