2 * linux/arch/arm/mach-omap2/pm.c
4 * OMAP2 Power Management Routines
6 * Copyright (C) 2006 Nokia Corporation
7 * Tony Lindgren <tony@atomide.com>
9 * Copyright (C) 2005 Texas Instruments, Inc.
10 * Richard Woodruff <r-woodruff2@ti.com>
12 * Based on pm.c for omap1
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.
19 #include <linux/suspend.h>
20 #include <linux/sched.h>
21 #include <linux/proc_fs.h>
22 #include <linux/interrupt.h>
23 #include <linux/sysfs.h>
24 #include <linux/module.h>
25 #include <linux/delay.h>
29 #include <asm/atomic.h>
30 #include <asm/mach/time.h>
31 #include <asm/mach/irq.h>
32 #include <asm/mach-types.h>
34 #include <asm/arch/irqs.h>
35 #include <asm/arch/clock.h>
36 #include <asm/arch/sram.h>
37 #include <asm/arch/pm.h>
39 #include "prcm-regs.h"
41 static struct clk *vclk;
42 static void (*omap2_sram_idle)(void);
43 static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
44 static void (*saved_idle)(void);
46 extern void __init pmdomain_init(void);
47 extern void pmdomain_set_autoidle(void);
49 static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
51 void omap2_pm_idle(void)
62 * Since an interrupt may set up a timer, we don't want to
63 * reprogram the hardware timer with interrupts enabled.
64 * Re-enable interrupts only after returning from idle.
66 timer_dyn_reprogram();
73 static int omap2_pm_prepare(suspend_state_t state)
77 /* We cannot sleep in idle until we have resumed */
83 case PM_SUSPEND_STANDBY:
94 #define INT0_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) | \
95 OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) | \
96 OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3))
98 #define INT1_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4))
100 #define INT2_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) | \
101 OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) | \
102 OMAP_IRQ_BIT(INT_24XX_UART3_IRQ))
104 #define preg(reg) printk("%s\t(0x%p):\t0x%08x\n", #reg, ®, reg);
106 static void omap2_pm_debug(char * desc)
108 printk("%s:\n", desc);
110 preg(CM_CLKSTCTRL_MPU);
111 preg(CM_CLKSTCTRL_CORE);
112 preg(CM_CLKSTCTRL_GFX);
113 preg(CM_CLKSTCTRL_DSP);
114 preg(CM_CLKSTCTRL_MDM);
116 preg(PM_PWSTCTRL_MPU);
117 preg(PM_PWSTCTRL_CORE);
118 preg(PM_PWSTCTRL_GFX);
119 preg(PM_PWSTCTRL_DSP);
120 preg(PM_PWSTCTRL_MDM);
123 preg(PM_PWSTST_CORE);
128 preg(CM_AUTOIDLE1_CORE);
129 preg(CM_AUTOIDLE2_CORE);
130 preg(CM_AUTOIDLE3_CORE);
131 preg(CM_AUTOIDLE4_CORE);
132 preg(CM_AUTOIDLE_WKUP);
133 preg(CM_AUTOIDLE_PLL);
134 preg(CM_AUTOIDLE_DSP);
135 preg(CM_AUTOIDLE_MDM);
137 preg(CM_ICLKEN1_CORE);
138 preg(CM_ICLKEN2_CORE);
139 preg(CM_ICLKEN3_CORE);
140 preg(CM_ICLKEN4_CORE);
142 preg(CM_ICLKEN_WKUP);
146 preg(CM_IDLEST1_CORE);
147 preg(CM_IDLEST2_CORE);
148 preg(CM_IDLEST3_CORE);
149 preg(CM_IDLEST4_CORE);
151 preg(CM_IDLEST_WKUP);
152 preg(CM_IDLEST_CKGEN);
168 preg(CM_FCLKEN_WKUP);
169 preg(CM_ICLKEN_WKUP);
170 preg(CM_IDLEST_WKUP);
171 preg(CM_AUTOIDLE_WKUP);
172 preg(CM_CLKSEL_WKUP);
178 static inline void omap2_pm_save_registers(void)
180 /* Save interrupt registers */
181 OMAP24XX_SAVE(INTC_MIR0);
182 OMAP24XX_SAVE(INTC_MIR1);
183 OMAP24XX_SAVE(INTC_MIR2);
185 /* Save power control registers */
186 OMAP24XX_SAVE(CM_CLKSTCTRL_MPU);
187 OMAP24XX_SAVE(CM_CLKSTCTRL_CORE);
188 OMAP24XX_SAVE(CM_CLKSTCTRL_GFX);
189 OMAP24XX_SAVE(CM_CLKSTCTRL_DSP);
190 OMAP24XX_SAVE(CM_CLKSTCTRL_MDM);
192 /* Save power state registers */
193 OMAP24XX_SAVE(PM_PWSTCTRL_MPU);
194 OMAP24XX_SAVE(PM_PWSTCTRL_CORE);
195 OMAP24XX_SAVE(PM_PWSTCTRL_GFX);
196 OMAP24XX_SAVE(PM_PWSTCTRL_DSP);
197 OMAP24XX_SAVE(PM_PWSTCTRL_MDM);
199 /* Save autoidle registers */
200 OMAP24XX_SAVE(CM_AUTOIDLE1_CORE);
201 OMAP24XX_SAVE(CM_AUTOIDLE2_CORE);
202 OMAP24XX_SAVE(CM_AUTOIDLE3_CORE);
203 OMAP24XX_SAVE(CM_AUTOIDLE4_CORE);
204 OMAP24XX_SAVE(CM_AUTOIDLE_WKUP);
205 OMAP24XX_SAVE(CM_AUTOIDLE_PLL);
206 OMAP24XX_SAVE(CM_AUTOIDLE_DSP);
207 OMAP24XX_SAVE(CM_AUTOIDLE_MDM);
209 /* Save idle state registers */
210 OMAP24XX_SAVE(CM_IDLEST1_CORE);
211 OMAP24XX_SAVE(CM_IDLEST2_CORE);
212 OMAP24XX_SAVE(CM_IDLEST3_CORE);
213 OMAP24XX_SAVE(CM_IDLEST4_CORE);
214 OMAP24XX_SAVE(CM_IDLEST_GFX);
215 OMAP24XX_SAVE(CM_IDLEST_WKUP);
216 OMAP24XX_SAVE(CM_IDLEST_CKGEN);
217 OMAP24XX_SAVE(CM_IDLEST_DSP);
218 OMAP24XX_SAVE(CM_IDLEST_MDM);
220 /* Save clock registers */
221 OMAP24XX_SAVE(CM_FCLKEN1_CORE);
222 OMAP24XX_SAVE(CM_FCLKEN2_CORE);
223 OMAP24XX_SAVE(CM_ICLKEN1_CORE);
224 OMAP24XX_SAVE(CM_ICLKEN2_CORE);
225 OMAP24XX_SAVE(CM_ICLKEN3_CORE);
226 OMAP24XX_SAVE(CM_ICLKEN4_CORE);
229 static inline void omap2_pm_restore_registers(void)
231 /* Restore clock state registers */
232 OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU);
233 OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE);
234 OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX);
235 OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP);
236 OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM);
238 /* Restore power state registers */
239 OMAP24XX_RESTORE(PM_PWSTCTRL_MPU);
240 OMAP24XX_RESTORE(PM_PWSTCTRL_CORE);
241 OMAP24XX_RESTORE(PM_PWSTCTRL_GFX);
242 OMAP24XX_RESTORE(PM_PWSTCTRL_DSP);
243 OMAP24XX_RESTORE(PM_PWSTCTRL_MDM);
245 /* Restore idle state registers */
246 OMAP24XX_RESTORE(CM_IDLEST1_CORE);
247 OMAP24XX_RESTORE(CM_IDLEST2_CORE);
248 OMAP24XX_RESTORE(CM_IDLEST3_CORE);
249 OMAP24XX_RESTORE(CM_IDLEST4_CORE);
250 OMAP24XX_RESTORE(CM_IDLEST_GFX);
251 OMAP24XX_RESTORE(CM_IDLEST_WKUP);
252 OMAP24XX_RESTORE(CM_IDLEST_CKGEN);
253 OMAP24XX_RESTORE(CM_IDLEST_DSP);
254 OMAP24XX_RESTORE(CM_IDLEST_MDM);
256 /* Restore autoidle registers */
257 OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE);
258 OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE);
259 OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE);
260 OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE);
261 OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP);
262 OMAP24XX_RESTORE(CM_AUTOIDLE_PLL);
263 OMAP24XX_RESTORE(CM_AUTOIDLE_DSP);
264 OMAP24XX_RESTORE(CM_AUTOIDLE_MDM);
266 /* Restore clock registers */
267 OMAP24XX_RESTORE(CM_FCLKEN1_CORE);
268 OMAP24XX_RESTORE(CM_FCLKEN2_CORE);
269 OMAP24XX_RESTORE(CM_ICLKEN1_CORE);
270 OMAP24XX_RESTORE(CM_ICLKEN2_CORE);
271 OMAP24XX_RESTORE(CM_ICLKEN3_CORE);
272 OMAP24XX_RESTORE(CM_ICLKEN4_CORE);
274 /* REVISIT: Clear interrupts here */
276 /* Restore interrupt registers */
277 OMAP24XX_RESTORE(INTC_MIR0);
278 OMAP24XX_RESTORE(INTC_MIR1);
279 OMAP24XX_RESTORE(INTC_MIR2);
282 static int omap2_pm_suspend(void)
284 int processor_type = 0;
286 /* REVISIT: 0x21 or 0x26? */
287 if (cpu_is_omap2420())
288 processor_type = 0x21;
296 omap2_pm_save_registers();
298 /* Disable interrupts except for the wake events */
299 INTC_MIR_SET0 = 0xffffffff & ~INT0_WAKE_MASK;
300 INTC_MIR_SET1 = 0xffffffff & ~INT1_WAKE_MASK;
301 INTC_MIR_SET2 = 0xffffffff & ~INT2_WAKE_MASK;
303 pmdomain_set_autoidle();
305 /* Clear old wake-up events */
310 /* Enable wake-up events */
311 PM_WKEN1_CORE = (1 << 22) | (1 << 21); /* UART1 & 2 */
312 PM_WKEN2_CORE = (1 << 2); /* UART3 */
313 PM_WKEN_WKUP = (1 << 2) | (1 << 0); /* GPIO & GPT1 */
315 /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled
316 * in the SRAM suspend code */
323 omap2_pm_debug("Status before suspend");
325 /* Must wait for serial buffers to clear */
328 /* Jump to SRAM suspend code
329 * REVISIT: When is this SDRC_DLLB_CTRL?
331 omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type);
333 /* Back from sleep */
334 omap2_pm_restore_registers();
342 static int omap2_pm_enter(suspend_state_t state)
348 case PM_SUSPEND_STANDBY:
350 ret = omap2_pm_suspend();
359 static int omap2_pm_finish(suspend_state_t state)
361 pm_idle = saved_idle;
365 static struct platform_suspend_ops omap_pm_ops = {
366 .prepare = omap2_pm_prepare,
367 .enter = omap2_pm_enter,
368 .finish = omap2_pm_finish,
369 .valid = suspend_valid_only_mem,
372 int __init omap2_pm_init(void)
374 printk("Power Management for TI OMAP.\n");
376 vclk = clk_get(NULL, "virt_prcm_set");
378 printk(KERN_ERR "Could not get PM vclk\n");
383 * We copy the assembler sleep/wakeup routines to SRAM.
384 * These routines need to be in SRAM as that's the only
385 * memory the MPU can see when it wakes up.
387 omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
388 omap24xx_idle_loop_suspend_sz);
390 omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
391 omap24xx_cpu_suspend_sz);
393 suspend_set_ops(&omap_pm_ops);
394 pm_idle = omap2_pm_idle;
401 __initcall(omap2_pm_init);