Commit 670c104ae8e7bcc28be0289a16dac2ddfb88b285
Committed by
Russell King
1 parent
6e60e79a1d
Exists in
master
and in
4 other branches
[ARM] 3430/1: ARM: OMAP: 5/8 Update PM
Patch from Tony Lindgren Update OMAP PM code from linux-omap tree: - Move PM code from plat-omap to mach-omap1 and mach-omap2 by Tony Lindgren - Add minimal PM support for omap24xx by Tony Lindgren and Richard Woodruff - Misc updates to omap1 PM code by Tuukka Tikkanen et al - Updates to the SRAM code needed for PM and FB by Imre Deak Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Showing 10 changed files with 1787 additions and 484 deletions Side-by-side Diff
arch/arm/mach-omap1/pm.c
1 | +/* | |
2 | + * linux/arch/arm/mach-omap1/pm.c | |
3 | + * | |
4 | + * OMAP Power Management Routines | |
5 | + * | |
6 | + * Original code for the SA11x0: | |
7 | + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | |
8 | + * | |
9 | + * Modified for the PXA250 by Nicolas Pitre: | |
10 | + * Copyright (c) 2002 Monta Vista Software, Inc. | |
11 | + * | |
12 | + * Modified for the OMAP1510 by David Singleton: | |
13 | + * Copyright (c) 2002 Monta Vista Software, Inc. | |
14 | + * | |
15 | + * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> | |
16 | + * | |
17 | + * This program is free software; you can redistribute it and/or modify it | |
18 | + * under the terms of the GNU General Public License as published by the | |
19 | + * Free Software Foundation; either version 2 of the License, or (at your | |
20 | + * option) any later version. | |
21 | + * | |
22 | + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
23 | + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
24 | + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
25 | + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
27 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
28 | + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
29 | + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
31 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | + * | |
33 | + * You should have received a copy of the GNU General Public License along | |
34 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
35 | + * 675 Mass Ave, Cambridge, MA 02139, USA. | |
36 | + */ | |
37 | + | |
38 | +#include <linux/pm.h> | |
39 | +#include <linux/sched.h> | |
40 | +#include <linux/proc_fs.h> | |
41 | +#include <linux/pm.h> | |
42 | +#include <linux/interrupt.h> | |
43 | +#include <linux/sysfs.h> | |
44 | +#include <linux/module.h> | |
45 | + | |
46 | +#include <asm/io.h> | |
47 | +#include <asm/irq.h> | |
48 | +#include <asm/atomic.h> | |
49 | +#include <asm/mach/time.h> | |
50 | +#include <asm/mach/irq.h> | |
51 | +#include <asm/mach-types.h> | |
52 | + | |
53 | +#include <asm/arch/irqs.h> | |
54 | +#include <asm/arch/clock.h> | |
55 | +#include <asm/arch/sram.h> | |
56 | +#include <asm/arch/tc.h> | |
57 | +#include <asm/arch/pm.h> | |
58 | +#include <asm/arch/mux.h> | |
59 | +#include <asm/arch/tps65010.h> | |
60 | +#include <asm/arch/dma.h> | |
61 | +#include <asm/arch/dsp_common.h> | |
62 | +#include <asm/arch/dmtimer.h> | |
63 | + | |
64 | +static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; | |
65 | +static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE]; | |
66 | +static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; | |
67 | +static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE]; | |
68 | +static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; | |
69 | +static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; | |
70 | + | |
71 | +static unsigned short enable_dyn_sleep = 1; | |
72 | + | |
73 | +static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf) | |
74 | +{ | |
75 | + return sprintf(buf, "%hu\n", enable_dyn_sleep); | |
76 | +} | |
77 | + | |
78 | +static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys, | |
79 | + const char * buf, | |
80 | + size_t n) | |
81 | +{ | |
82 | + unsigned short value; | |
83 | + if (sscanf(buf, "%hu", &value) != 1 || | |
84 | + (value != 0 && value != 1)) { | |
85 | + printk(KERN_ERR "idle_sleep_store: Invalid value\n"); | |
86 | + return -EINVAL; | |
87 | + } | |
88 | + enable_dyn_sleep = value; | |
89 | + return n; | |
90 | +} | |
91 | + | |
92 | +static struct subsys_attribute sleep_while_idle_attr = { | |
93 | + .attr = { | |
94 | + .name = __stringify(sleep_while_idle), | |
95 | + .mode = 0644, | |
96 | + }, | |
97 | + .show = omap_pm_sleep_while_idle_show, | |
98 | + .store = omap_pm_sleep_while_idle_store, | |
99 | +}; | |
100 | + | |
101 | +extern struct subsystem power_subsys; | |
102 | +static void (*omap_sram_idle)(void) = NULL; | |
103 | +static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; | |
104 | + | |
105 | +/* | |
106 | + * Let's power down on idle, but only if we are really | |
107 | + * idle, because once we start down the path of | |
108 | + * going idle we continue to do idle even if we get | |
109 | + * a clock tick interrupt . . | |
110 | + */ | |
111 | +void omap_pm_idle(void) | |
112 | +{ | |
113 | + extern __u32 arm_idlect1_mask; | |
114 | + __u32 use_idlect1 = arm_idlect1_mask; | |
115 | +#ifndef CONFIG_OMAP_MPU_TIMER | |
116 | + int do_sleep; | |
117 | +#endif | |
118 | + | |
119 | + local_irq_disable(); | |
120 | + local_fiq_disable(); | |
121 | + if (need_resched()) { | |
122 | + local_fiq_enable(); | |
123 | + local_irq_enable(); | |
124 | + return; | |
125 | + } | |
126 | + | |
127 | + /* | |
128 | + * Since an interrupt may set up a timer, we don't want to | |
129 | + * reprogram the hardware timer with interrupts enabled. | |
130 | + * Re-enable interrupts only after returning from idle. | |
131 | + */ | |
132 | + timer_dyn_reprogram(); | |
133 | + | |
134 | +#ifdef CONFIG_OMAP_MPU_TIMER | |
135 | +#warning Enable 32kHz OS timer in order to allow sleep states in idle | |
136 | + use_idlect1 = use_idlect1 & ~(1 << 9); | |
137 | +#else | |
138 | + | |
139 | + do_sleep = 0; | |
140 | + while (enable_dyn_sleep) { | |
141 | + | |
142 | +#ifdef CONFIG_CBUS_TAHVO_USB | |
143 | + extern int vbus_active; | |
144 | + /* Clock requirements? */ | |
145 | + if (vbus_active) | |
146 | + break; | |
147 | +#endif | |
148 | + do_sleep = 1; | |
149 | + break; | |
150 | + } | |
151 | + | |
152 | +#ifdef CONFIG_OMAP_DM_TIMER | |
153 | + use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1); | |
154 | +#endif | |
155 | + | |
156 | + if (omap_dma_running()) { | |
157 | + use_idlect1 &= ~(1 << 6); | |
158 | + if (omap_lcd_dma_ext_running()) | |
159 | + use_idlect1 &= ~(1 << 12); | |
160 | + } | |
161 | + | |
162 | + /* We should be able to remove the do_sleep variable and multiple | |
163 | + * tests above as soon as drivers, timer and DMA code have been fixed. | |
164 | + * Even the sleep block count should become obsolete. */ | |
165 | + if ((use_idlect1 != ~0) || !do_sleep) { | |
166 | + | |
167 | + __u32 saved_idlect1 = omap_readl(ARM_IDLECT1); | |
168 | + if (cpu_is_omap15xx()) | |
169 | + use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST; | |
170 | + else | |
171 | + use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL; | |
172 | + omap_writel(use_idlect1, ARM_IDLECT1); | |
173 | + __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); | |
174 | + omap_writel(saved_idlect1, ARM_IDLECT1); | |
175 | + | |
176 | + local_fiq_enable(); | |
177 | + local_irq_enable(); | |
178 | + return; | |
179 | + } | |
180 | + omap_sram_suspend(omap_readl(ARM_IDLECT1), | |
181 | + omap_readl(ARM_IDLECT2)); | |
182 | +#endif | |
183 | + | |
184 | + local_fiq_enable(); | |
185 | + local_irq_enable(); | |
186 | +} | |
187 | + | |
188 | +/* | |
189 | + * Configuration of the wakeup event is board specific. For the | |
190 | + * moment we put it into this helper function. Later it may move | |
191 | + * to board specific files. | |
192 | + */ | |
193 | +static void omap_pm_wakeup_setup(void) | |
194 | +{ | |
195 | + u32 level1_wake = 0; | |
196 | + u32 level2_wake = OMAP_IRQ_BIT(INT_UART2); | |
197 | + | |
198 | + /* | |
199 | + * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, | |
200 | + * and the L2 wakeup interrupts: keypad and UART2. Note that the | |
201 | + * drivers must still separately call omap_set_gpio_wakeup() to | |
202 | + * wake up to a GPIO interrupt. | |
203 | + */ | |
204 | + if (cpu_is_omap730()) | |
205 | + level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) | | |
206 | + OMAP_IRQ_BIT(INT_730_IH2_IRQ); | |
207 | + else if (cpu_is_omap15xx()) | |
208 | + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | | |
209 | + OMAP_IRQ_BIT(INT_1510_IH2_IRQ); | |
210 | + else if (cpu_is_omap16xx()) | |
211 | + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | | |
212 | + OMAP_IRQ_BIT(INT_1610_IH2_IRQ); | |
213 | + | |
214 | + omap_writel(~level1_wake, OMAP_IH1_MIR); | |
215 | + | |
216 | + if (cpu_is_omap730()) { | |
217 | + omap_writel(~level2_wake, OMAP_IH2_0_MIR); | |
218 | + omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | | |
219 | + OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), | |
220 | + OMAP_IH2_1_MIR); | |
221 | + } else if (cpu_is_omap15xx()) { | |
222 | + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); | |
223 | + omap_writel(~level2_wake, OMAP_IH2_MIR); | |
224 | + } else if (cpu_is_omap16xx()) { | |
225 | + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); | |
226 | + omap_writel(~level2_wake, OMAP_IH2_0_MIR); | |
227 | + | |
228 | + /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ | |
229 | + omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), | |
230 | + OMAP_IH2_1_MIR); | |
231 | + omap_writel(~0x0, OMAP_IH2_2_MIR); | |
232 | + omap_writel(~0x0, OMAP_IH2_3_MIR); | |
233 | + } | |
234 | + | |
235 | + /* New IRQ agreement, recalculate in cascade order */ | |
236 | + omap_writel(1, OMAP_IH2_CONTROL); | |
237 | + omap_writel(1, OMAP_IH1_CONTROL); | |
238 | +} | |
239 | + | |
240 | +#define EN_DSPCK 13 /* ARM_CKCTL */ | |
241 | +#define EN_APICK 6 /* ARM_IDLECT2 */ | |
242 | +#define DSP_EN 1 /* ARM_RSTCT1 */ | |
243 | + | |
244 | +void omap_pm_suspend(void) | |
245 | +{ | |
246 | + unsigned long arg0 = 0, arg1 = 0; | |
247 | + | |
248 | + printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); | |
249 | + | |
250 | + omap_serial_wake_trigger(1); | |
251 | + | |
252 | + if (machine_is_omap_osk()) { | |
253 | + /* Stop LED1 (D9) blink */ | |
254 | + tps65010_set_led(LED1, OFF); | |
255 | + } | |
256 | + | |
257 | + omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG); | |
258 | + | |
259 | + /* | |
260 | + * Step 1: turn off interrupts (FIXME: NOTE: already disabled) | |
261 | + */ | |
262 | + | |
263 | + local_irq_disable(); | |
264 | + local_fiq_disable(); | |
265 | + | |
266 | + /* | |
267 | + * Step 2: save registers | |
268 | + * | |
269 | + * The omap is a strange/beautiful device. The caches, memory | |
270 | + * and register state are preserved across power saves. | |
271 | + * We have to save and restore very little register state to | |
272 | + * idle the omap. | |
273 | + * | |
274 | + * Save interrupt, MPUI, ARM and UPLD control registers. | |
275 | + */ | |
276 | + | |
277 | + if (cpu_is_omap730()) { | |
278 | + MPUI730_SAVE(OMAP_IH1_MIR); | |
279 | + MPUI730_SAVE(OMAP_IH2_0_MIR); | |
280 | + MPUI730_SAVE(OMAP_IH2_1_MIR); | |
281 | + MPUI730_SAVE(MPUI_CTRL); | |
282 | + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); | |
283 | + MPUI730_SAVE(MPUI_DSP_API_CONFIG); | |
284 | + MPUI730_SAVE(EMIFS_CONFIG); | |
285 | + MPUI730_SAVE(EMIFF_SDRAM_CONFIG); | |
286 | + | |
287 | + } else if (cpu_is_omap15xx()) { | |
288 | + MPUI1510_SAVE(OMAP_IH1_MIR); | |
289 | + MPUI1510_SAVE(OMAP_IH2_MIR); | |
290 | + MPUI1510_SAVE(MPUI_CTRL); | |
291 | + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); | |
292 | + MPUI1510_SAVE(MPUI_DSP_API_CONFIG); | |
293 | + MPUI1510_SAVE(EMIFS_CONFIG); | |
294 | + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); | |
295 | + } else if (cpu_is_omap16xx()) { | |
296 | + MPUI1610_SAVE(OMAP_IH1_MIR); | |
297 | + MPUI1610_SAVE(OMAP_IH2_0_MIR); | |
298 | + MPUI1610_SAVE(OMAP_IH2_1_MIR); | |
299 | + MPUI1610_SAVE(OMAP_IH2_2_MIR); | |
300 | + MPUI1610_SAVE(OMAP_IH2_3_MIR); | |
301 | + MPUI1610_SAVE(MPUI_CTRL); | |
302 | + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); | |
303 | + MPUI1610_SAVE(MPUI_DSP_API_CONFIG); | |
304 | + MPUI1610_SAVE(EMIFS_CONFIG); | |
305 | + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); | |
306 | + } | |
307 | + | |
308 | + ARM_SAVE(ARM_CKCTL); | |
309 | + ARM_SAVE(ARM_IDLECT1); | |
310 | + ARM_SAVE(ARM_IDLECT2); | |
311 | + if (!(cpu_is_omap15xx())) | |
312 | + ARM_SAVE(ARM_IDLECT3); | |
313 | + ARM_SAVE(ARM_EWUPCT); | |
314 | + ARM_SAVE(ARM_RSTCT1); | |
315 | + ARM_SAVE(ARM_RSTCT2); | |
316 | + ARM_SAVE(ARM_SYSST); | |
317 | + ULPD_SAVE(ULPD_CLOCK_CTRL); | |
318 | + ULPD_SAVE(ULPD_STATUS_REQ); | |
319 | + | |
320 | + /* (Step 3 removed - we now allow deep sleep by default) */ | |
321 | + | |
322 | + /* | |
323 | + * Step 4: OMAP DSP Shutdown | |
324 | + */ | |
325 | + | |
326 | + /* stop DSP */ | |
327 | + omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1); | |
328 | + | |
329 | + /* shut down dsp_ck */ | |
330 | + omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); | |
331 | + | |
332 | + /* temporarily enabling api_ck to access DSP registers */ | |
333 | + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); | |
334 | + | |
335 | + /* save DSP registers */ | |
336 | + DSP_SAVE(DSP_IDLECT2); | |
337 | + | |
338 | + /* Stop all DSP domain clocks */ | |
339 | + __raw_writew(0, DSP_IDLECT2); | |
340 | + | |
341 | + /* | |
342 | + * Step 5: Wakeup Event Setup | |
343 | + */ | |
344 | + | |
345 | + omap_pm_wakeup_setup(); | |
346 | + | |
347 | + /* | |
348 | + * Step 6: ARM and Traffic controller shutdown | |
349 | + */ | |
350 | + | |
351 | + /* disable ARM watchdog */ | |
352 | + omap_writel(0x00F5, OMAP_WDT_TIMER_MODE); | |
353 | + omap_writel(0x00A0, OMAP_WDT_TIMER_MODE); | |
354 | + | |
355 | + /* | |
356 | + * Step 6b: ARM and Traffic controller shutdown | |
357 | + * | |
358 | + * Step 6 continues here. Prepare jump to power management | |
359 | + * assembly code in internal SRAM. | |
360 | + * | |
361 | + * Since the omap_cpu_suspend routine has been copied to | |
362 | + * SRAM, we'll do an indirect procedure call to it and pass the | |
363 | + * contents of arm_idlect1 and arm_idlect2 so it can restore | |
364 | + * them when it wakes up and it will return. | |
365 | + */ | |
366 | + | |
367 | + arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1]; | |
368 | + arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2]; | |
369 | + | |
370 | + /* | |
371 | + * Step 6c: ARM and Traffic controller shutdown | |
372 | + * | |
373 | + * Jump to assembly code. The processor will stay there | |
374 | + * until wake up. | |
375 | + */ | |
376 | + omap_sram_suspend(arg0, arg1); | |
377 | + | |
378 | + /* | |
379 | + * If we are here, processor is woken up! | |
380 | + */ | |
381 | + | |
382 | + /* | |
383 | + * Restore DSP clocks | |
384 | + */ | |
385 | + | |
386 | + /* again temporarily enabling api_ck to access DSP registers */ | |
387 | + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); | |
388 | + | |
389 | + /* Restore DSP domain clocks */ | |
390 | + DSP_RESTORE(DSP_IDLECT2); | |
391 | + | |
392 | + /* | |
393 | + * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did | |
394 | + */ | |
395 | + | |
396 | + if (!(cpu_is_omap15xx())) | |
397 | + ARM_RESTORE(ARM_IDLECT3); | |
398 | + ARM_RESTORE(ARM_CKCTL); | |
399 | + ARM_RESTORE(ARM_EWUPCT); | |
400 | + ARM_RESTORE(ARM_RSTCT1); | |
401 | + ARM_RESTORE(ARM_RSTCT2); | |
402 | + ARM_RESTORE(ARM_SYSST); | |
403 | + ULPD_RESTORE(ULPD_CLOCK_CTRL); | |
404 | + ULPD_RESTORE(ULPD_STATUS_REQ); | |
405 | + | |
406 | + if (cpu_is_omap730()) { | |
407 | + MPUI730_RESTORE(EMIFS_CONFIG); | |
408 | + MPUI730_RESTORE(EMIFF_SDRAM_CONFIG); | |
409 | + MPUI730_RESTORE(OMAP_IH1_MIR); | |
410 | + MPUI730_RESTORE(OMAP_IH2_0_MIR); | |
411 | + MPUI730_RESTORE(OMAP_IH2_1_MIR); | |
412 | + } else if (cpu_is_omap15xx()) { | |
413 | + MPUI1510_RESTORE(MPUI_CTRL); | |
414 | + MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); | |
415 | + MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); | |
416 | + MPUI1510_RESTORE(EMIFS_CONFIG); | |
417 | + MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG); | |
418 | + MPUI1510_RESTORE(OMAP_IH1_MIR); | |
419 | + MPUI1510_RESTORE(OMAP_IH2_MIR); | |
420 | + } else if (cpu_is_omap16xx()) { | |
421 | + MPUI1610_RESTORE(MPUI_CTRL); | |
422 | + MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG); | |
423 | + MPUI1610_RESTORE(MPUI_DSP_API_CONFIG); | |
424 | + MPUI1610_RESTORE(EMIFS_CONFIG); | |
425 | + MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG); | |
426 | + | |
427 | + MPUI1610_RESTORE(OMAP_IH1_MIR); | |
428 | + MPUI1610_RESTORE(OMAP_IH2_0_MIR); | |
429 | + MPUI1610_RESTORE(OMAP_IH2_1_MIR); | |
430 | + MPUI1610_RESTORE(OMAP_IH2_2_MIR); | |
431 | + MPUI1610_RESTORE(OMAP_IH2_3_MIR); | |
432 | + } | |
433 | + | |
434 | + omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG); | |
435 | + | |
436 | + /* | |
437 | + * Reenable interrupts | |
438 | + */ | |
439 | + | |
440 | + local_irq_enable(); | |
441 | + local_fiq_enable(); | |
442 | + | |
443 | + omap_serial_wake_trigger(0); | |
444 | + | |
445 | + printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev); | |
446 | + | |
447 | + if (machine_is_omap_osk()) { | |
448 | + /* Let LED1 (D9) blink again */ | |
449 | + tps65010_set_led(LED1, BLINK); | |
450 | + } | |
451 | +} | |
452 | + | |
453 | +#if defined(DEBUG) && defined(CONFIG_PROC_FS) | |
454 | +static int g_read_completed; | |
455 | + | |
456 | +/* | |
457 | + * Read system PM registers for debugging | |
458 | + */ | |
459 | +static int omap_pm_read_proc( | |
460 | + char *page_buffer, | |
461 | + char **my_first_byte, | |
462 | + off_t virtual_start, | |
463 | + int length, | |
464 | + int *eof, | |
465 | + void *data) | |
466 | +{ | |
467 | + int my_buffer_offset = 0; | |
468 | + char * const my_base = page_buffer; | |
469 | + | |
470 | + ARM_SAVE(ARM_CKCTL); | |
471 | + ARM_SAVE(ARM_IDLECT1); | |
472 | + ARM_SAVE(ARM_IDLECT2); | |
473 | + if (!(cpu_is_omap15xx())) | |
474 | + ARM_SAVE(ARM_IDLECT3); | |
475 | + ARM_SAVE(ARM_EWUPCT); | |
476 | + ARM_SAVE(ARM_RSTCT1); | |
477 | + ARM_SAVE(ARM_RSTCT2); | |
478 | + ARM_SAVE(ARM_SYSST); | |
479 | + | |
480 | + ULPD_SAVE(ULPD_IT_STATUS); | |
481 | + ULPD_SAVE(ULPD_CLOCK_CTRL); | |
482 | + ULPD_SAVE(ULPD_SOFT_REQ); | |
483 | + ULPD_SAVE(ULPD_STATUS_REQ); | |
484 | + ULPD_SAVE(ULPD_DPLL_CTRL); | |
485 | + ULPD_SAVE(ULPD_POWER_CTRL); | |
486 | + | |
487 | + if (cpu_is_omap730()) { | |
488 | + MPUI730_SAVE(MPUI_CTRL); | |
489 | + MPUI730_SAVE(MPUI_DSP_STATUS); | |
490 | + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); | |
491 | + MPUI730_SAVE(MPUI_DSP_API_CONFIG); | |
492 | + MPUI730_SAVE(EMIFF_SDRAM_CONFIG); | |
493 | + MPUI730_SAVE(EMIFS_CONFIG); | |
494 | + } else if (cpu_is_omap15xx()) { | |
495 | + MPUI1510_SAVE(MPUI_CTRL); | |
496 | + MPUI1510_SAVE(MPUI_DSP_STATUS); | |
497 | + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); | |
498 | + MPUI1510_SAVE(MPUI_DSP_API_CONFIG); | |
499 | + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); | |
500 | + MPUI1510_SAVE(EMIFS_CONFIG); | |
501 | + } else if (cpu_is_omap16xx()) { | |
502 | + MPUI1610_SAVE(MPUI_CTRL); | |
503 | + MPUI1610_SAVE(MPUI_DSP_STATUS); | |
504 | + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); | |
505 | + MPUI1610_SAVE(MPUI_DSP_API_CONFIG); | |
506 | + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); | |
507 | + MPUI1610_SAVE(EMIFS_CONFIG); | |
508 | + } | |
509 | + | |
510 | + if (virtual_start == 0) { | |
511 | + g_read_completed = 0; | |
512 | + | |
513 | + my_buffer_offset += sprintf(my_base + my_buffer_offset, | |
514 | + "ARM_CKCTL_REG: 0x%-8x \n" | |
515 | + "ARM_IDLECT1_REG: 0x%-8x \n" | |
516 | + "ARM_IDLECT2_REG: 0x%-8x \n" | |
517 | + "ARM_IDLECT3_REG: 0x%-8x \n" | |
518 | + "ARM_EWUPCT_REG: 0x%-8x \n" | |
519 | + "ARM_RSTCT1_REG: 0x%-8x \n" | |
520 | + "ARM_RSTCT2_REG: 0x%-8x \n" | |
521 | + "ARM_SYSST_REG: 0x%-8x \n" | |
522 | + "ULPD_IT_STATUS_REG: 0x%-4x \n" | |
523 | + "ULPD_CLOCK_CTRL_REG: 0x%-4x \n" | |
524 | + "ULPD_SOFT_REQ_REG: 0x%-4x \n" | |
525 | + "ULPD_DPLL_CTRL_REG: 0x%-4x \n" | |
526 | + "ULPD_STATUS_REQ_REG: 0x%-4x \n" | |
527 | + "ULPD_POWER_CTRL_REG: 0x%-4x \n", | |
528 | + ARM_SHOW(ARM_CKCTL), | |
529 | + ARM_SHOW(ARM_IDLECT1), | |
530 | + ARM_SHOW(ARM_IDLECT2), | |
531 | + ARM_SHOW(ARM_IDLECT3), | |
532 | + ARM_SHOW(ARM_EWUPCT), | |
533 | + ARM_SHOW(ARM_RSTCT1), | |
534 | + ARM_SHOW(ARM_RSTCT2), | |
535 | + ARM_SHOW(ARM_SYSST), | |
536 | + ULPD_SHOW(ULPD_IT_STATUS), | |
537 | + ULPD_SHOW(ULPD_CLOCK_CTRL), | |
538 | + ULPD_SHOW(ULPD_SOFT_REQ), | |
539 | + ULPD_SHOW(ULPD_DPLL_CTRL), | |
540 | + ULPD_SHOW(ULPD_STATUS_REQ), | |
541 | + ULPD_SHOW(ULPD_POWER_CTRL)); | |
542 | + | |
543 | + if (cpu_is_omap730()) { | |
544 | + my_buffer_offset += sprintf(my_base + my_buffer_offset, | |
545 | + "MPUI730_CTRL_REG 0x%-8x \n" | |
546 | + "MPUI730_DSP_STATUS_REG: 0x%-8x \n" | |
547 | + "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n" | |
548 | + "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n" | |
549 | + "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n" | |
550 | + "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n", | |
551 | + MPUI730_SHOW(MPUI_CTRL), | |
552 | + MPUI730_SHOW(MPUI_DSP_STATUS), | |
553 | + MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG), | |
554 | + MPUI730_SHOW(MPUI_DSP_API_CONFIG), | |
555 | + MPUI730_SHOW(EMIFF_SDRAM_CONFIG), | |
556 | + MPUI730_SHOW(EMIFS_CONFIG)); | |
557 | + } else if (cpu_is_omap15xx()) { | |
558 | + my_buffer_offset += sprintf(my_base + my_buffer_offset, | |
559 | + "MPUI1510_CTRL_REG 0x%-8x \n" | |
560 | + "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" | |
561 | + "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n" | |
562 | + "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n" | |
563 | + "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n" | |
564 | + "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n", | |
565 | + MPUI1510_SHOW(MPUI_CTRL), | |
566 | + MPUI1510_SHOW(MPUI_DSP_STATUS), | |
567 | + MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG), | |
568 | + MPUI1510_SHOW(MPUI_DSP_API_CONFIG), | |
569 | + MPUI1510_SHOW(EMIFF_SDRAM_CONFIG), | |
570 | + MPUI1510_SHOW(EMIFS_CONFIG)); | |
571 | + } else if (cpu_is_omap16xx()) { | |
572 | + my_buffer_offset += sprintf(my_base + my_buffer_offset, | |
573 | + "MPUI1610_CTRL_REG 0x%-8x \n" | |
574 | + "MPUI1610_DSP_STATUS_REG: 0x%-8x \n" | |
575 | + "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n" | |
576 | + "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n" | |
577 | + "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n" | |
578 | + "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n", | |
579 | + MPUI1610_SHOW(MPUI_CTRL), | |
580 | + MPUI1610_SHOW(MPUI_DSP_STATUS), | |
581 | + MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG), | |
582 | + MPUI1610_SHOW(MPUI_DSP_API_CONFIG), | |
583 | + MPUI1610_SHOW(EMIFF_SDRAM_CONFIG), | |
584 | + MPUI1610_SHOW(EMIFS_CONFIG)); | |
585 | + } | |
586 | + | |
587 | + g_read_completed++; | |
588 | + } else if (g_read_completed >= 1) { | |
589 | + *eof = 1; | |
590 | + return 0; | |
591 | + } | |
592 | + g_read_completed++; | |
593 | + | |
594 | + *my_first_byte = page_buffer; | |
595 | + return my_buffer_offset; | |
596 | +} | |
597 | + | |
598 | +static void omap_pm_init_proc(void) | |
599 | +{ | |
600 | + struct proc_dir_entry *entry; | |
601 | + | |
602 | + entry = create_proc_read_entry("driver/omap_pm", | |
603 | + S_IWUSR | S_IRUGO, NULL, | |
604 | + omap_pm_read_proc, NULL); | |
605 | +} | |
606 | + | |
607 | +#endif /* DEBUG && CONFIG_PROC_FS */ | |
608 | + | |
609 | +static void (*saved_idle)(void) = NULL; | |
610 | + | |
611 | +/* | |
612 | + * omap_pm_prepare - Do preliminary suspend work. | |
613 | + * @state: suspend state we're entering. | |
614 | + * | |
615 | + */ | |
616 | +static int omap_pm_prepare(suspend_state_t state) | |
617 | +{ | |
618 | + int error = 0; | |
619 | + | |
620 | + /* We cannot sleep in idle until we have resumed */ | |
621 | + saved_idle = pm_idle; | |
622 | + pm_idle = NULL; | |
623 | + | |
624 | + switch (state) | |
625 | + { | |
626 | + case PM_SUSPEND_STANDBY: | |
627 | + case PM_SUSPEND_MEM: | |
628 | + break; | |
629 | + | |
630 | + case PM_SUSPEND_DISK: | |
631 | + return -ENOTSUPP; | |
632 | + | |
633 | + default: | |
634 | + return -EINVAL; | |
635 | + } | |
636 | + | |
637 | + return error; | |
638 | +} | |
639 | + | |
640 | + | |
641 | +/* | |
642 | + * omap_pm_enter - Actually enter a sleep state. | |
643 | + * @state: State we're entering. | |
644 | + * | |
645 | + */ | |
646 | + | |
647 | +static int omap_pm_enter(suspend_state_t state) | |
648 | +{ | |
649 | + switch (state) | |
650 | + { | |
651 | + case PM_SUSPEND_STANDBY: | |
652 | + case PM_SUSPEND_MEM: | |
653 | + omap_pm_suspend(); | |
654 | + break; | |
655 | + | |
656 | + case PM_SUSPEND_DISK: | |
657 | + return -ENOTSUPP; | |
658 | + | |
659 | + default: | |
660 | + return -EINVAL; | |
661 | + } | |
662 | + | |
663 | + return 0; | |
664 | +} | |
665 | + | |
666 | + | |
667 | +/** | |
668 | + * omap_pm_finish - Finish up suspend sequence. | |
669 | + * @state: State we're coming out of. | |
670 | + * | |
671 | + * This is called after we wake back up (or if entering the sleep state | |
672 | + * failed). | |
673 | + */ | |
674 | + | |
675 | +static int omap_pm_finish(suspend_state_t state) | |
676 | +{ | |
677 | + pm_idle = saved_idle; | |
678 | + return 0; | |
679 | +} | |
680 | + | |
681 | + | |
682 | +static irqreturn_t omap_wakeup_interrupt(int irq, void * dev, | |
683 | + struct pt_regs * regs) | |
684 | +{ | |
685 | + return IRQ_HANDLED; | |
686 | +} | |
687 | + | |
688 | +static struct irqaction omap_wakeup_irq = { | |
689 | + .name = "peripheral wakeup", | |
690 | + .flags = SA_INTERRUPT, | |
691 | + .handler = omap_wakeup_interrupt | |
692 | +}; | |
693 | + | |
694 | + | |
695 | + | |
696 | +static struct pm_ops omap_pm_ops ={ | |
697 | + .pm_disk_mode = 0, | |
698 | + .prepare = omap_pm_prepare, | |
699 | + .enter = omap_pm_enter, | |
700 | + .finish = omap_pm_finish, | |
701 | +}; | |
702 | + | |
703 | +static int __init omap_pm_init(void) | |
704 | +{ | |
705 | + printk("Power Management for TI OMAP.\n"); | |
706 | + | |
707 | + /* | |
708 | + * We copy the assembler sleep/wakeup routines to SRAM. | |
709 | + * These routines need to be in SRAM as that's the only | |
710 | + * memory the MPU can see when it wakes up. | |
711 | + */ | |
712 | + if (cpu_is_omap730()) { | |
713 | + omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend, | |
714 | + omap730_idle_loop_suspend_sz); | |
715 | + omap_sram_suspend = omap_sram_push(omap730_cpu_suspend, | |
716 | + omap730_cpu_suspend_sz); | |
717 | + } else if (cpu_is_omap15xx()) { | |
718 | + omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend, | |
719 | + omap1510_idle_loop_suspend_sz); | |
720 | + omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, | |
721 | + omap1510_cpu_suspend_sz); | |
722 | + } else if (cpu_is_omap16xx()) { | |
723 | + omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend, | |
724 | + omap1610_idle_loop_suspend_sz); | |
725 | + omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend, | |
726 | + omap1610_cpu_suspend_sz); | |
727 | + } | |
728 | + | |
729 | + if (omap_sram_idle == NULL || omap_sram_suspend == NULL) { | |
730 | + printk(KERN_ERR "PM not initialized: Missing SRAM support\n"); | |
731 | + return -ENODEV; | |
732 | + } | |
733 | + | |
734 | + pm_idle = omap_pm_idle; | |
735 | + | |
736 | + if (cpu_is_omap730()) | |
737 | + setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq); | |
738 | + else if (cpu_is_omap16xx()) | |
739 | + setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq); | |
740 | + | |
741 | + /* Program new power ramp-up time | |
742 | + * (0 for most boards since we don't lower voltage when in deep sleep) | |
743 | + */ | |
744 | + omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3); | |
745 | + | |
746 | + /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */ | |
747 | + omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); | |
748 | + | |
749 | + /* Configure IDLECT3 */ | |
750 | + if (cpu_is_omap730()) | |
751 | + omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3); | |
752 | + else if (cpu_is_omap16xx()) | |
753 | + omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); | |
754 | + | |
755 | + pm_set_ops(&omap_pm_ops); | |
756 | + | |
757 | +#if defined(DEBUG) && defined(CONFIG_PROC_FS) | |
758 | + omap_pm_init_proc(); | |
759 | +#endif | |
760 | + | |
761 | + subsys_create_file(&power_subsys, &sleep_while_idle_attr); | |
762 | + | |
763 | + if (cpu_is_omap16xx()) { | |
764 | + /* configure LOW_PWR pin */ | |
765 | + omap_cfg_reg(T20_1610_LOW_PWR); | |
766 | + } | |
767 | + | |
768 | + return 0; | |
769 | +} | |
770 | +__initcall(omap_pm_init); |
arch/arm/mach-omap1/sleep.S
1 | +/* | |
2 | + * linux/arch/arm/mach-omap1/sleep.S | |
3 | + * | |
4 | + * Low-level OMAP730/1510/1610 sleep/wakeUp support | |
5 | + * | |
6 | + * Initial SA1110 code: | |
7 | + * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | |
8 | + * | |
9 | + * Adapted for PXA by Nicolas Pitre: | |
10 | + * Copyright (c) 2002 Monta Vista Software, Inc. | |
11 | + * | |
12 | + * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or modify it | |
15 | + * under the terms of the GNU General Public License as published by the | |
16 | + * Free Software Foundation; either version 2 of the License, or (at your | |
17 | + * option) any later version. | |
18 | + * | |
19 | + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
20 | + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
21 | + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
22 | + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 | + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
25 | + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
26 | + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | + * | |
30 | + * You should have received a copy of the GNU General Public License along | |
31 | + * with this program; if not, write to the Free Software Foundation, Inc., | |
32 | + * 675 Mass Ave, Cambridge, MA 02139, USA. | |
33 | + */ | |
34 | + | |
35 | +#include <linux/config.h> | |
36 | +#include <linux/linkage.h> | |
37 | +#include <asm/assembler.h> | |
38 | +#include <asm/arch/io.h> | |
39 | +#include <asm/arch/pm.h> | |
40 | + | |
41 | + .text | |
42 | + | |
43 | +/* | |
44 | + * Forces OMAP into idle state | |
45 | + * | |
46 | + * omapXXXX_idle_loop_suspend() | |
47 | + * | |
48 | + * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
49 | + * wakes up it continues execution at the point it went to sleep. | |
50 | + * | |
51 | + * Note: Because of slightly different configuration values we have | |
52 | + * processor specific functions here. | |
53 | + */ | |
54 | + | |
55 | +#if defined(CONFIG_ARCH_OMAP730) | |
56 | +ENTRY(omap730_idle_loop_suspend) | |
57 | + | |
58 | + stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
59 | + | |
60 | + @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
61 | + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
62 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
63 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
64 | + | |
65 | + @ turn off clock domains | |
66 | + @ get ARM_IDLECT2 into r2 | |
67 | + ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
68 | + mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | |
69 | + orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | |
70 | + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
71 | + | |
72 | + @ request ARM idle | |
73 | + @ get ARM_IDLECT1 into r1 | |
74 | + ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
75 | + orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff | |
76 | + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
77 | + | |
78 | + mov r5, #IDLE_WAIT_CYCLES & 0xff | |
79 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
80 | +l_730: subs r5, r5, #1 | |
81 | + bne l_730 | |
82 | +/* | |
83 | + * Let's wait for the next clock tick to wake us up. | |
84 | + */ | |
85 | + mov r0, #0 | |
86 | + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
87 | +/* | |
88 | + * omap730_idle_loop_suspend()'s resume point. | |
89 | + * | |
90 | + * It will just start executing here, so we'll restore stuff from the | |
91 | + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
92 | + */ | |
93 | + | |
94 | + @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | |
95 | + @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | |
96 | + strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
97 | + strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
98 | + | |
99 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
100 | + | |
101 | +ENTRY(omap730_idle_loop_suspend_sz) | |
102 | + .word . - omap730_idle_loop_suspend | |
103 | +#endif /* CONFIG_ARCH_OMAP730 */ | |
104 | + | |
105 | +#ifdef CONFIG_ARCH_OMAP15XX | |
106 | +ENTRY(omap1510_idle_loop_suspend) | |
107 | + | |
108 | + stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
109 | + | |
110 | + @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
111 | + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
112 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
113 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
114 | + | |
115 | + @ turn off clock domains | |
116 | + @ get ARM_IDLECT2 into r2 | |
117 | + ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
118 | + mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | |
119 | + orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
120 | + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
121 | + | |
122 | + @ request ARM idle | |
123 | + @ get ARM_IDLECT1 into r1 | |
124 | + ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
125 | + orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff | |
126 | + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
127 | + | |
128 | + mov r5, #IDLE_WAIT_CYCLES & 0xff | |
129 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
130 | +l_1510: subs r5, r5, #1 | |
131 | + bne l_1510 | |
132 | +/* | |
133 | + * Let's wait for the next clock tick to wake us up. | |
134 | + */ | |
135 | + mov r0, #0 | |
136 | + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
137 | +/* | |
138 | + * omap1510_idle_loop_suspend()'s resume point. | |
139 | + * | |
140 | + * It will just start executing here, so we'll restore stuff from the | |
141 | + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
142 | + */ | |
143 | + | |
144 | + @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | |
145 | + @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | |
146 | + strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
147 | + strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
148 | + | |
149 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
150 | + | |
151 | +ENTRY(omap1510_idle_loop_suspend_sz) | |
152 | + .word . - omap1510_idle_loop_suspend | |
153 | +#endif /* CONFIG_ARCH_OMAP15XX */ | |
154 | + | |
155 | +#if defined(CONFIG_ARCH_OMAP16XX) | |
156 | +ENTRY(omap1610_idle_loop_suspend) | |
157 | + | |
158 | + stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
159 | + | |
160 | + @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
161 | + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
162 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
163 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
164 | + | |
165 | + @ turn off clock domains | |
166 | + @ get ARM_IDLECT2 into r2 | |
167 | + ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
168 | + mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | |
169 | + orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
170 | + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
171 | + | |
172 | + @ request ARM idle | |
173 | + @ get ARM_IDLECT1 into r1 | |
174 | + ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
175 | + orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff | |
176 | + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
177 | + | |
178 | + mov r5, #IDLE_WAIT_CYCLES & 0xff | |
179 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
180 | +l_1610: subs r5, r5, #1 | |
181 | + bne l_1610 | |
182 | +/* | |
183 | + * Let's wait for the next clock tick to wake us up. | |
184 | + */ | |
185 | + mov r0, #0 | |
186 | + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
187 | +/* | |
188 | + * omap1610_idle_loop_suspend()'s resume point. | |
189 | + * | |
190 | + * It will just start executing here, so we'll restore stuff from the | |
191 | + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
192 | + */ | |
193 | + | |
194 | + @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | |
195 | + @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | |
196 | + strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
197 | + strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
198 | + | |
199 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
200 | + | |
201 | +ENTRY(omap1610_idle_loop_suspend_sz) | |
202 | + .word . - omap1610_idle_loop_suspend | |
203 | +#endif /* CONFIG_ARCH_OMAP16XX */ | |
204 | + | |
205 | +/* | |
206 | + * Forces OMAP into deep sleep state | |
207 | + * | |
208 | + * omapXXXX_cpu_suspend() | |
209 | + * | |
210 | + * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed | |
211 | + * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 | |
212 | + * in register r1. | |
213 | + * | |
214 | + * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
215 | + * wakes up it continues execution at the point it went to sleep. | |
216 | + * | |
217 | + * Note: Because of errata work arounds we have processor specific functions | |
218 | + * here. They are mostly the same, but slightly different. | |
219 | + * | |
220 | + */ | |
221 | + | |
222 | +#if defined(CONFIG_ARCH_OMAP730) | |
223 | +ENTRY(omap730_cpu_suspend) | |
224 | + | |
225 | + @ save registers on stack | |
226 | + stmfd sp!, {r0 - r12, lr} | |
227 | + | |
228 | + @ Drain write cache | |
229 | + mov r4, #0 | |
230 | + mcr p15, 0, r0, c7, c10, 4 | |
231 | + nop | |
232 | + | |
233 | + @ load base address of Traffic Controller | |
234 | + mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
235 | + orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
236 | + orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
237 | + | |
238 | + @ prepare to put SDRAM into self-refresh manually | |
239 | + ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
240 | + orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
241 | + orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
242 | + str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
243 | + | |
244 | + @ prepare to put EMIFS to Sleep | |
245 | + ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
246 | + orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
247 | + str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
248 | + | |
249 | + @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
250 | + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
251 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
252 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
253 | + | |
254 | + @ turn off clock domains | |
255 | + @ do not disable PERCK (0x04) | |
256 | + mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | |
257 | + orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | |
258 | + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
259 | + | |
260 | + @ request ARM idle | |
261 | + mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff | |
262 | + orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 | |
263 | + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
264 | + | |
265 | + @ disable instruction cache | |
266 | + mrc p15, 0, r9, c1, c0, 0 | |
267 | + bic r2, r9, #0x1000 | |
268 | + mcr p15, 0, r2, c1, c0, 0 | |
269 | + nop | |
270 | + | |
271 | +/* | |
272 | + * Let's wait for the next wake up event to wake us up. r0 can't be | |
273 | + * used here because r0 holds ARM_IDLECT1 | |
274 | + */ | |
275 | + mov r2, #0 | |
276 | + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
277 | +/* | |
278 | + * omap730_cpu_suspend()'s resume point. | |
279 | + * | |
280 | + * It will just start executing here, so we'll restore stuff from the | |
281 | + * stack. | |
282 | + */ | |
283 | + @ re-enable Icache | |
284 | + mcr p15, 0, r9, c1, c0, 0 | |
285 | + | |
286 | + @ reset the ARM_IDLECT1 and ARM_IDLECT2. | |
287 | + strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
288 | + strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
289 | + | |
290 | + @ Restore EMIFF controls | |
291 | + str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
292 | + str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
293 | + | |
294 | + @ restore regs and return | |
295 | + ldmfd sp!, {r0 - r12, pc} | |
296 | + | |
297 | +ENTRY(omap730_cpu_suspend_sz) | |
298 | + .word . - omap730_cpu_suspend | |
299 | +#endif /* CONFIG_ARCH_OMAP730 */ | |
300 | + | |
301 | +#ifdef CONFIG_ARCH_OMAP15XX | |
302 | +ENTRY(omap1510_cpu_suspend) | |
303 | + | |
304 | + @ save registers on stack | |
305 | + stmfd sp!, {r0 - r12, lr} | |
306 | + | |
307 | + @ load base address of Traffic Controller | |
308 | + mov r4, #TCMIF_ASM_BASE & 0xff000000 | |
309 | + orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 | |
310 | + orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 | |
311 | + | |
312 | + @ work around errata of OMAP1510 PDE bit for TC shut down | |
313 | + @ clear PDE bit | |
314 | + ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
315 | + bic r5, r5, #PDE_BIT & 0xff | |
316 | + str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
317 | + | |
318 | + @ set PWD_EN bit | |
319 | + and r5, r5, #PWD_EN_BIT & 0xff | |
320 | + str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
321 | + | |
322 | + @ prepare to put SDRAM into self-refresh manually | |
323 | + ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
324 | + orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 | |
325 | + orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff | |
326 | + str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
327 | + | |
328 | + @ prepare to put EMIFS to Sleep | |
329 | + ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
330 | + orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff | |
331 | + str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
332 | + | |
333 | + @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
334 | + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
335 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
336 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
337 | + | |
338 | + @ turn off clock domains | |
339 | + mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | |
340 | + orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
341 | + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
342 | + | |
343 | + @ request ARM idle | |
344 | + mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff | |
345 | + orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 | |
346 | + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
347 | + | |
348 | + mov r5, #IDLE_WAIT_CYCLES & 0xff | |
349 | + orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
350 | +l_1510_2: | |
351 | + subs r5, r5, #1 | |
352 | + bne l_1510_2 | |
353 | +/* | |
354 | + * Let's wait for the next wake up event to wake us up. r0 can't be | |
355 | + * used here because r0 holds ARM_IDLECT1 | |
356 | + */ | |
357 | + mov r2, #0 | |
358 | + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
359 | +/* | |
360 | + * omap1510_cpu_suspend()'s resume point. | |
361 | + * | |
362 | + * It will just start executing here, so we'll restore stuff from the | |
363 | + * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
364 | + */ | |
365 | + strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
366 | + strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
367 | + | |
368 | + @ restore regs and return | |
369 | + ldmfd sp!, {r0 - r12, pc} | |
370 | + | |
371 | +ENTRY(omap1510_cpu_suspend_sz) | |
372 | + .word . - omap1510_cpu_suspend | |
373 | +#endif /* CONFIG_ARCH_OMAP15XX */ | |
374 | + | |
375 | +#if defined(CONFIG_ARCH_OMAP16XX) | |
376 | +ENTRY(omap1610_cpu_suspend) | |
377 | + | |
378 | + @ save registers on stack | |
379 | + stmfd sp!, {r0 - r12, lr} | |
380 | + | |
381 | + @ Drain write cache | |
382 | + mov r4, #0 | |
383 | + mcr p15, 0, r0, c7, c10, 4 | |
384 | + nop | |
385 | + | |
386 | + @ Load base address of Traffic Controller | |
387 | + mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
388 | + orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
389 | + orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
390 | + | |
391 | + @ Prepare to put SDRAM into self-refresh manually | |
392 | + ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
393 | + orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
394 | + orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
395 | + str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
396 | + | |
397 | + @ Prepare to put EMIFS to Sleep | |
398 | + ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
399 | + orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
400 | + str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
401 | + | |
402 | + @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
403 | + mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
404 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
405 | + orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
406 | + | |
407 | + @ Turn off clock domains | |
408 | + @ Do not disable PERCK (0x04) | |
409 | + mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | |
410 | + orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
411 | + strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
412 | + | |
413 | + @ Request ARM idle | |
414 | + mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff | |
415 | + orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 | |
416 | + strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
417 | + | |
418 | +/* | |
419 | + * Let's wait for the next wake up event to wake us up. r0 can't be | |
420 | + * used here because r0 holds ARM_IDLECT1 | |
421 | + */ | |
422 | + mov r2, #0 | |
423 | + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
424 | + | |
425 | + @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions | |
426 | + @ according to this formula: | |
427 | + @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV | |
428 | + @ Max DPLL_MULT = 18 | |
429 | + @ DPLL_DIV = 1 | |
430 | + @ ARMDIV = 1 | |
431 | + @ => 74 nop-instructions | |
432 | + nop | |
433 | + nop | |
434 | + nop | |
435 | + nop | |
436 | + nop | |
437 | + nop | |
438 | + nop | |
439 | + nop | |
440 | + nop | |
441 | + nop @10 | |
442 | + nop | |
443 | + nop | |
444 | + nop | |
445 | + nop | |
446 | + nop | |
447 | + nop | |
448 | + nop | |
449 | + nop | |
450 | + nop | |
451 | + nop @20 | |
452 | + nop | |
453 | + nop | |
454 | + nop | |
455 | + nop | |
456 | + nop | |
457 | + nop | |
458 | + nop | |
459 | + nop | |
460 | + nop | |
461 | + nop @30 | |
462 | + nop | |
463 | + nop | |
464 | + nop | |
465 | + nop | |
466 | + nop | |
467 | + nop | |
468 | + nop | |
469 | + nop | |
470 | + nop | |
471 | + nop @40 | |
472 | + nop | |
473 | + nop | |
474 | + nop | |
475 | + nop | |
476 | + nop | |
477 | + nop | |
478 | + nop | |
479 | + nop | |
480 | + nop | |
481 | + nop @50 | |
482 | + nop | |
483 | + nop | |
484 | + nop | |
485 | + nop | |
486 | + nop | |
487 | + nop | |
488 | + nop | |
489 | + nop | |
490 | + nop | |
491 | + nop @60 | |
492 | + nop | |
493 | + nop | |
494 | + nop | |
495 | + nop | |
496 | + nop | |
497 | + nop | |
498 | + nop | |
499 | + nop | |
500 | + nop | |
501 | + nop @70 | |
502 | + nop | |
503 | + nop | |
504 | + nop | |
505 | + nop @74 | |
506 | +/* | |
507 | + * omap1610_cpu_suspend()'s resume point. | |
508 | + * | |
509 | + * It will just start executing here, so we'll restore stuff from the | |
510 | + * stack. | |
511 | + */ | |
512 | + @ Restore the ARM_IDLECT1 and ARM_IDLECT2. | |
513 | + strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
514 | + strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
515 | + | |
516 | + @ Restore EMIFF controls | |
517 | + str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
518 | + str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
519 | + | |
520 | + @ Restore regs and return | |
521 | + ldmfd sp!, {r0 - r12, pc} | |
522 | + | |
523 | +ENTRY(omap1610_cpu_suspend_sz) | |
524 | + .word . - omap1610_cpu_suspend | |
525 | +#endif /* CONFIG_ARCH_OMAP16XX */ |
arch/arm/mach-omap2/pm.c
1 | +/* | |
2 | + * linux/arch/arm/mach-omap2/pm.c | |
3 | + * | |
4 | + * OMAP2 Power Management Routines | |
5 | + * | |
6 | + * Copyright (C) 2006 Nokia Corporation | |
7 | + * Tony Lindgren <tony@atomide.com> | |
8 | + * | |
9 | + * Copyright (C) 2005 Texas Instruments, Inc. | |
10 | + * Richard Woodruff <r-woodruff2@ti.com> | |
11 | + * | |
12 | + * Based on pm.c for omap1 | |
13 | + * | |
14 | + * This program is free software; you can redistribute it and/or modify | |
15 | + * it under the terms of the GNU General Public License version 2 as | |
16 | + * published by the Free Software Foundation. | |
17 | + */ | |
18 | + | |
19 | +#include <linux/pm.h> | |
20 | +#include <linux/sched.h> | |
21 | +#include <linux/proc_fs.h> | |
22 | +#include <linux/pm.h> | |
23 | +#include <linux/interrupt.h> | |
24 | +#include <linux/sysfs.h> | |
25 | +#include <linux/module.h> | |
26 | + | |
27 | +#include <asm/io.h> | |
28 | +#include <asm/irq.h> | |
29 | +#include <asm/atomic.h> | |
30 | +#include <asm/mach/time.h> | |
31 | +#include <asm/mach/irq.h> | |
32 | +#include <asm/mach-types.h> | |
33 | + | |
34 | +#include <asm/arch/irqs.h> | |
35 | +#include <asm/arch/clock.h> | |
36 | +#include <asm/arch/sram.h> | |
37 | +#include <asm/arch/pm.h> | |
38 | + | |
39 | +static struct clk *vclk; | |
40 | +static void (*omap2_sram_idle)(void); | |
41 | +static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); | |
42 | +static void (*saved_idle)(void); | |
43 | + | |
44 | +void omap2_pm_idle(void) | |
45 | +{ | |
46 | + local_irq_disable(); | |
47 | + local_fiq_disable(); | |
48 | + if (need_resched()) { | |
49 | + local_fiq_enable(); | |
50 | + local_irq_enable(); | |
51 | + return; | |
52 | + } | |
53 | + | |
54 | + /* | |
55 | + * Since an interrupt may set up a timer, we don't want to | |
56 | + * reprogram the hardware timer with interrupts enabled. | |
57 | + * Re-enable interrupts only after returning from idle. | |
58 | + */ | |
59 | + timer_dyn_reprogram(); | |
60 | + | |
61 | + omap2_sram_idle(); | |
62 | + local_fiq_enable(); | |
63 | + local_irq_enable(); | |
64 | +} | |
65 | + | |
66 | +static int omap2_pm_prepare(suspend_state_t state) | |
67 | +{ | |
68 | + int error = 0; | |
69 | + | |
70 | + /* We cannot sleep in idle until we have resumed */ | |
71 | + saved_idle = pm_idle; | |
72 | + pm_idle = NULL; | |
73 | + | |
74 | + switch (state) | |
75 | + { | |
76 | + case PM_SUSPEND_STANDBY: | |
77 | + case PM_SUSPEND_MEM: | |
78 | + break; | |
79 | + | |
80 | + case PM_SUSPEND_DISK: | |
81 | + return -ENOTSUPP; | |
82 | + | |
83 | + default: | |
84 | + return -EINVAL; | |
85 | + } | |
86 | + | |
87 | + return error; | |
88 | +} | |
89 | + | |
90 | +static int omap2_pm_enter(suspend_state_t state) | |
91 | +{ | |
92 | + switch (state) | |
93 | + { | |
94 | + case PM_SUSPEND_STANDBY: | |
95 | + case PM_SUSPEND_MEM: | |
96 | + /* FIXME: Add suspend */ | |
97 | + break; | |
98 | + | |
99 | + case PM_SUSPEND_DISK: | |
100 | + return -ENOTSUPP; | |
101 | + | |
102 | + default: | |
103 | + return -EINVAL; | |
104 | + } | |
105 | + | |
106 | + return 0; | |
107 | +} | |
108 | + | |
109 | +static int omap2_pm_finish(suspend_state_t state) | |
110 | +{ | |
111 | + pm_idle = saved_idle; | |
112 | + return 0; | |
113 | +} | |
114 | + | |
115 | +static struct pm_ops omap_pm_ops = { | |
116 | + .pm_disk_mode = 0, | |
117 | + .prepare = omap2_pm_prepare, | |
118 | + .enter = omap2_pm_enter, | |
119 | + .finish = omap2_pm_finish, | |
120 | +}; | |
121 | + | |
122 | +int __init omap2_pm_init(void) | |
123 | +{ | |
124 | + printk("Power Management for TI OMAP.\n"); | |
125 | + | |
126 | + vclk = clk_get(NULL, "virt_prcm_set"); | |
127 | + if (IS_ERR(vclk)) { | |
128 | + printk(KERN_ERR "Could not get PM vclk\n"); | |
129 | + return -ENODEV; | |
130 | + } | |
131 | + | |
132 | + /* | |
133 | + * We copy the assembler sleep/wakeup routines to SRAM. | |
134 | + * These routines need to be in SRAM as that's the only | |
135 | + * memory the MPU can see when it wakes up. | |
136 | + */ | |
137 | + omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, | |
138 | + omap24xx_idle_loop_suspend_sz); | |
139 | + | |
140 | + omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, | |
141 | + omap24xx_cpu_suspend_sz); | |
142 | + | |
143 | + pm_set_ops(&omap_pm_ops); | |
144 | + pm_idle = omap2_pm_idle; | |
145 | + | |
146 | + return 0; | |
147 | +} | |
148 | + | |
149 | +__initcall(omap2_pm_init); |
arch/arm/mach-omap2/sleep.S
1 | +/* | |
2 | + * linux/arch/arm/mach-omap2/sleep.S | |
3 | + * | |
4 | + * (C) Copyright 2004 | |
5 | + * Texas Instruments, <www.ti.com> | |
6 | + * Richard Woodruff <r-woodruff2@ti.com> | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or | |
9 | + * modify it under the terms of the GNU General Public License as | |
10 | + * published by the Free Software Foundation; either version 2 of | |
11 | + * the License, or (at your option) any later version. | |
12 | + * | |
13 | + * This program is distributed in the hope that it will be useful, | |
14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the | |
16 | + * GNU General Public License for more details. | |
17 | + * | |
18 | + * You should have received a copy of the GNU General Public License | |
19 | + * along with this program; if not, write to the Free Software | |
20 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
21 | + * MA 02111-1307 USA | |
22 | + */ | |
23 | + | |
24 | +#include <linux/config.h> | |
25 | +#include <linux/linkage.h> | |
26 | +#include <asm/assembler.h> | |
27 | +#include <asm/arch/io.h> | |
28 | +#include <asm/arch/pm.h> | |
29 | + | |
30 | +#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10) | |
31 | +#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50) | |
32 | +#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80) | |
33 | +#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500) | |
34 | +#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520) | |
35 | +#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540) | |
36 | +#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544) | |
37 | + | |
38 | +#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60) | |
39 | +#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70) | |
40 | +#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4) | |
41 | +#define A_SDRC0_V (0xC0000000) | |
42 | +#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8) | |
43 | + | |
44 | + .text | |
45 | + | |
46 | +/* | |
47 | + * Forces OMAP into idle state | |
48 | + * | |
49 | + * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI | |
50 | + * for normal idles. | |
51 | + * | |
52 | + * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
53 | + * wakes up it continues execution at the point it went to sleep. | |
54 | + */ | |
55 | +ENTRY(omap24xx_idle_loop_suspend) | |
56 | + stmfd sp!, {r0, lr} @ save registers on stack | |
57 | + mov r0, #0 @ clear for mcr setup | |
58 | + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
59 | + ldmfd sp!, {r0, pc} @ restore regs and return | |
60 | + | |
61 | +ENTRY(omap24xx_idle_loop_suspend_sz) | |
62 | + .word . - omap24xx_idle_loop_suspend | |
63 | + | |
64 | +/* | |
65 | + * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing | |
66 | + * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore | |
67 | + * SDRC. | |
68 | + * | |
69 | + * Input: | |
70 | + * R0 : DLL ctrl value pre-Sleep | |
71 | + * R1 : Processor+Revision | |
72 | + * 2420: 0x21 = 242xES1, 0x26 = 242xES2.2 | |
73 | + * 2430: 0x31 = 2430ES1, 0x32 = 2430ES2 | |
74 | + * | |
75 | + * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on | |
76 | + * when we get called, but the DLL probably isn't. We will wait a bit more in | |
77 | + * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even | |
78 | + * if in unlocked mode. | |
79 | + * | |
80 | + * For less than 242x-ES2.2 upon wake from a sleep mode where the external | |
81 | + * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz | |
82 | + * clock can pass into the PRCM can cause problems at DSP and IVA. | |
83 | + * To work around this the code will switch to the 32kHz source prior to sleep. | |
84 | + * Post sleep we will shift back to using the DPLL. Apparently, | |
85 | + * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait | |
86 | + * 3x12MHz + 3x32kHz clocks for a full switch. | |
87 | + * | |
88 | + * The DLL load value is not kept in RETENTION or OFF. It needs to be restored | |
89 | + * at wake | |
90 | + */ | |
91 | +ENTRY(omap24xx_cpu_suspend) | |
92 | + stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
93 | + mov r3, #0x0 @ clear for mrc call | |
94 | + mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished | |
95 | + nop | |
96 | + nop | |
97 | + ldr r3, A_SDRC_POWER @ addr of sdrc power | |
98 | + ldr r4, [r3] @ value of sdrc power | |
99 | + orr r4, r4, #0x40 @ enable self refresh on idle req | |
100 | + mov r5, #0x2000 @ set delay (DPLL relock + DLL relock) | |
101 | + str r4, [r3] @ make it so | |
102 | + mov r2, #0 | |
103 | + nop | |
104 | + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
105 | + nop | |
106 | +loop: | |
107 | + subs r5, r5, #0x1 @ awake, wait just a bit | |
108 | + bne loop | |
109 | + | |
110 | + /* The DPLL has on before we take the DDR out of self refresh */ | |
111 | + bic r4, r4, #0x40 @ now clear self refresh bit. | |
112 | + str r4, [r3] @ put vlaue back. | |
113 | + ldr r4, A_SDRC0 @ make a clock happen | |
114 | + ldr r4, [r4] | |
115 | + nop @ start auto refresh only after clk ok | |
116 | + movs r0, r0 @ see if DDR or SDR | |
117 | + ldrne r1, A_SDRC_DLLA_CTRL_S @ get addr of DLL ctrl | |
118 | + strne r0, [r1] @ rewrite DLLA to force DLL reload | |
119 | + addne r1, r1, #0x8 @ move to DLLB | |
120 | + strne r0, [r1] @ rewrite DLLB to force DLL reload | |
121 | + | |
122 | + mov r5, #0x1000 | |
123 | +loop2: | |
124 | + subs r5, r5, #0x1 | |
125 | + bne loop2 | |
126 | + /* resume*/ | |
127 | + ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
128 | + | |
129 | +A_SDRC_POWER: | |
130 | + .word A_SDRC_POWER_V | |
131 | +A_SDRC0: | |
132 | + .word A_SDRC0_V | |
133 | +A_CM_CLKSEL2_PLL_S: | |
134 | + .word A_CM_CLKSEL2_PLL_V | |
135 | +A_CM_CLKEN_PLL: | |
136 | + .word A_CM_CLKEN_PLL_V | |
137 | +A_SDRC_DLLA_CTRL_S: | |
138 | + .word A_SDRC_DLLA_CTRL_V | |
139 | +A_SDRC_MANUAL_S: | |
140 | + .word A_SDRC_MANUAL_V | |
141 | + | |
142 | +ENTRY(omap24xx_cpu_suspend_sz) | |
143 | + .word . - omap24xx_cpu_suspend |
arch/arm/mach-omap2/sram-fn.S
1 | 1 | /* |
2 | - * linux/arch/arm/mach-omap1/sram.S | |
2 | + * linux/arch/arm/mach-omap2/sram.S | |
3 | 3 | * |
4 | 4 | * Omap2 specific functions that need to be run in internal SRAM |
5 | 5 | * |
... | ... | @@ -28,7 +28,7 @@ |
28 | 28 | #include <asm/arch/io.h> |
29 | 29 | #include <asm/hardware.h> |
30 | 30 | |
31 | -#include <asm/arch/prcm.h> | |
31 | +#include "prcm-regs.h" | |
32 | 32 | |
33 | 33 | #define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010) |
34 | 34 |
arch/arm/plat-omap/pm.c
arch/arm/plat-omap/sleep.S
1 | -/* | |
2 | - * linux/arch/arm/plat-omap/sleep.S | |
3 | - * | |
4 | - * Low-level OMAP730/1510/1610 sleep/wakeUp support | |
5 | - * | |
6 | - * Initial SA1110 code: | |
7 | - * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> | |
8 | - * | |
9 | - * Adapted for PXA by Nicolas Pitre: | |
10 | - * Copyright (c) 2002 Monta Vista Software, Inc. | |
11 | - * | |
12 | - * Support for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com> | |
13 | - * | |
14 | - * This program is free software; you can redistribute it and/or modify it | |
15 | - * under the terms of the GNU General Public License as published by the | |
16 | - * Free Software Foundation; either version 2 of the License, or (at your | |
17 | - * option) any later version. | |
18 | - * | |
19 | - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
20 | - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
21 | - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
22 | - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 | - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
25 | - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
26 | - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | - * | |
30 | - * You should have received a copy of the GNU General Public License along | |
31 | - * with this program; if not, write to the Free Software Foundation, Inc., | |
32 | - * 675 Mass Ave, Cambridge, MA 02139, USA. | |
33 | - */ | |
34 | - | |
35 | -#include <linux/config.h> | |
36 | -#include <linux/linkage.h> | |
37 | -#include <asm/assembler.h> | |
38 | -#include <asm/arch/io.h> | |
39 | -#include <asm/arch/pm.h> | |
40 | - | |
41 | - .text | |
42 | - | |
43 | -/* | |
44 | - * Forces OMAP into idle state | |
45 | - * | |
46 | - * omapXXXX_idle_loop_suspend() | |
47 | - * | |
48 | - * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
49 | - * wakes up it continues execution at the point it went to sleep. | |
50 | - * | |
51 | - * Note: Because of slightly different configuration values we have | |
52 | - * processor specific functions here. | |
53 | - */ | |
54 | - | |
55 | -#if defined(CONFIG_ARCH_OMAP730) | |
56 | -ENTRY(omap730_idle_loop_suspend) | |
57 | - | |
58 | - stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
59 | - | |
60 | - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
61 | - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
62 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
63 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
64 | - | |
65 | - @ turn off clock domains | |
66 | - @ get ARM_IDLECT2 into r2 | |
67 | - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
68 | - mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | |
69 | - orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | |
70 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
71 | - | |
72 | - @ request ARM idle | |
73 | - @ get ARM_IDLECT1 into r1 | |
74 | - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
75 | - orr r3, r1, #OMAP730_IDLE_LOOP_REQUEST & 0xffff | |
76 | - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
77 | - | |
78 | - mov r5, #IDLE_WAIT_CYCLES & 0xff | |
79 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
80 | -l_730: subs r5, r5, #1 | |
81 | - bne l_730 | |
82 | -/* | |
83 | - * Let's wait for the next clock tick to wake us up. | |
84 | - */ | |
85 | - mov r0, #0 | |
86 | - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
87 | -/* | |
88 | - * omap730_idle_loop_suspend()'s resume point. | |
89 | - * | |
90 | - * It will just start executing here, so we'll restore stuff from the | |
91 | - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
92 | - */ | |
93 | - | |
94 | - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | |
95 | - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | |
96 | - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
97 | - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
98 | - | |
99 | - ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
100 | - | |
101 | -ENTRY(omap730_idle_loop_suspend_sz) | |
102 | - .word . - omap730_idle_loop_suspend | |
103 | -#endif /* CONFIG_ARCH_OMAP730 */ | |
104 | - | |
105 | -#ifdef CONFIG_ARCH_OMAP15XX | |
106 | -ENTRY(omap1510_idle_loop_suspend) | |
107 | - | |
108 | - stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
109 | - | |
110 | - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
111 | - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
112 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
113 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
114 | - | |
115 | - @ turn off clock domains | |
116 | - @ get ARM_IDLECT2 into r2 | |
117 | - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
118 | - mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | |
119 | - orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
120 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
121 | - | |
122 | - @ request ARM idle | |
123 | - @ get ARM_IDLECT1 into r1 | |
124 | - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
125 | - orr r3, r1, #OMAP1510_IDLE_LOOP_REQUEST & 0xffff | |
126 | - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
127 | - | |
128 | - mov r5, #IDLE_WAIT_CYCLES & 0xff | |
129 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
130 | -l_1510: subs r5, r5, #1 | |
131 | - bne l_1510 | |
132 | -/* | |
133 | - * Let's wait for the next clock tick to wake us up. | |
134 | - */ | |
135 | - mov r0, #0 | |
136 | - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
137 | -/* | |
138 | - * omap1510_idle_loop_suspend()'s resume point. | |
139 | - * | |
140 | - * It will just start executing here, so we'll restore stuff from the | |
141 | - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
142 | - */ | |
143 | - | |
144 | - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | |
145 | - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | |
146 | - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
147 | - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
148 | - | |
149 | - ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
150 | - | |
151 | -ENTRY(omap1510_idle_loop_suspend_sz) | |
152 | - .word . - omap1510_idle_loop_suspend | |
153 | -#endif /* CONFIG_ARCH_OMAP15XX */ | |
154 | - | |
155 | -#if defined(CONFIG_ARCH_OMAP16XX) | |
156 | -ENTRY(omap1610_idle_loop_suspend) | |
157 | - | |
158 | - stmfd sp!, {r0 - r12, lr} @ save registers on stack | |
159 | - | |
160 | - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
161 | - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
162 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
163 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
164 | - | |
165 | - @ turn off clock domains | |
166 | - @ get ARM_IDLECT2 into r2 | |
167 | - ldrh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
168 | - mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | |
169 | - orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
170 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
171 | - | |
172 | - @ request ARM idle | |
173 | - @ get ARM_IDLECT1 into r1 | |
174 | - ldrh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
175 | - orr r3, r1, #OMAP1610_IDLE_LOOP_REQUEST & 0xffff | |
176 | - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
177 | - | |
178 | - mov r5, #IDLE_WAIT_CYCLES & 0xff | |
179 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
180 | -l_1610: subs r5, r5, #1 | |
181 | - bne l_1610 | |
182 | -/* | |
183 | - * Let's wait for the next clock tick to wake us up. | |
184 | - */ | |
185 | - mov r0, #0 | |
186 | - mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt | |
187 | -/* | |
188 | - * omap1610_idle_loop_suspend()'s resume point. | |
189 | - * | |
190 | - * It will just start executing here, so we'll restore stuff from the | |
191 | - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
192 | - */ | |
193 | - | |
194 | - @ restore ARM_IDLECT1 and ARM_IDLECT2 and return | |
195 | - @ r1 has ARM_IDLECT1 and r2 still has ARM_IDLECT2 | |
196 | - strh r2, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
197 | - strh r1, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
198 | - | |
199 | - ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
200 | - | |
201 | -ENTRY(omap1610_idle_loop_suspend_sz) | |
202 | - .word . - omap1610_idle_loop_suspend | |
203 | -#endif /* CONFIG_ARCH_OMAP16XX */ | |
204 | - | |
205 | -/* | |
206 | - * Forces OMAP into deep sleep state | |
207 | - * | |
208 | - * omapXXXX_cpu_suspend() | |
209 | - * | |
210 | - * The values of the registers ARM_IDLECT1 and ARM_IDLECT2 are passed | |
211 | - * as arg0 and arg1 from caller. arg0 is stored in register r0 and arg1 | |
212 | - * in register r1. | |
213 | - * | |
214 | - * Note: This code get's copied to internal SRAM at boot. When the OMAP | |
215 | - * wakes up it continues execution at the point it went to sleep. | |
216 | - * | |
217 | - * Note: Because of errata work arounds we have processor specific functions | |
218 | - * here. They are mostly the same, but slightly different. | |
219 | - * | |
220 | - */ | |
221 | - | |
222 | -#if defined(CONFIG_ARCH_OMAP730) | |
223 | -ENTRY(omap730_cpu_suspend) | |
224 | - | |
225 | - @ save registers on stack | |
226 | - stmfd sp!, {r0 - r12, lr} | |
227 | - | |
228 | - @ Drain write cache | |
229 | - mov r4, #0 | |
230 | - mcr p15, 0, r0, c7, c10, 4 | |
231 | - nop | |
232 | - | |
233 | - @ load base address of Traffic Controller | |
234 | - mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
235 | - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
236 | - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
237 | - | |
238 | - @ prepare to put SDRAM into self-refresh manually | |
239 | - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
240 | - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
241 | - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
242 | - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
243 | - | |
244 | - @ prepare to put EMIFS to Sleep | |
245 | - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
246 | - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
247 | - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
248 | - | |
249 | - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
250 | - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
251 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
252 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
253 | - | |
254 | - @ turn off clock domains | |
255 | - @ do not disable PERCK (0x04) | |
256 | - mov r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff | |
257 | - orr r5, r5, #OMAP730_IDLECT2_SLEEP_VAL & 0xff00 | |
258 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
259 | - | |
260 | - @ request ARM idle | |
261 | - mov r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff | |
262 | - orr r3, r3, #OMAP730_IDLECT1_SLEEP_VAL & 0xff00 | |
263 | - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
264 | - | |
265 | - @ disable instruction cache | |
266 | - mrc p15, 0, r9, c1, c0, 0 | |
267 | - bic r2, r9, #0x1000 | |
268 | - mcr p15, 0, r2, c1, c0, 0 | |
269 | - nop | |
270 | - | |
271 | -/* | |
272 | - * Let's wait for the next wake up event to wake us up. r0 can't be | |
273 | - * used here because r0 holds ARM_IDLECT1 | |
274 | - */ | |
275 | - mov r2, #0 | |
276 | - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
277 | -/* | |
278 | - * omap730_cpu_suspend()'s resume point. | |
279 | - * | |
280 | - * It will just start executing here, so we'll restore stuff from the | |
281 | - * stack. | |
282 | - */ | |
283 | - @ re-enable Icache | |
284 | - mcr p15, 0, r9, c1, c0, 0 | |
285 | - | |
286 | - @ reset the ARM_IDLECT1 and ARM_IDLECT2. | |
287 | - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
288 | - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
289 | - | |
290 | - @ Restore EMIFF controls | |
291 | - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
292 | - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
293 | - | |
294 | - @ restore regs and return | |
295 | - ldmfd sp!, {r0 - r12, pc} | |
296 | - | |
297 | -ENTRY(omap730_cpu_suspend_sz) | |
298 | - .word . - omap730_cpu_suspend | |
299 | -#endif /* CONFIG_ARCH_OMAP730 */ | |
300 | - | |
301 | -#ifdef CONFIG_ARCH_OMAP15XX | |
302 | -ENTRY(omap1510_cpu_suspend) | |
303 | - | |
304 | - @ save registers on stack | |
305 | - stmfd sp!, {r0 - r12, lr} | |
306 | - | |
307 | - @ load base address of Traffic Controller | |
308 | - mov r4, #TCMIF_ASM_BASE & 0xff000000 | |
309 | - orr r4, r4, #TCMIF_ASM_BASE & 0x00ff0000 | |
310 | - orr r4, r4, #TCMIF_ASM_BASE & 0x0000ff00 | |
311 | - | |
312 | - @ work around errata of OMAP1510 PDE bit for TC shut down | |
313 | - @ clear PDE bit | |
314 | - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
315 | - bic r5, r5, #PDE_BIT & 0xff | |
316 | - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
317 | - | |
318 | - @ set PWD_EN bit | |
319 | - and r5, r5, #PWD_EN_BIT & 0xff | |
320 | - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
321 | - | |
322 | - @ prepare to put SDRAM into self-refresh manually | |
323 | - ldr r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
324 | - orr r5, r5, #SELF_REFRESH_MODE & 0xff000000 | |
325 | - orr r5, r5, #SELF_REFRESH_MODE & 0x000000ff | |
326 | - str r5, [r4, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
327 | - | |
328 | - @ prepare to put EMIFS to Sleep | |
329 | - ldr r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
330 | - orr r5, r5, #IDLE_EMIFS_REQUEST & 0xff | |
331 | - str r5, [r4, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
332 | - | |
333 | - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
334 | - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
335 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
336 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
337 | - | |
338 | - @ turn off clock domains | |
339 | - mov r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff | |
340 | - orr r5, r5, #OMAP1510_IDLE_CLOCK_DOMAINS & 0xff00 | |
341 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
342 | - | |
343 | - @ request ARM idle | |
344 | - mov r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff | |
345 | - orr r3, r3, #OMAP1510_DEEP_SLEEP_REQUEST & 0xff00 | |
346 | - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
347 | - | |
348 | - mov r5, #IDLE_WAIT_CYCLES & 0xff | |
349 | - orr r5, r5, #IDLE_WAIT_CYCLES & 0xff00 | |
350 | -l_1510_2: | |
351 | - subs r5, r5, #1 | |
352 | - bne l_1510_2 | |
353 | -/* | |
354 | - * Let's wait for the next wake up event to wake us up. r0 can't be | |
355 | - * used here because r0 holds ARM_IDLECT1 | |
356 | - */ | |
357 | - mov r2, #0 | |
358 | - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
359 | -/* | |
360 | - * omap1510_cpu_suspend()'s resume point. | |
361 | - * | |
362 | - * It will just start executing here, so we'll restore stuff from the | |
363 | - * stack, reset the ARM_IDLECT1 and ARM_IDLECT2. | |
364 | - */ | |
365 | - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
366 | - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
367 | - | |
368 | - @ restore regs and return | |
369 | - ldmfd sp!, {r0 - r12, pc} | |
370 | - | |
371 | -ENTRY(omap1510_cpu_suspend_sz) | |
372 | - .word . - omap1510_cpu_suspend | |
373 | -#endif /* CONFIG_ARCH_OMAP15XX */ | |
374 | - | |
375 | -#if defined(CONFIG_ARCH_OMAP16XX) | |
376 | -ENTRY(omap1610_cpu_suspend) | |
377 | - | |
378 | - @ save registers on stack | |
379 | - stmfd sp!, {r0 - r12, lr} | |
380 | - | |
381 | - @ Drain write cache | |
382 | - mov r4, #0 | |
383 | - mcr p15, 0, r0, c7, c10, 4 | |
384 | - nop | |
385 | - | |
386 | - @ load base address of Traffic Controller | |
387 | - mov r6, #TCMIF_ASM_BASE & 0xff000000 | |
388 | - orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 | |
389 | - orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 | |
390 | - | |
391 | - @ prepare to put SDRAM into self-refresh manually | |
392 | - ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
393 | - orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 | |
394 | - orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff | |
395 | - str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
396 | - | |
397 | - @ prepare to put EMIFS to Sleep | |
398 | - ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
399 | - orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff | |
400 | - str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
401 | - | |
402 | - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 | |
403 | - mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 | |
404 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 | |
405 | - orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 | |
406 | - | |
407 | - @ turn off clock domains | |
408 | - @ do not disable PERCK (0x04) | |
409 | - mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff | |
410 | - orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 | |
411 | - strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
412 | - | |
413 | - @ request ARM idle | |
414 | - mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff | |
415 | - orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 | |
416 | - strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
417 | - | |
418 | - @ disable instruction cache | |
419 | - mrc p15, 0, r9, c1, c0, 0 | |
420 | - bic r2, r9, #0x1000 | |
421 | - mcr p15, 0, r2, c1, c0, 0 | |
422 | - nop | |
423 | - | |
424 | -/* | |
425 | - * Let's wait for the next wake up event to wake us up. r0 can't be | |
426 | - * used here because r0 holds ARM_IDLECT1 | |
427 | - */ | |
428 | - mov r2, #0 | |
429 | - mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt | |
430 | -/* | |
431 | - * omap1610_cpu_suspend()'s resume point. | |
432 | - * | |
433 | - * It will just start executing here, so we'll restore stuff from the | |
434 | - * stack. | |
435 | - */ | |
436 | - @ re-enable Icache | |
437 | - mcr p15, 0, r9, c1, c0, 0 | |
438 | - | |
439 | - @ reset the ARM_IDLECT1 and ARM_IDLECT2. | |
440 | - strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] | |
441 | - strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] | |
442 | - | |
443 | - @ Restore EMIFF controls | |
444 | - str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] | |
445 | - str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] | |
446 | - | |
447 | - @ restore regs and return | |
448 | - ldmfd sp!, {r0 - r12, pc} | |
449 | - | |
450 | -ENTRY(omap1610_cpu_suspend_sz) | |
451 | - .word . - omap1610_cpu_suspend | |
452 | -#endif /* CONFIG_ARCH_OMAP16XX */ |
arch/arm/plat-omap/sram.c
... | ... | @@ -16,24 +16,94 @@ |
16 | 16 | #include <linux/kernel.h> |
17 | 17 | #include <linux/init.h> |
18 | 18 | |
19 | -#include <asm/mach/map.h> | |
20 | 19 | #include <asm/tlb.h> |
21 | 20 | #include <asm/io.h> |
22 | 21 | #include <asm/cacheflush.h> |
23 | 22 | |
23 | +#include <asm/mach/map.h> | |
24 | + | |
24 | 25 | #include <asm/arch/sram.h> |
26 | +#include <asm/arch/board.h> | |
25 | 27 | |
26 | 28 | #define OMAP1_SRAM_PA 0x20000000 |
27 | 29 | #define OMAP1_SRAM_VA 0xd0000000 |
28 | 30 | #define OMAP2_SRAM_PA 0x40200000 |
31 | +#define OMAP2_SRAM_PUB_PA 0x4020f800 | |
29 | 32 | #define OMAP2_SRAM_VA 0xd0000000 |
33 | +#define OMAP2_SRAM_PUB_VA 0xd0000800 | |
30 | 34 | |
35 | +#if defined(CONFIG_ARCH_OMAP24XX) | |
36 | +#define SRAM_BOOTLOADER_SZ 0x00 | |
37 | +#else | |
31 | 38 | #define SRAM_BOOTLOADER_SZ 0x80 |
39 | +#endif | |
32 | 40 | |
41 | +#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048) | |
42 | +#define VA_READPERM0 IO_ADDRESS(0x68005050) | |
43 | +#define VA_WRITEPERM0 IO_ADDRESS(0x68005058) | |
44 | +#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8) | |
45 | +#define GP_DEVICE 0x300 | |
46 | +#define TYPE_MASK 0x700 | |
47 | + | |
48 | +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) | |
49 | + | |
33 | 50 | static unsigned long omap_sram_base; |
34 | 51 | static unsigned long omap_sram_size; |
35 | 52 | static unsigned long omap_sram_ceil; |
36 | 53 | |
54 | +unsigned long omap_fb_sram_start; | |
55 | +unsigned long omap_fb_sram_size; | |
56 | + | |
57 | +/* Depending on the target RAMFS firewall setup, the public usable amount of | |
58 | + * SRAM varies. The default accessable size for all device types is 2k. A GP | |
59 | + * device allows ARM11 but not other initators for full size. This | |
60 | + * functionality seems ok until some nice security API happens. | |
61 | + */ | |
62 | +static int is_sram_locked(void) | |
63 | +{ | |
64 | + int type = 0; | |
65 | + | |
66 | + if (cpu_is_omap242x()) | |
67 | + type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK; | |
68 | + | |
69 | + if (type == GP_DEVICE) { | |
70 | + /* RAMFW: R/W access to all initators for all qualifier sets */ | |
71 | + if (cpu_is_omap242x()) { | |
72 | + __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */ | |
73 | + __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */ | |
74 | + __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */ | |
75 | + } | |
76 | + return 0; | |
77 | + } else | |
78 | + return 1; /* assume locked with no PPA or security driver */ | |
79 | +} | |
80 | + | |
81 | +void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, | |
82 | + unsigned long *start, unsigned long *size) | |
83 | +{ | |
84 | + const struct omap_fbmem_config *fbmem_conf; | |
85 | + | |
86 | + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); | |
87 | + if (fbmem_conf != NULL) { | |
88 | + *start = fbmem_conf->fb_sram_start; | |
89 | + *size = fbmem_conf->fb_sram_size; | |
90 | + } else { | |
91 | + *size = 0; | |
92 | + *start = 0; | |
93 | + } | |
94 | + | |
95 | + if (*size && ( | |
96 | + *start < start_avail || | |
97 | + *start + *size > start_avail + size_avail)) { | |
98 | + printk(KERN_ERR "invalid FB SRAM configuration\n"); | |
99 | + *start = start_avail; | |
100 | + *size = size_avail; | |
101 | + } | |
102 | + | |
103 | + if (*size) | |
104 | + pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size); | |
105 | +} | |
106 | + | |
37 | 107 | /* |
38 | 108 | * The amount of SRAM depends on the core type. |
39 | 109 | * Note that we cannot try to test for SRAM here because writes |
40 | 110 | |
41 | 111 | |
42 | 112 | |
... | ... | @@ -42,26 +112,45 @@ |
42 | 112 | */ |
43 | 113 | void __init omap_detect_sram(void) |
44 | 114 | { |
45 | - if (!cpu_is_omap24xx()) | |
115 | + unsigned long sram_start; | |
116 | + | |
117 | + if (cpu_is_omap24xx()) { | |
118 | + if (is_sram_locked()) { | |
119 | + omap_sram_base = OMAP2_SRAM_PUB_VA; | |
120 | + sram_start = OMAP2_SRAM_PUB_PA; | |
121 | + omap_sram_size = 0x800; /* 2K */ | |
122 | + } else { | |
123 | + omap_sram_base = OMAP2_SRAM_VA; | |
124 | + sram_start = OMAP2_SRAM_PA; | |
125 | + if (cpu_is_omap242x()) | |
126 | + omap_sram_size = 0xa0000; /* 640K */ | |
127 | + else if (cpu_is_omap243x()) | |
128 | + omap_sram_size = 0x10000; /* 64K */ | |
129 | + } | |
130 | + } else { | |
46 | 131 | omap_sram_base = OMAP1_SRAM_VA; |
47 | - else | |
48 | - omap_sram_base = OMAP2_SRAM_VA; | |
132 | + sram_start = OMAP1_SRAM_PA; | |
49 | 133 | |
50 | - if (cpu_is_omap730()) | |
51 | - omap_sram_size = 0x32000; /* 200K */ | |
52 | - else if (cpu_is_omap15xx()) | |
53 | - omap_sram_size = 0x30000; /* 192K */ | |
54 | - else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) | |
55 | - omap_sram_size = 0x4000; /* 16K */ | |
56 | - else if (cpu_is_omap1611()) | |
57 | - omap_sram_size = 0x3e800; /* 250K */ | |
58 | - else if (cpu_is_omap2420()) | |
59 | - omap_sram_size = 0xa0014; /* 640K */ | |
60 | - else { | |
61 | - printk(KERN_ERR "Could not detect SRAM size\n"); | |
62 | - omap_sram_size = 0x4000; | |
134 | + if (cpu_is_omap730()) | |
135 | + omap_sram_size = 0x32000; /* 200K */ | |
136 | + else if (cpu_is_omap15xx()) | |
137 | + omap_sram_size = 0x30000; /* 192K */ | |
138 | + else if (cpu_is_omap1610() || cpu_is_omap1621() || | |
139 | + cpu_is_omap1710()) | |
140 | + omap_sram_size = 0x4000; /* 16K */ | |
141 | + else if (cpu_is_omap1611()) | |
142 | + omap_sram_size = 0x3e800; /* 250K */ | |
143 | + else { | |
144 | + printk(KERN_ERR "Could not detect SRAM size\n"); | |
145 | + omap_sram_size = 0x4000; | |
146 | + } | |
63 | 147 | } |
64 | - | |
148 | + get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ, | |
149 | + omap_sram_size - SRAM_BOOTLOADER_SZ, | |
150 | + &omap_fb_sram_start, &omap_fb_sram_size); | |
151 | + if (omap_fb_sram_size) | |
152 | + omap_sram_size -= sram_start + omap_sram_size - | |
153 | + omap_fb_sram_start; | |
65 | 154 | omap_sram_ceil = omap_sram_base + omap_sram_size; |
66 | 155 | } |
67 | 156 | |
68 | 157 | |
... | ... | @@ -80,12 +169,20 @@ |
80 | 169 | */ |
81 | 170 | void __init omap_map_sram(void) |
82 | 171 | { |
172 | + unsigned long base; | |
173 | + | |
83 | 174 | if (omap_sram_size == 0) |
84 | 175 | return; |
85 | 176 | |
86 | 177 | if (cpu_is_omap24xx()) { |
87 | 178 | omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA; |
88 | - omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA); | |
179 | + | |
180 | + if (is_sram_locked()) | |
181 | + base = OMAP2_SRAM_PUB_PA; | |
182 | + else | |
183 | + base = OMAP2_SRAM_PA; | |
184 | + base = ROUND_DOWN(base, PAGE_SIZE); | |
185 | + omap_sram_io_desc[0].pfn = __phys_to_pfn(base); | |
89 | 186 | } |
90 | 187 | |
91 | 188 | omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; |
... | ... | @@ -93,7 +190,8 @@ |
93 | 190 | iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); |
94 | 191 | |
95 | 192 | printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n", |
96 | - omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual, | |
193 | + __pfn_to_phys(omap_sram_io_desc[0].pfn), | |
194 | + omap_sram_io_desc[0].virtual, | |
97 | 195 | omap_sram_io_desc[0].length); |
98 | 196 | |
99 | 197 | /* |
100 | 198 | |
... | ... | @@ -118,8 +216,9 @@ |
118 | 216 | printk(KERN_ERR "Not enough space in SRAM\n"); |
119 | 217 | return NULL; |
120 | 218 | } |
219 | + | |
121 | 220 | omap_sram_ceil -= size; |
122 | - omap_sram_ceil &= ~0x3; | |
221 | + omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *)); | |
123 | 222 | memcpy((void *)omap_sram_ceil, start, size); |
124 | 223 | |
125 | 224 | return (void *)omap_sram_ceil; |
include/asm-arm/arch-omap/pm.h
... | ... | @@ -49,7 +49,7 @@ |
49 | 49 | |
50 | 50 | /* |
51 | 51 | * ---------------------------------------------------------------------------- |
52 | - * Powermanagement bitmasks | |
52 | + * Power management bitmasks | |
53 | 53 | * ---------------------------------------------------------------------------- |
54 | 54 | */ |
55 | 55 | #define IDLE_WAIT_CYCLES 0x00000fff |
56 | 56 | |
57 | 57 | |
58 | 58 | |
59 | 59 | |
60 | 60 | |
61 | 61 | |
... | ... | @@ -112,32 +112,59 @@ |
112 | 112 | #endif |
113 | 113 | |
114 | 114 | #ifndef __ASSEMBLER__ |
115 | + | |
116 | +#include <linux/clk.h> | |
117 | + | |
118 | +extern void prevent_idle_sleep(void); | |
119 | +extern void allow_idle_sleep(void); | |
120 | + | |
121 | +/** | |
122 | + * clk_deny_idle - Prevents the clock from being idled during MPU idle | |
123 | + * @clk: clock signal handle | |
124 | + */ | |
125 | +void clk_deny_idle(struct clk *clk); | |
126 | + | |
127 | +/** | |
128 | + * clk_allow_idle - Counters previous clk_deny_idle | |
129 | + * @clk: clock signal handle | |
130 | + */ | |
131 | +void clk_deny_idle(struct clk *clk); | |
132 | + | |
115 | 133 | extern void omap_pm_idle(void); |
116 | 134 | extern void omap_pm_suspend(void); |
117 | 135 | extern void omap730_cpu_suspend(unsigned short, unsigned short); |
118 | 136 | extern void omap1510_cpu_suspend(unsigned short, unsigned short); |
119 | 137 | extern void omap1610_cpu_suspend(unsigned short, unsigned short); |
138 | +extern void omap24xx_cpu_suspend(u32 dll_ctrl, u32 cpu_revision); | |
120 | 139 | extern void omap730_idle_loop_suspend(void); |
121 | 140 | extern void omap1510_idle_loop_suspend(void); |
122 | 141 | extern void omap1610_idle_loop_suspend(void); |
142 | +extern void omap24xx_idle_loop_suspend(void); | |
123 | 143 | |
144 | +extern unsigned int omap730_cpu_suspend_sz; | |
145 | +extern unsigned int omap1510_cpu_suspend_sz; | |
146 | +extern unsigned int omap1610_cpu_suspend_sz; | |
147 | +extern unsigned int omap24xx_cpu_suspend_sz; | |
148 | +extern unsigned int omap730_idle_loop_suspend_sz; | |
149 | +extern unsigned int omap1510_idle_loop_suspend_sz; | |
150 | +extern unsigned int omap1610_idle_loop_suspend_sz; | |
151 | +extern unsigned int omap24xx_idle_loop_suspend_sz; | |
152 | + | |
124 | 153 | #ifdef CONFIG_OMAP_SERIAL_WAKE |
125 | 154 | extern void omap_serial_wake_trigger(int enable); |
126 | 155 | #else |
156 | +#define omap_serial_wakeup_init() {} | |
127 | 157 | #define omap_serial_wake_trigger(x) {} |
128 | 158 | #endif /* CONFIG_OMAP_SERIAL_WAKE */ |
129 | 159 | |
130 | -extern unsigned int omap730_cpu_suspend_sz; | |
131 | -extern unsigned int omap730_idle_loop_suspend_sz; | |
132 | -extern unsigned int omap1510_cpu_suspend_sz; | |
133 | -extern unsigned int omap1510_idle_loop_suspend_sz; | |
134 | -extern unsigned int omap1610_cpu_suspend_sz; | |
135 | -extern unsigned int omap1610_idle_loop_suspend_sz; | |
136 | - | |
137 | 160 | #define ARM_SAVE(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] = omap_readl(x) |
138 | 161 | #define ARM_RESTORE(x) omap_writel((arm_sleep_save[ARM_SLEEP_SAVE_##x]), (x)) |
139 | 162 | #define ARM_SHOW(x) arm_sleep_save[ARM_SLEEP_SAVE_##x] |
140 | 163 | |
164 | +#define DSP_SAVE(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] = __raw_readw(x) | |
165 | +#define DSP_RESTORE(x) __raw_writew((dsp_sleep_save[DSP_SLEEP_SAVE_##x]), (x)) | |
166 | +#define DSP_SHOW(x) dsp_sleep_save[DSP_SLEEP_SAVE_##x] | |
167 | + | |
141 | 168 | #define ULPD_SAVE(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] = omap_readw(x) |
142 | 169 | #define ULPD_RESTORE(x) omap_writew((ulpd_sleep_save[ULPD_SLEEP_SAVE_##x]), (x)) |
143 | 170 | #define ULPD_SHOW(x) ulpd_sleep_save[ULPD_SLEEP_SAVE_##x] |
... | ... | @@ -154,6 +181,10 @@ |
154 | 181 | #define MPUI1610_RESTORE(x) omap_writel((mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x]), (x)) |
155 | 182 | #define MPUI1610_SHOW(x) mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_##x] |
156 | 183 | |
184 | +#define OMAP24XX_SAVE(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] = x | |
185 | +#define OMAP24XX_RESTORE(x) x = omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] | |
186 | +#define OMAP24XX_SHOW(x) omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_##x] | |
187 | + | |
157 | 188 | /* |
158 | 189 | * List of global OMAP registers to preserve. |
159 | 190 | * More ones like CP and general purpose register values are preserved |
... | ... | @@ -176,6 +207,15 @@ |
176 | 207 | ARM_SLEEP_SAVE_SIZE |
177 | 208 | }; |
178 | 209 | |
210 | +enum dsp_save_state { | |
211 | + DSP_SLEEP_SAVE_START = 0, | |
212 | + /* | |
213 | + * DSP registers 16 bits | |
214 | + */ | |
215 | + DSP_SLEEP_SAVE_DSP_IDLECT2, | |
216 | + DSP_SLEEP_SAVE_SIZE | |
217 | +}; | |
218 | + | |
179 | 219 | enum ulpd_save_state { |
180 | 220 | ULPD_SLEEP_SAVE_START = 0, |
181 | 221 | /* |
... | ... | @@ -252,6 +292,31 @@ |
252 | 292 | #else |
253 | 293 | MPUI1610_SLEEP_SAVE_SIZE = 0 |
254 | 294 | #endif |
295 | +}; | |
296 | + | |
297 | +enum omap24xx_save_state { | |
298 | + OMAP24XX_SLEEP_SAVE_START = 0, | |
299 | + OMAP24XX_SLEEP_SAVE_INTC_MIR0, | |
300 | + OMAP24XX_SLEEP_SAVE_INTC_MIR1, | |
301 | + OMAP24XX_SLEEP_SAVE_INTC_MIR2, | |
302 | + OMAP24XX_SLEEP_SAVE_CM_FCLKEN1_CORE, | |
303 | + OMAP24XX_SLEEP_SAVE_CM_FCLKEN2_CORE, | |
304 | + OMAP24XX_SLEEP_SAVE_CM_ICLKEN1_CORE, | |
305 | + OMAP24XX_SLEEP_SAVE_CM_ICLKEN2_CORE, | |
306 | + OMAP24XX_SLEEP_SAVE_CM_ICLKEN4_CORE, | |
307 | + OMAP24XX_SLEEP_SAVE_GPIO1_IRQENABLE1, | |
308 | + OMAP24XX_SLEEP_SAVE_GPIO2_IRQENABLE1, | |
309 | + OMAP24XX_SLEEP_SAVE_GPIO3_IRQENABLE1, | |
310 | + OMAP24XX_SLEEP_SAVE_GPIO4_IRQENABLE1, | |
311 | + OMAP24XX_SLEEP_SAVE_GPIO3_OE, | |
312 | + OMAP24XX_SLEEP_SAVE_GPIO4_OE, | |
313 | + OMAP24XX_SLEEP_SAVE_GPIO3_RISINGDETECT, | |
314 | + OMAP24XX_SLEEP_SAVE_GPIO3_FALLINGDETECT, | |
315 | + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SPI1_NCS2, | |
316 | + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_MCBSP1_DX, | |
317 | + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SSI1_FLAG_TX, | |
318 | + OMAP24XX_SLEEP_SAVE_CONTROL_PADCONF_SYS_NIRQW0, | |
319 | + OMAP24XX_SLEEP_SAVE_SIZE | |
255 | 320 | }; |
256 | 321 | |
257 | 322 | #endif /* ASSEMBLER */ |
include/asm-arm/arch-omap/sram.h
... | ... | @@ -20,6 +20,8 @@ |
20 | 20 | u32 mem_type); |
21 | 21 | extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass); |
22 | 22 | |
23 | +extern unsigned long omap_fb_sram_start; | |
24 | +extern unsigned long omap_fb_sram_size; | |
23 | 25 | |
24 | 26 | /* Do not use these */ |
25 | 27 | extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl); |