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