avr32: Move sleep code into mach-at32ap
authorHaavard Skinnemoen <hskinnemoen@atmel.com>
Sun, 24 Feb 2008 22:24:26 +0000 (23:24 +0100)
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>
Sun, 20 Apr 2008 00:40:07 +0000 (20:40 -0400)
Create a new file, pm-at32ap700x.S, in mach-at32ap and move the CPU
idle sleep code there. Make it possible to disable the sleep code.

Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
arch/avr32/kernel/entry-avr32b.S
arch/avr32/kernel/process.c
arch/avr32/mach-at32ap/Makefile
arch/avr32/mach-at32ap/pm-at32ap700x.S [new file with mode: 0644]
include/asm-avr32/arch-at32ap/pm.h [new file with mode: 0644]

index 8cf16d7a70409b1994990030cdef47612775a9b0..5f31702d6b1c9e3ffc55ee4866b8ac4f7b2dfdcb 100644 (file)
@@ -741,26 +741,6 @@ irq_level\level:
 
        .section .irq.text,"ax",@progbits
 
-.global cpu_idle_sleep
-cpu_idle_sleep:
-       mask_interrupts
-       get_thread_info r8
-       ld.w    r9, r8[TI_flags]
-       bld     r9, TIF_NEED_RESCHED
-       brcs    cpu_idle_enable_int_and_exit
-       sbr     r9, TIF_CPU_GOING_TO_SLEEP
-       st.w    r8[TI_flags], r9
-       unmask_interrupts
-       sleep 0
-cpu_idle_skip_sleep:
-       mask_interrupts
-       ld.w    r9, r8[TI_flags]
-       cbr     r9, TIF_CPU_GOING_TO_SLEEP
-       st.w    r8[TI_flags], r9
-cpu_idle_enable_int_and_exit:
-       unmask_interrupts
-       retal   r12
-
        .global irq_level0
        .global irq_level1
        .global irq_level2
index 7f4af0b1e111448f4941fbb7d3ae94589f13a961..3de115462d7bd8ca9405d942a29713e8abe424fc 100644 (file)
 #include <asm/sysreg.h>
 #include <asm/ocd.h>
 
+#include <asm/arch/pm.h>
+
 void (*pm_power_off)(void) = NULL;
 EXPORT_SYMBOL(pm_power_off);
 
-extern void cpu_idle_sleep(void);
-
 /*
  * This file handles the architecture-dependent parts of process handling..
  */
index 5e9f8217befc16f4095918f8be3c710a1c4fb621..83cab2abb6c36f6c32c09cf9a5cce5d1f637eef9 100644 (file)
@@ -1,4 +1,4 @@
 obj-y                          += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
-obj-$(CONFIG_CPU_AT32AP700X)   += at32ap700x.o
+obj-$(CONFIG_CPU_AT32AP700X)   += at32ap700x.o pm-at32ap700x.o
 obj-$(CONFIG_CPU_AT32AP700X)   += time-tc.o
 obj-$(CONFIG_CPU_FREQ_AT32AP)  += cpufreq.o
diff --git a/arch/avr32/mach-at32ap/pm-at32ap700x.S b/arch/avr32/mach-at32ap/pm-at32ap700x.S
new file mode 100644 (file)
index 0000000..949e248
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Low-level Power Management code.
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/arch/pm.h>
+
+       .section .bss, "wa", @nobits
+       .global disable_idle_sleep
+       .type   disable_idle_sleep, @object
+disable_idle_sleep:
+       .int    4
+       .size   disable_idle_sleep, . - disable_idle_sleep
+
+       /* Keep this close to the irq handlers */
+       .section .irq.text, "ax", @progbits
+
+       /*
+        * void cpu_enter_idle(void)
+        *
+        * Put the CPU into "idle" mode, in which it will consume
+        * significantly less power.
+        *
+        * If an interrupt comes along in the window between
+        * unmask_interrupts and the sleep instruction below, the
+        * interrupt code will adjust the return address so that we
+        * never execute the sleep instruction. This is required
+        * because the AP7000 doesn't unmask interrupts when entering
+        * sleep modes; later CPUs may not need this workaround.
+        */
+       .global cpu_enter_idle
+       .type   cpu_enter_idle, @function
+cpu_enter_idle:
+       mask_interrupts
+       get_thread_info r8
+       ld.w    r9, r8[TI_flags]
+       bld     r9, TIF_NEED_RESCHED
+       brcs    .Lret_from_sleep
+       sbr     r9, TIF_CPU_GOING_TO_SLEEP
+       st.w    r8[TI_flags], r9
+       unmask_interrupts
+       sleep   CPU_SLEEP_IDLE
+       .size   cpu_idle_sleep, . - cpu_idle_sleep
+
+       /*
+        * Common return path for PM functions that don't run from
+        * SRAM.
+        */
+       .global cpu_idle_skip_sleep
+       .type   cpu_idle_skip_sleep, @function
+cpu_idle_skip_sleep:
+       mask_interrupts
+       ld.w    r9, r8[TI_flags]
+       cbr     r9, TIF_CPU_GOING_TO_SLEEP
+       st.w    r8[TI_flags], r9
+.Lret_from_sleep:
+       unmask_interrupts
+       retal   r12
+       .size   cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
diff --git a/include/asm-avr32/arch-at32ap/pm.h b/include/asm-avr32/arch-at32ap/pm.h
new file mode 100644 (file)
index 0000000..356e430
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * AVR32 AP Power Management.
+ *
+ * Copyright (C) 2008 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_AVR32_ARCH_PM_H
+#define __ASM_AVR32_ARCH_PM_H
+
+/* Possible arguments to the "sleep" instruction */
+#define CPU_SLEEP_IDLE         0
+#define CPU_SLEEP_FROZEN       1
+#define CPU_SLEEP_STANDBY      2
+#define CPU_SLEEP_STOP         3
+#define CPU_SLEEP_STATIC       5
+
+#ifndef __ASSEMBLY__
+extern void cpu_enter_idle(void);
+
+extern bool disable_idle_sleep;
+
+static inline void cpu_disable_idle_sleep(void)
+{
+       disable_idle_sleep = true;
+}
+
+static inline void cpu_enable_idle_sleep(void)
+{
+       disable_idle_sleep = false;
+}
+
+static inline void cpu_idle_sleep(void)
+{
+       /*
+        * If we're using the COUNT and COMPARE registers for
+        * timekeeping, we can't use the IDLE state.
+        */
+       if (disable_idle_sleep)
+               cpu_relax();
+       else
+               cpu_enter_idle();
+}
+#endif
+
+#endif /* __ASM_AVR32_ARCH_PM_H */