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