]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
ARM: OMAP: Merge in Nokia 770 PM code for 16xx
authorTony Lindgren <tony@atomide.com>
Thu, 1 Dec 2005 01:08:21 +0000 (17:08 -0800)
committerTony Lindgren <tony@atomide.com>
Thu, 1 Dec 2005 01:08:21 +0000 (17:08 -0800)
This patch is based on the Nokia 770 PM code available at:

http://repository.maemo.org/pool/maemo1.1rc7/free/source/k/kernel-source-2.6.12.3/

arch/arm/plat-omap/dma.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/pm.c
arch/arm/plat-omap/sleep.S
include/asm-arm/arch-omap/dma.h
include/asm-arm/arch-omap/dmtimer.h
include/asm-arm/arch-omap/pm.h

index f5cc21ad09565cba72c2e1c46fd921919b8e1612..96d06e579bfba77f415b5e2e878e98cf2d0b9125 100644 (file)
@@ -1258,6 +1258,11 @@ void omap_stop_lcd_dma(void)
        omap_writew(w, OMAP1610_DMA_LCD_CTRL);
 }
 
+int omap_lcd_dma_ext_running(void)
+{
+       return lcd_dma.ext_ctrl && lcd_dma.active;
+}
+
 /*----------------------------------------------------------------------------*/
 
 static int __init omap_init_dma(void)
@@ -1389,6 +1394,7 @@ EXPORT_SYMBOL(omap_free_lcd_dma);
 EXPORT_SYMBOL(omap_enable_lcd_dma);
 EXPORT_SYMBOL(omap_setup_lcd_dma);
 EXPORT_SYMBOL(omap_stop_lcd_dma);
+EXPORT_SYMBOL(omap_lcd_dma_ext_running);
 EXPORT_SYMBOL(omap_set_lcd_dma_b1);
 EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer);
 EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller);
index 38d7ebf879207cb116ed17fc1c81e2b1ab7ec946..eba3cb52ad878567b39c0d87750e84d2a5e44180 100644 (file)
@@ -97,6 +97,32 @@ int omap_dm_timers_active(void)
 }
 
 
+/**
+ * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
+ * @inputmask: current value of idlect mask
+ */
+__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
+{
+       int n;
+
+       /* If ARMXOR cannot be idled this function call is unnecessary */
+       if (!(inputmask & (1 << 1)))
+               return inputmask;
+
+       /* If any active timer is using ARMXOR return modified mask */
+       for (n = 0; dm_timers[n].base; ++n)
+               if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)&
+                   OMAP_TIMER_CTRL_ST) {
+                       if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0)
+                               inputmask &= ~(1 << 1);
+                       else
+                               inputmask &= ~(1 << 2);
+               }
+
+       return inputmask;
+}
+
+
 void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
        int n = (timer - dm_timers) << 1;
index ccacbcf5033f5b44f00f783e1af2034629e1388a..b275af5c03fdfdd5fd312bb51671ff1d72f15fad 100644 (file)
 #include <linux/proc_fs.h>
 #include <linux/pm.h>
 #include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/atomic.h>
 #include <asm/mach/time.h>
 #include <asm/mach/irq.h>
-
 #include <asm/mach-types.h>
+
 #include <asm/arch/irqs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sram.h>
 #include <asm/arch/tc.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/mux.h>
 #include <asm/arch/tps65010.h>
+#include <asm/arch/dma.h>
 #include <asm/arch/dsp_common.h>
-
-#include <asm/arch/clock.h>
-#include <asm/arch/sram.h>
+#include <asm/arch/dmtimer.h>
 
 static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
 static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
@@ -63,6 +67,37 @@ static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
 static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
 static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
 
+static unsigned short enable_dyn_sleep = 1;
+
+static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
+{
+       return sprintf(buf, "%hu\n", enable_dyn_sleep);
+}
+
+static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+                                             const char * buf,
+                                             size_t n)
+{
+       unsigned short value;
+       if (sscanf(buf, "%hu", &value) != 1 ||
+           (value != 0 && value != 1)) {
+               printk(KERN_ERR "idle_sleep_store: Invalid value\n");
+               return -EINVAL;
+       }
+       enable_dyn_sleep = value;
+       return n;
+}
+
+static struct subsys_attribute sleep_while_idle_attr = {
+       .attr   = {
+               .name = __stringify(sleep_while_idle),
+               .mode = 0644,
+       },
+       .show   = omap_pm_sleep_while_idle_show,
+       .store  = omap_pm_sleep_while_idle_store,
+};
+
+extern struct subsystem power_subsys;
 static void (*omap_sram_idle)(void) = NULL;
 static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
 
