blob: 8b5bf91dc070ea89e84895e4e3e32700175fbd9e [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
Rajendra Nayak57f277b2008-09-26 17:49:34 +053032#include <asm/tlbflush.h>
33
Kevin Hilman8bd22942009-05-28 10:56:16 -070034#include "cm.h"
35#include "cm-regbits-34xx.h"
36#include "prm-regbits-34xx.h"
37
38#include "prm.h"
39#include "pm.h"
40
41struct power_state {
42 struct powerdomain *pwrdm;
43 u32 next_state;
Kevin Hilman10f90ed2009-06-24 11:39:18 -070044#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -070045 u32 saved_state;
Kevin Hilman10f90ed2009-06-24 11:39:18 -070046#endif
Kevin Hilman8bd22942009-05-28 10:56:16 -070047 struct list_head node;
48};
49
50static LIST_HEAD(pwrst_list);
51
52static void (*_omap_sram_idle)(u32 *addr, int save_state);
53
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +053054static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
55static struct powerdomain *core_pwrdm, *per_pwrdm;
56
57static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
Kevin Hilman8bd22942009-05-28 10:56:16 -070058
Jon Hunter77da2d92009-06-27 00:07:25 -050059/*
60 * PRCM Interrupt Handler Helper Function
61 *
62 * The purpose of this function is to clear any wake-up events latched
63 * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
64 * may occur whilst attempting to clear a PM_WKST_x register and thus
65 * set another bit in this register. A while loop is used to ensure
66 * that any peripheral wake-up events occurring while attempting to
67 * clear the PM_WKST_x are detected and cleared.
68 */
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070069static int prcm_clear_mod_irqs(s16 module, u8 regs)
Jon Hunter77da2d92009-06-27 00:07:25 -050070{
Vikram Pandita71a80772009-07-17 19:33:09 -050071 u32 wkst, fclk, iclk, clken;
Jon Hunter77da2d92009-06-27 00:07:25 -050072 u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
73 u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
74 u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
Paul Walmsley5d805972009-07-22 10:18:07 -070075 u16 grpsel_off = (regs == 3) ?
76 OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070077 int c = 0;
Jon Hunter77da2d92009-06-27 00:07:25 -050078
79 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley5d805972009-07-22 10:18:07 -070080 wkst &= prm_read_mod_reg(module, grpsel_off);
Jon Hunter77da2d92009-06-27 00:07:25 -050081 if (wkst) {
82 iclk = cm_read_mod_reg(module, iclk_off);
83 fclk = cm_read_mod_reg(module, fclk_off);
84 while (wkst) {
Vikram Pandita71a80772009-07-17 19:33:09 -050085 clken = wkst;
86 cm_set_mod_reg_bits(clken, module, iclk_off);
87 /*
88 * For USBHOST, we don't know whether HOST1 or
89 * HOST2 woke us up, so enable both f-clocks
90 */
91 if (module == OMAP3430ES2_USBHOST_MOD)
92 clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
93 cm_set_mod_reg_bits(clken, module, fclk_off);
Jon Hunter77da2d92009-06-27 00:07:25 -050094 prm_write_mod_reg(wkst, module, wkst_off);
95 wkst = prm_read_mod_reg(module, wkst_off);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -070096 c++;
Jon Hunter77da2d92009-06-27 00:07:25 -050097 }
98 cm_write_mod_reg(iclk, module, iclk_off);
99 cm_write_mod_reg(fclk, module, fclk_off);
100 }
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700101
102 return c;
103}
104
105static int _prcm_int_handle_wakeup(void)
106{
107 int c;
108
109 c = prcm_clear_mod_irqs(WKUP_MOD, 1);
110 c += prcm_clear_mod_irqs(CORE_MOD, 1);
111 c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
112 if (omap_rev() > OMAP3430_REV_ES1_0) {
113 c += prcm_clear_mod_irqs(CORE_MOD, 3);
114 c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
115 }
116
117 return c;
Jon Hunter77da2d92009-06-27 00:07:25 -0500118}
119
120/*
121 * PRCM Interrupt Handler
122 *
123 * The PRM_IRQSTATUS_MPU register indicates if there are any pending
124 * interrupts from the PRCM for the MPU. These bits must be cleared in
125 * order to clear the PRCM interrupt. The PRCM interrupt handler is
126 * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
127 * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
128 * register indicates that a wake-up event is pending for the MPU and
129 * this bit can only be cleared if the all the wake-up events latched
130 * in the various PM_WKST_x registers have been cleared. The interrupt
131 * handler is implemented using a do-while loop so that if a wake-up
132 * event occurred during the processing of the prcm interrupt handler
133 * (setting a bit in the corresponding PM_WKST_x register and thus
134 * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
135 * this would be handled.
136 */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700137static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
138{
Jon Hunter77da2d92009-06-27 00:07:25 -0500139 u32 irqstatus_mpu;
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700140 int c = 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700141
Jon Hunter77da2d92009-06-27 00:07:25 -0500142 do {
Jon Hunter77da2d92009-06-27 00:07:25 -0500143 irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
144 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Paul Walmsley8cb0ac92009-07-22 10:29:02 -0700145
146 if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
147 c = _prcm_int_handle_wakeup();
148
149 /*
150 * Is the MPU PRCM interrupt handler racing with the
151 * IVA2 PRCM interrupt handler ?
152 */
153 WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
154 "but no wakeup sources are marked\n");
155 } else {
156 /* XXX we need to expand our PRCM interrupt handler */
157 WARN(1, "prcm: WARNING: PRCM interrupt received, but "
158 "no code to handle it (%08x)\n", irqstatus_mpu);
159 }
160
Jon Hunter77da2d92009-06-27 00:07:25 -0500161 prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
162 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700163
Jon Hunter77da2d92009-06-27 00:07:25 -0500164 } while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET));
Kevin Hilman8bd22942009-05-28 10:56:16 -0700165
166 return IRQ_HANDLED;
167}
168
Rajendra Nayak57f277b2008-09-26 17:49:34 +0530169static void restore_control_register(u32 val)
170{
171 __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val));
172}
173
174/* Function to restore the table entry that was modified for enabling MMU */
175static void restore_table_entry(void)
176{
177 u32 *scratchpad_address;
178 u32 previous_value, control_reg_value;
179 u32 *address;
180
181 scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD);
182
183 /* Get address of entry that was modified */
184 address = (u32 *)__raw_readl(scratchpad_address +
185 OMAP343X_TABLE_ADDRESS_OFFSET);
186 /* Get the previous value which needs to be restored */
187 previous_value = __raw_readl(scratchpad_address +
188 OMAP343X_TABLE_VALUE_OFFSET);
189 address = __va(address);
190 *address = previous_value;
191 flush_tlb_all();
192 control_reg_value = __raw_readl(scratchpad_address
193 + OMAP343X_CONTROL_REG_VALUE_OFFSET);
194 /* This will enable caches and prediction */
195 restore_control_register(control_reg_value);
196}
197
Kevin Hilman8bd22942009-05-28 10:56:16 -0700198static void omap_sram_idle(void)
199{
200 /* Variable to tell what needs to be saved and restored
201 * in omap_sram_idle*/
202 /* save_state = 0 => Nothing to save and restored */
203 /* save_state = 1 => Only L1 and logic lost */
204 /* save_state = 2 => Only L2 lost */
205 /* save_state = 3 => L1, L2 and logic lost */
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530206 int save_state = 0;
207 int mpu_next_state = PWRDM_POWER_ON;
208 int per_next_state = PWRDM_POWER_ON;
209 int core_next_state = PWRDM_POWER_ON;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700210
211 if (!_omap_sram_idle)
212 return;
213
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530214 pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
215 pwrdm_clear_all_prev_pwrst(neon_pwrdm);
216 pwrdm_clear_all_prev_pwrst(core_pwrdm);
217 pwrdm_clear_all_prev_pwrst(per_pwrdm);
218
Kevin Hilman8bd22942009-05-28 10:56:16 -0700219 mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
220 switch (mpu_next_state) {
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530221 case PWRDM_POWER_ON:
Kevin Hilman8bd22942009-05-28 10:56:16 -0700222 case PWRDM_POWER_RET:
223 /* No need to save context */
224 save_state = 0;
225 break;
226 default:
227 /* Invalid state */
228 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
229 return;
230 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300231 pwrdm_pre_transition();
232
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530233 /* NEON control */
234 if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
235 set_pwrdm_state(neon_pwrdm, mpu_next_state);
236
237 /* CORE & PER */
238 core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
239 if (core_next_state < PWRDM_POWER_ON) {
240 omap2_gpio_prepare_for_retention();
241 omap_uart_prepare_idle(0);
242 omap_uart_prepare_idle(1);
243 /* PER changes only with core */
244 per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
245 if (per_next_state < PWRDM_POWER_ON)
246 omap_uart_prepare_idle(2);
247 /* Enable IO-PAD wakeup */
248 prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
249 }
Kevin Hilman8bd22942009-05-28 10:56:16 -0700250
251 _omap_sram_idle(NULL, save_state);
252 cpu_init();
253
Rajendra Nayak57f277b2008-09-26 17:49:34 +0530254 /* Restore table entry modified during MMU restoration */
255 if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF)
256 restore_table_entry();
257
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530258 if (core_next_state < PWRDM_POWER_ON) {
259 if (per_next_state < PWRDM_POWER_ON)
260 omap_uart_resume_idle(2);
261 omap_uart_resume_idle(1);
262 omap_uart_resume_idle(0);
263
264 /* Disable IO-PAD wakeup */
265 prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
266 omap2_gpio_resume_after_retention();
267 }
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300268
269 pwrdm_post_transition();
270
Kevin Hilman8bd22942009-05-28 10:56:16 -0700271}
272
273/*
274 * Check if functional clocks are enabled before entering
275 * sleep. This function could be behind CONFIG_PM_DEBUG
276 * when all drivers are configuring their sysconfig registers
277 * properly and using their clocks properly.
278 */
279static int omap3_fclks_active(void)
280{
281 u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
282 fck_cam = 0, fck_per = 0, fck_usbhost = 0;
283
284 fck_core1 = cm_read_mod_reg(CORE_MOD,
285 CM_FCLKEN1);
286 if (omap_rev() > OMAP3430_REV_ES1_0) {
287 fck_core3 = cm_read_mod_reg(CORE_MOD,
288 OMAP3430ES2_CM_FCLKEN3);
289 fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
290 CM_FCLKEN);
291 fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
292 CM_FCLKEN);
293 } else
294 fck_sgx = cm_read_mod_reg(GFX_MOD,
295 OMAP3430ES2_CM_FCLKEN3);
296 fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
297 CM_FCLKEN);
298 fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
299 CM_FCLKEN);
300 fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
301 CM_FCLKEN);
Kevin Hilman4af40162009-02-04 10:51:40 -0800302
303 /* Ignore UART clocks. These are handled by UART core (serial.c) */
304 fck_core1 &= ~(OMAP3430_EN_UART1 | OMAP3430_EN_UART2);
305 fck_per &= ~OMAP3430_EN_UART3;
306
Kevin Hilman8bd22942009-05-28 10:56:16 -0700307 if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
308 fck_cam | fck_per | fck_usbhost)
309 return 1;
310 return 0;
311}
312
313static int omap3_can_sleep(void)
314{
Kevin Hilman4af40162009-02-04 10:51:40 -0800315 if (!omap_uart_can_sleep())
316 return 0;
Kevin Hilman8bd22942009-05-28 10:56:16 -0700317 if (omap3_fclks_active())
318 return 0;
319 return 1;
320}
321
322/* This sets pwrdm state (other than mpu & core. Currently only ON &
323 * RET are supported. Function is assuming that clkdm doesn't have
324 * hw_sup mode enabled. */
325static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
326{
327 u32 cur_state;
328 int sleep_switch = 0;
329 int ret = 0;
330
331 if (pwrdm == NULL || IS_ERR(pwrdm))
332 return -EINVAL;
333
334 while (!(pwrdm->pwrsts & (1 << state))) {
335 if (state == PWRDM_POWER_OFF)
336 return ret;
337 state--;
338 }
339
340 cur_state = pwrdm_read_next_pwrst(pwrdm);
341 if (cur_state == state)
342 return ret;
343
344 if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
345 omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
346 sleep_switch = 1;
347 pwrdm_wait_transition(pwrdm);
348 }
349
350 ret = pwrdm_set_next_pwrst(pwrdm, state);
351 if (ret) {
352 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
353 pwrdm->name);
354 goto err;
355 }
356
357 if (sleep_switch) {
358 omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
359 pwrdm_wait_transition(pwrdm);
Peter 'p2' De Schrijverfe617af2008-10-15 17:48:44 +0300360 pwrdm_state_switch(pwrdm);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700361 }
362
363err:
364 return ret;
365}
366
367static void omap3_pm_idle(void)
368{
369 local_irq_disable();
370 local_fiq_disable();
371
372 if (!omap3_can_sleep())
373 goto out;
374
375 if (omap_irq_pending())
376 goto out;
377
378 omap_sram_idle();
379
380out:
381 local_fiq_enable();
382 local_irq_enable();
383}
384
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700385#ifdef CONFIG_SUSPEND
Tero Kristo24662112009-03-05 16:32:23 +0200386static suspend_state_t suspend_state;
387
Kevin Hilman8bd22942009-05-28 10:56:16 -0700388static int omap3_pm_prepare(void)
389{
390 disable_hlt();
391 return 0;
392}
393
394static int omap3_pm_suspend(void)
395{
396 struct power_state *pwrst;
397 int state, ret = 0;
398
399 /* Read current next_pwrsts */
400 list_for_each_entry(pwrst, &pwrst_list, node)
401 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
402 /* Set ones wanted by suspend */
403 list_for_each_entry(pwrst, &pwrst_list, node) {
404 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
405 goto restore;
406 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
407 goto restore;
408 }
409
Kevin Hilman4af40162009-02-04 10:51:40 -0800410 omap_uart_prepare_suspend();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700411 omap_sram_idle();
412
413restore:
414 /* Restore next_pwrsts */
415 list_for_each_entry(pwrst, &pwrst_list, node) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700416 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
417 if (state > pwrst->next_state) {
418 printk(KERN_INFO "Powerdomain (%s) didn't enter "
419 "target state %d\n",
420 pwrst->pwrdm->name, pwrst->next_state);
421 ret = -1;
422 }
Jouni Hogander6c5f8032008-10-29 12:06:04 +0200423 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700424 }
425 if (ret)
426 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
427 else
428 printk(KERN_INFO "Successfully put all powerdomains "
429 "to target state\n");
430
431 return ret;
432}
433
Tero Kristo24662112009-03-05 16:32:23 +0200434static int omap3_pm_enter(suspend_state_t unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700435{
436 int ret = 0;
437
Tero Kristo24662112009-03-05 16:32:23 +0200438 switch (suspend_state) {
Kevin Hilman8bd22942009-05-28 10:56:16 -0700439 case PM_SUSPEND_STANDBY:
440 case PM_SUSPEND_MEM:
441 ret = omap3_pm_suspend();
442 break;
443 default:
444 ret = -EINVAL;
445 }
446
447 return ret;
448}
449
450static void omap3_pm_finish(void)
451{
452 enable_hlt();
453}
454
Tero Kristo24662112009-03-05 16:32:23 +0200455/* Hooks to enable / disable UART interrupts during suspend */
456static int omap3_pm_begin(suspend_state_t state)
457{
458 suspend_state = state;
459 omap_uart_enable_irqs(0);
460 return 0;
461}
462
463static void omap3_pm_end(void)
464{
465 suspend_state = PM_SUSPEND_ON;
466 omap_uart_enable_irqs(1);
467 return;
468}
469
Kevin Hilman8bd22942009-05-28 10:56:16 -0700470static struct platform_suspend_ops omap_pm_ops = {
Tero Kristo24662112009-03-05 16:32:23 +0200471 .begin = omap3_pm_begin,
472 .end = omap3_pm_end,
Kevin Hilman8bd22942009-05-28 10:56:16 -0700473 .prepare = omap3_pm_prepare,
474 .enter = omap3_pm_enter,
475 .finish = omap3_pm_finish,
476 .valid = suspend_valid_only_mem,
477};
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700478#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700479
Kevin Hilman1155e422008-11-25 11:48:24 -0800480
481/**
482 * omap3_iva_idle(): ensure IVA is in idle so it can be put into
483 * retention
484 *
485 * In cases where IVA2 is activated by bootcode, it may prevent
486 * full-chip retention or off-mode because it is not idle. This
487 * function forces the IVA2 into idle state so it can go
488 * into retention/off and thus allow full-chip retention/off.
489 *
490 **/
491static void __init omap3_iva_idle(void)
492{
493 /* ensure IVA2 clock is disabled */
494 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
495
496 /* if no clock activity, nothing else to do */
497 if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) &
498 OMAP3430_CLKACTIVITY_IVA2_MASK))
499 return;
500
501 /* Reset IVA2 */
502 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
503 OMAP3430_RST2_IVA2 |
504 OMAP3430_RST3_IVA2,
505 OMAP3430_IVA2_MOD, RM_RSTCTRL);
506
507 /* Enable IVA2 clock */
508 cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2,
509 OMAP3430_IVA2_MOD, CM_FCLKEN);
510
511 /* Set IVA2 boot mode to 'idle' */
512 omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE,
513 OMAP343X_CONTROL_IVA2_BOOTMOD);
514
515 /* Un-reset IVA2 */
516 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, RM_RSTCTRL);
517
518 /* Disable IVA2 clock */
519 cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN);
520
521 /* Reset IVA2 */
522 prm_write_mod_reg(OMAP3430_RST1_IVA2 |
523 OMAP3430_RST2_IVA2 |
524 OMAP3430_RST3_IVA2,
525 OMAP3430_IVA2_MOD, RM_RSTCTRL);
526}
527
Kevin Hilman8111b222009-04-28 15:27:44 -0700528static void __init omap3_d2d_idle(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700529{
Kevin Hilman8111b222009-04-28 15:27:44 -0700530 u16 mask, padconf;
531
532 /* In a stand alone OMAP3430 where there is not a stacked
533 * modem for the D2D Idle Ack and D2D MStandby must be pulled
534 * high. S CONTROL_PADCONF_SAD2D_IDLEACK and
535 * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */
536 mask = (1 << 4) | (1 << 3); /* pull-up, enabled */
537 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY);
538 padconf |= mask;
539 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY);
540
541 padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK);
542 padconf |= mask;
543 omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK);
544
Kevin Hilman8bd22942009-05-28 10:56:16 -0700545 /* reset modem */
546 prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
547 OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
548 CORE_MOD, RM_RSTCTRL);
549 prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
Kevin Hilman8111b222009-04-28 15:27:44 -0700550}
Kevin Hilman8bd22942009-05-28 10:56:16 -0700551
Kevin Hilman8111b222009-04-28 15:27:44 -0700552static void __init prcm_setup_regs(void)
553{
Kevin Hilman8bd22942009-05-28 10:56:16 -0700554 /* XXX Reset all wkdeps. This should be done when initializing
555 * powerdomains */
556 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
557 prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
558 prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
559 prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
560 prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
561 prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
562 if (omap_rev() > OMAP3430_REV_ES1_0) {
563 prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
564 prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
565 } else
566 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
567
568 /*
569 * Enable interface clock autoidle for all modules.
570 * Note that in the long run this should be done by clockfw
571 */
572 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700573 OMAP3430_AUTO_MODEM |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700574 OMAP3430ES2_AUTO_MMC3 |
575 OMAP3430ES2_AUTO_ICR |
576 OMAP3430_AUTO_AES2 |
577 OMAP3430_AUTO_SHA12 |
578 OMAP3430_AUTO_DES2 |
579 OMAP3430_AUTO_MMC2 |
580 OMAP3430_AUTO_MMC1 |
581 OMAP3430_AUTO_MSPRO |
582 OMAP3430_AUTO_HDQ |
583 OMAP3430_AUTO_MCSPI4 |
584 OMAP3430_AUTO_MCSPI3 |
585 OMAP3430_AUTO_MCSPI2 |
586 OMAP3430_AUTO_MCSPI1 |
587 OMAP3430_AUTO_I2C3 |
588 OMAP3430_AUTO_I2C2 |
589 OMAP3430_AUTO_I2C1 |
590 OMAP3430_AUTO_UART2 |
591 OMAP3430_AUTO_UART1 |
592 OMAP3430_AUTO_GPT11 |
593 OMAP3430_AUTO_GPT10 |
594 OMAP3430_AUTO_MCBSP5 |
595 OMAP3430_AUTO_MCBSP1 |
596 OMAP3430ES1_AUTO_FAC | /* This is es1 only */
597 OMAP3430_AUTO_MAILBOXES |
598 OMAP3430_AUTO_OMAPCTRL |
599 OMAP3430ES1_AUTO_FSHOSTUSB |
600 OMAP3430_AUTO_HSOTGUSB |
Kevin Hilman8111b222009-04-28 15:27:44 -0700601 OMAP3430_AUTO_SAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700602 OMAP3430_AUTO_SSI,
603 CORE_MOD, CM_AUTOIDLE1);
604
605 cm_write_mod_reg(
606 OMAP3430_AUTO_PKA |
607 OMAP3430_AUTO_AES1 |
608 OMAP3430_AUTO_RNG |
609 OMAP3430_AUTO_SHA11 |
610 OMAP3430_AUTO_DES1,
611 CORE_MOD, CM_AUTOIDLE2);
612
613 if (omap_rev() > OMAP3430_REV_ES1_0) {
614 cm_write_mod_reg(
Kevin Hilman8111b222009-04-28 15:27:44 -0700615 OMAP3430_AUTO_MAD2D |
Kevin Hilman8bd22942009-05-28 10:56:16 -0700616 OMAP3430ES2_AUTO_USBTLL,
617 CORE_MOD, CM_AUTOIDLE3);
618 }
619
620 cm_write_mod_reg(
621 OMAP3430_AUTO_WDT2 |
622 OMAP3430_AUTO_WDT1 |
623 OMAP3430_AUTO_GPIO1 |
624 OMAP3430_AUTO_32KSYNC |
625 OMAP3430_AUTO_GPT12 |
626 OMAP3430_AUTO_GPT1 ,
627 WKUP_MOD, CM_AUTOIDLE);
628
629 cm_write_mod_reg(
630 OMAP3430_AUTO_DSS,
631 OMAP3430_DSS_MOD,
632 CM_AUTOIDLE);
633
634 cm_write_mod_reg(
635 OMAP3430_AUTO_CAM,
636 OMAP3430_CAM_MOD,
637 CM_AUTOIDLE);
638
639 cm_write_mod_reg(
640 OMAP3430_AUTO_GPIO6 |
641 OMAP3430_AUTO_GPIO5 |
642 OMAP3430_AUTO_GPIO4 |
643 OMAP3430_AUTO_GPIO3 |
644 OMAP3430_AUTO_GPIO2 |
645 OMAP3430_AUTO_WDT3 |
646 OMAP3430_AUTO_UART3 |
647 OMAP3430_AUTO_GPT9 |
648 OMAP3430_AUTO_GPT8 |
649 OMAP3430_AUTO_GPT7 |
650 OMAP3430_AUTO_GPT6 |
651 OMAP3430_AUTO_GPT5 |
652 OMAP3430_AUTO_GPT4 |
653 OMAP3430_AUTO_GPT3 |
654 OMAP3430_AUTO_GPT2 |
655 OMAP3430_AUTO_MCBSP4 |
656 OMAP3430_AUTO_MCBSP3 |
657 OMAP3430_AUTO_MCBSP2,
658 OMAP3430_PER_MOD,
659 CM_AUTOIDLE);
660
661 if (omap_rev() > OMAP3430_REV_ES1_0) {
662 cm_write_mod_reg(
663 OMAP3430ES2_AUTO_USBHOST,
664 OMAP3430ES2_USBHOST_MOD,
665 CM_AUTOIDLE);
666 }
667
668 /*
669 * Set all plls to autoidle. This is needed until autoidle is
670 * enabled by clockfw
671 */
672 cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
673 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
674 cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
675 MPU_MOD,
676 CM_AUTOIDLE2);
677 cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
678 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
679 PLL_MOD,
680 CM_AUTOIDLE);
681 cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
682 PLL_MOD,
683 CM_AUTOIDLE2);
684
685 /*
686 * Enable control of expternal oscillator through
687 * sys_clkreq. In the long run clock framework should
688 * take care of this.
689 */
690 prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
691 1 << OMAP_AUTOEXTCLKMODE_SHIFT,
692 OMAP3430_GR_MOD,
693 OMAP3_PRM_CLKSRC_CTRL_OFFSET);
694
695 /* setup wakup source */
696 prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
697 OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
698 WKUP_MOD, PM_WKEN);
699 /* No need to write EN_IO, that is always enabled */
700 prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
701 OMAP3430_EN_GPT12,
702 WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
703 /* For some reason IO doesn't generate wakeup event even if
704 * it is selected to mpu wakeup goup */
705 prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
706 OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
Kevin Hilman1155e422008-11-25 11:48:24 -0800707
Kevin Hilmanb427f922009-10-22 14:48:13 -0700708 /* Enable wakeups in PER */
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000709 prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 |
710 OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 |
Kevin Hilmanb427f922009-10-22 14:48:13 -0700711 OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3,
712 OMAP3430_PER_MOD, PM_WKEN);
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000713 /* and allow them to wake up MPU */
714 prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 |
715 OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 |
Kevin Hilmanb427f922009-10-22 14:48:13 -0700716 OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3,
Kevin Hilmaneb350f72009-09-10 15:53:08 +0000717 OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
718
Kevin Hilmand3fd3292009-05-05 16:34:25 -0700719 /* Don't attach IVA interrupts */
720 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
721 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
722 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
723 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
724
Kevin Hilmanb1340d12009-04-27 16:14:54 -0700725 /* Clear any pending 'reset' flags */
726 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
727 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
728 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
729 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
730 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
731 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
732 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
733
Kevin Hilman014c46d2009-04-27 07:50:23 -0700734 /* Clear any pending PRCM interrupts */
735 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
736
Kevin Hilman040fed02009-05-05 16:34:25 -0700737 /* Don't attach IVA interrupts */
738 prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
739 prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
740 prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3);
741 prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL);
742
Kevin Hilman3a07ae32009-04-27 16:14:54 -0700743 /* Clear any pending 'reset' flags */
744 prm_write_mod_reg(0xffffffff, MPU_MOD, RM_RSTST);
745 prm_write_mod_reg(0xffffffff, CORE_MOD, RM_RSTST);
746 prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, RM_RSTST);
747 prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, RM_RSTST);
748 prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, RM_RSTST);
749 prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, RM_RSTST);
750 prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, RM_RSTST);
751
Kevin Hilman3a6667a2009-04-27 07:50:23 -0700752 /* Clear any pending PRCM interrupts */
753 prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
754
Kevin Hilman1155e422008-11-25 11:48:24 -0800755 omap3_iva_idle();
Kevin Hilman8111b222009-04-28 15:27:44 -0700756 omap3_d2d_idle();
Kevin Hilman8bd22942009-05-28 10:56:16 -0700757}
758
Tero Kristo68d47782008-11-26 12:26:24 +0200759int omap3_pm_get_suspend_state(struct powerdomain *pwrdm)
760{
761 struct power_state *pwrst;
762
763 list_for_each_entry(pwrst, &pwrst_list, node) {
764 if (pwrst->pwrdm == pwrdm)
765 return pwrst->next_state;
766 }
767 return -EINVAL;
768}
769
770int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state)
771{
772 struct power_state *pwrst;
773
774 list_for_each_entry(pwrst, &pwrst_list, node) {
775 if (pwrst->pwrdm == pwrdm) {
776 pwrst->next_state = state;
777 return 0;
778 }
779 }
780 return -EINVAL;
781}
782
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300783static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700784{
785 struct power_state *pwrst;
786
787 if (!pwrdm->pwrsts)
788 return 0;
789
Ming Leid3d381c2009-08-22 21:20:26 +0800790 pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700791 if (!pwrst)
792 return -ENOMEM;
793 pwrst->pwrdm = pwrdm;
794 pwrst->next_state = PWRDM_POWER_RET;
795 list_add(&pwrst->node, &pwrst_list);
796
797 if (pwrdm_has_hdwr_sar(pwrdm))
798 pwrdm_enable_hdwr_sar(pwrdm);
799
800 return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
801}
802
803/*
804 * Enable hw supervised mode for all clockdomains if it's
805 * supported. Initiate sleep transition for other clockdomains, if
806 * they are not used
807 */
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300808static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700809{
810 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
811 omap2_clkdm_allow_idle(clkdm);
812 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
813 atomic_read(&clkdm->usecount) == 0)
814 omap2_clkdm_sleep(clkdm);
815 return 0;
816}
817
Rajendra Nayak3231fc82008-09-26 17:49:14 +0530818void omap_push_sram_idle(void)
819{
820 _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
821 omap34xx_cpu_suspend_sz);
822}
823
Kevin Hilman7cc515f2009-06-10 09:02:25 -0700824static int __init omap3_pm_init(void)
Kevin Hilman8bd22942009-05-28 10:56:16 -0700825{
826 struct power_state *pwrst, *tmp;
827 int ret;
828
829 if (!cpu_is_omap34xx())
830 return -ENODEV;
831
832 printk(KERN_ERR "Power Management for TI OMAP3.\n");
833
834 /* XXX prcm_setup_regs needs to be before enabling hw
835 * supervised mode for powerdomains */
836 prcm_setup_regs();
837
838 ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
839 (irq_handler_t)prcm_interrupt_handler,
840 IRQF_DISABLED, "prcm", NULL);
841 if (ret) {
842 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
843 INT_34XX_PRCM_MPU_IRQ);
844 goto err1;
845 }
846
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300847 ret = pwrdm_for_each(pwrdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700848 if (ret) {
849 printk(KERN_ERR "Failed to setup powerdomains\n");
850 goto err2;
851 }
852
Peter 'p2' De Schrijvera23456e2008-10-15 18:13:47 +0300853 (void) clkdm_for_each(clkdms_setup, NULL);
Kevin Hilman8bd22942009-05-28 10:56:16 -0700854
855 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
856 if (mpu_pwrdm == NULL) {
857 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
858 goto err2;
859 }
860
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530861 neon_pwrdm = pwrdm_lookup("neon_pwrdm");
862 per_pwrdm = pwrdm_lookup("per_pwrdm");
863 core_pwrdm = pwrdm_lookup("core_pwrdm");
864
Rajendra Nayak3231fc82008-09-26 17:49:14 +0530865 omap_push_sram_idle();
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700866#ifdef CONFIG_SUSPEND
Kevin Hilman8bd22942009-05-28 10:56:16 -0700867 suspend_set_ops(&omap_pm_ops);
Kevin Hilman10f90ed2009-06-24 11:39:18 -0700868#endif /* CONFIG_SUSPEND */
Kevin Hilman8bd22942009-05-28 10:56:16 -0700869
870 pm_idle = omap3_pm_idle;
871
Rajendra Nayakfa3c2a42008-09-26 17:49:22 +0530872 pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm);
873 /*
874 * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for
875 * IO-pad wakeup. Otherwise it will unnecessarily waste power
876 * waking up PER with every CORE wakeup - see
877 * http://marc.info/?l=linux-omap&m=121852150710062&w=2
878 */
879 pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
880
Kevin Hilman8bd22942009-05-28 10:56:16 -0700881err1:
882 return ret;
883err2:
884 free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
885 list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
886 list_del(&pwrst->node);
887 kfree(pwrst);
888 }
889 return ret;
890}
891
892late_initcall(omap3_pm_init);