diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/frv/kernel/sleep.S |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/frv/kernel/sleep.S')
-rw-r--r-- | arch/frv/kernel/sleep.S | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/arch/frv/kernel/sleep.S b/arch/frv/kernel/sleep.S new file mode 100644 index 000000000000..e6079b8cac60 --- /dev/null +++ b/arch/frv/kernel/sleep.S | |||
@@ -0,0 +1,374 @@ | |||
1 | /* sleep.S: power saving mode entry | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Woodhouse (dwmw2@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/sys.h> | ||
14 | #include <linux/config.h> | ||
15 | #include <linux/linkage.h> | ||
16 | #include <asm/setup.h> | ||
17 | #include <asm/segment.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/ptrace.h> | ||
20 | #include <asm/errno.h> | ||
21 | #include <asm/cache.h> | ||
22 | #include <asm/spr-regs.h> | ||
23 | |||
24 | #define __addr_MASK 0xfeff9820 /* interrupt controller mask */ | ||
25 | |||
26 | #define __addr_FR55X_DRCN 0xfeff0218 /* Address of DRCN register */ | ||
27 | #define FR55X_DSTS_OFFSET -4 /* Offset from DRCN to DSTS */ | ||
28 | #define FR55X_SDRAMC_DSTS_SSI 0x00000002 /* indicates that the SDRAM is in self-refresh mode */ | ||
29 | |||
30 | #define __addr_FR4XX_DRCN 0xfe000430 /* Address of DRCN register */ | ||
31 | #define FR4XX_DSTS_OFFSET -8 /* Offset from DRCN to DSTS */ | ||
32 | #define FR4XX_SDRAMC_DSTS_SSI 0x00000001 /* indicates that the SDRAM is in self-refresh mode */ | ||
33 | |||
34 | #define SDRAMC_DRCN_SR 0x00000001 /* transition SDRAM into self-refresh mode */ | ||
35 | |||
36 | .section .bss | ||
37 | .balign 8 | ||
38 | .globl __sleep_save_area | ||
39 | __sleep_save_area: | ||
40 | .space 16 | ||
41 | |||
42 | |||
43 | .text | ||
44 | .balign 4 | ||
45 | |||
46 | .macro li v r | ||
47 | sethi.p %hi(\v),\r | ||
48 | setlo %lo(\v),\r | ||
49 | .endm | ||
50 | |||
51 | #ifdef CONFIG_PM | ||
52 | ############################################################################### | ||
53 | # | ||
54 | # CPU suspension routine | ||
55 | # - void frv_cpu_suspend(unsigned long pdm_mode) | ||
56 | # | ||
57 | ############################################################################### | ||
58 | .globl frv_cpu_suspend | ||
59 | .type frv_cpu_suspend,@function | ||
60 | frv_cpu_suspend: | ||
61 | |||
62 | #---------------------------------------------------- | ||
63 | # save hsr0, psr, isr, and lr for resume code | ||
64 | #---------------------------------------------------- | ||
65 | li __sleep_save_area,gr11 | ||
66 | |||
67 | movsg hsr0,gr4 | ||
68 | movsg psr,gr5 | ||
69 | movsg isr,gr6 | ||
70 | movsg lr,gr7 | ||
71 | stdi gr4,@(gr11,#0) | ||
72 | stdi gr6,@(gr11,#8) | ||
73 | |||
74 | # store the return address from sleep in GR14, and its complement in GR13 as a check | ||
75 | li __ramboot_resume,gr14 | ||
76 | #ifdef CONFIG_MMU | ||
77 | # Resume via RAMBOOT# will turn MMU off, so bootloader needs a physical address. | ||
78 | sethi.p %hi(__page_offset),gr13 | ||
79 | setlo %lo(__page_offset),gr13 | ||
80 | sub gr14,gr13,gr14 | ||
81 | #endif | ||
82 | not gr14,gr13 | ||
83 | |||
84 | #---------------------------------------------------- | ||
85 | # preload and lock into icache that code which may have to run | ||
86 | # when dram is in self-refresh state. | ||
87 | #---------------------------------------------------- | ||
88 | movsg hsr0, gr3 | ||
89 | li HSR0_ICE,gr4 | ||
90 | or gr3,gr4,gr3 | ||
91 | movgs gr3,hsr0 | ||
92 | or gr3,gr8,gr7 // add the sleep bits for later | ||
93 | |||
94 | li #__icache_lock_start,gr3 | ||
95 | li #__icache_lock_end,gr4 | ||
96 | 1: icpl gr3,gr0,#1 | ||
97 | addi gr3,#L1_CACHE_BYTES,gr3 | ||
98 | cmp gr4,gr3,icc0 | ||
99 | bhi icc0,#0,1b | ||
100 | |||
101 | # disable exceptions | ||
102 | movsg psr,gr8 | ||
103 | andi.p gr8,#~PSR_PIL,gr8 | ||
104 | andi gr8,~PSR_ET,gr8 | ||
105 | movgs gr8,psr | ||
106 | ori gr8,#PSR_ET,gr8 | ||
107 | |||
108 | srli gr8,#28,gr4 | ||
109 | subicc gr4,#3,gr0,icc0 | ||
110 | beq icc0,#0,1f | ||
111 | # FR4xx | ||
112 | li __addr_FR4XX_DRCN,gr4 | ||
113 | li FR4XX_SDRAMC_DSTS_SSI,gr5 | ||
114 | li FR4XX_DSTS_OFFSET,gr6 | ||
115 | bra __icache_lock_start | ||
116 | 1: | ||
117 | # FR5xx | ||
118 | li __addr_FR55X_DRCN,gr4 | ||
119 | li FR55X_SDRAMC_DSTS_SSI,gr5 | ||
120 | li FR55X_DSTS_OFFSET,gr6 | ||
121 | bra __icache_lock_start | ||
122 | |||
123 | .size frv_cpu_suspend, .-frv_cpu_suspend | ||
124 | |||
125 | # | ||
126 | # the final part of the sleep sequence... | ||
127 | # - we want it to be be cacheline aligned so we can lock it into the icache easily | ||
128 | # On entry: gr7 holds desired hsr0 sleep value | ||
129 | # gr8 holds desired psr sleep value | ||
130 | # | ||
131 | .balign L1_CACHE_BYTES | ||
132 | .type __icache_lock_start,@function | ||
133 | __icache_lock_start: | ||
134 | |||
135 | #---------------------------------------------------- | ||
136 | # put SDRAM in self-refresh mode | ||
137 | #---------------------------------------------------- | ||
138 | |||
139 | # Flush all data in the cache using the DCEF instruction. | ||
140 | dcef @(gr0,gr0),#1 | ||
141 | |||
142 | # Stop DMAC transfer | ||
143 | |||
144 | # Execute dummy load from SDRAM | ||
145 | ldi @(gr11,#0),gr11 | ||
146 | |||
147 | # put the SDRAM into self-refresh mode | ||
148 | ld @(gr4,gr0),gr11 | ||
149 | ori gr11,#SDRAMC_DRCN_SR,gr11 | ||
150 | st gr11,@(gr4,gr0) | ||
151 | membar | ||
152 | |||
153 | # wait for SDRAM to reach self-refresh mode | ||
154 | 1: ld @(gr4,gr6),gr11 | ||
155 | andcc gr11,gr5,gr11,icc0 | ||
156 | beq icc0,#0,1b | ||
157 | |||
158 | # Set the GPIO register so that the IRQ[3:0] pins become valid, as required. | ||
159 | # Set the clock mode (CLKC register) as required. | ||
160 | # - At this time, also set the CLKC register P0 bit. | ||
161 | |||
162 | # Set the HSR0 register PDM field. | ||
163 | movgs gr7,hsr0 | ||
164 | |||
165 | # Execute NOP 32 times. | ||
166 | .rept 32 | ||
167 | nop | ||
168 | .endr | ||
169 | |||
170 | #if 0 // Fujitsu recommend to skip this and will update docs. | ||
171 | # Release the interrupt mask setting of the MASK register of the | ||
172 | # interrupt controller if necessary. | ||
173 | sti gr10,@(gr9,#0) | ||
174 | membar | ||
175 | #endif | ||
176 | |||
177 | # Set the PSR register ET bit to 1 to enable interrupts. | ||
178 | movgs gr8,psr | ||
179 | |||
180 | ################################################### | ||
181 | # this is only reached if waking up via interrupt | ||
182 | ################################################### | ||
183 | |||
184 | # Execute NOP 32 times. | ||
185 | .rept 32 | ||
186 | nop | ||
187 | .endr | ||
188 | |||
189 | #---------------------------------------------------- | ||
190 | # wake SDRAM from self-refresh mode | ||
191 | #---------------------------------------------------- | ||
192 | ld @(gr4,gr0),gr11 | ||
193 | andi gr11,#~SDRAMC_DRCN_SR,gr11 | ||
194 | st gr11,@(gr4,gr0) | ||
195 | membar | ||
196 | 2: | ||
197 | ld @(gr4,gr6),gr11 // Wait for it to come back... | ||
198 | andcc gr11,gr5,gr0,icc0 | ||
199 | bne icc0,0,2b | ||
200 | |||
201 | # wait for the SDRAM to stabilise | ||
202 | li 0x0100000,gr3 | ||
203 | 3: subicc gr3,#1,gr3,icc0 | ||
204 | bne icc0,#0,3b | ||
205 | |||
206 | # now that DRAM is back, this is the end of the code which gets | ||
207 | # locked in icache. | ||
208 | __icache_lock_end: | ||
209 | .size __icache_lock_start, .-__icache_lock_start | ||
210 | |||
211 | # Fall-through to the RAMBOOT# wakeup path | ||
212 | |||
213 | ############################################################################### | ||
214 | # | ||
215 | # resume from suspend re-entry point reached via RAMBOOT# and bootloader | ||
216 | # | ||
217 | ############################################################################### | ||
218 | __ramboot_resume: | ||
219 | |||
220 | #---------------------------------------------------- | ||
221 | # restore hsr0, psr, isr, and leave saved lr in gr7 | ||
222 | #---------------------------------------------------- | ||
223 | li __sleep_save_area,gr11 | ||
224 | #ifdef CONFIG_MMU | ||
225 | movsg hsr0,gr4 | ||
226 | sethi.p %hi(HSR0_EXMMU),gr3 | ||
227 | setlo %lo(HSR0_EXMMU),gr3 | ||
228 | andcc gr3,gr4,gr0,icc0 | ||
229 | bne icc0,#0,2f | ||
230 | |||
231 | # need to use physical address | ||
232 | sethi.p %hi(__page_offset),gr3 | ||
233 | setlo %lo(__page_offset),gr3 | ||
234 | sub gr11,gr3,gr11 | ||
235 | |||
236 | # flush all tlb entries | ||
237 | setlos #64,gr4 | ||
238 | setlos.p #PAGE_SIZE,gr5 | ||
239 | setlos #0,gr6 | ||
240 | 1: | ||
241 | tlbpr gr6,gr0,#6,#0 | ||
242 | subicc.p gr4,#1,gr4,icc0 | ||
243 | add gr6,gr5,gr6 | ||
244 | bne icc0,#2,1b | ||
245 | |||
246 | # need a temporary mapping for the current physical address we are | ||
247 | # using between time MMU is enabled and jump to virtual address is | ||
248 | # made. | ||
249 | sethi.p %hi(0x00000000),gr4 | ||
250 | setlo %lo(0x00000000),gr4 ; physical address | ||
251 | setlos #xAMPRx_L|xAMPRx_M|xAMPRx_SS_256Mb|xAMPRx_S_KERNEL|xAMPRx_V,gr5 | ||
252 | or gr4,gr5,gr5 | ||
253 | |||
254 | movsg cxnr,gr13 | ||
255 | or gr4,gr13,gr4 | ||
256 | |||
257 | movgs gr4,iamlr1 ; mapped from real address 0 | ||
258 | movgs gr5,iampr1 ; cached kernel memory at 0x00000000 | ||
259 | 2: | ||
260 | #endif | ||
261 | |||
262 | lddi @(gr11,#0),gr4 ; hsr0, psr | ||
263 | lddi @(gr11,#8),gr6 ; isr, lr | ||
264 | movgs gr4,hsr0 | ||
265 | bar | ||
266 | |||
267 | #ifdef CONFIG_MMU | ||
268 | sethi.p %hi(1f),gr11 | ||
269 | setlo %lo(1f),gr11 | ||
270 | jmpl @(gr11,gr0) | ||
271 | 1: | ||
272 | movgs gr0,iampr1 ; get rid of temporary mapping | ||
273 | #endif | ||
274 | movgs gr5,psr | ||
275 | movgs gr6,isr | ||
276 | |||
277 | #---------------------------------------------------- | ||
278 | # unlock the icache which was locked before going to sleep | ||
279 | #---------------------------------------------------- | ||
280 | li __icache_lock_start,gr3 | ||
281 | li __icache_lock_end,gr4 | ||
282 | 1: icul gr3 | ||
283 | addi gr3,#L1_CACHE_BYTES,gr3 | ||
284 | cmp gr4,gr3,icc0 | ||
285 | bhi icc0,#0,1b | ||
286 | |||
287 | #---------------------------------------------------- | ||
288 | # back to business as usual | ||
289 | #---------------------------------------------------- | ||
290 | jmpl @(gr7,gr0) ; | ||
291 | |||
292 | #endif /* CONFIG_PM */ | ||
293 | |||
294 | ############################################################################### | ||
295 | # | ||
296 | # CPU core sleep mode routine | ||
297 | # | ||
298 | ############################################################################### | ||
299 | .globl frv_cpu_core_sleep | ||
300 | .type frv_cpu_core_sleep,@function | ||
301 | frv_cpu_core_sleep: | ||
302 | |||
303 | # Preload into icache. | ||
304 | li #__core_sleep_icache_lock_start,gr3 | ||
305 | li #__core_sleep_icache_lock_end,gr4 | ||
306 | |||
307 | 1: icpl gr3,gr0,#1 | ||
308 | addi gr3,#L1_CACHE_BYTES,gr3 | ||
309 | cmp gr4,gr3,icc0 | ||
310 | bhi icc0,#0,1b | ||
311 | |||
312 | bra __core_sleep_icache_lock_start | ||
313 | |||
314 | .balign L1_CACHE_BYTES | ||
315 | __core_sleep_icache_lock_start: | ||
316 | |||
317 | # (1) Set the PSR register ET bit to 0 to disable interrupts. | ||
318 | movsg psr,gr8 | ||
319 | andi.p gr8,#~(PSR_PIL),gr8 | ||
320 | andi gr8,#~(PSR_ET),gr4 | ||
321 | movgs gr4,psr | ||
322 | |||
323 | #if 0 // Fujitsu recommend to skip this and will update docs. | ||
324 | # (2) Set '1' to all bits in the MASK register of the interrupt | ||
325 | # controller and mask interrupts. | ||
326 | sethi.p %hi(__addr_MASK),gr9 | ||
327 | setlo %lo(__addr_MASK),gr9 | ||
328 | sethi.p %hi(0xffff0000),gr4 | ||
329 | setlo %lo(0xffff0000),gr4 | ||
330 | ldi @(gr9,#0),gr10 | ||
331 | sti gr4,@(gr9,#0) | ||
332 | #endif | ||
333 | # (3) Flush all data in the cache using the DCEF instruction. | ||
334 | dcef @(gr0,gr0),#1 | ||
335 | |||
336 | # (4) Execute the memory barrier instruction | ||
337 | membar | ||
338 | |||
339 | # (5) Set the GPIO register so that the IRQ[3:0] pins become valid, as required. | ||
340 | # (6) Set the clock mode (CLKC register) as required. | ||
341 | # - At this time, also set the CLKC register P0 bit. | ||
342 | # (7) Set the HSR0 register PDM field to 001 . | ||
343 | movsg hsr0,gr4 | ||
344 | ori gr4,HSR0_PDM_CORE_SLEEP,gr4 | ||
345 | movgs gr4,hsr0 | ||
346 | |||
347 | # (8) Execute NOP 32 times. | ||
348 | .rept 32 | ||
349 | nop | ||
350 | .endr | ||
351 | |||
352 | #if 0 // Fujitsu recommend to skip this and will update docs. | ||
353 | # (9) Release the interrupt mask setting of the MASK register of the | ||
354 | # interrupt controller if necessary. | ||
355 | sti gr10,@(gr9,#0) | ||
356 | membar | ||
357 | #endif | ||
358 | |||
359 | # (10) Set the PSR register ET bit to 1 to enable interrupts. | ||
360 | movgs gr8,psr | ||
361 | |||
362 | __core_sleep_icache_lock_end: | ||
363 | |||
364 | # Unlock from icache | ||
365 | li __core_sleep_icache_lock_start,gr3 | ||
366 | li __core_sleep_icache_lock_end,gr4 | ||
367 | 1: icul gr3 | ||
368 | addi gr3,#L1_CACHE_BYTES,gr3 | ||
369 | cmp gr4,gr3,icc0 | ||
370 | bhi icc0,#0,1b | ||
371 | |||
372 | bralr | ||
373 | |||
374 | .size frv_cpu_core_sleep, .-frv_cpu_core_sleep | ||