1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. 4 */ 5/* 6 */ 7 8#include <linux/linkage.h> 9 10#define M4IF_MCR0_OFFSET (0x008C) 11#define M4IF_MCR0_FDVFS (0x1 << 11) 12#define M4IF_MCR0_FDVACK (0x1 << 27) 13 14 .align 3 15 16/* 17 * ==================== low level suspend ==================== 18 * 19 * On entry 20 * r0: pm_info structure address; 21 * 22 * suspend ocram space layout: 23 * ======================== high address ====================== 24 * . 25 * . 26 * . 27 * ^ 28 * ^ 29 * ^ 30 * imx53_suspend code 31 * PM_INFO structure(imx53_suspend_info) 32 * ======================== low address ======================= 33 */ 34 35/* Offsets of members of struct imx53_suspend_info */ 36#define SUSPEND_INFO_MX53_M4IF_V_OFFSET 0x0 37#define SUSPEND_INFO_MX53_IOMUXC_V_OFFSET 0x4 38#define SUSPEND_INFO_MX53_IO_COUNT_OFFSET 0x8 39#define SUSPEND_INFO_MX53_IO_STATE_OFFSET 0xc 40 41ENTRY(imx53_suspend) 42 stmfd sp!, {r4,r5,r6,r7} 43 44 /* Save pad config */ 45 ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] 46 cmp r1, #0 47 beq skip_pad_conf_1 48 49 add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET 50 ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] 51 521: 53 ldr r5, [r2], #12 /* IOMUXC register offset */ 54 ldr r6, [r3, r5] /* current value */ 55 str r6, [r2], #4 /* save area */ 56 subs r1, r1, #1 57 bne 1b 58 59skip_pad_conf_1: 60 /* Set FDVFS bit of M4IF_MCR0 to request DDR to enter self-refresh */ 61 ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET] 62 ldr r2,[r1, #M4IF_MCR0_OFFSET] 63 orr r2, r2, #M4IF_MCR0_FDVFS 64 str r2,[r1, #M4IF_MCR0_OFFSET] 65 66 /* Poll FDVACK bit of M4IF_MCR to wait for DDR to enter self-refresh */ 67wait_sr_ack: 68 ldr r2,[r1, #M4IF_MCR0_OFFSET] 69 ands r2, r2, #M4IF_MCR0_FDVACK 70 beq wait_sr_ack 71 72 /* Set pad config */ 73 ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] 74 cmp r1, #0 75 beq skip_pad_conf_2 76 77 add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET 78 ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] 79 802: 81 ldr r5, [r2], #4 /* IOMUXC register offset */ 82 ldr r6, [r2], #4 /* clear */ 83 ldr r7, [r3, r5] 84 bic r7, r7, r6 85 ldr r6, [r2], #8 /* set */ 86 orr r7, r7, r6 87 str r7, [r3, r5] 88 subs r1, r1, #1 89 bne 2b 90 91skip_pad_conf_2: 92 /* Zzz, enter stop mode */ 93 wfi 94 nop 95 nop 96 nop 97 nop 98 99 /* Restore pad config */ 100 ldr r1, [r0, #SUSPEND_INFO_MX53_IO_COUNT_OFFSET] 101 cmp r1, #0 102 beq skip_pad_conf_3 103 104 add r2, r0, #SUSPEND_INFO_MX53_IO_STATE_OFFSET 105 ldr r3, [r0, #SUSPEND_INFO_MX53_IOMUXC_V_OFFSET] 106 1073: 108 ldr r5, [r2], #12 /* IOMUXC register offset */ 109 ldr r6, [r2], #4 /* saved value */ 110 str r6, [r3, r5] 111 subs r1, r1, #1 112 bne 3b 113 114skip_pad_conf_3: 115 /* Clear FDVFS bit of M4IF_MCR0 to request DDR to exit self-refresh */ 116 ldr r1, [r0, #SUSPEND_INFO_MX53_M4IF_V_OFFSET] 117 ldr r2,[r1, #M4IF_MCR0_OFFSET] 118 bic r2, r2, #M4IF_MCR0_FDVFS 119 str r2,[r1, #M4IF_MCR0_OFFSET] 120 121 /* Poll FDVACK bit of M4IF_MCR to wait for DDR to exit self-refresh */ 122wait_ar_ack: 123 ldr r2,[r1, #M4IF_MCR0_OFFSET] 124 ands r2, r2, #M4IF_MCR0_FDVACK 125 bne wait_ar_ack 126 127 /* Restore registers */ 128 ldmfd sp!, {r4,r5,r6,r7} 129 mov pc, lr 130 131ENDPROC(imx53_suspend) 132 133ENTRY(imx53_suspend_sz) 134 .word . - imx53_suspend 135