[WATCHDOG] Merge code clean-up's from Alan Cox.
[linux-2.6] / 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@infradead.org)
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/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