aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
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/mach-omap2
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/mach-omap2')
-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
11 files changed, 1789 insertions, 115 deletions
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