xref: /linux/arch/arm/mach-omap2/pm.c (revision 14b42963f64b98ab61fa9723c03d71aa5ef4f862)
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 #include <linux/delay.h>
27 
28 #include <asm/io.h>
29 #include <asm/irq.h>
30 #include <asm/atomic.h>
31 #include <asm/mach/time.h>
32 #include <asm/mach/irq.h>
33 #include <asm/mach-types.h>
34 
35 #include <asm/arch/irqs.h>
36 #include <asm/arch/clock.h>
37 #include <asm/arch/sram.h>
38 #include <asm/arch/pm.h>
39 
40 #include "prcm-regs.h"
41 
42 static struct clk *vclk;
43 static void (*omap2_sram_idle)(void);
44 static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
45 static void (*saved_idle)(void);
46 
47 extern void __init pmdomain_init(void);
48 extern void pmdomain_set_autoidle(void);
49 
50 static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
51 
52 void omap2_pm_idle(void)
53 {
54 	local_irq_disable();
55 	local_fiq_disable();
56 	if (need_resched()) {
57 		local_fiq_enable();
58 		local_irq_enable();
59 		return;
60 	}
61 
62 	/*
63 	 * Since an interrupt may set up a timer, we don't want to
64 	 * reprogram the hardware timer with interrupts enabled.
65 	 * Re-enable interrupts only after returning from idle.
66 	 */
67 	timer_dyn_reprogram();
68 
69 	omap2_sram_idle();
70 	local_fiq_enable();
71 	local_irq_enable();
72 }
73 
74 static int omap2_pm_prepare(suspend_state_t state)
75 {
76 	int error = 0;
77 
78 	/* We cannot sleep in idle until we have resumed */
79 	saved_idle = pm_idle;
80 	pm_idle = NULL;
81 
82 	switch (state)
83 	{
84 	case PM_SUSPEND_STANDBY:
85 	case PM_SUSPEND_MEM:
86 		break;
87 
88 	case PM_SUSPEND_DISK:
89 		return -ENOTSUPP;
90 
91 	default:
92 		return -EINVAL;
93 	}
94 
95 	return error;
96 }
97 
98 #define INT0_WAKE_MASK	(OMAP_IRQ_BIT(INT_24XX_GPIO_BANK1) |	\
99 			OMAP_IRQ_BIT(INT_24XX_GPIO_BANK2) |	\
100 			OMAP_IRQ_BIT(INT_24XX_GPIO_BANK3))
101 
102 #define INT1_WAKE_MASK	(OMAP_IRQ_BIT(INT_24XX_GPIO_BANK4))
103 
104 #define INT2_WAKE_MASK	(OMAP_IRQ_BIT(INT_24XX_UART1_IRQ) |	\
105 			OMAP_IRQ_BIT(INT_24XX_UART2_IRQ) |	\
106 			OMAP_IRQ_BIT(INT_24XX_UART3_IRQ))
107 
108 #define preg(reg)	printk("%s\t(0x%p):\t0x%08x\n", #reg, &reg, reg);
109 
110 static void omap2_pm_debug(char * desc)
111 {
112 	printk("%s:\n", desc);
113 
114 	preg(CM_CLKSTCTRL_MPU);
115 	preg(CM_CLKSTCTRL_CORE);
116 	preg(CM_CLKSTCTRL_GFX);
117 	preg(CM_CLKSTCTRL_DSP);
118 	preg(CM_CLKSTCTRL_MDM);
119 
120 	preg(PM_PWSTCTRL_MPU);
121 	preg(PM_PWSTCTRL_CORE);
122 	preg(PM_PWSTCTRL_GFX);
123 	preg(PM_PWSTCTRL_DSP);
124 	preg(PM_PWSTCTRL_MDM);
125 
126 	preg(PM_PWSTST_MPU);
127 	preg(PM_PWSTST_CORE);
128 	preg(PM_PWSTST_GFX);
129 	preg(PM_PWSTST_DSP);
130 	preg(PM_PWSTST_MDM);
131 
132 	preg(CM_AUTOIDLE1_CORE);
133 	preg(CM_AUTOIDLE2_CORE);
134 	preg(CM_AUTOIDLE3_CORE);
135 	preg(CM_AUTOIDLE4_CORE);
136 	preg(CM_AUTOIDLE_WKUP);
137 	preg(CM_AUTOIDLE_PLL);
138 	preg(CM_AUTOIDLE_DSP);
139 	preg(CM_AUTOIDLE_MDM);
140 
141 	preg(CM_ICLKEN1_CORE);
142 	preg(CM_ICLKEN2_CORE);
143 	preg(CM_ICLKEN3_CORE);
144 	preg(CM_ICLKEN4_CORE);
145 	preg(CM_ICLKEN_GFX);
146 	preg(CM_ICLKEN_WKUP);
147 	preg(CM_ICLKEN_DSP);
148 	preg(CM_ICLKEN_MDM);
149 
150 	preg(CM_IDLEST1_CORE);
151 	preg(CM_IDLEST2_CORE);
152 	preg(CM_IDLEST3_CORE);
153 	preg(CM_IDLEST4_CORE);
154 	preg(CM_IDLEST_GFX);
155 	preg(CM_IDLEST_WKUP);
156 	preg(CM_IDLEST_CKGEN);
157 	preg(CM_IDLEST_DSP);
158 	preg(CM_IDLEST_MDM);
159 
160 	preg(RM_RSTST_MPU);
161 	preg(RM_RSTST_GFX);
162 	preg(RM_RSTST_WKUP);
163 	preg(RM_RSTST_DSP);
164 	preg(RM_RSTST_MDM);
165 
166 	preg(PM_WKDEP_MPU);
167 	preg(PM_WKDEP_CORE);
168 	preg(PM_WKDEP_GFX);
169 	preg(PM_WKDEP_DSP);
170 	preg(PM_WKDEP_MDM);
171 
172 	preg(CM_FCLKEN_WKUP);
173 	preg(CM_ICLKEN_WKUP);
174 	preg(CM_IDLEST_WKUP);
175 	preg(CM_AUTOIDLE_WKUP);
176 	preg(CM_CLKSEL_WKUP);
177 
178 	preg(PM_WKEN_WKUP);
179 	preg(PM_WKST_WKUP);
180 }
181 
182 static inline void omap2_pm_save_registers(void)
183 {
184 	/* Save interrupt registers */
185 	OMAP24XX_SAVE(INTC_MIR0);
186 	OMAP24XX_SAVE(INTC_MIR1);
187 	OMAP24XX_SAVE(INTC_MIR2);
188 
189 	/* Save power control registers */
190 	OMAP24XX_SAVE(CM_CLKSTCTRL_MPU);
191 	OMAP24XX_SAVE(CM_CLKSTCTRL_CORE);
192 	OMAP24XX_SAVE(CM_CLKSTCTRL_GFX);
193 	OMAP24XX_SAVE(CM_CLKSTCTRL_DSP);
194 	OMAP24XX_SAVE(CM_CLKSTCTRL_MDM);
195 
196 	/* Save power state registers */
197 	OMAP24XX_SAVE(PM_PWSTCTRL_MPU);
198 	OMAP24XX_SAVE(PM_PWSTCTRL_CORE);
199 	OMAP24XX_SAVE(PM_PWSTCTRL_GFX);
200 	OMAP24XX_SAVE(PM_PWSTCTRL_DSP);
201 	OMAP24XX_SAVE(PM_PWSTCTRL_MDM);
202 
203 	/* Save autoidle registers */
204 	OMAP24XX_SAVE(CM_AUTOIDLE1_CORE);
205 	OMAP24XX_SAVE(CM_AUTOIDLE2_CORE);
206 	OMAP24XX_SAVE(CM_AUTOIDLE3_CORE);
207 	OMAP24XX_SAVE(CM_AUTOIDLE4_CORE);
208 	OMAP24XX_SAVE(CM_AUTOIDLE_WKUP);
209 	OMAP24XX_SAVE(CM_AUTOIDLE_PLL);
210 	OMAP24XX_SAVE(CM_AUTOIDLE_DSP);
211 	OMAP24XX_SAVE(CM_AUTOIDLE_MDM);
212 
213 	/* Save idle state registers */
214 	OMAP24XX_SAVE(CM_IDLEST1_CORE);
215 	OMAP24XX_SAVE(CM_IDLEST2_CORE);
216 	OMAP24XX_SAVE(CM_IDLEST3_CORE);
217 	OMAP24XX_SAVE(CM_IDLEST4_CORE);
218 	OMAP24XX_SAVE(CM_IDLEST_GFX);
219 	OMAP24XX_SAVE(CM_IDLEST_WKUP);
220 	OMAP24XX_SAVE(CM_IDLEST_CKGEN);
221 	OMAP24XX_SAVE(CM_IDLEST_DSP);
222 	OMAP24XX_SAVE(CM_IDLEST_MDM);
223 
224 	/* Save clock registers */
225 	OMAP24XX_SAVE(CM_FCLKEN1_CORE);
226 	OMAP24XX_SAVE(CM_FCLKEN2_CORE);
227 	OMAP24XX_SAVE(CM_ICLKEN1_CORE);
228 	OMAP24XX_SAVE(CM_ICLKEN2_CORE);
229 	OMAP24XX_SAVE(CM_ICLKEN3_CORE);
230 	OMAP24XX_SAVE(CM_ICLKEN4_CORE);
231 }
232 
233 static inline void omap2_pm_restore_registers(void)
234 {
235 	/* Restore clock state registers */
236 	OMAP24XX_RESTORE(CM_CLKSTCTRL_MPU);
237 	OMAP24XX_RESTORE(CM_CLKSTCTRL_CORE);
238 	OMAP24XX_RESTORE(CM_CLKSTCTRL_GFX);
239 	OMAP24XX_RESTORE(CM_CLKSTCTRL_DSP);
240 	OMAP24XX_RESTORE(CM_CLKSTCTRL_MDM);
241 
242 	/* Restore power state registers */
243 	OMAP24XX_RESTORE(PM_PWSTCTRL_MPU);
244 	OMAP24XX_RESTORE(PM_PWSTCTRL_CORE);
245 	OMAP24XX_RESTORE(PM_PWSTCTRL_GFX);
246 	OMAP24XX_RESTORE(PM_PWSTCTRL_DSP);
247 	OMAP24XX_RESTORE(PM_PWSTCTRL_MDM);
248 
249 	/* Restore idle state registers */
250 	OMAP24XX_RESTORE(CM_IDLEST1_CORE);
251 	OMAP24XX_RESTORE(CM_IDLEST2_CORE);
252 	OMAP24XX_RESTORE(CM_IDLEST3_CORE);
253 	OMAP24XX_RESTORE(CM_IDLEST4_CORE);
254 	OMAP24XX_RESTORE(CM_IDLEST_GFX);
255 	OMAP24XX_RESTORE(CM_IDLEST_WKUP);
256 	OMAP24XX_RESTORE(CM_IDLEST_CKGEN);
257 	OMAP24XX_RESTORE(CM_IDLEST_DSP);
258 	OMAP24XX_RESTORE(CM_IDLEST_MDM);
259 
260 	/* Restore autoidle registers */
261 	OMAP24XX_RESTORE(CM_AUTOIDLE1_CORE);
262 	OMAP24XX_RESTORE(CM_AUTOIDLE2_CORE);
263 	OMAP24XX_RESTORE(CM_AUTOIDLE3_CORE);
264 	OMAP24XX_RESTORE(CM_AUTOIDLE4_CORE);
265 	OMAP24XX_RESTORE(CM_AUTOIDLE_WKUP);
266 	OMAP24XX_RESTORE(CM_AUTOIDLE_PLL);
267 	OMAP24XX_RESTORE(CM_AUTOIDLE_DSP);
268 	OMAP24XX_RESTORE(CM_AUTOIDLE_MDM);
269 
270 	/* Restore clock registers */
271 	OMAP24XX_RESTORE(CM_FCLKEN1_CORE);
272 	OMAP24XX_RESTORE(CM_FCLKEN2_CORE);
273 	OMAP24XX_RESTORE(CM_ICLKEN1_CORE);
274 	OMAP24XX_RESTORE(CM_ICLKEN2_CORE);
275 	OMAP24XX_RESTORE(CM_ICLKEN3_CORE);
276 	OMAP24XX_RESTORE(CM_ICLKEN4_CORE);
277 
278 	/* REVISIT: Clear interrupts here */
279 
280 	/* Restore interrupt registers */
281 	OMAP24XX_RESTORE(INTC_MIR0);
282 	OMAP24XX_RESTORE(INTC_MIR1);
283 	OMAP24XX_RESTORE(INTC_MIR2);
284 }
285 
286 static int omap2_pm_suspend(void)
287 {
288 	int processor_type = 0;
289 
290 	/* REVISIT: 0x21 or 0x26? */
291 	if (cpu_is_omap2420())
292 		processor_type = 0x21;
293 
294 	if (!processor_type)
295 		return -ENOTSUPP;
296 
297 	local_irq_disable();
298 	local_fiq_disable();
299 
300 	omap2_pm_save_registers();
301 
302 	/* Disable interrupts except for the wake events */
303 	INTC_MIR_SET0 = 0xffffffff & ~INT0_WAKE_MASK;
304 	INTC_MIR_SET1 = 0xffffffff & ~INT1_WAKE_MASK;
305 	INTC_MIR_SET2 = 0xffffffff & ~INT2_WAKE_MASK;
306 
307 	pmdomain_set_autoidle();
308 
309 	/* Clear old wake-up events */
310 	PM_WKST1_CORE = 0;
311 	PM_WKST2_CORE = 0;
312 	PM_WKST_WKUP = 0;
313 
314 	/* Enable wake-up events */
315 	PM_WKEN1_CORE = (1 << 22) | (1 << 21);	/* UART1 & 2 */
316 	PM_WKEN2_CORE = (1 << 2);		/* UART3 */
317 	PM_WKEN_WKUP = (1 << 2) | (1 << 0);	/* GPIO & GPT1 */
318 
319 	/* Disable clocks except for CM_ICLKEN2_CORE. It gets disabled
320 	 * in the SRAM suspend code */
321 	CM_FCLKEN1_CORE = 0;
322 	CM_FCLKEN2_CORE = 0;
323 	CM_ICLKEN1_CORE = 0;
324 	CM_ICLKEN3_CORE = 0;
325 	CM_ICLKEN4_CORE = 0;
326 
327 	omap2_pm_debug("Status before suspend");
328 
329 	/* Must wait for serial buffers to clear */
330 	mdelay(200);
331 
332 	/* Jump to SRAM suspend code
333 	 * REVISIT: When is this SDRC_DLLB_CTRL?
334 	 */
335 	omap2_sram_suspend(SDRC_DLLA_CTRL, processor_type);
336 
337 	/* Back from sleep */
338 	omap2_pm_restore_registers();
339 
340 	local_fiq_enable();
341 	local_irq_enable();
342 
343 	return 0;
344 }
345 
346 static int omap2_pm_enter(suspend_state_t state)
347 {
348 	int ret = 0;
349 
350 	switch (state)
351 	{
352 	case PM_SUSPEND_STANDBY:
353 	case PM_SUSPEND_MEM:
354 		ret = omap2_pm_suspend();
355 		break;
356 	case PM_SUSPEND_DISK:
357 		ret = -ENOTSUPP;
358 		break;
359 	default:
360 		ret = -EINVAL;
361 	}
362 
363 	return ret;
364 }
365 
366 static int omap2_pm_finish(suspend_state_t state)
367 {
368 	pm_idle = saved_idle;
369 	return 0;
370 }
371 
372 static struct pm_ops omap_pm_ops = {
373 	.pm_disk_mode	= 0,
374 	.prepare	= omap2_pm_prepare,
375 	.enter		= omap2_pm_enter,
376 	.finish		= omap2_pm_finish,
377 };
378 
379 int __init omap2_pm_init(void)
380 {
381 	printk("Power Management for TI OMAP.\n");
382 
383 	vclk = clk_get(NULL, "virt_prcm_set");
384 	if (IS_ERR(vclk)) {
385 		printk(KERN_ERR "Could not get PM vclk\n");
386 		return -ENODEV;
387 	}
388 
389 	/*
390 	 * We copy the assembler sleep/wakeup routines to SRAM.
391 	 * These routines need to be in SRAM as that's the only
392 	 * memory the MPU can see when it wakes up.
393 	 */
394 	omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
395 					 omap24xx_idle_loop_suspend_sz);
396 
397 	omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
398 					    omap24xx_cpu_suspend_sz);
399 
400 	pm_set_ops(&omap_pm_ops);
401 	pm_idle = omap2_pm_idle;
402 
403 	pmdomain_init();
404 
405 	return 0;
406 }
407 
408 __initcall(omap2_pm_init);
409