OMAP3: allow to disable UART4
[pandora-kernel.git] / arch / arm / mach-omap2 / pm34xx.c
index efa6649..abea9e9 100644 (file)
@@ -83,7 +83,6 @@ void (*omap3_do_wfi_sram)(void);
 
 static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
-static struct powerdomain *cam_pwrdm;
 
 static inline void omap3_per_save_context(void)
 {
@@ -101,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)
@@ -336,14 +335,9 @@ 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;
 
-       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:
@@ -382,10 +376,12 @@ void omap_sram_idle(void)
                        if (!console_trylock())
                                goto console_still_active;
 
-       pwrdm_pre_transition();
+       if (mpu_next_state < PWRDM_POWER_ON)
+               pwrdm_pre_transition(mpu_pwrdm);
 
        /* PER */
        if (per_next_state < PWRDM_POWER_ON) {
+               pwrdm_pre_transition(per_pwrdm);
                per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
                omap_uart_prepare_idle(2);
                omap_uart_prepare_idle(3);
@@ -398,6 +394,7 @@ void omap_sram_idle(void)
        if (core_next_state < PWRDM_POWER_ON) {
                omap_uart_prepare_idle(0);
                omap_uart_prepare_idle(1);
+               pwrdm_pre_transition(core_pwrdm);
                if (core_next_state == PWRDM_POWER_OFF) {
                        omap3_core_save_context();
                        omap3_cm_save_context();
@@ -438,24 +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);
-               if (core_next_state == PWRDM_POWER_OFF)
-                       omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
-                                              OMAP3430_GR_MOD,
-                                              OMAP3_PRM_VOLTCTRL_OFFSET);
+               pwrdm_post_transition(core_pwrdm);
        }
-       omap3_intc_resume_idle();
-
-       pwrdm_post_transition();
 
        /* PER */
        if (per_next_state < PWRDM_POWER_ON) {
@@ -465,6 +463,7 @@ void omap_sram_idle(void)
                        omap3_per_restore_context();
                omap_uart_resume_idle(2);
                omap_uart_resume_idle(3);
+               pwrdm_post_transition(per_pwrdm);
        }
 
        if (!is_suspending())
@@ -481,23 +480,13 @@ console_still_active:
                        omap3_disable_io_chain();
        }
 
-       clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
-}
-
-int omap3_can_sleep(void)
-{
-       if (!omap_uart_can_sleep())
-               return 0;
-       return 1;
+       if (mpu_next_state < PWRDM_POWER_ON)
+               pwrdm_post_transition(mpu_pwrdm);
 }
 
 static void omap3_pm_idle(void)
 {
        local_irq_disable();
-       local_fiq_disable();
-
-       if (!omap3_can_sleep())
-               goto out;
 
        if (omap_irq_pending() || need_resched())
                goto out;
@@ -511,10 +500,18 @@ static void omap3_pm_idle(void)
        trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
 
 out:
-       local_fiq_enable();
        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)
 {
@@ -677,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);
@@ -750,6 +750,8 @@ static void __init prcm_setup_regs(void)
 
        omap3_iva_idle();
        omap3_d2d_idle();
+
+       omap3_pm_alow_pmic_idle(1);
 }
 
 void omap3_pm_off_mode_enable(int enable)
@@ -769,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;
                }
@@ -817,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);
 }
 
@@ -906,7 +934,6 @@ static int __init omap3_pm_init(void)
        neon_pwrdm = pwrdm_lookup("neon_pwrdm");
        per_pwrdm = pwrdm_lookup("per_pwrdm");
        core_pwrdm = pwrdm_lookup("core_pwrdm");
-       cam_pwrdm = pwrdm_lookup("cam_pwrdm");
 
        neon_clkdm = clkdm_lookup("neon_clkdm");
        mpu_clkdm = clkdm_lookup("mpu_clkdm");
@@ -937,14 +964,12 @@ static int __init omap3_pm_init(void)
                                        "allocating for secure sram context\n");
 
                local_irq_disable();
-               local_fiq_disable();
 
                omap_dma_global_context_save();
                omap3_save_secure_ram_context();
                omap_dma_global_context_restore();
 
                local_irq_enable();
-               local_fiq_enable();
        }
 
        omap3_save_scratchpad_contents();