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(void)
75 /* We cannot sleep in idle until we have resumed */
81 #define INT0_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) | \
82 OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) | \
83 OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3))
85 #define INT1_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4))
87 #define INT2_WAKE_MASK (OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) | \
88 OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) | \
89 OMAP_IRQ_BIT(INT_24XX_UART3_IRQ))
91 #define preg(reg) printk("%s\t(0x%p):\t0x%08x\n", #reg, ®, reg);
93 static void omap2_pm_debug(char * desc
)
95 printk("%s:\n", desc
);
97 preg(CM_CLKSTCTRL_MPU
);
98 preg(CM_CLKSTCTRL_CORE
);
99 preg(CM_CLKSTCTRL_GFX
);
100 preg(CM_CLKSTCTRL_DSP
);
101 preg(CM_CLKSTCTRL_MDM
);
103 preg(PM_PWSTCTRL_MPU
);
104 preg(PM_PWSTCTRL_CORE
);
105 preg(PM_PWSTCTRL_GFX
);
106 preg(PM_PWSTCTRL_DSP
);
107 preg(PM_PWSTCTRL_MDM
);
110 preg(PM_PWSTST_CORE
);
115 preg(CM_AUTOIDLE1_CORE
);
116 preg(CM_AUTOIDLE2_CORE
);
117 preg(CM_AUTOIDLE3_CORE
);
118 preg(CM_AUTOIDLE4_CORE
);
119 preg(CM_AUTOIDLE_WKUP
);
120 preg(CM_AUTOIDLE_PLL
);
121 preg(CM_AUTOIDLE_DSP
);
122 preg(CM_AUTOIDLE_MDM
);
124 preg(CM_ICLKEN1_CORE
);
125 preg(CM_ICLKEN2_CORE
);
126 preg(CM_ICLKEN3_CORE
);
127 preg(CM_ICLKEN4_CORE
);
129 preg(CM_ICLKEN_WKUP
);
133 preg(CM_IDLEST1_CORE
);
134 preg(CM_IDLEST2_CORE
);
135 preg(CM_IDLEST3_CORE
);
136 preg(CM_IDLEST4_CORE
);
138 preg(CM_IDLEST_WKUP
);
139 preg(CM_IDLEST_CKGEN
);
155 preg(CM_FCLKEN_WKUP
);
156 preg(CM_ICLKEN_WKUP
);
157 preg(CM_IDLEST_WKUP
);
158 preg(CM_AUTOIDLE_WKUP
);
159 preg(CM_CLKSEL_WKUP
);
165 static inline void omap2_pm_save_registers(void)
167 /* Save interrupt registers */
168 OMAP24XX_SAVE(INTC_MIR0
);
169 OMAP24XX_SAVE(INTC_MIR1
);
170 OMAP24XX_SAVE(INTC_MIR2
);
172 /* Save power control registers */
173 OMAP24XX_SAVE(CM_CLKSTCTRL_MPU
);
174 OMAP24XX_SAVE(CM_CLKSTCTRL_CORE
);
175 OMAP24XX_SAVE(CM_CLKSTCTRL_GFX
);
176 OMAP24XX_SAVE(CM_CLKSTCTRL_DSP
);
177 OMAP24XX_SAVE(CM_CLKSTCTRL_MDM
);
179 /* Save power state registers */
180 OMAP24XX_SAVE(PM_PWSTCTRL_MPU
);
181 OMAP24XX_SAVE(PM_PWSTCTRL_CORE
);
182 OMAP24XX_SAVE(PM_PWSTCTRL_GFX
);
183 OMAP24XX_SAVE(PM_PWSTCTRL_DSP
);
184 OMAP24XX_SAVE(PM_PWSTCTRL_MDM
);
186 /* Save autoidle registers */
187 OMAP24XX_SAVE(CM_AUTOIDLE1_CORE
);
188 OMAP24XX_SAVE(CM_AUTOIDLE2_CORE
);
189 OMAP24XX_SAVE(CM_AUTOIDLE3_CORE
);
190 OMAP24XX_SAVE(CM_AUTOIDLE4_CORE
);
191 OMAP24XX_SAVE(CM_AUTOIDLE_WKUP
);
192 OMAP24XX_SAVE(CM_AUTOIDLE_PLL
);
193 OMAP24XX_SAVE(CM_AUTOIDLE_DSP
);
194 OMAP24XX_SAVE(CM_AUTOIDLE_MDM
);
196 /* Save idle state registers */
197 OMAP24XX_SAVE(CM_IDLEST1_CORE
);
198 OMAP24XX_SAVE(CM_IDLEST2_CORE
);
199 OMAP24XX_SAVE(CM_IDLEST3_CORE
);
200 OMAP24XX_SAVE(CM_IDLEST4_CORE
);
201 OMAP24XX_SAVE(CM_IDLEST_GFX
);
202 OMAP24XX_SAVE(CM_IDLEST_WKUP
);
203 OMAP24XX_SAVE(CM_IDLEST_CKGEN
);
204 OMAP24XX_SAVE(CM_IDLEST_DSP
);
205 OMAP24XX_SAVE(CM_IDLEST_MDM
);
207 /* Save clock registers */
208 OMAP24XX_SAVE(CM_FCLKEN1_CORE
);
209 OMAP24XX_SAVE(CM_FCLKEN2_CORE
);
210 OMAP24XX_SAVE(CM_ICLKEN1_CORE
);
211 OMAP24XX_SAVE(CM_ICLKEN2_CORE
);
212 OMAP24XX_SAVE(CM_ICLKEN3_CORE
);
213 OMAP24XX_SAVE(CM_ICLKEN4_CORE
);
216 static inline void omap2_pm_restore_registers(void)
218 /* Restore clock state registers */
219 OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU
);
220 OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE
);
221 OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX
);
222 OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP
);
223 OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM
);
225 /* Restore power state registers */
226 OMAP24XX_RESTORE(PM_PWSTCTRL_MPU
);
227 OMAP24XX_RESTORE(PM_PWSTCTRL_CORE
);
228 OMAP24XX_RESTORE(PM_PWSTCTRL_GFX
);
229 OMAP24XX_RESTORE(PM_PWSTCTRL_DSP
);
230 OMAP24XX_RESTORE(PM_PWSTCTRL_MDM
);
232 /* Restore idle state registers */
233 OMAP24XX_RESTORE(CM_IDLEST1_CORE
);
234 OMAP24XX_RESTORE(CM_IDLEST2_CORE
);
235 OMAP24XX_RESTORE(CM_IDLEST3_CORE
);
236 OMAP24XX_RESTORE(CM_IDLEST4_CORE
);
237 OMAP24XX_RESTORE(CM_IDLEST_GFX
);
238 OMAP24XX_RESTORE(CM_IDLEST_WKUP
);
239 OMAP24XX_RESTORE(CM_IDLEST_CKGEN
);
240 OMAP24XX_RESTORE(CM_IDLEST_DSP
);
241 OMAP24XX_RESTORE(CM_IDLEST_MDM
);
243 /* Restore autoidle registers */
244 OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE
);
245 OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE
);
246 OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE
);
247 OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE
);
248 OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP
);
249 OMAP24XX_RESTORE(CM_AUTOIDLE_PLL
);
250 OMAP24XX_RESTORE(CM_AUTOIDLE_DSP
);
251 OMAP24XX_RESTORE(CM_AUTOIDLE_MDM
);
253 /* Restore clock registers */
254 OMAP24XX_RESTORE(CM_FCLKEN1_CORE
);
255 OMAP24XX_RESTORE(CM_FCLKEN2_CORE
);
256 OMAP24XX_RESTORE(CM_ICLKEN1_CORE
);
257 OMAP24XX_RESTORE(CM_ICLKEN2_CORE
);
258 OMAP24XX_RESTORE(CM_ICLKEN3_CORE
);
259 OMAP24XX_RESTORE(CM_ICLKEN4_CORE
);
261 /* REVISIT: Clear interrupts here */
263 /* Restore interrupt registers */
264 OMAP24XX_RESTORE(INTC_MIR0
);
265 OMAP24XX_RESTORE(INTC_MIR1
);
266 OMAP24XX_RESTORE(INTC_MIR2
);
269 static int omap2_pm_suspend(void)
271 int processor_type
= 0;
273 /* REVISIT: 0x21 or 0x26? */
274 if (cpu_is_omap2420())
275 processor_type
= 0x21;
283 omap2_pm_save_registers();
285 /* Disable interrupts except for the wake events */
286 INTC_MIR_SET0
= 0xffffffff & ~INT0_WAKE_MASK
;
287 INTC_MIR_SET1
= 0xffffffff & ~INT1_WAKE_MASK
;
288 INTC_MIR_SET2
= 0xffffffff & ~INT2_WAKE_MASK
;
290 pmdomain_set_autoidle();
292 /* Clear old wake-up events */
297 /* Enable wake-up events */
298 PM_WKEN1_CORE
= (1 << 22) | (1 << 21); /* UART1 & 2 */
299 PM_WKEN2_CORE
= (1 << 2); /* UART3 */
300 PM_WKEN_WKUP
= (1 << 2) | (1 << 0); /* GPIO & GPT1 */
302 /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled
303 * in the SRAM suspend code */
310 omap2_pm_debug("Status before suspend");
312 /* Must wait for serial buffers to clear */
315 /* Jump to SRAM suspend code
316 * REVISIT: When is this SDRC_DLLB_CTRL?
318 omap2_sram_suspend(SDRC_DLLA_CTRL
, processor_type
);
320 /* Back from sleep */
321 omap2_pm_restore_registers();
329 static int omap2_pm_enter(suspend_state_t state
)
335 case PM_SUSPEND_STANDBY
:
337 ret
= omap2_pm_suspend();
346 static void omap2_pm_finish(void)
348 pm_idle
= saved_idle
;
351 static struct platform_suspend_ops omap_pm_ops
= {
352 .prepare
= omap2_pm_prepare
,
353 .enter
= omap2_pm_enter
,
354 .finish
= omap2_pm_finish
,
355 .valid
= suspend_valid_only_mem
,
358 int __init
omap2_pm_init(void)
360 printk("Power Management for TI OMAP.\n");
362 vclk
= clk_get(NULL
, "virt_prcm_set");
364 printk(KERN_ERR
"Could not get PM vclk\n");
369 * We copy the assembler sleep/wakeup routines to SRAM.
370 * These routines need to be in SRAM as that's the only
371 * memory the MPU can see when it wakes up.
373 omap2_sram_idle
= omap_sram_push(omap24xx_idle_loop_suspend
,
374 omap24xx_idle_loop_suspend_sz
);
376 omap2_sram_suspend
= omap_sram_push(omap24xx_cpu_suspend
,
377 omap24xx_cpu_suspend_sz
);
379 suspend_set_ops(&omap_pm_ops
);
380 pm_idle
= omap2_pm_idle
;
387 __initcall(omap2_pm_init
);