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