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
42static struct clk *vclk;
43static void (*omap2_sram_idle)(void);
44static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
45static void (*saved_idle)(void);
46
47extern void __init pmdomain_init(void);
48extern void pmdomain_set_autoidle(void);
49
50static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
51
52void 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
74static 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
110static 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
182static 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
233static 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
286static 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
346static 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
366static int omap2_pm_finish(suspend_state_t state)
367{
368	pm_idle = saved_idle;
369	return 0;
370}
371
372static struct pm_ops omap_pm_ops = {
373	.prepare	= omap2_pm_prepare,
374	.enter		= omap2_pm_enter,
375	.finish		= omap2_pm_finish,
376	.valid		= pm_valid_only_mem,
377};
378
379int __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