Pull cpuidle into release branch
[pandora-kernel.git] / 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/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>
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 #include "prcm-regs.h"
40
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);
45
46 extern void __init pmdomain_init(void);
47 extern void pmdomain_set_autoidle(void);
48
49 static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
50
51 void omap2_pm_idle(void)
52 {
53         local_irq_disable();
54         local_fiq_disable();
55         if (need_resched()) {
56                 local_fiq_enable();
57                 local_irq_enable();
58                 return;
59         }
60
61         /*
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.
65          */
66         timer_dyn_reprogram();
67
68         omap2_sram_idle();
69         local_fiq_enable();
70         local_irq_enable();
71 }
72
73 static int omap2_pm_prepare(void)
74 {
75         /* We cannot sleep in idle until we have resumed */
76         saved_idle = pm_idle;
77         pm_idle = NULL;
78         return 0;
79 }
80
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))
84
85 #define INT1_WAKE_MASK  (OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4))
86
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))
90
91 #define preg(reg)       printk("%s\t(0x%p):\t0x%08x\n", #reg, &reg, reg);
92
93 static void omap2_pm_debug(char * desc)
94 {
95         printk("%s:\n", desc);
96
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);
102
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);
108
109         preg(PM_PWSTST_MPU);
110         preg(PM_PWSTST_CORE);
111         preg(PM_PWSTST_GFX);
112         preg(PM_PWSTST_DSP);
113         preg(PM_PWSTST_MDM);
114
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);
123
124         preg(CM_ICLKEN1_CORE);
125         preg(CM_ICLKEN2_CORE);
126         preg(CM_ICLKEN3_CORE);
127         preg(CM_ICLKEN4_CORE);
128         preg(CM_ICLKEN_GFX);
129         preg(CM_ICLKEN_WKUP);
130         preg(CM_ICLKEN_DSP);
131         preg(CM_ICLKEN_MDM);
132
133         preg(CM_IDLEST1_CORE);
134         preg(CM_IDLEST2_CORE);
135         preg(CM_IDLEST3_CORE);
136         preg(CM_IDLEST4_CORE);
137         preg(CM_IDLEST_GFX);
138         preg(CM_IDLEST_WKUP);
139         preg(CM_IDLEST_CKGEN);
140         preg(CM_IDLEST_DSP);
141         preg(CM_IDLEST_MDM);
142
143         preg(RM_RSTST_MPU);
144         preg(RM_RSTST_GFX);
145         preg(RM_RSTST_WKUP);
146         preg(RM_RSTST_DSP);
147         preg(RM_RSTST_MDM);
148
149         preg(PM_WKDEP_MPU);
150         preg(PM_WKDEP_CORE);
151         preg(PM_WKDEP_GFX);
152         preg(PM_WKDEP_DSP);
153         preg(PM_WKDEP_MDM);
154
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);
160
161         preg(PM_WKEN_WKUP);
162         preg(PM_WKST_WKUP);
163 }
164
165 static inline void omap2_pm_save_registers(void)
166 {
167         /* Save interrupt registers */
168         OMAP24XX_SAVE(INTC_MIR0);
169         OMAP24XX_SAVE(INTC_MIR1);
170         OMAP24XX_SAVE(INTC_MIR2);
171
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);
178
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);
185
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);
195
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);
206
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);
214 }
215
216 static inline void omap2_pm_restore_registers(void)
217 {
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);
224
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);
231
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);
242
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);
252
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);
260
261         /* REVISIT: Clear interrupts here */
262
263         /* Restore interrupt registers */
264         OMAP24XX_RESTORE(INTC_MIR0);
265         OMAP24XX_RESTORE(INTC_MIR1);
266         OMAP24XX_RESTORE(INTC_MIR2);
267 }
268
269 static int omap2_pm_suspend(void)
270 {
271         int processor_type = 0;
272
273         /* REVISIT: 0x21 or 0x26? */
274         if (cpu_is_omap2420())
275                 processor_type = 0x21;
276
277         if (!processor_type)
278                 return -ENOTSUPP;
279
280         local_irq_disable();
281         local_fiq_disable();
282
283         omap2_pm_save_registers();
284
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;
289
290         pmdomain_set_autoidle();
291
292         /* Clear old wake-up events */
293         PM_WKST1_CORE = 0;
294         PM_WKST2_CORE = 0;
295         PM_WKST_WKUP = 0;
296
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 */
301
302         /* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled
303          * in the SRAM suspend code */
304         CM_FCLKEN1_CORE = 0;
305         CM_FCLKEN2_CORE = 0;
306         CM_ICLKEN1_CORE = 0;
307         CM_ICLKEN3_CORE = 0;
308         CM_ICLKEN4_CORE = 0;
309
310         omap2_pm_debug("Status before suspend");
311
312         /* Must wait for serial buffers to clear */
313         mdelay(200);
314
315         /* Jump to SRAM suspend code
316          * REVISIT: When is this SDRC_DLLB_CTRL?
317          */
318         omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type);
319
320         /* Back from sleep */
321         omap2_pm_restore_registers();
322
323         local_fiq_enable();
324         local_irq_enable();
325
326         return 0;
327 }
328
329 static int omap2_pm_enter(suspend_state_t state)
330 {
331         int ret = 0;
332
333         switch (state)
334         {
335         case PM_SUSPEND_STANDBY:
336         case PM_SUSPEND_MEM:
337                 ret = omap2_pm_suspend();
338                 break;
339         default:
340                 ret = -EINVAL;
341         }
342
343         return ret;
344 }
345
346 static void omap2_pm_finish(void)
347 {
348         pm_idle = saved_idle;
349 }
350
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,
356 };
357
358 int __init omap2_pm_init(void)
359 {
360         printk("Power Management for TI OMAP.\n");
361
362         vclk = clk_get(NULL, "virt_prcm_set");
363         if (IS_ERR(vclk)) {
364                 printk(KERN_ERR "Could not get PM vclk\n");
365                 return -ENODEV;
366         }
367
368         /*
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.
372          */
373         omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
374                                          omap24xx_idle_loop_suspend_sz);
375
376         omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
377                                             omap24xx_cpu_suspend_sz);
378
379         suspend_set_ops(&omap_pm_ops);
380         pm_idle = omap2_pm_idle;
381
382         pmdomain_init();
383
384         return 0;
385 }
386
387 __initcall(omap2_pm_init);