blob: 05ee05f012adc00573324b79b272d2008226ec68 [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
Tony Lindgrence491cf2009-10-20 09:40:47 -070026#include <plat/sram.h>
27#include <plat/clockdomain.h>
28#include <plat/powerdomain.h>
29#include <plat/control.h>
30#include <plat/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
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +053052static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
53static struct powerdomain *core_pwrdm, *per_pwrdm;
54
55static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
Kevin Hilman8bd22942009-05-28 10:56:16 -070056
Jon Hunter77da2d92009-06-27 00:07:25 -050057/*
58 * PRCM Interrupt Handler Helper Function
59 *
60 * The purpose of this function is to clear any wake-up events latched
61 * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
62 * may occur whilst attempting to clear a PM_WKST_x register and thus
63 * set another bit in this register. A while loop is used to ensure
64 * that any peripheral wake-up events occurring while attempting to
65 * clear the PM_WKST_x are detected and cleared.
66 */
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070067static int prcm_clear_mod_irqs(s16 module, u8 regs)
Jon Hunter77da2d92009-06-27 00:07:25 -050068{
Vikram Pandita71a80772009-07-17 19:33:09 -050069 u32 wkst, fclk, iclk, clken;
Jon Hunter77da2d92009-06-27 00:07:25 -050070 u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
71 u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
72 u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
Paul Walmsley5d805972009-07-22 10:18:07 -070073 u16 grpsel_off = (regs == 3) ?
74 OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070075 int c = 0;
Jon Hunter77da2d92009-06-27 00:07:25 -050076
77 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley5d805972009-07-22 10:18:07 -070078 wkst &= prm_read_mod_reg(module, grpsel_off);
Jon Hunter77da2d92009-06-27 00:07:25 -050079 if (wkst) {
80 iclk = cm_read_mod_reg(module, iclk_off);
81 fclk = cm_read_mod_reg(module, fclk_off);
82 while (wkst) {
Vikram Pandita71a80772009-07-17 19:33:09 -050083 clken = wkst;
84 cm_set_mod_reg_bits(clken, module, iclk_off);
85 /*
86 * For USBHOST, we don't know whether HOST1 or
87 * HOST2 woke us up, so enable both f-clocks
88 */
89 if (module == OMAP3430ES2_USBHOST_MOD)
90 clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
91 cm_set_mod_reg_bits(clken, module, fclk_off);
Jon Hunter77da2d92009-06-27 00:07:25 -050092 prm_write_mod_reg(wkst, module, wkst_off);
93 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070094 c++;
Jon Hunter77da2d92009-06-27 00:07:25 -050095 }
96 cm_write_mod_reg(iclk, module, iclk_off);
97 cm_write_mod_reg(fclk, module, fclk_off);
98 }
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070099
100 return c;
101}
102
103static int _prcm_int_handle_wakeup(void)
104{
105 int c;
106
107 c = prcm_clear_mod_irqs(WKUP_MOD, 1);
108 c += prcm_clear_mod_irqs(CORE_MOD, 1);
109 c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
110 if (omap_rev() > OMAP3430_REV_ES1_0) {
111 c += prcm_clear_mod_irqs(CORE_MOD, 3);
112 c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
113 }
114
115 return c;
Jon Hunter77da2d92009-06-27 00:07:25 -0500116}
117
118/*
119 * PRCM Interrupt Handler
120 *
121 * The PRM_IRQSTATUS_MPU register indicates if there are any pending
122 * interrupts from the PRCM for the MPU. These bits must be cleared in
123 * order to clear the PRCM interrupt. The PRCM interrupt handler is
124 * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
125 * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
126 * register indicates that a wake-up event is pending for the MPU and
127 * this bit can only be cleared if the all the wake-up events latched
128 * in the various PM_WKST_x registers have been cleared. The interrupt
129 * handler is implemented using a do-while loop so that if a wake-up
130 * event occurred during the processing of the prcm interrupt handler
131 * (setting a bit in the corresponding PM_WKST_x register and thus
132 * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
133 * this would be handled.
134 */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700135static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
136{
Jon Hunter77da2d92009-06-27 00:07:25 -0500137 u32 irqstatus_mpu;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700138 int c = 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700139
Jon Hunter77da2d92009-06-27 00:07:25 -0500140 do {
Jon Hunter77da2d92009-06-27 00:07:25 -0500141 irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
142 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700143
144 if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
145 c = _prcm_int_handle_wakeup();
146
147 /*
148 * Is the MPU PRCM interrupt handler racing with the
149 * IVA2 PRCM interrupt handler ?
150 */
151 WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
152 "but no wakeup sources are marked\n");
153 } else {
154 /* XXX we need to expand our PRCM interrupt handler */
155 WARN(1, "prcm: WARNING: PRCM interrupt received, but "
156 "no code to handle it (%08x)\n", irqstatus_mpu);
157 }
158
Jon Hunter77da2d92009-06-27 00:07:25 -0500159 prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
160 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700161
Jon Hunter77da2d92009-06-27 00:07:25 -0500162 } while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET));
Kevin Hilman8bd22942009-05-28 10:56:16 -0700163
164 return IRQ_HANDLED;
165}
166
167static void omap_sram_idle(void)
168{
169 /* Variable to tell what needs to be saved and restored
170 * in omap_sram_idle*/
171 /* save_state = 0 => Nothing to save and restored */
172 /* save_state = 1 => Only L1 and logic lost */
173 /* save_state = 2 => Only L2 lost */
174 /* save_state = 3 => L1, L2 and logic lost */
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530175 int save_state = 0;
176 int mpu_next_state = PWRDM_POWER_ON;
177 int per_next_state = PWRDM_POWER_ON;
178 int core_next_state = PWRDM_POWER_ON;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700179
180 if (!_omap_sram_idle)
181 return;
182
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530183 pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
184 pwrdm_clear_all_prev_pwrst(neon_pwrdm);
185 pwrdm_clear_all_prev_pwrst(core_pwrdm);
186 pwrdm_clear_all_prev_pwrst(per_pwrdm);
187
Kevin Hilman8bd22942009-05-28 10:56:16 -0700188 mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
189 switch (mpu_next_state) {
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530190 case PWRDM_POWER_ON:
Kevin Hilman8bd22942009-05-28 10:56:16 -0700191 case PWRDM_POWER_RET:
192 /* No need to save context */
193 save_state = 0;
194 break;
195 default:
196 /* Invalid state */
197 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
198 return;
199 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300200 pwrdm_pre_transition();
201
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530202 /* NEON control */
203 if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
204 set_pwrdm_state(neon_pwrdm, mpu_next_state);
205
206 /* CORE & PER */
207 core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
208 if (core_next_state < PWRDM_POWER_ON) {
209 omap2_gpio_prepare_for_retention();
210 omap_uart_prepare_idle(0);
211 omap_uart_prepare_idle(1);
212 /* PER changes only with core */
213 per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
214 if (per_next_state < PWRDM_POWER_ON)
215 omap_uart_prepare_idle(2);
216 /* Enable IO-PAD wakeup */
217 prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
218 }
Kevin Hilman8bd22942009-05-28 10:56:16 -0700219
220 _omap_sram_idle(NULL, save_state);
221 cpu_init();
222
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530223 if (core_next_state < PWRDM_POWER_ON) {
224 if (per_next_state < PWRDM_POWER_ON)
225 omap_uart_resume_idle(2);
226 omap_uart_resume_idle(1);
227 omap_uart_resume_idle(0);
228
229 /* Disable IO-PAD wakeup */
230 prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
231 omap2_gpio_resume_after_retention();
232 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300233
234 pwrdm_post_transition();
235
Kevin Hilman8bd22942009-05-28 10:56:16 -0700236}
237
238/*
239 * Check if functional clocks are enabled before entering
240 * sleep. This function could be behind CONFIG_PM_DEBUG
241 * when all drivers are configuring their sysconfig registers
242 * properly and using their clocks properly.
243 */
244static int omap3_fclks_active(void)
245{
246 u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
247 fck_cam = 0, fck_per = 0, fck_usbhost = 0;
248
249 fck_core1 = cm_read_mod_reg(CORE_MOD,
250 CM_FCLKEN1);
251 if (omap_rev() > OMAP3430_REV_ES1_0) {
252 fck_core3 = cm_read_mod_reg(CORE_MOD,
253 OMAP3430ES2_CM_FCLKEN3);
254 fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
255 CM_FCLKEN);
256 fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
257 CM_FCLKEN);
258 } else
259 fck_sgx = cm_read_mod_reg(GFX_MOD,
260 OMAP3430ES2_CM_FCLKEN3);
261 fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
262 CM_FCLKEN);
263 fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
264 CM_FCLKEN);
265 fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
266 CM_FCLKEN);
Kevin Hilman4af40162009-02-04 10:51:40 -0800267
268 /* Ignore UART clocks. These are handled by UART core (serial.c) */
269 fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
270 fck_per &= ~OMAP3430_EN_UART3;
271
Kevin Hilman8bd22942009-05-28 10:56:16 -0700272 if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
273 fck_cam | fck_per | fck_usbhost)
274 return 1;
275 return 0;
276}
277
278static int omap3_can_sleep(void)
279{
Kevin Hilman4af40162009-02-04 10:51:40 -0800280 if (!omap_uart_can_sleep())
281 return 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700282 if (omap3_fclks_active())
283 return 0;
284 return 1;
285}
286
287/* This sets pwrdm state (other than mpu & core. Currently only ON &
288 * RET are supported. Function is assuming that clkdm doesn't have
289 * hw_sup mode enabled. */
290static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
291{
292 u32 cur_state;
293 int sleep_switch = 0;
294 int ret = 0;
295
296 if (pwrdm == NULL || IS_ERR(pwrdm))
297 return -EINVAL;
298
299 while (!(pwrdm->pwrsts & (1 << state))) {
300 if (state == PWRDM_POWER_OFF)
301 return ret;
302 state--;
303 }
304
305 cur_state = pwrdm_read_next_pwrst(pwrdm);
306 if (cur_state == state)
307 return ret;
308
309 if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
310 omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
311 sleep_switch = 1;
312 pwrdm_wait_transition(pwrdm);
313 }
314
315 ret = pwrdm_set_next_pwrst(pwrdm, state);
316 if (ret) {
317 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
318 pwrdm->name);
319 goto err;
320 }
321
322 if (sleep_switch) {
323 omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
324 pwrdm_wait_transition(pwrdm);
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300325 pwrdm_state_switch(pwrdm);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700326 }
327
328err:
329 return ret;
330}
331
332static void omap3_pm_idle(void)
333{
334 local_irq_disable();
335 local_fiq_disable();
336
337 if (!omap3_can_sleep())
338 goto out;
339
340 if (omap_irq_pending())
341 goto out;
342
343 omap_sram_idle();
344
345out:
346 local_fiq_enable();
347 local_irq_enable();
348}
349
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700350#ifdef CONFIG_SUSPEND
Tero Kristo24662112009-03-05 16:32:23 +0200351static suspend_state_t suspend_state;
352
Kevin Hilman8bd22942009-05-28 10:56:16 -0700353static int omap3_pm_prepare(void)
354{
355 disable_hlt();
356 return 0;
357}
358
359static int omap3_pm_suspend(void)
360{
361 struct power_state *pwrst;
362 int state, ret = 0;
363
364 /* Read current next_pwrsts */
365 list_for_each_entry(pwrst, &pwrst_list, node)
366 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
367 /* Set ones wanted by suspend */
368 list_for_each_entry(pwrst, &pwrst_list, node) {
369 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
370 goto restore;
371 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
372 goto restore;
373 }
374
Kevin Hilman4af40162009-02-04 10:51:40 -0800375 omap_uart_prepare_suspend();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700376 omap_sram_idle();
377
378restore:
379 /* Restore next_pwrsts */
380 list_for_each_entry(pwrst, &pwrst_list, node) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700381 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
382 if (state > pwrst->next_state) {
383 printk(KERN_INFO "Powerdomain (%s) didn't enter "
384 "target state %d\n",
385 pwrst->pwrdm->name, pwrst->next_state);
386 ret = -1;
387 }
Jouni Hogander6c5f8032008-10-29 12:06:04 +0200388 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700389 }
390 if (ret)
391 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
392 else
393 printk(KERN_INFO "Successfully put all powerdomains "
394 "to target state\n");
395
396 return ret;
397}
398
Tero Kristo24662112009-03-05 16:32:23 +0200399static int omap3_pm_enter(suspend_state_t unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700400{
401 int ret = 0;
402
Tero Kristo24662112009-03-05 16:32:23 +0200403 switch (suspend_state) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700404 case PM_SUSPEND_STANDBY:
405 case PM_SUSPEND_MEM:
406 ret = omap3_pm_suspend();
407 break;
408 default:
409 ret = -EINVAL;
410 }
411
412 return ret;
413}
414
415static void omap3_pm_finish(void)
416{
417 enable_hlt();
418}
419
Tero Kristo24662112009-03-05 16:32:23 +0200420/* Hooks to enable / disable UART interrupts during suspend */
421static int omap3_pm_begin(suspend_state_t state)
422{
423 suspend_state = state;
424 omap_uart_enable_irqs(0);
425 return 0;
426}
427
428static void omap3_pm_end(void)
429{
430 suspend_state = PM_SUSPEND_ON;
431 omap_uart_enable_irqs(1);
432 return;
433}
434
Kevin Hilman8bd22942009-05-28 10:56:16 -0700435static struct platform_suspend_ops omap_pm_ops = {
Tero Kristo24662112009-03-05 16:32:23 +0200436 .begin = omap3_pm_begin,
437 .end = omap3_pm_end,
Kevin Hilman8bd22942009-05-28 10:56:16 -0700438 .prepare = omap3_pm_prepare,
439 .enter = omap3_pm_enter,
440 .finish = omap3_pm_finish,
441 .valid = suspend_valid_only_mem,
442};
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700443#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700444
Kevin Hilman1155e422008-11-25 11:48:24 -0800445
446/**
447 * omap3_iva_idle(): ensure IVA is in idle so it can be put into
448 * retention
449 *
450 * In cases where IVA2 is activated by bootcode, it may prevent
451 * full-chip retention or off-mode because it is not idle. This
452 * function forces the IVA2 into idle state so it can go
453 * into retention/off and thus allow full-chip retention/off.
454 *
455 **/
456static void __init omap3_iva_idle(void)
457{
458 /* ensure IVA2 clock is disabled */
459 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
460
461 /* if no clock activity, nothing else to do */
462 if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
463 OMAP3430_CLKACTIVITY_IVA2_MASK))
464 return;
465
466 /* Reset IVA2 */
467 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
468 OMAP3430_RST2_IVA2 |
469 OMAP3430_RST3_IVA2,
470 OMAP3430_IVA2_MOD, RM_RSTCTRL);
471
472 /* Enable IVA2 clock */
473 cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
474 OMAP3430_IVA2_MOD, CM_FCLKEN);
475
476 /* Set IVA2 boot mode to 'idle' */
477 omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
478 OMAP343X_CONTROL_IVA2_BOOTMOD);
479
480 /* Un-reset IVA2 */
481 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
482
483 /* Disable IVA2 clock */
484 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
485
486 /* Reset IVA2 */
487 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
488 OMAP3430_RST2_IVA2 |
489 OMAP3430_RST3_IVA2,
490 OMAP3430_IVA2_MOD, RM_RSTCTRL);
491}
492
Kevin Hilman8111b222009-04-28 15:27:44 -0700493static void __init omap3_d2d_idle(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700494{
Kevin Hilman8111b222009-04-28 15:27:44 -0700495 u16 mask, padconf;
496
497 /* In a stand alone OMAP3430 where there is not a stacked
498 * modem for the D2D Idle Ack and D2D MStandby must be pulled
499 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
500 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
501 mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
502 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
503 padconf |= mask;
504 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
505
506 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
507 padconf |= mask;
508 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
509
Kevin Hilman8bd22942009-05-28 10:56:16 -0700510 /* reset modem */
511 prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
512 OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
513 CORE_MOD, RM_RSTCTRL);
514 prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
Kevin Hilman8111b222009-04-28 15:27:44 -0700515}
Kevin Hilman8bd22942009-05-28 10:56:16 -0700516
Kevin Hilman8111b222009-04-28 15:27:44 -0700517static void __init prcm_setup_regs(void)
518{
Kevin Hilman8bd22942009-05-28 10:56:16 -0700519 /* XXX Reset all wkdeps. This should be done when initializing
520 * powerdomains */
521 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
522 prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
523 prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
524 prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
525 prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
526 prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
527 if (omap_rev() > OMAP3430_REV_ES1_0) {
528 prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
529 prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
530 } else
531 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
532
533 /*
534 * Enable interface clock autoidle for all modules.
535 * Note that in the long run this should be done by clockfw
536 */
537 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700538 OMAP3430_AUTO_MODEM |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700539 OMAP3430ES2_AUTO_MMC3 |
540 OMAP3430ES2_AUTO_ICR |
541 OMAP3430_AUTO_AES2 |
542 OMAP3430_AUTO_SHA12 |
543 OMAP3430_AUTO_DES2 |
544 OMAP3430_AUTO_MMC2 |
545 OMAP3430_AUTO_MMC1 |
546 OMAP3430_AUTO_MSPRO |
547 OMAP3430_AUTO_HDQ |
548 OMAP3430_AUTO_MCSPI4 |
549 OMAP3430_AUTO_MCSPI3 |
550 OMAP3430_AUTO_MCSPI2 |
551 OMAP3430_AUTO_MCSPI1 |
552 OMAP3430_AUTO_I2C3 |
553 OMAP3430_AUTO_I2C2 |
554 OMAP3430_AUTO_I2C1 |
555 OMAP3430_AUTO_UART2 |
556 OMAP3430_AUTO_UART1 |
557 OMAP3430_AUTO_GPT11 |
558 OMAP3430_AUTO_GPT10 |
559 OMAP3430_AUTO_MCBSP5 |
560 OMAP3430_AUTO_MCBSP1 |
561 OMAP3430ES1_AUTO_FAC | /* This is es1 only */
562 OMAP3430_AUTO_MAILBOXES |
563 OMAP3430_AUTO_OMAPCTRL |
564 OMAP3430ES1_AUTO_FSHOSTUSB |
565 OMAP3430_AUTO_HSOTGUSB |
Kevin Hilman8111b222009-04-28 15:27:44 -0700566 OMAP3430_AUTO_SAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700567 OMAP3430_AUTO_SSI,
568 CORE_MOD, CM_AUTOIDLE1);
569
570 cm_write_mod_reg(
571 OMAP3430_AUTO_PKA |
572 OMAP3430_AUTO_AES1 |
573 OMAP3430_AUTO_RNG |
574 OMAP3430_AUTO_SHA11 |
575 OMAP3430_AUTO_DES1,
576 CORE_MOD, CM_AUTOIDLE2);
577
578 if (omap_rev() > OMAP3430_REV_ES1_0) {
579 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700580 OMAP3430_AUTO_MAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700581 OMAP3430ES2_AUTO_USBTLL,
582 CORE_MOD, CM_AUTOIDLE3);
583 }
584
585 cm_write_mod_reg(
586 OMAP3430_AUTO_WDT2 |
587 OMAP3430_AUTO_WDT1 |
588 OMAP3430_AUTO_GPIO1 |
589 OMAP3430_AUTO_32KSYNC |
590 OMAP3430_AUTO_GPT12 |
591 OMAP3430_AUTO_GPT1 ,
592 WKUP_MOD, CM_AUTOIDLE);
593
594 cm_write_mod_reg(
595 OMAP3430_AUTO_DSS,
596 OMAP3430_DSS_MOD,
597 CM_AUTOIDLE);
598
599 cm_write_mod_reg(
600 OMAP3430_AUTO_CAM,
601 OMAP3430_CAM_MOD,
602 CM_AUTOIDLE);
603
604 cm_write_mod_reg(
605 OMAP3430_AUTO_GPIO6 |
606 OMAP3430_AUTO_GPIO5 |
607 OMAP3430_AUTO_GPIO4 |
608 OMAP3430_AUTO_GPIO3 |
609 OMAP3430_AUTO_GPIO2 |
610 OMAP3430_AUTO_WDT3 |
611 OMAP3430_AUTO_UART3 |
612 OMAP3430_AUTO_GPT9 |
613 OMAP3430_AUTO_GPT8 |
614 OMAP3430_AUTO_GPT7 |
615 OMAP3430_AUTO_GPT6 |
616 OMAP3430_AUTO_GPT5 |
617 OMAP3430_AUTO_GPT4 |
618 OMAP3430_AUTO_GPT3 |
619 OMAP3430_AUTO_GPT2 |
620 OMAP3430_AUTO_MCBSP4 |
621 OMAP3430_AUTO_MCBSP3 |
622 OMAP3430_AUTO_MCBSP2,
623 OMAP3430_PER_MOD,
624 CM_AUTOIDLE);
625
626 if (omap_rev() > OMAP3430_REV_ES1_0) {
627 cm_write_mod_reg(
628 OMAP3430ES2_AUTO_USBHOST,
629 OMAP3430ES2_USBHOST_MOD,
630 CM_AUTOIDLE);
631 }
632
633 /*
634 * Set all plls to autoidle. This is needed until autoidle is
635 * enabled by clockfw
636 */
637 cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
638 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
639 cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
640 MPU_MOD,
641 CM_AUTOIDLE2);
642 cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
643 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
644 PLL_MOD,
645 CM_AUTOIDLE);
646 cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
647 PLL_MOD,
648 CM_AUTOIDLE2);
649
650 /*
651 * Enable control of expternal oscillator through
652 * sys_clkreq. In the long run clock framework should
653 * take care of this.
654 */
655 prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
656 1 << OMAP_AUTOEXTCLKMODE_SHIFT,
657 OMAP3430_GR_MOD,
658 OMAP3_PRM_CLKSRC_CTRL_OFFSET);
659
660 /* setup wakup source */
661 prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
662 OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
663 WKUP_MOD, PM_WKEN);
664 /* No need to write EN_IO, that is always enabled */
665 prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
666 OMAP3430_EN_GPT12,
667 WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
668 /* For some reason IO doesn't generate wakeup event even if
669 * it is selected to mpu wakeup goup */
670 prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
671 OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
Kevin Hilman1155e422008-11-25 11:48:24 -0800672
Kevin Hilmanb427f922009-10-22 14:48:13 -0700673 /* Enable wakeups in PER */
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000674 prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 |
675 OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 |
Kevin Hilmanb427f922009-10-22 14:48:13 -0700676 OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3,
677 OMAP3430_PER_MOD, PM_WKEN);
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000678 /* and allow them to wake up MPU */
679 prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 |
680 OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 |
Kevin Hilmanb427f922009-10-22 14:48:13 -0700681 OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3,
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000682 OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
683
Kevin Hilmand3fd3292009-05-05 16:34:25 -0700684 /* Don't attach IVA interrupts */
685 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
686 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
687 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
688 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
689
Kevin Hilmanb1340d12009-04-27 16:14:54 -0700690 /* Clear any pending 'reset' flags */
691 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
692 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
693 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
694 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
695 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
696 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
697 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
698
Kevin Hilman014c46d2009-04-27 07:50:23 -0700699 /* Clear any pending PRCM interrupts */
700 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
701
Kevin Hilman040fed02009-05-05 16:34:25 -0700702 /* Don't attach IVA interrupts */
703 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
704 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
705 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
706 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
707
Kevin Hilman3a07ae32009-04-27 16:14:54 -0700708 /* Clear any pending 'reset' flags */
709 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
710 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
711 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
712 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
713 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
714 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
715 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
716
Kevin Hilman3a6667a2009-04-27 07:50:23 -0700717 /* Clear any pending PRCM interrupts */
718 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
719
Kevin Hilman1155e422008-11-25 11:48:24 -0800720 omap3_iva_idle();
Kevin Hilman8111b222009-04-28 15:27:44 -0700721 omap3_d2d_idle();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700722}
723
Tero Kristo68d47782008-11-26 12:26:24 +0200724int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
725{
726 struct power_state *pwrst;
727
728 list_for_each_entry(pwrst, &pwrst_list, node) {
729 if (pwrst->pwrdm == pwrdm)
730 return pwrst->next_state;
731 }
732 return -EINVAL;
733}
734
735int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state)
736{
737 struct power_state *pwrst;
738
739 list_for_each_entry(pwrst, &pwrst_list, node) {
740 if (pwrst->pwrdm == pwrdm) {
741 pwrst->next_state = state;
742 return 0;
743 }
744 }
745 return -EINVAL;
746}
747
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300748static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700749{
750 struct power_state *pwrst;
751
752 if (!pwrdm->pwrsts)
753 return 0;
754
Ming Leid3d381c2009-08-22 21:20:26 +0800755 pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700756 if (!pwrst)
757 return -ENOMEM;
758 pwrst->pwrdm = pwrdm;
759 pwrst->next_state = PWRDM_POWER_RET;
760 list_add(&pwrst->node, &pwrst_list);
761
762 if (pwrdm_has_hdwr_sar(pwrdm))
763 pwrdm_enable_hdwr_sar(pwrdm);
764
765 return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
766}
767
768/*
769 * Enable hw supervised mode for all clockdomains if it's
770 * supported. Initiate sleep transition for other clockdomains, if
771 * they are not used
772 */
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300773static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700774{
775 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
776 omap2_clkdm_allow_idle(clkdm);
777 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
778 atomic_read(&clkdm->usecount) == 0)
779 omap2_clkdm_sleep(clkdm);
780 return 0;
781}
782
Rajendra Nayak3231fc82008-09-26 17:49:14 +0530783void omap_push_sram_idle(void)
784{
785 _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
786 omap34xx_cpu_suspend_sz);
787}
788
Kevin Hilman7cc515f2009-06-10 09:02:25 -0700789static int __init omap3_pm_init(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700790{
791 struct power_state *pwrst, *tmp;
792 int ret;
793
794 if (!cpu_is_omap34xx())
795 return -ENODEV;
796
797 printk(KERN_ERR "Power Management for TI OMAP3.\n");
798
799 /* XXX prcm_setup_regs needs to be before enabling hw
800 * supervised mode for powerdomains */
801 prcm_setup_regs();
802
803 ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
804 (irq_handler_t)prcm_interrupt_handler,
805 IRQF_DISABLED, "prcm", NULL);
806 if (ret) {
807 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
808 INT_34XX_PRCM_MPU_IRQ);
809 goto err1;
810 }
811
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300812 ret = pwrdm_for_each(pwrdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700813 if (ret) {
814 printk(KERN_ERR "Failed to setup powerdomains\n");
815 goto err2;
816 }
817
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300818 (void) clkdm_for_each(clkdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700819
820 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
821 if (mpu_pwrdm == NULL) {
822 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
823 goto err2;
824 }
825
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530826 neon_pwrdm = pwrdm_lookup("neon_pwrdm");
827 per_pwrdm = pwrdm_lookup("per_pwrdm");
828 core_pwrdm = pwrdm_lookup("core_pwrdm");
829
Rajendra Nayak3231fc82008-09-26 17:49:14 +0530830 omap_push_sram_idle();
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700831#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -0700832 suspend_set_ops(&omap_pm_ops);
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700833#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700834
835 pm_idle = omap3_pm_idle;
836
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530837 pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm);
838 /*
839 * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for
840 * IO-pad wakeup. Otherwise it will unnecessarily waste power
841 * waking up PER with every CORE wakeup - see
842 * http://marc.info/?l=linux-omap&m=121852150710062&w=2
843 */
844 pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
845
Kevin Hilman8bd22942009-05-28 10:56:16 -0700846err1:
847 return ret;
848err2:
849 free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
850 list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
851 list_del(&pwrst->node);
852 kfree(pwrst);
853 }
854 return ret;
855}
856
857late_initcall(omap3_pm_init);