Commit | Line | Data |
---|---|---|
eaad2db0 AV |
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 | */ | |
14 | ||
15 | #include <linux/linkage.h> | |
16 | #include <mach/hardware.h> | |
17 | #include <mach/at91_pmc.h> | |
18 | ||
19 | #ifdef CONFIG_ARCH_AT91RM9200 | |
20 | #include <mach/at91rm9200_mc.h> | |
21 | #elif defined(CONFIG_ARCH_AT91CAP9) | |
22 | #include <mach/at91cap9_ddrsdr.h> | |
23 | #else | |
24 | #include <mach/at91sam9_sdramc.h> | |
25 | #endif | |
26 | ||
27 | ||
28 | #ifdef CONFIG_ARCH_AT91SAM9263 | |
29 | /* | |
30 | * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use; | |
31 | * handle those cases both here and in the Suspend-To-RAM support. | |
32 | */ | |
33 | #define AT91_SDRAMC AT91_SDRAMC0 | |
34 | #warning Assuming EB1 SDRAM controller is *NOT* used | |
35 | #endif | |
36 | ||
37 | /* | |
38 | * When SLOWDOWN_MASTER_CLOCK is defined we will also slow down the Master | |
39 | * clock during suspend by adjusting its prescalar and divisor. | |
40 | * NOTE: This hasn't been shown to be stable on SAM9s; and on the RM9200 there | |
41 | * are errata regarding adjusting the prescalar and divisor. | |
42 | */ | |
43 | #undef SLOWDOWN_MASTER_CLOCK | |
44 | ||
45 | #define MCKRDY_TIMEOUT 1000 | |
46 | #define MOSCRDY_TIMEOUT 1000 | |
47 | #define PLLALOCK_TIMEOUT 1000 | |
48 | #define PLLBLOCK_TIMEOUT 1000 | |
49 | ||
50 | ||
51 | /* | |
52 | * Wait until master clock is ready (after switching master clock source) | |
53 | */ | |
54 | .macro wait_mckrdy | |
55 | mov r4, #MCKRDY_TIMEOUT | |
56 | 1: sub r4, r4, #1 | |
57 | cmp r4, #0 | |
58 | beq 2f | |
59 | ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] | |
60 | tst r3, #AT91_PMC_MCKRDY | |
61 | beq 1b | |
62 | 2: | |
63 | .endm | |
64 | ||
65 | /* | |
66 | * Wait until master oscillator has stabilized. | |
67 | */ | |
68 | .macro wait_moscrdy | |
69 | mov r4, #MOSCRDY_TIMEOUT | |
70 | 1: sub r4, r4, #1 | |
71 | cmp r4, #0 | |
72 | beq 2f | |
73 | ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] | |
74 | tst r3, #AT91_PMC_MOSCS | |
75 | beq 1b | |
76 | 2: | |
77 | .endm | |
78 | ||
79 | /* | |
80 | * Wait until PLLA has locked. | |
81 | */ | |
82 | .macro wait_pllalock | |
83 | mov r4, #PLLALOCK_TIMEOUT | |
84 | 1: sub r4, r4, #1 | |
85 | cmp r4, #0 | |
86 | beq 2f | |
87 | ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] | |
88 | tst r3, #AT91_PMC_LOCKA | |
89 | beq 1b | |
90 | 2: | |
91 | .endm | |
92 | ||
93 | /* | |
94 | * Wait until PLLB has locked. | |
95 | */ | |
96 | .macro wait_pllblock | |
97 | mov r4, #PLLBLOCK_TIMEOUT | |
98 | 1: sub r4, r4, #1 | |
99 | cmp r4, #0 | |
100 | beq 2f | |
101 | ldr r3, [r1, #(AT91_PMC_SR - AT91_PMC)] | |
102 | tst r3, #AT91_PMC_LOCKB | |
103 | beq 1b | |
104 | 2: | |
105 | .endm | |
106 | ||
107 | .text | |
108 | ||
109 | ENTRY(at91_slow_clock) | |
110 | /* Save registers on stack */ | |
111 | stmfd sp!, {r0 - r12, lr} | |
112 | ||
113 | /* | |
114 | * Register usage: | |
115 | * R1 = Base address of AT91_PMC | |
116 | * R2 = Base address of AT91_SDRAMC (or AT91_SYS on AT91RM9200) | |
117 | * R3 = temporary register | |
118 | * R4 = temporary register | |
119 | */ | |
120 | ldr r1, .at91_va_base_pmc | |
121 | ldr r2, .at91_va_base_sdramc | |
122 | ||
123 | /* Drain write buffer */ | |
124 | mcr p15, 0, r0, c7, c10, 4 | |
125 | ||
126 | #ifdef CONFIG_ARCH_AT91RM9200 | |
127 | /* Put SDRAM in self-refresh mode */ | |
128 | mov r3, #1 | |
129 | str r3, [r2, #AT91_SDRAMC_SRR] | |
130 | #elif defined(CONFIG_ARCH_AT91CAP9) | |
131 | /* Enable SDRAM self-refresh mode */ | |
132 | ldr r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC] | |
133 | str r3, .saved_sam9_lpr | |
134 | ||
135 | mov r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH | |
136 | str r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC] | |
137 | #else | |
138 | /* Enable SDRAM self-refresh mode */ | |
139 | ldr r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC] | |
140 | str r3, .saved_sam9_lpr | |
141 | ||
142 | mov r3, #AT91_SDRAMC_LPCB_SELF_REFRESH | |
143 | str r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC] | |
144 | #endif | |
145 | ||
146 | /* Save Master clock setting */ | |
147 | ldr r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] | |
148 | str r3, .saved_mckr | |
149 | ||
150 | /* | |
151 | * Set the Master clock source to slow clock | |
152 | */ | |
153 | bic r3, r3, #AT91_PMC_CSS | |
154 | str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] | |
155 | ||
156 | wait_mckrdy | |
157 | ||
158 | #ifdef SLOWDOWN_MASTER_CLOCK | |
159 | /* | |
160 | * Set the Master Clock PRES and MDIV fields. | |
161 | * | |
162 | * See AT91RM9200 errata #27 and #28 for details. | |
163 | */ | |
164 | mov r3, #0 | |
165 | str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] | |
166 | ||
167 | wait_mckrdy | |
168 | #endif | |
169 | ||
170 | /* Save PLLA setting and disable it */ | |
171 | ldr r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)] | |
172 | str r3, .saved_pllar | |
173 | ||
174 | mov r3, #AT91_PMC_PLLCOUNT | |
175 | orr r3, r3, #(1 << 29) /* bit 29 always set */ | |
176 | str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)] | |
177 | ||
178 | wait_pllalock | |
179 | ||
180 | /* Save PLLB setting and disable it */ | |
181 | ldr r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)] | |
182 | str r3, .saved_pllbr | |
183 | ||
184 | mov r3, #AT91_PMC_PLLCOUNT | |
185 | str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)] | |
186 | ||
187 | wait_pllblock | |
188 | ||
189 | /* Turn off the main oscillator */ | |
190 | ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] | |
191 | bic r3, r3, #AT91_PMC_MOSCEN | |
192 | str r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] | |
193 | ||
194 | /* Wait for interrupt */ | |
195 | mcr p15, 0, r0, c7, c0, 4 | |
196 | ||
197 | /* Turn on the main oscillator */ | |
198 | ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] | |
199 | orr r3, r3, #AT91_PMC_MOSCEN | |
200 | str r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)] | |
201 | ||
202 | wait_moscrdy | |
203 | ||
204 | /* Restore PLLB setting */ | |
205 | ldr r3, .saved_pllbr | |
206 | str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)] | |
207 | ||
208 | wait_pllblock | |
209 | ||
210 | /* Restore PLLA setting */ | |
211 | ldr r3, .saved_pllar | |
212 | str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)] | |
213 | ||
214 | wait_pllalock | |
215 | ||
216 | #ifdef SLOWDOWN_MASTER_CLOCK | |
217 | /* | |
218 | * First set PRES if it was not 0, | |
219 | * than set CSS and MDIV fields. | |
220 | * | |
221 | * See AT91RM9200 errata #27 and #28 for details. | |
222 | */ | |
223 | ldr r3, .saved_mckr | |
224 | tst r3, #AT91_PMC_PRES | |
225 | beq 2f | |
226 | and r3, r3, #AT91_PMC_PRES | |
227 | str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] | |
228 | ||
229 | wait_mckrdy | |
230 | #endif | |
231 | ||
232 | /* | |
233 | * Restore master clock setting | |
234 | */ | |
235 | 2: ldr r3, .saved_mckr | |
236 | str r3, [r1, #(AT91_PMC_MCKR - AT91_PMC)] | |
237 | ||
238 | wait_mckrdy | |
239 | ||
240 | #ifdef CONFIG_ARCH_AT91RM9200 | |
241 | /* Do nothing - self-refresh is automatically disabled. */ | |
242 | #elif defined(CONFIG_ARCH_AT91CAP9) | |
243 | /* Restore LPR on AT91CAP9 */ | |
244 | ldr r3, .saved_sam9_lpr | |
245 | str r3, [r2, #AT91_DDRSDRC_LPR - AT91_DDRSDRC] | |
246 | #else | |
247 | /* Restore LPR on AT91SAM9 */ | |
248 | ldr r3, .saved_sam9_lpr | |
249 | str r3, [r2, #AT91_SDRAMC_LPR - AT91_SDRAMC] | |
250 | #endif | |
251 | ||
252 | /* Restore registers, and return */ | |
253 | ldmfd sp!, {r0 - r12, pc} | |
254 | ||
255 | ||
256 | .saved_mckr: | |
257 | .word 0 | |
258 | ||
259 | .saved_pllar: | |
260 | .word 0 | |
261 | ||
262 | .saved_pllbr: | |
263 | .word 0 | |
264 | ||
265 | .saved_sam9_lpr: | |
266 | .word 0 | |
267 | ||
268 | .at91_va_base_pmc: | |
269 | .word AT91_VA_BASE_SYS + AT91_PMC | |
270 | ||
271 | #ifdef CONFIG_ARCH_AT91RM9200 | |
272 | .at91_va_base_sdramc: | |
273 | .word AT91_VA_BASE_SYS | |
274 | #elif defined(CONFIG_ARCH_AT91CAP9) | |
275 | .at91_va_base_sdramc: | |
276 | .word AT91_VA_BASE_SYS + AT91_DDRSDRC | |
277 | #else | |
278 | .at91_va_base_sdramc: | |
279 | .word AT91_VA_BASE_SYS + AT91_SDRAMC | |
280 | #endif | |
281 | ||
282 | ENTRY(at91_slow_clock_sz) | |
283 | .word .-at91_slow_clock |