|
@@ -49,7 +49,10 @@ static LIST_HEAD(pwrst_list);
|
|
|
|
|
|
static void (*_omap_sram_idle)(u32 *addr, int save_state);
|
|
|
|
|
|
-static struct powerdomain *mpu_pwrdm;
|
|
|
+static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
|
|
|
+static struct powerdomain *core_pwrdm, *per_pwrdm;
|
|
|
+
|
|
|
+static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
|
|
|
|
|
|
/*
|
|
|
* PRCM Interrupt Handler Helper Function
|
|
@@ -169,13 +172,22 @@ static void omap_sram_idle(void)
|
|
|
/* save_state = 1 => Only L1 and logic lost */
|
|
|
/* save_state = 2 => Only L2 lost */
|
|
|
/* save_state = 3 => L1, L2 and logic lost */
|
|
|
- int save_state = 0, mpu_next_state;
|
|
|
+ int save_state = 0;
|
|
|
+ int mpu_next_state = PWRDM_POWER_ON;
|
|
|
+ int per_next_state = PWRDM_POWER_ON;
|
|
|
+ int core_next_state = PWRDM_POWER_ON;
|
|
|
|
|
|
if (!_omap_sram_idle)
|
|
|
return;
|
|
|
|
|
|
+ pwrdm_clear_all_prev_pwrst(mpu_pwrdm);
|
|
|
+ pwrdm_clear_all_prev_pwrst(neon_pwrdm);
|
|
|
+ pwrdm_clear_all_prev_pwrst(core_pwrdm);
|
|
|
+ pwrdm_clear_all_prev_pwrst(per_pwrdm);
|
|
|
+
|
|
|
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
|
|
|
switch (mpu_next_state) {
|
|
|
+ case PWRDM_POWER_ON:
|
|
|
case PWRDM_POWER_RET:
|
|
|
/* No need to save context */
|
|
|
save_state = 0;
|
|
@@ -187,18 +199,37 @@ static void omap_sram_idle(void)
|
|
|
}
|
|
|
pwrdm_pre_transition();
|
|
|
|
|
|
- omap2_gpio_prepare_for_retention();
|
|
|
- omap_uart_prepare_idle(0);
|
|
|
- omap_uart_prepare_idle(1);
|
|
|
- omap_uart_prepare_idle(2);
|
|
|
+ /* NEON control */
|
|
|
+ if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
|
|
|
+ set_pwrdm_state(neon_pwrdm, mpu_next_state);
|
|
|
+
|
|
|
+ /* CORE & PER */
|
|
|
+ core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
|
|
|
+ if (core_next_state < PWRDM_POWER_ON) {
|
|
|
+ omap2_gpio_prepare_for_retention();
|
|
|
+ omap_uart_prepare_idle(0);
|
|
|
+ omap_uart_prepare_idle(1);
|
|
|
+ /* PER changes only with core */
|
|
|
+ per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
|
|
|
+ if (per_next_state < PWRDM_POWER_ON)
|
|
|
+ omap_uart_prepare_idle(2);
|
|
|
+ /* Enable IO-PAD wakeup */
|
|
|
+ prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
|
|
|
+ }
|
|
|
|
|
|
_omap_sram_idle(NULL, save_state);
|
|
|
cpu_init();
|
|
|
|
|
|
- omap_uart_resume_idle(2);
|
|
|
- omap_uart_resume_idle(1);
|
|
|
- omap_uart_resume_idle(0);
|
|
|
- omap2_gpio_resume_after_retention();
|
|
|
+ if (core_next_state < PWRDM_POWER_ON) {
|
|
|
+ if (per_next_state < PWRDM_POWER_ON)
|
|
|
+ omap_uart_resume_idle(2);
|
|
|
+ omap_uart_resume_idle(1);
|
|
|
+ omap_uart_resume_idle(0);
|
|
|
+
|
|
|
+ /* Disable IO-PAD wakeup */
|
|
|
+ prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
|
|
|
+ omap2_gpio_resume_after_retention();
|
|
|
+ }
|
|
|
|
|
|
pwrdm_post_transition();
|
|
|
|
|
@@ -792,6 +823,10 @@ static int __init omap3_pm_init(void)
|
|
|
goto err2;
|
|
|
}
|
|
|
|
|
|
+ neon_pwrdm = pwrdm_lookup("neon_pwrdm");
|
|
|
+ per_pwrdm = pwrdm_lookup("per_pwrdm");
|
|
|
+ core_pwrdm = pwrdm_lookup("core_pwrdm");
|
|
|
+
|
|
|
omap_push_sram_idle();
|
|
|
#ifdef CONFIG_SUSPEND
|
|
|
suspend_set_ops(&omap_pm_ops);
|
|
@@ -799,6 +834,15 @@ static int __init omap3_pm_init(void)
|
|
|
|
|
|
pm_idle = omap3_pm_idle;
|
|
|
|
|
|
+ pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm);
|
|
|
+ /*
|
|
|
+ * REVISIT: This wkdep is only necessary when GPIO2-6 are enabled for
|
|
|
+ * IO-pad wakeup. Otherwise it will unnecessarily waste power
|
|
|
+ * waking up PER with every CORE wakeup - see
|
|
|
+ * http://marc.info/?l=linux-omap&m=121852150710062&w=2
|
|
|
+ */
|
|
|
+ pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
|
|
|
+
|
|
|
err1:
|
|
|
return ret;
|
|
|
err2:
|