@@ -74,13 +109,9 @@ static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
  */
 void omap_pm_idle(void)
 {
-       unsigned int mask32 = 0;
-
-       /*
-        * If the DSP is being used let's just idle the CPU, the overhead
-        * to wake up from Big Sleep is big, milliseconds versus micro
-        * seconds for wait for interrupt.
-        */
+       extern __u32 arm_idlect1_mask;
+       __u32 use_idlect1 = arm_idlect1_mask;
+       int do_sleep;
 
        local_irq_disable();
        local_fiq_disable();
@@ -89,14 +120,6 @@ void omap_pm_idle(void)
                local_irq_enable();
                return;
        }
-       mask32 = omap_readl(ARM_SYSST);
-
-       /*
-        * Prevent the ULPD from entering low power state by setting
-        * POWER_CTRL_REG:4 = 0
-        */
-       omap_writew(omap_readw(ULPD_POWER_CTRL) &
-                   ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL);
 
        /*
         * Since an interrupt may set up a timer, we don't want to
@@ -105,10 +128,55 @@ void omap_pm_idle(void)
         */
        timer_dyn_reprogram();
 
-       if ((mask32 & DSP_IDLE) == 0) {
+#ifdef CONFIG_OMAP_MPU_TIMER
+#warning Enable 32kHz OS timer in order to allow sleep states in idle
+       use_idlect1 = use_idlect1 & ~(1 << 9);
+#else
+
+       do_sleep = 0;
+       while (enable_dyn_sleep) {
+               extern int vbus_active;
+
+#ifdef CONFIG_CBUS_TAHVO_USB
+               /* Clock requirements? */
+               if (vbus_active)
+                       break;
+#endif
+               do_sleep = 1;
+               break;
+       }
+
+#ifdef CONFIG_OMAP_DM_TIMER
+       use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
+#endif
+
+       if (omap_dma_running()) {
+               use_idlect1 &= ~(1 << 6);
+               if (omap_lcd_dma_ext_running())
+                       use_idlect1 &= ~(1 << 12);
+       }
+
+       /* We should be able to remove the do_sleep variable and multiple
+        * tests above as soon as drivers, timer and DMA code have been fixed.
+        * Even the sleep block count should become obsolete. */
+       if ((use_idlect1 != ~0) || !do_sleep) {
+
+               __u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
+               if (cpu_is_omap1510())
+                       use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
+               else
+                       use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
+               omap_writel(use_idlect1, ARM_IDLECT1);
                __asm__ volatile ("mcr  p15, 0, r0, c7, c0, 4");
-       } else
-               omap_sram_idle();
+               omap_writel(saved_idlect1, ARM_IDLECT1);
+
+               local_fiq_enable();
+               local_irq_enable();
+               return;
+       }
+       omap_sram_suspend(omap_readl(ARM_IDLECT1),
+                         omap_readl(ARM_IDLECT2));
+#endif
 
        local_fiq_enable();
        local_irq_enable();
@@ -144,7 +212,9 @@ static void omap_pm_wakeup_setup(void)
 
        if (cpu_is_omap730()) {
                omap_writel(~level2_wake, OMAP_IH2_0_MIR);
-               omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), OMAP_IH2_1_MIR);
+               omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) |
+                               OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)),
+                               OMAP_IH2_1_MIR);
        } else if (cpu_is_omap1510()) {
                level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
                omap_writel(~level2_wake,  OMAP_IH2_MIR);
@@ -153,7 +223,8 @@ static void omap_pm_wakeup_setup(void)
                omap_writel(~level2_wake, OMAP_IH2_0_MIR);
 
                /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
-               omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
+               omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ),
+                           OMAP_IH2_1_MIR);
                omap_writel(~0x0, OMAP_IH2_2_MIR);
                omap_writel(~0x0, OMAP_IH2_3_MIR);
        }
