xref: /openbmc/linux/arch/arm/mach-omap2/pm.c (revision a1e58bbd)
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);
388