OMAP3: allow to disable UART4
[pandora-kernel.git] / arch / arm / mach-omap2 / pm34xx.c
index 4889a08..abea9e9 100644 (file)
@@ -100,19 +100,19 @@ static void omap3_enable_io_chain(void)
 
        omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
                                   PM_WKEN);
-       /* Do a readback to assure write has been done */
-       omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
 
-       while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
+       while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
                 OMAP3430_ST_IO_CHAIN_MASK)) {
                timeout++;
-               if (timeout > 1000) {
+               if (timeout > 100) {
                        pr_err("Wake up daisy chain activation failed.\n");
                        return;
                }
-               omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
-                                          WKUP_MOD, PM_WKEN);
+               udelay(1);
        }
+
+       omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD,
+                                  PM_WKST);
 }
 
 static void omap3_disable_io_chain(void)
@@ -335,7 +335,7 @@ void omap_sram_idle(void)
        int per_next_state = PWRDM_POWER_ON;
        int core_next_state = PWRDM_POWER_ON;
        int per_going_off;
-       int core_prev_state, per_prev_state;
+       int per_prev_state;
        u32 sdrc_pwr = 0;
 
        mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
@@ -435,19 +435,25 @@ void omap_sram_idle(void)
                sdrc_write_reg(sdrc_pwr, SDRC_POWER);
 
        /* CORE */
+       if (core_next_state < PWRDM_POWER_ON &&
+           pwrdm_read_prev_pwrst(core_pwrdm) == PWRDM_POWER_OFF) {
+               omap3_core_restore_context();
+               omap3_cm_restore_context();
+               omap3_sram_restore_context();
+               omap2_sms_restore_context();
+       } else {
+               /*
+                * In off-mode resume path above, omap3_core_restore_context
+                * also handles the INTC autoidle restore done here so limit
+                * this to non-off mode resume paths so we don't do it twice.
+                */
+               omap3_intc_resume_idle();
+       }
        if (core_next_state < PWRDM_POWER_ON) {
-               core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
-               if (core_prev_state == PWRDM_POWER_OFF) {
-                       omap3_core_restore_context();
-                       omap3_cm_restore_context();
-                       omap3_sram_restore_context();
-                       omap2_sms_restore_context();
-               }
                omap_uart_resume_idle(0);
                omap_uart_resume_idle(1);
                pwrdm_post_transition(core_pwrdm);
        }
-       omap3_intc_resume_idle();
 
        /* PER */
        if (per_next_state < PWRDM_POWER_ON) {
@@ -497,6 +503,15 @@ out:
        local_irq_enable();
 }
 
+void omap3_pm_alow_pmic_idle(int allow)
+{
+       /* enable sys_clkreq signalling on RET */
+       omap2_prm_rmw_mod_reg_bits((OMAP3430_AUTO_OFF_MASK | OMAP3430_AUTO_RET_MASK
+               | OMAP3430_AUTO_SLEEP_MASK), allow ? OMAP3430_AUTO_RET_MASK : 0,
+               OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET);
+}
+EXPORT_SYMBOL(omap3_pm_alow_pmic_idle);
+
 #ifdef CONFIG_SUSPEND
 static int omap3_pm_suspend(void)
 {
@@ -659,6 +674,9 @@ static void __init prcm_setup_regs(void)
                                        OMAP3630_EN_UART4_MASK : 0;
        u32 omap3630_grpsel_uart4_mask = cpu_is_omap3630() ?
                                        OMAP3630_GRPSEL_UART4_MASK : 0;
+#ifdef CONFIG_OMAP3_DISABLE_UART4
+       omap3630_en_uart4_mask = omap3630_grpsel_uart4_mask = 0;
+#endif
 
        /* XXX This should be handled by hwmod code or SCM init code */
        omap_ctrl_writel(OMAP3430_AUTOIDLE_MASK, OMAP2_CONTROL_SYSCONFIG);
@@ -733,10 +751,7 @@ static void __init prcm_setup_regs(void)
        omap3_iva_idle();
        omap3_d2d_idle();
 
-       /* enable sys_clkreq signalling */
-       omap2_prm_rmw_mod_reg_bits((OMAP3430_AUTO_OFF_MASK | OMAP3430_AUTO_RET_MASK
-               | OMAP3430_AUTO_SLEEP_MASK), OMAP3430_AUTO_RET_MASK,
-               OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET);
+       omap3_pm_alow_pmic_idle(1);
 }
 
 void omap3_pm_off_mode_enable(int enable)
@@ -756,6 +771,9 @@ void omap3_pm_off_mode_enable(int enable)
                        pwrst->next_state = PWRDM_POWER_RET;
                        pr_warn("%s: Core OFF disabled due to errata i583\n",
                                __func__);
+               } else if (enable < 3 && pwrst->pwrdm == per_pwrdm) {
+                       /* pandora hack */
+                       pwrst->next_state = PWRDM_POWER_RET;
                } else {
                        pwrst->next_state = state;
                }
@@ -804,6 +822,29 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
        if (pwrdm_has_hdwr_sar(pwrdm))
                pwrdm_enable_hdwr_sar(pwrdm);
 
+       /* pandora OFF hacks, notes for missing:
+        * - core_pwrdm - loses GPIO state?!
+        * - per_pwrdm  - must keep RET because of GPIOs
+        * - neon_pwrdm - depends on mpu_pwrdm
+        * - mpu_pwrdm  - sometimes hangs?
+        * notes for enabled:
+        * - usbhost_pwrdm - does driver reload + reinit anyway, no runtime PM
+        * - sgx_pwrdm  - only OFF is supported
+        * - dss_pwrdm  - works, needs working context_loss counter
+        * - cam_pwrdm  - not used
+        * - iva2_pwrdm - c64_tools reprograms with direct reg hits anyway
+        */
+       if (   pwrdm == pwrdm_lookup("usbhost_pwrdm")
+           || pwrdm == pwrdm_lookup("sgx_pwrdm")
+           || pwrdm == pwrdm_lookup("cam_pwrdm")
+           || pwrdm == pwrdm_lookup("iva2_pwrdm")
+           )
+               pwrst->next_state = PWRDM_POWER_OFF;
+
+       /* on OMAP3, at least on ES2.1, DSS drains more in OFF than in RET?? */
+       else if (cpu_is_omap3630() && pwrdm == pwrdm_lookup("dss_pwrdm"))
+               pwrst->next_state = PWRDM_POWER_OFF;
+
        return omap_set_pwrdm_state(pwrst->pwrdm, pwrst->next_state);
 }