@@ -447,15 +518,15 @@ static int omap_pm_read_proc(
                           "MPUI730_CTRL_REG         0x%-8x \n"
                           "MPUI730_DSP_STATUS_REG:      0x%-8x \n"
                           "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
-        "MPUI730_DSP_API_CONFIG_REG:  0x%-8x \n"
-        "MPUI730_SDRAM_CONFIG_REG:    0x%-8x \n"
-        "MPUI730_EMIFS_CONFIG_REG:    0x%-8x \n",
-        MPUI730_SHOW(MPUI_CTRL),
-        MPUI730_SHOW(MPUI_DSP_STATUS),
-        MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
-        MPUI730_SHOW(MPUI_DSP_API_CONFIG),
-        MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
-        MPUI730_SHOW(EMIFS_CONFIG));
+                          "MPUI730_DSP_API_CONFIG_REG:  0x%-8x \n"
+                          "MPUI730_SDRAM_CONFIG_REG:    0x%-8x \n"
+                          "MPUI730_EMIFS_CONFIG_REG:    0x%-8x \n",
+                          MPUI730_SHOW(MPUI_CTRL),
+                          MPUI730_SHOW(MPUI_DSP_STATUS),
+                          MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
+                          MPUI730_SHOW(MPUI_DSP_API_CONFIG),
+                          MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
+                          MPUI730_SHOW(EMIFS_CONFIG));
                } else if (cpu_is_omap1510()) {
                        my_buffer_offset += sprintf(my_base + my_buffer_offset,
                           "MPUI1510_CTRL_REG             0x%-8x \n"
@@ -503,22 +574,26 @@ static void omap_pm_init_proc(void)
 
        entry = create_proc_read_entry("driver/omap_pm",
                                       S_IWUSR | S_IRUGO, NULL,
-          omap_pm_read_proc, NULL);
+                                      omap_pm_read_proc, NULL);
 }
 
 #endif /* DEBUG && CONFIG_PROC_FS */
 
+static void (*saved_idle)(void) = NULL;
+
 /*
  *     omap_pm_prepare - Do preliminary suspend work.
  *     @state:         suspend state we're entering.
  *
  */
-//#include <asm/hardware.h>
-
 static int omap_pm_prepare(suspend_state_t state)
 {
        int error = 0;
 
+       /* We cannot sleep in idle until we have resumed */
+       saved_idle = pm_idle;
+       pm_idle = NULL;
+
        switch (state)
        {
        case PM_SUSPEND_STANDBY:
@@ -572,6 +647,7 @@ static int omap_pm_enter(suspend_state_t state)
 
 static int omap_pm_finish(suspend_state_t state)
 {
+       pm_idle = saved_idle;
        return 0;
 }
 
@@ -600,6 +676,7 @@ static struct pm_ops omap_pm_ops ={
 static int __init omap_pm_init(void)
 {
        printk("Power Management for TI OMAP.\n");
+
        /*
         * We copy the assembler sleep/wakeup routines to SRAM.
         * These routines need to be in SRAM as that's the only
@@ -609,7 +686,7 @@ static int __init omap_pm_init(void)
                omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
                                                omap730_idle_loop_suspend_sz);
                omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
-        omap730_cpu_suspend_sz);
+                                                  omap730_cpu_suspend_sz);
        } else if (cpu_is_omap1510()) {
                omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
                                                omap1510_idle_loop_suspend_sz);
@@ -663,6 +740,8 @@ static int __init omap_pm_init(void)
        omap_pm_init_proc();
 #endif
 
+       subsys_create_file(&power_subsys, &sleep_while_idle_attr);
+
        if (cpu_is_omap16xx()) {
                /* configure LOW_PWR pin */
                omap_cfg_reg(T20_1610_LOW_PWR);
@@ -671,4 +750,3 @@ static int __init omap_pm_init(void)
        return 0;
 }
 __initcall(omap_pm_init);
-
index 4cd7d292f854be9c5b743829081ac0dcdbce2279..218bfe949b24bd500d24b7f151269de7923fd11d 100644 (file)
@@ -383,60 +383,133 @@ ENTRY(omap1610_cpu_suspend)
        mcr     p15, 0, r0, c7, c10, 4
        nop
 
-       @ load base address of Traffic Controller
+       @ Load base address of Traffic Controller
        mov     r6, #TCMIF_ASM_BASE & 0xff000000
        orr     r6, r6, #TCMIF_ASM_BASE & 0x00ff0000
        orr     r6, r6, #TCMIF_ASM_BASE & 0x0000ff00
 
-       @ prepare to put SDRAM into self-refresh manually
+       @ Prepare to put SDRAM into self-refresh manually
        ldr     r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
        orr     r9, r7, #SELF_REFRESH_MODE & 0xff000000
        orr     r9, r9, #SELF_REFRESH_MODE & 0x000000ff
        str     r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
 
-       @ prepare to put EMIFS to Sleep
+       @ Prepare to put EMIFS to Sleep
        ldr     r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
        orr     r9, r8, #IDLE_EMIFS_REQUEST & 0xff
        str     r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
 
-       @ load base address of ARM_IDLECT1 and ARM_IDLECT2
+       @ Load base address of ARM_IDLECT1 and ARM_IDLECT2
        mov     r4, #CLKGEN_REG_ASM_BASE & 0xff000000
        orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000
        orr     r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00
 
-       @ turn off clock domains
-       @ do not disable PERCK (0x04)
+       @ Turn off clock domains
+       @ Do not disable PERCK (0x04)
        mov     r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff
        orr     r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00
        strh    r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
 
-       @ request ARM idle
+       @ Request ARM idle
        mov     r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff
        orr     r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00
        strh    r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
-       @ disable instruction cache
-       mrc     p15, 0, r9, c1, c0, 0
-       bic     r2, r9, #0x1000
-       mcr     p15, 0, r2, c1, c0, 0
-       nop
-
 /*
  * Let's wait for the next wake up event to wake us up. r0 can't be
  * used here because r0 holds ARM_IDLECT1
  */
        mov     r2, #0
        mcr     p15, 0, r2, c7, c0, 4           @ wait for interrupt
+
+       @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions
+       @ according to this formula:
+       @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV
+       @ Max DPLL_MULT = 18
+       @ DPLL_DIV = 1
+       @ ARMDIV = 1
+       @ => 74 nop-instructions
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @10
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @20
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @30
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @40
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @50
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @60
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop     @70
+       nop
+       nop
+       nop
+       nop     @74
 /*
  * omap1610_cpu_suspend()'s resume point.
  *
  * It will just start executing here, so we'll restore stuff from the
  * stack.
  */
-       @ re-enable Icache
-       mcr     p15, 0, r9, c1, c0, 0
-
-       @ reset the ARM_IDLECT1 and ARM_IDLECT2.
+       @ Restore the ARM_IDLECT1 and ARM_IDLECT2.
        strh    r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff]
        strh    r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff]
 
@@ -444,7 +517,7 @@ ENTRY(omap1610_cpu_suspend)
        str     r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff]
        str     r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff]
 
