aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/Makefile2
-rw-r--r--arch/arm/mach-omap2/pm-domain.c300
-rw-r--r--arch/arm/mach-omap2/pm.c271
3 files changed, 566 insertions, 7 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 7a8edd6cd198..266d88e77bdc 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -9,7 +9,7 @@ obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o \
9obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o 9obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o
10 10
11# Power Management 11# Power Management
12obj-$(CONFIG_PM) += pm.o sleep.o 12obj-$(CONFIG_PM) += pm.o pm-domain.o sleep.o
13 13
14# Specific board support 14# Specific board support
15obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o 15obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c
new file mode 100644
index 000000000000..5e20e740cde5
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-domain.c
@@ -0,0 +1,300 @@
1/*
2 * linux/arch/arm/mach-omap2/pm-domain.c
3 *
4 * Power domain functions for OMAP2
5 *
6 * Copyright (C) 2006 Nokia Corporation
7 * Tony Lindgren <tony@atomide.com>
8 *
9 * Some code based on earlier OMAP2 sample PM code
10 * Copyright (C) 2005 Texas Instruments, Inc.
11 * Richard Woodruff <r-woodruff2@ti.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
18#include <linux/config.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/clk.h>
22
23#include <asm/io.h>
24
25#include "prcm-regs.h"
26
27/* Power domain offsets */
28#define PM_MPU_OFFSET 0x100
29#define PM_CORE_OFFSET 0x200
30#define PM_GFX_OFFSET 0x300
31#define PM_WKUP_OFFSET 0x400 /* Autoidle only */
32#define PM_PLL_OFFSET 0x500 /* Autoidle only */
33#define PM_DSP_OFFSET 0x800
34#define PM_MDM_OFFSET 0xc00
35
36/* Power domain wake-up dependency control register */
37#define PM_WKDEP_OFFSET 0xc8
38#define EN_MDM (1 << 5)
39#define EN_WKUP (1 << 4)
40#define EN_GFX (1 << 3)
41#define EN_DSP (1 << 2)
42#define EN_MPU (1 << 1)
43#define EN_CORE (1 << 0)
44
45/* Core power domain state transition control register */
46#define PM_PWSTCTRL_OFFSET 0xe0
47#define FORCESTATE (1 << 18) /* Only for DSP & GFX */
48#define MEM4RETSTATE (1 << 6)
49#define MEM3RETSTATE (1 << 5)
50#define MEM2RETSTATE (1 << 4)
51#define MEM1RETSTATE (1 << 3)
52#define LOGICRETSTATE (1 << 2) /* Logic is retained */
53#define POWERSTATE_OFF 0x3
54#define POWERSTATE_RETENTION 0x1
55#define POWERSTATE_ON 0x0
56
57/* Power domain state register */
58#define PM_PWSTST_OFFSET 0xe4
59
60/* Hardware supervised state transition control register */
61#define CM_CLKSTCTRL_OFFSET 0x48
62#define AUTOSTAT_MPU (1 << 0) /* MPU */
63#define AUTOSTAT_DSS (1 << 2) /* Core */
64#define AUTOSTAT_L4 (1 << 1) /* Core */
65#define AUTOSTAT_L3 (1 << 0) /* Core */
66#define AUTOSTAT_GFX (1 << 0) /* GFX */
67#define AUTOSTAT_IVA (1 << 8) /* 2420 IVA in DSP domain */
68#define AUTOSTAT_DSP (1 << 0) /* DSP */
69#define AUTOSTAT_MDM (1 << 0) /* MDM */
70
71/* Automatic control of interface clock idling */
72#define CM_AUTOIDLE1_OFFSET 0x30
73#define CM_AUTOIDLE2_OFFSET 0x34 /* Core only */
74#define CM_AUTOIDLE3_OFFSET 0x38 /* Core only */
75#define CM_AUTOIDLE4_OFFSET 0x3c /* Core only */
76#define AUTO_54M(x) (((x) & 0x3) << 6)
77#define AUTO_96M(x) (((x) & 0x3) << 2)
78#define AUTO_DPLL(x) (((x) & 0x3) << 0)
79#define AUTO_STOPPED 0x3
80#define AUTO_BYPASS_FAST 0x2 /* DPLL only */
81#define AUTO_BYPASS_LOW_POWER 0x1 /* DPLL only */
82#define AUTO_DISABLED 0x0
83
84/* Voltage control PRCM_VOLTCTRL bits */
85#define AUTO_EXTVOLT (1 << 15)
86#define FORCE_EXTVOLT (1 << 14)
87#define SETOFF_LEVEL(x) (((x) & 0x3) << 12)
88#define MEMRETCTRL (1 << 8)
89#define SETRET_LEVEL(x) (((x) & 0x3) << 6)
90#define VOLT_LEVEL(x) (((x) & 0x3) << 0)
91
92#define OMAP24XX_PRCM_VBASE IO_ADDRESS(OMAP24XX_PRCM_BASE)
93#define prcm_readl(r) __raw_readl(OMAP24XX_PRCM_VBASE + (r))
94#define prcm_writel(v, r) __raw_writel((v), OMAP24XX_PRCM_VBASE + (r))
95
96static u32 pmdomain_get_wakeup_dependencies(int domain_offset)
97{
98 return prcm_readl(domain_offset + PM_WKDEP_OFFSET);
99}
100
101static void pmdomain_set_wakeup_dependencies(u32 state, int domain_offset)
102{
103 prcm_writel(state, domain_offset + PM_WKDEP_OFFSET);
104}
105
106static u32 pmdomain_get_powerstate(int domain_offset)
107{
108 return prcm_readl(domain_offset + PM_PWSTCTRL_OFFSET);
109}
110
111static void pmdomain_set_powerstate(u32 state, int domain_offset)
112{
113 prcm_writel(state, domain_offset + PM_PWSTCTRL_OFFSET);
114}
115
116static u32 pmdomain_get_clock_autocontrol(int domain_offset)
117{
118 return prcm_readl(domain_offset + CM_CLKSTCTRL_OFFSET);
119}
120
121static void pmdomain_set_clock_autocontrol(u32 state, int domain_offset)
122{
123 prcm_writel(state, domain_offset + CM_CLKSTCTRL_OFFSET);
124}
125
126static u32 pmdomain_get_clock_autoidle1(int domain_offset)
127{
128 return prcm_readl(domain_offset + CM_AUTOIDLE1_OFFSET);
129}
130
131/* Core domain only */
132static u32 pmdomain_get_clock_autoidle2(int domain_offset)
133{
134 return prcm_readl(domain_offset + CM_AUTOIDLE2_OFFSET);
135}
136
137/* Core domain only */
138static u32 pmdomain_get_clock_autoidle3(int domain_offset)
139{
140 return prcm_readl(domain_offset + CM_AUTOIDLE3_OFFSET);
141}
142
143/* Core domain only */
144static u32 pmdomain_get_clock_autoidle4(int domain_offset)
145{
146 return prcm_readl(domain_offset + CM_AUTOIDLE4_OFFSET);
147}
148
149static void pmdomain_set_clock_autoidle1(u32 state, int domain_offset)
150{
151 prcm_writel(state, CM_AUTOIDLE1_OFFSET + domain_offset);
152}
153
154/* Core domain only */
155static void pmdomain_set_clock_autoidle2(u32 state, int domain_offset)
156{
157 prcm_writel(state, CM_AUTOIDLE2_OFFSET + domain_offset);
158}
159
160/* Core domain only */
161static void pmdomain_set_clock_autoidle3(u32 state, int domain_offset)
162{
163 prcm_writel(state, CM_AUTOIDLE3_OFFSET + domain_offset);
164}
165
166/* Core domain only */
167static void pmdomain_set_clock_autoidle4(u32 state, int domain_offset)
168{
169 prcm_writel(state, CM_AUTOIDLE4_OFFSET + domain_offset);
170}
171
172/*
173 * Configures power management domains to idle clocks automatically.
174 */
175void pmdomain_set_autoidle(void)
176{
177 u32 val;
178
179 /* Set PLL auto stop for 54M, 96M & DPLL */
180 pmdomain_set_clock_autoidle1(AUTO_54M(AUTO_STOPPED) |
181 AUTO_96M(AUTO_STOPPED) |
182 AUTO_DPLL(AUTO_STOPPED), PM_PLL_OFFSET);
183
184 /* External clock input control
185 * REVISIT: Should this be in clock framework?
186 */
187 PRCM_CLKSRC_CTRL |= (0x3 << 3);
188
189 /* Configure number of 32KHz clock cycles for sys_clk */
190 PRCM_CLKSSETUP = 0x00ff;
191
192 /* Configure automatic voltage transition */
193 PRCM_VOLTSETUP = 0;
194 val = PRCM_VOLTCTRL;
195 val &= ~(SETOFF_LEVEL(0x3) | VOLT_LEVEL(0x3));
196 val |= SETOFF_LEVEL(1) | VOLT_LEVEL(1) | AUTO_EXTVOLT;
197 PRCM_VOLTCTRL = val;
198
199 /* Disable emulation tools functional clock */
200 PRCM_CLKEMUL_CTRL = 0x0;
201
202 /* Set core memory retention state */
203 val = pmdomain_get_powerstate(PM_CORE_OFFSET);
204 if (cpu_is_omap2420()) {
205 val &= ~(0x7 << 3);
206 val |= (MEM3RETSTATE | MEM2RETSTATE | MEM1RETSTATE);
207 } else {
208 val &= ~(0xf << 3);
209 val |= (MEM4RETSTATE | MEM3RETSTATE | MEM2RETSTATE |
210 MEM1RETSTATE);
211 }
212 pmdomain_set_powerstate(val, PM_CORE_OFFSET);
213
214 /* OCP interface smart idle. REVISIT: Enable autoidle bit0 ? */
215 val = SMS_SYSCONFIG;
216 val &= ~(0x3 << 3);
217 val |= (0x2 << 3) | (1 << 0);
218 SMS_SYSCONFIG |= val;
219
220 val = SDRC_SYSCONFIG;
221 val &= ~(0x3 << 3);
222 val |= (0x2 << 3);
223 SDRC_SYSCONFIG = val;
224
225 /* Configure L3 interface for smart idle.
226 * REVISIT: Enable autoidle bit0 ?
227 */
228 val = GPMC_SYSCONFIG;
229 val &= ~(0x3 << 3);
230 val |= (0x2 << 3) | (1 << 0);
231 GPMC_SYSCONFIG = val;
232
233 pmdomain_set_powerstate(LOGICRETSTATE | POWERSTATE_RETENTION,
234 PM_MPU_OFFSET);
235 pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_CORE_OFFSET);
236 if (!cpu_is_omap2420())
237 pmdomain_set_powerstate(POWERSTATE_RETENTION, PM_MDM_OFFSET);
238
239 /* Assume suspend function has saved the state for DSP and GFX */
240 pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_DSP_OFFSET);
241 pmdomain_set_powerstate(FORCESTATE | POWERSTATE_OFF, PM_GFX_OFFSET);
242
243#if 0
244 /* REVISIT: Internal USB needs special handling */
245 force_standby_usb();
246 if (cpu_is_omap2430())
247 force_hsmmc();
248 sdram_self_refresh_on_idle_req(1);
249#endif
250
251 /* Enable clock auto control for all domains.
252 * Note that CORE domain includes also DSS, L4 & L3.
253 */
254 pmdomain_set_clock_autocontrol(AUTOSTAT_MPU, PM_MPU_OFFSET);
255 pmdomain_set_clock_autocontrol(AUTOSTAT_GFX, PM_GFX_OFFSET);
256 pmdomain_set_clock_autocontrol(AUTOSTAT_DSS | AUTOSTAT_L4 | AUTOSTAT_L3,
257 PM_CORE_OFFSET);
258 if (cpu_is_omap2420())
259 pmdomain_set_clock_autocontrol(AUTOSTAT_IVA | AUTOSTAT_DSP,
260 PM_DSP_OFFSET);
261 else {
262 pmdomain_set_clock_autocontrol(AUTOSTAT_DSP, PM_DSP_OFFSET);
263 pmdomain_set_clock_autocontrol(AUTOSTAT_MDM, PM_MDM_OFFSET);
264 }
265
266 /* Enable clock autoidle for all domains */
267 pmdomain_set_clock_autoidle1(0x2, PM_DSP_OFFSET);
268 if (cpu_is_omap2420()) {
269 pmdomain_set_clock_autoidle1(0xfffffff9, PM_CORE_OFFSET);
270 pmdomain_set_clock_autoidle2(0x7, PM_CORE_OFFSET);
271 pmdomain_set_clock_autoidle1(0x3f, PM_WKUP_OFFSET);
272 } else {
273 pmdomain_set_clock_autoidle1(0xeafffff1, PM_CORE_OFFSET);
274 pmdomain_set_clock_autoidle2(0xfff, PM_CORE_OFFSET);
275 pmdomain_set_clock_autoidle1(0x7f, PM_WKUP_OFFSET);
276 pmdomain_set_clock_autoidle1(0x3, PM_MDM_OFFSET);
277 }
278 pmdomain_set_clock_autoidle3(0x7, PM_CORE_OFFSET);
279 pmdomain_set_clock_autoidle4(0x1f, PM_CORE_OFFSET);
280}
281
282/*
283 * Initializes power domains by removing wake-up dependencies and powering
284 * down DSP and GFX. Gets called from PM init. Note that DSP and IVA code
285 * must re-enable DSP and GFX when used.
286 */
287void __init pmdomain_init(void)
288{
289 /* Remove all domain wakeup dependencies */
290 pmdomain_set_wakeup_dependencies(EN_WKUP | EN_CORE, PM_MPU_OFFSET);
291 pmdomain_set_wakeup_dependencies(0, PM_DSP_OFFSET);
292 pmdomain_set_wakeup_dependencies(0, PM_GFX_OFFSET);
293 pmdomain_set_wakeup_dependencies(EN_WKUP | EN_MPU, PM_CORE_OFFSET);
294 if (cpu_is_omap2430())
295 pmdomain_set_wakeup_dependencies(0, PM_MDM_OFFSET);
296
297 /* Power down DSP and GFX */
298 pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_DSP_OFFSET);
299 pmdomain_set_powerstate(POWERSTATE_OFF | FORCESTATE, PM_GFX_OFFSET);
300}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 562168fa2b16..d7eee99b7e3f 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -23,6 +23,7 @@
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/sysfs.h> 24#include <linux/sysfs.h>
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/delay.h>
26 27
27#include <asm/io.h> 28#include <asm/io.h>
28#include <asm/irq.h> 29#include <asm/irq.h>
@@ -36,11 +37,18 @@
36#include <asm/arch/sram.h> 37#include <asm/arch/sram.h>
37#include <asm/arch/pm.h> 38#include <asm/arch/pm.h>
38 39
40#include "prcm-regs.h"
41
39static struct clk *vclk; 42static struct clk *vclk;
40static void (*omap2_sram_idle)(void); 43static void (*omap2_sram_idle)(void);
41static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); 44static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
42static void (*saved_idle)(void); 45static void (*saved_idle)(void);
43 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
44void omap2_pm_idle(void) 52void omap2_pm_idle(void)
45{ 53{
46 local_irq_disable(); 54 local_irq_disable();
@@ -87,23 +95,272 @@ static int omap2_pm_prepare(suspend_state_t state)
87 return error; 95 return error;
88} 96}
89 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
90static int omap2_pm_enter(suspend_state_t state) 346static int omap2_pm_enter(suspend_state_t state)
91{ 347{
348 int ret = 0;
349
92 switch (state) 350 switch (state)
93 { 351 {
94 case PM_SUSPEND_STANDBY: 352 case PM_SUSPEND_STANDBY:
95 case PM_SUSPEND_MEM: 353 case PM_SUSPEND_MEM:
96 /* FIXME: Add suspend */ 354 ret = omap2_pm_suspend();
97 break; 355 break;
98
99 case PM_SUSPEND_DISK: 356 case PM_SUSPEND_DISK:
100 return -ENOTSUPP; 357 ret = -ENOTSUPP;
101 358 break;
102 default: 359 default:
103 return -EINVAL; 360 ret = -EINVAL;
104 } 361 }
105 362
106 return 0; 363 return ret;
107} 364}
108 365
109static int omap2_pm_finish(suspend_state_t state) 366static int omap2_pm_finish(suspend_state_t state)
@@ -143,6 +400,8 @@ int __init omap2_pm_init(void)
143 pm_set_ops(&omap_pm_ops); 400 pm_set_ops(&omap_pm_ops);
144 pm_idle = omap2_pm_idle; 401 pm_idle = omap2_pm_idle;
145 402
403 pmdomain_init();
404
146 return 0; 405 return 0;
147} 406}
148 407