1/*
2 * Based on swsusp_32.S, modified for FSL BookE by
3 * Anton Vorontsov <avorontsov@ru.mvista.com>
4 * Copyright (c) 2009-2010 MontaVista Software, LLC.
5 */
6
7#include <linux/threads.h>
8#include <asm/processor.h>
9#include <asm/page.h>
10#include <asm/cputable.h>
11#include <asm/thread_info.h>
12#include <asm/ppc_asm.h>
13#include <asm/asm-offsets.h>
14#include <asm/mmu.h>
15
16/*
17 * Structure for storing CPU registers on the save area.
18 */
19#define SL_SP		0
20#define SL_PC		4
21#define SL_MSR		8
22#define SL_TCR		0xc
23#define SL_SPRG0	0x10
24#define SL_SPRG1	0x14
25#define SL_SPRG2	0x18
26#define SL_SPRG3	0x1c
27#define SL_SPRG4	0x20
28#define SL_SPRG5	0x24
29#define SL_SPRG6	0x28
30#define SL_SPRG7	0x2c
31#define SL_TBU		0x30
32#define SL_TBL		0x34
33#define SL_R2		0x38
34#define SL_CR		0x3c
35#define SL_LR		0x40
36#define SL_R12		0x44	/* r12 to r31 */
37#define SL_SIZE		(SL_R12 + 80)
38
39	.section .data
40	.align	5
41
42_GLOBAL(swsusp_save_area)
43	.space	SL_SIZE
44
45
46	.section .text
47	.align	5
48
49_GLOBAL(swsusp_arch_suspend)
50	lis	r11,swsusp_save_area@h
51	ori	r11,r11,swsusp_save_area@l
52
53	mflr	r0
54	stw	r0,SL_LR(r11)
55	mfcr	r0
56	stw	r0,SL_CR(r11)
57	stw	r1,SL_SP(r11)
58	stw	r2,SL_R2(r11)
59	stmw	r12,SL_R12(r11)
60
61	/* Save MSR & TCR */
62	mfmsr	r4
63	stw	r4,SL_MSR(r11)
64	mfspr	r4,SPRN_TCR
65	stw	r4,SL_TCR(r11)
66
67	/* Get a stable timebase and save it */
681:	mfspr	r4,SPRN_TBRU
69	stw	r4,SL_TBU(r11)
70	mfspr	r5,SPRN_TBRL
71	stw	r5,SL_TBL(r11)
72	mfspr	r3,SPRN_TBRU
73	cmpw	r3,r4
74	bne	1b
75
76	/* Save SPRGs */
77	mfspr	r4,SPRN_SPRG0
78	stw	r4,SL_SPRG0(r11)
79	mfspr	r4,SPRN_SPRG1
80	stw	r4,SL_SPRG1(r11)
81	mfspr	r4,SPRN_SPRG2
82	stw	r4,SL_SPRG2(r11)
83	mfspr	r4,SPRN_SPRG3
84	stw	r4,SL_SPRG3(r11)
85	mfspr	r4,SPRN_SPRG4
86	stw	r4,SL_SPRG4(r11)
87	mfspr	r4,SPRN_SPRG5
88	stw	r4,SL_SPRG5(r11)
89	mfspr	r4,SPRN_SPRG6
90	stw	r4,SL_SPRG6(r11)
91	mfspr	r4,SPRN_SPRG7
92	stw	r4,SL_SPRG7(r11)
93
94	/* Call the low level suspend stuff (we should probably have made
95	 * a stackframe...
96	 */
97	bl	swsusp_save
98
99	/* Restore LR from the save area */
100	lis	r11,swsusp_save_area@h
101	ori	r11,r11,swsusp_save_area@l
102	lwz	r0,SL_LR(r11)
103	mtlr	r0
104
105	blr
106
107_GLOBAL(swsusp_arch_resume)
108	sync
109
110	/* Load ptr the list of pages to copy in r3 */
111	lis	r11,(restore_pblist)@h
112	ori	r11,r11,restore_pblist@l
113	lwz	r3,0(r11)
114
115	/* Copy the pages. This is a very basic implementation, to
116	 * be replaced by something more cache efficient */
1171:
118	li	r0,256
119	mtctr	r0
120	lwz	r5,pbe_address(r3)	/* source */
121	lwz	r6,pbe_orig_address(r3)	/* destination */
1222:
123	lwz	r8,0(r5)
124	lwz	r9,4(r5)
125	lwz	r10,8(r5)
126	lwz	r11,12(r5)
127	addi	r5,r5,16
128	stw	r8,0(r6)
129	stw	r9,4(r6)
130	stw	r10,8(r6)
131	stw	r11,12(r6)
132	addi	r6,r6,16
133	bdnz	2b
134	lwz	r3,pbe_next(r3)
135	cmpwi	0,r3,0
136	bne	1b
137
138	bl flush_dcache_L1
139	bl flush_instruction_cache
140
141	lis	r11,swsusp_save_area@h
142	ori	r11,r11,swsusp_save_area@l
143
144	/*
145	 * Mappings from virtual addresses to physical addresses may be
146	 * different than they were prior to restoring hibernation state.
147	 * Invalidate the TLB so that the boot CPU is using the new
148	 * mappings.
149	 */
150	bl	_tlbil_all
151
152	lwz	r4,SL_SPRG0(r11)
153	mtspr	SPRN_SPRG0,r4
154	lwz	r4,SL_SPRG1(r11)
155	mtspr	SPRN_SPRG1,r4
156	lwz	r4,SL_SPRG2(r11)
157	mtspr	SPRN_SPRG2,r4
158	lwz	r4,SL_SPRG3(r11)
159	mtspr	SPRN_SPRG3,r4
160	lwz	r4,SL_SPRG4(r11)
161	mtspr	SPRN_SPRG4,r4
162	lwz	r4,SL_SPRG5(r11)
163	mtspr	SPRN_SPRG5,r4
164	lwz	r4,SL_SPRG6(r11)
165	mtspr	SPRN_SPRG6,r4
166	lwz	r4,SL_SPRG7(r11)
167	mtspr	SPRN_SPRG7,r4
168
169	/* restore the MSR */
170	lwz	r3,SL_MSR(r11)
171	mtmsr	r3
172
173	/* Restore TB */
174	li	r3,0
175	mtspr	SPRN_TBWL,r3
176	lwz	r3,SL_TBU(r11)
177	lwz	r4,SL_TBL(r11)
178	mtspr	SPRN_TBWU,r3
179	mtspr	SPRN_TBWL,r4
180
181	/* Restore TCR and clear any pending bits in TSR. */
182	lwz	r4,SL_TCR(r11)
183	mtspr	SPRN_TCR,r4
184	lis	r4, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h
185	mtspr	SPRN_TSR,r4
186
187	/* Kick decrementer */
188	li	r0,1
189	mtdec	r0
190
191	/* Restore the callee-saved registers and return */
192	lwz	r0,SL_CR(r11)
193	mtcr	r0
194	lwz	r2,SL_R2(r11)
195	lmw	r12,SL_R12(r11)
196	lwz	r1,SL_SP(r11)
197	lwz	r0,SL_LR(r11)
198	mtlr	r0
199
200	li	r3,0
201	blr
202