aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/include/asm/pm.h
blob: 10bb7b640738363fcd5711b9666c800f2343274a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2014 Imagination Technologies Ltd
 *
 * PM helper macros for CPU power off (e.g. Suspend-to-RAM).
 */

#ifndef __ASM_PM_H
#define __ASM_PM_H

#ifdef __ASSEMBLY__

#include <asm/asm-offsets.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>

/* Save CPU state to stack for suspend to RAM */
.macro SUSPEND_SAVE_REGS
	subu	sp, PT_SIZE
	/* Call preserved GPRs */
	LONG_S	$16, PT_R16(sp)
	LONG_S	$17, PT_R17(sp)
	LONG_S	$18, PT_R18(sp)
	LONG_S	$19, PT_R19(sp)
	LONG_S	$20, PT_R20(sp)
	LONG_S	$21, PT_R21(sp)
	LONG_S	$22, PT_R22(sp)
	LONG_S	$23, PT_R23(sp)
	LONG_S	$28, PT_R28(sp)
	LONG_S	$30, PT_R30(sp)
	LONG_S	$31, PT_R31(sp)
	/* A couple of CP0 registers with space in pt_regs */
	mfc0	k0, CP0_STATUS
	LONG_S	k0, PT_STATUS(sp)
.endm

/* Restore CPU state from stack after resume from RAM */
.macro RESUME_RESTORE_REGS_RETURN
	.set	push
	.set	noreorder
	/* A couple of CP0 registers with space in pt_regs */
	LONG_L	k0, PT_STATUS(sp)
	mtc0	k0, CP0_STATUS
	/* Call preserved GPRs */
	LONG_L	$16, PT_R16(sp)
	LONG_L	$17, PT_R17(sp)
	LONG_L	$18, PT_R18(sp)
	LONG_L	$19, PT_R19(sp)
	LONG_L	$20, PT_R20(sp)
	LONG_L	$21, PT_R21(sp)
	LONG_L	$22, PT_R22(sp)
	LONG_L	$23, PT_R23(sp)
	LONG_L	$28, PT_R28(sp)
	LONG_L	$30, PT_R30(sp)
	LONG_L	$31, PT_R31(sp)
	/* Pop and return */
	jr	ra
	 addiu	sp, PT_SIZE
	.set	pop
.endm

/* Get address of static suspend state into t1 */
.macro LA_STATIC_SUSPEND
	la	t1, mips_static_suspend_state
.endm

/* Save important CPU state for early restoration to global data */
.macro SUSPEND_SAVE_STATIC
#ifdef CONFIG_EVA
	/*
	 * Segment configuration is saved in global data where it can be easily
	 * reloaded without depending on the segment configuration.
	 */
	mfc0	k0, CP0_PAGEMASK, 2	/* SegCtl0 */
	LONG_S	k0, SSS_SEGCTL0(t1)
	mfc0	k0, CP0_PAGEMASK, 3	/* SegCtl1 */
	LONG_S	k0, SSS_SEGCTL1(t1)
	mfc0	k0, CP0_PAGEMASK, 4	/* SegCtl2 */
	LONG_S	k0, SSS_SEGCTL2(t1)
#endif
	/* save stack pointer (pointing to GPRs) */
	LONG_S	sp, SSS_SP(t1)
.endm

/* Restore important CPU state early from global data */
.macro RESUME_RESTORE_STATIC
#ifdef CONFIG_EVA
	/*
	 * Segment configuration must be restored prior to any access to
	 * allocated memory, as it may reside outside of the legacy kernel
	 * segments.
	 */
	LONG_L	k0, SSS_SEGCTL0(t1)
	mtc0	k0, CP0_PAGEMASK, 2	/* SegCtl0 */
	LONG_L	k0, SSS_SEGCTL1(t1)
	mtc0	k0, CP0_PAGEMASK, 3	/* SegCtl1 */
	LONG_L	k0, SSS_SEGCTL2(t1)
	mtc0	k0, CP0_PAGEMASK, 4	/* SegCtl2 */
	tlbw_use_hazard
#endif
	/* restore stack pointer (pointing to GPRs) */
	LONG_L	sp, SSS_SP(t1)
.endm

/* flush caches to make sure context has reached memory */
.macro SUSPEND_CACHE_FLUSH
	.extern	__wback_cache_all
	.set	push
	.set	noreorder
	la	t1, __wback_cache_all
	LONG_L	t0, 0(t1)
	jalr	t0
	 nop
	.set	pop
 .endm

/* Save suspend state and flush data caches to RAM */
.macro SUSPEND_SAVE
	SUSPEND_SAVE_REGS
	LA_STATIC_SUSPEND
	SUSPEND_SAVE_STATIC
	SUSPEND_CACHE_FLUSH
.endm

/* Restore saved state after resume from RAM and return */
.macro RESUME_RESTORE_RETURN
	LA_STATIC_SUSPEND
	RESUME_RESTORE_STATIC
	RESUME_RESTORE_REGS_RETURN
.endm

#else /* __ASSEMBLY__ */

/**
 * struct mips_static_suspend_state - Core saved CPU state across S2R.
 * @segctl:	CP0 Segment control registers.
 * @sp:		Stack frame where GP register context is saved.
 *
 * This structure contains minimal CPU state that must be saved in static kernel
 * data in order to be able to restore the rest of the state. This includes
 * segmentation configuration in the case of EVA being enabled, as they must be
 * restored prior to any kmalloc'd memory being referenced (even the stack
 * pointer).
 */
struct mips_static_suspend_state {
#ifdef CONFIG_EVA
	unsigned long segctl[3];
#endif
	unsigned long sp;
};

#endif /* !__ASSEMBLY__ */

#endif /* __ASM_PM_HELPERS_H */