pm: at91: pm_slowclock: fix suspend/resume hang up in timeouts
[linux-2.6/btrfs-unstable.git] / arch / arm / mach-at91 / pm_slowclock.S
blob50744e7d55770d68da4229d31140e6907c16572d
1 /*
2  * arch/arm/mach-at91/pm_slow_clock.S
3  *
4  *  Copyright (C) 2006 Savin Zlobec
5  *
6  * AT91SAM9 support:
7  *  Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  */
15 #include <linux/linkage.h>
16 #include <linux/clk/at91_pmc.h>
17 #include <mach/hardware.h>
18 #include <mach/at91_ramc.h>
21  * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master
22  * clock during suspend by adjusting its prescalar and divisor.
23  * NOTE: This hasn't been shown to be stable on SAM9s; and on the RM9200 there
24  *       are errata regarding adjusting the prescalar and divisor.
25  */
26 #undef SLOWDOWN_MASTER_CLOCK
28 pmc     .req    r0
29 sdramc  .req    r1
30 ramc1   .req    r2
31 memctrl .req    r3
32 tmp1    .req    r4
33 tmp2    .req    r5
36  * Wait until master clock is ready (after switching master clock source)
37  */
38         .macro wait_mckrdy
39 1:      ldr     tmp1, [pmc, #AT91_PMC_SR]
40         tst     tmp1, #AT91_PMC_MCKRDY
41         beq     1b
42         .endm
45  * Wait until master oscillator has stabilized.
46  */
47         .macro wait_moscrdy
48 1:      ldr     tmp1, [pmc, #AT91_PMC_SR]
49         tst     tmp1, #AT91_PMC_MOSCS
50         beq     1b
51         .endm
54  * Wait until PLLA has locked.
55  */
56         .macro wait_pllalock
57 1:      ldr     tmp1, [pmc, #AT91_PMC_SR]
58         tst     tmp1, #AT91_PMC_LOCKA
59         beq     1b
60         .endm
63  * Wait until PLLB has locked.
64  */
65         .macro wait_pllblock
66 1:      ldr     tmp1, [pmc, #AT91_PMC_SR]
67         tst     tmp1, #AT91_PMC_LOCKB
68         beq     1b
69         .endm
71         .text
73 /* void at91_slow_clock(void __iomem *pmc, void __iomem *sdramc,
74  *                      void __iomem *ramc1, int memctrl)
75  */
76 ENTRY(at91_slow_clock)
77         /* Save registers on stack */
78         stmfd   sp!, {r4 - r12, lr}
80         /*
81          * Register usage:
82          *  R0 = Base address of AT91_PMC
83          *  R1 = Base address of RAM Controller (SDRAM, DDRSDR, or AT91_SYS)
84          *  R2 = Base address of second RAM Controller or 0 if not present
85          *  R3 = Memory controller
86          *  R4 = temporary register
87          *  R5 = temporary register
88          */
90         /* Drain write buffer */
91         mov     tmp1, #0
92         mcr     p15, 0, tmp1, c7, c10, 4
94         cmp     memctrl, #AT91_MEMCTRL_MC
95         bne     ddr_sr_enable
97         /*
98          * at91rm9200 Memory controller
99          */
100         /* Put SDRAM in self-refresh mode */
101         mov     tmp1, #1
102         str     tmp1, [sdramc, #AT91RM9200_SDRAMC_SRR]
103         b       sdr_sr_done
105         /*
106          * DDRSDR Memory controller
107          */
108 ddr_sr_enable:
109         cmp     memctrl, #AT91_MEMCTRL_DDRSDR
110         bne     sdr_sr_enable
112         /* prepare for DDRAM self-refresh mode */
113         ldr     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
114         str     tmp1, .saved_sam9_lpr
115         bic     tmp1, #AT91_DDRSDRC_LPCB
116         orr     tmp1, #AT91_DDRSDRC_LPCB_SELF_REFRESH
118         /* figure out if we use the second ram controller */
119         cmp     ramc1, #0
120         ldrne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
121         strne   tmp2, .saved_sam9_lpr1
122         bicne   tmp2, #AT91_DDRSDRC_LPCB
123         orrne   tmp2, #AT91_DDRSDRC_LPCB_SELF_REFRESH
125         /* Enable DDRAM self-refresh mode */
126         str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
127         strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
129         b       sdr_sr_done
131         /*
132          * SDRAMC Memory controller
133          */
134 sdr_sr_enable:
135         /* Enable SDRAM self-refresh mode */
136         ldr     tmp1, [sdramc, #AT91_SDRAMC_LPR]
137         str     tmp1, .saved_sam9_lpr
139         bic     tmp1, #AT91_SDRAMC_LPCB
140         orr     tmp1, #AT91_SDRAMC_LPCB_SELF_REFRESH
141         str     tmp1, [sdramc, #AT91_SDRAMC_LPR]
143 sdr_sr_done:
144         /* Save Master clock setting */
145         ldr     tmp1, [pmc, #AT91_PMC_MCKR]
146         str     tmp1, .saved_mckr
148         /*
149          * Set the Master clock source to slow clock
150          */
151         bic     tmp1, tmp1, #AT91_PMC_CSS
152         str     tmp1, [pmc, #AT91_PMC_MCKR]
154         wait_mckrdy
156 #ifdef SLOWDOWN_MASTER_CLOCK
157         /*
158          * Set the Master Clock PRES and MDIV fields.
159          *
160          * See AT91RM9200 errata #27 and #28 for details.
161          */
162         mov     tmp1, #0
163         str     tmp1, [pmc, #AT91_PMC_MCKR]
165         wait_mckrdy
166 #endif
168         /* Save PLLA setting and disable it */
169         ldr     tmp1, [pmc, #AT91_CKGR_PLLAR]
170         str     tmp1, .saved_pllar
172         mov     tmp1, #AT91_PMC_PLLCOUNT
173         orr     tmp1, tmp1, #(1 << 29)          /* bit 29 always set */
174         str     tmp1, [pmc, #AT91_CKGR_PLLAR]
176         /* Save PLLB setting and disable it */
177         ldr     tmp1, [pmc, #AT91_CKGR_PLLBR]
178         str     tmp1, .saved_pllbr
180         mov     tmp1, #AT91_PMC_PLLCOUNT
181         str     tmp1, [pmc, #AT91_CKGR_PLLBR]
183         /* Turn off the main oscillator */
184         ldr     tmp1, [pmc, #AT91_CKGR_MOR]
185         bic     tmp1, tmp1, #AT91_PMC_MOSCEN
186         str     tmp1, [pmc, #AT91_CKGR_MOR]
188         /* Wait for interrupt */
189         mcr     p15, 0, tmp1, c7, c0, 4
191         /* Turn on the main oscillator */
192         ldr     tmp1, [pmc, #AT91_CKGR_MOR]
193         orr     tmp1, tmp1, #AT91_PMC_MOSCEN
194         str     tmp1, [pmc, #AT91_CKGR_MOR]
196         wait_moscrdy
198         /* Restore PLLB setting */
199         ldr     tmp1, .saved_pllbr
200         str     tmp1, [pmc, #AT91_CKGR_PLLBR]
202         tst     tmp1, #(AT91_PMC_MUL &  0xff0000)
203         bne     1f
204         tst     tmp1, #(AT91_PMC_MUL & ~0xff0000)
205         beq     2f
207         wait_pllblock
210         /* Restore PLLA setting */
211         ldr     tmp1, .saved_pllar
212         str     tmp1, [pmc, #AT91_CKGR_PLLAR]
214         tst     tmp1, #(AT91_PMC_MUL &  0xff0000)
215         bne     3f
216         tst     tmp1, #(AT91_PMC_MUL & ~0xff0000)
217         beq     4f
219         wait_pllalock
222 #ifdef SLOWDOWN_MASTER_CLOCK
223         /*
224          * First set PRES if it was not 0,
225          * than set CSS and MDIV fields.
226          *
227          * See AT91RM9200 errata #27 and #28 for details.
228          */
229         ldr     tmp1, .saved_mckr
230         tst     tmp1, #AT91_PMC_PRES
231         beq     2f
232         and     tmp1, tmp1, #AT91_PMC_PRES
233         str     tmp1, [pmc, #AT91_PMC_MCKR]
235         wait_mckrdy
236 #endif
238         /*
239          * Restore master clock setting
240          */
241 2:      ldr     tmp1, .saved_mckr
242         str     tmp1, [pmc, #AT91_PMC_MCKR]
244         wait_mckrdy
246         /*
247          * at91rm9200 Memory controller
248          * Do nothing - self-refresh is automatically disabled.
249          */
250         cmp     memctrl, #AT91_MEMCTRL_MC
251         beq     ram_restored
253         /*
254          * DDRSDR Memory controller
255          */
256         cmp     memctrl, #AT91_MEMCTRL_DDRSDR
257         bne     sdr_en_restore
258         /* Restore LPR on AT91 with DDRAM */
259         ldr     tmp1, .saved_sam9_lpr
260         str     tmp1, [sdramc, #AT91_DDRSDRC_LPR]
262         /* if we use the second ram controller */
263         cmp     ramc1, #0
264         ldrne   tmp2, .saved_sam9_lpr1
265         strne   tmp2, [ramc1, #AT91_DDRSDRC_LPR]
267         b       ram_restored
269         /*
270          * SDRAMC Memory controller
271          */
272 sdr_en_restore:
273         /* Restore LPR on AT91 with SDRAM */
274         ldr     tmp1, .saved_sam9_lpr
275         str     tmp1, [sdramc, #AT91_SDRAMC_LPR]
277 ram_restored:
278         /* Restore registers, and return */
279         ldmfd   sp!, {r4 - r12, pc}
282 .saved_mckr:
283         .word 0
285 .saved_pllar:
286         .word 0
288 .saved_pllbr:
289         .word 0
291 .saved_sam9_lpr:
292         .word 0
294 .saved_sam9_lpr1:
295         .word 0
297 ENTRY(at91_slow_clock_sz)
298         .word .-at91_slow_clock