Linux-2.6.12-rc2
[linux-2.6.git] / arch / frv / kernel / sleep.S
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