18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2014 Imagination Technologies Ltd
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * PM helper macros for CPU power off (e.g. Suspend-to-RAM).
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef __ASM_PM_H
98c2ecf20Sopenharmony_ci#define __ASM_PM_H
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifdef __ASSEMBLY__
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
148c2ecf20Sopenharmony_ci#include <asm/asm.h>
158c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
168c2ecf20Sopenharmony_ci#include <asm/regdef.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/* Save CPU state to stack for suspend to RAM */
198c2ecf20Sopenharmony_ci.macro SUSPEND_SAVE_REGS
208c2ecf20Sopenharmony_ci	subu	sp, PT_SIZE
218c2ecf20Sopenharmony_ci	/* Call preserved GPRs */
228c2ecf20Sopenharmony_ci	LONG_S	$16, PT_R16(sp)
238c2ecf20Sopenharmony_ci	LONG_S	$17, PT_R17(sp)
248c2ecf20Sopenharmony_ci	LONG_S	$18, PT_R18(sp)
258c2ecf20Sopenharmony_ci	LONG_S	$19, PT_R19(sp)
268c2ecf20Sopenharmony_ci	LONG_S	$20, PT_R20(sp)
278c2ecf20Sopenharmony_ci	LONG_S	$21, PT_R21(sp)
288c2ecf20Sopenharmony_ci	LONG_S	$22, PT_R22(sp)
298c2ecf20Sopenharmony_ci	LONG_S	$23, PT_R23(sp)
308c2ecf20Sopenharmony_ci	LONG_S	$28, PT_R28(sp)
318c2ecf20Sopenharmony_ci	LONG_S	$30, PT_R30(sp)
328c2ecf20Sopenharmony_ci	LONG_S	$31, PT_R31(sp)
338c2ecf20Sopenharmony_ci	/* A couple of CP0 registers with space in pt_regs */
348c2ecf20Sopenharmony_ci	mfc0	k0, CP0_STATUS
358c2ecf20Sopenharmony_ci	LONG_S	k0, PT_STATUS(sp)
368c2ecf20Sopenharmony_ci.endm
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* Restore CPU state from stack after resume from RAM */
398c2ecf20Sopenharmony_ci.macro RESUME_RESTORE_REGS_RETURN
408c2ecf20Sopenharmony_ci	.set	push
418c2ecf20Sopenharmony_ci	.set	noreorder
428c2ecf20Sopenharmony_ci	/* A couple of CP0 registers with space in pt_regs */
438c2ecf20Sopenharmony_ci	LONG_L	k0, PT_STATUS(sp)
448c2ecf20Sopenharmony_ci	mtc0	k0, CP0_STATUS
458c2ecf20Sopenharmony_ci	/* Call preserved GPRs */
468c2ecf20Sopenharmony_ci	LONG_L	$16, PT_R16(sp)
478c2ecf20Sopenharmony_ci	LONG_L	$17, PT_R17(sp)
488c2ecf20Sopenharmony_ci	LONG_L	$18, PT_R18(sp)
498c2ecf20Sopenharmony_ci	LONG_L	$19, PT_R19(sp)
508c2ecf20Sopenharmony_ci	LONG_L	$20, PT_R20(sp)
518c2ecf20Sopenharmony_ci	LONG_L	$21, PT_R21(sp)
528c2ecf20Sopenharmony_ci	LONG_L	$22, PT_R22(sp)
538c2ecf20Sopenharmony_ci	LONG_L	$23, PT_R23(sp)
548c2ecf20Sopenharmony_ci	LONG_L	$28, PT_R28(sp)
558c2ecf20Sopenharmony_ci	LONG_L	$30, PT_R30(sp)
568c2ecf20Sopenharmony_ci	LONG_L	$31, PT_R31(sp)
578c2ecf20Sopenharmony_ci	/* Pop and return */
588c2ecf20Sopenharmony_ci	jr	ra
598c2ecf20Sopenharmony_ci	 addiu	sp, PT_SIZE
608c2ecf20Sopenharmony_ci	.set	pop
618c2ecf20Sopenharmony_ci.endm
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Get address of static suspend state into t1 */
648c2ecf20Sopenharmony_ci.macro LA_STATIC_SUSPEND
658c2ecf20Sopenharmony_ci	la	t1, mips_static_suspend_state
668c2ecf20Sopenharmony_ci.endm
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* Save important CPU state for early restoration to global data */
698c2ecf20Sopenharmony_ci.macro SUSPEND_SAVE_STATIC
708c2ecf20Sopenharmony_ci#ifdef CONFIG_EVA
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * Segment configuration is saved in global data where it can be easily
738c2ecf20Sopenharmony_ci	 * reloaded without depending on the segment configuration.
748c2ecf20Sopenharmony_ci	 */
758c2ecf20Sopenharmony_ci	mfc0	k0, CP0_PAGEMASK, 2	/* SegCtl0 */
768c2ecf20Sopenharmony_ci	LONG_S	k0, SSS_SEGCTL0(t1)
778c2ecf20Sopenharmony_ci	mfc0	k0, CP0_PAGEMASK, 3	/* SegCtl1 */
788c2ecf20Sopenharmony_ci	LONG_S	k0, SSS_SEGCTL1(t1)
798c2ecf20Sopenharmony_ci	mfc0	k0, CP0_PAGEMASK, 4	/* SegCtl2 */
808c2ecf20Sopenharmony_ci	LONG_S	k0, SSS_SEGCTL2(t1)
818c2ecf20Sopenharmony_ci#endif
828c2ecf20Sopenharmony_ci	/* save stack pointer (pointing to GPRs) */
838c2ecf20Sopenharmony_ci	LONG_S	sp, SSS_SP(t1)
848c2ecf20Sopenharmony_ci.endm
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* Restore important CPU state early from global data */
878c2ecf20Sopenharmony_ci.macro RESUME_RESTORE_STATIC
888c2ecf20Sopenharmony_ci#ifdef CONFIG_EVA
898c2ecf20Sopenharmony_ci	/*
908c2ecf20Sopenharmony_ci	 * Segment configuration must be restored prior to any access to
918c2ecf20Sopenharmony_ci	 * allocated memory, as it may reside outside of the legacy kernel
928c2ecf20Sopenharmony_ci	 * segments.
938c2ecf20Sopenharmony_ci	 */
948c2ecf20Sopenharmony_ci	LONG_L	k0, SSS_SEGCTL0(t1)
958c2ecf20Sopenharmony_ci	mtc0	k0, CP0_PAGEMASK, 2	/* SegCtl0 */
968c2ecf20Sopenharmony_ci	LONG_L	k0, SSS_SEGCTL1(t1)
978c2ecf20Sopenharmony_ci	mtc0	k0, CP0_PAGEMASK, 3	/* SegCtl1 */
988c2ecf20Sopenharmony_ci	LONG_L	k0, SSS_SEGCTL2(t1)
998c2ecf20Sopenharmony_ci	mtc0	k0, CP0_PAGEMASK, 4	/* SegCtl2 */
1008c2ecf20Sopenharmony_ci	tlbw_use_hazard
1018c2ecf20Sopenharmony_ci#endif
1028c2ecf20Sopenharmony_ci	/* restore stack pointer (pointing to GPRs) */
1038c2ecf20Sopenharmony_ci	LONG_L	sp, SSS_SP(t1)
1048c2ecf20Sopenharmony_ci.endm
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* flush caches to make sure context has reached memory */
1078c2ecf20Sopenharmony_ci.macro SUSPEND_CACHE_FLUSH
1088c2ecf20Sopenharmony_ci	.extern	__wback_cache_all
1098c2ecf20Sopenharmony_ci	.set	push
1108c2ecf20Sopenharmony_ci	.set	noreorder
1118c2ecf20Sopenharmony_ci	la	t1, __wback_cache_all
1128c2ecf20Sopenharmony_ci	LONG_L	t0, 0(t1)
1138c2ecf20Sopenharmony_ci	jalr	t0
1148c2ecf20Sopenharmony_ci	 nop
1158c2ecf20Sopenharmony_ci	.set	pop
1168c2ecf20Sopenharmony_ci .endm
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* Save suspend state and flush data caches to RAM */
1198c2ecf20Sopenharmony_ci.macro SUSPEND_SAVE
1208c2ecf20Sopenharmony_ci	SUSPEND_SAVE_REGS
1218c2ecf20Sopenharmony_ci	LA_STATIC_SUSPEND
1228c2ecf20Sopenharmony_ci	SUSPEND_SAVE_STATIC
1238c2ecf20Sopenharmony_ci	SUSPEND_CACHE_FLUSH
1248c2ecf20Sopenharmony_ci.endm
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* Restore saved state after resume from RAM and return */
1278c2ecf20Sopenharmony_ci.macro RESUME_RESTORE_RETURN
1288c2ecf20Sopenharmony_ci	LA_STATIC_SUSPEND
1298c2ecf20Sopenharmony_ci	RESUME_RESTORE_STATIC
1308c2ecf20Sopenharmony_ci	RESUME_RESTORE_REGS_RETURN
1318c2ecf20Sopenharmony_ci.endm
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci#else /* __ASSEMBLY__ */
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/**
1368c2ecf20Sopenharmony_ci * struct mips_static_suspend_state - Core saved CPU state across S2R.
1378c2ecf20Sopenharmony_ci * @segctl:	CP0 Segment control registers.
1388c2ecf20Sopenharmony_ci * @sp:		Stack frame where GP register context is saved.
1398c2ecf20Sopenharmony_ci *
1408c2ecf20Sopenharmony_ci * This structure contains minimal CPU state that must be saved in static kernel
1418c2ecf20Sopenharmony_ci * data in order to be able to restore the rest of the state. This includes
1428c2ecf20Sopenharmony_ci * segmentation configuration in the case of EVA being enabled, as they must be
1438c2ecf20Sopenharmony_ci * restored prior to any kmalloc'd memory being referenced (even the stack
1448c2ecf20Sopenharmony_ci * pointer).
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistruct mips_static_suspend_state {
1478c2ecf20Sopenharmony_ci#ifdef CONFIG_EVA
1488c2ecf20Sopenharmony_ci	unsigned long segctl[3];
1498c2ecf20Sopenharmony_ci#endif
1508c2ecf20Sopenharmony_ci	unsigned long sp;
1518c2ecf20Sopenharmony_ci};
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#endif /* __ASM_PM_HELPERS_H */
156