diff options
Diffstat (limited to 'arch/arm/mach-omap2/pm34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 419 |
1 files changed, 356 insertions, 63 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 89463190923a..81ed252a0f8a 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -5,6 +5,9 @@ | |||
5 | * Tony Lindgren <tony@atomide.com> | 5 | * Tony Lindgren <tony@atomide.com> |
6 | * Jouni Hogander | 6 | * Jouni Hogander |
7 | * | 7 | * |
8 | * Copyright (C) 2007 Texas Instruments, Inc. | ||
9 | * Rajendra Nayak <rnayak@ti.com> | ||
10 | * | ||
8 | * Copyright (C) 2005 Texas Instruments, Inc. | 11 | * Copyright (C) 2005 Texas Instruments, Inc. |
9 | * Richard Woodruff <r-woodruff2@ti.com> | 12 | * Richard Woodruff <r-woodruff2@ti.com> |
10 | * | 13 | * |
@@ -22,12 +25,20 @@ | |||
22 | #include <linux/list.h> | 25 | #include <linux/list.h> |
23 | #include <linux/err.h> | 26 | #include <linux/err.h> |
24 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <linux/clk.h> | ||
29 | |||
30 | #include <plat/sram.h> | ||
31 | #include <plat/clockdomain.h> | ||
32 | #include <plat/powerdomain.h> | ||
33 | #include <plat/control.h> | ||
34 | #include <plat/serial.h> | ||
35 | #include <plat/sdrc.h> | ||
36 | #include <plat/prcm.h> | ||
37 | #include <plat/gpmc.h> | ||
38 | #include <plat/dma.h> | ||
39 | #include <plat/dmtimer.h> | ||
25 | 40 | ||
26 | #include <mach/sram.h> | 41 | #include <asm/tlbflush.h> |
27 | #include <mach/clockdomain.h> | ||
28 | #include <mach/powerdomain.h> | ||
29 | #include <mach/control.h> | ||
30 | #include <mach/serial.h> | ||
31 | 42 | ||
32 | #include "cm.h" | 43 | #include "cm.h" |
33 | #include "cm-regbits-34xx.h" | 44 | #include "cm-regbits-34xx.h" |
@@ -35,6 +46,16 @@ | |||
35 | 46 | ||
36 | #include "prm.h" | 47 | #include "prm.h" |
37 | #include "pm.h" | 48 | #include "pm.h" |
49 | #include "sdrc.h" | ||
50 | |||
51 | /* Scratchpad offsets */ | ||
52 | #define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 | ||
53 | #define OMAP343X_TABLE_VALUE_OFFSET 0x30 | ||
54 | #define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32 | ||
55 | |||
56 | u32 enable_off_mode; | ||
57 | u32 sleep_while_idle; | ||
58 | u32 wakeup_timer_seconds; | ||
38 | 59 | ||
39 | struct power_state { | 60 | struct power_state { |
40 | struct powerdomain *pwrdm; | 61 | struct powerdomain *pwrdm; |
@@ -49,7 +70,112 @@ static LIST_HEAD(pwrst_list); | |||
49 | 70 | ||
50 | static void (*_omap_sram_idle)(u32 *addr, int save_state); | 71 | static void (*_omap_sram_idle)(u32 *addr, int save_state); |
51 | 72 | ||
52 | static struct powerdomain *mpu_pwrdm; | 73 | static int (*_omap_save_secure_sram)(u32 *addr); |
74 | |||
75 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; | ||
76 | static struct powerdomain *core_pwrdm, *per_pwrdm; | ||
77 | static struct powerdomain *cam_pwrdm; | ||
78 | |||
79 | static inline void omap3_per_save_context(void) | ||
80 | { | ||
81 | omap_gpio_save_context(); | ||
82 | } | ||
83 | |||
84 | static inline void omap3_per_restore_context(void) | ||
85 | { | ||
86 | omap_gpio_restore_context(); | ||
87 | } | ||
88 | |||
89 | static void omap3_enable_io_chain(void) | ||
90 | { | ||
91 | int timeout = 0; | ||
92 | |||
93 | if (omap_rev() >= OMAP3430_REV_ES3_1) { | ||
94 | prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); | ||
95 | /* Do a readback to assure write has been done */ | ||
96 | prm_read_mod_reg(WKUP_MOD, PM_WKEN); | ||
97 | |||
98 | while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) & | ||
99 | OMAP3430_ST_IO_CHAIN)) { | ||
100 | timeout++; | ||
101 | if (timeout > 1000) { | ||
102 | printk(KERN_ERR "Wake up daisy chain " | ||
103 | "activation failed.\n"); | ||
104 | return; | ||
105 | } | ||
106 | prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN, | ||
107 | WKUP_MOD, PM_WKST); | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static void omap3_disable_io_chain(void) | ||
113 | { | ||
114 | if (omap_rev() >= OMAP3430_REV_ES3_1) | ||
115 | prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); | ||
116 | } | ||
117 | |||
118 | static void omap3_core_save_context(void) | ||
119 | { | ||
120 | u32 control_padconf_off; | ||
121 | |||
122 | /* Save the padconf registers */ | ||
123 | control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF); | ||
124 | control_padconf_off |= START_PADCONF_SAVE; | ||
125 | omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF); | ||
126 | /* wait for the save to complete */ | ||
127 | while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) | ||
128 | & PADCONF_SAVE_DONE) | ||
129 | ; | ||
130 | /* Save the Interrupt controller context */ | ||
131 | omap_intc_save_context(); | ||
132 | /* Save the GPMC context */ | ||
133 | omap3_gpmc_save_context(); | ||
134 | /* Save the system control module context, padconf already save above*/ | ||
135 | omap3_control_save_context(); | ||
136 | omap_dma_global_context_save(); | ||
137 | } | ||
138 | |||
139 | static void omap3_core_restore_context(void) | ||
140 | { | ||
141 | /* Restore the control module context, padconf restored by h/w */ | ||
142 | omap3_control_restore_context(); | ||
143 | /* Restore the GPMC context */ | ||
144 | omap3_gpmc_restore_context(); | ||
145 | /* Restore the interrupt controller context */ | ||
146 | omap_intc_restore_context(); | ||
147 | omap_dma_global_context_restore(); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * FIXME: This function should be called before entering off-mode after | ||
152 | * OMAP3 secure services have been accessed. Currently it is only called | ||
153 | * once during boot sequence, but this works as we are not using secure | ||
154 | * services. | ||
155 | */ | ||
156 | static void omap3_save_secure_ram_context(u32 target_mpu_state) | ||
157 | { | ||
158 | u32 ret; | ||
159 | |||
160 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | ||
161 | /* | ||
162 | * MPU next state must be set to POWER_ON temporarily, | ||
163 | * otherwise the WFI executed inside the ROM code | ||
164 | * will hang the system. | ||
165 | */ | ||
166 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | ||
167 | ret = _omap_save_secure_sram((u32 *) | ||
168 | __pa(omap3_secure_ram_storage)); | ||
169 | pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state); | ||
170 | /* Following is for error tracking, it should not happen */ | ||
171 | if (ret) { | ||
172 | printk(KERN_ERR "save_secure_sram() returns %08x\n", | ||
173 | ret); | ||
174 | while (1) | ||
175 | ; | ||
176 | } | ||
177 | } | ||
178 | } | ||
53 | 179 | ||
54 | /* | 180 | /* |
55 | * PRCM Interrupt Handler Helper Function | 181 | * PRCM Interrupt Handler Helper Function |
@@ -161,7 +287,36 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) | |||
161 | return IRQ_HANDLED; | 287 | return IRQ_HANDLED; |
162 | } | 288 | } |
163 | 289 | ||
164 | static void omap_sram_idle(void) | 290 | static void restore_control_register(u32 val) |
291 | { | ||
292 | __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val)); | ||
293 | } | ||
294 | |||
295 | /* Function to restore the table entry that was modified for enabling MMU */ | ||
296 | static void restore_table_entry(void) | ||
297 | { | ||
298 | u32 *scratchpad_address; | ||
299 | u32 previous_value, control_reg_value; | ||
300 | u32 *address; | ||
301 | |||
302 | scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); | ||
303 | |||
304 | /* Get address of entry that was modified */ | ||
305 | address = (u32 *)__raw_readl(scratchpad_address + | ||
306 | OMAP343X_TABLE_ADDRESS_OFFSET); | ||
307 | /* Get the previous value which needs to be restored */ | ||
308 | previous_value = __raw_readl(scratchpad_address + | ||
309 | OMAP343X_TABLE_VALUE_OFFSET); | ||
310 | address = __va(address); | ||
311 | *address = previous_value; | ||
312 | flush_tlb_all(); | ||
313 | control_reg_value = __raw_readl(scratchpad_address | ||
314 | + OMAP343X_CONTROL_REG_VALUE_OFFSET); | ||
315 | /* This will enable caches and prediction */ | ||
316 | restore_control_register(control_reg_value); | ||
317 | } | ||
318 | |||
319 | void omap_sram_idle(void) | ||
165 | { | 320 | { |
166 | /* Variable to tell what needs to be saved and restored | 321 | /* Variable to tell what needs to be saved and restored |
167 | * in omap_sram_idle*/ | 322 | * in omap_sram_idle*/ |
@@ -169,17 +324,32 @@ static void omap_sram_idle(void) | |||
169 | /* save_state = 1 => Only L1 and logic lost */ | 324 | /* save_state = 1 => Only L1 and logic lost */ |
170 | /* save_state = 2 => Only L2 lost */ | 325 | /* save_state = 2 => Only L2 lost */ |
171 | /* save_state = 3 => L1, L2 and logic lost */ | 326 | /* save_state = 3 => L1, L2 and logic lost */ |
172 | int save_state = 0, mpu_next_state; | 327 | int save_state = 0; |
328 | int mpu_next_state = PWRDM_POWER_ON; | ||
329 | int per_next_state = PWRDM_POWER_ON; | ||
330 | int core_next_state = PWRDM_POWER_ON; | ||
331 | int core_prev_state, per_prev_state; | ||
332 | u32 sdrc_pwr = 0; | ||
333 | int per_state_modified = 0; | ||
173 | 334 | ||
174 | if (!_omap_sram_idle) | 335 | if (!_omap_sram_idle) |
175 | return; | 336 | return; |
176 | 337 | ||
338 | pwrdm_clear_all_prev_pwrst(mpu_pwrdm); | ||
339 | pwrdm_clear_all_prev_pwrst(neon_pwrdm); | ||
340 | pwrdm_clear_all_prev_pwrst(core_pwrdm); | ||
341 | pwrdm_clear_all_prev_pwrst(per_pwrdm); | ||
342 | |||
177 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); | 343 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); |
178 | switch (mpu_next_state) { | 344 | switch (mpu_next_state) { |
345 | case PWRDM_POWER_ON: | ||
179 | case PWRDM_POWER_RET: | 346 | case PWRDM_POWER_RET: |
180 | /* No need to save context */ | 347 | /* No need to save context */ |
181 | save_state = 0; | 348 | save_state = 0; |
182 | break; | 349 | break; |
350 | case PWRDM_POWER_OFF: | ||
351 | save_state = 3; | ||
352 | break; | ||
183 | default: | 353 | default: |
184 | /* Invalid state */ | 354 | /* Invalid state */ |
185 | printk(KERN_ERR "Invalid mpu state in sram_idle\n"); | 355 | printk(KERN_ERR "Invalid mpu state in sram_idle\n"); |
@@ -187,68 +357,115 @@ static void omap_sram_idle(void) | |||
187 | } | 357 | } |
188 | pwrdm_pre_transition(); | 358 | pwrdm_pre_transition(); |
189 | 359 | ||
190 | omap2_gpio_prepare_for_retention(); | 360 | /* NEON control */ |
191 | omap_uart_prepare_idle(0); | 361 | if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) |
192 | omap_uart_prepare_idle(1); | 362 | pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); |
193 | omap_uart_prepare_idle(2); | 363 | |
364 | /* PER */ | ||
365 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); | ||
366 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); | ||
367 | if (per_next_state < PWRDM_POWER_ON) { | ||
368 | omap_uart_prepare_idle(2); | ||
369 | omap2_gpio_prepare_for_retention(); | ||
370 | if (per_next_state == PWRDM_POWER_OFF) { | ||
371 | if (core_next_state == PWRDM_POWER_ON) { | ||
372 | per_next_state = PWRDM_POWER_RET; | ||
373 | pwrdm_set_next_pwrst(per_pwrdm, per_next_state); | ||
374 | per_state_modified = 1; | ||
375 | } else | ||
376 | omap3_per_save_context(); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) | ||
381 | omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]); | ||
382 | |||
383 | /* CORE */ | ||
384 | if (core_next_state < PWRDM_POWER_ON) { | ||
385 | omap_uart_prepare_idle(0); | ||
386 | omap_uart_prepare_idle(1); | ||
387 | if (core_next_state == PWRDM_POWER_OFF) { | ||
388 | omap3_core_save_context(); | ||
389 | omap3_prcm_save_context(); | ||
390 | } | ||
391 | /* Enable IO-PAD and IO-CHAIN wakeups */ | ||
392 | prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | ||
393 | omap3_enable_io_chain(); | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * On EMU/HS devices ROM code restores a SRDC value | ||
398 | * from scratchpad which has automatic self refresh on timeout | ||
399 | * of AUTO_CNT = 1 enabled. This takes care of errata 1.142. | ||
400 | * Hence store/restore the SDRC_POWER register here. | ||
401 | */ | ||
402 | if (omap_rev() >= OMAP3430_REV_ES3_0 && | ||
403 | omap_type() != OMAP2_DEVICE_TYPE_GP && | ||
404 | core_next_state == PWRDM_POWER_OFF) | ||
405 | sdrc_pwr = sdrc_read_reg(SDRC_POWER); | ||
194 | 406 | ||
195 | _omap_sram_idle(NULL, save_state); | 407 | /* |
408 | * omap3_arm_context is the location where ARM registers | ||
409 | * get saved. The restore path then reads from this | ||
410 | * location and restores them back. | ||
411 | */ | ||
412 | _omap_sram_idle(omap3_arm_context, save_state); | ||
196 | cpu_init(); | 413 | cpu_init(); |
197 | 414 | ||
198 | omap_uart_resume_idle(2); | 415 | /* Restore normal SDRC POWER settings */ |
199 | omap_uart_resume_idle(1); | 416 | if (omap_rev() >= OMAP3430_REV_ES3_0 && |
200 | omap_uart_resume_idle(0); | 417 | omap_type() != OMAP2_DEVICE_TYPE_GP && |
201 | omap2_gpio_resume_after_retention(); | 418 | core_next_state == PWRDM_POWER_OFF) |
419 | sdrc_write_reg(sdrc_pwr, SDRC_POWER); | ||
420 | |||
421 | /* Restore table entry modified during MMU restoration */ | ||
422 | if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) | ||
423 | restore_table_entry(); | ||
424 | |||
425 | /* CORE */ | ||
426 | if (core_next_state < PWRDM_POWER_ON) { | ||
427 | core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); | ||
428 | if (core_prev_state == PWRDM_POWER_OFF) { | ||
429 | omap3_core_restore_context(); | ||
430 | omap3_prcm_restore_context(); | ||
431 | omap3_sram_restore_context(); | ||
432 | omap2_sms_restore_context(); | ||
433 | } | ||
434 | omap_uart_resume_idle(0); | ||
435 | omap_uart_resume_idle(1); | ||
436 | if (core_next_state == PWRDM_POWER_OFF) | ||
437 | prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, | ||
438 | OMAP3430_GR_MOD, | ||
439 | OMAP3_PRM_VOLTCTRL_OFFSET); | ||
440 | } | ||
202 | 441 | ||
203 | pwrdm_post_transition(); | 442 | /* PER */ |
443 | if (per_next_state < PWRDM_POWER_ON) { | ||
444 | per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); | ||
445 | if (per_prev_state == PWRDM_POWER_OFF) | ||
446 | omap3_per_restore_context(); | ||
447 | omap2_gpio_resume_after_retention(); | ||
448 | omap_uart_resume_idle(2); | ||
449 | if (per_state_modified) | ||
450 | pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); | ||
451 | } | ||
204 | 452 | ||
205 | } | 453 | /* Disable IO-PAD and IO-CHAIN wakeup */ |
454 | if (core_next_state < PWRDM_POWER_ON) { | ||
455 | prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | ||
456 | omap3_disable_io_chain(); | ||
457 | } | ||
206 | 458 | ||
207 | /* | 459 | pwrdm_post_transition(); |
208 | * Check if functional clocks are enabled before entering | ||
209 | * sleep. This function could be behind CONFIG_PM_DEBUG | ||
210 | * when all drivers are configuring their sysconfig registers | ||
211 | * properly and using their clocks properly. | ||
212 | */ | ||
213 | static int omap3_fclks_active(void) | ||
214 | { | ||
215 | u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0, | ||
216 | fck_cam = 0, fck_per = 0, fck_usbhost = 0; | ||
217 | 460 | ||
218 | fck_core1 = cm_read_mod_reg(CORE_MOD, | 461 | omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); |
219 | CM_FCLKEN1); | ||
220 | if (omap_rev() > OMAP3430_REV_ES1_0) { | ||
221 | fck_core3 = cm_read_mod_reg(CORE_MOD, | ||
222 | OMAP3430ES2_CM_FCLKEN3); | ||
223 | fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, | ||
224 | CM_FCLKEN); | ||
225 | fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, | ||
226 | CM_FCLKEN); | ||
227 | } else | ||
228 | fck_sgx = cm_read_mod_reg(GFX_MOD, | ||
229 | OMAP3430ES2_CM_FCLKEN3); | ||
230 | fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD, | ||
231 | CM_FCLKEN); | ||
232 | fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD, | ||
233 | CM_FCLKEN); | ||
234 | fck_per = cm_read_mod_reg(OMAP3430_PER_MOD, | ||
235 | CM_FCLKEN); | ||
236 | |||
237 | /* Ignore UART clocks. These are handled by UART core (serial.c) */ | ||
238 | fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2); | ||
239 | fck_per &= ~OMAP3430_EN_UART3; | ||
240 | |||
241 | if (fck_core1 | fck_core3 | fck_sgx | fck_dss | | ||
242 | fck_cam | fck_per | fck_usbhost) | ||
243 | return 1; | ||
244 | return 0; | ||
245 | } | 462 | } |
246 | 463 | ||
247 | static int omap3_can_sleep(void) | 464 | int omap3_can_sleep(void) |
248 | { | 465 | { |
249 | if (!omap_uart_can_sleep()) | 466 | if (!sleep_while_idle) |
250 | return 0; | 467 | return 0; |
251 | if (omap3_fclks_active()) | 468 | if (!omap_uart_can_sleep()) |
252 | return 0; | 469 | return 0; |
253 | return 1; | 470 | return 1; |
254 | } | 471 | } |
@@ -256,7 +473,7 @@ static int omap3_can_sleep(void) | |||
256 | /* This sets pwrdm state (other than mpu & core. Currently only ON & | 473 | /* This sets pwrdm state (other than mpu & core. Currently only ON & |
257 | * RET are supported. Function is assuming that clkdm doesn't have | 474 | * RET are supported. Function is assuming that clkdm doesn't have |
258 | * hw_sup mode enabled. */ | 475 | * hw_sup mode enabled. */ |
259 | static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | 476 | int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) |
260 | { | 477 | { |
261 | u32 cur_state; | 478 | u32 cur_state; |
262 | int sleep_switch = 0; | 479 | int sleep_switch = 0; |
@@ -306,7 +523,7 @@ static void omap3_pm_idle(void) | |||
306 | if (!omap3_can_sleep()) | 523 | if (!omap3_can_sleep()) |
307 | goto out; | 524 | goto out; |
308 | 525 | ||
309 | if (omap_irq_pending()) | 526 | if (omap_irq_pending() || need_resched()) |
310 | goto out; | 527 | goto out; |
311 | 528 | ||
312 | omap_sram_idle(); | 529 | omap_sram_idle(); |
@@ -319,6 +536,22 @@ out: | |||
319 | #ifdef CONFIG_SUSPEND | 536 | #ifdef CONFIG_SUSPEND |
320 | static suspend_state_t suspend_state; | 537 | static suspend_state_t suspend_state; |
321 | 538 | ||
539 | static void omap2_pm_wakeup_on_timer(u32 seconds) | ||
540 | { | ||
541 | u32 tick_rate, cycles; | ||
542 | |||
543 | if (!seconds) | ||
544 | return; | ||
545 | |||
546 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); | ||
547 | cycles = tick_rate * seconds; | ||
548 | omap_dm_timer_stop(gptimer_wakeup); | ||
549 | omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); | ||
550 | |||
551 | pr_info("PM: Resume timer in %d secs (%d ticks at %d ticks/sec.)\n", | ||
552 | seconds, cycles, tick_rate); | ||
553 | } | ||
554 | |||
322 | static int omap3_pm_prepare(void) | 555 | static int omap3_pm_prepare(void) |
323 | { | 556 | { |
324 | disable_hlt(); | 557 | disable_hlt(); |
@@ -330,6 +563,9 @@ static int omap3_pm_suspend(void) | |||
330 | struct power_state *pwrst; | 563 | struct power_state *pwrst; |
331 | int state, ret = 0; | 564 | int state, ret = 0; |
332 | 565 | ||
566 | if (wakeup_timer_seconds) | ||
567 | omap2_pm_wakeup_on_timer(wakeup_timer_seconds); | ||
568 | |||
333 | /* Read current next_pwrsts */ | 569 | /* Read current next_pwrsts */ |
334 | list_for_each_entry(pwrst, &pwrst_list, node) | 570 | list_for_each_entry(pwrst, &pwrst_list, node) |
335 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); | 571 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); |
@@ -690,6 +926,22 @@ static void __init prcm_setup_regs(void) | |||
690 | omap3_d2d_idle(); | 926 | omap3_d2d_idle(); |
691 | } | 927 | } |
692 | 928 | ||
929 | void omap3_pm_off_mode_enable(int enable) | ||
930 | { | ||
931 | struct power_state *pwrst; | ||
932 | u32 state; | ||
933 | |||
934 | if (enable) | ||
935 | state = PWRDM_POWER_OFF; | ||
936 | else | ||
937 | state = PWRDM_POWER_RET; | ||
938 | |||
939 | list_for_each_entry(pwrst, &pwrst_list, node) { | ||
940 | pwrst->next_state = state; | ||
941 | set_pwrdm_state(pwrst->pwrdm, state); | ||
942 | } | ||
943 | } | ||
944 | |||
693 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) | 945 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) |
694 | { | 946 | { |
695 | struct power_state *pwrst; | 947 | struct power_state *pwrst; |
@@ -749,6 +1001,15 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) | |||
749 | return 0; | 1001 | return 0; |
750 | } | 1002 | } |
751 | 1003 | ||
1004 | void omap_push_sram_idle(void) | ||
1005 | { | ||
1006 | _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, | ||
1007 | omap34xx_cpu_suspend_sz); | ||
1008 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) | ||
1009 | _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, | ||
1010 | save_secure_ram_context_sz); | ||
1011 | } | ||
1012 | |||
752 | static int __init omap3_pm_init(void) | 1013 | static int __init omap3_pm_init(void) |
753 | { | 1014 | { |
754 | struct power_state *pwrst, *tmp; | 1015 | struct power_state *pwrst, *tmp; |
@@ -786,15 +1047,47 @@ static int __init omap3_pm_init(void) | |||
786 | goto err2; | 1047 | goto err2; |
787 | } | 1048 | } |
788 | 1049 | ||
789 | _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, | 1050 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); |
790 | omap34xx_cpu_suspend_sz); | 1051 | per_pwrdm = pwrdm_lookup("per_pwrdm"); |
1052 | core_pwrdm = pwrdm_lookup("core_pwrdm"); | ||
1053 | cam_pwrdm = pwrdm_lookup("cam_pwrdm"); | ||
791 | 1054 | ||
1055 | omap_push_sram_idle(); | ||
792 | #ifdef CONFIG_SUSPEND | 1056 | #ifdef CONFIG_SUSPEND |
793 | suspend_set_ops(&omap_pm_ops); | 1057 | suspend_set_ops(&omap_pm_ops); |
794 | #endif /* CONFIG_SUSPEND */ | 1058 | #endif /* CONFIG_SUSPEND */ |
795 | 1059 | ||
796 | pm_idle = omap3_pm_idle; | 1060 | pm_idle = omap3_pm_idle; |
1061 | omap3_idle_init(); | ||
1062 | |||
1063 | pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm); | ||
1064 | /* | ||
1065 | * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for | ||
1066 | * IO-pad wakeup. Otherwise it will unnecessarily waste power | ||
1067 | * waking up PER with every CORE wakeup - see | ||
1068 | * http://marc.info/?l=linux-omap&m=121852150710062&w=2 | ||
1069 | */ | ||
1070 | pwrdm_add_wkdep(per_pwrdm, core_pwrdm); | ||
1071 | |||
1072 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | ||
1073 | omap3_secure_ram_storage = | ||
1074 | kmalloc(0x803F, GFP_KERNEL); | ||
1075 | if (!omap3_secure_ram_storage) | ||
1076 | printk(KERN_ERR "Memory allocation failed when" | ||
1077 | "allocating for secure sram context\n"); | ||
1078 | |||
1079 | local_irq_disable(); | ||
1080 | local_fiq_disable(); | ||
1081 | |||
1082 | omap_dma_global_context_save(); | ||
1083 | omap3_save_secure_ram_context(PWRDM_POWER_ON); | ||
1084 | omap_dma_global_context_restore(); | ||
1085 | |||
1086 | local_irq_enable(); | ||
1087 | local_fiq_enable(); | ||
1088 | } | ||
797 | 1089 | ||
1090 | omap3_save_scratchpad_contents(); | ||
798 | err1: | 1091 | err1: |
799 | return ret; | 1092 | return ret; |
800 | err2: | 1093 | err2: |