-       @ restore regs and return
+       @ Restore regs and return
        ldmfd   sp!, {r0 - r12, pc}
 
 ENTRY(omap1610_cpu_suspend_sz)
index ccbcb580a5c17b90326c8c9c679cfe737d0d908d..3a6fcd6240994340085cf3ab9277cff22173032f 100644 (file)
@@ -407,6 +407,7 @@ extern void omap_free_lcd_dma(void);
 extern void omap_setup_lcd_dma(void);
 extern void omap_enable_lcd_dma(void);
 extern void omap_stop_lcd_dma(void);
+extern int  omap_lcd_dma_ext_running(void);
 extern void omap_set_lcd_dma_ext_controller(int external);
 extern void omap_set_lcd_dma_single_transfer(int single);
 extern void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
index 11772c792f3e99164878a67d70ed56100c12155c..e6522e6a38344dee5c19c19549a767ee4fca5a50 100644 (file)
@@ -88,5 +88,6 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
 void omap_dm_timer_reset_counter(struct omap_dm_timer *timer);
 
 int omap_dm_timers_active(void);
+u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
 
 #endif /* __ASM_ARCH_TIMER_H */
index 7c790425e3633527080d98c238389ca0d1afbd01..401aec93b8c72461c539d4cd94286c40d05d42a2 100644 (file)
 #endif
 
 #ifndef __ASSEMBLER__
+
+#include <asm/hardware/clock.h>
+
+extern void prevent_idle_sleep(void);
+extern void allow_idle_sleep(void);
+
+/**
+ * clk_deny_idle - Prevents the clock from being idled during MPU idle
+ * @clk: clock signal handle
+ */
+void clk_deny_idle(struct clk *clk);
+
+/**
+ * clk_allow_idle - Counters previous clk_deny_idle
+ * @clk: clock signal handle
+ */
+void clk_deny_idle(struct clk *clk);
+
 extern void omap_pm_idle(void);
 extern void omap_pm_suspend(void);
 extern void omap730_cpu_suspend(unsigned short, unsigned short);
@@ -124,6 +142,7 @@ extern void omap1610_idle_loop_suspend(void);
 #ifdef CONFIG_OMAP_SERIAL_WAKE
 extern void omap_serial_wake_trigger(int enable);
 #else
+#define omap_serial_wakeup_init()      {}
 #define omap_serial_wake_trigger(x)    {}
 #endif /* CONFIG_OMAP_SERIAL_WAKE */