Commit 8e2efde9f1ba2fb918245f9419246e4e59b42a11
Committed by
Kevin Hilman
1 parent
d6290a3ead
Exists in
master
and in
4 other branches
OMAP3: PM: Add milliseconds interface to suspend wakeup timer
Millisecond resolution is possible and there are use cases for it (automatic testing). Seconds-based interface is preserved for compatibility. Signed-off-by: Ari Kauppi <Ext-Ari.Kauppi@nokia.com> Reviewed-by: Phil Carmody <ext-phil.2.carmody@nokia.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Showing 3 changed files with 14 additions and 7 deletions Inline Diff
arch/arm/mach-omap2/pm-debug.c
1 | /* | 1 | /* |
2 | * OMAP Power Management debug routines | 2 | * OMAP Power Management debug routines |
3 | * | 3 | * |
4 | * Copyright (C) 2005 Texas Instruments, Inc. | 4 | * Copyright (C) 2005 Texas Instruments, Inc. |
5 | * Copyright (C) 2006-2008 Nokia Corporation | 5 | * Copyright (C) 2006-2008 Nokia Corporation |
6 | * | 6 | * |
7 | * Written by: | 7 | * Written by: |
8 | * Richard Woodruff <r-woodruff2@ti.com> | 8 | * Richard Woodruff <r-woodruff2@ti.com> |
9 | * Tony Lindgren | 9 | * Tony Lindgren |
10 | * Juha Yrjola | 10 | * Juha Yrjola |
11 | * Amit Kucheria <amit.kucheria@nokia.com> | 11 | * Amit Kucheria <amit.kucheria@nokia.com> |
12 | * Igor Stoppa <igor.stoppa@nokia.com> | 12 | * Igor Stoppa <igor.stoppa@nokia.com> |
13 | * Jouni Hogander | 13 | * Jouni Hogander |
14 | * | 14 | * |
15 | * Based on pm.c for omap2 | 15 | * Based on pm.c for omap2 |
16 | * | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | 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 | 18 | * it under the terms of the GNU General Public License version 2 as |
19 | * published by the Free Software Foundation. | 19 | * published by the Free Software Foundation. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/err.h> | 25 | #include <linux/err.h> |
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | 29 | ||
30 | #include <plat/clock.h> | 30 | #include <plat/clock.h> |
31 | #include <plat/board.h> | 31 | #include <plat/board.h> |
32 | #include <plat/powerdomain.h> | 32 | #include <plat/powerdomain.h> |
33 | #include <plat/clockdomain.h> | 33 | #include <plat/clockdomain.h> |
34 | 34 | ||
35 | #include "prm.h" | 35 | #include "prm.h" |
36 | #include "cm.h" | 36 | #include "cm.h" |
37 | #include "pm.h" | 37 | #include "pm.h" |
38 | 38 | ||
39 | int omap2_pm_debug; | 39 | int omap2_pm_debug; |
40 | 40 | ||
41 | #define DUMP_PRM_MOD_REG(mod, reg) \ | 41 | #define DUMP_PRM_MOD_REG(mod, reg) \ |
42 | regs[reg_count].name = #mod "." #reg; \ | 42 | regs[reg_count].name = #mod "." #reg; \ |
43 | regs[reg_count++].val = prm_read_mod_reg(mod, reg) | 43 | regs[reg_count++].val = prm_read_mod_reg(mod, reg) |
44 | #define DUMP_CM_MOD_REG(mod, reg) \ | 44 | #define DUMP_CM_MOD_REG(mod, reg) \ |
45 | regs[reg_count].name = #mod "." #reg; \ | 45 | regs[reg_count].name = #mod "." #reg; \ |
46 | regs[reg_count++].val = cm_read_mod_reg(mod, reg) | 46 | regs[reg_count++].val = cm_read_mod_reg(mod, reg) |
47 | #define DUMP_PRM_REG(reg) \ | 47 | #define DUMP_PRM_REG(reg) \ |
48 | regs[reg_count].name = #reg; \ | 48 | regs[reg_count].name = #reg; \ |
49 | regs[reg_count++].val = __raw_readl(reg) | 49 | regs[reg_count++].val = __raw_readl(reg) |
50 | #define DUMP_CM_REG(reg) \ | 50 | #define DUMP_CM_REG(reg) \ |
51 | regs[reg_count].name = #reg; \ | 51 | regs[reg_count].name = #reg; \ |
52 | regs[reg_count++].val = __raw_readl(reg) | 52 | regs[reg_count++].val = __raw_readl(reg) |
53 | #define DUMP_INTC_REG(reg, off) \ | 53 | #define DUMP_INTC_REG(reg, off) \ |
54 | regs[reg_count].name = #reg; \ | 54 | regs[reg_count].name = #reg; \ |
55 | regs[reg_count++].val = \ | 55 | regs[reg_count++].val = \ |
56 | __raw_readl(OMAP2_L4_IO_ADDRESS(0x480fe000 + (off))) | 56 | __raw_readl(OMAP2_L4_IO_ADDRESS(0x480fe000 + (off))) |
57 | 57 | ||
58 | void omap2_pm_dump(int mode, int resume, unsigned int us) | 58 | void omap2_pm_dump(int mode, int resume, unsigned int us) |
59 | { | 59 | { |
60 | struct reg { | 60 | struct reg { |
61 | const char *name; | 61 | const char *name; |
62 | u32 val; | 62 | u32 val; |
63 | } regs[32]; | 63 | } regs[32]; |
64 | int reg_count = 0, i; | 64 | int reg_count = 0, i; |
65 | const char *s1 = NULL, *s2 = NULL; | 65 | const char *s1 = NULL, *s2 = NULL; |
66 | 66 | ||
67 | if (!resume) { | 67 | if (!resume) { |
68 | #if 0 | 68 | #if 0 |
69 | /* MPU */ | 69 | /* MPU */ |
70 | DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET); | 70 | DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRM_IRQENABLE_MPU_OFFSET); |
71 | DUMP_CM_MOD_REG(MPU_MOD, OMAP2_CM_CLKSTCTRL); | 71 | DUMP_CM_MOD_REG(MPU_MOD, OMAP2_CM_CLKSTCTRL); |
72 | DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTCTRL); | 72 | DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTCTRL); |
73 | DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTST); | 73 | DUMP_PRM_MOD_REG(MPU_MOD, OMAP2_PM_PWSTST); |
74 | DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP); | 74 | DUMP_PRM_MOD_REG(MPU_MOD, PM_WKDEP); |
75 | #endif | 75 | #endif |
76 | #if 0 | 76 | #if 0 |
77 | /* INTC */ | 77 | /* INTC */ |
78 | DUMP_INTC_REG(INTC_MIR0, 0x0084); | 78 | DUMP_INTC_REG(INTC_MIR0, 0x0084); |
79 | DUMP_INTC_REG(INTC_MIR1, 0x00a4); | 79 | DUMP_INTC_REG(INTC_MIR1, 0x00a4); |
80 | DUMP_INTC_REG(INTC_MIR2, 0x00c4); | 80 | DUMP_INTC_REG(INTC_MIR2, 0x00c4); |
81 | #endif | 81 | #endif |
82 | #if 0 | 82 | #if 0 |
83 | DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1); | 83 | DUMP_CM_MOD_REG(CORE_MOD, CM_FCLKEN1); |
84 | if (cpu_is_omap24xx()) { | 84 | if (cpu_is_omap24xx()) { |
85 | DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2); | 85 | DUMP_CM_MOD_REG(CORE_MOD, OMAP24XX_CM_FCLKEN2); |
86 | DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, | 86 | DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, |
87 | OMAP2_PRCM_CLKEMUL_CTRL_OFFSET); | 87 | OMAP2_PRCM_CLKEMUL_CTRL_OFFSET); |
88 | DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, | 88 | DUMP_PRM_MOD_REG(OMAP24XX_GR_MOD, |
89 | OMAP2_PRCM_CLKSRC_CTRL_OFFSET); | 89 | OMAP2_PRCM_CLKSRC_CTRL_OFFSET); |
90 | } | 90 | } |
91 | DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN); | 91 | DUMP_CM_MOD_REG(WKUP_MOD, CM_FCLKEN); |
92 | DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1); | 92 | DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN1); |
93 | DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2); | 93 | DUMP_CM_MOD_REG(CORE_MOD, CM_ICLKEN2); |
94 | DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN); | 94 | DUMP_CM_MOD_REG(WKUP_MOD, CM_ICLKEN); |
95 | DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN); | 95 | DUMP_CM_MOD_REG(PLL_MOD, CM_CLKEN); |
96 | DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE); | 96 | DUMP_CM_MOD_REG(PLL_MOD, CM_AUTOIDLE); |
97 | DUMP_PRM_MOD_REG(CORE_MOD, OMAP2_PM_PWSTST); | 97 | DUMP_PRM_MOD_REG(CORE_MOD, OMAP2_PM_PWSTST); |
98 | #endif | 98 | #endif |
99 | #if 0 | 99 | #if 0 |
100 | /* DSP */ | 100 | /* DSP */ |
101 | if (cpu_is_omap24xx()) { | 101 | if (cpu_is_omap24xx()) { |
102 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN); | 102 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_FCLKEN); |
103 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN); | 103 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_ICLKEN); |
104 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST); | 104 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_IDLEST); |
105 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE); | 105 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_AUTOIDLE); |
106 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL); | 106 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, CM_CLKSEL); |
107 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL); | 107 | DUMP_CM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_CM_CLKSTCTRL); |
108 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTCTRL); | 108 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTCTRL); |
109 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTST); | 109 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_RM_RSTST); |
110 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTCTRL); | 110 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTCTRL); |
111 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTST); | 111 | DUMP_PRM_MOD_REG(OMAP24XX_DSP_MOD, OMAP2_PM_PWSTST); |
112 | } | 112 | } |
113 | #endif | 113 | #endif |
114 | } else { | 114 | } else { |
115 | DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1); | 115 | DUMP_PRM_MOD_REG(CORE_MOD, PM_WKST1); |
116 | if (cpu_is_omap24xx()) | 116 | if (cpu_is_omap24xx()) |
117 | DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2); | 117 | DUMP_PRM_MOD_REG(CORE_MOD, OMAP24XX_PM_WKST2); |
118 | DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST); | 118 | DUMP_PRM_MOD_REG(WKUP_MOD, PM_WKST); |
119 | DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); | 119 | DUMP_PRM_MOD_REG(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); |
120 | #if 1 | 120 | #if 1 |
121 | DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098); | 121 | DUMP_INTC_REG(INTC_PENDING_IRQ0, 0x0098); |
122 | DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8); | 122 | DUMP_INTC_REG(INTC_PENDING_IRQ1, 0x00b8); |
123 | DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8); | 123 | DUMP_INTC_REG(INTC_PENDING_IRQ2, 0x00d8); |
124 | #endif | 124 | #endif |
125 | } | 125 | } |
126 | 126 | ||
127 | switch (mode) { | 127 | switch (mode) { |
128 | case 0: | 128 | case 0: |
129 | s1 = "full"; | 129 | s1 = "full"; |
130 | s2 = "retention"; | 130 | s2 = "retention"; |
131 | break; | 131 | break; |
132 | case 1: | 132 | case 1: |
133 | s1 = "MPU"; | 133 | s1 = "MPU"; |
134 | s2 = "retention"; | 134 | s2 = "retention"; |
135 | break; | 135 | break; |
136 | case 2: | 136 | case 2: |
137 | s1 = "MPU"; | 137 | s1 = "MPU"; |
138 | s2 = "idle"; | 138 | s2 = "idle"; |
139 | break; | 139 | break; |
140 | } | 140 | } |
141 | 141 | ||
142 | if (!resume) | 142 | if (!resume) |
143 | #ifdef CONFIG_NO_HZ | 143 | #ifdef CONFIG_NO_HZ |
144 | printk(KERN_INFO | 144 | printk(KERN_INFO |
145 | "--- Going to %s %s (next timer after %u ms)\n", s1, s2, | 145 | "--- Going to %s %s (next timer after %u ms)\n", s1, s2, |
146 | jiffies_to_msecs(get_next_timer_interrupt(jiffies) - | 146 | jiffies_to_msecs(get_next_timer_interrupt(jiffies) - |
147 | jiffies)); | 147 | jiffies)); |
148 | #else | 148 | #else |
149 | printk(KERN_INFO "--- Going to %s %s\n", s1, s2); | 149 | printk(KERN_INFO "--- Going to %s %s\n", s1, s2); |
150 | #endif | 150 | #endif |
151 | else | 151 | else |
152 | printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n", | 152 | printk(KERN_INFO "--- Woke up (slept for %u.%03u ms)\n", |
153 | us / 1000, us % 1000); | 153 | us / 1000, us % 1000); |
154 | 154 | ||
155 | for (i = 0; i < reg_count; i++) | 155 | for (i = 0; i < reg_count; i++) |
156 | printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); | 156 | printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); |
157 | } | 157 | } |
158 | 158 | ||
159 | #ifdef CONFIG_DEBUG_FS | 159 | #ifdef CONFIG_DEBUG_FS |
160 | #include <linux/debugfs.h> | 160 | #include <linux/debugfs.h> |
161 | #include <linux/seq_file.h> | 161 | #include <linux/seq_file.h> |
162 | 162 | ||
163 | static void pm_dbg_regset_store(u32 *ptr); | 163 | static void pm_dbg_regset_store(u32 *ptr); |
164 | 164 | ||
165 | struct dentry *pm_dbg_dir; | 165 | struct dentry *pm_dbg_dir; |
166 | 166 | ||
167 | static int pm_dbg_init_done; | 167 | static int pm_dbg_init_done; |
168 | 168 | ||
169 | static int __init pm_dbg_init(void); | 169 | static int __init pm_dbg_init(void); |
170 | 170 | ||
171 | enum { | 171 | enum { |
172 | DEBUG_FILE_COUNTERS = 0, | 172 | DEBUG_FILE_COUNTERS = 0, |
173 | DEBUG_FILE_TIMERS, | 173 | DEBUG_FILE_TIMERS, |
174 | }; | 174 | }; |
175 | 175 | ||
176 | struct pm_module_def { | 176 | struct pm_module_def { |
177 | char name[8]; /* Name of the module */ | 177 | char name[8]; /* Name of the module */ |
178 | short type; /* CM or PRM */ | 178 | short type; /* CM or PRM */ |
179 | unsigned short offset; | 179 | unsigned short offset; |
180 | int low; /* First register address on this module */ | 180 | int low; /* First register address on this module */ |
181 | int high; /* Last register address on this module */ | 181 | int high; /* Last register address on this module */ |
182 | }; | 182 | }; |
183 | 183 | ||
184 | #define MOD_CM 0 | 184 | #define MOD_CM 0 |
185 | #define MOD_PRM 1 | 185 | #define MOD_PRM 1 |
186 | 186 | ||
187 | static const struct pm_module_def *pm_dbg_reg_modules; | 187 | static const struct pm_module_def *pm_dbg_reg_modules; |
188 | static const struct pm_module_def omap3_pm_reg_modules[] = { | 188 | static const struct pm_module_def omap3_pm_reg_modules[] = { |
189 | { "IVA2", MOD_CM, OMAP3430_IVA2_MOD, 0, 0x4c }, | 189 | { "IVA2", MOD_CM, OMAP3430_IVA2_MOD, 0, 0x4c }, |
190 | { "OCP", MOD_CM, OCP_MOD, 0, 0x10 }, | 190 | { "OCP", MOD_CM, OCP_MOD, 0, 0x10 }, |
191 | { "MPU", MOD_CM, MPU_MOD, 4, 0x4c }, | 191 | { "MPU", MOD_CM, MPU_MOD, 4, 0x4c }, |
192 | { "CORE", MOD_CM, CORE_MOD, 0, 0x4c }, | 192 | { "CORE", MOD_CM, CORE_MOD, 0, 0x4c }, |
193 | { "SGX", MOD_CM, OMAP3430ES2_SGX_MOD, 0, 0x4c }, | 193 | { "SGX", MOD_CM, OMAP3430ES2_SGX_MOD, 0, 0x4c }, |
194 | { "WKUP", MOD_CM, WKUP_MOD, 0, 0x40 }, | 194 | { "WKUP", MOD_CM, WKUP_MOD, 0, 0x40 }, |
195 | { "CCR", MOD_CM, PLL_MOD, 0, 0x70 }, | 195 | { "CCR", MOD_CM, PLL_MOD, 0, 0x70 }, |
196 | { "DSS", MOD_CM, OMAP3430_DSS_MOD, 0, 0x4c }, | 196 | { "DSS", MOD_CM, OMAP3430_DSS_MOD, 0, 0x4c }, |
197 | { "CAM", MOD_CM, OMAP3430_CAM_MOD, 0, 0x4c }, | 197 | { "CAM", MOD_CM, OMAP3430_CAM_MOD, 0, 0x4c }, |
198 | { "PER", MOD_CM, OMAP3430_PER_MOD, 0, 0x4c }, | 198 | { "PER", MOD_CM, OMAP3430_PER_MOD, 0, 0x4c }, |
199 | { "EMU", MOD_CM, OMAP3430_EMU_MOD, 0x40, 0x54 }, | 199 | { "EMU", MOD_CM, OMAP3430_EMU_MOD, 0x40, 0x54 }, |
200 | { "NEON", MOD_CM, OMAP3430_NEON_MOD, 0x20, 0x48 }, | 200 | { "NEON", MOD_CM, OMAP3430_NEON_MOD, 0x20, 0x48 }, |
201 | { "USB", MOD_CM, OMAP3430ES2_USBHOST_MOD, 0, 0x4c }, | 201 | { "USB", MOD_CM, OMAP3430ES2_USBHOST_MOD, 0, 0x4c }, |
202 | 202 | ||
203 | { "IVA2", MOD_PRM, OMAP3430_IVA2_MOD, 0x50, 0xfc }, | 203 | { "IVA2", MOD_PRM, OMAP3430_IVA2_MOD, 0x50, 0xfc }, |
204 | { "OCP", MOD_PRM, OCP_MOD, 4, 0x1c }, | 204 | { "OCP", MOD_PRM, OCP_MOD, 4, 0x1c }, |
205 | { "MPU", MOD_PRM, MPU_MOD, 0x58, 0xe8 }, | 205 | { "MPU", MOD_PRM, MPU_MOD, 0x58, 0xe8 }, |
206 | { "CORE", MOD_PRM, CORE_MOD, 0x58, 0xf8 }, | 206 | { "CORE", MOD_PRM, CORE_MOD, 0x58, 0xf8 }, |
207 | { "SGX", MOD_PRM, OMAP3430ES2_SGX_MOD, 0x58, 0xe8 }, | 207 | { "SGX", MOD_PRM, OMAP3430ES2_SGX_MOD, 0x58, 0xe8 }, |
208 | { "WKUP", MOD_PRM, WKUP_MOD, 0xa0, 0xb0 }, | 208 | { "WKUP", MOD_PRM, WKUP_MOD, 0xa0, 0xb0 }, |
209 | { "CCR", MOD_PRM, PLL_MOD, 0x40, 0x70 }, | 209 | { "CCR", MOD_PRM, PLL_MOD, 0x40, 0x70 }, |
210 | { "DSS", MOD_PRM, OMAP3430_DSS_MOD, 0x58, 0xe8 }, | 210 | { "DSS", MOD_PRM, OMAP3430_DSS_MOD, 0x58, 0xe8 }, |
211 | { "CAM", MOD_PRM, OMAP3430_CAM_MOD, 0x58, 0xe8 }, | 211 | { "CAM", MOD_PRM, OMAP3430_CAM_MOD, 0x58, 0xe8 }, |
212 | { "PER", MOD_PRM, OMAP3430_PER_MOD, 0x58, 0xe8 }, | 212 | { "PER", MOD_PRM, OMAP3430_PER_MOD, 0x58, 0xe8 }, |
213 | { "EMU", MOD_PRM, OMAP3430_EMU_MOD, 0x58, 0xe4 }, | 213 | { "EMU", MOD_PRM, OMAP3430_EMU_MOD, 0x58, 0xe4 }, |
214 | { "GLBL", MOD_PRM, OMAP3430_GR_MOD, 0x20, 0xe4 }, | 214 | { "GLBL", MOD_PRM, OMAP3430_GR_MOD, 0x20, 0xe4 }, |
215 | { "NEON", MOD_PRM, OMAP3430_NEON_MOD, 0x58, 0xe8 }, | 215 | { "NEON", MOD_PRM, OMAP3430_NEON_MOD, 0x58, 0xe8 }, |
216 | { "USB", MOD_PRM, OMAP3430ES2_USBHOST_MOD, 0x58, 0xe8 }, | 216 | { "USB", MOD_PRM, OMAP3430ES2_USBHOST_MOD, 0x58, 0xe8 }, |
217 | { "", 0, 0, 0, 0 }, | 217 | { "", 0, 0, 0, 0 }, |
218 | }; | 218 | }; |
219 | 219 | ||
220 | #define PM_DBG_MAX_REG_SETS 4 | 220 | #define PM_DBG_MAX_REG_SETS 4 |
221 | 221 | ||
222 | static void *pm_dbg_reg_set[PM_DBG_MAX_REG_SETS]; | 222 | static void *pm_dbg_reg_set[PM_DBG_MAX_REG_SETS]; |
223 | 223 | ||
224 | static int pm_dbg_get_regset_size(void) | 224 | static int pm_dbg_get_regset_size(void) |
225 | { | 225 | { |
226 | static int regset_size; | 226 | static int regset_size; |
227 | 227 | ||
228 | if (regset_size == 0) { | 228 | if (regset_size == 0) { |
229 | int i = 0; | 229 | int i = 0; |
230 | 230 | ||
231 | while (pm_dbg_reg_modules[i].name[0] != 0) { | 231 | while (pm_dbg_reg_modules[i].name[0] != 0) { |
232 | regset_size += pm_dbg_reg_modules[i].high + | 232 | regset_size += pm_dbg_reg_modules[i].high + |
233 | 4 - pm_dbg_reg_modules[i].low; | 233 | 4 - pm_dbg_reg_modules[i].low; |
234 | i++; | 234 | i++; |
235 | } | 235 | } |
236 | } | 236 | } |
237 | return regset_size; | 237 | return regset_size; |
238 | } | 238 | } |
239 | 239 | ||
240 | static int pm_dbg_show_regs(struct seq_file *s, void *unused) | 240 | static int pm_dbg_show_regs(struct seq_file *s, void *unused) |
241 | { | 241 | { |
242 | int i, j; | 242 | int i, j; |
243 | unsigned long val; | 243 | unsigned long val; |
244 | int reg_set = (int)s->private; | 244 | int reg_set = (int)s->private; |
245 | u32 *ptr; | 245 | u32 *ptr; |
246 | void *store = NULL; | 246 | void *store = NULL; |
247 | int regs; | 247 | int regs; |
248 | int linefeed; | 248 | int linefeed; |
249 | 249 | ||
250 | if (reg_set == 0) { | 250 | if (reg_set == 0) { |
251 | store = kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); | 251 | store = kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); |
252 | ptr = store; | 252 | ptr = store; |
253 | pm_dbg_regset_store(ptr); | 253 | pm_dbg_regset_store(ptr); |
254 | } else { | 254 | } else { |
255 | ptr = pm_dbg_reg_set[reg_set - 1]; | 255 | ptr = pm_dbg_reg_set[reg_set - 1]; |
256 | } | 256 | } |
257 | 257 | ||
258 | i = 0; | 258 | i = 0; |
259 | 259 | ||
260 | while (pm_dbg_reg_modules[i].name[0] != 0) { | 260 | while (pm_dbg_reg_modules[i].name[0] != 0) { |
261 | regs = 0; | 261 | regs = 0; |
262 | linefeed = 0; | 262 | linefeed = 0; |
263 | if (pm_dbg_reg_modules[i].type == MOD_CM) | 263 | if (pm_dbg_reg_modules[i].type == MOD_CM) |
264 | seq_printf(s, "MOD: CM_%s (%08x)\n", | 264 | seq_printf(s, "MOD: CM_%s (%08x)\n", |
265 | pm_dbg_reg_modules[i].name, | 265 | pm_dbg_reg_modules[i].name, |
266 | (u32)(OMAP3430_CM_BASE + | 266 | (u32)(OMAP3430_CM_BASE + |
267 | pm_dbg_reg_modules[i].offset)); | 267 | pm_dbg_reg_modules[i].offset)); |
268 | else | 268 | else |
269 | seq_printf(s, "MOD: PRM_%s (%08x)\n", | 269 | seq_printf(s, "MOD: PRM_%s (%08x)\n", |
270 | pm_dbg_reg_modules[i].name, | 270 | pm_dbg_reg_modules[i].name, |
271 | (u32)(OMAP3430_PRM_BASE + | 271 | (u32)(OMAP3430_PRM_BASE + |
272 | pm_dbg_reg_modules[i].offset)); | 272 | pm_dbg_reg_modules[i].offset)); |
273 | 273 | ||
274 | for (j = pm_dbg_reg_modules[i].low; | 274 | for (j = pm_dbg_reg_modules[i].low; |
275 | j <= pm_dbg_reg_modules[i].high; j += 4) { | 275 | j <= pm_dbg_reg_modules[i].high; j += 4) { |
276 | val = *(ptr++); | 276 | val = *(ptr++); |
277 | if (val != 0) { | 277 | if (val != 0) { |
278 | regs++; | 278 | regs++; |
279 | if (linefeed) { | 279 | if (linefeed) { |
280 | seq_printf(s, "\n"); | 280 | seq_printf(s, "\n"); |
281 | linefeed = 0; | 281 | linefeed = 0; |
282 | } | 282 | } |
283 | seq_printf(s, " %02x => %08lx", j, val); | 283 | seq_printf(s, " %02x => %08lx", j, val); |
284 | if (regs % 4 == 0) | 284 | if (regs % 4 == 0) |
285 | linefeed = 1; | 285 | linefeed = 1; |
286 | } | 286 | } |
287 | } | 287 | } |
288 | seq_printf(s, "\n"); | 288 | seq_printf(s, "\n"); |
289 | i++; | 289 | i++; |
290 | } | 290 | } |
291 | 291 | ||
292 | if (store != NULL) | 292 | if (store != NULL) |
293 | kfree(store); | 293 | kfree(store); |
294 | 294 | ||
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | static void pm_dbg_regset_store(u32 *ptr) | 298 | static void pm_dbg_regset_store(u32 *ptr) |
299 | { | 299 | { |
300 | int i, j; | 300 | int i, j; |
301 | u32 val; | 301 | u32 val; |
302 | 302 | ||
303 | i = 0; | 303 | i = 0; |
304 | 304 | ||
305 | while (pm_dbg_reg_modules[i].name[0] != 0) { | 305 | while (pm_dbg_reg_modules[i].name[0] != 0) { |
306 | for (j = pm_dbg_reg_modules[i].low; | 306 | for (j = pm_dbg_reg_modules[i].low; |
307 | j <= pm_dbg_reg_modules[i].high; j += 4) { | 307 | j <= pm_dbg_reg_modules[i].high; j += 4) { |
308 | if (pm_dbg_reg_modules[i].type == MOD_CM) | 308 | if (pm_dbg_reg_modules[i].type == MOD_CM) |
309 | val = cm_read_mod_reg( | 309 | val = cm_read_mod_reg( |
310 | pm_dbg_reg_modules[i].offset, j); | 310 | pm_dbg_reg_modules[i].offset, j); |
311 | else | 311 | else |
312 | val = prm_read_mod_reg( | 312 | val = prm_read_mod_reg( |
313 | pm_dbg_reg_modules[i].offset, j); | 313 | pm_dbg_reg_modules[i].offset, j); |
314 | *(ptr++) = val; | 314 | *(ptr++) = val; |
315 | } | 315 | } |
316 | i++; | 316 | i++; |
317 | } | 317 | } |
318 | } | 318 | } |
319 | 319 | ||
320 | int pm_dbg_regset_save(int reg_set) | 320 | int pm_dbg_regset_save(int reg_set) |
321 | { | 321 | { |
322 | if (pm_dbg_reg_set[reg_set-1] == NULL) | 322 | if (pm_dbg_reg_set[reg_set-1] == NULL) |
323 | return -EINVAL; | 323 | return -EINVAL; |
324 | 324 | ||
325 | pm_dbg_regset_store(pm_dbg_reg_set[reg_set-1]); | 325 | pm_dbg_regset_store(pm_dbg_reg_set[reg_set-1]); |
326 | 326 | ||
327 | return 0; | 327 | return 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = { | 330 | static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = { |
331 | "OFF", | 331 | "OFF", |
332 | "RET", | 332 | "RET", |
333 | "INA", | 333 | "INA", |
334 | "ON" | 334 | "ON" |
335 | }; | 335 | }; |
336 | 336 | ||
337 | void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) | 337 | void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) |
338 | { | 338 | { |
339 | s64 t; | 339 | s64 t; |
340 | 340 | ||
341 | if (!pm_dbg_init_done) | 341 | if (!pm_dbg_init_done) |
342 | return ; | 342 | return ; |
343 | 343 | ||
344 | /* Update timer for previous state */ | 344 | /* Update timer for previous state */ |
345 | t = sched_clock(); | 345 | t = sched_clock(); |
346 | 346 | ||
347 | pwrdm->state_timer[prev] += t - pwrdm->timer; | 347 | pwrdm->state_timer[prev] += t - pwrdm->timer; |
348 | 348 | ||
349 | pwrdm->timer = t; | 349 | pwrdm->timer = t; |
350 | } | 350 | } |
351 | 351 | ||
352 | static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) | 352 | static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) |
353 | { | 353 | { |
354 | struct seq_file *s = (struct seq_file *)user; | 354 | struct seq_file *s = (struct seq_file *)user; |
355 | 355 | ||
356 | if (strcmp(clkdm->name, "emu_clkdm") == 0 || | 356 | if (strcmp(clkdm->name, "emu_clkdm") == 0 || |
357 | strcmp(clkdm->name, "wkup_clkdm") == 0 || | 357 | strcmp(clkdm->name, "wkup_clkdm") == 0 || |
358 | strncmp(clkdm->name, "dpll", 4) == 0) | 358 | strncmp(clkdm->name, "dpll", 4) == 0) |
359 | return 0; | 359 | return 0; |
360 | 360 | ||
361 | seq_printf(s, "%s->%s (%d)", clkdm->name, | 361 | seq_printf(s, "%s->%s (%d)", clkdm->name, |
362 | clkdm->pwrdm.ptr->name, | 362 | clkdm->pwrdm.ptr->name, |
363 | atomic_read(&clkdm->usecount)); | 363 | atomic_read(&clkdm->usecount)); |
364 | seq_printf(s, "\n"); | 364 | seq_printf(s, "\n"); |
365 | 365 | ||
366 | return 0; | 366 | return 0; |
367 | } | 367 | } |
368 | 368 | ||
369 | static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) | 369 | static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) |
370 | { | 370 | { |
371 | struct seq_file *s = (struct seq_file *)user; | 371 | struct seq_file *s = (struct seq_file *)user; |
372 | int i; | 372 | int i; |
373 | 373 | ||
374 | if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || | 374 | if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || |
375 | strcmp(pwrdm->name, "wkup_pwrdm") == 0 || | 375 | strcmp(pwrdm->name, "wkup_pwrdm") == 0 || |
376 | strncmp(pwrdm->name, "dpll", 4) == 0) | 376 | strncmp(pwrdm->name, "dpll", 4) == 0) |
377 | return 0; | 377 | return 0; |
378 | 378 | ||
379 | if (pwrdm->state != pwrdm_read_pwrst(pwrdm)) | 379 | if (pwrdm->state != pwrdm_read_pwrst(pwrdm)) |
380 | printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n", | 380 | printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n", |
381 | pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm)); | 381 | pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm)); |
382 | 382 | ||
383 | seq_printf(s, "%s (%s)", pwrdm->name, | 383 | seq_printf(s, "%s (%s)", pwrdm->name, |
384 | pwrdm_state_names[pwrdm->state]); | 384 | pwrdm_state_names[pwrdm->state]); |
385 | for (i = 0; i < PWRDM_MAX_PWRSTS; i++) | 385 | for (i = 0; i < PWRDM_MAX_PWRSTS; i++) |
386 | seq_printf(s, ",%s:%d", pwrdm_state_names[i], | 386 | seq_printf(s, ",%s:%d", pwrdm_state_names[i], |
387 | pwrdm->state_counter[i]); | 387 | pwrdm->state_counter[i]); |
388 | 388 | ||
389 | seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter); | 389 | seq_printf(s, ",RET-LOGIC-OFF:%d", pwrdm->ret_logic_off_counter); |
390 | for (i = 0; i < pwrdm->banks; i++) | 390 | for (i = 0; i < pwrdm->banks; i++) |
391 | seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, | 391 | seq_printf(s, ",RET-MEMBANK%d-OFF:%d", i + 1, |
392 | pwrdm->ret_mem_off_counter[i]); | 392 | pwrdm->ret_mem_off_counter[i]); |
393 | 393 | ||
394 | seq_printf(s, "\n"); | 394 | seq_printf(s, "\n"); |
395 | 395 | ||
396 | return 0; | 396 | return 0; |
397 | } | 397 | } |
398 | 398 | ||
399 | static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) | 399 | static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) |
400 | { | 400 | { |
401 | struct seq_file *s = (struct seq_file *)user; | 401 | struct seq_file *s = (struct seq_file *)user; |
402 | int i; | 402 | int i; |
403 | 403 | ||
404 | if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || | 404 | if (strcmp(pwrdm->name, "emu_pwrdm") == 0 || |
405 | strcmp(pwrdm->name, "wkup_pwrdm") == 0 || | 405 | strcmp(pwrdm->name, "wkup_pwrdm") == 0 || |
406 | strncmp(pwrdm->name, "dpll", 4) == 0) | 406 | strncmp(pwrdm->name, "dpll", 4) == 0) |
407 | return 0; | 407 | return 0; |
408 | 408 | ||
409 | pwrdm_state_switch(pwrdm); | 409 | pwrdm_state_switch(pwrdm); |
410 | 410 | ||
411 | seq_printf(s, "%s (%s)", pwrdm->name, | 411 | seq_printf(s, "%s (%s)", pwrdm->name, |
412 | pwrdm_state_names[pwrdm->state]); | 412 | pwrdm_state_names[pwrdm->state]); |
413 | 413 | ||
414 | for (i = 0; i < 4; i++) | 414 | for (i = 0; i < 4; i++) |
415 | seq_printf(s, ",%s:%lld", pwrdm_state_names[i], | 415 | seq_printf(s, ",%s:%lld", pwrdm_state_names[i], |
416 | pwrdm->state_timer[i]); | 416 | pwrdm->state_timer[i]); |
417 | 417 | ||
418 | seq_printf(s, "\n"); | 418 | seq_printf(s, "\n"); |
419 | return 0; | 419 | return 0; |
420 | } | 420 | } |
421 | 421 | ||
422 | static int pm_dbg_show_counters(struct seq_file *s, void *unused) | 422 | static int pm_dbg_show_counters(struct seq_file *s, void *unused) |
423 | { | 423 | { |
424 | pwrdm_for_each(pwrdm_dbg_show_counter, s); | 424 | pwrdm_for_each(pwrdm_dbg_show_counter, s); |
425 | clkdm_for_each(clkdm_dbg_show_counter, s); | 425 | clkdm_for_each(clkdm_dbg_show_counter, s); |
426 | 426 | ||
427 | return 0; | 427 | return 0; |
428 | } | 428 | } |
429 | 429 | ||
430 | static int pm_dbg_show_timers(struct seq_file *s, void *unused) | 430 | static int pm_dbg_show_timers(struct seq_file *s, void *unused) |
431 | { | 431 | { |
432 | pwrdm_for_each(pwrdm_dbg_show_timer, s); | 432 | pwrdm_for_each(pwrdm_dbg_show_timer, s); |
433 | return 0; | 433 | return 0; |
434 | } | 434 | } |
435 | 435 | ||
436 | static int pm_dbg_open(struct inode *inode, struct file *file) | 436 | static int pm_dbg_open(struct inode *inode, struct file *file) |
437 | { | 437 | { |
438 | switch ((int)inode->i_private) { | 438 | switch ((int)inode->i_private) { |
439 | case DEBUG_FILE_COUNTERS: | 439 | case DEBUG_FILE_COUNTERS: |
440 | return single_open(file, pm_dbg_show_counters, | 440 | return single_open(file, pm_dbg_show_counters, |
441 | &inode->i_private); | 441 | &inode->i_private); |
442 | case DEBUG_FILE_TIMERS: | 442 | case DEBUG_FILE_TIMERS: |
443 | default: | 443 | default: |
444 | return single_open(file, pm_dbg_show_timers, | 444 | return single_open(file, pm_dbg_show_timers, |
445 | &inode->i_private); | 445 | &inode->i_private); |
446 | }; | 446 | }; |
447 | } | 447 | } |
448 | 448 | ||
449 | static int pm_dbg_reg_open(struct inode *inode, struct file *file) | 449 | static int pm_dbg_reg_open(struct inode *inode, struct file *file) |
450 | { | 450 | { |
451 | return single_open(file, pm_dbg_show_regs, inode->i_private); | 451 | return single_open(file, pm_dbg_show_regs, inode->i_private); |
452 | } | 452 | } |
453 | 453 | ||
454 | static const struct file_operations debug_fops = { | 454 | static const struct file_operations debug_fops = { |
455 | .open = pm_dbg_open, | 455 | .open = pm_dbg_open, |
456 | .read = seq_read, | 456 | .read = seq_read, |
457 | .llseek = seq_lseek, | 457 | .llseek = seq_lseek, |
458 | .release = single_release, | 458 | .release = single_release, |
459 | }; | 459 | }; |
460 | 460 | ||
461 | static const struct file_operations debug_reg_fops = { | 461 | static const struct file_operations debug_reg_fops = { |
462 | .open = pm_dbg_reg_open, | 462 | .open = pm_dbg_reg_open, |
463 | .read = seq_read, | 463 | .read = seq_read, |
464 | .llseek = seq_lseek, | 464 | .llseek = seq_lseek, |
465 | .release = single_release, | 465 | .release = single_release, |
466 | }; | 466 | }; |
467 | 467 | ||
468 | int pm_dbg_regset_init(int reg_set) | 468 | int pm_dbg_regset_init(int reg_set) |
469 | { | 469 | { |
470 | char name[2]; | 470 | char name[2]; |
471 | 471 | ||
472 | if (!pm_dbg_init_done) | 472 | if (!pm_dbg_init_done) |
473 | pm_dbg_init(); | 473 | pm_dbg_init(); |
474 | 474 | ||
475 | if (reg_set < 1 || reg_set > PM_DBG_MAX_REG_SETS || | 475 | if (reg_set < 1 || reg_set > PM_DBG_MAX_REG_SETS || |
476 | pm_dbg_reg_set[reg_set-1] != NULL) | 476 | pm_dbg_reg_set[reg_set-1] != NULL) |
477 | return -EINVAL; | 477 | return -EINVAL; |
478 | 478 | ||
479 | pm_dbg_reg_set[reg_set-1] = | 479 | pm_dbg_reg_set[reg_set-1] = |
480 | kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); | 480 | kmalloc(pm_dbg_get_regset_size(), GFP_KERNEL); |
481 | 481 | ||
482 | if (pm_dbg_reg_set[reg_set-1] == NULL) | 482 | if (pm_dbg_reg_set[reg_set-1] == NULL) |
483 | return -ENOMEM; | 483 | return -ENOMEM; |
484 | 484 | ||
485 | if (pm_dbg_dir != NULL) { | 485 | if (pm_dbg_dir != NULL) { |
486 | sprintf(name, "%d", reg_set); | 486 | sprintf(name, "%d", reg_set); |
487 | 487 | ||
488 | (void) debugfs_create_file(name, S_IRUGO, | 488 | (void) debugfs_create_file(name, S_IRUGO, |
489 | pm_dbg_dir, (void *)reg_set, &debug_reg_fops); | 489 | pm_dbg_dir, (void *)reg_set, &debug_reg_fops); |
490 | } | 490 | } |
491 | 491 | ||
492 | return 0; | 492 | return 0; |
493 | } | 493 | } |
494 | 494 | ||
495 | static int pwrdm_suspend_get(void *data, u64 *val) | 495 | static int pwrdm_suspend_get(void *data, u64 *val) |
496 | { | 496 | { |
497 | int ret; | 497 | int ret; |
498 | ret = omap3_pm_get_suspend_state((struct powerdomain *)data); | 498 | ret = omap3_pm_get_suspend_state((struct powerdomain *)data); |
499 | *val = ret; | 499 | *val = ret; |
500 | 500 | ||
501 | if (ret >= 0) | 501 | if (ret >= 0) |
502 | return 0; | 502 | return 0; |
503 | return *val; | 503 | return *val; |
504 | } | 504 | } |
505 | 505 | ||
506 | static int pwrdm_suspend_set(void *data, u64 val) | 506 | static int pwrdm_suspend_set(void *data, u64 val) |
507 | { | 507 | { |
508 | return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val); | 508 | return omap3_pm_set_suspend_state((struct powerdomain *)data, (int)val); |
509 | } | 509 | } |
510 | 510 | ||
511 | DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, | 511 | DEFINE_SIMPLE_ATTRIBUTE(pwrdm_suspend_fops, pwrdm_suspend_get, |
512 | pwrdm_suspend_set, "%llu\n"); | 512 | pwrdm_suspend_set, "%llu\n"); |
513 | 513 | ||
514 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) | 514 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir) |
515 | { | 515 | { |
516 | int i; | 516 | int i; |
517 | s64 t; | 517 | s64 t; |
518 | struct dentry *d; | 518 | struct dentry *d; |
519 | 519 | ||
520 | t = sched_clock(); | 520 | t = sched_clock(); |
521 | 521 | ||
522 | for (i = 0; i < 4; i++) | 522 | for (i = 0; i < 4; i++) |
523 | pwrdm->state_timer[i] = 0; | 523 | pwrdm->state_timer[i] = 0; |
524 | 524 | ||
525 | pwrdm->timer = t; | 525 | pwrdm->timer = t; |
526 | 526 | ||
527 | if (strncmp(pwrdm->name, "dpll", 4) == 0) | 527 | if (strncmp(pwrdm->name, "dpll", 4) == 0) |
528 | return 0; | 528 | return 0; |
529 | 529 | ||
530 | d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir); | 530 | d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir); |
531 | 531 | ||
532 | (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, | 532 | (void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, |
533 | (void *)pwrdm, &pwrdm_suspend_fops); | 533 | (void *)pwrdm, &pwrdm_suspend_fops); |
534 | 534 | ||
535 | return 0; | 535 | return 0; |
536 | } | 536 | } |
537 | 537 | ||
538 | static int option_get(void *data, u64 *val) | 538 | static int option_get(void *data, u64 *val) |
539 | { | 539 | { |
540 | u32 *option = data; | 540 | u32 *option = data; |
541 | 541 | ||
542 | *val = *option; | 542 | *val = *option; |
543 | 543 | ||
544 | return 0; | 544 | return 0; |
545 | } | 545 | } |
546 | 546 | ||
547 | static int option_set(void *data, u64 val) | 547 | static int option_set(void *data, u64 val) |
548 | { | 548 | { |
549 | u32 *option = data; | 549 | u32 *option = data; |
550 | 550 | ||
551 | if (option == &wakeup_timer_milliseconds && val >= 1000) | ||
552 | return -EINVAL; | ||
553 | |||
551 | *option = val; | 554 | *option = val; |
552 | 555 | ||
553 | if (option == &enable_off_mode) | 556 | if (option == &enable_off_mode) |
554 | omap3_pm_off_mode_enable(val); | 557 | omap3_pm_off_mode_enable(val); |
555 | 558 | ||
556 | return 0; | 559 | return 0; |
557 | } | 560 | } |
558 | 561 | ||
559 | DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n"); | 562 | DEFINE_SIMPLE_ATTRIBUTE(pm_dbg_option_fops, option_get, option_set, "%llu\n"); |
560 | 563 | ||
561 | static int __init pm_dbg_init(void) | 564 | static int __init pm_dbg_init(void) |
562 | { | 565 | { |
563 | int i; | 566 | int i; |
564 | struct dentry *d; | 567 | struct dentry *d; |
565 | char name[2]; | 568 | char name[2]; |
566 | 569 | ||
567 | if (pm_dbg_init_done) | 570 | if (pm_dbg_init_done) |
568 | return 0; | 571 | return 0; |
569 | 572 | ||
570 | if (cpu_is_omap34xx()) | 573 | if (cpu_is_omap34xx()) |
571 | pm_dbg_reg_modules = omap3_pm_reg_modules; | 574 | pm_dbg_reg_modules = omap3_pm_reg_modules; |
572 | else { | 575 | else { |
573 | printk(KERN_ERR "%s: only OMAP3 supported\n", __func__); | 576 | printk(KERN_ERR "%s: only OMAP3 supported\n", __func__); |
574 | return -ENODEV; | 577 | return -ENODEV; |
575 | } | 578 | } |
576 | 579 | ||
577 | d = debugfs_create_dir("pm_debug", NULL); | 580 | d = debugfs_create_dir("pm_debug", NULL); |
578 | if (IS_ERR(d)) | 581 | if (IS_ERR(d)) |
579 | return PTR_ERR(d); | 582 | return PTR_ERR(d); |
580 | 583 | ||
581 | (void) debugfs_create_file("count", S_IRUGO, | 584 | (void) debugfs_create_file("count", S_IRUGO, |
582 | d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); | 585 | d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); |
583 | (void) debugfs_create_file("time", S_IRUGO, | 586 | (void) debugfs_create_file("time", S_IRUGO, |
584 | d, (void *)DEBUG_FILE_TIMERS, &debug_fops); | 587 | d, (void *)DEBUG_FILE_TIMERS, &debug_fops); |
585 | 588 | ||
586 | pwrdm_for_each(pwrdms_setup, (void *)d); | 589 | pwrdm_for_each(pwrdms_setup, (void *)d); |
587 | 590 | ||
588 | pm_dbg_dir = debugfs_create_dir("registers", d); | 591 | pm_dbg_dir = debugfs_create_dir("registers", d); |
589 | if (IS_ERR(pm_dbg_dir)) | 592 | if (IS_ERR(pm_dbg_dir)) |
590 | return PTR_ERR(pm_dbg_dir); | 593 | return PTR_ERR(pm_dbg_dir); |
591 | 594 | ||
592 | (void) debugfs_create_file("current", S_IRUGO, | 595 | (void) debugfs_create_file("current", S_IRUGO, |
593 | pm_dbg_dir, (void *)0, &debug_reg_fops); | 596 | pm_dbg_dir, (void *)0, &debug_reg_fops); |
594 | 597 | ||
595 | for (i = 0; i < PM_DBG_MAX_REG_SETS; i++) | 598 | for (i = 0; i < PM_DBG_MAX_REG_SETS; i++) |
596 | if (pm_dbg_reg_set[i] != NULL) { | 599 | if (pm_dbg_reg_set[i] != NULL) { |
597 | sprintf(name, "%d", i+1); | 600 | sprintf(name, "%d", i+1); |
598 | (void) debugfs_create_file(name, S_IRUGO, | 601 | (void) debugfs_create_file(name, S_IRUGO, |
599 | pm_dbg_dir, (void *)(i+1), &debug_reg_fops); | 602 | pm_dbg_dir, (void *)(i+1), &debug_reg_fops); |
600 | 603 | ||
601 | } | 604 | } |
602 | 605 | ||
603 | (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUGO, d, | 606 | (void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUGO, d, |
604 | &enable_off_mode, &pm_dbg_option_fops); | 607 | &enable_off_mode, &pm_dbg_option_fops); |
605 | (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d, | 608 | (void) debugfs_create_file("sleep_while_idle", S_IRUGO | S_IWUGO, d, |
606 | &sleep_while_idle, &pm_dbg_option_fops); | 609 | &sleep_while_idle, &pm_dbg_option_fops); |
607 | (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d, | 610 | (void) debugfs_create_file("wakeup_timer_seconds", S_IRUGO | S_IWUGO, d, |
608 | &wakeup_timer_seconds, &pm_dbg_option_fops); | 611 | &wakeup_timer_seconds, &pm_dbg_option_fops); |
609 | pm_dbg_init_done = 1; | 612 | pm_dbg_init_done = 1; |
610 | 613 | ||
611 | return 0; | 614 | return 0; |
612 | } | 615 | } |
613 | arch_initcall(pm_dbg_init); | 616 | arch_initcall(pm_dbg_init); |
614 | 617 | ||
615 | #endif | 618 | #endif |
616 | 619 |
arch/arm/mach-omap2/pm.h
1 | /* | 1 | /* |
2 | * OMAP2/3 Power Management Routines | 2 | * OMAP2/3 Power Management Routines |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Nokia Corporation | 4 | * Copyright (C) 2008 Nokia Corporation |
5 | * Jouni Hogander | 5 | * Jouni Hogander |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 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 | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #ifndef __ARCH_ARM_MACH_OMAP2_PM_H | 11 | #ifndef __ARCH_ARM_MACH_OMAP2_PM_H |
12 | #define __ARCH_ARM_MACH_OMAP2_PM_H | 12 | #define __ARCH_ARM_MACH_OMAP2_PM_H |
13 | 13 | ||
14 | #include <plat/powerdomain.h> | 14 | #include <plat/powerdomain.h> |
15 | 15 | ||
16 | extern u32 enable_off_mode; | 16 | extern u32 enable_off_mode; |
17 | extern u32 sleep_while_idle; | 17 | extern u32 sleep_while_idle; |
18 | 18 | ||
19 | extern void *omap3_secure_ram_storage; | 19 | extern void *omap3_secure_ram_storage; |
20 | extern void omap3_pm_off_mode_enable(int); | 20 | extern void omap3_pm_off_mode_enable(int); |
21 | extern void omap_sram_idle(void); | 21 | extern void omap_sram_idle(void); |
22 | extern int omap3_can_sleep(void); | 22 | extern int omap3_can_sleep(void); |
23 | extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); | 23 | extern int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); |
24 | extern int omap3_idle_init(void); | 24 | extern int omap3_idle_init(void); |
25 | 25 | ||
26 | struct cpuidle_params { | 26 | struct cpuidle_params { |
27 | u8 valid; | 27 | u8 valid; |
28 | u32 sleep_latency; | 28 | u32 sleep_latency; |
29 | u32 wake_latency; | 29 | u32 wake_latency; |
30 | u32 threshold; | 30 | u32 threshold; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE) | 33 | #if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE) |
34 | extern void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params); | 34 | extern void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params); |
35 | #else | 35 | #else |
36 | static | 36 | static |
37 | inline void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params) | 37 | inline void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params) |
38 | { | 38 | { |
39 | } | 39 | } |
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); | 42 | extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); |
43 | extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); | 43 | extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); |
44 | 44 | ||
45 | extern u32 wakeup_timer_seconds; | 45 | extern u32 wakeup_timer_seconds; |
46 | extern u32 wakeup_timer_milliseconds; | ||
46 | extern struct omap_dm_timer *gptimer_wakeup; | 47 | extern struct omap_dm_timer *gptimer_wakeup; |
47 | 48 | ||
48 | #ifdef CONFIG_PM_DEBUG | 49 | #ifdef CONFIG_PM_DEBUG |
49 | extern void omap2_pm_dump(int mode, int resume, unsigned int us); | 50 | extern void omap2_pm_dump(int mode, int resume, unsigned int us); |
50 | extern int omap2_pm_debug; | 51 | extern int omap2_pm_debug; |
51 | #else | 52 | #else |
52 | #define omap2_pm_dump(mode, resume, us) do {} while (0); | 53 | #define omap2_pm_dump(mode, resume, us) do {} while (0); |
53 | #define omap2_pm_debug 0 | 54 | #define omap2_pm_debug 0 |
54 | #endif | 55 | #endif |
55 | 56 | ||
56 | #if defined(CONFIG_CPU_IDLE) | 57 | #if defined(CONFIG_CPU_IDLE) |
57 | extern void omap3_cpuidle_update_states(void); | 58 | extern void omap3_cpuidle_update_states(void); |
58 | #endif | 59 | #endif |
59 | 60 | ||
60 | #if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) | 61 | #if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) |
61 | extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); | 62 | extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev); |
62 | extern int pm_dbg_regset_save(int reg_set); | 63 | extern int pm_dbg_regset_save(int reg_set); |
63 | extern int pm_dbg_regset_init(int reg_set); | 64 | extern int pm_dbg_regset_init(int reg_set); |
64 | #else | 65 | #else |
65 | #define pm_dbg_update_time(pwrdm, prev) do {} while (0); | 66 | #define pm_dbg_update_time(pwrdm, prev) do {} while (0); |
66 | #define pm_dbg_regset_save(reg_set) do {} while (0); | 67 | #define pm_dbg_regset_save(reg_set) do {} while (0); |
67 | #define pm_dbg_regset_init(reg_set) do {} while (0); | 68 | #define pm_dbg_regset_init(reg_set) do {} while (0); |
68 | #endif /* CONFIG_PM_DEBUG */ | 69 | #endif /* CONFIG_PM_DEBUG */ |
69 | 70 | ||
70 | extern void omap24xx_idle_loop_suspend(void); | 71 | extern void omap24xx_idle_loop_suspend(void); |
71 | 72 | ||
72 | extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, | 73 | extern void omap24xx_cpu_suspend(u32 dll_ctrl, void __iomem *sdrc_dlla_ctrl, |
73 | void __iomem *sdrc_power); | 74 | void __iomem *sdrc_power); |
74 | extern void omap34xx_cpu_suspend(u32 *addr, int save_state); | 75 | extern void omap34xx_cpu_suspend(u32 *addr, int save_state); |
75 | extern void save_secure_ram_context(u32 *addr); | 76 | extern void save_secure_ram_context(u32 *addr); |
76 | extern void omap3_save_scratchpad_contents(void); | 77 | extern void omap3_save_scratchpad_contents(void); |
77 | 78 | ||
78 | extern unsigned int omap24xx_idle_loop_suspend_sz; | 79 | extern unsigned int omap24xx_idle_loop_suspend_sz; |
79 | extern unsigned int omap34xx_suspend_sz; | 80 | extern unsigned int omap34xx_suspend_sz; |
80 | extern unsigned int save_secure_ram_context_sz; | 81 | extern unsigned int save_secure_ram_context_sz; |
81 | extern unsigned int omap24xx_cpu_suspend_sz; | 82 | extern unsigned int omap24xx_cpu_suspend_sz; |
82 | extern unsigned int omap34xx_cpu_suspend_sz; | 83 | extern unsigned int omap34xx_cpu_suspend_sz; |
83 | 84 | ||
84 | #endif | 85 | #endif |
85 | 86 |
arch/arm/mach-omap2/pm34xx.c
1 | /* | 1 | /* |
2 | * OMAP3 Power Management Routines | 2 | * OMAP3 Power Management Routines |
3 | * | 3 | * |
4 | * Copyright (C) 2006-2008 Nokia Corporation | 4 | * Copyright (C) 2006-2008 Nokia Corporation |
5 | * Tony Lindgren <tony@atomide.com> | 5 | * Tony Lindgren <tony@atomide.com> |
6 | * Jouni Hogander | 6 | * Jouni Hogander |
7 | * | 7 | * |
8 | * Copyright (C) 2007 Texas Instruments, Inc. | 8 | * Copyright (C) 2007 Texas Instruments, Inc. |
9 | * Rajendra Nayak <rnayak@ti.com> | 9 | * Rajendra Nayak <rnayak@ti.com> |
10 | * | 10 | * |
11 | * Copyright (C) 2005 Texas Instruments, Inc. | 11 | * Copyright (C) 2005 Texas Instruments, Inc. |
12 | * Richard Woodruff <r-woodruff2@ti.com> | 12 | * Richard Woodruff <r-woodruff2@ti.com> |
13 | * | 13 | * |
14 | * Based on pm.c for omap1 | 14 | * Based on pm.c for omap1 |
15 | * | 15 | * |
16 | * This program is free software; you can redistribute it and/or modify | 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 | 17 | * it under the terms of the GNU General Public License version 2 as |
18 | * published by the Free Software Foundation. | 18 | * published by the Free Software Foundation. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/pm.h> | 21 | #include <linux/pm.h> |
22 | #include <linux/suspend.h> | 22 | #include <linux/suspend.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/list.h> | 25 | #include <linux/list.h> |
26 | #include <linux/err.h> | 26 | #include <linux/err.h> |
27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <linux/clk.h> | 28 | #include <linux/clk.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | 31 | ||
32 | #include <plat/sram.h> | 32 | #include <plat/sram.h> |
33 | #include <plat/clockdomain.h> | 33 | #include <plat/clockdomain.h> |
34 | #include <plat/powerdomain.h> | 34 | #include <plat/powerdomain.h> |
35 | #include <plat/control.h> | 35 | #include <plat/control.h> |
36 | #include <plat/serial.h> | 36 | #include <plat/serial.h> |
37 | #include <plat/sdrc.h> | 37 | #include <plat/sdrc.h> |
38 | #include <plat/prcm.h> | 38 | #include <plat/prcm.h> |
39 | #include <plat/gpmc.h> | 39 | #include <plat/gpmc.h> |
40 | #include <plat/dma.h> | 40 | #include <plat/dma.h> |
41 | #include <plat/dmtimer.h> | 41 | #include <plat/dmtimer.h> |
42 | 42 | ||
43 | #include <asm/tlbflush.h> | 43 | #include <asm/tlbflush.h> |
44 | 44 | ||
45 | #include "cm.h" | 45 | #include "cm.h" |
46 | #include "cm-regbits-34xx.h" | 46 | #include "cm-regbits-34xx.h" |
47 | #include "prm-regbits-34xx.h" | 47 | #include "prm-regbits-34xx.h" |
48 | 48 | ||
49 | #include "prm.h" | 49 | #include "prm.h" |
50 | #include "pm.h" | 50 | #include "pm.h" |
51 | #include "sdrc.h" | 51 | #include "sdrc.h" |
52 | 52 | ||
53 | /* Scratchpad offsets */ | 53 | /* Scratchpad offsets */ |
54 | #define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 | 54 | #define OMAP343X_TABLE_ADDRESS_OFFSET 0x31 |
55 | #define OMAP343X_TABLE_VALUE_OFFSET 0x30 | 55 | #define OMAP343X_TABLE_VALUE_OFFSET 0x30 |
56 | #define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32 | 56 | #define OMAP343X_CONTROL_REG_VALUE_OFFSET 0x32 |
57 | 57 | ||
58 | u32 enable_off_mode; | 58 | u32 enable_off_mode; |
59 | u32 sleep_while_idle; | 59 | u32 sleep_while_idle; |
60 | u32 wakeup_timer_seconds; | 60 | u32 wakeup_timer_seconds; |
61 | u32 wakeup_timer_milliseconds; | ||
61 | 62 | ||
62 | struct power_state { | 63 | struct power_state { |
63 | struct powerdomain *pwrdm; | 64 | struct powerdomain *pwrdm; |
64 | u32 next_state; | 65 | u32 next_state; |
65 | #ifdef CONFIG_SUSPEND | 66 | #ifdef CONFIG_SUSPEND |
66 | u32 saved_state; | 67 | u32 saved_state; |
67 | #endif | 68 | #endif |
68 | struct list_head node; | 69 | struct list_head node; |
69 | }; | 70 | }; |
70 | 71 | ||
71 | static LIST_HEAD(pwrst_list); | 72 | static LIST_HEAD(pwrst_list); |
72 | 73 | ||
73 | static void (*_omap_sram_idle)(u32 *addr, int save_state); | 74 | static void (*_omap_sram_idle)(u32 *addr, int save_state); |
74 | 75 | ||
75 | static int (*_omap_save_secure_sram)(u32 *addr); | 76 | static int (*_omap_save_secure_sram)(u32 *addr); |
76 | 77 | ||
77 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; | 78 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; |
78 | static struct powerdomain *core_pwrdm, *per_pwrdm; | 79 | static struct powerdomain *core_pwrdm, *per_pwrdm; |
79 | static struct powerdomain *cam_pwrdm; | 80 | static struct powerdomain *cam_pwrdm; |
80 | 81 | ||
81 | static inline void omap3_per_save_context(void) | 82 | static inline void omap3_per_save_context(void) |
82 | { | 83 | { |
83 | omap_gpio_save_context(); | 84 | omap_gpio_save_context(); |
84 | } | 85 | } |
85 | 86 | ||
86 | static inline void omap3_per_restore_context(void) | 87 | static inline void omap3_per_restore_context(void) |
87 | { | 88 | { |
88 | omap_gpio_restore_context(); | 89 | omap_gpio_restore_context(); |
89 | } | 90 | } |
90 | 91 | ||
91 | static void omap3_enable_io_chain(void) | 92 | static void omap3_enable_io_chain(void) |
92 | { | 93 | { |
93 | int timeout = 0; | 94 | int timeout = 0; |
94 | 95 | ||
95 | if (omap_rev() >= OMAP3430_REV_ES3_1) { | 96 | if (omap_rev() >= OMAP3430_REV_ES3_1) { |
96 | prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); | 97 | prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); |
97 | /* Do a readback to assure write has been done */ | 98 | /* Do a readback to assure write has been done */ |
98 | prm_read_mod_reg(WKUP_MOD, PM_WKEN); | 99 | prm_read_mod_reg(WKUP_MOD, PM_WKEN); |
99 | 100 | ||
100 | while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) & | 101 | while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) & |
101 | OMAP3430_ST_IO_CHAIN)) { | 102 | OMAP3430_ST_IO_CHAIN)) { |
102 | timeout++; | 103 | timeout++; |
103 | if (timeout > 1000) { | 104 | if (timeout > 1000) { |
104 | printk(KERN_ERR "Wake up daisy chain " | 105 | printk(KERN_ERR "Wake up daisy chain " |
105 | "activation failed.\n"); | 106 | "activation failed.\n"); |
106 | return; | 107 | return; |
107 | } | 108 | } |
108 | prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN, | 109 | prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN, |
109 | WKUP_MOD, PM_WKST); | 110 | WKUP_MOD, PM_WKST); |
110 | } | 111 | } |
111 | } | 112 | } |
112 | } | 113 | } |
113 | 114 | ||
114 | static void omap3_disable_io_chain(void) | 115 | static void omap3_disable_io_chain(void) |
115 | { | 116 | { |
116 | if (omap_rev() >= OMAP3430_REV_ES3_1) | 117 | if (omap_rev() >= OMAP3430_REV_ES3_1) |
117 | prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); | 118 | prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN); |
118 | } | 119 | } |
119 | 120 | ||
120 | static void omap3_core_save_context(void) | 121 | static void omap3_core_save_context(void) |
121 | { | 122 | { |
122 | u32 control_padconf_off; | 123 | u32 control_padconf_off; |
123 | 124 | ||
124 | /* Save the padconf registers */ | 125 | /* Save the padconf registers */ |
125 | control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF); | 126 | control_padconf_off = omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF); |
126 | control_padconf_off |= START_PADCONF_SAVE; | 127 | control_padconf_off |= START_PADCONF_SAVE; |
127 | omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF); | 128 | omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF); |
128 | /* wait for the save to complete */ | 129 | /* wait for the save to complete */ |
129 | while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) | 130 | while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS) |
130 | & PADCONF_SAVE_DONE)) | 131 | & PADCONF_SAVE_DONE)) |
131 | udelay(1); | 132 | udelay(1); |
132 | 133 | ||
133 | /* | 134 | /* |
134 | * Force write last pad into memory, as this can fail in some | 135 | * Force write last pad into memory, as this can fail in some |
135 | * cases according to erratas 1.157, 1.185 | 136 | * cases according to erratas 1.157, 1.185 |
136 | */ | 137 | */ |
137 | omap_ctrl_writel(omap_ctrl_readl(OMAP343X_PADCONF_ETK_D14), | 138 | omap_ctrl_writel(omap_ctrl_readl(OMAP343X_PADCONF_ETK_D14), |
138 | OMAP343X_CONTROL_MEM_WKUP + 0x2a0); | 139 | OMAP343X_CONTROL_MEM_WKUP + 0x2a0); |
139 | 140 | ||
140 | /* Save the Interrupt controller context */ | 141 | /* Save the Interrupt controller context */ |
141 | omap_intc_save_context(); | 142 | omap_intc_save_context(); |
142 | /* Save the GPMC context */ | 143 | /* Save the GPMC context */ |
143 | omap3_gpmc_save_context(); | 144 | omap3_gpmc_save_context(); |
144 | /* Save the system control module context, padconf already save above*/ | 145 | /* Save the system control module context, padconf already save above*/ |
145 | omap3_control_save_context(); | 146 | omap3_control_save_context(); |
146 | omap_dma_global_context_save(); | 147 | omap_dma_global_context_save(); |
147 | } | 148 | } |
148 | 149 | ||
149 | static void omap3_core_restore_context(void) | 150 | static void omap3_core_restore_context(void) |
150 | { | 151 | { |
151 | /* Restore the control module context, padconf restored by h/w */ | 152 | /* Restore the control module context, padconf restored by h/w */ |
152 | omap3_control_restore_context(); | 153 | omap3_control_restore_context(); |
153 | /* Restore the GPMC context */ | 154 | /* Restore the GPMC context */ |
154 | omap3_gpmc_restore_context(); | 155 | omap3_gpmc_restore_context(); |
155 | /* Restore the interrupt controller context */ | 156 | /* Restore the interrupt controller context */ |
156 | omap_intc_restore_context(); | 157 | omap_intc_restore_context(); |
157 | omap_dma_global_context_restore(); | 158 | omap_dma_global_context_restore(); |
158 | } | 159 | } |
159 | 160 | ||
160 | /* | 161 | /* |
161 | * FIXME: This function should be called before entering off-mode after | 162 | * FIXME: This function should be called before entering off-mode after |
162 | * OMAP3 secure services have been accessed. Currently it is only called | 163 | * OMAP3 secure services have been accessed. Currently it is only called |
163 | * once during boot sequence, but this works as we are not using secure | 164 | * once during boot sequence, but this works as we are not using secure |
164 | * services. | 165 | * services. |
165 | */ | 166 | */ |
166 | static void omap3_save_secure_ram_context(u32 target_mpu_state) | 167 | static void omap3_save_secure_ram_context(u32 target_mpu_state) |
167 | { | 168 | { |
168 | u32 ret; | 169 | u32 ret; |
169 | 170 | ||
170 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | 171 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { |
171 | /* | 172 | /* |
172 | * MPU next state must be set to POWER_ON temporarily, | 173 | * MPU next state must be set to POWER_ON temporarily, |
173 | * otherwise the WFI executed inside the ROM code | 174 | * otherwise the WFI executed inside the ROM code |
174 | * will hang the system. | 175 | * will hang the system. |
175 | */ | 176 | */ |
176 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | 177 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); |
177 | ret = _omap_save_secure_sram((u32 *) | 178 | ret = _omap_save_secure_sram((u32 *) |
178 | __pa(omap3_secure_ram_storage)); | 179 | __pa(omap3_secure_ram_storage)); |
179 | pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state); | 180 | pwrdm_set_next_pwrst(mpu_pwrdm, target_mpu_state); |
180 | /* Following is for error tracking, it should not happen */ | 181 | /* Following is for error tracking, it should not happen */ |
181 | if (ret) { | 182 | if (ret) { |
182 | printk(KERN_ERR "save_secure_sram() returns %08x\n", | 183 | printk(KERN_ERR "save_secure_sram() returns %08x\n", |
183 | ret); | 184 | ret); |
184 | while (1) | 185 | while (1) |
185 | ; | 186 | ; |
186 | } | 187 | } |
187 | } | 188 | } |
188 | } | 189 | } |
189 | 190 | ||
190 | /* | 191 | /* |
191 | * PRCM Interrupt Handler Helper Function | 192 | * PRCM Interrupt Handler Helper Function |
192 | * | 193 | * |
193 | * The purpose of this function is to clear any wake-up events latched | 194 | * The purpose of this function is to clear any wake-up events latched |
194 | * in the PRCM PM_WKST_x registers. It is possible that a wake-up event | 195 | * in the PRCM PM_WKST_x registers. It is possible that a wake-up event |
195 | * may occur whilst attempting to clear a PM_WKST_x register and thus | 196 | * may occur whilst attempting to clear a PM_WKST_x register and thus |
196 | * set another bit in this register. A while loop is used to ensure | 197 | * set another bit in this register. A while loop is used to ensure |
197 | * that any peripheral wake-up events occurring while attempting to | 198 | * that any peripheral wake-up events occurring while attempting to |
198 | * clear the PM_WKST_x are detected and cleared. | 199 | * clear the PM_WKST_x are detected and cleared. |
199 | */ | 200 | */ |
200 | static int prcm_clear_mod_irqs(s16 module, u8 regs) | 201 | static int prcm_clear_mod_irqs(s16 module, u8 regs) |
201 | { | 202 | { |
202 | u32 wkst, fclk, iclk, clken; | 203 | u32 wkst, fclk, iclk, clken; |
203 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; | 204 | u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1; |
204 | u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1; | 205 | u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1; |
205 | u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1; | 206 | u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1; |
206 | u16 grpsel_off = (regs == 3) ? | 207 | u16 grpsel_off = (regs == 3) ? |
207 | OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL; | 208 | OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL; |
208 | int c = 0; | 209 | int c = 0; |
209 | 210 | ||
210 | wkst = prm_read_mod_reg(module, wkst_off); | 211 | wkst = prm_read_mod_reg(module, wkst_off); |
211 | wkst &= prm_read_mod_reg(module, grpsel_off); | 212 | wkst &= prm_read_mod_reg(module, grpsel_off); |
212 | if (wkst) { | 213 | if (wkst) { |
213 | iclk = cm_read_mod_reg(module, iclk_off); | 214 | iclk = cm_read_mod_reg(module, iclk_off); |
214 | fclk = cm_read_mod_reg(module, fclk_off); | 215 | fclk = cm_read_mod_reg(module, fclk_off); |
215 | while (wkst) { | 216 | while (wkst) { |
216 | clken = wkst; | 217 | clken = wkst; |
217 | cm_set_mod_reg_bits(clken, module, iclk_off); | 218 | cm_set_mod_reg_bits(clken, module, iclk_off); |
218 | /* | 219 | /* |
219 | * For USBHOST, we don't know whether HOST1 or | 220 | * For USBHOST, we don't know whether HOST1 or |
220 | * HOST2 woke us up, so enable both f-clocks | 221 | * HOST2 woke us up, so enable both f-clocks |
221 | */ | 222 | */ |
222 | if (module == OMAP3430ES2_USBHOST_MOD) | 223 | if (module == OMAP3430ES2_USBHOST_MOD) |
223 | clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT; | 224 | clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT; |
224 | cm_set_mod_reg_bits(clken, module, fclk_off); | 225 | cm_set_mod_reg_bits(clken, module, fclk_off); |
225 | prm_write_mod_reg(wkst, module, wkst_off); | 226 | prm_write_mod_reg(wkst, module, wkst_off); |
226 | wkst = prm_read_mod_reg(module, wkst_off); | 227 | wkst = prm_read_mod_reg(module, wkst_off); |
227 | c++; | 228 | c++; |
228 | } | 229 | } |
229 | cm_write_mod_reg(iclk, module, iclk_off); | 230 | cm_write_mod_reg(iclk, module, iclk_off); |
230 | cm_write_mod_reg(fclk, module, fclk_off); | 231 | cm_write_mod_reg(fclk, module, fclk_off); |
231 | } | 232 | } |
232 | 233 | ||
233 | return c; | 234 | return c; |
234 | } | 235 | } |
235 | 236 | ||
236 | static int _prcm_int_handle_wakeup(void) | 237 | static int _prcm_int_handle_wakeup(void) |
237 | { | 238 | { |
238 | int c; | 239 | int c; |
239 | 240 | ||
240 | c = prcm_clear_mod_irqs(WKUP_MOD, 1); | 241 | c = prcm_clear_mod_irqs(WKUP_MOD, 1); |
241 | c += prcm_clear_mod_irqs(CORE_MOD, 1); | 242 | c += prcm_clear_mod_irqs(CORE_MOD, 1); |
242 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1); | 243 | c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1); |
243 | if (omap_rev() > OMAP3430_REV_ES1_0) { | 244 | if (omap_rev() > OMAP3430_REV_ES1_0) { |
244 | c += prcm_clear_mod_irqs(CORE_MOD, 3); | 245 | c += prcm_clear_mod_irqs(CORE_MOD, 3); |
245 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1); | 246 | c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1); |
246 | } | 247 | } |
247 | 248 | ||
248 | return c; | 249 | return c; |
249 | } | 250 | } |
250 | 251 | ||
251 | /* | 252 | /* |
252 | * PRCM Interrupt Handler | 253 | * PRCM Interrupt Handler |
253 | * | 254 | * |
254 | * The PRM_IRQSTATUS_MPU register indicates if there are any pending | 255 | * The PRM_IRQSTATUS_MPU register indicates if there are any pending |
255 | * interrupts from the PRCM for the MPU. These bits must be cleared in | 256 | * interrupts from the PRCM for the MPU. These bits must be cleared in |
256 | * order to clear the PRCM interrupt. The PRCM interrupt handler is | 257 | * order to clear the PRCM interrupt. The PRCM interrupt handler is |
257 | * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear | 258 | * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear |
258 | * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU | 259 | * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU |
259 | * register indicates that a wake-up event is pending for the MPU and | 260 | * register indicates that a wake-up event is pending for the MPU and |
260 | * this bit can only be cleared if the all the wake-up events latched | 261 | * this bit can only be cleared if the all the wake-up events latched |
261 | * in the various PM_WKST_x registers have been cleared. The interrupt | 262 | * in the various PM_WKST_x registers have been cleared. The interrupt |
262 | * handler is implemented using a do-while loop so that if a wake-up | 263 | * handler is implemented using a do-while loop so that if a wake-up |
263 | * event occurred during the processing of the prcm interrupt handler | 264 | * event occurred during the processing of the prcm interrupt handler |
264 | * (setting a bit in the corresponding PM_WKST_x register and thus | 265 | * (setting a bit in the corresponding PM_WKST_x register and thus |
265 | * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register) | 266 | * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register) |
266 | * this would be handled. | 267 | * this would be handled. |
267 | */ | 268 | */ |
268 | static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) | 269 | static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id) |
269 | { | 270 | { |
270 | u32 irqenable_mpu, irqstatus_mpu; | 271 | u32 irqenable_mpu, irqstatus_mpu; |
271 | int c = 0; | 272 | int c = 0; |
272 | 273 | ||
273 | irqenable_mpu = prm_read_mod_reg(OCP_MOD, | 274 | irqenable_mpu = prm_read_mod_reg(OCP_MOD, |
274 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | 275 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); |
275 | irqstatus_mpu = prm_read_mod_reg(OCP_MOD, | 276 | irqstatus_mpu = prm_read_mod_reg(OCP_MOD, |
276 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 277 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
277 | irqstatus_mpu &= irqenable_mpu; | 278 | irqstatus_mpu &= irqenable_mpu; |
278 | 279 | ||
279 | do { | 280 | do { |
280 | if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) { | 281 | if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) { |
281 | c = _prcm_int_handle_wakeup(); | 282 | c = _prcm_int_handle_wakeup(); |
282 | 283 | ||
283 | /* | 284 | /* |
284 | * Is the MPU PRCM interrupt handler racing with the | 285 | * Is the MPU PRCM interrupt handler racing with the |
285 | * IVA2 PRCM interrupt handler ? | 286 | * IVA2 PRCM interrupt handler ? |
286 | */ | 287 | */ |
287 | WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup " | 288 | WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup " |
288 | "but no wakeup sources are marked\n"); | 289 | "but no wakeup sources are marked\n"); |
289 | } else { | 290 | } else { |
290 | /* XXX we need to expand our PRCM interrupt handler */ | 291 | /* XXX we need to expand our PRCM interrupt handler */ |
291 | WARN(1, "prcm: WARNING: PRCM interrupt received, but " | 292 | WARN(1, "prcm: WARNING: PRCM interrupt received, but " |
292 | "no code to handle it (%08x)\n", irqstatus_mpu); | 293 | "no code to handle it (%08x)\n", irqstatus_mpu); |
293 | } | 294 | } |
294 | 295 | ||
295 | prm_write_mod_reg(irqstatus_mpu, OCP_MOD, | 296 | prm_write_mod_reg(irqstatus_mpu, OCP_MOD, |
296 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 297 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
297 | 298 | ||
298 | irqstatus_mpu = prm_read_mod_reg(OCP_MOD, | 299 | irqstatus_mpu = prm_read_mod_reg(OCP_MOD, |
299 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 300 | OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
300 | irqstatus_mpu &= irqenable_mpu; | 301 | irqstatus_mpu &= irqenable_mpu; |
301 | 302 | ||
302 | } while (irqstatus_mpu); | 303 | } while (irqstatus_mpu); |
303 | 304 | ||
304 | return IRQ_HANDLED; | 305 | return IRQ_HANDLED; |
305 | } | 306 | } |
306 | 307 | ||
307 | static void restore_control_register(u32 val) | 308 | static void restore_control_register(u32 val) |
308 | { | 309 | { |
309 | __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val)); | 310 | __asm__ __volatile__ ("mcr p15, 0, %0, c1, c0, 0" : : "r" (val)); |
310 | } | 311 | } |
311 | 312 | ||
312 | /* Function to restore the table entry that was modified for enabling MMU */ | 313 | /* Function to restore the table entry that was modified for enabling MMU */ |
313 | static void restore_table_entry(void) | 314 | static void restore_table_entry(void) |
314 | { | 315 | { |
315 | u32 *scratchpad_address; | 316 | u32 *scratchpad_address; |
316 | u32 previous_value, control_reg_value; | 317 | u32 previous_value, control_reg_value; |
317 | u32 *address; | 318 | u32 *address; |
318 | 319 | ||
319 | scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); | 320 | scratchpad_address = OMAP2_L4_IO_ADDRESS(OMAP343X_SCRATCHPAD); |
320 | 321 | ||
321 | /* Get address of entry that was modified */ | 322 | /* Get address of entry that was modified */ |
322 | address = (u32 *)__raw_readl(scratchpad_address + | 323 | address = (u32 *)__raw_readl(scratchpad_address + |
323 | OMAP343X_TABLE_ADDRESS_OFFSET); | 324 | OMAP343X_TABLE_ADDRESS_OFFSET); |
324 | /* Get the previous value which needs to be restored */ | 325 | /* Get the previous value which needs to be restored */ |
325 | previous_value = __raw_readl(scratchpad_address + | 326 | previous_value = __raw_readl(scratchpad_address + |
326 | OMAP343X_TABLE_VALUE_OFFSET); | 327 | OMAP343X_TABLE_VALUE_OFFSET); |
327 | address = __va(address); | 328 | address = __va(address); |
328 | *address = previous_value; | 329 | *address = previous_value; |
329 | flush_tlb_all(); | 330 | flush_tlb_all(); |
330 | control_reg_value = __raw_readl(scratchpad_address | 331 | control_reg_value = __raw_readl(scratchpad_address |
331 | + OMAP343X_CONTROL_REG_VALUE_OFFSET); | 332 | + OMAP343X_CONTROL_REG_VALUE_OFFSET); |
332 | /* This will enable caches and prediction */ | 333 | /* This will enable caches and prediction */ |
333 | restore_control_register(control_reg_value); | 334 | restore_control_register(control_reg_value); |
334 | } | 335 | } |
335 | 336 | ||
336 | void omap_sram_idle(void) | 337 | void omap_sram_idle(void) |
337 | { | 338 | { |
338 | /* Variable to tell what needs to be saved and restored | 339 | /* Variable to tell what needs to be saved and restored |
339 | * in omap_sram_idle*/ | 340 | * in omap_sram_idle*/ |
340 | /* save_state = 0 => Nothing to save and restored */ | 341 | /* save_state = 0 => Nothing to save and restored */ |
341 | /* save_state = 1 => Only L1 and logic lost */ | 342 | /* save_state = 1 => Only L1 and logic lost */ |
342 | /* save_state = 2 => Only L2 lost */ | 343 | /* save_state = 2 => Only L2 lost */ |
343 | /* save_state = 3 => L1, L2 and logic lost */ | 344 | /* save_state = 3 => L1, L2 and logic lost */ |
344 | int save_state = 0; | 345 | int save_state = 0; |
345 | int mpu_next_state = PWRDM_POWER_ON; | 346 | int mpu_next_state = PWRDM_POWER_ON; |
346 | int per_next_state = PWRDM_POWER_ON; | 347 | int per_next_state = PWRDM_POWER_ON; |
347 | int core_next_state = PWRDM_POWER_ON; | 348 | int core_next_state = PWRDM_POWER_ON; |
348 | int core_prev_state, per_prev_state; | 349 | int core_prev_state, per_prev_state; |
349 | u32 sdrc_pwr = 0; | 350 | u32 sdrc_pwr = 0; |
350 | int per_state_modified = 0; | 351 | int per_state_modified = 0; |
351 | 352 | ||
352 | if (!_omap_sram_idle) | 353 | if (!_omap_sram_idle) |
353 | return; | 354 | return; |
354 | 355 | ||
355 | pwrdm_clear_all_prev_pwrst(mpu_pwrdm); | 356 | pwrdm_clear_all_prev_pwrst(mpu_pwrdm); |
356 | pwrdm_clear_all_prev_pwrst(neon_pwrdm); | 357 | pwrdm_clear_all_prev_pwrst(neon_pwrdm); |
357 | pwrdm_clear_all_prev_pwrst(core_pwrdm); | 358 | pwrdm_clear_all_prev_pwrst(core_pwrdm); |
358 | pwrdm_clear_all_prev_pwrst(per_pwrdm); | 359 | pwrdm_clear_all_prev_pwrst(per_pwrdm); |
359 | 360 | ||
360 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); | 361 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); |
361 | switch (mpu_next_state) { | 362 | switch (mpu_next_state) { |
362 | case PWRDM_POWER_ON: | 363 | case PWRDM_POWER_ON: |
363 | case PWRDM_POWER_RET: | 364 | case PWRDM_POWER_RET: |
364 | /* No need to save context */ | 365 | /* No need to save context */ |
365 | save_state = 0; | 366 | save_state = 0; |
366 | break; | 367 | break; |
367 | case PWRDM_POWER_OFF: | 368 | case PWRDM_POWER_OFF: |
368 | save_state = 3; | 369 | save_state = 3; |
369 | break; | 370 | break; |
370 | default: | 371 | default: |
371 | /* Invalid state */ | 372 | /* Invalid state */ |
372 | printk(KERN_ERR "Invalid mpu state in sram_idle\n"); | 373 | printk(KERN_ERR "Invalid mpu state in sram_idle\n"); |
373 | return; | 374 | return; |
374 | } | 375 | } |
375 | pwrdm_pre_transition(); | 376 | pwrdm_pre_transition(); |
376 | 377 | ||
377 | /* NEON control */ | 378 | /* NEON control */ |
378 | if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) | 379 | if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) |
379 | pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); | 380 | pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state); |
380 | 381 | ||
381 | /* PER */ | 382 | /* PER */ |
382 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); | 383 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); |
383 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); | 384 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); |
384 | if (per_next_state < PWRDM_POWER_ON) { | 385 | if (per_next_state < PWRDM_POWER_ON) { |
385 | omap_uart_prepare_idle(2); | 386 | omap_uart_prepare_idle(2); |
386 | omap2_gpio_prepare_for_retention(); | 387 | omap2_gpio_prepare_for_retention(); |
387 | if (per_next_state == PWRDM_POWER_OFF) { | 388 | if (per_next_state == PWRDM_POWER_OFF) { |
388 | if (core_next_state == PWRDM_POWER_ON) { | 389 | if (core_next_state == PWRDM_POWER_ON) { |
389 | per_next_state = PWRDM_POWER_RET; | 390 | per_next_state = PWRDM_POWER_RET; |
390 | pwrdm_set_next_pwrst(per_pwrdm, per_next_state); | 391 | pwrdm_set_next_pwrst(per_pwrdm, per_next_state); |
391 | per_state_modified = 1; | 392 | per_state_modified = 1; |
392 | } else | 393 | } else |
393 | omap3_per_save_context(); | 394 | omap3_per_save_context(); |
394 | } | 395 | } |
395 | } | 396 | } |
396 | 397 | ||
397 | if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) | 398 | if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON) |
398 | omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]); | 399 | omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]); |
399 | 400 | ||
400 | /* CORE */ | 401 | /* CORE */ |
401 | if (core_next_state < PWRDM_POWER_ON) { | 402 | if (core_next_state < PWRDM_POWER_ON) { |
402 | omap_uart_prepare_idle(0); | 403 | omap_uart_prepare_idle(0); |
403 | omap_uart_prepare_idle(1); | 404 | omap_uart_prepare_idle(1); |
404 | if (core_next_state == PWRDM_POWER_OFF) { | 405 | if (core_next_state == PWRDM_POWER_OFF) { |
405 | omap3_core_save_context(); | 406 | omap3_core_save_context(); |
406 | omap3_prcm_save_context(); | 407 | omap3_prcm_save_context(); |
407 | } | 408 | } |
408 | /* Enable IO-PAD and IO-CHAIN wakeups */ | 409 | /* Enable IO-PAD and IO-CHAIN wakeups */ |
409 | prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | 410 | prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); |
410 | omap3_enable_io_chain(); | 411 | omap3_enable_io_chain(); |
411 | } | 412 | } |
412 | omap3_intc_prepare_idle(); | 413 | omap3_intc_prepare_idle(); |
413 | 414 | ||
414 | /* | 415 | /* |
415 | * On EMU/HS devices ROM code restores a SRDC value | 416 | * On EMU/HS devices ROM code restores a SRDC value |
416 | * from scratchpad which has automatic self refresh on timeout | 417 | * from scratchpad which has automatic self refresh on timeout |
417 | * of AUTO_CNT = 1 enabled. This takes care of errata 1.142. | 418 | * of AUTO_CNT = 1 enabled. This takes care of errata 1.142. |
418 | * Hence store/restore the SDRC_POWER register here. | 419 | * Hence store/restore the SDRC_POWER register here. |
419 | */ | 420 | */ |
420 | if (omap_rev() >= OMAP3430_REV_ES3_0 && | 421 | if (omap_rev() >= OMAP3430_REV_ES3_0 && |
421 | omap_type() != OMAP2_DEVICE_TYPE_GP && | 422 | omap_type() != OMAP2_DEVICE_TYPE_GP && |
422 | core_next_state == PWRDM_POWER_OFF) | 423 | core_next_state == PWRDM_POWER_OFF) |
423 | sdrc_pwr = sdrc_read_reg(SDRC_POWER); | 424 | sdrc_pwr = sdrc_read_reg(SDRC_POWER); |
424 | 425 | ||
425 | /* | 426 | /* |
426 | * omap3_arm_context is the location where ARM registers | 427 | * omap3_arm_context is the location where ARM registers |
427 | * get saved. The restore path then reads from this | 428 | * get saved. The restore path then reads from this |
428 | * location and restores them back. | 429 | * location and restores them back. |
429 | */ | 430 | */ |
430 | _omap_sram_idle(omap3_arm_context, save_state); | 431 | _omap_sram_idle(omap3_arm_context, save_state); |
431 | cpu_init(); | 432 | cpu_init(); |
432 | 433 | ||
433 | /* Restore normal SDRC POWER settings */ | 434 | /* Restore normal SDRC POWER settings */ |
434 | if (omap_rev() >= OMAP3430_REV_ES3_0 && | 435 | if (omap_rev() >= OMAP3430_REV_ES3_0 && |
435 | omap_type() != OMAP2_DEVICE_TYPE_GP && | 436 | omap_type() != OMAP2_DEVICE_TYPE_GP && |
436 | core_next_state == PWRDM_POWER_OFF) | 437 | core_next_state == PWRDM_POWER_OFF) |
437 | sdrc_write_reg(sdrc_pwr, SDRC_POWER); | 438 | sdrc_write_reg(sdrc_pwr, SDRC_POWER); |
438 | 439 | ||
439 | /* Restore table entry modified during MMU restoration */ | 440 | /* Restore table entry modified during MMU restoration */ |
440 | if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) | 441 | if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF) |
441 | restore_table_entry(); | 442 | restore_table_entry(); |
442 | 443 | ||
443 | /* CORE */ | 444 | /* CORE */ |
444 | if (core_next_state < PWRDM_POWER_ON) { | 445 | if (core_next_state < PWRDM_POWER_ON) { |
445 | core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); | 446 | core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm); |
446 | if (core_prev_state == PWRDM_POWER_OFF) { | 447 | if (core_prev_state == PWRDM_POWER_OFF) { |
447 | omap3_core_restore_context(); | 448 | omap3_core_restore_context(); |
448 | omap3_prcm_restore_context(); | 449 | omap3_prcm_restore_context(); |
449 | omap3_sram_restore_context(); | 450 | omap3_sram_restore_context(); |
450 | omap2_sms_restore_context(); | 451 | omap2_sms_restore_context(); |
451 | } | 452 | } |
452 | omap_uart_resume_idle(0); | 453 | omap_uart_resume_idle(0); |
453 | omap_uart_resume_idle(1); | 454 | omap_uart_resume_idle(1); |
454 | if (core_next_state == PWRDM_POWER_OFF) | 455 | if (core_next_state == PWRDM_POWER_OFF) |
455 | prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, | 456 | prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF, |
456 | OMAP3430_GR_MOD, | 457 | OMAP3430_GR_MOD, |
457 | OMAP3_PRM_VOLTCTRL_OFFSET); | 458 | OMAP3_PRM_VOLTCTRL_OFFSET); |
458 | } | 459 | } |
459 | omap3_intc_resume_idle(); | 460 | omap3_intc_resume_idle(); |
460 | 461 | ||
461 | /* PER */ | 462 | /* PER */ |
462 | if (per_next_state < PWRDM_POWER_ON) { | 463 | if (per_next_state < PWRDM_POWER_ON) { |
463 | per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); | 464 | per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm); |
464 | if (per_prev_state == PWRDM_POWER_OFF) | 465 | if (per_prev_state == PWRDM_POWER_OFF) |
465 | omap3_per_restore_context(); | 466 | omap3_per_restore_context(); |
466 | omap2_gpio_resume_after_retention(); | 467 | omap2_gpio_resume_after_retention(); |
467 | omap_uart_resume_idle(2); | 468 | omap_uart_resume_idle(2); |
468 | if (per_state_modified) | 469 | if (per_state_modified) |
469 | pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); | 470 | pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF); |
470 | } | 471 | } |
471 | 472 | ||
472 | /* Disable IO-PAD and IO-CHAIN wakeup */ | 473 | /* Disable IO-PAD and IO-CHAIN wakeup */ |
473 | if (core_next_state < PWRDM_POWER_ON) { | 474 | if (core_next_state < PWRDM_POWER_ON) { |
474 | prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | 475 | prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); |
475 | omap3_disable_io_chain(); | 476 | omap3_disable_io_chain(); |
476 | } | 477 | } |
477 | 478 | ||
478 | pwrdm_post_transition(); | 479 | pwrdm_post_transition(); |
479 | 480 | ||
480 | omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); | 481 | omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); |
481 | } | 482 | } |
482 | 483 | ||
483 | int omap3_can_sleep(void) | 484 | int omap3_can_sleep(void) |
484 | { | 485 | { |
485 | if (!sleep_while_idle) | 486 | if (!sleep_while_idle) |
486 | return 0; | 487 | return 0; |
487 | if (!omap_uart_can_sleep()) | 488 | if (!omap_uart_can_sleep()) |
488 | return 0; | 489 | return 0; |
489 | return 1; | 490 | return 1; |
490 | } | 491 | } |
491 | 492 | ||
492 | /* This sets pwrdm state (other than mpu & core. Currently only ON & | 493 | /* This sets pwrdm state (other than mpu & core. Currently only ON & |
493 | * RET are supported. Function is assuming that clkdm doesn't have | 494 | * RET are supported. Function is assuming that clkdm doesn't have |
494 | * hw_sup mode enabled. */ | 495 | * hw_sup mode enabled. */ |
495 | int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) | 496 | int set_pwrdm_state(struct powerdomain *pwrdm, u32 state) |
496 | { | 497 | { |
497 | u32 cur_state; | 498 | u32 cur_state; |
498 | int sleep_switch = 0; | 499 | int sleep_switch = 0; |
499 | int ret = 0; | 500 | int ret = 0; |
500 | 501 | ||
501 | if (pwrdm == NULL || IS_ERR(pwrdm)) | 502 | if (pwrdm == NULL || IS_ERR(pwrdm)) |
502 | return -EINVAL; | 503 | return -EINVAL; |
503 | 504 | ||
504 | while (!(pwrdm->pwrsts & (1 << state))) { | 505 | while (!(pwrdm->pwrsts & (1 << state))) { |
505 | if (state == PWRDM_POWER_OFF) | 506 | if (state == PWRDM_POWER_OFF) |
506 | return ret; | 507 | return ret; |
507 | state--; | 508 | state--; |
508 | } | 509 | } |
509 | 510 | ||
510 | cur_state = pwrdm_read_next_pwrst(pwrdm); | 511 | cur_state = pwrdm_read_next_pwrst(pwrdm); |
511 | if (cur_state == state) | 512 | if (cur_state == state) |
512 | return ret; | 513 | return ret; |
513 | 514 | ||
514 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { | 515 | if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) { |
515 | omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | 516 | omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); |
516 | sleep_switch = 1; | 517 | sleep_switch = 1; |
517 | pwrdm_wait_transition(pwrdm); | 518 | pwrdm_wait_transition(pwrdm); |
518 | } | 519 | } |
519 | 520 | ||
520 | ret = pwrdm_set_next_pwrst(pwrdm, state); | 521 | ret = pwrdm_set_next_pwrst(pwrdm, state); |
521 | if (ret) { | 522 | if (ret) { |
522 | printk(KERN_ERR "Unable to set state of powerdomain: %s\n", | 523 | printk(KERN_ERR "Unable to set state of powerdomain: %s\n", |
523 | pwrdm->name); | 524 | pwrdm->name); |
524 | goto err; | 525 | goto err; |
525 | } | 526 | } |
526 | 527 | ||
527 | if (sleep_switch) { | 528 | if (sleep_switch) { |
528 | omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); | 529 | omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); |
529 | pwrdm_wait_transition(pwrdm); | 530 | pwrdm_wait_transition(pwrdm); |
530 | pwrdm_state_switch(pwrdm); | 531 | pwrdm_state_switch(pwrdm); |
531 | } | 532 | } |
532 | 533 | ||
533 | err: | 534 | err: |
534 | return ret; | 535 | return ret; |
535 | } | 536 | } |
536 | 537 | ||
537 | static void omap3_pm_idle(void) | 538 | static void omap3_pm_idle(void) |
538 | { | 539 | { |
539 | local_irq_disable(); | 540 | local_irq_disable(); |
540 | local_fiq_disable(); | 541 | local_fiq_disable(); |
541 | 542 | ||
542 | if (!omap3_can_sleep()) | 543 | if (!omap3_can_sleep()) |
543 | goto out; | 544 | goto out; |
544 | 545 | ||
545 | if (omap_irq_pending() || need_resched()) | 546 | if (omap_irq_pending() || need_resched()) |
546 | goto out; | 547 | goto out; |
547 | 548 | ||
548 | omap_sram_idle(); | 549 | omap_sram_idle(); |
549 | 550 | ||
550 | out: | 551 | out: |
551 | local_fiq_enable(); | 552 | local_fiq_enable(); |
552 | local_irq_enable(); | 553 | local_irq_enable(); |
553 | } | 554 | } |
554 | 555 | ||
555 | #ifdef CONFIG_SUSPEND | 556 | #ifdef CONFIG_SUSPEND |
556 | static suspend_state_t suspend_state; | 557 | static suspend_state_t suspend_state; |
557 | 558 | ||
558 | static void omap2_pm_wakeup_on_timer(u32 seconds) | 559 | static void omap2_pm_wakeup_on_timer(u32 seconds, u32 milliseconds) |
559 | { | 560 | { |
560 | u32 tick_rate, cycles; | 561 | u32 tick_rate, cycles; |
561 | 562 | ||
562 | if (!seconds) | 563 | if (!seconds && !milliseconds) |
563 | return; | 564 | return; |
564 | 565 | ||
565 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); | 566 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer_wakeup)); |
566 | cycles = tick_rate * seconds; | 567 | cycles = tick_rate * seconds + tick_rate * milliseconds / 1000; |
567 | omap_dm_timer_stop(gptimer_wakeup); | 568 | omap_dm_timer_stop(gptimer_wakeup); |
568 | omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); | 569 | omap_dm_timer_set_load_start(gptimer_wakeup, 0, 0xffffffff - cycles); |
569 | 570 | ||
570 | pr_info("PM: Resume timer in %d secs (%d ticks at %d ticks/sec.)\n", | 571 | pr_info("PM: Resume timer in %u.%03u secs" |
571 | seconds, cycles, tick_rate); | 572 | " (%d ticks at %d ticks/sec.)\n", |
573 | seconds, milliseconds, cycles, tick_rate); | ||
572 | } | 574 | } |
573 | 575 | ||
574 | static int omap3_pm_prepare(void) | 576 | static int omap3_pm_prepare(void) |
575 | { | 577 | { |
576 | disable_hlt(); | 578 | disable_hlt(); |
577 | return 0; | 579 | return 0; |
578 | } | 580 | } |
579 | 581 | ||
580 | static int omap3_pm_suspend(void) | 582 | static int omap3_pm_suspend(void) |
581 | { | 583 | { |
582 | struct power_state *pwrst; | 584 | struct power_state *pwrst; |
583 | int state, ret = 0; | 585 | int state, ret = 0; |
584 | 586 | ||
585 | if (wakeup_timer_seconds) | 587 | if (wakeup_timer_seconds || wakeup_timer_milliseconds) |
586 | omap2_pm_wakeup_on_timer(wakeup_timer_seconds); | 588 | omap2_pm_wakeup_on_timer(wakeup_timer_seconds, |
589 | wakeup_timer_milliseconds); | ||
587 | 590 | ||
588 | /* Read current next_pwrsts */ | 591 | /* Read current next_pwrsts */ |
589 | list_for_each_entry(pwrst, &pwrst_list, node) | 592 | list_for_each_entry(pwrst, &pwrst_list, node) |
590 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); | 593 | pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); |
591 | /* Set ones wanted by suspend */ | 594 | /* Set ones wanted by suspend */ |
592 | list_for_each_entry(pwrst, &pwrst_list, node) { | 595 | list_for_each_entry(pwrst, &pwrst_list, node) { |
593 | if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state)) | 596 | if (set_pwrdm_state(pwrst->pwrdm, pwrst->next_state)) |
594 | goto restore; | 597 | goto restore; |
595 | if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm)) | 598 | if (pwrdm_clear_all_prev_pwrst(pwrst->pwrdm)) |
596 | goto restore; | 599 | goto restore; |
597 | } | 600 | } |
598 | 601 | ||
599 | omap_uart_prepare_suspend(); | 602 | omap_uart_prepare_suspend(); |
600 | omap3_intc_suspend(); | 603 | omap3_intc_suspend(); |
601 | 604 | ||
602 | omap_sram_idle(); | 605 | omap_sram_idle(); |
603 | 606 | ||
604 | restore: | 607 | restore: |
605 | /* Restore next_pwrsts */ | 608 | /* Restore next_pwrsts */ |
606 | list_for_each_entry(pwrst, &pwrst_list, node) { | 609 | list_for_each_entry(pwrst, &pwrst_list, node) { |
607 | state = pwrdm_read_prev_pwrst(pwrst->pwrdm); | 610 | state = pwrdm_read_prev_pwrst(pwrst->pwrdm); |
608 | if (state > pwrst->next_state) { | 611 | if (state > pwrst->next_state) { |
609 | printk(KERN_INFO "Powerdomain (%s) didn't enter " | 612 | printk(KERN_INFO "Powerdomain (%s) didn't enter " |
610 | "target state %d\n", | 613 | "target state %d\n", |
611 | pwrst->pwrdm->name, pwrst->next_state); | 614 | pwrst->pwrdm->name, pwrst->next_state); |
612 | ret = -1; | 615 | ret = -1; |
613 | } | 616 | } |
614 | set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); | 617 | set_pwrdm_state(pwrst->pwrdm, pwrst->saved_state); |
615 | } | 618 | } |
616 | if (ret) | 619 | if (ret) |
617 | printk(KERN_ERR "Could not enter target state in pm_suspend\n"); | 620 | printk(KERN_ERR "Could not enter target state in pm_suspend\n"); |
618 | else | 621 | else |
619 | printk(KERN_INFO "Successfully put all powerdomains " | 622 | printk(KERN_INFO "Successfully put all powerdomains " |
620 | "to target state\n"); | 623 | "to target state\n"); |
621 | 624 | ||
622 | return ret; | 625 | return ret; |
623 | } | 626 | } |
624 | 627 | ||
625 | static int omap3_pm_enter(suspend_state_t unused) | 628 | static int omap3_pm_enter(suspend_state_t unused) |
626 | { | 629 | { |
627 | int ret = 0; | 630 | int ret = 0; |
628 | 631 | ||
629 | switch (suspend_state) { | 632 | switch (suspend_state) { |
630 | case PM_SUSPEND_STANDBY: | 633 | case PM_SUSPEND_STANDBY: |
631 | case PM_SUSPEND_MEM: | 634 | case PM_SUSPEND_MEM: |
632 | ret = omap3_pm_suspend(); | 635 | ret = omap3_pm_suspend(); |
633 | break; | 636 | break; |
634 | default: | 637 | default: |
635 | ret = -EINVAL; | 638 | ret = -EINVAL; |
636 | } | 639 | } |
637 | 640 | ||
638 | return ret; | 641 | return ret; |
639 | } | 642 | } |
640 | 643 | ||
641 | static void omap3_pm_finish(void) | 644 | static void omap3_pm_finish(void) |
642 | { | 645 | { |
643 | enable_hlt(); | 646 | enable_hlt(); |
644 | } | 647 | } |
645 | 648 | ||
646 | /* Hooks to enable / disable UART interrupts during suspend */ | 649 | /* Hooks to enable / disable UART interrupts during suspend */ |
647 | static int omap3_pm_begin(suspend_state_t state) | 650 | static int omap3_pm_begin(suspend_state_t state) |
648 | { | 651 | { |
649 | suspend_state = state; | 652 | suspend_state = state; |
650 | omap_uart_enable_irqs(0); | 653 | omap_uart_enable_irqs(0); |
651 | return 0; | 654 | return 0; |
652 | } | 655 | } |
653 | 656 | ||
654 | static void omap3_pm_end(void) | 657 | static void omap3_pm_end(void) |
655 | { | 658 | { |
656 | suspend_state = PM_SUSPEND_ON; | 659 | suspend_state = PM_SUSPEND_ON; |
657 | omap_uart_enable_irqs(1); | 660 | omap_uart_enable_irqs(1); |
658 | return; | 661 | return; |
659 | } | 662 | } |
660 | 663 | ||
661 | static struct platform_suspend_ops omap_pm_ops = { | 664 | static struct platform_suspend_ops omap_pm_ops = { |
662 | .begin = omap3_pm_begin, | 665 | .begin = omap3_pm_begin, |
663 | .end = omap3_pm_end, | 666 | .end = omap3_pm_end, |
664 | .prepare = omap3_pm_prepare, | 667 | .prepare = omap3_pm_prepare, |
665 | .enter = omap3_pm_enter, | 668 | .enter = omap3_pm_enter, |
666 | .finish = omap3_pm_finish, | 669 | .finish = omap3_pm_finish, |
667 | .valid = suspend_valid_only_mem, | 670 | .valid = suspend_valid_only_mem, |
668 | }; | 671 | }; |
669 | #endif /* CONFIG_SUSPEND */ | 672 | #endif /* CONFIG_SUSPEND */ |
670 | 673 | ||
671 | 674 | ||
672 | /** | 675 | /** |
673 | * omap3_iva_idle(): ensure IVA is in idle so it can be put into | 676 | * omap3_iva_idle(): ensure IVA is in idle so it can be put into |
674 | * retention | 677 | * retention |
675 | * | 678 | * |
676 | * In cases where IVA2 is activated by bootcode, it may prevent | 679 | * In cases where IVA2 is activated by bootcode, it may prevent |
677 | * full-chip retention or off-mode because it is not idle. This | 680 | * full-chip retention or off-mode because it is not idle. This |
678 | * function forces the IVA2 into idle state so it can go | 681 | * function forces the IVA2 into idle state so it can go |
679 | * into retention/off and thus allow full-chip retention/off. | 682 | * into retention/off and thus allow full-chip retention/off. |
680 | * | 683 | * |
681 | **/ | 684 | **/ |
682 | static void __init omap3_iva_idle(void) | 685 | static void __init omap3_iva_idle(void) |
683 | { | 686 | { |
684 | /* ensure IVA2 clock is disabled */ | 687 | /* ensure IVA2 clock is disabled */ |
685 | cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | 688 | cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); |
686 | 689 | ||
687 | /* if no clock activity, nothing else to do */ | 690 | /* if no clock activity, nothing else to do */ |
688 | if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) & | 691 | if (!(cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKSTST) & |
689 | OMAP3430_CLKACTIVITY_IVA2_MASK)) | 692 | OMAP3430_CLKACTIVITY_IVA2_MASK)) |
690 | return; | 693 | return; |
691 | 694 | ||
692 | /* Reset IVA2 */ | 695 | /* Reset IVA2 */ |
693 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | | 696 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | |
694 | OMAP3430_RST2_IVA2 | | 697 | OMAP3430_RST2_IVA2 | |
695 | OMAP3430_RST3_IVA2, | 698 | OMAP3430_RST3_IVA2, |
696 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | 699 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); |
697 | 700 | ||
698 | /* Enable IVA2 clock */ | 701 | /* Enable IVA2 clock */ |
699 | cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK, | 702 | cm_write_mod_reg(OMAP3430_CM_FCLKEN_IVA2_EN_IVA2_MASK, |
700 | OMAP3430_IVA2_MOD, CM_FCLKEN); | 703 | OMAP3430_IVA2_MOD, CM_FCLKEN); |
701 | 704 | ||
702 | /* Set IVA2 boot mode to 'idle' */ | 705 | /* Set IVA2 boot mode to 'idle' */ |
703 | omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE, | 706 | omap_ctrl_writel(OMAP3_IVA2_BOOTMOD_IDLE, |
704 | OMAP343X_CONTROL_IVA2_BOOTMOD); | 707 | OMAP343X_CONTROL_IVA2_BOOTMOD); |
705 | 708 | ||
706 | /* Un-reset IVA2 */ | 709 | /* Un-reset IVA2 */ |
707 | prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | 710 | prm_write_mod_reg(0, OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); |
708 | 711 | ||
709 | /* Disable IVA2 clock */ | 712 | /* Disable IVA2 clock */ |
710 | cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); | 713 | cm_write_mod_reg(0, OMAP3430_IVA2_MOD, CM_FCLKEN); |
711 | 714 | ||
712 | /* Reset IVA2 */ | 715 | /* Reset IVA2 */ |
713 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | | 716 | prm_write_mod_reg(OMAP3430_RST1_IVA2 | |
714 | OMAP3430_RST2_IVA2 | | 717 | OMAP3430_RST2_IVA2 | |
715 | OMAP3430_RST3_IVA2, | 718 | OMAP3430_RST3_IVA2, |
716 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); | 719 | OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); |
717 | } | 720 | } |
718 | 721 | ||
719 | static void __init omap3_d2d_idle(void) | 722 | static void __init omap3_d2d_idle(void) |
720 | { | 723 | { |
721 | u16 mask, padconf; | 724 | u16 mask, padconf; |
722 | 725 | ||
723 | /* In a stand alone OMAP3430 where there is not a stacked | 726 | /* In a stand alone OMAP3430 where there is not a stacked |
724 | * modem for the D2D Idle Ack and D2D MStandby must be pulled | 727 | * modem for the D2D Idle Ack and D2D MStandby must be pulled |
725 | * high. S CONTROL_PADCONF_SAD2D_IDLEACK and | 728 | * high. S CONTROL_PADCONF_SAD2D_IDLEACK and |
726 | * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */ | 729 | * CONTROL_PADCONF_SAD2D_MSTDBY to have a pull up. */ |
727 | mask = (1 << 4) | (1 << 3); /* pull-up, enabled */ | 730 | mask = (1 << 4) | (1 << 3); /* pull-up, enabled */ |
728 | padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY); | 731 | padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_MSTANDBY); |
729 | padconf |= mask; | 732 | padconf |= mask; |
730 | omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY); | 733 | omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_MSTANDBY); |
731 | 734 | ||
732 | padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK); | 735 | padconf = omap_ctrl_readw(OMAP3_PADCONF_SAD2D_IDLEACK); |
733 | padconf |= mask; | 736 | padconf |= mask; |
734 | omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK); | 737 | omap_ctrl_writew(padconf, OMAP3_PADCONF_SAD2D_IDLEACK); |
735 | 738 | ||
736 | /* reset modem */ | 739 | /* reset modem */ |
737 | prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON | | 740 | prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON | |
738 | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST, | 741 | OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST, |
739 | CORE_MOD, OMAP2_RM_RSTCTRL); | 742 | CORE_MOD, OMAP2_RM_RSTCTRL); |
740 | prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL); | 743 | prm_write_mod_reg(0, CORE_MOD, OMAP2_RM_RSTCTRL); |
741 | } | 744 | } |
742 | 745 | ||
743 | static void __init prcm_setup_regs(void) | 746 | static void __init prcm_setup_regs(void) |
744 | { | 747 | { |
745 | /* XXX Reset all wkdeps. This should be done when initializing | 748 | /* XXX Reset all wkdeps. This should be done when initializing |
746 | * powerdomains */ | 749 | * powerdomains */ |
747 | prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP); | 750 | prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP); |
748 | prm_write_mod_reg(0, MPU_MOD, PM_WKDEP); | 751 | prm_write_mod_reg(0, MPU_MOD, PM_WKDEP); |
749 | prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP); | 752 | prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP); |
750 | prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP); | 753 | prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP); |
751 | prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP); | 754 | prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP); |
752 | prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP); | 755 | prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP); |
753 | if (omap_rev() > OMAP3430_REV_ES1_0) { | 756 | if (omap_rev() > OMAP3430_REV_ES1_0) { |
754 | prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP); | 757 | prm_write_mod_reg(0, OMAP3430ES2_SGX_MOD, PM_WKDEP); |
755 | prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP); | 758 | prm_write_mod_reg(0, OMAP3430ES2_USBHOST_MOD, PM_WKDEP); |
756 | } else | 759 | } else |
757 | prm_write_mod_reg(0, GFX_MOD, PM_WKDEP); | 760 | prm_write_mod_reg(0, GFX_MOD, PM_WKDEP); |
758 | 761 | ||
759 | /* | 762 | /* |
760 | * Enable interface clock autoidle for all modules. | 763 | * Enable interface clock autoidle for all modules. |
761 | * Note that in the long run this should be done by clockfw | 764 | * Note that in the long run this should be done by clockfw |
762 | */ | 765 | */ |
763 | cm_write_mod_reg( | 766 | cm_write_mod_reg( |
764 | OMAP3430_AUTO_MODEM | | 767 | OMAP3430_AUTO_MODEM | |
765 | OMAP3430ES2_AUTO_MMC3 | | 768 | OMAP3430ES2_AUTO_MMC3 | |
766 | OMAP3430ES2_AUTO_ICR | | 769 | OMAP3430ES2_AUTO_ICR | |
767 | OMAP3430_AUTO_AES2 | | 770 | OMAP3430_AUTO_AES2 | |
768 | OMAP3430_AUTO_SHA12 | | 771 | OMAP3430_AUTO_SHA12 | |
769 | OMAP3430_AUTO_DES2 | | 772 | OMAP3430_AUTO_DES2 | |
770 | OMAP3430_AUTO_MMC2 | | 773 | OMAP3430_AUTO_MMC2 | |
771 | OMAP3430_AUTO_MMC1 | | 774 | OMAP3430_AUTO_MMC1 | |
772 | OMAP3430_AUTO_MSPRO | | 775 | OMAP3430_AUTO_MSPRO | |
773 | OMAP3430_AUTO_HDQ | | 776 | OMAP3430_AUTO_HDQ | |
774 | OMAP3430_AUTO_MCSPI4 | | 777 | OMAP3430_AUTO_MCSPI4 | |
775 | OMAP3430_AUTO_MCSPI3 | | 778 | OMAP3430_AUTO_MCSPI3 | |
776 | OMAP3430_AUTO_MCSPI2 | | 779 | OMAP3430_AUTO_MCSPI2 | |
777 | OMAP3430_AUTO_MCSPI1 | | 780 | OMAP3430_AUTO_MCSPI1 | |
778 | OMAP3430_AUTO_I2C3 | | 781 | OMAP3430_AUTO_I2C3 | |
779 | OMAP3430_AUTO_I2C2 | | 782 | OMAP3430_AUTO_I2C2 | |
780 | OMAP3430_AUTO_I2C1 | | 783 | OMAP3430_AUTO_I2C1 | |
781 | OMAP3430_AUTO_UART2 | | 784 | OMAP3430_AUTO_UART2 | |
782 | OMAP3430_AUTO_UART1 | | 785 | OMAP3430_AUTO_UART1 | |
783 | OMAP3430_AUTO_GPT11 | | 786 | OMAP3430_AUTO_GPT11 | |
784 | OMAP3430_AUTO_GPT10 | | 787 | OMAP3430_AUTO_GPT10 | |
785 | OMAP3430_AUTO_MCBSP5 | | 788 | OMAP3430_AUTO_MCBSP5 | |
786 | OMAP3430_AUTO_MCBSP1 | | 789 | OMAP3430_AUTO_MCBSP1 | |
787 | OMAP3430ES1_AUTO_FAC | /* This is es1 only */ | 790 | OMAP3430ES1_AUTO_FAC | /* This is es1 only */ |
788 | OMAP3430_AUTO_MAILBOXES | | 791 | OMAP3430_AUTO_MAILBOXES | |
789 | OMAP3430_AUTO_OMAPCTRL | | 792 | OMAP3430_AUTO_OMAPCTRL | |
790 | OMAP3430ES1_AUTO_FSHOSTUSB | | 793 | OMAP3430ES1_AUTO_FSHOSTUSB | |
791 | OMAP3430_AUTO_HSOTGUSB | | 794 | OMAP3430_AUTO_HSOTGUSB | |
792 | OMAP3430_AUTO_SAD2D | | 795 | OMAP3430_AUTO_SAD2D | |
793 | OMAP3430_AUTO_SSI, | 796 | OMAP3430_AUTO_SSI, |
794 | CORE_MOD, CM_AUTOIDLE1); | 797 | CORE_MOD, CM_AUTOIDLE1); |
795 | 798 | ||
796 | cm_write_mod_reg( | 799 | cm_write_mod_reg( |
797 | OMAP3430_AUTO_PKA | | 800 | OMAP3430_AUTO_PKA | |
798 | OMAP3430_AUTO_AES1 | | 801 | OMAP3430_AUTO_AES1 | |
799 | OMAP3430_AUTO_RNG | | 802 | OMAP3430_AUTO_RNG | |
800 | OMAP3430_AUTO_SHA11 | | 803 | OMAP3430_AUTO_SHA11 | |
801 | OMAP3430_AUTO_DES1, | 804 | OMAP3430_AUTO_DES1, |
802 | CORE_MOD, CM_AUTOIDLE2); | 805 | CORE_MOD, CM_AUTOIDLE2); |
803 | 806 | ||
804 | if (omap_rev() > OMAP3430_REV_ES1_0) { | 807 | if (omap_rev() > OMAP3430_REV_ES1_0) { |
805 | cm_write_mod_reg( | 808 | cm_write_mod_reg( |
806 | OMAP3430_AUTO_MAD2D | | 809 | OMAP3430_AUTO_MAD2D | |
807 | OMAP3430ES2_AUTO_USBTLL, | 810 | OMAP3430ES2_AUTO_USBTLL, |
808 | CORE_MOD, CM_AUTOIDLE3); | 811 | CORE_MOD, CM_AUTOIDLE3); |
809 | } | 812 | } |
810 | 813 | ||
811 | cm_write_mod_reg( | 814 | cm_write_mod_reg( |
812 | OMAP3430_AUTO_WDT2 | | 815 | OMAP3430_AUTO_WDT2 | |
813 | OMAP3430_AUTO_WDT1 | | 816 | OMAP3430_AUTO_WDT1 | |
814 | OMAP3430_AUTO_GPIO1 | | 817 | OMAP3430_AUTO_GPIO1 | |
815 | OMAP3430_AUTO_32KSYNC | | 818 | OMAP3430_AUTO_32KSYNC | |
816 | OMAP3430_AUTO_GPT12 | | 819 | OMAP3430_AUTO_GPT12 | |
817 | OMAP3430_AUTO_GPT1 , | 820 | OMAP3430_AUTO_GPT1 , |
818 | WKUP_MOD, CM_AUTOIDLE); | 821 | WKUP_MOD, CM_AUTOIDLE); |
819 | 822 | ||
820 | cm_write_mod_reg( | 823 | cm_write_mod_reg( |
821 | OMAP3430_AUTO_DSS, | 824 | OMAP3430_AUTO_DSS, |
822 | OMAP3430_DSS_MOD, | 825 | OMAP3430_DSS_MOD, |
823 | CM_AUTOIDLE); | 826 | CM_AUTOIDLE); |
824 | 827 | ||
825 | cm_write_mod_reg( | 828 | cm_write_mod_reg( |
826 | OMAP3430_AUTO_CAM, | 829 | OMAP3430_AUTO_CAM, |
827 | OMAP3430_CAM_MOD, | 830 | OMAP3430_CAM_MOD, |
828 | CM_AUTOIDLE); | 831 | CM_AUTOIDLE); |
829 | 832 | ||
830 | cm_write_mod_reg( | 833 | cm_write_mod_reg( |
831 | OMAP3430_AUTO_GPIO6 | | 834 | OMAP3430_AUTO_GPIO6 | |
832 | OMAP3430_AUTO_GPIO5 | | 835 | OMAP3430_AUTO_GPIO5 | |
833 | OMAP3430_AUTO_GPIO4 | | 836 | OMAP3430_AUTO_GPIO4 | |
834 | OMAP3430_AUTO_GPIO3 | | 837 | OMAP3430_AUTO_GPIO3 | |
835 | OMAP3430_AUTO_GPIO2 | | 838 | OMAP3430_AUTO_GPIO2 | |
836 | OMAP3430_AUTO_WDT3 | | 839 | OMAP3430_AUTO_WDT3 | |
837 | OMAP3430_AUTO_UART3 | | 840 | OMAP3430_AUTO_UART3 | |
838 | OMAP3430_AUTO_GPT9 | | 841 | OMAP3430_AUTO_GPT9 | |
839 | OMAP3430_AUTO_GPT8 | | 842 | OMAP3430_AUTO_GPT8 | |
840 | OMAP3430_AUTO_GPT7 | | 843 | OMAP3430_AUTO_GPT7 | |
841 | OMAP3430_AUTO_GPT6 | | 844 | OMAP3430_AUTO_GPT6 | |
842 | OMAP3430_AUTO_GPT5 | | 845 | OMAP3430_AUTO_GPT5 | |
843 | OMAP3430_AUTO_GPT4 | | 846 | OMAP3430_AUTO_GPT4 | |
844 | OMAP3430_AUTO_GPT3 | | 847 | OMAP3430_AUTO_GPT3 | |
845 | OMAP3430_AUTO_GPT2 | | 848 | OMAP3430_AUTO_GPT2 | |
846 | OMAP3430_AUTO_MCBSP4 | | 849 | OMAP3430_AUTO_MCBSP4 | |
847 | OMAP3430_AUTO_MCBSP3 | | 850 | OMAP3430_AUTO_MCBSP3 | |
848 | OMAP3430_AUTO_MCBSP2, | 851 | OMAP3430_AUTO_MCBSP2, |
849 | OMAP3430_PER_MOD, | 852 | OMAP3430_PER_MOD, |
850 | CM_AUTOIDLE); | 853 | CM_AUTOIDLE); |
851 | 854 | ||
852 | if (omap_rev() > OMAP3430_REV_ES1_0) { | 855 | if (omap_rev() > OMAP3430_REV_ES1_0) { |
853 | cm_write_mod_reg( | 856 | cm_write_mod_reg( |
854 | OMAP3430ES2_AUTO_USBHOST, | 857 | OMAP3430ES2_AUTO_USBHOST, |
855 | OMAP3430ES2_USBHOST_MOD, | 858 | OMAP3430ES2_USBHOST_MOD, |
856 | CM_AUTOIDLE); | 859 | CM_AUTOIDLE); |
857 | } | 860 | } |
858 | 861 | ||
859 | omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG); | 862 | omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG); |
860 | 863 | ||
861 | /* | 864 | /* |
862 | * Set all plls to autoidle. This is needed until autoidle is | 865 | * Set all plls to autoidle. This is needed until autoidle is |
863 | * enabled by clockfw | 866 | * enabled by clockfw |
864 | */ | 867 | */ |
865 | cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT, | 868 | cm_write_mod_reg(1 << OMAP3430_AUTO_IVA2_DPLL_SHIFT, |
866 | OMAP3430_IVA2_MOD, CM_AUTOIDLE2); | 869 | OMAP3430_IVA2_MOD, CM_AUTOIDLE2); |
867 | cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT, | 870 | cm_write_mod_reg(1 << OMAP3430_AUTO_MPU_DPLL_SHIFT, |
868 | MPU_MOD, | 871 | MPU_MOD, |
869 | CM_AUTOIDLE2); | 872 | CM_AUTOIDLE2); |
870 | cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) | | 873 | cm_write_mod_reg((1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT) | |
871 | (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT), | 874 | (1 << OMAP3430_AUTO_CORE_DPLL_SHIFT), |
872 | PLL_MOD, | 875 | PLL_MOD, |
873 | CM_AUTOIDLE); | 876 | CM_AUTOIDLE); |
874 | cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT, | 877 | cm_write_mod_reg(1 << OMAP3430ES2_AUTO_PERIPH2_DPLL_SHIFT, |
875 | PLL_MOD, | 878 | PLL_MOD, |
876 | CM_AUTOIDLE2); | 879 | CM_AUTOIDLE2); |
877 | 880 | ||
878 | /* | 881 | /* |
879 | * Enable control of expternal oscillator through | 882 | * Enable control of expternal oscillator through |
880 | * sys_clkreq. In the long run clock framework should | 883 | * sys_clkreq. In the long run clock framework should |
881 | * take care of this. | 884 | * take care of this. |
882 | */ | 885 | */ |
883 | prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, | 886 | prm_rmw_mod_reg_bits(OMAP_AUTOEXTCLKMODE_MASK, |
884 | 1 << OMAP_AUTOEXTCLKMODE_SHIFT, | 887 | 1 << OMAP_AUTOEXTCLKMODE_SHIFT, |
885 | OMAP3430_GR_MOD, | 888 | OMAP3430_GR_MOD, |
886 | OMAP3_PRM_CLKSRC_CTRL_OFFSET); | 889 | OMAP3_PRM_CLKSRC_CTRL_OFFSET); |
887 | 890 | ||
888 | /* setup wakup source */ | 891 | /* setup wakup source */ |
889 | prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | | 892 | prm_write_mod_reg(OMAP3430_EN_IO | OMAP3430_EN_GPIO1 | |
890 | OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12, | 893 | OMAP3430_EN_GPT1 | OMAP3430_EN_GPT12, |
891 | WKUP_MOD, PM_WKEN); | 894 | WKUP_MOD, PM_WKEN); |
892 | /* No need to write EN_IO, that is always enabled */ | 895 | /* No need to write EN_IO, that is always enabled */ |
893 | prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 | | 896 | prm_write_mod_reg(OMAP3430_EN_GPIO1 | OMAP3430_EN_GPT1 | |
894 | OMAP3430_EN_GPT12, | 897 | OMAP3430_EN_GPT12, |
895 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); | 898 | WKUP_MOD, OMAP3430_PM_MPUGRPSEL); |
896 | /* For some reason IO doesn't generate wakeup event even if | 899 | /* For some reason IO doesn't generate wakeup event even if |
897 | * it is selected to mpu wakeup goup */ | 900 | * it is selected to mpu wakeup goup */ |
898 | prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN, | 901 | prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN, |
899 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); | 902 | OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET); |
900 | 903 | ||
901 | /* Enable PM_WKEN to support DSS LPR */ | 904 | /* Enable PM_WKEN to support DSS LPR */ |
902 | prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS, | 905 | prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS, |
903 | OMAP3430_DSS_MOD, PM_WKEN); | 906 | OMAP3430_DSS_MOD, PM_WKEN); |
904 | 907 | ||
905 | /* Enable wakeups in PER */ | 908 | /* Enable wakeups in PER */ |
906 | prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 | | 909 | prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 | |
907 | OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 | | 910 | OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 | |
908 | OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3 | | 911 | OMAP3430_EN_GPIO6 | OMAP3430_EN_UART3 | |
909 | OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 | | 912 | OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 | |
910 | OMAP3430_EN_MCBSP4, | 913 | OMAP3430_EN_MCBSP4, |
911 | OMAP3430_PER_MOD, PM_WKEN); | 914 | OMAP3430_PER_MOD, PM_WKEN); |
912 | /* and allow them to wake up MPU */ | 915 | /* and allow them to wake up MPU */ |
913 | prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 | | 916 | prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 | |
914 | OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 | | 917 | OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 | |
915 | OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3 | | 918 | OMAP3430_GRPSEL_GPIO6 | OMAP3430_EN_UART3 | |
916 | OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 | | 919 | OMAP3430_EN_MCBSP2 | OMAP3430_EN_MCBSP3 | |
917 | OMAP3430_EN_MCBSP4, | 920 | OMAP3430_EN_MCBSP4, |
918 | OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); | 921 | OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL); |
919 | 922 | ||
920 | /* Don't attach IVA interrupts */ | 923 | /* Don't attach IVA interrupts */ |
921 | prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); | 924 | prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL); |
922 | prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); | 925 | prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1); |
923 | prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); | 926 | prm_write_mod_reg(0, CORE_MOD, OMAP3430ES2_PM_IVAGRPSEL3); |
924 | prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); | 927 | prm_write_mod_reg(0, OMAP3430_PER_MOD, OMAP3430_PM_IVAGRPSEL); |
925 | 928 | ||
926 | /* Clear any pending 'reset' flags */ | 929 | /* Clear any pending 'reset' flags */ |
927 | prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST); | 930 | prm_write_mod_reg(0xffffffff, MPU_MOD, OMAP2_RM_RSTST); |
928 | prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST); | 931 | prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP2_RM_RSTST); |
929 | prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST); | 932 | prm_write_mod_reg(0xffffffff, OMAP3430_PER_MOD, OMAP2_RM_RSTST); |
930 | prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST); | 933 | prm_write_mod_reg(0xffffffff, OMAP3430_EMU_MOD, OMAP2_RM_RSTST); |
931 | prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST); | 934 | prm_write_mod_reg(0xffffffff, OMAP3430_NEON_MOD, OMAP2_RM_RSTST); |
932 | prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST); | 935 | prm_write_mod_reg(0xffffffff, OMAP3430_DSS_MOD, OMAP2_RM_RSTST); |
933 | prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, OMAP2_RM_RSTST); | 936 | prm_write_mod_reg(0xffffffff, OMAP3430ES2_USBHOST_MOD, OMAP2_RM_RSTST); |
934 | 937 | ||
935 | /* Clear any pending PRCM interrupts */ | 938 | /* Clear any pending PRCM interrupts */ |
936 | prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); | 939 | prm_write_mod_reg(0, OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET); |
937 | 940 | ||
938 | omap3_iva_idle(); | 941 | omap3_iva_idle(); |
939 | omap3_d2d_idle(); | 942 | omap3_d2d_idle(); |
940 | } | 943 | } |
941 | 944 | ||
942 | void omap3_pm_off_mode_enable(int enable) | 945 | void omap3_pm_off_mode_enable(int enable) |
943 | { | 946 | { |
944 | struct power_state *pwrst; | 947 | struct power_state *pwrst; |
945 | u32 state; | 948 | u32 state; |
946 | 949 | ||
947 | if (enable) | 950 | if (enable) |
948 | state = PWRDM_POWER_OFF; | 951 | state = PWRDM_POWER_OFF; |
949 | else | 952 | else |
950 | state = PWRDM_POWER_RET; | 953 | state = PWRDM_POWER_RET; |
951 | 954 | ||
952 | #ifdef CONFIG_CPU_IDLE | 955 | #ifdef CONFIG_CPU_IDLE |
953 | omap3_cpuidle_update_states(); | 956 | omap3_cpuidle_update_states(); |
954 | #endif | 957 | #endif |
955 | 958 | ||
956 | list_for_each_entry(pwrst, &pwrst_list, node) { | 959 | list_for_each_entry(pwrst, &pwrst_list, node) { |
957 | pwrst->next_state = state; | 960 | pwrst->next_state = state; |
958 | set_pwrdm_state(pwrst->pwrdm, state); | 961 | set_pwrdm_state(pwrst->pwrdm, state); |
959 | } | 962 | } |
960 | } | 963 | } |
961 | 964 | ||
962 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) | 965 | int omap3_pm_get_suspend_state(struct powerdomain *pwrdm) |
963 | { | 966 | { |
964 | struct power_state *pwrst; | 967 | struct power_state *pwrst; |
965 | 968 | ||
966 | list_for_each_entry(pwrst, &pwrst_list, node) { | 969 | list_for_each_entry(pwrst, &pwrst_list, node) { |
967 | if (pwrst->pwrdm == pwrdm) | 970 | if (pwrst->pwrdm == pwrdm) |
968 | return pwrst->next_state; | 971 | return pwrst->next_state; |
969 | } | 972 | } |
970 | return -EINVAL; | 973 | return -EINVAL; |
971 | } | 974 | } |
972 | 975 | ||
973 | int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) | 976 | int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state) |
974 | { | 977 | { |
975 | struct power_state *pwrst; | 978 | struct power_state *pwrst; |
976 | 979 | ||
977 | list_for_each_entry(pwrst, &pwrst_list, node) { | 980 | list_for_each_entry(pwrst, &pwrst_list, node) { |
978 | if (pwrst->pwrdm == pwrdm) { | 981 | if (pwrst->pwrdm == pwrdm) { |
979 | pwrst->next_state = state; | 982 | pwrst->next_state = state; |
980 | return 0; | 983 | return 0; |
981 | } | 984 | } |
982 | } | 985 | } |
983 | return -EINVAL; | 986 | return -EINVAL; |
984 | } | 987 | } |
985 | 988 | ||
986 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) | 989 | static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused) |
987 | { | 990 | { |
988 | struct power_state *pwrst; | 991 | struct power_state *pwrst; |
989 | 992 | ||
990 | if (!pwrdm->pwrsts) | 993 | if (!pwrdm->pwrsts) |
991 | return 0; | 994 | return 0; |
992 | 995 | ||
993 | pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC); | 996 | pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC); |
994 | if (!pwrst) | 997 | if (!pwrst) |
995 | return -ENOMEM; | 998 | return -ENOMEM; |
996 | pwrst->pwrdm = pwrdm; | 999 | pwrst->pwrdm = pwrdm; |
997 | pwrst->next_state = PWRDM_POWER_RET; | 1000 | pwrst->next_state = PWRDM_POWER_RET; |
998 | list_add(&pwrst->node, &pwrst_list); | 1001 | list_add(&pwrst->node, &pwrst_list); |
999 | 1002 | ||
1000 | if (pwrdm_has_hdwr_sar(pwrdm)) | 1003 | if (pwrdm_has_hdwr_sar(pwrdm)) |
1001 | pwrdm_enable_hdwr_sar(pwrdm); | 1004 | pwrdm_enable_hdwr_sar(pwrdm); |
1002 | 1005 | ||
1003 | return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); | 1006 | return set_pwrdm_state(pwrst->pwrdm, pwrst->next_state); |
1004 | } | 1007 | } |
1005 | 1008 | ||
1006 | /* | 1009 | /* |
1007 | * Enable hw supervised mode for all clockdomains if it's | 1010 | * Enable hw supervised mode for all clockdomains if it's |
1008 | * supported. Initiate sleep transition for other clockdomains, if | 1011 | * supported. Initiate sleep transition for other clockdomains, if |
1009 | * they are not used | 1012 | * they are not used |
1010 | */ | 1013 | */ |
1011 | static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) | 1014 | static int __init clkdms_setup(struct clockdomain *clkdm, void *unused) |
1012 | { | 1015 | { |
1013 | clkdm_clear_all_wkdeps(clkdm); | 1016 | clkdm_clear_all_wkdeps(clkdm); |
1014 | clkdm_clear_all_sleepdeps(clkdm); | 1017 | clkdm_clear_all_sleepdeps(clkdm); |
1015 | 1018 | ||
1016 | if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) | 1019 | if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO) |
1017 | omap2_clkdm_allow_idle(clkdm); | 1020 | omap2_clkdm_allow_idle(clkdm); |
1018 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && | 1021 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && |
1019 | atomic_read(&clkdm->usecount) == 0) | 1022 | atomic_read(&clkdm->usecount) == 0) |
1020 | omap2_clkdm_sleep(clkdm); | 1023 | omap2_clkdm_sleep(clkdm); |
1021 | return 0; | 1024 | return 0; |
1022 | } | 1025 | } |
1023 | 1026 | ||
1024 | void omap_push_sram_idle(void) | 1027 | void omap_push_sram_idle(void) |
1025 | { | 1028 | { |
1026 | _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, | 1029 | _omap_sram_idle = omap_sram_push(omap34xx_cpu_suspend, |
1027 | omap34xx_cpu_suspend_sz); | 1030 | omap34xx_cpu_suspend_sz); |
1028 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) | 1031 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) |
1029 | _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, | 1032 | _omap_save_secure_sram = omap_sram_push(save_secure_ram_context, |
1030 | save_secure_ram_context_sz); | 1033 | save_secure_ram_context_sz); |
1031 | } | 1034 | } |
1032 | 1035 | ||
1033 | static int __init omap3_pm_init(void) | 1036 | static int __init omap3_pm_init(void) |
1034 | { | 1037 | { |
1035 | struct power_state *pwrst, *tmp; | 1038 | struct power_state *pwrst, *tmp; |
1036 | struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm; | 1039 | struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm; |
1037 | int ret; | 1040 | int ret; |
1038 | 1041 | ||
1039 | if (!cpu_is_omap34xx()) | 1042 | if (!cpu_is_omap34xx()) |
1040 | return -ENODEV; | 1043 | return -ENODEV; |
1041 | 1044 | ||
1042 | printk(KERN_ERR "Power Management for TI OMAP3.\n"); | 1045 | printk(KERN_ERR "Power Management for TI OMAP3.\n"); |
1043 | 1046 | ||
1044 | /* XXX prcm_setup_regs needs to be before enabling hw | 1047 | /* XXX prcm_setup_regs needs to be before enabling hw |
1045 | * supervised mode for powerdomains */ | 1048 | * supervised mode for powerdomains */ |
1046 | prcm_setup_regs(); | 1049 | prcm_setup_regs(); |
1047 | 1050 | ||
1048 | ret = request_irq(INT_34XX_PRCM_MPU_IRQ, | 1051 | ret = request_irq(INT_34XX_PRCM_MPU_IRQ, |
1049 | (irq_handler_t)prcm_interrupt_handler, | 1052 | (irq_handler_t)prcm_interrupt_handler, |
1050 | IRQF_DISABLED, "prcm", NULL); | 1053 | IRQF_DISABLED, "prcm", NULL); |
1051 | if (ret) { | 1054 | if (ret) { |
1052 | printk(KERN_ERR "request_irq failed to register for 0x%x\n", | 1055 | printk(KERN_ERR "request_irq failed to register for 0x%x\n", |
1053 | INT_34XX_PRCM_MPU_IRQ); | 1056 | INT_34XX_PRCM_MPU_IRQ); |
1054 | goto err1; | 1057 | goto err1; |
1055 | } | 1058 | } |
1056 | 1059 | ||
1057 | ret = pwrdm_for_each(pwrdms_setup, NULL); | 1060 | ret = pwrdm_for_each(pwrdms_setup, NULL); |
1058 | if (ret) { | 1061 | if (ret) { |
1059 | printk(KERN_ERR "Failed to setup powerdomains\n"); | 1062 | printk(KERN_ERR "Failed to setup powerdomains\n"); |
1060 | goto err2; | 1063 | goto err2; |
1061 | } | 1064 | } |
1062 | 1065 | ||
1063 | (void) clkdm_for_each(clkdms_setup, NULL); | 1066 | (void) clkdm_for_each(clkdms_setup, NULL); |
1064 | 1067 | ||
1065 | mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); | 1068 | mpu_pwrdm = pwrdm_lookup("mpu_pwrdm"); |
1066 | if (mpu_pwrdm == NULL) { | 1069 | if (mpu_pwrdm == NULL) { |
1067 | printk(KERN_ERR "Failed to get mpu_pwrdm\n"); | 1070 | printk(KERN_ERR "Failed to get mpu_pwrdm\n"); |
1068 | goto err2; | 1071 | goto err2; |
1069 | } | 1072 | } |
1070 | 1073 | ||
1071 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); | 1074 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); |
1072 | per_pwrdm = pwrdm_lookup("per_pwrdm"); | 1075 | per_pwrdm = pwrdm_lookup("per_pwrdm"); |
1073 | core_pwrdm = pwrdm_lookup("core_pwrdm"); | 1076 | core_pwrdm = pwrdm_lookup("core_pwrdm"); |
1074 | cam_pwrdm = pwrdm_lookup("cam_pwrdm"); | 1077 | cam_pwrdm = pwrdm_lookup("cam_pwrdm"); |
1075 | 1078 | ||
1076 | neon_clkdm = clkdm_lookup("neon_clkdm"); | 1079 | neon_clkdm = clkdm_lookup("neon_clkdm"); |
1077 | mpu_clkdm = clkdm_lookup("mpu_clkdm"); | 1080 | mpu_clkdm = clkdm_lookup("mpu_clkdm"); |
1078 | per_clkdm = clkdm_lookup("per_clkdm"); | 1081 | per_clkdm = clkdm_lookup("per_clkdm"); |
1079 | core_clkdm = clkdm_lookup("core_clkdm"); | 1082 | core_clkdm = clkdm_lookup("core_clkdm"); |
1080 | 1083 | ||
1081 | omap_push_sram_idle(); | 1084 | omap_push_sram_idle(); |
1082 | #ifdef CONFIG_SUSPEND | 1085 | #ifdef CONFIG_SUSPEND |
1083 | suspend_set_ops(&omap_pm_ops); | 1086 | suspend_set_ops(&omap_pm_ops); |
1084 | #endif /* CONFIG_SUSPEND */ | 1087 | #endif /* CONFIG_SUSPEND */ |
1085 | 1088 | ||
1086 | pm_idle = omap3_pm_idle; | 1089 | pm_idle = omap3_pm_idle; |
1087 | omap3_idle_init(); | 1090 | omap3_idle_init(); |
1088 | 1091 | ||
1089 | clkdm_add_wkdep(neon_clkdm, mpu_clkdm); | 1092 | clkdm_add_wkdep(neon_clkdm, mpu_clkdm); |
1090 | /* | 1093 | /* |
1091 | * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for | 1094 | * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for |
1092 | * IO-pad wakeup. Otherwise it will unnecessarily waste power | 1095 | * IO-pad wakeup. Otherwise it will unnecessarily waste power |
1093 | * waking up PER with every CORE wakeup - see | 1096 | * waking up PER with every CORE wakeup - see |
1094 | * http://marc.info/?l=linux-omap&m=121852150710062&w=2 | 1097 | * http://marc.info/?l=linux-omap&m=121852150710062&w=2 |
1095 | */ | 1098 | */ |
1096 | clkdm_add_wkdep(per_clkdm, core_clkdm); | 1099 | clkdm_add_wkdep(per_clkdm, core_clkdm); |
1097 | 1100 | ||
1098 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { | 1101 | if (omap_type() != OMAP2_DEVICE_TYPE_GP) { |
1099 | omap3_secure_ram_storage = | 1102 | omap3_secure_ram_storage = |
1100 | kmalloc(0x803F, GFP_KERNEL); | 1103 | kmalloc(0x803F, GFP_KERNEL); |
1101 | if (!omap3_secure_ram_storage) | 1104 | if (!omap3_secure_ram_storage) |
1102 | printk(KERN_ERR "Memory allocation failed when" | 1105 | printk(KERN_ERR "Memory allocation failed when" |
1103 | "allocating for secure sram context\n"); | 1106 | "allocating for secure sram context\n"); |
1104 | 1107 | ||
1105 | local_irq_disable(); | 1108 | local_irq_disable(); |
1106 | local_fiq_disable(); | 1109 | local_fiq_disable(); |
1107 | 1110 | ||
1108 | omap_dma_global_context_save(); | 1111 | omap_dma_global_context_save(); |
1109 | omap3_save_secure_ram_context(PWRDM_POWER_ON); | 1112 | omap3_save_secure_ram_context(PWRDM_POWER_ON); |
1110 | omap_dma_global_context_restore(); | 1113 | omap_dma_global_context_restore(); |
1111 | 1114 | ||
1112 | local_irq_enable(); | 1115 | local_irq_enable(); |
1113 | local_fiq_enable(); | 1116 | local_fiq_enable(); |
1114 | } | 1117 | } |
1115 | 1118 | ||
1116 | omap3_save_scratchpad_contents(); | 1119 | omap3_save_scratchpad_contents(); |
1117 | err1: | 1120 | err1: |
1118 | return ret; | 1121 | return ret; |
1119 | err2: | 1122 | err2: |
1120 | free_irq(INT_34XX_PRCM_MPU_IRQ, NULL); | 1123 | free_irq(INT_34XX_PRCM_MPU_IRQ, NULL); |
1121 | list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) { | 1124 | list_for_each_entry_safe(pwrst, tmp, &pwrst_list, node) { |
1122 | list_del(&pwrst->node); | 1125 | list_del(&pwrst->node); |
1123 | kfree(pwrst); | 1126 | kfree(pwrst); |
1124 | } | 1127 | } |
1125 | return ret; | 1128 | return ret; |
1126 | } | 1129 | } |
1127 | 1130 | ||
1128 | late_initcall(omap3_pm_init); | 1131 | late_initcall(omap3_pm_init); |
1129 | 1132 |