1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * Copyright (C) 2014 Imagination Technologies Ltd 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * PM helper macros for CPU power off (e.g. Suspend-to-RAM). 6*4882a593Smuzhiyun */ 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun #ifndef __ASM_PM_H 9*4882a593Smuzhiyun #define __ASM_PM_H 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun #ifdef __ASSEMBLY__ 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun #include <asm/asm-offsets.h> 14*4882a593Smuzhiyun #include <asm/asm.h> 15*4882a593Smuzhiyun #include <asm/mipsregs.h> 16*4882a593Smuzhiyun #include <asm/regdef.h> 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun /* Save CPU state to stack for suspend to RAM */ 19*4882a593Smuzhiyun .macro SUSPEND_SAVE_REGS 20*4882a593Smuzhiyun subu sp, PT_SIZE 21*4882a593Smuzhiyun /* Call preserved GPRs */ 22*4882a593Smuzhiyun LONG_S $16, PT_R16(sp) 23*4882a593Smuzhiyun LONG_S $17, PT_R17(sp) 24*4882a593Smuzhiyun LONG_S $18, PT_R18(sp) 25*4882a593Smuzhiyun LONG_S $19, PT_R19(sp) 26*4882a593Smuzhiyun LONG_S $20, PT_R20(sp) 27*4882a593Smuzhiyun LONG_S $21, PT_R21(sp) 28*4882a593Smuzhiyun LONG_S $22, PT_R22(sp) 29*4882a593Smuzhiyun LONG_S $23, PT_R23(sp) 30*4882a593Smuzhiyun LONG_S $28, PT_R28(sp) 31*4882a593Smuzhiyun LONG_S $30, PT_R30(sp) 32*4882a593Smuzhiyun LONG_S $31, PT_R31(sp) 33*4882a593Smuzhiyun /* A couple of CP0 registers with space in pt_regs */ 34*4882a593Smuzhiyun mfc0 k0, CP0_STATUS 35*4882a593Smuzhiyun LONG_S k0, PT_STATUS(sp) 36*4882a593Smuzhiyun .endm 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun /* Restore CPU state from stack after resume from RAM */ 39*4882a593Smuzhiyun .macro RESUME_RESTORE_REGS_RETURN 40*4882a593Smuzhiyun .set push 41*4882a593Smuzhiyun .set noreorder 42*4882a593Smuzhiyun /* A couple of CP0 registers with space in pt_regs */ 43*4882a593Smuzhiyun LONG_L k0, PT_STATUS(sp) 44*4882a593Smuzhiyun mtc0 k0, CP0_STATUS 45*4882a593Smuzhiyun /* Call preserved GPRs */ 46*4882a593Smuzhiyun LONG_L $16, PT_R16(sp) 47*4882a593Smuzhiyun LONG_L $17, PT_R17(sp) 48*4882a593Smuzhiyun LONG_L $18, PT_R18(sp) 49*4882a593Smuzhiyun LONG_L $19, PT_R19(sp) 50*4882a593Smuzhiyun LONG_L $20, PT_R20(sp) 51*4882a593Smuzhiyun LONG_L $21, PT_R21(sp) 52*4882a593Smuzhiyun LONG_L $22, PT_R22(sp) 53*4882a593Smuzhiyun LONG_L $23, PT_R23(sp) 54*4882a593Smuzhiyun LONG_L $28, PT_R28(sp) 55*4882a593Smuzhiyun LONG_L $30, PT_R30(sp) 56*4882a593Smuzhiyun LONG_L $31, PT_R31(sp) 57*4882a593Smuzhiyun /* Pop and return */ 58*4882a593Smuzhiyun jr ra 59*4882a593Smuzhiyun addiu sp, PT_SIZE 60*4882a593Smuzhiyun .set pop 61*4882a593Smuzhiyun .endm 62*4882a593Smuzhiyun 63*4882a593Smuzhiyun /* Get address of static suspend state into t1 */ 64*4882a593Smuzhiyun .macro LA_STATIC_SUSPEND 65*4882a593Smuzhiyun la t1, mips_static_suspend_state 66*4882a593Smuzhiyun .endm 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun /* Save important CPU state for early restoration to global data */ 69*4882a593Smuzhiyun .macro SUSPEND_SAVE_STATIC 70*4882a593Smuzhiyun #ifdef CONFIG_EVA 71*4882a593Smuzhiyun /* 72*4882a593Smuzhiyun * Segment configuration is saved in global data where it can be easily 73*4882a593Smuzhiyun * reloaded without depending on the segment configuration. 74*4882a593Smuzhiyun */ 75*4882a593Smuzhiyun mfc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ 76*4882a593Smuzhiyun LONG_S k0, SSS_SEGCTL0(t1) 77*4882a593Smuzhiyun mfc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ 78*4882a593Smuzhiyun LONG_S k0, SSS_SEGCTL1(t1) 79*4882a593Smuzhiyun mfc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ 80*4882a593Smuzhiyun LONG_S k0, SSS_SEGCTL2(t1) 81*4882a593Smuzhiyun #endif 82*4882a593Smuzhiyun /* save stack pointer (pointing to GPRs) */ 83*4882a593Smuzhiyun LONG_S sp, SSS_SP(t1) 84*4882a593Smuzhiyun .endm 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun /* Restore important CPU state early from global data */ 87*4882a593Smuzhiyun .macro RESUME_RESTORE_STATIC 88*4882a593Smuzhiyun #ifdef CONFIG_EVA 89*4882a593Smuzhiyun /* 90*4882a593Smuzhiyun * Segment configuration must be restored prior to any access to 91*4882a593Smuzhiyun * allocated memory, as it may reside outside of the legacy kernel 92*4882a593Smuzhiyun * segments. 93*4882a593Smuzhiyun */ 94*4882a593Smuzhiyun LONG_L k0, SSS_SEGCTL0(t1) 95*4882a593Smuzhiyun mtc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ 96*4882a593Smuzhiyun LONG_L k0, SSS_SEGCTL1(t1) 97*4882a593Smuzhiyun mtc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ 98*4882a593Smuzhiyun LONG_L k0, SSS_SEGCTL2(t1) 99*4882a593Smuzhiyun mtc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ 100*4882a593Smuzhiyun tlbw_use_hazard 101*4882a593Smuzhiyun #endif 102*4882a593Smuzhiyun /* restore stack pointer (pointing to GPRs) */ 103*4882a593Smuzhiyun LONG_L sp, SSS_SP(t1) 104*4882a593Smuzhiyun .endm 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun /* flush caches to make sure context has reached memory */ 107*4882a593Smuzhiyun .macro SUSPEND_CACHE_FLUSH 108*4882a593Smuzhiyun .extern __wback_cache_all 109*4882a593Smuzhiyun .set push 110*4882a593Smuzhiyun .set noreorder 111*4882a593Smuzhiyun la t1, __wback_cache_all 112*4882a593Smuzhiyun LONG_L t0, 0(t1) 113*4882a593Smuzhiyun jalr t0 114*4882a593Smuzhiyun nop 115*4882a593Smuzhiyun .set pop 116*4882a593Smuzhiyun .endm 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun /* Save suspend state and flush data caches to RAM */ 119*4882a593Smuzhiyun .macro SUSPEND_SAVE 120*4882a593Smuzhiyun SUSPEND_SAVE_REGS 121*4882a593Smuzhiyun LA_STATIC_SUSPEND 122*4882a593Smuzhiyun SUSPEND_SAVE_STATIC 123*4882a593Smuzhiyun SUSPEND_CACHE_FLUSH 124*4882a593Smuzhiyun .endm 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun /* Restore saved state after resume from RAM and return */ 127*4882a593Smuzhiyun .macro RESUME_RESTORE_RETURN 128*4882a593Smuzhiyun LA_STATIC_SUSPEND 129*4882a593Smuzhiyun RESUME_RESTORE_STATIC 130*4882a593Smuzhiyun RESUME_RESTORE_REGS_RETURN 131*4882a593Smuzhiyun .endm 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun #else /* __ASSEMBLY__ */ 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun /** 136*4882a593Smuzhiyun * struct mips_static_suspend_state - Core saved CPU state across S2R. 137*4882a593Smuzhiyun * @segctl: CP0 Segment control registers. 138*4882a593Smuzhiyun * @sp: Stack frame where GP register context is saved. 139*4882a593Smuzhiyun * 140*4882a593Smuzhiyun * This structure contains minimal CPU state that must be saved in static kernel 141*4882a593Smuzhiyun * data in order to be able to restore the rest of the state. This includes 142*4882a593Smuzhiyun * segmentation configuration in the case of EVA being enabled, as they must be 143*4882a593Smuzhiyun * restored prior to any kmalloc'd memory being referenced (even the stack 144*4882a593Smuzhiyun * pointer). 145*4882a593Smuzhiyun */ 146*4882a593Smuzhiyun struct mips_static_suspend_state { 147*4882a593Smuzhiyun #ifdef CONFIG_EVA 148*4882a593Smuzhiyun unsigned long segctl[3]; 149*4882a593Smuzhiyun #endif 150*4882a593Smuzhiyun unsigned long sp; 151*4882a593Smuzhiyun }; 152*4882a593Smuzhiyun 153*4882a593Smuzhiyun #endif /* !__ASSEMBLY__ */ 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun #endif /* __ASM_PM_HELPERS_H */ 156