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