aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2012-07-03 16:01:29 -0400
committerArnd Bergmann <arnd@arndb.de>2012-07-03 16:02:17 -0400
commit6b21a9ce0402e0c5fd2adfa3d41328fdd8f55a9a (patch)
tree05545030ed958b1568f701b0134ec54e925654b5 /arch/arm/mach-omap2
parent0d1d76dd350a53c31e93442e573af8d14f89b2f0 (diff)
parentd660e9b92b44f113c3fc345a8ce66ffa56a3506f (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.c71
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c4
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c38
-rw-r--r--arch/arm/mach-omap2/pm34xx.c63
-rw-r--r--arch/arm/mach-omap2/powerdomain.c16
-rw-r--r--arch/arm/mach-omap2/powerdomain.h4
-rw-r--r--arch/arm/mach-omap2/prcm-common.h8
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c48
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.h6
-rw-r--r--arch/arm/mach-omap2/prm44xx.c63
-rw-r--r--arch/arm/mach-omap2/prm44xx.h2
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
78static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; 78static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
79 79
80static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
81 struct clockdomain *clkdm)
82{
83 clkdm_allow_idle(clkdm);
84 return 0;
85}
86
87static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
88 struct clockdomain *clkdm)
89{
90 clkdm_deny_idle(clkdm);
91 return 0;
92}
93
94static int __omap3_enter_idle(struct cpuidle_device *dev, 80static 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
138return_sleep_time: 124return_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 */
230static int omap3_enter_idle_bm(struct cpuidle_device *dev, 210static 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
274select_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 */
173static struct omap_hwmod *mpu_oh; 174static struct omap_hwmod *mpu_oh;
174 175
176/* io_chain_lock: used to serialize reconfigurations of the I/O chain */
177static 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 */
1756static 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
71static struct powerdomain *mpu_pwrdm, *neon_pwrdm; 71static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
72static struct powerdomain *core_pwrdm, *per_pwrdm; 72static struct powerdomain *core_pwrdm, *per_pwrdm;
73static struct powerdomain *cam_pwrdm;
74
75static 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
96static 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
102static void omap3_core_save_context(void) 74static 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
394static void omap3_pm_idle(void) 358static 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
984int pwrdm_pre_transition(void) 984int 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
990int pwrdm_post_transition(void) 994int 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);
213int pwrdm_wait_transition(struct powerdomain *pwrdm); 213int pwrdm_wait_transition(struct powerdomain *pwrdm);
214 214
215int pwrdm_state_switch(struct powerdomain *pwrdm); 215int pwrdm_state_switch(struct powerdomain *pwrdm);
216int pwrdm_pre_transition(void); 216int pwrdm_pre_transition(struct powerdomain *pwrdm);
217int pwrdm_post_transition(void); 217int pwrdm_post_transition(struct powerdomain *pwrdm);
218int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); 218int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
219int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); 219int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
220bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); 220bool 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__
414extern void __iomem *prm_base; 422extern void __iomem *prm_base;
415extern void __iomem *cm_base; 423extern 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 */
314void 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 */
345static 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
305static int __init omap3xxx_prcm_init(void) 352static 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);
303extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift); 303extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
304extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift); 304extern 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 */
307u32 omap3_prm_vp_check_txdone(u8 vp_id); 309u32 omap3_prm_vp_check_txdone(u8 vp_id);
308void omap3_prm_vp_clear_txdone(u8 vp_id); 310void omap3_prm_vp_clear_txdone(u8 vp_id);
@@ -315,14 +317,14 @@ extern u32 omap3_prm_vcvp_read(u8 offset);
315extern void omap3_prm_vcvp_write(u32 val, u8 offset); 317extern void omap3_prm_vcvp_write(u32 val, u8 offset);
316extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); 318extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
317 319
320extern void omap3xxx_prm_reconfigure_io_chain(void);
321
318/* PRM interrupt-related functions */ 322/* PRM interrupt-related functions */
319extern void omap3xxx_prm_read_pending_irqs(unsigned long *events); 323extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
320extern void omap3xxx_prm_ocp_barrier(void); 324extern void omap3xxx_prm_ocp_barrier(void);
321extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask); 325extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
322extern void omap3xxx_prm_restore_irqen(u32 *saved_mask); 326extern 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 */
245void 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 */
287static 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
236static int __init omap4xxx_prcm_init(void) 295static 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}
242subsys_initcall(omap4xxx_prcm_init); 303subsys_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);
763extern void omap4_prm_vcvp_write(u32 val, u8 offset); 763extern void omap4_prm_vcvp_write(u32 val, u8 offset);
764extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset); 764extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
765 765
766extern void omap44xx_prm_reconfigure_io_chain(void);
767
766/* PRM interrupt-related functions */ 768/* PRM interrupt-related functions */
767extern void omap44xx_prm_read_pending_irqs(unsigned long *events); 769extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
768extern void omap44xx_prm_ocp_barrier(void); 770extern void omap44xx_prm_ocp_barrier(void);