Commit | Line | Data |
---|---|---|
8bd22949 KH |
1 | /* |
2 | * OMAP3 Power Management Routines | |
3 | * | |
4 | * Copyright (C) 2006-2008 Nokia Corporation | |
5 | * Tony Lindgren <tony@atomide.com> | |
6 | * Jouni Hogander | |
7 | * | |
2f5939c3 RN |
8 | * Copyright (C) 2007 Texas Instruments, Inc. |
9 | * Rajendra Nayak <rnayak@ti.com> | |
10 | * | |
8bd22949 KH |
11 | * Copyright (C) 2005 Texas Instruments, Inc. |
12 | * Richard Woodruff <r-woodruff2@ti.com> | |
13 | * | |
14 | * Based on pm.c for omap1 | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License version 2 as | |
18 | * published by the Free Software Foundation. | |
19 | */ | |
20 | ||
b764a586 | 21 | #include <linux/cpu_pm.h> |
8bd22949 KH |
22 | #include <linux/pm.h> |
23 | #include <linux/suspend.h> | |
24 | #include <linux/interrupt.h> | |
25 | #include <linux/module.h> | |
26 | #include <linux/list.h> | |
27 | #include <linux/err.h> | |
c40552bc | 28 | #include <linux/clk.h> |
dccaad89 | 29 | #include <linux/delay.h> |
5a0e3ad6 | 30 | #include <linux/slab.h> |
45c3eb7d | 31 | #include <linux/omap-dma.h> |
e639cd5b | 32 | #include <linux/omap-gpmc.h> |
4b25408f | 33 | |
5e7c58dc | 34 | #include <trace/events/power.h> |
8bd22949 | 35 | |
bf027ca1 | 36 | #include <asm/fncpy.h> |
2c74a0ce | 37 | #include <asm/suspend.h> |
9f97da78 | 38 | #include <asm/system_misc.h> |
2c74a0ce | 39 | |
1540f214 | 40 | #include "clockdomain.h" |
72e06d08 | 41 | #include "powerdomain.h" |
e4c060db | 42 | #include "soc.h" |
4e65331c | 43 | #include "common.h" |
ff4ae5d9 | 44 | #include "cm3xxx.h" |
8bd22949 KH |
45 | #include "cm-regbits-34xx.h" |
46 | #include "prm-regbits-34xx.h" | |
139563ad | 47 | #include "prm3xxx.h" |
8bd22949 | 48 | #include "pm.h" |
13a6fe0f | 49 | #include "sdrc.h" |
d09220a8 | 50 | #include "omap-secure.h" |
bf027ca1 | 51 | #include "sram.h" |
4814ced5 | 52 | #include "control.h" |
3b8c4ebb | 53 | #include "vc.h" |
13a6fe0f | 54 | |
8cdfd834 NM |
55 | /* pm34xx errata defined in pm.h */ |
56 | u16 pm34xx_errata; | |
57 | ||
8bd22949 KH |
58 | struct power_state { |
59 | struct powerdomain *pwrdm; | |
60 | u32 next_state; | |
10f90ed2 | 61 | #ifdef CONFIG_SUSPEND |
8bd22949 | 62 | u32 saved_state; |
10f90ed2 | 63 | #endif |
8bd22949 KH |
64 | struct list_head node; |
65 | }; | |
66 | ||
67 | static LIST_HEAD(pwrst_list); | |
68 | ||
46e130d2 | 69 | void (*omap3_do_wfi_sram)(void); |
27d59a4a | 70 | |
fa3c2a4f RN |
71 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; |
72 | static struct powerdomain *core_pwrdm, *per_pwrdm; | |
3a7ec26b | 73 | |
2f5939c3 RN |
74 | static void omap3_core_save_context(void) |
75 | { | |
596efe47 | 76 | omap3_ctrl_save_padconf(); |
dccaad89 TK |
77 | |
78 | /* | |
79 | * Force write last pad into memory, as this can fail in some | |
83521291 | 80 | * cases according to errata 1.157, 1.185 |
dccaad89 TK |
81 | */ |
82 | omap_ctrl_writel(omap_ctrl_readl(OMAP343X_PADCONF_ETK_D14), | |
83 | OMAP343X_CONTROL_MEM_WKUP + 0x2a0); | |
84 | ||
2f5939c3 RN |
85 | /* Save the Interrupt controller context */ |
86 | omap_intc_save_context(); | |
87 | /* Save the GPMC context */ | |
88 | omap3_gpmc_save_context(); | |
89 | /* Save the system control module context, padconf already save above*/ | |
90 | omap3_control_save_context(); | |
f2d11858 | 91 | omap_dma_global_context_save(); |
2f5939c3 RN |
92 | } |
93 | ||
94 | static void omap3_core_restore_context(void) | |
95 | { | |
96 | /* Restore the control module context, padconf restored by h/w */ | |
97 | omap3_control_restore_context(); | |
98 | /* Restore the GPMC context */ | |
99 | omap3_gpmc_restore_context(); | |
100 | /* Restore the interrupt controller context */ | |
101 | omap_intc_restore_context(); | |
f2d11858 | 102 | omap_dma_global_context_restore(); |
2f5939c3 RN |
103 | } |
104 | ||
9d97140b TK |
105 | /* |
106 | * FIXME: This function should be called before entering off-mode after | |
107 | * OMAP3 secure services have been accessed. Currently it is only called | |
108 | * once during boot sequence, but this works as we are not using secure | |
109 | * services. | |
110 | */ | |
617fcc98 | 111 | static void omap3_save_secure_ram_context(void) |
27d59a4a TK |
112 | { |
113 | u32 ret; | |
617fcc98 | 114 | int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); |
27d59a4a TK |
115 | |
116 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | |
27d59a4a TK |
117 | /* |
118 | * MPU next state must be set to POWER_ON temporarily, | |
119 | * otherwise the WFI executed inside the ROM code | |
120 | * will hang the system. | |
121 | */ | |
122 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | |
d09220a8 TL |
123 | ret = omap3_save_secure_ram(omap3_secure_ram_storage, |
124 | OMAP3_SAVE_SECURE_RAM_SZ); | |
617fcc98 | 125 | pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state); |
27d59a4a TK |
126 | /* Following is for error tracking, it should not happen */ |
127 | if (ret) { | |
98179856 | 128 | pr_err("save_secure_sram() returns %08x\n", ret); |
27d59a4a TK |
129 | while (1) |
130 | ; | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
22f51371 | 135 | static irqreturn_t _prcm_int_handle_io(int irq, void *unused) |
8cb0ac99 PW |
136 | { |
137 | int c; | |
138 | ||
9cb6d363 TK |
139 | c = omap_prm_clear_mod_irqs(WKUP_MOD, 1, OMAP3430_ST_IO_MASK | |
140 | OMAP3430_ST_IO_CHAIN_MASK); | |
8cb0ac99 | 141 | |
22f51371 | 142 | return c ? IRQ_HANDLED : IRQ_NONE; |
77da2d91 | 143 | } |
8bd22949 | 144 | |
22f51371 | 145 | static irqreturn_t _prcm_int_handle_wakeup(int irq, void *unused) |
77da2d91 | 146 | { |
22f51371 | 147 | int c; |
d6290a3e | 148 | |
22f51371 TK |
149 | /* |
150 | * Clear all except ST_IO and ST_IO_CHAIN for wkup module, | |
151 | * these are handled in a separate handler to avoid acking | |
152 | * IO events before parsing in mux code | |
153 | */ | |
9cb6d363 TK |
154 | c = omap_prm_clear_mod_irqs(WKUP_MOD, 1, ~(OMAP3430_ST_IO_MASK | |
155 | OMAP3430_ST_IO_CHAIN_MASK)); | |
156 | c += omap_prm_clear_mod_irqs(CORE_MOD, 1, ~0); | |
157 | c += omap_prm_clear_mod_irqs(OMAP3430_PER_MOD, 1, ~0); | |
22f51371 | 158 | if (omap_rev() > OMAP3430_REV_ES1_0) { |
9cb6d363 TK |
159 | c += omap_prm_clear_mod_irqs(CORE_MOD, 3, ~0); |
160 | c += omap_prm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1, ~0); | |
22f51371 | 161 | } |
8bd22949 | 162 | |
22f51371 | 163 | return c ? IRQ_HANDLED : IRQ_NONE; |
8bd22949 KH |
164 | } |
165 | ||
cbe26349 RK |
166 | static void omap34xx_save_context(u32 *save) |
167 | { | |
168 | u32 val; | |
169 | ||
170 | /* Read Auxiliary Control Register */ | |
171 | asm("mrc p15, 0, %0, c1, c0, 1" : "=r" (val)); | |
172 | *save++ = 1; | |
173 | *save++ = val; | |
174 | ||
175 | /* Read L2 AUX ctrl register */ | |
176 | asm("mrc p15, 1, %0, c9, c0, 2" : "=r" (val)); | |
177 | *save++ = 1; | |
178 | *save++ = val; | |
179 | } | |
180 | ||
29cb3cd2 | 181 | static int omap34xx_do_sram_idle(unsigned long save_state) |
57f277b0 | 182 | { |
cbe26349 | 183 | omap34xx_cpu_suspend(save_state); |
29cb3cd2 | 184 | return 0; |
57f277b0 RN |
185 | } |
186 | ||
99e6a4d2 | 187 | void omap_sram_idle(void) |
8bd22949 KH |
188 | { |
189 | /* Variable to tell what needs to be saved and restored | |
190 | * in omap_sram_idle*/ | |
191 | /* save_state = 0 => Nothing to save and restored */ | |
192 | /* save_state = 1 => Only L1 and logic lost */ | |
193 | /* save_state = 2 => Only L2 lost */ | |
194 | /* save_state = 3 => L1, L2 and logic lost */ | |
fa3c2a4f RN |
195 | int save_state = 0; |
196 | int mpu_next_state = PWRDM_POWER_ON; | |
197 | int per_next_state = PWRDM_POWER_ON; | |
198 | int core_next_state = PWRDM_POWER_ON; | |
13a6fe0f | 199 | u32 sdrc_pwr = 0; |
8bd22949 | 200 | |
8bd22949 KH |
201 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); |
202 | switch (mpu_next_state) { | |
fa3c2a4f | 203 | case PWRDM_POWER_ON: |
8bd22949 KH |
204 | case PWRDM_POWER_RET: |
205 | /* No need to save context */ | |
206 | save_state = 0; | |
207 | break; | |
61255ab9 RN |
208 | case PWRDM_POWER_OFF: |
209 | save_state = 3; | |
210 | break; | |
8bd22949 KH |
211 | default: |
212 | /* Invalid state */ | |
98179856 | 213 | pr_err("Invalid mpu state in sram_idle\n"); |
8bd22949 KH |
214 | return; |
215 | } | |
fe617af7 | 216 | |
fa3c2a4f RN |
217 | /* NEON control */ |
218 | if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) | |
7139178e | 219 | pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); |
fa3c2a4f | 220 | |
40742fa8 | 221 | /* Enable IO-PAD and IO-CHAIN wakeups */ |
658ce97e | 222 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); |
ecf157d0 | 223 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); |
40742fa8 | 224 | |
e0e29fd7 | 225 | pwrdm_pre_transition(NULL); |
ff2f8e5f | 226 | |
40742fa8 | 227 | /* PER */ |
b764a586 TL |
228 | if (per_next_state == PWRDM_POWER_OFF) |
229 | cpu_cluster_pm_enter(); | |
658ce97e KH |
230 | |
231 | /* CORE */ | |
fa3c2a4f | 232 | if (core_next_state < PWRDM_POWER_ON) { |
2f5939c3 RN |
233 | if (core_next_state == PWRDM_POWER_OFF) { |
234 | omap3_core_save_context(); | |
f0611a5c | 235 | omap3_cm_save_context(); |
2f5939c3 | 236 | } |
fa3c2a4f | 237 | } |
40742fa8 | 238 | |
3b8c4ebb TL |
239 | /* Configure PMIC signaling for I2C4 or sys_off_mode */ |
240 | omap3_vc_set_pmic_signaling(core_next_state); | |
241 | ||
f18cc2ff | 242 | omap3_intc_prepare_idle(); |
8bd22949 | 243 | |
13a6fe0f | 244 | /* |
30474544 PW |
245 | * On EMU/HS devices ROM code restores a SRDC value |
246 | * from scratchpad which has automatic self refresh on timeout | |
247 | * of AUTO_CNT = 1 enabled. This takes care of erratum ID i443. | |
248 | * Hence store/restore the SDRC_POWER register here. | |
249 | */ | |
250 | if (cpu_is_omap3430() && omap_rev() >= OMAP3430_REV_ES3_0 && | |
251 | (omap_type() == OMAP2_DEVICE_TYPE_EMU || | |
252 | omap_type() == OMAP2_DEVICE_TYPE_SEC) && | |
f265dc4c | 253 | core_next_state == PWRDM_POWER_OFF) |
13a6fe0f | 254 | sdrc_pwr = sdrc_read_reg(SDRC_POWER); |
13a6fe0f | 255 | |
61255ab9 | 256 | /* |
076f2cc4 RK |
257 | * omap3_arm_context is the location where some ARM context |
258 | * get saved. The rest is placed on the stack, and restored | |
259 | * from there before resuming. | |
61255ab9 | 260 | */ |
cbe26349 RK |
261 | if (save_state) |
262 | omap34xx_save_context(omap3_arm_context); | |
076f2cc4 | 263 | if (save_state == 1 || save_state == 3) |
2c74a0ce | 264 | cpu_suspend(save_state, omap34xx_do_sram_idle); |
076f2cc4 RK |
265 | else |
266 | omap34xx_do_sram_idle(save_state); | |
8bd22949 | 267 | |
f265dc4c | 268 | /* Restore normal SDRC POWER settings */ |
30474544 PW |
269 | if (cpu_is_omap3430() && omap_rev() >= OMAP3430_REV_ES3_0 && |
270 | (omap_type() == OMAP2_DEVICE_TYPE_EMU || | |
271 | omap_type() == OMAP2_DEVICE_TYPE_SEC) && | |
13a6fe0f TK |
272 | core_next_state == PWRDM_POWER_OFF) |
273 | sdrc_write_reg(sdrc_pwr, SDRC_POWER); | |
274 | ||
658ce97e | 275 | /* CORE */ |
1560d158 DG |
276 | if (core_next_state < PWRDM_POWER_ON && |
277 | pwrdm_read_prev_pwrst(core_pwrdm) == PWRDM_POWER_OFF) { | |
278 | omap3_core_restore_context(); | |
279 | omap3_cm_restore_context(); | |
280 | omap3_sram_restore_context(); | |
281 | omap2_sms_restore_context(); | |
282 | } else { | |
283 | /* | |
284 | * In off-mode resume path above, omap3_core_restore_context | |
285 | * also handles the INTC autoidle restore done here so limit | |
286 | * this to non-off mode resume paths so we don't do it twice. | |
287 | */ | |
288 | omap3_intc_resume_idle(); | |
658ce97e KH |
289 | } |
290 | ||
e0e29fd7 KH |
291 | pwrdm_post_transition(NULL); |
292 | ||
658ce97e | 293 | /* PER */ |
b764a586 TL |
294 | if (per_next_state == PWRDM_POWER_OFF) |
295 | cpu_cluster_pm_exit(); | |
8bd22949 KH |
296 | } |
297 | ||
8bd22949 KH |
298 | static void omap3_pm_idle(void) |
299 | { | |
0bcd24b0 | 300 | if (omap_irq_pending()) |
6b85638b | 301 | return; |
8bd22949 | 302 | |
6ca22700 | 303 | trace_cpu_idle_rcuidle(1, smp_processor_id()); |
5e7c58dc | 304 | |
8bd22949 KH |
305 | omap_sram_idle(); |
306 | ||
6ca22700 | 307 | trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); |
8bd22949 KH |
308 | } |
309 | ||
10f90ed2 | 310 | #ifdef CONFIG_SUSPEND |
8bd22949 KH |
311 | static int omap3_pm_suspend(void) |
312 | { | |
313 | struct power_state *pwrst; | |
314 | int state, ret = 0; | |
315 | ||
316 | /* Read current next_pwrsts */ | |
317 | list_for_each_entry(pwrst, &pwrst_list, node) | |
318 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); | |
319 | /* Set ones wanted by suspend */ | |
320 | list_for_each_entry(pwrst, &pwrst_list, node) { | |
eb6a2c75 | 321 | if (omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state)) |
8bd22949 KH |
322 | goto restore; |
323 | if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm)) | |
324 | goto restore; | |
325 | } | |
326 | ||
2bbe3af3 TK |
327 | omap3_intc_suspend(); |
328 | ||
8bd22949 KH |
329 | omap_sram_idle(); |
330 | ||
331 | restore: | |
332 | /* Restore next_pwrsts */ | |
333 | list_for_each_entry(pwrst, &pwrst_list, node) { | |
8bd22949 KH |
334 | state = pwrdm_read_prev_pwrst(pwrst->pwrdm); |
335 | if (state > pwrst->next_state) { | |
7852ec05 PW |
336 | pr_info("Powerdomain (%s) didn't enter target state %d\n", |
337 | pwrst->pwrdm->name, pwrst->next_state); | |
8bd22949 KH |
338 | ret = -1; |
339 | } | |
eb6a2c75 | 340 | omap_set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); |
8bd22949 KH |
341 | } |
342 | if (ret) | |
98179856 | 343 | pr_err("Could not enter target state in pm_suspend\n"); |
8bd22949 | 344 | else |
98179856 | 345 | pr_info("Successfully put all powerdomains to target state\n"); |
8bd22949 KH |
346 | |
347 | return ret; | |
348 | } | |
2e4b62dc DG |
349 | #else |
350 | #define omap3_pm_suspend NULL | |
10f90ed2 | 351 | #endif /* CONFIG_SUSPEND */ |
8bd22949 | 352 | |
8111b221 KH |
353 | static void __init prcm_setup_regs(void) |
354 | { | |
ba12c242 | 355 | omap3_ctrl_init(); |
b296c811 | 356 | |
c5180a2b | 357 | omap3_prm_init_pm(cpu_is_omap3630(), omap3_has_iva()); |
8bd22949 KH |
358 | } |
359 | ||
c40552bc KH |
360 | void omap3_pm_off_mode_enable(int enable) |
361 | { | |
362 | struct power_state *pwrst; | |
363 | u32 state; | |
364 | ||
365 | if (enable) | |
366 | state = PWRDM_POWER_OFF; | |
367 | else | |
368 | state = PWRDM_POWER_RET; | |
369 | ||
370 | list_for_each_entry(pwrst, &pwrst_list, node) { | |
cc1b6028 EV |
371 | if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) && |
372 | pwrst->pwrdm == core_pwrdm && | |
373 | state == PWRDM_POWER_OFF) { | |
374 | pwrst->next_state = PWRDM_POWER_RET; | |
e16b41bf | 375 | pr_warn("%s: Core OFF disabled due to errata i583\n", |
cc1b6028 EV |
376 | __func__); |
377 | } else { | |
378 | pwrst->next_state = state; | |
379 | } | |
380 | omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); | |
c40552bc KH |
381 | } |
382 | } | |
383 | ||
68d4778c TK |
384 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) |
385 | { | |
386 | struct power_state *pwrst; | |
387 | ||
388 | list_for_each_entry(pwrst, &pwrst_list, node) { | |
389 | if (pwrst->pwrdm == pwrdm) | |
390 | return pwrst->next_state; | |
391 | } | |
392 | return -EINVAL; | |
393 | } | |
394 | ||
395 | int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) | |
396 | { | |
397 | struct power_state *pwrst; | |
398 | ||
399 | list_for_each_entry(pwrst, &pwrst_list, node) { | |
400 | if (pwrst->pwrdm == pwrdm) { | |
401 | pwrst->next_state = state; | |
402 | return 0; | |
403 | } | |
404 | } | |
405 | return -EINVAL; | |
406 | } | |
407 | ||
a23456e9 | 408 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) |
8bd22949 KH |
409 | { |
410 | struct power_state *pwrst; | |
411 | ||
412 | if (!pwrdm->pwrsts) | |
413 | return 0; | |
414 | ||
d3d381c6 | 415 | pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC); |
8bd22949 KH |
416 | if (!pwrst) |
417 | return -ENOMEM; | |
418 | pwrst->pwrdm = pwrdm; | |
419 | pwrst->next_state = PWRDM_POWER_RET; | |
420 | list_add(&pwrst->node, &pwrst_list); | |
421 | ||
422 | if (pwrdm_has_hdwr_sar(pwrdm)) | |
423 | pwrdm_enable_hdwr_sar(pwrdm); | |
424 | ||
eb6a2c75 | 425 | return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); |
8bd22949 KH |
426 | } |
427 | ||
46e130d2 JP |
428 | /* |
429 | * Push functions to SRAM | |
430 | * | |
431 | * The minimum set of functions is pushed to SRAM for execution: | |
432 | * - omap3_do_wfi for erratum i581 WA, | |
46e130d2 | 433 | */ |
3231fc88 RN |
434 | void omap_push_sram_idle(void) |
435 | { | |
46e130d2 | 436 | omap3_do_wfi_sram = omap_sram_push(omap3_do_wfi, omap3_do_wfi_sz); |
3231fc88 RN |
437 | } |
438 | ||
8cdfd834 NM |
439 | static void __init pm_errata_configure(void) |
440 | { | |
c4236d2e | 441 | if (cpu_is_omap3630()) { |
458e999e | 442 | pm34xx_errata |= PM_RTA_ERRATUM_i608; |
c4236d2e PDS |
443 | /* Enable the l2 cache toggling in sleep logic */ |
444 | enable_omap3630_toggle_l2_on_restore(); | |
cc1b6028 | 445 | if (omap_rev() < OMAP3630_REV_ES1_2) |
856c3c5b PW |
446 | pm34xx_errata |= (PM_SDRC_WAKEUP_ERRATUM_i583 | |
447 | PM_PER_MEMORIES_ERRATUM_i582); | |
448 | } else if (cpu_is_omap34xx()) { | |
449 | pm34xx_errata |= PM_PER_MEMORIES_ERRATUM_i582; | |
c4236d2e | 450 | } |
8cdfd834 NM |
451 | } |
452 | ||
bbd707ac | 453 | int __init omap3_pm_init(void) |
8bd22949 KH |
454 | { |
455 | struct power_state *pwrst, *tmp; | |
856c3c5b | 456 | struct clockdomain *neon_clkdm, *mpu_clkdm, *per_clkdm, *wkup_clkdm; |
8bd22949 KH |
457 | int ret; |
458 | ||
b02b9172 | 459 | if (!omap3_has_io_chain_ctrl()) |
3d0cb73e | 460 | pr_warn("PM: no software I/O chain control; some wakeups may be lost\n"); |
b02b9172 | 461 | |
8cdfd834 NM |
462 | pm_errata_configure(); |
463 | ||
8bd22949 KH |
464 | /* XXX prcm_setup_regs needs to be before enabling hw |
465 | * supervised mode for powerdomains */ | |
466 | prcm_setup_regs(); | |
467 | ||
22f51371 TK |
468 | ret = request_irq(omap_prcm_event_to_irq("wkup"), |
469 | _prcm_int_handle_wakeup, IRQF_NO_SUSPEND, "pm_wkup", NULL); | |
470 | ||
471 | if (ret) { | |
472 | pr_err("pm: Failed to request pm_wkup irq\n"); | |
473 | goto err1; | |
474 | } | |
475 | ||
476 | /* IO interrupt is shared with mux code */ | |
477 | ret = request_irq(omap_prcm_event_to_irq("io"), | |
478 | _prcm_int_handle_io, IRQF_SHARED | IRQF_NO_SUSPEND, "pm_io", | |
479 | omap3_pm_init); | |
480 | ||
8bd22949 | 481 | if (ret) { |
22f51371 | 482 | pr_err("pm: Failed to request pm_io irq\n"); |
ce229c5d | 483 | goto err2; |
8bd22949 KH |
484 | } |
485 | ||
a23456e9 | 486 | ret = pwrdm_for_each(pwrdms_setup, NULL); |
8bd22949 | 487 | if (ret) { |
98179856 | 488 | pr_err("Failed to setup powerdomains\n"); |
ce229c5d | 489 | goto err3; |
8bd22949 KH |
490 | } |
491 | ||
92206fd2 | 492 | (void) clkdm_for_each(omap_pm_clkdms_setup, NULL); |
8bd22949 KH |
493 | |
494 | mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); | |
495 | if (mpu_pwrdm == NULL) { | |
98179856 | 496 | pr_err("Failed to get mpu_pwrdm\n"); |
ce229c5d MG |
497 | ret = -EINVAL; |
498 | goto err3; | |
8bd22949 KH |
499 | } |
500 | ||
fa3c2a4f RN |
501 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); |
502 | per_pwrdm = pwrdm_lookup("per_pwrdm"); | |
503 | core_pwrdm = pwrdm_lookup("core_pwrdm"); | |
504 | ||
55ed9694 PW |
505 | neon_clkdm = clkdm_lookup("neon_clkdm"); |
506 | mpu_clkdm = clkdm_lookup("mpu_clkdm"); | |
856c3c5b PW |
507 | per_clkdm = clkdm_lookup("per_clkdm"); |
508 | wkup_clkdm = clkdm_lookup("wkup_clkdm"); | |
55ed9694 | 509 | |
2e4b62dc | 510 | omap_common_suspend_init(omap3_pm_suspend); |
8bd22949 | 511 | |
0bcd24b0 | 512 | arm_pm_idle = omap3_pm_idle; |
0343371e | 513 | omap3_idle_init(); |
8bd22949 | 514 | |
458e999e NM |
515 | /* |
516 | * RTA is disabled during initialization as per erratum i608 | |
517 | * it is safer to disable RTA by the bootloader, but we would like | |
518 | * to be doubly sure here and prevent any mishaps. | |
519 | */ | |
520 | if (IS_PM34XX_ERRATUM(PM_RTA_ERRATUM_i608)) | |
521 | omap3630_ctrl_disable_rta(); | |
522 | ||
856c3c5b PW |
523 | /* |
524 | * The UART3/4 FIFO and the sidetone memory in McBSP2/3 are | |
525 | * not correctly reset when the PER powerdomain comes back | |
526 | * from OFF or OSWR when the CORE powerdomain is kept active. | |
527 | * See OMAP36xx Erratum i582 "PER Domain reset issue after | |
528 | * Domain-OFF/OSWR Wakeup". This wakeup dependency is not a | |
529 | * complete workaround. The kernel must also prevent the PER | |
530 | * powerdomain from going to OSWR/OFF while the CORE | |
531 | * powerdomain is not going to OSWR/OFF. And if PER last | |
532 | * power state was off while CORE last power state was ON, the | |
533 | * UART3/4 and McBSP2/3 SIDETONE devices need to run a | |
534 | * self-test using their loopback tests; if that fails, those | |
535 | * devices are unusable until the PER/CORE can complete a transition | |
536 | * from ON to OSWR/OFF and then back to ON. | |
537 | * | |
538 | * XXX Technically this workaround is only needed if off-mode | |
539 | * or OSWR is enabled. | |
540 | */ | |
541 | if (IS_PM34XX_ERRATUM(PM_PER_MEMORIES_ERRATUM_i582)) | |
542 | clkdm_add_wkdep(per_clkdm, wkup_clkdm); | |
543 | ||
55ed9694 | 544 | clkdm_add_wkdep(neon_clkdm, mpu_clkdm); |
27d59a4a TK |
545 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { |
546 | omap3_secure_ram_storage = | |
d09220a8 | 547 | kmalloc(OMAP3_SAVE_SECURE_RAM_SZ, GFP_KERNEL); |
27d59a4a | 548 | if (!omap3_secure_ram_storage) |
7852ec05 | 549 | pr_err("Memory allocation failed when allocating for secure sram context\n"); |
9d97140b TK |
550 | |
551 | local_irq_disable(); | |
9d97140b TK |
552 | |
553 | omap_dma_global_context_save(); | |
617fcc98 | 554 | omap3_save_secure_ram_context(); |
9d97140b TK |
555 | omap_dma_global_context_restore(); |
556 | ||
557 | local_irq_enable(); | |
27d59a4a | 558 | } |
27d59a4a | 559 | |
9d97140b | 560 | omap3_save_scratchpad_contents(); |
8bd22949 | 561 | return ret; |
ce229c5d MG |
562 | |
563 | err3: | |
8bd22949 KH |
564 | list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) { |
565 | list_del(&pwrst->node); | |
566 | kfree(pwrst); | |
567 | } | |
ce229c5d MG |
568 | free_irq(omap_prcm_event_to_irq("io"), omap3_pm_init); |
569 | err2: | |
570 | free_irq(omap_prcm_event_to_irq("wkup"), NULL); | |
571 | err1: | |
8bd22949 KH |
572 | return ret; |
573 | } |