diff options
author | Arnd Bergmann <arnd@arndb.de> | 2012-07-03 16:01:29 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2012-07-03 16:02:17 -0400 |
commit | 6b21a9ce0402e0c5fd2adfa3d41328fdd8f55a9a (patch) | |
tree | 05545030ed958b1568f701b0134ec54e925654b5 /arch/arm/mach-omap2 | |
parent | 0d1d76dd350a53c31e93442e573af8d14f89b2f0 (diff) | |
parent | d660e9b92b44f113c3fc345a8ce66ffa56a3506f (diff) |
Merge tag 'omap-devel-pm-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/pm
From: Tony Lindgren <tony@atomide.com>:
Here are some omap PM changes that reimplement omap PRCM I/O chain
code for wake-ups, and improve idle latencies for cpuidle.
* tag 'omap-devel-pm-for-v3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
ARM: OMAP2+: PM: fix IRQ_NOAUTOEN removal by mis-merge
ARM: OMAP3: PM: cpuidle: optimize the clkdm idle latency in C1 state
ARM: OMAP3: PM: cpuidle: optimize the PER latency in C1 state
ARM: OMAP3: PM: cpuidle: default to C1 in next_valid_state
ARM: OMAP3: PM: cleanup cam_pwrdm leftovers
ARM: OMAP3: PM: call pre/post transition per powerdomain
ARM: OMAP2+: powerdomain: allow pre/post transtion to be per pwrdm
ARM: OMAP3: PM: Remove IO Daisychain control from cpuidle
ARM: OMAP3PLUS: hwmod: reconfigure IO Daisychain during hwmod mux
ARM: OMAP3+: PRM: Enable IO wake up
ARM: OMAP4: PRM: Add IO Daisychain support
ARM: OMAP3: PM: Move IO Daisychain function to omap3 prm file
ARM: OMAP3: PM: correct enable/disable of daisy io chain
ARM: OMAP2+: PRM: fix compile for OMAP4-only build
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 71 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-mpuss-lowpower.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 38 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 63 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.c | 16 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prcm-common.h | 8 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm2xxx_3xxx.c | 48 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm2xxx_3xxx.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm44xx.c | 63 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm44xx.h | 2 |
11 files changed, 216 insertions, 107 deletions
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 207bc1c7759f..e6ae3fe5cdc6 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -77,20 +77,6 @@ static struct omap3_idle_statedata omap3_idle_data[] = { | |||
77 | 77 | ||
78 | static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; | 78 | static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; |
79 | 79 | ||
80 | static int _cpuidle_allow_idle(struct powerdomain *pwrdm, | ||
81 | struct clockdomain *clkdm) | ||
82 | { | ||
83 | clkdm_allow_idle(clkdm); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int _cpuidle_deny_idle(struct powerdomain *pwrdm, | ||
88 | struct clockdomain *clkdm) | ||
89 | { | ||
90 | clkdm_deny_idle(clkdm); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int __omap3_enter_idle(struct cpuidle_device *dev, | 80 | static int __omap3_enter_idle(struct cpuidle_device *dev, |
95 | struct cpuidle_driver *drv, | 81 | struct cpuidle_driver *drv, |
96 | int index) | 82 | int index) |
@@ -108,8 +94,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, | |||
108 | 94 | ||
109 | /* Deny idle for C1 */ | 95 | /* Deny idle for C1 */ |
110 | if (index == 0) { | 96 | if (index == 0) { |
111 | pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); | 97 | clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); |
112 | pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); | 98 | clkdm_deny_idle(core_pd->pwrdm_clkdms[0]); |
113 | } | 99 | } |
114 | 100 | ||
115 | /* | 101 | /* |
@@ -131,8 +117,8 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, | |||
131 | 117 | ||
132 | /* Re-allow idle for C1 */ | 118 | /* Re-allow idle for C1 */ |
133 | if (index == 0) { | 119 | if (index == 0) { |
134 | pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); | 120 | clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); |
135 | pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); | 121 | clkdm_allow_idle(core_pd->pwrdm_clkdms[0]); |
136 | } | 122 | } |
137 | 123 | ||
138 | return_sleep_time: | 124 | return_sleep_time: |
@@ -178,7 +164,7 @@ static int next_valid_state(struct cpuidle_device *dev, | |||
178 | u32 mpu_deepest_state = PWRDM_POWER_RET; | 164 | u32 mpu_deepest_state = PWRDM_POWER_RET; |
179 | u32 core_deepest_state = PWRDM_POWER_RET; | 165 | u32 core_deepest_state = PWRDM_POWER_RET; |
180 | int idx; | 166 | int idx; |
181 | int next_index = -1; | 167 | int next_index = 0; /* C1 is the default value */ |
182 | 168 | ||
183 | if (enable_off_mode) { | 169 | if (enable_off_mode) { |
184 | mpu_deepest_state = PWRDM_POWER_OFF; | 170 | mpu_deepest_state = PWRDM_POWER_OFF; |
@@ -209,12 +195,6 @@ static int next_valid_state(struct cpuidle_device *dev, | |||
209 | } | 195 | } |
210 | } | 196 | } |
211 | 197 | ||
212 | /* | ||
213 | * C1 is always valid. | ||
214 | * So, no need to check for 'next_index == -1' outside | ||
215 | * this loop. | ||
216 | */ | ||
217 | |||
218 | return next_index; | 198 | return next_index; |
219 | } | 199 | } |
220 | 200 | ||
@@ -228,23 +208,22 @@ static int next_valid_state(struct cpuidle_device *dev, | |||
228 | * the device to the specified or a safer state. | 208 | * the device to the specified or a safer state. |
229 | */ | 209 | */ |
230 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, | 210 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, |
231 | struct cpuidle_driver *drv, | 211 | struct cpuidle_driver *drv, |
232 | int index) | 212 | int index) |
233 | { | 213 | { |
234 | int new_state_idx; | 214 | int new_state_idx; |
235 | u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; | 215 | u32 core_next_state, per_next_state = 0, per_saved_state = 0; |
236 | struct omap3_idle_statedata *cx; | 216 | struct omap3_idle_statedata *cx; |
237 | int ret; | 217 | int ret; |
238 | 218 | ||
239 | /* | 219 | /* |
240 | * Prevent idle completely if CAM is active. | 220 | * Use only C1 if CAM is active. |
241 | * CAM does not have wakeup capability in OMAP3. | 221 | * CAM does not have wakeup capability in OMAP3. |
242 | */ | 222 | */ |
243 | cam_state = pwrdm_read_pwrst(cam_pd); | 223 | if (pwrdm_read_pwrst(cam_pd) == PWRDM_POWER_ON) |
244 | if (cam_state == PWRDM_POWER_ON) { | ||
245 | new_state_idx = drv->safe_state_index; | 224 | new_state_idx = drv->safe_state_index; |
246 | goto select_state; | 225 | else |
247 | } | 226 | new_state_idx = next_valid_state(dev, drv, index); |
248 | 227 | ||
249 | /* | 228 | /* |
250 | * FIXME: we currently manage device-specific idle states | 229 | * FIXME: we currently manage device-specific idle states |
@@ -254,24 +233,28 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
254 | * its own code. | 233 | * its own code. |
255 | */ | 234 | */ |
256 | 235 | ||
257 | /* | 236 | /* Program PER state */ |
258 | * Prevent PER off if CORE is not in retention or off as this | 237 | cx = &omap3_idle_data[new_state_idx]; |
259 | * would disable PER wakeups completely. | ||
260 | */ | ||
261 | cx = &omap3_idle_data[index]; | ||
262 | core_next_state = cx->core_state; | 238 | core_next_state = cx->core_state; |
263 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | 239 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); |
264 | if ((per_next_state == PWRDM_POWER_OFF) && | 240 | if (new_state_idx == 0) { |
265 | (core_next_state > PWRDM_POWER_RET)) | 241 | /* In C1 do not allow PER state lower than CORE state */ |
266 | per_next_state = PWRDM_POWER_RET; | 242 | if (per_next_state < core_next_state) |
243 | per_next_state = core_next_state; | ||
244 | } else { | ||
245 | /* | ||
246 | * Prevent PER OFF if CORE is not in RETention or OFF as this | ||
247 | * would disable PER wakeups completely. | ||
248 | */ | ||
249 | if ((per_next_state == PWRDM_POWER_OFF) && | ||
250 | (core_next_state > PWRDM_POWER_RET)) | ||
251 | per_next_state = PWRDM_POWER_RET; | ||
252 | } | ||
267 | 253 | ||
268 | /* Are we changing PER target state? */ | 254 | /* Are we changing PER target state? */ |
269 | if (per_next_state != per_saved_state) | 255 | if (per_next_state != per_saved_state) |
270 | pwrdm_set_next_pwrst(per_pd, per_next_state); | 256 | pwrdm_set_next_pwrst(per_pd, per_next_state); |
271 | 257 | ||
272 | new_state_idx = next_valid_state(dev, drv, index); | ||
273 | |||
274 | select_state: | ||
275 | ret = omap3_enter_idle(dev, drv, new_state_idx); | 258 | ret = omap3_enter_idle(dev, drv, new_state_idx); |
276 | 259 | ||
277 | /* Restore original PER state if it was modified */ | 260 | /* Restore original PER state if it was modified */ |
@@ -288,7 +271,7 @@ struct cpuidle_driver omap3_idle_driver = { | |||
288 | .owner = THIS_MODULE, | 271 | .owner = THIS_MODULE, |
289 | .states = { | 272 | .states = { |
290 | { | 273 | { |
291 | .enter = omap3_enter_idle, | 274 | .enter = omap3_enter_idle_bm, |
292 | .exit_latency = 2 + 2, | 275 | .exit_latency = 2 + 2, |
293 | .target_residency = 5, | 276 | .target_residency = 5, |
294 | .flags = CPUIDLE_FLAG_TIME_VALID, | 277 | .flags = CPUIDLE_FLAG_TIME_VALID, |
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index 13670aa84e58..e35a86bf4e1d 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c | |||
@@ -255,7 +255,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) | |||
255 | return -ENXIO; | 255 | return -ENXIO; |
256 | } | 256 | } |
257 | 257 | ||
258 | pwrdm_pre_transition(); | 258 | pwrdm_pre_transition(NULL); |
259 | 259 | ||
260 | /* | 260 | /* |
261 | * Check MPUSS next state and save interrupt controller if needed. | 261 | * Check MPUSS next state and save interrupt controller if needed. |
@@ -287,7 +287,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) | |||
287 | wakeup_cpu = smp_processor_id(); | 287 | wakeup_cpu = smp_processor_id(); |
288 | set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); | 288 | set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); |
289 | 289 | ||
290 | pwrdm_post_transition(); | 290 | pwrdm_post_transition(NULL); |
291 | 291 | ||
292 | return 0; | 292 | return 0; |
293 | } | 293 | } |
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 773193670ea2..09f44d56e026 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -153,6 +153,7 @@ | |||
153 | #include "prm44xx.h" | 153 | #include "prm44xx.h" |
154 | #include "prminst44xx.h" | 154 | #include "prminst44xx.h" |
155 | #include "mux.h" | 155 | #include "mux.h" |
156 | #include "pm.h" | ||
156 | 157 | ||
157 | /* Maximum microseconds to wait for OMAP module to softreset */ | 158 | /* Maximum microseconds to wait for OMAP module to softreset */ |
158 | #define MAX_MODULE_SOFTRESET_WAIT 10000 | 159 | #define MAX_MODULE_SOFTRESET_WAIT 10000 |
@@ -172,6 +173,9 @@ static LIST_HEAD(omap_hwmod_list); | |||
172 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ | 173 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ |
173 | static struct omap_hwmod *mpu_oh; | 174 | static struct omap_hwmod *mpu_oh; |
174 | 175 | ||
176 | /* io_chain_lock: used to serialize reconfigurations of the I/O chain */ | ||
177 | static DEFINE_SPINLOCK(io_chain_lock); | ||
178 | |||
175 | /* | 179 | /* |
176 | * linkspace: ptr to a buffer that struct omap_hwmod_link records are | 180 | * linkspace: ptr to a buffer that struct omap_hwmod_link records are |
177 | * allocated from - used to reduce the number of small memory | 181 | * allocated from - used to reduce the number of small memory |
@@ -1738,6 +1742,32 @@ static int _reset(struct omap_hwmod *oh) | |||
1738 | } | 1742 | } |
1739 | 1743 | ||
1740 | /** | 1744 | /** |
1745 | * _reconfigure_io_chain - clear any I/O chain wakeups and reconfigure chain | ||
1746 | * | ||
1747 | * Call the appropriate PRM function to clear any logged I/O chain | ||
1748 | * wakeups and to reconfigure the chain. This apparently needs to be | ||
1749 | * done upon every mux change. Since hwmods can be concurrently | ||
1750 | * enabled and idled, hold a spinlock around the I/O chain | ||
1751 | * reconfiguration sequence. No return value. | ||
1752 | * | ||
1753 | * XXX When the PRM code is moved to drivers, this function can be removed, | ||
1754 | * as the PRM infrastructure should abstract this. | ||
1755 | */ | ||
1756 | static void _reconfigure_io_chain(void) | ||
1757 | { | ||
1758 | unsigned long flags; | ||
1759 | |||
1760 | spin_lock_irqsave(&io_chain_lock, flags); | ||
1761 | |||
1762 | if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl()) | ||
1763 | omap3xxx_prm_reconfigure_io_chain(); | ||
1764 | else if (cpu_is_omap44xx()) | ||
1765 | omap44xx_prm_reconfigure_io_chain(); | ||
1766 | |||
1767 | spin_unlock_irqrestore(&io_chain_lock, flags); | ||
1768 | } | ||
1769 | |||
1770 | /** | ||
1741 | * _enable - enable an omap_hwmod | 1771 | * _enable - enable an omap_hwmod |
1742 | * @oh: struct omap_hwmod * | 1772 | * @oh: struct omap_hwmod * |
1743 | * | 1773 | * |
@@ -1793,8 +1823,10 @@ static int _enable(struct omap_hwmod *oh) | |||
1793 | /* Mux pins for device runtime if populated */ | 1823 | /* Mux pins for device runtime if populated */ |
1794 | if (oh->mux && (!oh->mux->enabled || | 1824 | if (oh->mux && (!oh->mux->enabled || |
1795 | ((oh->_state == _HWMOD_STATE_IDLE) && | 1825 | ((oh->_state == _HWMOD_STATE_IDLE) && |
1796 | oh->mux->pads_dynamic))) | 1826 | oh->mux->pads_dynamic))) { |
1797 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); | 1827 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED); |
1828 | _reconfigure_io_chain(); | ||
1829 | } | ||
1798 | 1830 | ||
1799 | _add_initiator_dep(oh, mpu_oh); | 1831 | _add_initiator_dep(oh, mpu_oh); |
1800 | 1832 | ||
@@ -1883,8 +1915,10 @@ static int _idle(struct omap_hwmod *oh) | |||
1883 | clkdm_hwmod_disable(oh->clkdm, oh); | 1915 | clkdm_hwmod_disable(oh->clkdm, oh); |
1884 | 1916 | ||
1885 | /* Mux pins for device idle if populated */ | 1917 | /* Mux pins for device idle if populated */ |
1886 | if (oh->mux && oh->mux->pads_dynamic) | 1918 | if (oh->mux && oh->mux->pads_dynamic) { |
1887 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); | 1919 | omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE); |
1920 | _reconfigure_io_chain(); | ||
1921 | } | ||
1888 | 1922 | ||
1889 | oh->_state = _HWMOD_STATE_IDLE; | 1923 | oh->_state = _HWMOD_STATE_IDLE; |
1890 | 1924 | ||
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 3a595e899724..e63fdd02c6f5 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -70,34 +70,6 @@ void (*omap3_do_wfi_sram)(void); | |||
70 | 70 | ||
71 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; | 71 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; |
72 | static struct powerdomain *core_pwrdm, *per_pwrdm; | 72 | static struct powerdomain *core_pwrdm, *per_pwrdm; |
73 | static struct powerdomain *cam_pwrdm; | ||
74 | |||
75 | static void omap3_enable_io_chain(void) | ||
76 | { | ||
77 | int timeout = 0; | ||
78 | |||
79 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | ||
80 | PM_WKEN); | ||
81 | /* Do a readback to assure write has been done */ | ||
82 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN); | ||
83 | |||
84 | while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) & | ||
85 | OMAP3430_ST_IO_CHAIN_MASK)) { | ||
86 | timeout++; | ||
87 | if (timeout > 1000) { | ||
88 | pr_err("Wake up daisy chain activation failed.\n"); | ||
89 | return; | ||
90 | } | ||
91 | omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, | ||
92 | WKUP_MOD, PM_WKEN); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static void omap3_disable_io_chain(void) | ||
97 | { | ||
98 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | ||
99 | PM_WKEN); | ||
100 | } | ||
101 | 73 | ||
102 | static void omap3_core_save_context(void) | 74 | static void omap3_core_save_context(void) |
103 | { | 75 | { |
@@ -299,24 +271,22 @@ void omap_sram_idle(void) | |||
299 | /* Enable IO-PAD and IO-CHAIN wakeups */ | 271 | /* Enable IO-PAD and IO-CHAIN wakeups */ |
300 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); | 272 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); |
301 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); | 273 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); |
302 | if (omap3_has_io_wakeup() && | ||
303 | (per_next_state < PWRDM_POWER_ON || | ||
304 | core_next_state < PWRDM_POWER_ON)) { | ||
305 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN); | ||
306 | if (omap3_has_io_chain_ctrl()) | ||
307 | omap3_enable_io_chain(); | ||
308 | } | ||
309 | 274 | ||
310 | pwrdm_pre_transition(); | 275 | if (mpu_next_state < PWRDM_POWER_ON) { |
276 | pwrdm_pre_transition(mpu_pwrdm); | ||
277 | pwrdm_pre_transition(neon_pwrdm); | ||
278 | } | ||
311 | 279 | ||
312 | /* PER */ | 280 | /* PER */ |
313 | if (per_next_state < PWRDM_POWER_ON) { | 281 | if (per_next_state < PWRDM_POWER_ON) { |
282 | pwrdm_pre_transition(per_pwrdm); | ||
314 | per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; | 283 | per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0; |
315 | omap2_gpio_prepare_for_idle(per_going_off); | 284 | omap2_gpio_prepare_for_idle(per_going_off); |
316 | } | 285 | } |
317 | 286 | ||
318 | /* CORE */ | 287 | /* CORE */ |
319 | if (core_next_state < PWRDM_POWER_ON) { | 288 | if (core_next_state < PWRDM_POWER_ON) { |
289 | pwrdm_pre_transition(core_pwrdm); | ||
320 | if (core_next_state == PWRDM_POWER_OFF) { | 290 | if (core_next_state == PWRDM_POWER_OFF) { |
321 | omap3_core_save_context(); | 291 | omap3_core_save_context(); |
322 | omap3_cm_save_context(); | 292 | omap3_cm_save_context(); |
@@ -369,26 +339,20 @@ void omap_sram_idle(void) | |||
369 | omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, | 339 | omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK, |
370 | OMAP3430_GR_MOD, | 340 | OMAP3430_GR_MOD, |
371 | OMAP3_PRM_VOLTCTRL_OFFSET); | 341 | OMAP3_PRM_VOLTCTRL_OFFSET); |
342 | pwrdm_post_transition(core_pwrdm); | ||
372 | } | 343 | } |
373 | omap3_intc_resume_idle(); | 344 | omap3_intc_resume_idle(); |
374 | 345 | ||
375 | pwrdm_post_transition(); | ||
376 | |||
377 | /* PER */ | 346 | /* PER */ |
378 | if (per_next_state < PWRDM_POWER_ON) | 347 | if (per_next_state < PWRDM_POWER_ON) { |
379 | omap2_gpio_resume_after_idle(); | 348 | omap2_gpio_resume_after_idle(); |
380 | 349 | pwrdm_post_transition(per_pwrdm); | |
381 | /* Disable IO-PAD and IO-CHAIN wakeup */ | ||
382 | if (omap3_has_io_wakeup() && | ||
383 | (per_next_state < PWRDM_POWER_ON || | ||
384 | core_next_state < PWRDM_POWER_ON)) { | ||
385 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | ||
386 | PM_WKEN); | ||
387 | if (omap3_has_io_chain_ctrl()) | ||
388 | omap3_disable_io_chain(); | ||
389 | } | 350 | } |
390 | 351 | ||
391 | clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); | 352 | if (mpu_next_state < PWRDM_POWER_ON) { |
353 | pwrdm_post_transition(mpu_pwrdm); | ||
354 | pwrdm_post_transition(neon_pwrdm); | ||
355 | } | ||
392 | } | 356 | } |
393 | 357 | ||
394 | static void omap3_pm_idle(void) | 358 | static void omap3_pm_idle(void) |
@@ -749,7 +713,6 @@ int __init omap3_pm_init(void) | |||
749 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); | 713 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); |
750 | per_pwrdm = pwrdm_lookup("per_pwrdm"); | 714 | per_pwrdm = pwrdm_lookup("per_pwrdm"); |
751 | core_pwrdm = pwrdm_lookup("core_pwrdm"); | 715 | core_pwrdm = pwrdm_lookup("core_pwrdm"); |
752 | cam_pwrdm = pwrdm_lookup("cam_pwrdm"); | ||
753 | 716 | ||
754 | neon_clkdm = clkdm_lookup("neon_clkdm"); | 717 | neon_clkdm = clkdm_lookup("neon_clkdm"); |
755 | mpu_clkdm = clkdm_lookup("mpu_clkdm"); | 718 | mpu_clkdm = clkdm_lookup("mpu_clkdm"); |
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 96114901b932..eefe179045e6 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c | |||
@@ -981,15 +981,23 @@ int pwrdm_state_switch(struct powerdomain *pwrdm) | |||
981 | return ret; | 981 | return ret; |
982 | } | 982 | } |
983 | 983 | ||
984 | int pwrdm_pre_transition(void) | 984 | int pwrdm_pre_transition(struct powerdomain *pwrdm) |
985 | { | 985 | { |
986 | pwrdm_for_each(_pwrdm_pre_transition_cb, NULL); | 986 | if (pwrdm) |
987 | _pwrdm_pre_transition_cb(pwrdm, NULL); | ||
988 | else | ||
989 | pwrdm_for_each(_pwrdm_pre_transition_cb, NULL); | ||
990 | |||
987 | return 0; | 991 | return 0; |
988 | } | 992 | } |
989 | 993 | ||
990 | int pwrdm_post_transition(void) | 994 | int pwrdm_post_transition(struct powerdomain *pwrdm) |
991 | { | 995 | { |
992 | pwrdm_for_each(_pwrdm_post_transition_cb, NULL); | 996 | if (pwrdm) |
997 | _pwrdm_post_transition_cb(pwrdm, NULL); | ||
998 | else | ||
999 | pwrdm_for_each(_pwrdm_post_transition_cb, NULL); | ||
1000 | |||
993 | return 0; | 1001 | return 0; |
994 | } | 1002 | } |
995 | 1003 | ||
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 8f88d65c46ea..a6a4604801ad 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h | |||
@@ -213,8 +213,8 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); | |||
213 | int pwrdm_wait_transition(struct powerdomain *pwrdm); | 213 | int pwrdm_wait_transition(struct powerdomain *pwrdm); |
214 | 214 | ||
215 | int pwrdm_state_switch(struct powerdomain *pwrdm); | 215 | int pwrdm_state_switch(struct powerdomain *pwrdm); |
216 | int pwrdm_pre_transition(void); | 216 | int pwrdm_pre_transition(struct powerdomain *pwrdm); |
217 | int pwrdm_post_transition(void); | 217 | int pwrdm_post_transition(struct powerdomain *pwrdm); |
218 | int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); | 218 | int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); |
219 | int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); | 219 | int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); |
220 | bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); | 220 | bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); |
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h index 6da3ba483ad1..fca23cbea708 100644 --- a/arch/arm/mach-omap2/prcm-common.h +++ b/arch/arm/mach-omap2/prcm-common.h | |||
@@ -410,6 +410,14 @@ | |||
410 | */ | 410 | */ |
411 | #define MAX_MODULE_HARDRESET_WAIT 10000 | 411 | #define MAX_MODULE_HARDRESET_WAIT 10000 |
412 | 412 | ||
413 | /* | ||
414 | * Maximum time(us) it takes to output the signal WUCLKOUT of the last | ||
415 | * pad of the I/O ring after asserting WUCLKIN high. Tero measured | ||
416 | * the actual time at 7 to 8 microseconds on OMAP3 and 2 to 4 | ||
417 | * microseconds on OMAP4, so this timeout may be too high. | ||
418 | */ | ||
419 | #define MAX_IOPAD_LATCH_TIME 100 | ||
420 | |||
413 | # ifndef __ASSEMBLER__ | 421 | # ifndef __ASSEMBLER__ |
414 | extern void __iomem *prm_base; | 422 | extern void __iomem *prm_base; |
415 | extern void __iomem *cm_base; | 423 | extern void __iomem *cm_base; |
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index 21cb74003a56..a0309dea6794 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c | |||
@@ -302,11 +302,59 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask) | |||
302 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); | 302 | OMAP3_PRM_IRQENABLE_MPU_OFFSET); |
303 | } | 303 | } |
304 | 304 | ||
305 | /** | ||
306 | * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain | ||
307 | * | ||
308 | * Clear any previously-latched I/O wakeup events and ensure that the | ||
309 | * I/O wakeup gates are aligned with the current mux settings. Works | ||
310 | * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then | ||
311 | * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No | ||
312 | * return value. | ||
313 | */ | ||
314 | void omap3xxx_prm_reconfigure_io_chain(void) | ||
315 | { | ||
316 | int i = 0; | ||
317 | |||
318 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | ||
319 | PM_WKEN); | ||
320 | |||
321 | omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) & | ||
322 | OMAP3430_ST_IO_CHAIN_MASK, | ||
323 | MAX_IOPAD_LATCH_TIME, i); | ||
324 | if (i == MAX_IOPAD_LATCH_TIME) | ||
325 | pr_warn("PRM: I/O chain clock line assertion timed out\n"); | ||
326 | |||
327 | omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, | ||
328 | PM_WKEN); | ||
329 | |||
330 | omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD, | ||
331 | PM_WKST); | ||
332 | |||
333 | omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST); | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches | ||
338 | * | ||
339 | * Activates the I/O wakeup event latches and allows events logged by | ||
340 | * those latches to signal a wakeup event to the PRCM. For I/O | ||
341 | * wakeups to occur, WAKEUPENABLE bits must be set in the pad mux | ||
342 | * registers, and omap3xxx_prm_reconfigure_io_chain() must be called. | ||
343 | * No return value. | ||
344 | */ | ||
345 | static void __init omap3xxx_prm_enable_io_wakeup(void) | ||
346 | { | ||
347 | if (omap3_has_io_wakeup()) | ||
348 | omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, | ||
349 | PM_WKEN); | ||
350 | } | ||
351 | |||
305 | static int __init omap3xxx_prcm_init(void) | 352 | static int __init omap3xxx_prcm_init(void) |
306 | { | 353 | { |
307 | int ret = 0; | 354 | int ret = 0; |
308 | 355 | ||
309 | if (cpu_is_omap34xx()) { | 356 | if (cpu_is_omap34xx()) { |
357 | omap3xxx_prm_enable_io_wakeup(); | ||
310 | ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); | 358 | ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup); |
311 | if (!ret) | 359 | if (!ret) |
312 | irq_set_status_flags(omap_prcm_event_to_irq("io"), | 360 | irq_set_status_flags(omap_prcm_event_to_irq("io"), |
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h index 70ac2a19dc5f..a8c946f318ab 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.h +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h | |||
@@ -303,6 +303,8 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift); | |||
303 | extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); | 303 | extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); |
304 | extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); | 304 | extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); |
305 | 305 | ||
306 | #endif /* CONFIG_ARCH_OMAP4 */ | ||
307 | |||
306 | /* OMAP3-specific VP functions */ | 308 | /* OMAP3-specific VP functions */ |
307 | u32 omap3_prm_vp_check_txdone(u8 vp_id); | 309 | u32 omap3_prm_vp_check_txdone(u8 vp_id); |
308 | void omap3_prm_vp_clear_txdone(u8 vp_id); | 310 | void omap3_prm_vp_clear_txdone(u8 vp_id); |
@@ -315,14 +317,14 @@ extern u32 omap3_prm_vcvp_read(u8 offset); | |||
315 | extern void omap3_prm_vcvp_write(u32 val, u8 offset); | 317 | extern void omap3_prm_vcvp_write(u32 val, u8 offset); |
316 | extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); | 318 | extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); |
317 | 319 | ||
320 | extern void omap3xxx_prm_reconfigure_io_chain(void); | ||
321 | |||
318 | /* PRM interrupt-related functions */ | 322 | /* PRM interrupt-related functions */ |
319 | extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); | 323 | extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); |
320 | extern void omap3xxx_prm_ocp_barrier(void); | 324 | extern void omap3xxx_prm_ocp_barrier(void); |
321 | extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); | 325 | extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); |
322 | extern void omap3xxx_prm_restore_irqen(u32 *saved_mask); | 326 | extern void omap3xxx_prm_restore_irqen(u32 *saved_mask); |
323 | 327 | ||
324 | #endif /* CONFIG_ARCH_OMAP4 */ | ||
325 | |||
326 | #endif | 328 | #endif |
327 | 329 | ||
328 | /* | 330 | /* |
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c index f106d21ff581..bb727c2d9337 100644 --- a/arch/arm/mach-omap2/prm44xx.c +++ b/arch/arm/mach-omap2/prm44xx.c | |||
@@ -233,10 +233,71 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask) | |||
233 | OMAP4_PRM_IRQENABLE_MPU_2_OFFSET); | 233 | OMAP4_PRM_IRQENABLE_MPU_2_OFFSET); |
234 | } | 234 | } |
235 | 235 | ||
236 | /** | ||
237 | * omap44xx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain | ||
238 | * | ||
239 | * Clear any previously-latched I/O wakeup events and ensure that the | ||
240 | * I/O wakeup gates are aligned with the current mux settings. Works | ||
241 | * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then | ||
242 | * deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted. | ||
243 | * No return value. XXX Are the final two steps necessary? | ||
244 | */ | ||
245 | void omap44xx_prm_reconfigure_io_chain(void) | ||
246 | { | ||
247 | int i = 0; | ||
248 | |||
249 | /* Trigger WUCLKIN enable */ | ||
250 | omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, | ||
251 | OMAP4430_WUCLK_CTRL_MASK, | ||
252 | OMAP4430_PRM_DEVICE_INST, | ||
253 | OMAP4_PRM_IO_PMCTRL_OFFSET); | ||
254 | omap_test_timeout( | ||
255 | (((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, | ||
256 | OMAP4_PRM_IO_PMCTRL_OFFSET) & | ||
257 | OMAP4430_WUCLK_STATUS_MASK) >> | ||
258 | OMAP4430_WUCLK_STATUS_SHIFT) == 1), | ||
259 | MAX_IOPAD_LATCH_TIME, i); | ||
260 | if (i == MAX_IOPAD_LATCH_TIME) | ||
261 | pr_warn("PRM: I/O chain clock line assertion timed out\n"); | ||
262 | |||
263 | /* Trigger WUCLKIN disable */ | ||
264 | omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, 0x0, | ||
265 | OMAP4430_PRM_DEVICE_INST, | ||
266 | OMAP4_PRM_IO_PMCTRL_OFFSET); | ||
267 | omap_test_timeout( | ||
268 | (((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST, | ||
269 | OMAP4_PRM_IO_PMCTRL_OFFSET) & | ||
270 | OMAP4430_WUCLK_STATUS_MASK) >> | ||
271 | OMAP4430_WUCLK_STATUS_SHIFT) == 0), | ||
272 | MAX_IOPAD_LATCH_TIME, i); | ||
273 | if (i == MAX_IOPAD_LATCH_TIME) | ||
274 | pr_warn("PRM: I/O chain clock line deassertion timed out\n"); | ||
275 | |||
276 | return; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * omap44xx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches | ||
281 | * | ||
282 | * Activates the I/O wakeup event latches and allows events logged by | ||
283 | * those latches to signal a wakeup event to the PRCM. For I/O wakeups | ||
284 | * to occur, WAKEUPENABLE bits must be set in the pad mux registers, and | ||
285 | * omap44xx_prm_reconfigure_io_chain() must be called. No return value. | ||
286 | */ | ||
287 | static void __init omap44xx_prm_enable_io_wakeup(void) | ||
288 | { | ||
289 | omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK, | ||
290 | OMAP4430_GLOBAL_WUEN_MASK, | ||
291 | OMAP4430_PRM_DEVICE_INST, | ||
292 | OMAP4_PRM_IO_PMCTRL_OFFSET); | ||
293 | } | ||
294 | |||
236 | static int __init omap4xxx_prcm_init(void) | 295 | static int __init omap4xxx_prcm_init(void) |
237 | { | 296 | { |
238 | if (cpu_is_omap44xx()) | 297 | if (cpu_is_omap44xx()) { |
298 | omap44xx_prm_enable_io_wakeup(); | ||
239 | return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup); | 299 | return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup); |
300 | } | ||
240 | return 0; | 301 | return 0; |
241 | } | 302 | } |
242 | subsys_initcall(omap4xxx_prcm_init); | 303 | subsys_initcall(omap4xxx_prcm_init); |
diff --git a/arch/arm/mach-omap2/prm44xx.h b/arch/arm/mach-omap2/prm44xx.h index 7978092946db..ee72ae6bd8c9 100644 --- a/arch/arm/mach-omap2/prm44xx.h +++ b/arch/arm/mach-omap2/prm44xx.h | |||
@@ -763,6 +763,8 @@ extern u32 omap4_prm_vcvp_read(u8 offset); | |||
763 | extern void omap4_prm_vcvp_write(u32 val, u8 offset); | 763 | extern void omap4_prm_vcvp_write(u32 val, u8 offset); |
764 | extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); | 764 | extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); |
765 | 765 | ||
766 | extern void omap44xx_prm_reconfigure_io_chain(void); | ||
767 | |||
766 | /* PRM interrupt-related functions */ | 768 | /* PRM interrupt-related functions */ |
767 | extern void omap44xx_prm_read_pending_irqs(unsigned long *events); | 769 | extern void omap44xx_prm_read_pending_irqs(unsigned long *events); |
768 | extern void omap44xx_prm_ocp_barrier(void); | 770 | extern void omap44xx_prm_ocp_barrier(void); |