blob: d9440a18bd006a8ed9a889142e91624067875d04 [file] [log] [blame]
Kevin Hilman8bd22942009-05-28 10:56:16 -07001/*
2 * OMAP3 Power Management Routines
3 *
4 * Copyright (C) 2006-2008 Nokia Corporation
5 * Tony Lindgren <tony@atomide.com>
6 * Jouni Hogander
7 *
8 * Copyright (C) 2005 Texas Instruments, Inc.
9 * Richard Woodruff <r-woodruff2@ti.com>
10 *
11 * Based on pm.c for omap1
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/pm.h>
19#include <linux/suspend.h>
20#include <linux/interrupt.h>
21#include <linux/module.h>
22#include <linux/list.h>
23#include <linux/err.h>
24#include <linux/gpio.h>
25
26#include <mach/sram.h>
27#include <mach/clockdomain.h>
28#include <mach/powerdomain.h>
29#include <mach/control.h>
Kevin Hilman4af40162009-02-04 10:51:40 -080030#include <mach/serial.h>
Kevin Hilman8bd22942009-05-28 10:56:16 -070031
32#include "cm.h"
33#include "cm-regbits-34xx.h"
34#include "prm-regbits-34xx.h"
35
36#include "prm.h"
37#include "pm.h"
38
39struct power_state {
40 struct powerdomain *pwrdm;
41 u32 next_state;
Kevin Hilman10f90ed2009-06-24 11:39:18 -070042#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -070043 u32 saved_state;
Kevin Hilman10f90ed2009-06-24 11:39:18 -070044#endif
Kevin Hilman8bd22942009-05-28 10:56:16 -070045 struct list_head node;
46};
47
48static LIST_HEAD(pwrst_list);
49
50static void (*_omap_sram_idle)(u32 *addr, int save_state);
51
52static struct powerdomain *mpu_pwrdm;
53
Jon Hunter77da2d92009-06-27 00:07:25 -050054/*
55 * PRCM Interrupt Handler Helper Function
56 *
57 * The purpose of this function is to clear any wake-up events latched
58 * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
59 * may occur whilst attempting to clear a PM_WKST_x register and thus
60 * set another bit in this register. A while loop is used to ensure
61 * that any peripheral wake-up events occurring while attempting to
62 * clear the PM_WKST_x are detected and cleared.
63 */
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070064static int prcm_clear_mod_irqs(s16 module, u8 regs)
Jon Hunter77da2d92009-06-27 00:07:25 -050065{
66 u32 wkst, fclk, iclk;
67 u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
68 u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
69 u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
Paul Walmsley5d805972009-07-22 10:18:07 -070070 u16 grpsel_off = (regs == 3) ?
71 OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070072 int c = 0;
Jon Hunter77da2d92009-06-27 00:07:25 -050073
74 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley5d805972009-07-22 10:18:07 -070075 wkst &= prm_read_mod_reg(module, grpsel_off);
Jon Hunter77da2d92009-06-27 00:07:25 -050076 if (wkst) {
77 iclk = cm_read_mod_reg(module, iclk_off);
78 fclk = cm_read_mod_reg(module, fclk_off);
79 while (wkst) {
80 cm_set_mod_reg_bits(wkst, module, iclk_off);
81 cm_set_mod_reg_bits(wkst, module, fclk_off);
82 prm_write_mod_reg(wkst, module, wkst_off);
83 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070084 c++;
Jon Hunter77da2d92009-06-27 00:07:25 -050085 }
86 cm_write_mod_reg(iclk, module, iclk_off);
87 cm_write_mod_reg(fclk, module, fclk_off);
88 }
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070089
90 return c;
91}
92
93static int _prcm_int_handle_wakeup(void)
94{
95 int c;
96
97 c = prcm_clear_mod_irqs(WKUP_MOD, 1);
98 c += prcm_clear_mod_irqs(CORE_MOD, 1);
99 c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
100 if (omap_rev() > OMAP3430_REV_ES1_0) {
101 c += prcm_clear_mod_irqs(CORE_MOD, 3);
102 c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
103 }
104
105 return c;
Jon Hunter77da2d92009-06-27 00:07:25 -0500106}
107
108/*
109 * PRCM Interrupt Handler
110 *
111 * The PRM_IRQSTATUS_MPU register indicates if there are any pending
112 * interrupts from the PRCM for the MPU. These bits must be cleared in
113 * order to clear the PRCM interrupt. The PRCM interrupt handler is
114 * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
115 * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
116 * register indicates that a wake-up event is pending for the MPU and
117 * this bit can only be cleared if the all the wake-up events latched
118 * in the various PM_WKST_x registers have been cleared. The interrupt
119 * handler is implemented using a do-while loop so that if a wake-up
120 * event occurred during the processing of the prcm interrupt handler
121 * (setting a bit in the corresponding PM_WKST_x register and thus
122 * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
123 * this would be handled.
124 */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700125static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
126{
Jon Hunter77da2d92009-06-27 00:07:25 -0500127 u32 irqstatus_mpu;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700128 int c = 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700129
Jon Hunter77da2d92009-06-27 00:07:25 -0500130 do {
Jon Hunter77da2d92009-06-27 00:07:25 -0500131 irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
132 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700133
134 if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
135 c = _prcm_int_handle_wakeup();
136
137 /*
138 * Is the MPU PRCM interrupt handler racing with the
139 * IVA2 PRCM interrupt handler ?
140 */
141 WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
142 "but no wakeup sources are marked\n");
143 } else {
144 /* XXX we need to expand our PRCM interrupt handler */
145 WARN(1, "prcm: WARNING: PRCM interrupt received, but "
146 "no code to handle it (%08x)\n", irqstatus_mpu);
147 }
148
Jon Hunter77da2d92009-06-27 00:07:25 -0500149 prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
150 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700151
Jon Hunter77da2d92009-06-27 00:07:25 -0500152 } while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET));
Kevin Hilman8bd22942009-05-28 10:56:16 -0700153
154 return IRQ_HANDLED;
155}
156
157static void omap_sram_idle(void)
158{
159 /* Variable to tell what needs to be saved and restored
160 * in omap_sram_idle*/
161 /* save_state = 0 => Nothing to save and restored */
162 /* save_state = 1 => Only L1 and logic lost */
163 /* save_state = 2 => Only L2 lost */
164 /* save_state = 3 => L1, L2 and logic lost */
165 int save_state = 0, mpu_next_state;
166
167 if (!_omap_sram_idle)
168 return;
169
170 mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
171 switch (mpu_next_state) {
172 case PWRDM_POWER_RET:
173 /* No need to save context */
174 save_state = 0;
175 break;
176 default:
177 /* Invalid state */
178 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
179 return;
180 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300181 pwrdm_pre_transition();
182
Kevin Hilman8bd22942009-05-28 10:56:16 -0700183 omap2_gpio_prepare_for_retention();
Kevin Hilman4af40162009-02-04 10:51:40 -0800184 omap_uart_prepare_idle(0);
185 omap_uart_prepare_idle(1);
186 omap_uart_prepare_idle(2);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700187
188 _omap_sram_idle(NULL, save_state);
189 cpu_init();
190
Kevin Hilman4af40162009-02-04 10:51:40 -0800191 omap_uart_resume_idle(2);
192 omap_uart_resume_idle(1);
193 omap_uart_resume_idle(0);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700194 omap2_gpio_resume_after_retention();
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300195
196 pwrdm_post_transition();
197
Kevin Hilman8bd22942009-05-28 10:56:16 -0700198}
199
200/*
201 * Check if functional clocks are enabled before entering
202 * sleep. This function could be behind CONFIG_PM_DEBUG
203 * when all drivers are configuring their sysconfig registers
204 * properly and using their clocks properly.
205 */
206static int omap3_fclks_active(void)
207{
208 u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
209 fck_cam = 0, fck_per = 0, fck_usbhost = 0;
210
211 fck_core1 = cm_read_mod_reg(CORE_MOD,
212 CM_FCLKEN1);
213 if (omap_rev() > OMAP3430_REV_ES1_0) {
214 fck_core3 = cm_read_mod_reg(CORE_MOD,
215 OMAP3430ES2_CM_FCLKEN3);
216 fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
217 CM_FCLKEN);
218 fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
219 CM_FCLKEN);
220 } else
221 fck_sgx = cm_read_mod_reg(GFX_MOD,
222 OMAP3430ES2_CM_FCLKEN3);
223 fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
224 CM_FCLKEN);
225 fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
226 CM_FCLKEN);
227 fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
228 CM_FCLKEN);
Kevin Hilman4af40162009-02-04 10:51:40 -0800229
230 /* Ignore UART clocks. These are handled by UART core (serial.c) */
231 fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
232 fck_per &= ~OMAP3430_EN_UART3;
233
Kevin Hilman8bd22942009-05-28 10:56:16 -0700234 if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
235 fck_cam | fck_per | fck_usbhost)
236 return 1;
237 return 0;
238}
239
240static int omap3_can_sleep(void)
241{
Kevin Hilman4af40162009-02-04 10:51:40 -0800242 if (!omap_uart_can_sleep())
243 return 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700244 if (omap3_fclks_active())
245 return 0;
246 return 1;
247}
248
249/* This sets pwrdm state (other than mpu & core. Currently only ON &
250 * RET are supported. Function is assuming that clkdm doesn't have
251 * hw_sup mode enabled. */
252static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
253{
254 u32 cur_state;
255 int sleep_switch = 0;
256 int ret = 0;
257
258 if (pwrdm == NULL || IS_ERR(pwrdm))
259 return -EINVAL;
260
261 while (!(pwrdm->pwrsts & (1 << state))) {
262 if (state == PWRDM_POWER_OFF)
263 return ret;
264 state--;
265 }
266
267 cur_state = pwrdm_read_next_pwrst(pwrdm);
268 if (cur_state == state)
269 return ret;
270
271 if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
272 omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
273 sleep_switch = 1;
274 pwrdm_wait_transition(pwrdm);
275 }
276
277 ret = pwrdm_set_next_pwrst(pwrdm, state);
278 if (ret) {
279 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
280 pwrdm->name);
281 goto err;
282 }
283
284 if (sleep_switch) {
285 omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
286 pwrdm_wait_transition(pwrdm);
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300287 pwrdm_state_switch(pwrdm);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700288 }
289
290err:
291 return ret;
292}
293
294static void omap3_pm_idle(void)
295{
296 local_irq_disable();
297 local_fiq_disable();
298
299 if (!omap3_can_sleep())
300 goto out;
301
302 if (omap_irq_pending())
303 goto out;
304
305 omap_sram_idle();
306
307out:
308 local_fiq_enable();
309 local_irq_enable();
310}
311
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700312#ifdef CONFIG_SUSPEND
Tero Kristo24662112009-03-05 16:32:23 +0200313static suspend_state_t suspend_state;
314
Kevin Hilman8bd22942009-05-28 10:56:16 -0700315static int omap3_pm_prepare(void)
316{
317 disable_hlt();
318 return 0;
319}
320
321static int omap3_pm_suspend(void)
322{
323 struct power_state *pwrst;
324 int state, ret = 0;
325
326 /* Read current next_pwrsts */
327 list_for_each_entry(pwrst, &pwrst_list, node)
328 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
329 /* Set ones wanted by suspend */
330 list_for_each_entry(pwrst, &pwrst_list, node) {
331 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
332 goto restore;
333 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
334 goto restore;
335 }
336
Kevin Hilman4af40162009-02-04 10:51:40 -0800337 omap_uart_prepare_suspend();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700338 omap_sram_idle();
339
340restore:
341 /* Restore next_pwrsts */
342 list_for_each_entry(pwrst, &pwrst_list, node) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700343 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
344 if (state > pwrst->next_state) {
345 printk(KERN_INFO "Powerdomain (%s) didn't enter "
346 "target state %d\n",
347 pwrst->pwrdm->name, pwrst->next_state);
348 ret = -1;
349 }
Jouni Hogander6c5f8032008-10-29 12:06:04 +0200350 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700351 }
352 if (ret)
353 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
354 else
355 printk(KERN_INFO "Successfully put all powerdomains "
356 "to target state\n");
357
358 return ret;
359}
360
Tero Kristo24662112009-03-05 16:32:23 +0200361static int omap3_pm_enter(suspend_state_t unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700362{
363 int ret = 0;
364
Tero Kristo24662112009-03-05 16:32:23 +0200365 switch (suspend_state) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700366 case PM_SUSPEND_STANDBY:
367 case PM_SUSPEND_MEM:
368 ret = omap3_pm_suspend();
369 break;
370 default:
371 ret = -EINVAL;
372 }
373
374 return ret;
375}
376
377static void omap3_pm_finish(void)
378{
379 enable_hlt();
380}
381
Tero Kristo24662112009-03-05 16:32:23 +0200382/* Hooks to enable / disable UART interrupts during suspend */
383static int omap3_pm_begin(suspend_state_t state)
384{
385 suspend_state = state;
386 omap_uart_enable_irqs(0);
387 return 0;
388}
389
390static void omap3_pm_end(void)
391{
392 suspend_state = PM_SUSPEND_ON;
393 omap_uart_enable_irqs(1);
394 return;
395}
396
Kevin Hilman8bd22942009-05-28 10:56:16 -0700397static struct platform_suspend_ops omap_pm_ops = {
Tero Kristo24662112009-03-05 16:32:23 +0200398 .begin = omap3_pm_begin,
399 .end = omap3_pm_end,
Kevin Hilman8bd22942009-05-28 10:56:16 -0700400 .prepare = omap3_pm_prepare,
401 .enter = omap3_pm_enter,
402 .finish = omap3_pm_finish,
403 .valid = suspend_valid_only_mem,
404};
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700405#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700406
Kevin Hilman1155e422008-11-25 11:48:24 -0800407
408/**
409 * omap3_iva_idle(): ensure IVA is in idle so it can be put into
410 * retention
411 *
412 * In cases where IVA2 is activated by bootcode, it may prevent
413 * full-chip retention or off-mode because it is not idle. This
414 * function forces the IVA2 into idle state so it can go
415 * into retention/off and thus allow full-chip retention/off.
416 *
417 **/
418static void __init omap3_iva_idle(void)
419{
420 /* ensure IVA2 clock is disabled */
421 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
422
423 /* if no clock activity, nothing else to do */
424 if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
425 OMAP3430_CLKACTIVITY_IVA2_MASK))
426 return;
427
428 /* Reset IVA2 */
429 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
430 OMAP3430_RST2_IVA2 |
431 OMAP3430_RST3_IVA2,
432 OMAP3430_IVA2_MOD, RM_RSTCTRL);
433
434 /* Enable IVA2 clock */
435 cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
436 OMAP3430_IVA2_MOD, CM_FCLKEN);
437
438 /* Set IVA2 boot mode to 'idle' */
439 omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
440 OMAP343X_CONTROL_IVA2_BOOTMOD);
441
442 /* Un-reset IVA2 */
443 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
444
445 /* Disable IVA2 clock */
446 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
447
448 /* Reset IVA2 */
449 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
450 OMAP3430_RST2_IVA2 |
451 OMAP3430_RST3_IVA2,
452 OMAP3430_IVA2_MOD, RM_RSTCTRL);
453}
454
Kevin Hilman8111b222009-04-28 15:27:44 -0700455static void __init omap3_d2d_idle(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700456{
Kevin Hilman8111b222009-04-28 15:27:44 -0700457 u16 mask, padconf;
458
459 /* In a stand alone OMAP3430 where there is not a stacked
460 * modem for the D2D Idle Ack and D2D MStandby must be pulled
461 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
462 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
463 mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
464 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
465 padconf |= mask;
466 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
467
468 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
469 padconf |= mask;
470 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
471
Kevin Hilman8bd22942009-05-28 10:56:16 -0700472 /* reset modem */
473 prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
474 OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
475 CORE_MOD, RM_RSTCTRL);
476 prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
Kevin Hilman8111b222009-04-28 15:27:44 -0700477}
Kevin Hilman8bd22942009-05-28 10:56:16 -0700478
Kevin Hilman8111b222009-04-28 15:27:44 -0700479static void __init prcm_setup_regs(void)
480{
Kevin Hilman8bd22942009-05-28 10:56:16 -0700481 /* XXX Reset all wkdeps. This should be done when initializing
482 * powerdomains */
483 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
484 prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
485 prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
486 prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
487 prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
488 prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
489 if (omap_rev() > OMAP3430_REV_ES1_0) {
490 prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
491 prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
492 } else
493 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
494
495 /*
496 * Enable interface clock autoidle for all modules.
497 * Note that in the long run this should be done by clockfw
498 */
499 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700500 OMAP3430_AUTO_MODEM |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700501 OMAP3430ES2_AUTO_MMC3 |
502 OMAP3430ES2_AUTO_ICR |
503 OMAP3430_AUTO_AES2 |
504 OMAP3430_AUTO_SHA12 |
505 OMAP3430_AUTO_DES2 |
506 OMAP3430_AUTO_MMC2 |
507 OMAP3430_AUTO_MMC1 |
508 OMAP3430_AUTO_MSPRO |
509 OMAP3430_AUTO_HDQ |
510 OMAP3430_AUTO_MCSPI4 |
511 OMAP3430_AUTO_MCSPI3 |
512 OMAP3430_AUTO_MCSPI2 |
513 OMAP3430_AUTO_MCSPI1 |
514 OMAP3430_AUTO_I2C3 |
515 OMAP3430_AUTO_I2C2 |
516 OMAP3430_AUTO_I2C1 |
517 OMAP3430_AUTO_UART2 |
518 OMAP3430_AUTO_UART1 |
519 OMAP3430_AUTO_GPT11 |
520 OMAP3430_AUTO_GPT10 |
521 OMAP3430_AUTO_MCBSP5 |
522 OMAP3430_AUTO_MCBSP1 |
523 OMAP3430ES1_AUTO_FAC | /* This is es1 only */
524 OMAP3430_AUTO_MAILBOXES |
525 OMAP3430_AUTO_OMAPCTRL |
526 OMAP3430ES1_AUTO_FSHOSTUSB |
527 OMAP3430_AUTO_HSOTGUSB |
Kevin Hilman8111b222009-04-28 15:27:44 -0700528 OMAP3430_AUTO_SAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700529 OMAP3430_AUTO_SSI,
530 CORE_MOD, CM_AUTOIDLE1);
531
532 cm_write_mod_reg(
533 OMAP3430_AUTO_PKA |
534 OMAP3430_AUTO_AES1 |
535 OMAP3430_AUTO_RNG |
536 OMAP3430_AUTO_SHA11 |
537 OMAP3430_AUTO_DES1,
538 CORE_MOD, CM_AUTOIDLE2);
539
540 if (omap_rev() > OMAP3430_REV_ES1_0) {
541 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700542 OMAP3430_AUTO_MAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700543 OMAP3430ES2_AUTO_USBTLL,
544 CORE_MOD, CM_AUTOIDLE3);
545 }
546
547 cm_write_mod_reg(
548 OMAP3430_AUTO_WDT2 |
549 OMAP3430_AUTO_WDT1 |
550 OMAP3430_AUTO_GPIO1 |
551 OMAP3430_AUTO_32KSYNC |
552 OMAP3430_AUTO_GPT12 |
553 OMAP3430_AUTO_GPT1 ,
554 WKUP_MOD, CM_AUTOIDLE);
555
556 cm_write_mod_reg(
557 OMAP3430_AUTO_DSS,
558 OMAP3430_DSS_MOD,
559 CM_AUTOIDLE);
560
561 cm_write_mod_reg(
562 OMAP3430_AUTO_CAM,
563 OMAP3430_CAM_MOD,
564 CM_AUTOIDLE);
565
566 cm_write_mod_reg(
567 OMAP3430_AUTO_GPIO6 |
568 OMAP3430_AUTO_GPIO5 |
569 OMAP3430_AUTO_GPIO4 |
570 OMAP3430_AUTO_GPIO3 |
571 OMAP3430_AUTO_GPIO2 |
572 OMAP3430_AUTO_WDT3 |
573 OMAP3430_AUTO_UART3 |
574 OMAP3430_AUTO_GPT9 |
575 OMAP3430_AUTO_GPT8 |
576 OMAP3430_AUTO_GPT7 |
577 OMAP3430_AUTO_GPT6 |
578 OMAP3430_AUTO_GPT5 |
579 OMAP3430_AUTO_GPT4 |
580 OMAP3430_AUTO_GPT3 |
581 OMAP3430_AUTO_GPT2 |
582 OMAP3430_AUTO_MCBSP4 |
583 OMAP3430_AUTO_MCBSP3 |
584 OMAP3430_AUTO_MCBSP2,
585 OMAP3430_PER_MOD,
586 CM_AUTOIDLE);
587
588 if (omap_rev() > OMAP3430_REV_ES1_0) {
589 cm_write_mod_reg(
590 OMAP3430ES2_AUTO_USBHOST,
591 OMAP3430ES2_USBHOST_MOD,
592 CM_AUTOIDLE);
593 }
594
595 /*
596 * Set all plls to autoidle. This is needed until autoidle is
597 * enabled by clockfw
598 */
599 cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
600 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
601 cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
602 MPU_MOD,
603 CM_AUTOIDLE2);
604 cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
605 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
606 PLL_MOD,
607 CM_AUTOIDLE);
608 cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
609 PLL_MOD,
610 CM_AUTOIDLE2);
611
612 /*
613 * Enable control of expternal oscillator through
614 * sys_clkreq. In the long run clock framework should
615 * take care of this.
616 */
617 prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
618 1 << OMAP_AUTOEXTCLKMODE_SHIFT,
619 OMAP3430_GR_MOD,
620 OMAP3_PRM_CLKSRC_CTRL_OFFSET);
621
622 /* setup wakup source */
623 prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
624 OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
625 WKUP_MOD, PM_WKEN);
626 /* No need to write EN_IO, that is always enabled */
627 prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
628 OMAP3430_EN_GPT12,
629 WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
630 /* For some reason IO doesn't generate wakeup event even if
631 * it is selected to mpu wakeup goup */
632 prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
633 OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
Kevin Hilman1155e422008-11-25 11:48:24 -0800634
Kevin Hilmand3fd3292009-05-05 16:34:25 -0700635 /* Don't attach IVA interrupts */
636 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
637 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
638 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
639 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
640
Kevin Hilmanb1340d12009-04-27 16:14:54 -0700641 /* Clear any pending 'reset' flags */
642 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
643 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
644 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
645 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
646 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
647 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
648 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
649
Kevin Hilman014c46d2009-04-27 07:50:23 -0700650 /* Clear any pending PRCM interrupts */
651 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
652
Kevin Hilman040fed02009-05-05 16:34:25 -0700653 /* Don't attach IVA interrupts */
654 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
655 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
656 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
657 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
658
Kevin Hilman3a07ae32009-04-27 16:14:54 -0700659 /* Clear any pending 'reset' flags */
660 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
661 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
662 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
663 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
664 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
665 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
666 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
667
Kevin Hilman3a6667a2009-04-27 07:50:23 -0700668 /* Clear any pending PRCM interrupts */
669 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
670
Kevin Hilman1155e422008-11-25 11:48:24 -0800671 omap3_iva_idle();
Kevin Hilman8111b222009-04-28 15:27:44 -0700672 omap3_d2d_idle();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700673}
674
Tero Kristo68d47782008-11-26 12:26:24 +0200675int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
676{
677 struct power_state *pwrst;
678
679 list_for_each_entry(pwrst, &pwrst_list, node) {
680 if (pwrst->pwrdm == pwrdm)
681 return pwrst->next_state;
682 }
683 return -EINVAL;
684}
685
686int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state)
687{
688 struct power_state *pwrst;
689
690 list_for_each_entry(pwrst, &pwrst_list, node) {
691 if (pwrst->pwrdm == pwrdm) {
692 pwrst->next_state = state;
693 return 0;
694 }
695 }
696 return -EINVAL;
697}
698
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300699static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700700{
701 struct power_state *pwrst;
702
703 if (!pwrdm->pwrsts)
704 return 0;
705
Ming Leid3d381c2009-08-22 21:20:26 +0800706 pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700707 if (!pwrst)
708 return -ENOMEM;
709 pwrst->pwrdm = pwrdm;
710 pwrst->next_state = PWRDM_POWER_RET;
711 list_add(&pwrst->node, &pwrst_list);
712
713 if (pwrdm_has_hdwr_sar(pwrdm))
714 pwrdm_enable_hdwr_sar(pwrdm);
715
716 return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
717}
718
719/*
720 * Enable hw supervised mode for all clockdomains if it's
721 * supported. Initiate sleep transition for other clockdomains, if
722 * they are not used
723 */
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300724static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700725{
726 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
727 omap2_clkdm_allow_idle(clkdm);
728 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
729 atomic_read(&clkdm->usecount) == 0)
730 omap2_clkdm_sleep(clkdm);
731 return 0;
732}
733
Kevin Hilman7cc515f2009-06-10 09:02:25 -0700734static int __init omap3_pm_init(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700735{
736 struct power_state *pwrst, *tmp;
737 int ret;
738
739 if (!cpu_is_omap34xx())
740 return -ENODEV;
741
742 printk(KERN_ERR "Power Management for TI OMAP3.\n");
743
744 /* XXX prcm_setup_regs needs to be before enabling hw
745 * supervised mode for powerdomains */
746 prcm_setup_regs();
747
748 ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
749 (irq_handler_t)prcm_interrupt_handler,
750 IRQF_DISABLED, "prcm", NULL);
751 if (ret) {
752 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
753 INT_34XX_PRCM_MPU_IRQ);
754 goto err1;
755 }
756
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300757 ret = pwrdm_for_each(pwrdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700758 if (ret) {
759 printk(KERN_ERR "Failed to setup powerdomains\n");
760 goto err2;
761 }
762
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300763 (void) clkdm_for_each(clkdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700764
765 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
766 if (mpu_pwrdm == NULL) {
767 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
768 goto err2;
769 }
770
771 _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
772 omap34xx_cpu_suspend_sz);
773
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700774#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -0700775 suspend_set_ops(&omap_pm_ops);
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700776#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700777
778 pm_idle = omap3_pm_idle;
779
780err1:
781 return ret;
782err2:
783 free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
784 list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
785 list_del(&pwrst->node);
786 kfree(pwrst);
787 }
788 return ret;
789}
790
791late_initcall(omap3_pm_init);