diff options
Diffstat (limited to 'arch/arm/mach-omap2/pm34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 506 |
1 files changed, 409 insertions, 97 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 89463190923a..ea0000bc5358 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,22 @@ | |||
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> |
25 | 28 | #include <linux/clk.h> | |
26 | #include <mach/sram.h> | 29 | #include <linux/delay.h> |
27 | #include <mach/clockdomain.h> | 30 | #include <linux/slab.h> |
28 | #include <mach/powerdomain.h> | 31 | |
29 | #include <mach/control.h> | 32 | #include <plat/sram.h> |
30 | #include <mach/serial.h> | 33 | #include <plat/clockdomain.h> |
34 | #include <plat/powerdomain.h> | ||
35 | #include <plat/control.h> | ||
36 | #include <plat/serial.h> | ||
37 | #include <plat/sdrc.h> | ||
38 | #include <plat/prcm.h> | ||
39 | #include <plat/gpmc.h> | ||
40 | #include <plat/dma.h> | ||
41 | #include <plat/dmtimer.h> | ||
42 | |||
43 | #include <asm/tlbflush.h> | ||
31 | 44 | ||
32 | #include "cm.h" | 45 | #include "cm.h" |
33 | #include "cm-regbits-34xx.h" | 46 | #include "cm-regbits-34xx.h" |
@@ -35,6 +48,16 @@ | |||
35 | 48 | ||
36 | #include "prm.h" | 49 | #include "prm.h" |
37 | #include "pm.h" | 50 | #include "pm.h" |
51 | #include "sdrc.h" | ||
52 | |||
53 | /* Scratchpad offsets */ | ||
54 | #define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 | ||
55 | #define OMAP343X_TABLE_VALUE_OFFSET 0x30 | ||
56 | #define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32 | ||
57 | |||
58 | u32 enable_off_mode; | ||
59 | u32 sleep_while_idle; | ||
60 | u32 wakeup_timer_seconds; | ||
38 | 61 | ||
39 | struct power_state { | 62 | struct power_state { |
40 | struct powerdomain *pwrdm; | 63 | struct powerdomain *pwrdm; |
@@ -49,7 +72,120 @@ static LIST_HEAD(pwrst_list); | |||
49 | 72 | ||
50 | static void (*_omap_sram_idle)(u32 *addr, int save_state); | 73 | static void (*_omap_sram_idle)(u32 *addr, int save_state); |
51 | 74 | ||
52 | static struct powerdomain *mpu_pwrdm; | 75 | static int (*_omap_save_secure_sram)(u32 *addr); |
76 | |||
77 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; | ||
78 | static struct powerdomain *core_pwrdm, *per_pwrdm; | ||
79 | static struct powerdomain *cam_pwrdm; | ||
80 | |||
81 | static inline void omap3_per_save_context(void) | ||
82 | { | ||
83 | omap_gpio_save_context(); | ||
84 | } | ||
85 | |||
86 | static inline void omap3_per_restore_context(void) | ||
87 | { | ||
88 | omap_gpio_restore_context(); | ||
89 | } | ||
90 | |||
91 | static void omap3_enable_io_chain(void) | ||
92 | { | ||
93 | int timeout = 0; | ||
94 | |||
95 | if (omap_rev() >= OMAP3430_REV_ES3_1) { | ||
96 | prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); | ||
97 | /* Do a readback to assure write has been done */ | ||
98 | prm_read_mod_reg(WKUP_MOD, PM_WKEN); | ||
99 | |||
100 | while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) & | ||
101 | OMAP3430_ST_IO_CHAIN)) { | ||
102 | timeout++; | ||
103 | if (timeout > 1000) { | ||
104 | printk(KERN_ERR "Wake up daisy chain " | ||
105 | "activation failed.\n"); | ||
106 | return; | ||
107 | } | ||
108 | prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN, | ||
109 | WKUP_MOD, PM_WKST); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | static void omap3_disable_io_chain(void) | ||
115 | { | ||
116 | if (omap_rev() >= OMAP3430_REV_ES3_1) | ||
117 | prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); | ||
118 | } | ||
119 | |||
120 | static void omap3_core_save_context(void) | ||
121 | { | ||
122 | u32 control_padconf_off; | ||
123 | |||
124 | /* Save the padconf registers */ | ||
125 | control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF); | ||
126 | control_padconf_off |= START_PADCONF_SAVE; | ||
127 | omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF); | ||
128 | /* wait for the save to complete */ | ||
129 | while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) | ||
130 | & PADCONF_SAVE_DONE)) | ||
131 | udelay(1); | ||
132 | |||
133 | /* | ||
134 | * Force write last pad into memory, as this can fail in some | ||
135 | * cases according to erratas 1.157, 1.185 | ||
136 | */ | ||
137 | omap_ctrl_writel(omap_ctrl_readl(OMAP343X_PADCONF_ETK_D14), | ||
138 | OMAP343X_CONTROL_MEM_WKUP + 0x2a0); | ||
139 | |||
140 | /* Save the Interrupt controller context */ | ||
141 | omap_intc_save_context(); | ||
142 | /* Save the GPMC context */ | ||
143 | omap3_gpmc_save_context(); | ||
144 | /* Save the system control module context, padconf already save above*/ | ||
145 | omap3_control_save_context(); | ||
146 | omap_dma_global_context_save(); | ||
147 | } | ||
148 | |||
149 | static void omap3_core_restore_context(void) | ||
150 | { | ||
151 | /* Restore the control module context, padconf restored by h/w */ | ||
152 | omap3_control_restore_context(); | ||
153 | /* Restore the GPMC context */ | ||
154 | omap3_gpmc_restore_context(); | ||
155 | /* Restore the interrupt controller context */ | ||
156 | omap_intc_restore_context(); | ||
157 | omap_dma_global_context_restore(); | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * FIXME: This function should be called before entering off-mode after | ||
162 | * OMAP3 secure services have been accessed. Currently it is only called | ||
163 | * once during boot sequence, but this works as we are not using secure | ||
164 | * services. | ||
165 | */ | ||
166 | static void omap3_save_secure_ram_context(u32 target_mpu_state) | ||
167 | { | ||
168 | u32 ret; | ||
169 | |||
170 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | ||
171 | /* | ||
172 | * MPU next state must be set to POWER_ON temporarily, | ||
173 | * otherwise the WFI executed inside the ROM code | ||
174 | * will hang the system. | ||
175 | */ | ||
176 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | ||
177 | ret = _omap_save_secure_sram((u32 *) | ||
178 | __pa(omap3_secure_ram_storage)); | ||
179 | pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state); | ||
180 | /* Following is for error tracking, it should not happen */ | ||
181 | if (ret) { | ||
182 | printk(KERN_ERR "save_secure_sram() returns %08x\n", | ||
183 | ret); | ||
184 | while (1) | ||
185 | ; | ||
186 | } | ||
187 | } | ||
188 | } | ||
53 | 189 | ||
54 | /* | 190 | /* |
55 | * PRCM Interrupt Handler Helper Function | 191 | * PRCM Interrupt Handler Helper Function |
@@ -161,7 +297,36 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) | |||
161 | return IRQ_HANDLED; | 297 | return IRQ_HANDLED; |
162 | } | 298 | } |
163 | 299 | ||
164 | static void omap_sram_idle(void) | 300 | static void restore_control_register(u32 val) |
301 | { | ||
302 | __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val)); | ||
303 | } | ||
304 | |||
305 | /* Function to restore the table entry that was modified for enabling MMU */ | ||
306 | static void restore_table_entry(void) | ||
307 | { | ||
308 | u32 *scratchpad_address; | ||
309 | u32 previous_value, control_reg_value; | ||
310 | u32 *address; | ||
311 | |||
312 | scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); | ||
313 | |||
314 | /* Get address of entry that was modified */ | ||
315 | address = (u32 *)__raw_readl(scratchpad_address + | ||
316 | OMAP343X_TABLE_ADDRESS_OFFSET); | ||
317 | /* Get the previous value which needs to be restored */ | ||
318 | previous_value = __raw_readl(scratchpad_address + | ||
319 | OMAP343X_TABLE_VALUE_OFFSET); | ||
320 | address = __va(address); | ||
321 | *address = previous_value; | ||
322 | flush_tlb_all(); | ||
323 | control_reg_value = __raw_readl(scratchpad_address | ||
324 | + OMAP343X_CONTROL_REG_VALUE_OFFSET); | ||
325 | /* This will enable caches and prediction */ | ||
326 | restore_control_register(control_reg_value); | ||
327 | } | ||
328 | |||
329 | void omap_sram_idle(void) | ||
165 | { | 330 | { |
166 | /* Variable to tell what needs to be saved and restored | 331 | /* Variable to tell what needs to be saved and restored |
167 | * in omap_sram_idle*/ | 332 | * in omap_sram_idle*/ |
@@ -169,17 +334,32 @@ static void omap_sram_idle(void) | |||
169 | /* save_state = 1 => Only L1 and logic lost */ | 334 | /* save_state = 1 => Only L1 and logic lost */ |
170 | /* save_state = 2 => Only L2 lost */ | 335 | /* save_state = 2 => Only L2 lost */ |
171 | /* save_state = 3 => L1, L2 and logic lost */ | 336 | /* save_state = 3 => L1, L2 and logic lost */ |
172 | int save_state = 0, mpu_next_state; | 337 | int save_state = 0; |
338 | int mpu_next_state = PWRDM_POWER_ON; | ||
339 | int per_next_state = PWRDM_POWER_ON; | ||
340 | int core_next_state = PWRDM_POWER_ON; | ||
341 | int core_prev_state, per_prev_state; | ||
342 | u32 sdrc_pwr = 0; | ||
343 | int per_state_modified = 0; | ||
173 | 344 | ||
174 | if (!_omap_sram_idle) | 345 | if (!_omap_sram_idle) |
175 | return; | 346 | return; |
176 | 347 | ||
348 | pwrdm_clear_all_prev_pwrst(mpu_pwrdm); | ||
349 | pwrdm_clear_all_prev_pwrst(neon_pwrdm); | ||
350 | pwrdm_clear_all_prev_pwrst(core_pwrdm); | ||
351 | pwrdm_clear_all_prev_pwrst(per_pwrdm); | ||
352 | |||
177 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); | 353 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); |
178 | switch (mpu_next_state) { | 354 | switch (mpu_next_state) { |
355 | case PWRDM_POWER_ON: | ||
179 | case PWRDM_POWER_RET: | 356 | case PWRDM_POWER_RET: |
180 | /* No need to save context */ | 357 | /* No need to save context */ |
181 | save_state = 0; | 358 | save_state = 0; |
182 | break; | 359 | break; |
360 | case PWRDM_POWER_OFF: | ||
361 | save_state = 3; | ||
362 | break; | ||
183 | default: | 363 | default: |
184 | /* Invalid state */ | 364 | /* Invalid state */ |
185 | printk(KERN_ERR "Invalid mpu state in sram_idle\n"); | 365 | printk(KERN_ERR "Invalid mpu state in sram_idle\n"); |
@@ -187,68 +367,117 @@ static void omap_sram_idle(void) | |||
187 | } | 367 | } |
188 | pwrdm_pre_transition(); | 368 | pwrdm_pre_transition(); |
189 | 369 | ||
190 | omap2_gpio_prepare_for_retention(); | 370 | /* NEON control */ |
191 | omap_uart_prepare_idle(0); | 371 | if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) |
192 | omap_uart_prepare_idle(1); | 372 | pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); |
193 | omap_uart_prepare_idle(2); | 373 | |
374 | /* PER */ | ||
375 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); | ||
376 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); | ||
377 | if (per_next_state < PWRDM_POWER_ON) { | ||
378 | omap_uart_prepare_idle(2); | ||
379 | omap2_gpio_prepare_for_retention(); | ||
380 | if (per_next_state == PWRDM_POWER_OFF) { | ||
381 | if (core_next_state == PWRDM_POWER_ON) { | ||
382 | per_next_state = PWRDM_POWER_RET; | ||
383 | pwrdm_set_next_pwrst(per_pwrdm, per_next_state); | ||
384 | per_state_modified = 1; | ||
385 | } else | ||
386 | omap3_per_save_context(); | ||
387 | } | ||
388 | } | ||
194 | 389 | ||
195 | _omap_sram_idle(NULL, save_state); | 390 | if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) |
196 | cpu_init(); | 391 | omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]); |
197 | 392 | ||
198 | omap_uart_resume_idle(2); | 393 | /* CORE */ |
199 | omap_uart_resume_idle(1); | 394 | if (core_next_state < PWRDM_POWER_ON) { |
200 | omap_uart_resume_idle(0); | 395 | omap_uart_prepare_idle(0); |
201 | omap2_gpio_resume_after_retention(); | 396 | omap_uart_prepare_idle(1); |
397 | if (core_next_state == PWRDM_POWER_OFF) { | ||
398 | omap3_core_save_context(); | ||
399 | omap3_prcm_save_context(); | ||
400 | } | ||
401 | /* Enable IO-PAD and IO-CHAIN wakeups */ | ||
402 | prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | ||
403 | omap3_enable_io_chain(); | ||
404 | } | ||
405 | omap3_intc_prepare_idle(); | ||
202 | 406 | ||
203 | pwrdm_post_transition(); | 407 | /* |
408 | * On EMU/HS devices ROM code restores a SRDC value | ||
409 | * from scratchpad which has automatic self refresh on timeout | ||
410 | * of AUTO_CNT = 1 enabled. This takes care of errata 1.142. | ||
411 | * Hence store/restore the SDRC_POWER register here. | ||
412 | */ | ||
413 | if (omap_rev() >= OMAP3430_REV_ES3_0 && | ||
414 | omap_type() != OMAP2_DEVICE_TYPE_GP && | ||
415 | core_next_state == PWRDM_POWER_OFF) | ||
416 | sdrc_pwr = sdrc_read_reg(SDRC_POWER); | ||
204 | 417 | ||
205 | } | 418 | /* |
419 | * omap3_arm_context is the location where ARM registers | ||
420 | * get saved. The restore path then reads from this | ||
421 | * location and restores them back. | ||
422 | */ | ||
423 | _omap_sram_idle(omap3_arm_context, save_state); | ||
424 | cpu_init(); | ||
206 | 425 | ||
207 | /* | 426 | /* Restore normal SDRC POWER settings */ |
208 | * Check if functional clocks are enabled before entering | 427 | if (omap_rev() >= OMAP3430_REV_ES3_0 && |
209 | * sleep. This function could be behind CONFIG_PM_DEBUG | 428 | omap_type() != OMAP2_DEVICE_TYPE_GP && |
210 | * when all drivers are configuring their sysconfig registers | 429 | core_next_state == PWRDM_POWER_OFF) |
211 | * properly and using their clocks properly. | 430 | sdrc_write_reg(sdrc_pwr, SDRC_POWER); |
212 | */ | 431 | |
213 | static int omap3_fclks_active(void) | 432 | /* Restore table entry modified during MMU restoration */ |
214 | { | 433 | if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) |
215 | u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0, | 434 | restore_table_entry(); |
216 | fck_cam = 0, fck_per = 0, fck_usbhost = 0; | 435 | |
436 | /* CORE */ | ||
437 | if (core_next_state < PWRDM_POWER_ON) { | ||
438 | core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); | ||
439 | if (core_prev_state == PWRDM_POWER_OFF) { | ||
440 | omap3_core_restore_context(); | ||
441 | omap3_prcm_restore_context(); | ||
442 | omap3_sram_restore_context(); | ||
443 | omap2_sms_restore_context(); | ||
444 | } | ||
445 | omap_uart_resume_idle(0); | ||
446 | omap_uart_resume_idle(1); | ||
447 | if (core_next_state == PWRDM_POWER_OFF) | ||
448 | prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, | ||
449 | OMAP3430_GR_MOD, | ||
450 | OMAP3_PRM_VOLTCTRL_OFFSET); | ||
451 | } | ||
452 | omap3_intc_resume_idle(); | ||
453 | |||
454 | /* PER */ | ||
455 | if (per_next_state < PWRDM_POWER_ON) { | ||
456 | per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); | ||
457 | if (per_prev_state == PWRDM_POWER_OFF) | ||
458 | omap3_per_restore_context(); | ||
459 | omap2_gpio_resume_after_retention(); | ||
460 | omap_uart_resume_idle(2); | ||
461 | if (per_state_modified) | ||
462 | pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); | ||
463 | } | ||
217 | 464 | ||
218 | fck_core1 = cm_read_mod_reg(CORE_MOD, | 465 | /* Disable IO-PAD and IO-CHAIN wakeup */ |
219 | CM_FCLKEN1); | 466 | if (core_next_state < PWRDM_POWER_ON) { |
220 | if (omap_rev() > OMAP3430_REV_ES1_0) { | 467 | prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); |
221 | fck_core3 = cm_read_mod_reg(CORE_MOD, | 468 | omap3_disable_io_chain(); |
222 | OMAP3430ES2_CM_FCLKEN3); | 469 | } |
223 | fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD, | 470 | |
224 | CM_FCLKEN); | 471 | pwrdm_post_transition(); |
225 | fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, | 472 | |
226 | CM_FCLKEN); | 473 | omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); |
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 | } | 474 | } |
246 | 475 | ||
247 | static int omap3_can_sleep(void) | 476 | int omap3_can_sleep(void) |
248 | { | 477 | { |
249 | if (!omap_uart_can_sleep()) | 478 | if (!sleep_while_idle) |
250 | return 0; | 479 | return 0; |
251 | if (omap3_fclks_active()) | 480 | if (!omap_uart_can_sleep()) |
252 | return 0; | 481 | return 0; |
253 | return 1; | 482 | return 1; |
254 | } | 483 | } |
@@ -256,7 +485,7 @@ static int omap3_can_sleep(void) | |||
256 | /* This sets pwrdm state (other than mpu & core. Currently only ON & | 485 | /* This sets pwrdm state (other than mpu & core. Currently only ON & |
257 | * RET are supported. Function is assuming that clkdm doesn't have | 486 | * RET are supported. Function is assuming that clkdm doesn't have |
258 | * hw_sup mode enabled. */ | 487 | * hw_sup mode enabled. */ |
259 | static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | 488 | int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) |
260 | { | 489 | { |
261 | u32 cur_state; | 490 | u32 cur_state; |
262 | int sleep_switch = 0; | 491 | int sleep_switch = 0; |
@@ -306,7 +535,7 @@ static void omap3_pm_idle(void) | |||
306 | if (!omap3_can_sleep()) | 535 | if (!omap3_can_sleep()) |
307 | goto out; | 536 | goto out; |
308 | 537 | ||
309 | if (omap_irq_pending()) | 538 | if (omap_irq_pending() || need_resched()) |
310 | goto out; | 539 | goto out; |
311 | 540 | ||
312 | omap_sram_idle(); | 541 | omap_sram_idle(); |
@@ -319,6 +548,22 @@ out: | |||
319 | #ifdef CONFIG_SUSPEND | 548 | #ifdef CONFIG_SUSPEND |
320 | static suspend_state_t suspend_state; | 549 | static suspend_state_t suspend_state; |
321 | 550 | ||
551 | static void omap2_pm_wakeup_on_timer(u32 seconds) | ||
552 | { | ||
553 | u32 tick_rate, cycles; | ||
554 | |||
555 | if (!seconds) | ||
556 | return; | ||
557 | |||
558 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); | ||
559 | cycles = tick_rate * seconds; | ||
560 | omap_dm_timer_stop(gptimer_wakeup); | ||
561 | omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); | ||
562 | |||
563 | pr_info("PM: Resume timer in %d secs (%d ticks at %d ticks/sec.)\n", | ||
564 | seconds, cycles, tick_rate); | ||
565 | } | ||
566 | |||
322 | static int omap3_pm_prepare(void) | 567 | static int omap3_pm_prepare(void) |
323 | { | 568 | { |
324 | disable_hlt(); | 569 | disable_hlt(); |
@@ -330,6 +575,9 @@ static int omap3_pm_suspend(void) | |||
330 | struct power_state *pwrst; | 575 | struct power_state *pwrst; |
331 | int state, ret = 0; | 576 | int state, ret = 0; |
332 | 577 | ||
578 | if (wakeup_timer_seconds) | ||
579 | omap2_pm_wakeup_on_timer(wakeup_timer_seconds); | ||
580 | |||
333 | /* Read current next_pwrsts */ | 581 | /* Read current next_pwrsts */ |
334 | list_for_each_entry(pwrst, &pwrst_list, node) | 582 | list_for_each_entry(pwrst, &pwrst_list, node) |
335 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); | 583 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); |
@@ -342,6 +590,8 @@ static int omap3_pm_suspend(void) | |||
342 | } | 590 | } |
343 | 591 | ||
344 | omap_uart_prepare_suspend(); | 592 | omap_uart_prepare_suspend(); |
593 | omap3_intc_suspend(); | ||
594 | |||
345 | omap_sram_idle(); | 595 | omap_sram_idle(); |
346 | 596 | ||
347 | restore: | 597 | restore: |
@@ -436,10 +686,10 @@ static void __init omap3_iva_idle(void) | |||
436 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | | 686 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | |
437 | OMAP3430_RST2_IVA2 | | 687 | OMAP3430_RST2_IVA2 | |
438 | OMAP3430_RST3_IVA2, | 688 | OMAP3430_RST3_IVA2, |
439 | OMAP3430_IVA2_MOD, RM_RSTCTRL); | 689 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); |
440 | 690 | ||
441 | /* Enable IVA2 clock */ | 691 | /* Enable IVA2 clock */ |
442 | cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2, | 692 | cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK, |
443 | OMAP3430_IVA2_MOD, CM_FCLKEN); | 693 | OMAP3430_IVA2_MOD, CM_FCLKEN); |
444 | 694 | ||
445 | /* Set IVA2 boot mode to 'idle' */ | 695 | /* Set IVA2 boot mode to 'idle' */ |
@@ -447,7 +697,7 @@ static void __init omap3_iva_idle(void) | |||
447 | OMAP343X_CONTROL_IVA2_BOOTMOD); | 697 | OMAP343X_CONTROL_IVA2_BOOTMOD); |
448 | 698 | ||
449 | /* Un-reset IVA2 */ | 699 | /* Un-reset IVA2 */ |
450 | prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL); | 700 | prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); |
451 | 701 | ||
452 | /* Disable IVA2 clock */ | 702 | /* Disable IVA2 clock */ |
453 | cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | 703 | cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); |
@@ -456,7 +706,7 @@ static void __init omap3_iva_idle(void) | |||
456 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | | 706 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | |
457 | OMAP3430_RST2_IVA2 | | 707 | OMAP3430_RST2_IVA2 | |
458 | OMAP3430_RST3_IVA2, | 708 | OMAP3430_RST3_IVA2, |
459 | OMAP3430_IVA2_MOD, RM_RSTCTRL); | 709 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); |
460 | } | 710 | } |
461 | 711 | ||
462 | static void __init omap3_d2d_idle(void) | 712 | static void __init omap3_d2d_idle(void) |
@@ -479,8 +729,8 @@ static void __init omap3_d2d_idle(void) | |||
479 | /* reset modem */ | 729 | /* reset modem */ |
480 | prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON | | 730 | prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON | |
481 | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST, | 731 | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST, |
482 | CORE_MOD, RM_RSTCTRL); | 732 | CORE_MOD, OMAP2_RM_RSTCTRL); |
483 | prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL); | 733 | prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL); |
484 | } | 734 | } |
485 | 735 | ||
486 | static void __init prcm_setup_regs(void) | 736 | static void __init prcm_setup_regs(void) |
@@ -599,6 +849,8 @@ static void __init prcm_setup_regs(void) | |||
599 | CM_AUTOIDLE); | 849 | CM_AUTOIDLE); |
600 | } | 850 | } |
601 | 851 | ||
852 | omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG); | ||
853 | |||
602 | /* | 854 | /* |
603 | * Set all plls to autoidle. This is needed until autoidle is | 855 | * Set all plls to autoidle. This is needed until autoidle is |
604 | * enabled by clockfw | 856 | * enabled by clockfw |
@@ -639,15 +891,23 @@ static void __init prcm_setup_regs(void) | |||
639 | prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN, | 891 | prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN, |
640 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | 892 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); |
641 | 893 | ||
894 | /* Enable PM_WKEN to support DSS LPR */ | ||
895 | prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS, | ||
896 | OMAP3430_DSS_MOD, PM_WKEN); | ||
897 | |||
642 | /* Enable wakeups in PER */ | 898 | /* Enable wakeups in PER */ |
643 | prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 | | 899 | prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 | |
644 | OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 | | 900 | OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 | |
645 | OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3, | 901 | OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3 | |
902 | OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 | | ||
903 | OMAP3430_EN_MCBSP4, | ||
646 | OMAP3430_PER_MOD, PM_WKEN); | 904 | OMAP3430_PER_MOD, PM_WKEN); |
647 | /* and allow them to wake up MPU */ | 905 | /* and allow them to wake up MPU */ |
648 | prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 | | 906 | prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 | |
649 | OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 | | 907 | OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 | |
650 | OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3, | 908 | OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3 | |
909 | OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 | | ||
910 | OMAP3430_EN_MCBSP4, | ||
651 | OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); | 911 | OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); |
652 | 912 | ||
653 | /* Don't attach IVA interrupts */ | 913 | /* Don't attach IVA interrupts */ |
@@ -657,37 +917,39 @@ static void __init prcm_setup_regs(void) | |||
657 | prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); | 917 | prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); |
658 | 918 | ||
659 | /* Clear any pending 'reset' flags */ | 919 | /* Clear any pending 'reset' flags */ |
660 | prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST); | 920 | prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST); |
661 | prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST); | 921 | prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST); |
662 | prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST); | 922 | prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST); |
663 | prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST); | 923 | prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST); |
664 | prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST); | 924 | prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST); |
665 | prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST); | 925 | prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST); |
666 | prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST); | 926 | prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, OMAP2_RM_RSTST); |
667 | 927 | ||
668 | /* Clear any pending PRCM interrupts */ | 928 | /* Clear any pending PRCM interrupts */ |
669 | prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 929 | prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
670 | 930 | ||
671 | /* Don't attach IVA interrupts */ | 931 | omap3_iva_idle(); |
672 | prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); | 932 | omap3_d2d_idle(); |
673 | prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); | 933 | } |
674 | prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); | ||
675 | prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); | ||
676 | 934 | ||
677 | /* Clear any pending 'reset' flags */ | 935 | void omap3_pm_off_mode_enable(int enable) |
678 | prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST); | 936 | { |
679 | prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST); | 937 | struct power_state *pwrst; |
680 | prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST); | 938 | u32 state; |
681 | prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST); | ||
682 | prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST); | ||
683 | prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST); | ||
684 | prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST); | ||
685 | 939 | ||
686 | /* Clear any pending PRCM interrupts */ | 940 | if (enable) |
687 | prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 941 | state = PWRDM_POWER_OFF; |
942 | else | ||
943 | state = PWRDM_POWER_RET; | ||
688 | 944 | ||
689 | omap3_iva_idle(); | 945 | #ifdef CONFIG_CPU_IDLE |
690 | omap3_d2d_idle(); | 946 | omap3_cpuidle_update_states(); |
947 | #endif | ||
948 | |||
949 | list_for_each_entry(pwrst, &pwrst_list, node) { | ||
950 | pwrst->next_state = state; | ||
951 | set_pwrdm_state(pwrst->pwrdm, state); | ||
952 | } | ||
691 | } | 953 | } |
692 | 954 | ||
693 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) | 955 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) |
@@ -741,6 +1003,9 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) | |||
741 | */ | 1003 | */ |
742 | static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) | 1004 | static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) |
743 | { | 1005 | { |
1006 | clkdm_clear_all_wkdeps(clkdm); | ||
1007 | clkdm_clear_all_sleepdeps(clkdm); | ||
1008 | |||
744 | if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) | 1009 | if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) |
745 | omap2_clkdm_allow_idle(clkdm); | 1010 | omap2_clkdm_allow_idle(clkdm); |
746 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && | 1011 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && |
@@ -749,9 +1014,19 @@ static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) | |||
749 | return 0; | 1014 | return 0; |
750 | } | 1015 | } |
751 | 1016 | ||
1017 | void omap_push_sram_idle(void) | ||
1018 | { | ||
1019 | _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, | ||
1020 | omap34xx_cpu_suspend_sz); | ||
1021 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) | ||
1022 | _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, | ||
1023 | save_secure_ram_context_sz); | ||
1024 | } | ||
1025 | |||
752 | static int __init omap3_pm_init(void) | 1026 | static int __init omap3_pm_init(void) |
753 | { | 1027 | { |
754 | struct power_state *pwrst, *tmp; | 1028 | struct power_state *pwrst, *tmp; |
1029 | struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm; | ||
755 | int ret; | 1030 | int ret; |
756 | 1031 | ||
757 | if (!cpu_is_omap34xx()) | 1032 | if (!cpu_is_omap34xx()) |
@@ -786,15 +1061,52 @@ static int __init omap3_pm_init(void) | |||
786 | goto err2; | 1061 | goto err2; |
787 | } | 1062 | } |
788 | 1063 | ||
789 | _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, | 1064 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); |
790 | omap34xx_cpu_suspend_sz); | 1065 | per_pwrdm = pwrdm_lookup("per_pwrdm"); |
1066 | core_pwrdm = pwrdm_lookup("core_pwrdm"); | ||
1067 | cam_pwrdm = pwrdm_lookup("cam_pwrdm"); | ||
1068 | |||
1069 | neon_clkdm = clkdm_lookup("neon_clkdm"); | ||
1070 | mpu_clkdm = clkdm_lookup("mpu_clkdm"); | ||
1071 | per_clkdm = clkdm_lookup("per_clkdm"); | ||
1072 | core_clkdm = clkdm_lookup("core_clkdm"); | ||
791 | 1073 | ||
1074 | omap_push_sram_idle(); | ||
792 | #ifdef CONFIG_SUSPEND | 1075 | #ifdef CONFIG_SUSPEND |
793 | suspend_set_ops(&omap_pm_ops); | 1076 | suspend_set_ops(&omap_pm_ops); |
794 | #endif /* CONFIG_SUSPEND */ | 1077 | #endif /* CONFIG_SUSPEND */ |
795 | 1078 | ||
796 | pm_idle = omap3_pm_idle; | 1079 | pm_idle = omap3_pm_idle; |
1080 | omap3_idle_init(); | ||
1081 | |||
1082 | clkdm_add_wkdep(neon_clkdm, mpu_clkdm); | ||
1083 | /* | ||
1084 | * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for | ||
1085 | * IO-pad wakeup. Otherwise it will unnecessarily waste power | ||
1086 | * waking up PER with every CORE wakeup - see | ||
1087 | * http://marc.info/?l=linux-omap&m=121852150710062&w=2 | ||
1088 | */ | ||
1089 | clkdm_add_wkdep(per_clkdm, core_clkdm); | ||
1090 | |||
1091 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | ||
1092 | omap3_secure_ram_storage = | ||
1093 | kmalloc(0x803F, GFP_KERNEL); | ||
1094 | if (!omap3_secure_ram_storage) | ||
1095 | printk(KERN_ERR "Memory allocation failed when" | ||
1096 | "allocating for secure sram context\n"); | ||
1097 | |||
1098 | local_irq_disable(); | ||
1099 | local_fiq_disable(); | ||
1100 | |||
1101 | omap_dma_global_context_save(); | ||
1102 | omap3_save_secure_ram_context(PWRDM_POWER_ON); | ||
1103 | omap_dma_global_context_restore(); | ||
1104 | |||
1105 | local_irq_enable(); | ||
1106 | local_fiq_enable(); | ||
1107 | } | ||
797 | 1108 | ||
1109 | omap3_save_scratchpad_contents(); | ||
798 | err1: | 1110 | err1: |
799 | return ret; | 1111 | return ret; |
800 | err2: | 1112 | err2: |