This patch adds handling of PER/NEON and CORE domain in idle.
Enables state C4(MPU RET + CORE RET).

Signed-off-by: Rajendra Nayak <[EMAIL PROTECTED]>

---
 arch/arm/mach-omap2/cpuidle34xx.c        |   68 +++++++++++++++--------
 arch/arm/mach-omap2/cpuidle34xx.h        |    2
 arch/arm/mach-omap2/pm34xx.c             |   90 ++++++++++++++++++++++++-------
 arch/arm/mach-omap2/serial.c             |   19 ++----
 arch/arm/plat-omap/include/mach/common.h |    2
 5 files changed, 129 insertions(+), 52 deletions(-)

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/cpuidle34xx.c       2008-08-26
17:22:27.000000000 +0530
+++ linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c    2008-08-26
17:22:52.000000000 +0530
@@ -26,6 +26,8 @@
 #include <mach/pm.h>
 #include <mach/prcm.h>
 #include <mach/powerdomain.h>
+#include <linux/sched.h>
+
 #include "cpuidle34xx.h"

 #ifdef CONFIG_CPU_IDLE
@@ -35,9 +37,12 @@ struct omap3_processor_cx current_cx_sta

 static int omap3_idle_bm_check(void)
 {
+       if (!omap3_can_sleep())
+               return 1;
        return 0;
 }

+int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
 /* omap3_enter_idle - Programs OMAP3 to enter the specified state.
  * returns the total time during which the system was idle.
  */
