162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014 Imagination Technologies Ltd 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * PM helper macros for CPU power off (e.g. Suspend-to-RAM). 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef __ASM_PM_H 962306a36Sopenharmony_ci#define __ASM_PM_H 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#ifdef __ASSEMBLY__ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1462306a36Sopenharmony_ci#include <asm/asm.h> 1562306a36Sopenharmony_ci#include <asm/mipsregs.h> 1662306a36Sopenharmony_ci#include <asm/regdef.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* Save CPU state to stack for suspend to RAM */ 1962306a36Sopenharmony_ci.macro SUSPEND_SAVE_REGS 2062306a36Sopenharmony_ci subu sp, PT_SIZE 2162306a36Sopenharmony_ci /* Call preserved GPRs */ 2262306a36Sopenharmony_ci LONG_S $16, PT_R16(sp) 2362306a36Sopenharmony_ci LONG_S $17, PT_R17(sp) 2462306a36Sopenharmony_ci LONG_S $18, PT_R18(sp) 2562306a36Sopenharmony_ci LONG_S $19, PT_R19(sp) 2662306a36Sopenharmony_ci LONG_S $20, PT_R20(sp) 2762306a36Sopenharmony_ci LONG_S $21, PT_R21(sp) 2862306a36Sopenharmony_ci LONG_S $22, PT_R22(sp) 2962306a36Sopenharmony_ci LONG_S $23, PT_R23(sp) 3062306a36Sopenharmony_ci LONG_S $28, PT_R28(sp) 3162306a36Sopenharmony_ci LONG_S $30, PT_R30(sp) 3262306a36Sopenharmony_ci LONG_S $31, PT_R31(sp) 3362306a36Sopenharmony_ci /* A couple of CP0 registers with space in pt_regs */ 3462306a36Sopenharmony_ci mfc0 k0, CP0_STATUS 3562306a36Sopenharmony_ci LONG_S k0, PT_STATUS(sp) 3662306a36Sopenharmony_ci.endm 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* Restore CPU state from stack after resume from RAM */ 3962306a36Sopenharmony_ci.macro RESUME_RESTORE_REGS_RETURN 4062306a36Sopenharmony_ci .set push 4162306a36Sopenharmony_ci .set noreorder 4262306a36Sopenharmony_ci /* A couple of CP0 registers with space in pt_regs */ 4362306a36Sopenharmony_ci LONG_L k0, PT_STATUS(sp) 4462306a36Sopenharmony_ci mtc0 k0, CP0_STATUS 4562306a36Sopenharmony_ci /* Call preserved GPRs */ 4662306a36Sopenharmony_ci LONG_L $16, PT_R16(sp) 4762306a36Sopenharmony_ci LONG_L $17, PT_R17(sp) 4862306a36Sopenharmony_ci LONG_L $18, PT_R18(sp) 4962306a36Sopenharmony_ci LONG_L $19, PT_R19(sp) 5062306a36Sopenharmony_ci LONG_L $20, PT_R20(sp) 5162306a36Sopenharmony_ci LONG_L $21, PT_R21(sp) 5262306a36Sopenharmony_ci LONG_L $22, PT_R22(sp) 5362306a36Sopenharmony_ci LONG_L $23, PT_R23(sp) 5462306a36Sopenharmony_ci LONG_L $28, PT_R28(sp) 5562306a36Sopenharmony_ci LONG_L $30, PT_R30(sp) 5662306a36Sopenharmony_ci LONG_L $31, PT_R31(sp) 5762306a36Sopenharmony_ci /* Pop and return */ 5862306a36Sopenharmony_ci jr ra 5962306a36Sopenharmony_ci addiu sp, PT_SIZE 6062306a36Sopenharmony_ci .set pop 6162306a36Sopenharmony_ci.endm 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Get address of static suspend state into t1 */ 6462306a36Sopenharmony_ci.macro LA_STATIC_SUSPEND 6562306a36Sopenharmony_ci la t1, mips_static_suspend_state 6662306a36Sopenharmony_ci.endm 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* Save important CPU state for early restoration to global data */ 6962306a36Sopenharmony_ci.macro SUSPEND_SAVE_STATIC 7062306a36Sopenharmony_ci#ifdef CONFIG_EVA 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * Segment configuration is saved in global data where it can be easily 7362306a36Sopenharmony_ci * reloaded without depending on the segment configuration. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci mfc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ 7662306a36Sopenharmony_ci LONG_S k0, SSS_SEGCTL0(t1) 7762306a36Sopenharmony_ci mfc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ 7862306a36Sopenharmony_ci LONG_S k0, SSS_SEGCTL1(t1) 7962306a36Sopenharmony_ci mfc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ 8062306a36Sopenharmony_ci LONG_S k0, SSS_SEGCTL2(t1) 8162306a36Sopenharmony_ci#endif 8262306a36Sopenharmony_ci /* save stack pointer (pointing to GPRs) */ 8362306a36Sopenharmony_ci LONG_S sp, SSS_SP(t1) 8462306a36Sopenharmony_ci.endm 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Restore important CPU state early from global data */ 8762306a36Sopenharmony_ci.macro RESUME_RESTORE_STATIC 8862306a36Sopenharmony_ci#ifdef CONFIG_EVA 8962306a36Sopenharmony_ci /* 9062306a36Sopenharmony_ci * Segment configuration must be restored prior to any access to 9162306a36Sopenharmony_ci * allocated memory, as it may reside outside of the legacy kernel 9262306a36Sopenharmony_ci * segments. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci LONG_L k0, SSS_SEGCTL0(t1) 9562306a36Sopenharmony_ci mtc0 k0, CP0_PAGEMASK, 2 /* SegCtl0 */ 9662306a36Sopenharmony_ci LONG_L k0, SSS_SEGCTL1(t1) 9762306a36Sopenharmony_ci mtc0 k0, CP0_PAGEMASK, 3 /* SegCtl1 */ 9862306a36Sopenharmony_ci LONG_L k0, SSS_SEGCTL2(t1) 9962306a36Sopenharmony_ci mtc0 k0, CP0_PAGEMASK, 4 /* SegCtl2 */ 10062306a36Sopenharmony_ci tlbw_use_hazard 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_ci /* restore stack pointer (pointing to GPRs) */ 10362306a36Sopenharmony_ci LONG_L sp, SSS_SP(t1) 10462306a36Sopenharmony_ci.endm 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* flush caches to make sure context has reached memory */ 10762306a36Sopenharmony_ci.macro SUSPEND_CACHE_FLUSH 10862306a36Sopenharmony_ci .extern __wback_cache_all 10962306a36Sopenharmony_ci .set push 11062306a36Sopenharmony_ci .set noreorder 11162306a36Sopenharmony_ci la t1, __wback_cache_all 11262306a36Sopenharmony_ci LONG_L t0, 0(t1) 11362306a36Sopenharmony_ci jalr t0 11462306a36Sopenharmony_ci nop 11562306a36Sopenharmony_ci .set pop 11662306a36Sopenharmony_ci .endm 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* Save suspend state and flush data caches to RAM */ 11962306a36Sopenharmony_ci.macro SUSPEND_SAVE 12062306a36Sopenharmony_ci SUSPEND_SAVE_REGS 12162306a36Sopenharmony_ci LA_STATIC_SUSPEND 12262306a36Sopenharmony_ci SUSPEND_SAVE_STATIC 12362306a36Sopenharmony_ci SUSPEND_CACHE_FLUSH 12462306a36Sopenharmony_ci.endm 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* Restore saved state after resume from RAM and return */ 12762306a36Sopenharmony_ci.macro RESUME_RESTORE_RETURN 12862306a36Sopenharmony_ci LA_STATIC_SUSPEND 12962306a36Sopenharmony_ci RESUME_RESTORE_STATIC 13062306a36Sopenharmony_ci RESUME_RESTORE_REGS_RETURN 13162306a36Sopenharmony_ci.endm 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#else /* __ASSEMBLY__ */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/** 13662306a36Sopenharmony_ci * struct mips_static_suspend_state - Core saved CPU state across S2R. 13762306a36Sopenharmony_ci * @segctl: CP0 Segment control registers. 13862306a36Sopenharmony_ci * @sp: Stack frame where GP register context is saved. 13962306a36Sopenharmony_ci * 14062306a36Sopenharmony_ci * This structure contains minimal CPU state that must be saved in static kernel 14162306a36Sopenharmony_ci * data in order to be able to restore the rest of the state. This includes 14262306a36Sopenharmony_ci * segmentation configuration in the case of EVA being enabled, as they must be 14362306a36Sopenharmony_ci * restored prior to any kmalloc'd memory being referenced (even the stack 14462306a36Sopenharmony_ci * pointer). 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistruct mips_static_suspend_state { 14762306a36Sopenharmony_ci#ifdef CONFIG_EVA 14862306a36Sopenharmony_ci unsigned long segctl[3]; 14962306a36Sopenharmony_ci#endif 15062306a36Sopenharmony_ci unsigned long sp; 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci#endif /* __ASM_PM_HELPERS_H */ 156