aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/pm34xx.c64
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
50static void (*_omap_sram_idle)(u32 *addr, int save_state); 50static void (*_omap_sram_idle)(u32 *addr, int save_state);
51 51
52static struct powerdomain *mpu_pwrdm; 52static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
53static struct powerdomain *core_pwrdm, *per_pwrdm;
54
55static 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
802err1: 846err1:
803 return ret; 847 return ret;
804err2: 848err2: