aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/swsusp_booke.S
blob: 88cfdbd530f163bb64b81747eaf41972291912e1 (plain)
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Based on swsusp_32.S, modified for FSL BookE by
 * Anton Vorontsov <avorontsov@ru.mvista.com>
 * Copyright (c) 2009-2010 MontaVista Software, LLC.
 */

#include <linux/threads.h>
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/cputable.h>
#include <asm/thread_info.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/mmu.h>

/*
 * Structure for storing CPU registers on the save area.
 */
#define SL_SP		0
#define SL_PC		4
#define SL_MSR		8
#define SL_TCR		0xc
#define SL_SPRG0	0x10
#define SL_SPRG1	0x14
#define SL_SPRG2	0x18
#define SL_SPRG3	0x1c
#define SL_SPRG4	0x20
#define SL_SPRG5	0x24
#define SL_SPRG6	0x28
#define SL_SPRG7	0x2c
#define SL_TBU		0x30
#define SL_TBL		0x34
#define SL_R2		0x38
#define SL_CR		0x3c
#define SL_LR		0x40
#define SL_R12		0x44	/* r12 to r31 */
#define SL_SIZE		(SL_R12 + 80)

	.section .data
	.align	5

_GLOBAL(swsusp_save_area)
	.space	SL_SIZE


	.section .text
	.align	5

_GLOBAL(swsusp_arch_suspend)
	lis	r11,swsusp_save_area@h
	ori	r11,r11,swsusp_save_area@l

	mflr	r0
	stw	r0,SL_LR(r11)
	mfcr	r0
	stw	r0,SL_CR(r11)
	stw	r1,SL_SP(r11)
	stw	r2,SL_R2(r11)
	stmw	r12,SL_R12(r11)

	/* Save MSR & TCR */
	mfmsr	r4
	stw	r4,SL_MSR(r11)
	mfspr	r4,SPRN_TCR
	stw	r4,SL_TCR(r11)

	/* Get a stable timebase and save it */
1:	mfspr	r4,SPRN_TBRU
	stw	r4,SL_TBU(r11)
	mfspr	r5,SPRN_TBRL
	stw	r5,SL_TBL(r11)
	mfspr	r3,SPRN_TBRU
	cmpw	r3,r4
	bne	1b

	/* Save SPRGs */
	mfspr	r4,SPRN_SPRG0
	stw	r4,SL_SPRG0(r11)
	mfspr	r4,SPRN_SPRG1
	stw	r4,SL_SPRG1(r11)
	mfspr	r4,SPRN_SPRG2
	stw	r4,SL_SPRG2(r11)
	mfspr	r4,SPRN_SPRG3
	stw	r4,SL_SPRG3(r11)
	mfspr	r4,SPRN_SPRG4
	stw	r4,SL_SPRG4(r11)
	mfspr	r4,SPRN_SPRG5
	stw	r4,SL_SPRG5(r11)
	mfspr	r4,SPRN_SPRG6
	stw	r4,SL_SPRG6(r11)
	mfspr	r4,SPRN_SPRG7
	stw	r4,SL_SPRG7(r11)

	/* Call the low level suspend stuff (we should probably have made
	 * a stackframe...
	 */
	bl	swsusp_save

	/* Restore LR from the save area */
	lis	r11,swsusp_save_area@h
	ori	r11,r11,swsusp_save_area@l
	lwz	r0,SL_LR(r11)
	mtlr	r0

	blr

_GLOBAL(swsusp_arch_resume)
	sync

	/* Load ptr the list of pages to copy in r3 */
	lis	r11,(restore_pblist)@h
	ori	r11,r11,restore_pblist@l
	lwz	r3,0(r11)

	/* Copy the pages. This is a very basic implementation, to
	 * be replaced by something more cache efficient */
1:
	li	r0,256
	mtctr	r0
	lwz	r5,pbe_address(r3)	/* source */
	lwz	r6,pbe_orig_address(r3)	/* destination */
2:
	lwz	r8,0(r5)
	lwz	r9,4(r5)
	lwz	r10,8(r5)
	lwz	r11,12(r5)
	addi	r5,r5,16
	stw	r8,0(r6)
	stw	r9,4(r6)
	stw	r10,8(r6)
	stw	r11,12(r6)
	addi	r6,r6,16
	bdnz	2b
	lwz	r3,pbe_next(r3)
	cmpwi	0,r3,0
	bne	1b

	bl flush_dcache_L1
	bl flush_instruction_cache

	lis	r11,swsusp_save_area@h
	ori	r11,r11,swsusp_save_area@l

	/*
	 * Mappings from virtual addresses to physical addresses may be
	 * different than they were prior to restoring hibernation state. 
	 * Invalidate the TLB so that the boot CPU is using the new
	 * mappings.
	 */
	bl	_tlbil_all

	lwz	r4,SL_SPRG0(r11)
	mtspr	SPRN_SPRG0,r4
	lwz	r4,SL_SPRG1(r11)
	mtspr	SPRN_SPRG1,r4
	lwz	r4,SL_SPRG2(r11)
	mtspr	SPRN_SPRG2,r4
	lwz	r4,SL_SPRG3(r11)
	mtspr	SPRN_SPRG3,r4
	lwz	r4,SL_SPRG4(r11)
	mtspr	SPRN_SPRG4,r4
	lwz	r4,SL_SPRG5(r11)
	mtspr	SPRN_SPRG5,r4
	lwz	r4,SL_SPRG6(r11)
	mtspr	SPRN_SPRG6,r4
	lwz	r4,SL_SPRG7(r11)
	mtspr	SPRN_SPRG7,r4

	/* restore the MSR */
	lwz	r3,SL_MSR(r11)
	mtmsr	r3

	/* Restore TB */
	li	r3,0
	mtspr	SPRN_TBWL,r3
	lwz	r3,SL_TBU(r11)
	lwz	r4,SL_TBL(r11)
	mtspr	SPRN_TBWU,r3
	mtspr	SPRN_TBWL,r4

	/* Restore TCR and clear any pending bits in TSR. */
	lwz	r4,SL_TCR(r11)
	mtspr	SPRN_TCR,r4
	lis	r4, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h
	mtspr	SPRN_TSR,r4

	/* Kick decrementer */
	li	r0,1
	mtdec	r0

	/* Restore the callee-saved registers and return */
	lwz	r0,SL_CR(r11)
	mtcr	r0
	lwz	r2,SL_R2(r11)
	lmw	r12,SL_R12(r11)
	lwz	r1,SL_SP(r11)
	lwz	r0,SL_LR(r11)
	mtlr	r0

	li	r3,0
	blr