diff options
Diffstat (limited to 'arch/arm/mach-imx/suspend-imx53.S')
-rw-r--r-- | arch/arm/mach-imx/suspend-imx53.S | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/suspend-imx53.S b/arch/arm/mach-imx/suspend-imx53.S new file mode 100644 index 0000000..5ed078a --- /dev/null +++ b/arch/arm/mach-imx/suspend-imx53.S @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + */ +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/linkage.h> + +#define M4IF_MCR0_OFFSET (0x008C) +#define M4IF_MCR0_FDVFS (0x1 << 11) +#define M4IF_MCR0_FDVACK (0x1 << 27) + + .align 3 + +/* + * ==================== low level suspend ==================== + * + * On entry + * r0: pm_info structure address; + * + * suspend ocram space layout: + * ======================== high address ====================== + * . + * . + * . + * ^ + * ^ + * ^ + * imx53_suspend code + * PM_INFO structure(imx53_suspend_info) + * ======================== low address ======================= + */ + +/* Offsets of members of struct imx53_suspend_info */ +#define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0 +#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4 +#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8 +#define SUSPEND_INFO_MX53_IO_STATE_OFFSET 0xc + +ENTRY(imx53_suspend) + stmfd sp!, {r4,r5,r6,r7} + + /* Save pad config */ + ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] + cmp r1, #0 + beq skip_pad_conf_1 + + add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET + ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] + +1: + ldr r5, [r2], #12 /* IOMUXC register offset */ + ldr r6, [r3, r5] /* current value */ + str r6, [r2], #4 /* save area */ + subs r1, r1, #1 + bne 1b + +skip_pad_conf_1: + /* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */ + ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET] + ldr r2,[r1, #M4IF_MCR0_OFFSET] + orr r2, r2, #M4IF_MCR0_FDVFS + str r2,[r1, #M4IF_MCR0_OFFSET] + + /* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */ +wait_sr_ack: + ldr r2,[r1, #M4IF_MCR0_OFFSET] + ands r2, r2, #M4IF_MCR0_FDVACK + beq wait_sr_ack + + /* Set pad config */ + ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] + cmp r1, #0 + beq skip_pad_conf_2 + + add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET + ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] + +2: + ldr r5, [r2], #4 /* IOMUXC register offset */ + ldr r6, [r2], #4 /* clear */ + ldr r7, [r3, r5] + bic r7, r7, r6 + ldr r6, [r2], #8 /* set */ + orr r7, r7, r6 + str r7, [r3, r5] + subs r1, r1, #1 + bne 2b + +skip_pad_conf_2: + /* Zzz, enter stop mode */ + wfi + nop + nop + nop + nop + + /* Restore pad config */ + ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] + cmp r1, #0 + beq skip_pad_conf_3 + + add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET + ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] + +3: + ldr r5, [r2], #12 /* IOMUXC register offset */ + ldr r6, [r2], #4 /* saved value */ + str r6, [r3, r5] + subs r1, r1, #1 + bne 3b + +skip_pad_conf_3: + /* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */ + ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET] + ldr r2,[r1, #M4IF_MCR0_OFFSET] + bic r2, r2, #M4IF_MCR0_FDVFS + str r2,[r1, #M4IF_MCR0_OFFSET] + + /* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */ +wait_ar_ack: + ldr r2,[r1, #M4IF_MCR0_OFFSET] + ands r2, r2, #M4IF_MCR0_FDVACK + bne wait_ar_ack + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6,r7} + mov pc, lr + +ENDPROC(imx53_suspend) + +ENTRY(imx53_suspend_sz) + .word . - imx53_suspend |