diff options
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index b88da1bcb66c..05ee05f012ad 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -49,7 +49,10 @@ static LIST_HEAD(pwrst_list); | |||
49 | 49 | ||
50 | static void (*_omap_sram_idle)(u32 *addr, int save_state); | 50 | static void (*_omap_sram_idle)(u32 *addr, int save_state); |
51 | 51 | ||
52 | static struct powerdomain *mpu_pwrdm; | 52 | static struct powerdomain *mpu_pwrdm, *neon_pwrdm; |
53 | static struct powerdomain *core_pwrdm, *per_pwrdm; | ||
54 | |||
55 | static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state); | ||
53 | 56 | ||
54 | /* | 57 | /* |
55 | * PRCM Interrupt Handler Helper Function | 58 | * PRCM Interrupt Handler Helper Function |
@@ -169,13 +172,22 @@ static void omap_sram_idle(void) | |||
169 | /* save_state = 1 => Only L1 and logic lost */ | 172 | /* save_state = 1 => Only L1 and logic lost */ |
170 | /* save_state = 2 => Only L2 lost */ | 173 | /* save_state = 2 => Only L2 lost */ |
171 | /* save_state = 3 => L1, L2 and logic lost */ | 174 | /* save_state = 3 => L1, L2 and logic lost */ |
172 | int save_state = 0, mpu_next_state; | 175 | int save_state = 0; |
176 | int mpu_next_state = PWRDM_POWER_ON; | ||
177 | int per_next_state = PWRDM_POWER_ON; | ||
178 | int core_next_state = PWRDM_POWER_ON; | ||
173 | 179 | ||
174 | if (!_omap_sram_idle) | 180 | if (!_omap_sram_idle) |
175 | return; | 181 | return; |
176 | 182 | ||
183 | pwrdm_clear_all_prev_pwrst(mpu_pwrdm); | ||
184 | pwrdm_clear_all_prev_pwrst(neon_pwrdm); | ||
185 | pwrdm_clear_all_prev_pwrst(core_pwrdm); | ||
186 | pwrdm_clear_all_prev_pwrst(per_pwrdm); | ||
187 | |||
177 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); | 188 | mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm); |
178 | switch (mpu_next_state) { | 189 | switch (mpu_next_state) { |
190 | case PWRDM_POWER_ON: | ||
179 | case PWRDM_POWER_RET: | 191 | case PWRDM_POWER_RET: |
180 | /* No need to save context */ | 192 | /* No need to save context */ |
181 | save_state = 0; | 193 | save_state = 0; |
@@ -187,18 +199,37 @@ static void omap_sram_idle(void) | |||
187 | } | 199 | } |
188 | pwrdm_pre_transition(); | 200 | pwrdm_pre_transition(); |
189 | 201 | ||
190 | omap2_gpio_prepare_for_retention(); | 202 | /* NEON control */ |
191 | omap_uart_prepare_idle(0); | 203 | if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) |
192 | omap_uart_prepare_idle(1); | 204 | set_pwrdm_state(neon_pwrdm, mpu_next_state); |
193 | omap_uart_prepare_idle(2); | 205 | |
206 | /* CORE & PER */ | ||
207 | core_next_state = pwrdm_read_next_pwrst(core_pwrdm); | ||
208 | if (core_next_state < PWRDM_POWER_ON) { | ||
209 | omap2_gpio_prepare_for_retention(); | ||
210 | omap_uart_prepare_idle(0); | ||
211 | omap_uart_prepare_idle(1); | ||
212 | /* PER changes only with core */ | ||
213 | per_next_state = pwrdm_read_next_pwrst(per_pwrdm); | ||
214 | if (per_next_state < PWRDM_POWER_ON) | ||
215 | omap_uart_prepare_idle(2); | ||
216 | /* Enable IO-PAD wakeup */ | ||
217 | prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | ||
218 | } | ||
194 | 219 | ||
195 | _omap_sram_idle(NULL, save_state); | 220 | _omap_sram_idle(NULL, save_state); |
196 | cpu_init(); | 221 | cpu_init(); |
197 | 222 | ||
198 | omap_uart_resume_idle(2); | 223 | if (core_next_state < PWRDM_POWER_ON) { |
199 | omap_uart_resume_idle(1); | 224 | if (per_next_state < PWRDM_POWER_ON) |
200 | omap_uart_resume_idle(0); | 225 | omap_uart_resume_idle(2); |
201 | omap2_gpio_resume_after_retention(); | 226 | omap_uart_resume_idle(1); |
227 | omap_uart_resume_idle(0); | ||
228 | |||
229 | /* Disable IO-PAD wakeup */ | ||
230 | prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN); | ||
231 | omap2_gpio_resume_after_retention(); | ||
232 | } | ||
202 | 233 | ||
203 | pwrdm_post_transition(); | 234 | pwrdm_post_transition(); |
204 | 235 | ||
@@ -792,6 +823,10 @@ static int __init omap3_pm_init(void) | |||
792 | goto err2; | 823 | goto err2; |
793 | } | 824 | } |
794 | 825 | ||
826 | neon_pwrdm = pwrdm_lookup("neon_pwrdm"); | ||
827 | per_pwrdm = pwrdm_lookup("per_pwrdm"); | ||
828 | core_pwrdm = pwrdm_lookup("core_pwrdm"); | ||
829 | |||
795 | omap_push_sram_idle(); | 830 | omap_push_sram_idle(); |
796 | #ifdef CONFIG_SUSPEND | 831 | #ifdef CONFIG_SUSPEND |
797 | suspend_set_ops(&omap_pm_ops); | 832 | suspend_set_ops(&omap_pm_ops); |
@@ -799,6 +834,15 @@ static int __init omap3_pm_init(void) | |||
799 | 834 | ||
800 | pm_idle = omap3_pm_idle; | 835 | pm_idle = omap3_pm_idle; |
801 | 836 | ||
837 | pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm); | ||
838 | /* | ||
839 | * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for | ||
840 | * IO-pad wakeup. Otherwise it will unnecessarily waste power | ||
841 | * waking up PER with every CORE wakeup - see | ||
842 | * http://marc.info/?l=linux-omap&m=121852150710062&w=2 | ||
843 | */ | ||
844 | pwrdm_add_wkdep(per_pwrdm, core_pwrdm); | ||
845 | |||
802 | err1: | 846 | err1: |
803 | return ret; | 847 | return ret; |
804 | err2: | 848 | err2: |