aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorKevin Hilman <khilman@deeprootsystems.com>2009-05-28 13:56:16 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2009-05-28 13:58:50 -0400
commit8bd229492209c0c7d050e2f9a600c12f035d72f7 (patch)
treec76039df215b1c3ba58adb23845baa4af40f25fe /arch/arm
parenta330bd4750bc84aebb28faddd525d0bcbdde262d (diff)
OMAP2/3: PM: push core PM code from linux-omap
This patch is to sync the core linux-omap PM code with mainline. This code has evolved and been used for a while the linux-omap tree, but the attempt here is to finally get this into mainline. Following this will be a series of patches from the 'PM branch' of the linux-omap tree to add full PM hardware support from the linux-omap tree. Much of this PM core code was written by Jouni Hogander with significant contributions from Paul Walmsley as well as many others from Nokia, Texas Instruments and linux-omap community. Signed-off-by: Jouni Hogander <jouni.hogander@nokia.com> Cc: Paul Walmsley <paul@pwsan.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-omap1/pm.h (renamed from arch/arm/plat-omap/include/mach/pm.h)0
-rw-r--r--arch/arm/mach-omap2/Makefile4
-rw-r--r--arch/arm/mach-omap2/pm-debug.c152
-rw-r--r--arch/arm/mach-omap2/pm.c111
-rw-r--r--arch/arm/mach-omap2/pm.h38
-rw-r--r--arch/arm/mach-omap2/pm24xx.c548
-rw-r--r--arch/arm/mach-omap2/pm34xx.c606
-rw-r--r--arch/arm/mach-omap2/prcm-common.h2
-rw-r--r--arch/arm/mach-omap2/sdrc.c5
-rw-r--r--arch/arm/mach-omap2/sleep24xx.S1
-rw-r--r--arch/arm/mach-omap2/sleep34xx.S436
-rw-r--r--arch/arm/mach-omap2/usb-musb.c1
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/plat-omap/common.c1
14 files changed, 1790 insertions, 117 deletions
diff --git a/arch/arm/plat-omap/include/mach/pm.h b/arch/arm/mach-omap1/pm.h
index ce6ee7927537..ce6ee7927537 100644
--- a/arch/arm/plat-omap/include/mach/pm.h
+++ b/arch/arm/mach-omap1/pm.h
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index bf3827ae2c5f..6fd1c1f77398 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -25,8 +25,10 @@ obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o
25 25
26# Power Management 26# Power Management
27ifeq ($(CONFIG_PM),y) 27ifeq ($(CONFIG_PM),y)
28obj-y += pm.o 28obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
29obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o 29obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o
30obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o
31obj-$(CONFIG_PM_DEBUG) += pm-debug.o
30endif 32endif
31 33
32# Clock framework 34# Clock framework
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
new file mode 100644
index 000000000000..6cc375a275be
--- /dev/null
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -0,0 +1,152 @@
1/*
2 * OMAP Power Management debug routines
3 *
4 * Copyright (C) 2005 Texas Instruments, Inc.
5 * Copyright (C) 2006-2008 Nokia Corporation
6 *
7 * Written by:
8 * Richard Woodruff <r-woodruff2@ti.com>
9 * Tony Lindgren
10 * Juha Yrjola
11 * Amit Kucheria <amit.kucheria@nokia.com>
12 * Igor Stoppa <igor.stoppa@nokia.com>
13 * Jouni Hogander
14 *
15 * Based on pm.c for omap2
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License version 2 as
19 * published by the Free Software Foundation.
20 */
21
22#include <linux/kernel.h>
23#include <linux/timer.h>
24#include <linux/clk.h>
25#include <linux/err.h>
26#include <linux/io.h>
27
28#include <mach/clock.h>
29#include <mach/board.h>
30
31#include "prm.h"
32#include "cm.h"
33#include "pm.h"
34
35int omap2_pm_debug;
36
37#define DUMP_PRM_MOD_REG(mod, reg) \
38 regs[reg_count].name = #mod "." #reg; \
39 regs[reg_count++].val = prm_read_mod_reg(mod, reg)
40#define DUMP_CM_MOD_REG(mod, reg) \
41 regs[reg_count].name = #mod "." #reg; \
42 regs[reg_count++].val = cm_read_mod_reg(mod, reg)
43#define DUMP_PRM_REG(reg) \
44 regs[reg_count].name = #reg; \
45 regs[reg_count++].val = __raw_readl(reg)
46#define DUMP_CM_REG(reg) \
47 regs[reg_count].name = #reg; \
48 regs[reg_count++].val = __raw_readl(reg)
49#define DUMP_INTC_REG(reg, off) \
50 regs[reg_count].name = #reg; \
51 regs[reg_count++].val = __raw_readl(IO_ADDRESS(0x480fe000 + (off)))
52
53void omap2_pm_dump(int mode, int resume, unsigned int us)
54{
55 struct reg {
56 const char *name;
57 u32 val;
58 } regs[32];
59 int reg_count = 0, i;
60 const char *s1 = NULL, *s2 = NULL;
61
62 if (!resume) {
63#if 0
64 /* MPU */
65 DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET);
66 DUMP_CM_MOD_REG(MPU_MOD, CM_CLKSTCTRL);
67 DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTCTRL);
68 DUMP_PRM_MOD_REG(MPU_MOD, PM_PWSTST);
69 DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP);
70#endif
71#if 0
72 /* INTC */
73 DUMP_INTC_REG(INTC_MIR0, 0x0084);
74 DUMP_INTC_REG(INTC_MIR1, 0x00a4);
75 DUMP_INTC_REG(INTC_MIR2, 0x00c4);
76#endif
77#if 0
78 DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1);
79 if (cpu_is_omap24xx()) {
80 DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2);
81 DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
82 OMAP2_PRCM_CLKEMUL_CTRL_OFFSET);
83 DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD,
84 OMAP2_PRCM_CLKSRC_CTRL_OFFSET);
85 }
86 DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN);
87 DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1);
88 DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2);
89 DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN);
90 DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN);
91 DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE);
92 DUMP_PRM_MOD_REG(CORE_MOD, PM_PWSTST);
93#endif
94#if 0
95 /* DSP */
96 if (cpu_is_omap24xx()) {
97 DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN);
98 DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN);
99 DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST);
100 DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE);
101 DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL);
102 DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSTCTRL);
103 DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTCTRL);
104 DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, RM_RSTST);
105 DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTCTRL);
106 DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, PM_PWSTST);
107 }
108#endif
109 } else {
110 DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1);
111 if (cpu_is_omap24xx())
112 DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2);
113 DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST);
114 DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
115#if 1
116 DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098);
117 DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8);
118 DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8);
119#endif
120 }
121
122 switch (mode) {
123 case 0:
124 s1 = "full";
125 s2 = "retention";
126 break;
127 case 1:
128 s1 = "MPU";
129 s2 = "retention";
130 break;
131 case 2:
132 s1 = "MPU";
133 s2 = "idle";
134 break;
135 }
136
137 if (!resume)
138#ifdef CONFIG_NO_HZ
139 printk(KERN_INFO
140 "--- Going to %s %s (next timer after %u ms)\n", s1, s2,
141 jiffies_to_msecs(get_next_timer_interrupt(jiffies) -
142 jiffies));
143#else
144 printk(KERN_INFO "--- Going to %s %s\n", s1, s2);
145#endif
146 else
147 printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n",
148 us / 1000, us % 1000);
149
150 for (i = 0; i < reg_count; i++)
151 printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
152}
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
deleted file mode 100644
index ea8ceaed09cb..000000000000
--- a/arch/arm/mach-omap2/pm.c
+++ /dev/null
@@ -1,111 +0,0 @@
1/*
2 * linux/arch/arm/mach-omap2/pm.c
3 *
4 * OMAP2 Power Management Routines
5 *
6 * Copyright (C) 2006 Nokia Corporation
7 * Tony Lindgren <tony@atomide.com>
8 *
9 * Copyright (C) 2005 Texas Instruments, Inc.
10 * Richard Woodruff <r-woodruff2@ti.com>
11 *
12 * Based on pm.c for omap1
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19#include <linux/suspend.h>
20#include <linux/sched.h>
21#include <linux/proc_fs.h>
22#include <linux/interrupt.h>
23#include <linux/sysfs.h>
24#include <linux/module.h>
25#include <linux/delay.h>
26#include <linux/clk.h>
27#include <linux/io.h>
28
29#include <asm/irq.h>
30#include <asm/atomic.h>
31#include <asm/mach/time.h>
32#include <asm/mach/irq.h>
33
34#include <mach/irqs.h>
35#include <mach/clock.h>
36#include <mach/sram.h>
37#include <mach/pm.h>
38
39static struct clk *vclk;
40static void (*omap2_sram_idle)(void);
41static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev);
42static void (*saved_idle)(void);
43
44extern void __init pmdomain_init(void);
45extern void pmdomain_set_autoidle(void);
46
47static unsigned int omap24xx_sleep_save[OMAP24XX_SLEEP_SAVE_SIZE];
48
49void omap2_pm_idle(void)
50{
51 local_irq_disable();
52 local_fiq_disable();
53 if (need_resched()) {
54 local_fiq_enable();
55 local_irq_enable();
56 return;
57 }
58
59 omap2_sram_idle();
60 local_fiq_enable();
61 local_irq_enable();
62}
63
64static int omap2_pm_prepare(void)
65{
66 /* We cannot sleep in idle until we have resumed */
67 saved_idle = pm_idle;
68 pm_idle = NULL;
69 return 0;
70}
71
72static int omap2_pm_suspend(void)
73{
74 return 0;
75}
76
77static int omap2_pm_enter(suspend_state_t state)
78{
79 int ret = 0;
80
81 switch (state)
82 {
83 case PM_SUSPEND_STANDBY:
84 case PM_SUSPEND_MEM:
85 ret = omap2_pm_suspend();
86 break;
87 default:
88 ret = -EINVAL;
89 }
90
91 return ret;
92}
93
94static void omap2_pm_finish(void)
95{
96 pm_idle = saved_idle;
97}
98
99static struct platform_suspend_ops omap_pm_ops = {
100 .prepare = omap2_pm_prepare,
101 .enter = omap2_pm_enter,
102 .finish = omap2_pm_finish,
103 .valid = suspend_valid_only_mem,
104};
105
106static int __init omap2_pm_init(void)
107{
108 return 0;
109}
110
111__initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
new file mode 100644
index 000000000000..f7b3baf76678
--- /dev/null
+++ b/arch/arm/mach-omap2/pm.h
@@ -0,0 +1,38 @@
1/*
2 * OMAP2/3 Power Management Routines
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Jouni Hogander
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
12#define __ARCH_ARM_MACH_OMAP2_PM_H
13
14extern int omap2_pm_init(void);
15extern int omap3_pm_init(void);
16
17#ifdef CONFIG_PM_DEBUG
18extern void omap2_pm_dump(int mode, int resume, unsigned int us);
19extern int omap2_pm_debug;
20#else
21#define omap2_pm_dump(mode, resume, us) do {} while (0);
22#define omap2_pm_debug 0
23#endif /* CONFIG_PM_DEBUG */
24
25extern void omap24xx_idle_loop_suspend(void);
26
27extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl,
28 void __iomem *sdrc_power);
29extern void omap34xx_cpu_suspend(u32 *addr, int save_state);
30extern void save_secure_ram_context(u32 *addr);
31
32extern unsigned int omap24xx_idle_loop_suspend_sz;
33extern unsigned int omap34xx_suspend_sz;
34extern unsigned int save_secure_ram_context_sz;
35extern unsigned int omap24xx_cpu_suspend_sz;
36extern unsigned int omap34xx_cpu_suspend_sz;
37
38#endif
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
new file mode 100644
index 000000000000..232b9f6032e8
--- /dev/null
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -0,0 +1,548 @@
1/*
2 * OMAP2 Power Management Routines
3 *
4 * Copyright (C) 2005 Texas Instruments, Inc.
5 * Copyright (C) 2006-2008 Nokia Corporation
6 *
7 * Written by:
8 * Richard Woodruff <r-woodruff2@ti.com>
9 * Tony Lindgren
10 * Juha Yrjola
11 * Amit Kucheria <amit.kucheria@nokia.com>
12 * Igor Stoppa <igor.stoppa@nokia.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
21#include <linux/suspend.h>
22#include <linux/sched.h>
23#include <linux/proc_fs.h>
24#include <linux/interrupt.h>
25#include <linux/sysfs.h>
26#include <linux/module.h>
27#include <linux/delay.h>
28#include <linux/clk.h>
29#include <linux/io.h>
30#include <linux/irq.h>
31#include <linux/time.h>
32#include <linux/gpio.h>
33
34#include <asm/mach/time.h>
35#include <asm/mach/irq.h>
36#include <asm/mach-types.h>
37
38#include <mach/irqs.h>
39#include <mach/clock.h>
40#include <mach/sram.h>
41#include <mach/control.h>
42#include <mach/mux.h>
43#include <mach/dma.h>
44#include <mach/board.h>
45
46#include "prm.h"
47#include "prm-regbits-24xx.h"
48#include "cm.h"
49#include "cm-regbits-24xx.h"
50#include "sdrc.h"
51#include "pm.h"
52
53#include <mach/powerdomain.h>
54#include <mach/clockdomain.h>
55
56static void (*omap2_sram_idle)(void);
57static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
58 void __iomem *sdrc_power);
59
60static struct powerdomain *mpu_pwrdm;
61static struct powerdomain *core_pwrdm;
62
63static struct clockdomain *dsp_clkdm;
64static struct clockdomain *gfx_clkdm;
65
66static struct clk *osc_ck, *emul_ck;
67
68static int omap2_fclks_active(void)
69{
70 u32 f1, f2;
71
72 f1 = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
73 f2 = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
74 if (f1 | f2)
75 return 1;
76 return 0;
77}
78
79static int omap2_irq_pending(void)
80{
81 u32 pending_reg = 0x480fe098;
82 int i;
83
84 for (i = 0; i < 4; i++) {
85 if (omap_readl(pending_reg))
86 return 1;
87 pending_reg += 0x20;
88 }
89 return 0;
90}
91
92static void omap2_enter_full_retention(void)
93{
94 u32 l;
95 struct timespec ts_preidle, ts_postidle, ts_idle;
96
97 /* There is 1 reference hold for all children of the oscillator
98 * clock, the following will remove it. If no one else uses the
99 * oscillator itself it will be disabled if/when we enter retention
100 * mode.
101 */
102 clk_disable(osc_ck);
103
104 /* Clear old wake-up events */
105 /* REVISIT: These write to reserved bits? */
106 prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
107 prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
108 prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
109
110 /*
111 * Set MPU powerdomain's next power state to RETENTION;
112 * preserve logic state during retention
113 */
114 pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
115 pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
116
117 /* Workaround to kill USB */
118 l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
119 omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
120
121 omap2_gpio_prepare_for_retention();
122
123 if (omap2_pm_debug) {
124 omap2_pm_dump(0, 0, 0);
125 getnstimeofday(&ts_preidle);
126 }
127
128 /* One last check for pending IRQs to avoid extra latency due
129 * to sleeping unnecessarily. */
130 if (omap2_irq_pending())
131 goto no_sleep;
132
133 /* Jump to SRAM suspend code */
134 omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
135 OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
136 OMAP_SDRC_REGADDR(SDRC_POWER));
137no_sleep:
138
139 if (omap2_pm_debug) {
140 unsigned long long tmp;
141
142 getnstimeofday(&ts_postidle);
143 ts_idle = timespec_sub(ts_postidle, ts_preidle);
144 tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
145 omap2_pm_dump(0, 1, tmp);
146 }
147 omap2_gpio_resume_after_retention();
148
149 clk_enable(osc_ck);
150
151 /* clear CORE wake-up events */
152 prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
153 prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
154
155 /* wakeup domain events - bit 1: GPT1, bit5 GPIO */
156 prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
157
158 /* MPU domain wake events */
159 l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
160 if (l & 0x01)
161 prm_write_mod_reg(0x01, OCP_MOD,
162 OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
163 if (l & 0x20)
164 prm_write_mod_reg(0x20, OCP_MOD,
165 OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
166
167 /* Mask future PRCM-to-MPU interrupts */
168 prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
169}
170
171static int omap2_i2c_active(void)
172{
173 u32 l;
174
175 l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
176 return l & (OMAP2420_EN_I2C2 | OMAP2420_EN_I2C1);
177}
178
179static int sti_console_enabled;
180
181static int omap2_allow_mpu_retention(void)
182{
183 u32 l;
184
185 /* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
186 l = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
187 if (l & (OMAP2420_EN_MMC | OMAP24XX_EN_UART2 |
188 OMAP24XX_EN_UART1 | OMAP24XX_EN_MCSPI2 |
189 OMAP24XX_EN_MCSPI1 | OMAP24XX_EN_DSS1))
190 return 0;
191 /* Check for UART3. */
192 l = cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
193 if (l & OMAP24XX_EN_UART3)
194 return 0;
195 if (sti_console_enabled)
196 return 0;
197
198 return 1;
199}
200
201static void omap2_enter_mpu_retention(void)
202{
203 int only_idle = 0;
204 struct timespec ts_preidle, ts_postidle, ts_idle;
205
206 /* Putting MPU into the WFI state while a transfer is active
207 * seems to cause the I2C block to timeout. Why? Good question. */
208 if (omap2_i2c_active())
209 return;
210
211 /* The peripherals seem not to be able to wake up the MPU when
212 * it is in retention mode. */
213 if (omap2_allow_mpu_retention()) {
214 /* REVISIT: These write to reserved bits? */
215 prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
216 prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
217 prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
218
219 /* Try to enter MPU retention */
220 prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
221 OMAP_LOGICRETSTATE,
222 MPU_MOD, PM_PWSTCTRL);
223 } else {
224 /* Block MPU retention */
225
226 prm_write_mod_reg(OMAP_LOGICRETSTATE, MPU_MOD, PM_PWSTCTRL);
227 only_idle = 1;
228 }
229
230 if (omap2_pm_debug) {
231 omap2_pm_dump(only_idle ? 2 : 1, 0, 0);
232 getnstimeofday(&ts_preidle);
233 }
234
235 omap2_sram_idle();
236
237 if (omap2_pm_debug) {
238 unsigned long long tmp;
239
240 getnstimeofday(&ts_postidle);
241 ts_idle = timespec_sub(ts_postidle, ts_preidle);
242 tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
243 omap2_pm_dump(only_idle ? 2 : 1, 1, tmp);
244 }
245}
246
247static int omap2_can_sleep(void)
248{
249 if (omap2_fclks_active())
250 return 0;
251 if (osc_ck->usecount > 1)
252 return 0;
253 if (omap_dma_running())
254 return 0;
255
256 return 1;
257}
258
259static void omap2_pm_idle(void)
260{
261 local_irq_disable();
262 local_fiq_disable();
263
264 if (!omap2_can_sleep()) {
265 if (omap2_irq_pending())
266 goto out;
267 omap2_enter_mpu_retention();
268 goto out;
269 }
270
271 if (omap2_irq_pending())
272 goto out;
273
274 omap2_enter_full_retention();
275
276out:
277 local_fiq_enable();
278 local_irq_enable();
279}
280
281static int omap2_pm_prepare(void)
282{
283 /* We cannot sleep in idle until we have resumed */
284 disable_hlt();
285 return 0;
286}
287
288static int omap2_pm_suspend(void)
289{
290 u32 wken_wkup, mir1;
291
292 wken_wkup = prm_read_mod_reg(WKUP_MOD, PM_WKEN);
293 prm_write_mod_reg(wken_wkup & ~OMAP24XX_EN_GPT1, WKUP_MOD, PM_WKEN);
294
295 /* Mask GPT1 */
296 mir1 = omap_readl(0x480fe0a4);
297 omap_writel(1 << 5, 0x480fe0ac);
298
299 omap2_enter_full_retention();
300
301 omap_writel(mir1, 0x480fe0a4);
302 prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
303
304 return 0;
305}
306
307static int omap2_pm_enter(suspend_state_t state)
308{
309 int ret = 0;
310
311 switch (state) {
312 case PM_SUSPEND_STANDBY:
313 case PM_SUSPEND_MEM:
314 ret = omap2_pm_suspend();
315 break;
316 default:
317 ret = -EINVAL;
318 }
319
320 return ret;
321}
322
323static void omap2_pm_finish(void)
324{
325 enable_hlt();
326}
327
328static struct platform_suspend_ops omap_pm_ops = {
329 .prepare = omap2_pm_prepare,
330 .enter = omap2_pm_enter,
331 .finish = omap2_pm_finish,
332 .valid = suspend_valid_only_mem,
333};
334
335static int _pm_clkdm_enable_hwsup(struct clockdomain *clkdm)
336{
337 omap2_clkdm_allow_idle(clkdm);
338 return 0;
339}
340
341static void __init prcm_setup_regs(void)
342{
343 int i, num_mem_banks;
344 struct powerdomain *pwrdm;
345
346 /* Enable autoidle */
347 prm_write_mod_reg(OMAP24XX_AUTOIDLE, OCP_MOD,
348 OMAP2_PRCM_SYSCONFIG_OFFSET);
349
350 /* Set all domain wakeup dependencies */
351 prm_write_mod_reg(OMAP_EN_WKUP_MASK, MPU_MOD, PM_WKDEP);
352 prm_write_mod_reg(0, OMAP24XX_DSP_MOD, PM_WKDEP);
353 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
354 prm_write_mod_reg(0, CORE_MOD, PM_WKDEP);
355 if (cpu_is_omap2430())
356 prm_write_mod_reg(0, OMAP2430_MDM_MOD, PM_WKDEP);
357
358 /*
359 * Set CORE powerdomain memory banks to retain their contents
360 * during RETENTION
361 */
362 num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
363 for (i = 0; i < num_mem_banks; i++)
364 pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
365
366 /* Set CORE powerdomain's next power state to RETENTION */
367 pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
368
369 /*
370 * Set MPU powerdomain's next power state to RETENTION;
371 * preserve logic state during retention
372 */
373 pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
374 pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
375
376 /* Force-power down DSP, GFX powerdomains */
377
378 pwrdm = clkdm_get_pwrdm(dsp_clkdm);
379 pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
380 omap2_clkdm_sleep(dsp_clkdm);
381
382 pwrdm = clkdm_get_pwrdm(gfx_clkdm);
383 pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
384 omap2_clkdm_sleep(gfx_clkdm);
385
386 /* Enable clockdomain hardware-supervised control for all clkdms */
387 clkdm_for_each(_pm_clkdm_enable_hwsup);
388
389 /* Enable clock autoidle for all domains */
390 cm_write_mod_reg(OMAP24XX_AUTO_CAM |
391 OMAP24XX_AUTO_MAILBOXES |
392 OMAP24XX_AUTO_WDT4 |
393 OMAP2420_AUTO_WDT3 |
394 OMAP24XX_AUTO_MSPRO |
395 OMAP2420_AUTO_MMC |
396 OMAP24XX_AUTO_FAC |
397 OMAP2420_AUTO_EAC |
398 OMAP24XX_AUTO_HDQ |
399 OMAP24XX_AUTO_UART2 |
400 OMAP24XX_AUTO_UART1 |
401 OMAP24XX_AUTO_I2C2 |
402 OMAP24XX_AUTO_I2C1 |
403 OMAP24XX_AUTO_MCSPI2 |
404 OMAP24XX_AUTO_MCSPI1 |
405 OMAP24XX_AUTO_MCBSP2 |
406 OMAP24XX_AUTO_MCBSP1 |
407 OMAP24XX_AUTO_GPT12 |
408 OMAP24XX_AUTO_GPT11 |
409 OMAP24XX_AUTO_GPT10 |
410 OMAP24XX_AUTO_GPT9 |
411 OMAP24XX_AUTO_GPT8 |
412 OMAP24XX_AUTO_GPT7 |
413 OMAP24XX_AUTO_GPT6 |
414 OMAP24XX_AUTO_GPT5 |
415 OMAP24XX_AUTO_GPT4 |
416 OMAP24XX_AUTO_GPT3 |
417 OMAP24XX_AUTO_GPT2 |
418 OMAP2420_AUTO_VLYNQ |
419 OMAP24XX_AUTO_DSS,
420 CORE_MOD, CM_AUTOIDLE1);
421 cm_write_mod_reg(OMAP24XX_AUTO_UART3 |
422 OMAP24XX_AUTO_SSI |
423 OMAP24XX_AUTO_USB,
424 CORE_MOD, CM_AUTOIDLE2);
425 cm_write_mod_reg(OMAP24XX_AUTO_SDRC |
426 OMAP24XX_AUTO_GPMC |
427 OMAP24XX_AUTO_SDMA,
428 CORE_MOD, CM_AUTOIDLE3);
429 cm_write_mod_reg(OMAP24XX_AUTO_PKA |
430 OMAP24XX_AUTO_AES |
431 OMAP24XX_AUTO_RNG |
432 OMAP24XX_AUTO_SHA |
433 OMAP24XX_AUTO_DES,
434 CORE_MOD, OMAP24XX_CM_AUTOIDLE4);
435
436 cm_write_mod_reg(OMAP2420_AUTO_DSP_IPI, OMAP24XX_DSP_MOD, CM_AUTOIDLE);
437
438 /* Put DPLL and both APLLs into autoidle mode */
439 cm_write_mod_reg((0x03 << OMAP24XX_AUTO_DPLL_SHIFT) |
440 (0x03 << OMAP24XX_AUTO_96M_SHIFT) |
441 (0x03 << OMAP24XX_AUTO_54M_SHIFT),
442 PLL_MOD, CM_AUTOIDLE);
443
444 cm_write_mod_reg(OMAP24XX_AUTO_OMAPCTRL |
445 OMAP24XX_AUTO_WDT1 |
446 OMAP24XX_AUTO_MPU_WDT |
447 OMAP24XX_AUTO_GPIOS |
448 OMAP24XX_AUTO_32KSYNC |
449 OMAP24XX_AUTO_GPT1,
450 WKUP_MOD, CM_AUTOIDLE);
451
452 /* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
453 * stabilisation */
454 prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
455 OMAP2_PRCM_CLKSSETUP_OFFSET);
456
457 /* Configure automatic voltage transition */
458 prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
459 OMAP2_PRCM_VOLTSETUP_OFFSET);
460 prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT |
461 (0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
462 OMAP24XX_MEMRETCTRL |
463 (0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
464 (0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
465 OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
466
467 /* Enable wake-up events */
468 prm_write_mod_reg(OMAP24XX_EN_GPIOS | OMAP24XX_EN_GPT1,
469 WKUP_MOD, PM_WKEN);
470}
471
472int __init omap2_pm_init(void)
473{
474 u32 l;
475
476 if (!cpu_is_omap24xx())
477 return -ENODEV;
478
479 printk(KERN_INFO "Power Management for OMAP2 initializing\n");
480 l = prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
481 printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
482
483 /* Look up important powerdomains, clockdomains */
484
485 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
486 if (!mpu_pwrdm)
487 pr_err("PM: mpu_pwrdm not found\n");
488
489 core_pwrdm = pwrdm_lookup("core_pwrdm");
490 if (!core_pwrdm)
491 pr_err("PM: core_pwrdm not found\n");
492
493 dsp_clkdm = clkdm_lookup("dsp_clkdm");
494 if (!dsp_clkdm)
495 pr_err("PM: mpu_clkdm not found\n");
496
497 gfx_clkdm = clkdm_lookup("gfx_clkdm");
498 if (!gfx_clkdm)
499 pr_err("PM: gfx_clkdm not found\n");
500
501
502 osc_ck = clk_get(NULL, "osc_ck");
503 if (IS_ERR(osc_ck)) {
504 printk(KERN_ERR "could not get osc_ck\n");
505 return -ENODEV;
506 }
507
508 if (cpu_is_omap242x()) {
509 emul_ck = clk_get(NULL, "emul_ck");
510 if (IS_ERR(emul_ck)) {
511 printk(KERN_ERR "could not get emul_ck\n");
512 clk_put(osc_ck);
513 return -ENODEV;
514 }
515 }
516
517 prcm_setup_regs();
518
519 /* Hack to prevent MPU retention when STI console is enabled. */
520 {
521 const struct omap_sti_console_config *sti;
522
523 sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
524 struct omap_sti_console_config);
525 if (sti != NULL && sti->enable)
526 sti_console_enabled = 1;
527 }
528
529 /*
530 * We copy the assembler sleep/wakeup routines to SRAM.
531 * These routines need to be in SRAM as that's the only
532 * memory the MPU can see when it wakes up.
533 */
534 if (cpu_is_omap24xx()) {
535 omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
536 omap24xx_idle_loop_suspend_sz);
537
538 omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
539 omap24xx_cpu_suspend_sz);
540 }
541
542 suspend_set_ops(&omap_pm_ops);
543 pm_idle = omap2_pm_idle;
544
545 return 0;
546}
547
548late_initcall(omap2_pm_init);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
new file mode 100644
index 000000000000..4474947ddd64
--- /dev/null
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -0,0 +1,606 @@
1/*
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>
30
31#include "cm.h"
32#include "cm-regbits-34xx.h"
33#include "prm-regbits-34xx.h"
34
35#include "prm.h"
36#include "pm.h"
37
38struct power_state {
39 struct powerdomain *pwrdm;
40 u32 next_state;
41 u32 saved_state;
42 struct list_head node;
43};
44
45static LIST_HEAD(pwrst_list);
46
47static void (*_omap_sram_idle)(u32 *addr, int save_state);
48
49static struct powerdomain *mpu_pwrdm;
50
51/* PRCM Interrupt Handler for wakeups */
52static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
53{
54 u32 wkst, irqstatus_mpu;
55 u32 fclk, iclk;
56
57 /* WKUP */
58 wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
59 if (wkst) {
60 iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
61 fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
62 cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
63 cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
64 prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
65 while (prm_read_mod_reg(WKUP_MOD, PM_WKST))
66 cpu_relax();
67 cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
68 cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
69 }
70
71 /* CORE */
72 wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
73 if (wkst) {
74 iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
75 fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
76 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
77 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
78 prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
79 while (prm_read_mod_reg(CORE_MOD, PM_WKST1))
80 cpu_relax();
81 cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
82 cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
83 }
84 wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
85 if (wkst) {
86 iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
87 fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
88 cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
89 cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
90 prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
91 while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3))
92 cpu_relax();
93 cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
94 cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
95 }
96
97 /* PER */
98 wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
99 if (wkst) {
100 iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
101 fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
102 cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
103 cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
104 prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
105 while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST))
106 cpu_relax();
107 cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
108 cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
109 }
110
111 if (omap_rev() > OMAP3430_REV_ES1_0) {
112 /* USBHOST */
113 wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
114 if (wkst) {
115 iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
116 CM_ICLKEN);
117 fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
118 CM_FCLKEN);
119 cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
120 CM_ICLKEN);
121 cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
122 CM_FCLKEN);
123 prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
124 PM_WKST);
125 while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
126 PM_WKST))
127 cpu_relax();
128 cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
129 CM_ICLKEN);
130 cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
131 CM_FCLKEN);
132 }
133 }
134
135 irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
136 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
137 prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
138 OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
139
140 while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET))
141 cpu_relax();
142
143 return IRQ_HANDLED;
144}
145
146static void omap_sram_idle(void)
147{
148 /* Variable to tell what needs to be saved and restored
149 * in omap_sram_idle*/
150 /* save_state = 0 => Nothing to save and restored */
151 /* save_state = 1 => Only L1 and logic lost */
152 /* save_state = 2 => Only L2 lost */
153 /* save_state = 3 => L1, L2 and logic lost */
154 int save_state = 0, mpu_next_state;
155
156 if (!_omap_sram_idle)
157 return;
158
159 mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
160 switch (mpu_next_state) {
161 case PWRDM_POWER_RET:
162 /* No need to save context */
163 save_state = 0;
164 break;
165 default:
166 /* Invalid state */
167 printk(KERN_ERR "Invalid mpu state in sram_idle\n");
168 return;
169 }
170 omap2_gpio_prepare_for_retention();
171
172 _omap_sram_idle(NULL, save_state);
173 cpu_init();
174
175 omap2_gpio_resume_after_retention();
176}
177
178/*
179 * Check if functional clocks are enabled before entering
180 * sleep. This function could be behind CONFIG_PM_DEBUG
181 * when all drivers are configuring their sysconfig registers
182 * properly and using their clocks properly.
183 */
184static int omap3_fclks_active(void)
185{
186 u32 fck_core1 = 0, fck_core3 = 0, fck_sgx = 0, fck_dss = 0,
187 fck_cam = 0, fck_per = 0, fck_usbhost = 0;
188
189 fck_core1 = cm_read_mod_reg(CORE_MOD,
190 CM_FCLKEN1);
191 if (omap_rev() > OMAP3430_REV_ES1_0) {
192 fck_core3 = cm_read_mod_reg(CORE_MOD,
193 OMAP3430ES2_CM_FCLKEN3);
194 fck_sgx = cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
195 CM_FCLKEN);
196 fck_usbhost = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
197 CM_FCLKEN);
198 } else
199 fck_sgx = cm_read_mod_reg(GFX_MOD,
200 OMAP3430ES2_CM_FCLKEN3);
201 fck_dss = cm_read_mod_reg(OMAP3430_DSS_MOD,
202 CM_FCLKEN);
203 fck_cam = cm_read_mod_reg(OMAP3430_CAM_MOD,
204 CM_FCLKEN);
205 fck_per = cm_read_mod_reg(OMAP3430_PER_MOD,
206 CM_FCLKEN);
207 if (fck_core1 | fck_core3 | fck_sgx | fck_dss |
208 fck_cam | fck_per | fck_usbhost)
209 return 1;
210 return 0;
211}
212
213static int omap3_can_sleep(void)
214{
215 if (omap3_fclks_active())
216 return 0;
217 return 1;
218}
219
220/* This sets pwrdm state (other than mpu & core. Currently only ON &
221 * RET are supported. Function is assuming that clkdm doesn't have
222 * hw_sup mode enabled. */
223static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
224{
225 u32 cur_state;
226 int sleep_switch = 0;
227 int ret = 0;
228
229 if (pwrdm == NULL || IS_ERR(pwrdm))
230 return -EINVAL;
231
232 while (!(pwrdm->pwrsts & (1 << state))) {
233 if (state == PWRDM_POWER_OFF)
234 return ret;
235 state--;
236 }
237
238 cur_state = pwrdm_read_next_pwrst(pwrdm);
239 if (cur_state == state)
240 return ret;
241
242 if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
243 omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
244 sleep_switch = 1;
245 pwrdm_wait_transition(pwrdm);
246 }
247
248 ret = pwrdm_set_next_pwrst(pwrdm, state);
249 if (ret) {
250 printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
251 pwrdm->name);
252 goto err;
253 }
254
255 if (sleep_switch) {
256 omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
257 pwrdm_wait_transition(pwrdm);
258 }
259
260err:
261 return ret;
262}
263
264static void omap3_pm_idle(void)
265{
266 local_irq_disable();
267 local_fiq_disable();
268
269 if (!omap3_can_sleep())
270 goto out;
271
272 if (omap_irq_pending())
273 goto out;
274
275 omap_sram_idle();
276
277out:
278 local_fiq_enable();
279 local_irq_enable();
280}
281
282static int omap3_pm_prepare(void)
283{
284 disable_hlt();
285 return 0;
286}
287
288static int omap3_pm_suspend(void)
289{
290 struct power_state *pwrst;
291 int state, ret = 0;
292
293 /* Read current next_pwrsts */
294 list_for_each_entry(pwrst, &pwrst_list, node)
295 pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm);
296 /* Set ones wanted by suspend */
297 list_for_each_entry(pwrst, &pwrst_list, node) {
298 if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state))
299 goto restore;
300 if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm))
301 goto restore;
302 }
303
304 omap_sram_idle();
305
306restore:
307 /* Restore next_pwrsts */
308 list_for_each_entry(pwrst, &pwrst_list, node) {
309 set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state);
310 state = pwrdm_read_prev_pwrst(pwrst->pwrdm);
311 if (state > pwrst->next_state) {
312 printk(KERN_INFO "Powerdomain (%s) didn't enter "
313 "target state %d\n",
314 pwrst->pwrdm->name, pwrst->next_state);
315 ret = -1;
316 }
317 }
318 if (ret)
319 printk(KERN_ERR "Could not enter target state in pm_suspend\n");
320 else
321 printk(KERN_INFO "Successfully put all powerdomains "
322 "to target state\n");
323
324 return ret;
325}
326
327static int omap3_pm_enter(suspend_state_t state)
328{
329 int ret = 0;
330
331 switch (state) {
332 case PM_SUSPEND_STANDBY:
333 case PM_SUSPEND_MEM:
334 ret = omap3_pm_suspend();
335 break;
336 default:
337 ret = -EINVAL;
338 }
339
340 return ret;
341}
342
343static void omap3_pm_finish(void)
344{
345 enable_hlt();
346}
347
348static struct platform_suspend_ops omap_pm_ops = {
349 .prepare = omap3_pm_prepare,
350 .enter = omap3_pm_enter,
351 .finish = omap3_pm_finish,
352 .valid = suspend_valid_only_mem,
353};
354
355static void __init prcm_setup_regs(void)
356{
357 /* reset modem */
358 prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
359 OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
360 CORE_MOD, RM_RSTCTRL);
361 prm_write_mod_reg(0, CORE_MOD, RM_RSTCTRL);
362
363 /* XXX Reset all wkdeps. This should be done when initializing
364 * powerdomains */
365 prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
366 prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
367 prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
368 prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
369 prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
370 prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
371 if (omap_rev() > OMAP3430_REV_ES1_0) {
372 prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP);
373 prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP);
374 } else
375 prm_write_mod_reg(0, GFX_MOD, PM_WKDEP);
376
377 /*
378 * Enable interface clock autoidle for all modules.
379 * Note that in the long run this should be done by clockfw
380 */
381 cm_write_mod_reg(
382 OMAP3430ES2_AUTO_MMC3 |
383 OMAP3430ES2_AUTO_ICR |
384 OMAP3430_AUTO_AES2 |
385 OMAP3430_AUTO_SHA12 |
386 OMAP3430_AUTO_DES2 |
387 OMAP3430_AUTO_MMC2 |
388 OMAP3430_AUTO_MMC1 |
389 OMAP3430_AUTO_MSPRO |
390 OMAP3430_AUTO_HDQ |
391 OMAP3430_AUTO_MCSPI4 |
392 OMAP3430_AUTO_MCSPI3 |
393 OMAP3430_AUTO_MCSPI2 |
394 OMAP3430_AUTO_MCSPI1 |
395 OMAP3430_AUTO_I2C3 |
396 OMAP3430_AUTO_I2C2 |
397 OMAP3430_AUTO_I2C1 |
398 OMAP3430_AUTO_UART2 |
399 OMAP3430_AUTO_UART1 |
400 OMAP3430_AUTO_GPT11 |
401 OMAP3430_AUTO_GPT10 |
402 OMAP3430_AUTO_MCBSP5 |
403 OMAP3430_AUTO_MCBSP1 |
404 OMAP3430ES1_AUTO_FAC | /* This is es1 only */
405 OMAP3430_AUTO_MAILBOXES |
406 OMAP3430_AUTO_OMAPCTRL |
407 OMAP3430ES1_AUTO_FSHOSTUSB |
408 OMAP3430_AUTO_HSOTGUSB |
409 OMAP3430ES1_AUTO_D2D | /* This is es1 only */
410 OMAP3430_AUTO_SSI,
411 CORE_MOD, CM_AUTOIDLE1);
412
413 cm_write_mod_reg(
414 OMAP3430_AUTO_PKA |
415 OMAP3430_AUTO_AES1 |
416 OMAP3430_AUTO_RNG |
417 OMAP3430_AUTO_SHA11 |
418 OMAP3430_AUTO_DES1,
419 CORE_MOD, CM_AUTOIDLE2);
420
421 if (omap_rev() > OMAP3430_REV_ES1_0) {
422 cm_write_mod_reg(
423 OMAP3430ES2_AUTO_USBTLL,
424 CORE_MOD, CM_AUTOIDLE3);
425 }
426
427 cm_write_mod_reg(
428 OMAP3430_AUTO_WDT2 |
429 OMAP3430_AUTO_WDT1 |
430 OMAP3430_AUTO_GPIO1 |
431 OMAP3430_AUTO_32KSYNC |
432 OMAP3430_AUTO_GPT12 |
433 OMAP3430_AUTO_GPT1 ,
434 WKUP_MOD, CM_AUTOIDLE);
435
436 cm_write_mod_reg(
437 OMAP3430_AUTO_DSS,
438 OMAP3430_DSS_MOD,
439 CM_AUTOIDLE);
440
441 cm_write_mod_reg(
442 OMAP3430_AUTO_CAM,
443 OMAP3430_CAM_MOD,
444 CM_AUTOIDLE);
445
446 cm_write_mod_reg(
447 OMAP3430_AUTO_GPIO6 |
448 OMAP3430_AUTO_GPIO5 |
449 OMAP3430_AUTO_GPIO4 |
450 OMAP3430_AUTO_GPIO3 |
451 OMAP3430_AUTO_GPIO2 |
452 OMAP3430_AUTO_WDT3 |
453 OMAP3430_AUTO_UART3 |
454 OMAP3430_AUTO_GPT9 |
455 OMAP3430_AUTO_GPT8 |
456 OMAP3430_AUTO_GPT7 |
457 OMAP3430_AUTO_GPT6 |
458 OMAP3430_AUTO_GPT5 |
459 OMAP3430_AUTO_GPT4 |
460 OMAP3430_AUTO_GPT3 |
461 OMAP3430_AUTO_GPT2 |
462 OMAP3430_AUTO_MCBSP4 |
463 OMAP3430_AUTO_MCBSP3 |
464 OMAP3430_AUTO_MCBSP2,
465 OMAP3430_PER_MOD,
466 CM_AUTOIDLE);
467
468 if (omap_rev() > OMAP3430_REV_ES1_0) {
469 cm_write_mod_reg(
470 OMAP3430ES2_AUTO_USBHOST,
471 OMAP3430ES2_USBHOST_MOD,
472 CM_AUTOIDLE);
473 }
474
475 /*
476 * Set all plls to autoidle. This is needed until autoidle is
477 * enabled by clockfw
478 */
479 cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT,
480 OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
481 cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT,
482 MPU_MOD,
483 CM_AUTOIDLE2);
484 cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) |
485 (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT),
486 PLL_MOD,
487 CM_AUTOIDLE);
488 cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT,
489 PLL_MOD,
490 CM_AUTOIDLE2);
491
492 /*
493 * Enable control of expternal oscillator through
494 * sys_clkreq. In the long run clock framework should
495 * take care of this.
496 */
497 prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK,
498 1 << OMAP_AUTOEXTCLKMODE_SHIFT,
499 OMAP3430_GR_MOD,
500 OMAP3_PRM_CLKSRC_CTRL_OFFSET);
501
502 /* setup wakup source */
503 prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 |
504 OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12,
505 WKUP_MOD, PM_WKEN);
506 /* No need to write EN_IO, that is always enabled */
507 prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 |
508 OMAP3430_EN_GPT12,
509 WKUP_MOD, OMAP3430_PM_MPUGRPSEL);
510 /* For some reason IO doesn't generate wakeup event even if
511 * it is selected to mpu wakeup goup */
512 prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
513 OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
514}
515
516static int __init pwrdms_setup(struct powerdomain *pwrdm)
517{
518 struct power_state *pwrst;
519
520 if (!pwrdm->pwrsts)
521 return 0;
522
523 pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
524 if (!pwrst)
525 return -ENOMEM;
526 pwrst->pwrdm = pwrdm;
527 pwrst->next_state = PWRDM_POWER_RET;
528 list_add(&pwrst->node, &pwrst_list);
529
530 if (pwrdm_has_hdwr_sar(pwrdm))
531 pwrdm_enable_hdwr_sar(pwrdm);
532
533 return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
534}
535
536/*
537 * Enable hw supervised mode for all clockdomains if it's
538 * supported. Initiate sleep transition for other clockdomains, if
539 * they are not used
540 */
541static int __init clkdms_setup(struct clockdomain *clkdm)
542{
543 if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
544 omap2_clkdm_allow_idle(clkdm);
545 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
546 atomic_read(&clkdm->usecount) == 0)
547 omap2_clkdm_sleep(clkdm);
548 return 0;
549}
550
551int __init omap3_pm_init(void)
552{
553 struct power_state *pwrst, *tmp;
554 int ret;
555
556 if (!cpu_is_omap34xx())
557 return -ENODEV;
558
559 printk(KERN_ERR "Power Management for TI OMAP3.\n");
560
561 /* XXX prcm_setup_regs needs to be before enabling hw
562 * supervised mode for powerdomains */
563 prcm_setup_regs();
564
565 ret = request_irq(INT_34XX_PRCM_MPU_IRQ,
566 (irq_handler_t)prcm_interrupt_handler,
567 IRQF_DISABLED, "prcm", NULL);
568 if (ret) {
569 printk(KERN_ERR "request_irq failed to register for 0x%x\n",
570 INT_34XX_PRCM_MPU_IRQ);
571 goto err1;
572 }
573
574 ret = pwrdm_for_each(pwrdms_setup);
575 if (ret) {
576 printk(KERN_ERR "Failed to setup powerdomains\n");
577 goto err2;
578 }
579
580 (void) clkdm_for_each(clkdms_setup);
581
582 mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
583 if (mpu_pwrdm == NULL) {
584 printk(KERN_ERR "Failed to get mpu_pwrdm\n");
585 goto err2;
586 }
587
588 _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
589 omap34xx_cpu_suspend_sz);
590
591 suspend_set_ops(&omap_pm_ops);
592
593 pm_idle = omap3_pm_idle;
594
595err1:
596 return ret;
597err2:
598 free_irq(INT_34XX_PRCM_MPU_IRQ, NULL);
599 list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) {
600 list_del(&pwrst->node);
601 kfree(pwrst);
602 }
603 return ret;
604}
605
606late_initcall(omap3_pm_init);
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 812d50ee495d..cb1ae84e0925 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -276,6 +276,8 @@
276/* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */ 276/* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
277#define OMAP3430_EN_GPIO1 (1 << 3) 277#define OMAP3430_EN_GPIO1 (1 << 3)
278#define OMAP3430_EN_GPIO1_SHIFT 3 278#define OMAP3430_EN_GPIO1_SHIFT 3
279#define OMAP3430_EN_GPT12 (1 << 1)
280#define OMAP3430_EN_GPT12_SHIFT 1
279#define OMAP3430_EN_GPT1 (1 << 0) 281#define OMAP3430_EN_GPT1 (1 << 0)
280#define OMAP3430_EN_GPT1_SHIFT 0 282#define OMAP3430_EN_GPT1_SHIFT 0
281 283
diff --git a/arch/arm/mach-omap2/sdrc.c b/arch/arm/mach-omap2/sdrc.c
index d62e4e10d4b0..2045441e8385 100644
--- a/arch/arm/mach-omap2/sdrc.c
+++ b/arch/arm/mach-omap2/sdrc.c
@@ -60,9 +60,12 @@ struct omap_sdrc_params *omap2_sdrc_get_params(unsigned long r)
60{ 60{
61 struct omap_sdrc_params *sp; 61 struct omap_sdrc_params *sp;
62 62
63 if (!sdrc_init_params)
64 return NULL;
65
63 sp = sdrc_init_params; 66 sp = sdrc_init_params;
64 67
65 while (sp->rate != r) 68 while (sp->rate && sp->rate != r)
66 sp++; 69 sp++;
67 70
68 if (!sp->rate) 71 if (!sp->rate)
diff --git a/arch/arm/mach-omap2/sleep24xx.S b/arch/arm/mach-omap2/sleep24xx.S
index bf9e96105e11..130aadbfa083 100644
--- a/arch/arm/mach-omap2/sleep24xx.S
+++ b/arch/arm/mach-omap2/sleep24xx.S
@@ -28,7 +28,6 @@
28#include <linux/linkage.h> 28#include <linux/linkage.h>
29#include <asm/assembler.h> 29#include <asm/assembler.h>
30#include <mach/io.h> 30#include <mach/io.h>
31#include <mach/pm.h>
32 31
33#include <mach/omap24xx.h> 32#include <mach/omap24xx.h>
34 33
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
new file mode 100644
index 000000000000..e5e2553e79a6
--- /dev/null
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -0,0 +1,436 @@
1/*
2 * linux/arch/arm/mach-omap2/sleep.S
3 *
4 * (C) Copyright 2007
5 * Texas Instruments
6 * Karthik Dasu <karthik-dp@ti.com>
7 *
8 * (C) Copyright 2004
9 * Texas Instruments, <www.ti.com>
10 * Richard Woodruff <r-woodruff2@ti.com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27#include <linux/linkage.h>
28#include <asm/assembler.h>
29#include <mach/io.h>
30#include <mach/control.h>
31
32#include "prm.h"
33#include "sdrc.h"
34
35#define PM_PREPWSTST_CORE_V OMAP34XX_PRM_REGADDR(CORE_MOD, \
36 OMAP3430_PM_PREPWSTST)
37#define PM_PREPWSTST_MPU_V OMAP34XX_PRM_REGADDR(MPU_MOD, \
38 OMAP3430_PM_PREPWSTST)
39#define PM_PWSTCTRL_MPU_P OMAP34XX_PRM_REGADDR(MPU_MOD, PM_PWSTCTRL)
40#define SCRATCHPAD_MEM_OFFS 0x310 /* Move this as correct place is
41 * available */
42#define SCRATCHPAD_BASE_P OMAP343X_CTRL_REGADDR(\
43 OMAP343X_CONTROL_MEM_WKUP +\
44 SCRATCHPAD_MEM_OFFS)
45#define SDRC_POWER_V OMAP34XX_SDRC_REGADDR(SDRC_POWER)
46
47 .text
48/* Function call to get the restore pointer for resume from OFF */
49ENTRY(get_restore_pointer)
50 stmfd sp!, {lr} @ save registers on stack
51 adr r0, restore
52 ldmfd sp!, {pc} @ restore regs and return
53ENTRY(get_restore_pointer_sz)
54 .word . - get_restore_pointer_sz
55/*
56 * Forces OMAP into idle state
57 *
58 * omap34xx_suspend() - This bit of code just executes the WFI
59 * for normal idles.
60 *
61 * Note: This code get's copied to internal SRAM at boot. When the OMAP
62 * wakes up it continues execution at the point it went to sleep.
63 */
64ENTRY(omap34xx_cpu_suspend)
65 stmfd sp!, {r0-r12, lr} @ save registers on stack
66loop:
67 /*b loop*/ @Enable to debug by stepping through code
68 /* r0 contains restore pointer in sdram */
69 /* r1 contains information about saving context */
70 ldr r4, sdrc_power @ read the SDRC_POWER register
71 ldr r5, [r4] @ read the contents of SDRC_POWER
72 orr r5, r5, #0x40 @ enable self refresh on idle req
73 str r5, [r4] @ write back to SDRC_POWER register
74
75 cmp r1, #0x0
76 /* If context save is required, do that and execute wfi */
77 bne save_context_wfi
78 /* Data memory barrier and Data sync barrier */
79 mov r1, #0
80 mcr p15, 0, r1, c7, c10, 4
81 mcr p15, 0, r1, c7, c10, 5
82
83 wfi @ wait for interrupt
84
85 nop
86 nop
87 nop
88 nop
89 nop
90 nop
91 nop
92 nop
93 nop
94 nop
95 bl i_dll_wait
96
97 ldmfd sp!, {r0-r12, pc} @ restore regs and return
98restore:
99 /* b restore*/ @ Enable to debug restore code
100 /* Check what was the reason for mpu reset and store the reason in r9*/
101 /* 1 - Only L1 and logic lost */
102 /* 2 - Only L2 lost - In this case, we wont be here */
103 /* 3 - Both L1 and L2 lost */
104 ldr r1, pm_pwstctrl_mpu
105 ldr r2, [r1]
106 and r2, r2, #0x3
107 cmp r2, #0x0 @ Check if target power state was OFF or RET
108 moveq r9, #0x3 @ MPU OFF => L1 and L2 lost
109 movne r9, #0x1 @ Only L1 and L2 lost => avoid L2 invalidation
110 bne logic_l1_restore
111 /* Execute smi to invalidate L2 cache */
112 mov r12, #0x1 @ set up to invalide L2
113smi: .word 0xE1600070 @ Call SMI monitor (smieq)
114logic_l1_restore:
115 mov r1, #0
116 /* Invalidate all instruction caches to PoU
117 * and flush branch target cache */
118 mcr p15, 0, r1, c7, c5, 0
119
120 ldr r4, scratchpad_base
121 ldr r3, [r4,#0xBC]
122 ldmia r3!, {r4-r6}
123 mov sp, r4
124 msr spsr_cxsf, r5
125 mov lr, r6
126
127 ldmia r3!, {r4-r9}
128 /* Coprocessor access Control Register */
129 mcr p15, 0, r4, c1, c0, 2
130
131 /* TTBR0 */
132 MCR p15, 0, r5, c2, c0, 0
133 /* TTBR1 */
134 MCR p15, 0, r6, c2, c0, 1
135 /* Translation table base control register */
136 MCR p15, 0, r7, c2, c0, 2
137 /*domain access Control Register */
138 MCR p15, 0, r8, c3, c0, 0
139 /* data fault status Register */
140 MCR p15, 0, r9, c5, c0, 0
141
142 ldmia r3!,{r4-r8}
143 /* instruction fault status Register */
144 MCR p15, 0, r4, c5, c0, 1
145 /*Data Auxiliary Fault Status Register */
146 MCR p15, 0, r5, c5, c1, 0
147 /*Instruction Auxiliary Fault Status Register*/
148 MCR p15, 0, r6, c5, c1, 1
149 /*Data Fault Address Register */
150 MCR p15, 0, r7, c6, c0, 0
151 /*Instruction Fault Address Register*/
152 MCR p15, 0, r8, c6, c0, 2
153 ldmia r3!,{r4-r7}
154
155 /* user r/w thread and process ID */
156 MCR p15, 0, r4, c13, c0, 2
157 /* user ro thread and process ID */
158 MCR p15, 0, r5, c13, c0, 3
159 /*Privileged only thread and process ID */
160 MCR p15, 0, r6, c13, c0, 4
161 /* cache size selection */
162 MCR p15, 2, r7, c0, c0, 0
163 ldmia r3!,{r4-r8}
164 /* Data TLB lockdown registers */
165 MCR p15, 0, r4, c10, c0, 0
166 /* Instruction TLB lockdown registers */
167 MCR p15, 0, r5, c10, c0, 1
168 /* Secure or Nonsecure Vector Base Address */
169 MCR p15, 0, r6, c12, c0, 0
170 /* FCSE PID */
171 MCR p15, 0, r7, c13, c0, 0
172 /* Context PID */
173 MCR p15, 0, r8, c13, c0, 1
174
175 ldmia r3!,{r4-r5}
176 /* primary memory remap register */
177 MCR p15, 0, r4, c10, c2, 0
178 /*normal memory remap register */
179 MCR p15, 0, r5, c10, c2, 1
180
181 /* Restore cpsr */
182 ldmia r3!,{r4} /*load CPSR from SDRAM*/
183 msr cpsr, r4 /*store cpsr */
184
185 /* Enabling MMU here */
186 mrc p15, 0, r7, c2, c0, 2 /* Read TTBRControl */
187 /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1*/
188 and r7, #0x7
189 cmp r7, #0x0
190 beq usettbr0
191ttbr_error:
192 /* More work needs to be done to support N[0:2] value other than 0
193 * So looping here so that the error can be detected
194 */
195 b ttbr_error
196usettbr0:
197 mrc p15, 0, r2, c2, c0, 0
198 ldr r5, ttbrbit_mask
199 and r2, r5
200 mov r4, pc
201 ldr r5, table_index_mask
202 and r4, r5 /* r4 = 31 to 20 bits of pc */
203 /* Extract the value to be written to table entry */
204 ldr r1, table_entry
205 add r1, r1, r4 /* r1 has value to be written to table entry*/
206 /* Getting the address of table entry to modify */
207 lsr r4, #18
208 add r2, r4 /* r2 has the location which needs to be modified */
209 /* Storing previous entry of location being modified */
210 ldr r5, scratchpad_base
211 ldr r4, [r2]
212 str r4, [r5, #0xC0]
213 /* Modify the table entry */
214 str r1, [r2]
215 /* Storing address of entry being modified
216 * - will be restored after enabling MMU */
217 ldr r5, scratchpad_base
218 str r2, [r5, #0xC4]
219
220 mov r0, #0
221 mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
222 mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
223 mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
224 mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
225 /* Restore control register but dont enable caches here*/
226 /* Caches will be enabled after restoring MMU table entry */
227 ldmia r3!, {r4}
228 /* Store previous value of control register in scratchpad */
229 str r4, [r5, #0xC8]
230 ldr r2, cache_pred_disable_mask
231 and r4, r2
232 mcr p15, 0, r4, c1, c0, 0
233
234 ldmfd sp!, {r0-r12, pc} @ restore regs and return
235save_context_wfi:
236 /*b save_context_wfi*/ @ enable to debug save code
237 mov r8, r0 /* Store SDRAM address in r8 */
238 /* Check what that target sleep state is:stored in r1*/
239 /* 1 - Only L1 and logic lost */
240 /* 2 - Only L2 lost */
241 /* 3 - Both L1 and L2 lost */
242 cmp r1, #0x2 /* Only L2 lost */
243 beq clean_l2
244 cmp r1, #0x1 /* L2 retained */
245 /* r9 stores whether to clean L2 or not*/
246 moveq r9, #0x0 /* Dont Clean L2 */
247 movne r9, #0x1 /* Clean L2 */
248l1_logic_lost:
249 /* Store sp and spsr to SDRAM */
250 mov r4, sp
251 mrs r5, spsr
252 mov r6, lr
253 stmia r8!, {r4-r6}
254 /* Save all ARM registers */
255 /* Coprocessor access control register */
256 mrc p15, 0, r6, c1, c0, 2
257 stmia r8!, {r6}
258 /* TTBR0, TTBR1 and Translation table base control */
259 mrc p15, 0, r4, c2, c0, 0
260 mrc p15, 0, r5, c2, c0, 1
261 mrc p15, 0, r6, c2, c0, 2
262 stmia r8!, {r4-r6}
263 /* Domain access control register, data fault status register,
264 and instruction fault status register */
265 mrc p15, 0, r4, c3, c0, 0
266 mrc p15, 0, r5, c5, c0, 0
267 mrc p15, 0, r6, c5, c0, 1
268 stmia r8!, {r4-r6}
269 /* Data aux fault status register, instruction aux fault status,
270 datat fault address register and instruction fault address register*/
271 mrc p15, 0, r4, c5, c1, 0
272 mrc p15, 0, r5, c5, c1, 1
273 mrc p15, 0, r6, c6, c0, 0
274 mrc p15, 0, r7, c6, c0, 2
275 stmia r8!, {r4-r7}
276 /* user r/w thread and process ID, user r/o thread and process ID,
277 priv only thread and process ID, cache size selection */
278 mrc p15, 0, r4, c13, c0, 2
279 mrc p15, 0, r5, c13, c0, 3
280 mrc p15, 0, r6, c13, c0, 4
281 mrc p15, 2, r7, c0, c0, 0
282 stmia r8!, {r4-r7}
283 /* Data TLB lockdown, instruction TLB lockdown registers */
284 mrc p15, 0, r5, c10, c0, 0
285 mrc p15, 0, r6, c10, c0, 1
286 stmia r8!, {r5-r6}
287 /* Secure or non secure vector base address, FCSE PID, Context PID*/
288 mrc p15, 0, r4, c12, c0, 0
289 mrc p15, 0, r5, c13, c0, 0
290 mrc p15, 0, r6, c13, c0, 1
291 stmia r8!, {r4-r6}
292 /* Primary remap, normal remap registers */
293 mrc p15, 0, r4, c10, c2, 0
294 mrc p15, 0, r5, c10, c2, 1
295 stmia r8!,{r4-r5}
296
297 /* Store current cpsr*/
298 mrs r2, cpsr
299 stmia r8!, {r2}
300
301 mrc p15, 0, r4, c1, c0, 0
302 /* save control register */
303 stmia r8!, {r4}
304clean_caches:
305 /* Clean Data or unified cache to POU*/
306 /* How to invalidate only L1 cache???? - #FIX_ME# */
307 /* mcr p15, 0, r11, c7, c11, 1 */
308 cmp r9, #1 /* Check whether L2 inval is required or not*/
309 bne skip_l2_inval
310clean_l2:
311 /* read clidr */
312 mrc p15, 1, r0, c0, c0, 1
313 /* extract loc from clidr */
314 ands r3, r0, #0x7000000
315 /* left align loc bit field */
316 mov r3, r3, lsr #23
317 /* if loc is 0, then no need to clean */
318 beq finished
319 /* start clean at cache level 0 */
320 mov r10, #0
321loop1:
322 /* work out 3x current cache level */
323 add r2, r10, r10, lsr #1
324 /* extract cache type bits from clidr*/
325 mov r1, r0, lsr r2
326 /* mask of the bits for current cache only */
327 and r1, r1, #7
328 /* see what cache we have at this level */
329 cmp r1, #2
330 /* skip if no cache, or just i-cache */
331 blt skip
332 /* select current cache level in cssr */
333 mcr p15, 2, r10, c0, c0, 0
334 /* isb to sych the new cssr&csidr */
335 isb
336 /* read the new csidr */
337 mrc p15, 1, r1, c0, c0, 0
338 /* extract the length of the cache lines */
339 and r2, r1, #7
340 /* add 4 (line length offset) */
341 add r2, r2, #4
342 ldr r4, assoc_mask
343 /* find maximum number on the way size */
344 ands r4, r4, r1, lsr #3
345 /* find bit position of way size increment */
346 clz r5, r4
347 ldr r7, numset_mask
348 /* extract max number of the index size*/
349 ands r7, r7, r1, lsr #13
350loop2:
351 mov r9, r4
352 /* create working copy of max way size*/
353loop3:
354 /* factor way and cache number into r11 */
355 orr r11, r10, r9, lsl r5
356 /* factor index number into r11 */
357 orr r11, r11, r7, lsl r2
358 /*clean & invalidate by set/way */
359 mcr p15, 0, r11, c7, c10, 2
360 /* decrement the way*/
361 subs r9, r9, #1
362 bge loop3
363 /*decrement the index */
364 subs r7, r7, #1
365 bge loop2
366skip:
367 add r10, r10, #2
368 /* increment cache number */
369 cmp r3, r10
370 bgt loop1
371finished:
372 /*swith back to cache level 0 */
373 mov r10, #0
374 /* select current cache level in cssr */
375 mcr p15, 2, r10, c0, c0, 0
376 isb
377skip_l2_inval:
378 /* Data memory barrier and Data sync barrier */
379 mov r1, #0
380 mcr p15, 0, r1, c7, c10, 4
381 mcr p15, 0, r1, c7, c10, 5
382
383 wfi @ wait for interrupt
384 nop
385 nop
386 nop
387 nop
388 nop
389 nop
390 nop
391 nop
392 nop
393 nop
394 bl i_dll_wait
395 /* restore regs and return */
396 ldmfd sp!, {r0-r12, pc}
397
398i_dll_wait:
399 ldr r4, clk_stabilize_delay
400
401i_dll_delay:
402 subs r4, r4, #0x1
403 bne i_dll_delay
404 ldr r4, sdrc_power
405 ldr r5, [r4]
406 bic r5, r5, #0x40
407 str r5, [r4]
408 bx lr
409pm_prepwstst_core:
410 .word PM_PREPWSTST_CORE_V
411pm_prepwstst_mpu:
412 .word PM_PREPWSTST_MPU_V
413pm_pwstctrl_mpu:
414 .word PM_PWSTCTRL_MPU_P
415scratchpad_base:
416 .word SCRATCHPAD_BASE_P
417sdrc_power:
418 .word SDRC_POWER_V
419context_mem:
420 .word 0x803E3E14
421clk_stabilize_delay:
422 .word 0x000001FF
423assoc_mask:
424 .word 0x3ff
425numset_mask:
426 .word 0x7fff
427ttbrbit_mask:
428 .word 0xFFFFC000
429table_index_mask:
430 .word 0xFFF00000
431table_entry:
432 .word 0x00000C02
433cache_pred_disable_mask:
434 .word 0xFFFFE7FB
435ENTRY(omap34xx_cpu_suspend_sz)
436 .word . - omap34xx_cpu_suspend
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 34a56a136efd..215d463b70e3 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -28,7 +28,6 @@
28 28
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <mach/irqs.h> 30#include <mach/irqs.h>
31#include <mach/pm.h>
32#include <mach/mux.h> 31#include <mach/mux.h>
33#include <mach/usb.h> 32#include <mach/usb.h>
34 33
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 9dd68fafb374..4bc9ed701dc4 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -171,7 +171,7 @@ endchoice
171 171
172config OMAP_SERIAL_WAKE 172config OMAP_SERIAL_WAKE
173 bool "Enable wake-up events for serial ports" 173 bool "Enable wake-up events for serial ports"
174 depends on OMAP_MUX 174 depends on ARCH_OMAP1 && OMAP_MUX
175 default y 175 default y
176 help 176 help
177 Select this option if you want to have your system wake up 177 Select this option if you want to have your system wake up
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 70b68ef83201..86ee23d6f73c 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -11,7 +11,6 @@
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/delay.h> 13#include <linux/delay.h>
14#include <linux/pm.h>
15#include <linux/console.h> 14#include <linux/console.h>
16#include <linux/serial.h> 15#include <linux/serial.h>
17#include <linux/tty.h> 16#include <linux/tty.h>