@@ -46,34 +51,47 @@ static int omap3_enter_idle(struct cpuid
 {
        struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
        struct timespec ts_preidle, ts_postidle, ts_idle;
-       struct powerdomain *mpu_pd;
+       struct powerdomain *mpu_pd, *core_pd;;

        current_cx_state = *cx;

-       /* Used to keep track of the total time in idle */
-       getnstimeofday(&ts_preidle);
-
-
        if (cx->type == OMAP3_STATE_C0) {
                /* Do nothing for C0, not even a wfi */
                return 0;
        }

+       local_irq_disable();
+       local_fiq_disable();
+
+       /* Used to keep track of the total time in idle */
+       getnstimeofday(&ts_preidle);
+
+       if (cx->type > OMAP3_STATE_C1)
+               sched_clock_idle_sleep_event(); /* about to enter deep idle */
+
        mpu_pd = pwrdm_lookup("mpu_pwrdm");
-       /* Program MPU to target state */
-       if (cx->mpu_state < PWRDM_POWER_ON)
-               pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
+       core_pd = pwrdm_lookup("core_pwrdm");
+
+       set_pwrdm_state(mpu_pd, cx->mpu_state);
+       set_pwrdm_state(core_pd, cx->core_state);
+
+       if (omap_irq_pending())
+               goto return_sleep_time;

        /* Execute ARM wfi */
        omap_sram_idle();

-       /* Program MPU to ON */
-       if (cx->mpu_state < PWRDM_POWER_ON)
-               pwrdm_set_next_pwrst(mpu_pd, PWRDM_POWER_ON);
-
+return_sleep_time:
        getnstimeofday(&ts_postidle);
        ts_idle = timespec_sub(ts_postidle, ts_preidle);
-       return timespec_to_ns(&ts_idle);
+
+       if (cx->type > OMAP3_STATE_C1)
+               sched_clock_idle_wakeup_event(timespec_to_ns(&ts_idle));
+
+       local_irq_enable();
+       local_fiq_enable();
+
+       return (u32)timespec_to_ns(&ts_idle)/1000;
 }

 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
@@ -130,7 +148,7 @@ void omap_init_power_states(void)
        omap3_power_states[0].threshold = 0;
        omap3_power_states[0].mpu_state = PWRDM_POWER_ON;
        omap3_power_states[0].core_state = PWRDM_POWER_ON;
-       omap3_power_states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[0].flags = CPUIDLE_FLAG_SHALLOW;

        /* C1 . MPU WFI + Core active */
        omap3_power_states[1].valid = 1;
@@ -140,7 +158,8 @@ void omap_init_power_states(void)
        omap3_power_states[1].threshold = 30;
        omap3_power_states[1].mpu_state = PWRDM_POWER_ON;
        omap3_power_states[1].core_state = PWRDM_POWER_ON;
-       omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID |
+                                               CPUIDLE_FLAG_SHALLOW;

        /* C2 . MPU CSWR + Core active */
        omap3_power_states[2].valid = 1;
@@ -150,7 +169,8 @@ void omap_init_power_states(void)
        omap3_power_states[2].threshold = 300;
        omap3_power_states[2].mpu_state = PWRDM_POWER_RET;
        omap3_power_states[2].core_state = PWRDM_POWER_ON;
-       omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID |
+                                               CPUIDLE_FLAG_BALANCED;

        /* C3 . MPU OFF + Core active */
        omap3_power_states[3].valid = 0;
@@ -159,18 +179,20 @@ void omap_init_power_states(void)
        omap3_power_states[3].wakeup_latency = 1800;
        omap3_power_states[3].threshold = 4000;
        omap3_power_states[3].mpu_state = PWRDM_POWER_OFF;
-       omap3_power_states[3].core_state = PWRDM_POWER_RET;
-       omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[3].core_state = PWRDM_POWER_ON;
+       omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID |
+                       CPUIDLE_FLAG_BALANCED;

        /* C4 . MPU CSWR + Core CSWR*/
-       omap3_power_states[4].valid = 0;
+       omap3_power_states[4].valid = 1;
        omap3_power_states[4].type = OMAP3_STATE_C4;
        omap3_power_states[4].sleep_latency = 2500;
        omap3_power_states[4].wakeup_latency = 7500;
        omap3_power_states[4].threshold = 12000;
        omap3_power_states[4].mpu_state = PWRDM_POWER_RET;
        omap3_power_states[4].core_state = PWRDM_POWER_RET;
-       omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID |
+                       CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;

        /* C5 . MPU OFF + Core CSWR */
        omap3_power_states[5].valid = 0;
@@ -180,7 +202,8 @@ void omap_init_power_states(void)
        omap3_power_states[5].threshold = 15000;
        omap3_power_states[5].mpu_state = PWRDM_POWER_OFF;
        omap3_power_states[5].core_state = PWRDM_POWER_RET;
-       omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID |
+                       CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;

        /* C6 . MPU OFF + Core OFF */
        omap3_power_states[6].valid = 0;
@@ -190,7 +213,8 @@ void omap_init_power_states(void)
        omap3_power_states[6].threshold = 300000;
        omap3_power_states[6].mpu_state = PWRDM_POWER_OFF;
        omap3_power_states[6].core_state = PWRDM_POWER_OFF;
-       omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID;
+       omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID |
+                       CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_CHECK_BM;
 }

 struct cpuidle_driver omap3_idle_driver = {
Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/cpuidle34xx.h       2008-08-26
17:22:27.000000000 +0530
+++ linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h    2008-08-26
17:22:52.000000000 +0530
@@ -34,6 +34,8 @@
 #define MAX_SUPPORTED_STATES 3

 extern void omap_sram_idle(void);
+extern int omap_irq_pending(void);
+extern int omap3_can_sleep();

 struct omap3_processor_cx {
        u8 valid;
Index: linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/pm34xx.c    2008-08-26
17:22:27.000000000 +0530
+++ linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c 2008-08-26 17:23:13.000000000
+0530
@@ -52,7 +52,10 @@ static void (*_omap_sram_idle)(u32 *addr

 static void (*saved_idle)(void);

-static struct powerdomain *mpu_pwrdm;
+static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
+static struct powerdomain *core_pwrdm, *per_pwrdm;
+
+int set_pwrdm_state(struct powerdomain *pwrdm, u32 state);

 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
@@ -184,11 +187,20 @@ 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;
+       int mpu_prev_state, core_prev_state, per_prev_state;

        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:
@@ -202,24 +214,50 @@ void omap_sram_idle(void)
                return;
        }

-       omap2_gpio_prepare_for_retention();
-       if (clocks_off_while_idle) {
-               omap_serial_enable_clocks(0);
-               /* XXX This is for gpio fclk hack. Will be removed as
-                * gpio driver * handles fcks correctly */
-               per_gpio_clk_disable();
+       /* 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();
+               /* PER changes only with core */
+               per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
+               if (per_next_state < PWRDM_POWER_ON) {
+                       if (clocks_off_while_idle) {
+                               per_gpio_clk_disable();
+                               omap_serial_enable_clocks(0, 2);
+                       }
+               }
+               if (clocks_off_while_idle) {
+                       omap_serial_enable_clocks(0, 0);
+                       omap_serial_enable_clocks(0, 1);
+               }
+               /* Enable IO-PAD wakeup */
+               prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
        }

        _omap_sram_idle(NULL, save_state);

-       if (clocks_off_while_idle) {
-               omap_serial_enable_clocks(1);
-               /* XXX This is for gpio fclk hack. Will be removed as
-                * gpio driver * handles fcks correctly */
-               per_gpio_clk_enable();
+       if (core_next_state < PWRDM_POWER_ON) {
+               /* Disable IO-PAD wakeup */
+               prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
+               core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
+               if (clocks_off_while_idle) {
+                       omap_serial_enable_clocks(1, 0);
+                       omap_serial_enable_clocks(1, 1);
+               }
+               if (per_next_state < PWRDM_POWER_ON) {
+                       if (clocks_off_while_idle) {
+                               per_gpio_clk_enable();
+                               /* This would be actually more effective */
+                               omap_serial_enable_clocks(1, 2);
+                       }
+                       per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+               }
+               omap2_gpio_resume_after_retention();
        }
-
-       omap2_gpio_resume_after_retention();
 }

 /*
@@ -263,7 +301,7 @@ static int omap3_fclks_active(void)
        return 0;
 }

-static int omap3_can_sleep(void)
+int omap3_can_sleep(void)
 {
        if (!enable_dyn_sleep)
                return 0;
@@ -295,7 +333,7 @@ static int _clkdm_allow_idle(struct powe
 /* This sets pwrdm state (other than mpu & core. Currently only ON &
  * RET are supported. Function is assuming that clkdm doesn't have
  * hw_sup mode enabled. */
-static int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
+int set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
 {
        u32 cur_state;
        int ret = 0;
@@ -708,7 +746,11 @@ static int __init pwrdms_setup(struct po
        if (!pwrst)
                return -ENOMEM;
        pwrst->pwrdm = pwrdm;
-       pwrst->next_state = PWRDM_POWER_RET;
+       if (!strcmp(pwrst->pwrdm->name, "core_pwrdm") ||
+                       !strcmp(pwrst->pwrdm->name, "mpu_pwrdm"))
+               pwrst->next_state = PWRDM_POWER_ON;
+       else
+               pwrst->next_state = PWRDM_POWER_OFF;
        list_add(&pwrst->node, &pwrst_list);

        if (pwrdm_has_hdwr_sar(pwrdm))
@@ -750,6 +792,10 @@ 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_sram_idle = omap_sram_push(omap34xx_cpu_suspend,
                                        omap34xx_cpu_suspend_sz);

@@ -765,6 +811,14 @@ int __init omap3_pm_init(void)
                sprintf(clk_name, "gpio%d_fck", i + 1);
                gpio_fcks[i-1] = clk_get(NULL, clk_name);
        }
+       /*
+        * 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(neon_pwrdm, mpu_pwrdm);
+       pwrdm_add_wkdep(per_pwrdm, core_pwrdm);

 err1:
        return ret;
Index: linux-omap-2.6/arch/arm/mach-omap2/serial.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/serial.c    2008-08-26
17:22:24.000000000 +0530
+++ linux-omap-2.6/arch/arm/mach-omap2/serial.c 2008-08-26 17:22:52.000000000
+0530
@@ -147,18 +147,15 @@ static void omap_serial_kick(void)
                NSEC_PER_SEC);
 }

-void omap_serial_enable_clocks(int enable)
+void omap_serial_enable_clocks(int enable, int unum)
 {
-       int i;
-       for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
-               if (uart_ick[i] && uart_fck[i]) {
-                       if (enable) {
-                               clk_enable(uart_ick[i]);
-                               clk_enable(uart_fck[i]);
-                       } else {
-                               clk_disable(uart_ick[i]);
-                               clk_disable(uart_fck[i]);
-                       }
+       if (uart_ick[unum] && uart_fck[unum]) {
+               if (enable) {
+                       clk_enable(uart_ick[unum]);
+                       clk_enable(uart_fck[unum]);
+               } else {
+                       clk_disable(uart_ick[unum]);
+                       clk_disable(uart_fck[unum]);
                }
        }
 }
Index: linux-omap-2.6/arch/arm/plat-omap/include/mach/common.h
===================================================================
--- linux-omap-2.6.orig/arch/arm/plat-omap/include/mach/common.h        
2008-08-26
17:22:24.000000000 +0530
+++ linux-omap-2.6/arch/arm/plat-omap/include/mach/common.h     2008-08-26
17:22:52.000000000 +0530
@@ -34,7 +34,7 @@ struct sys_timer;
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 extern void omap_serial_init(void);
-extern void omap_serial_enable_clocks(int enable);
+extern void omap_serial_enable_clocks(int enable, int unum);
 extern int omap_serial_can_sleep(void);
 extern void omap_serial_fclk_mask(u32 *f1, u32 *f2);
 void omap_serial_check_wakeup(void);


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to