diff options
| -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); |
