Merge tag 'split-asm_system_h-for-linus-20120328' of git://git.kernel.org/pub/scm...
[linux-2.6.git] / arch / arm / mach-ebsa110 / core.c
index 0c40e59..8c9f56a 100644 (file)
 
 #include <asm/mach/time.h>
 
-#define IRQ_MASK               0xfe000000      /* read */
-#define IRQ_MSET               0xfe000000      /* write */
-#define IRQ_STAT               0xff000000      /* read */
-#define IRQ_MCLR               0xff000000      /* write */
+#include "core.h"
 
 static void ebsa110_mask_irq(struct irq_data *d)
 {
@@ -79,22 +76,22 @@ static struct map_desc ebsa110_io_desc[] __initdata = {
        {       /* IRQ_STAT/IRQ_MCLR */
                .virtual        = IRQ_STAT,
                .pfn            = __phys_to_pfn(TRICK4_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK4_SIZE,
                .type           = MT_DEVICE
        }, {    /* IRQ_MASK/IRQ_MSET */
                .virtual        = IRQ_MASK,
                .pfn            = __phys_to_pfn(TRICK3_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK3_SIZE,
                .type           = MT_DEVICE
        }, {    /* SOFT_BASE */
                .virtual        = SOFT_BASE,
                .pfn            = __phys_to_pfn(TRICK1_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK1_SIZE,
                .type           = MT_DEVICE
        }, {    /* PIT_BASE */
                .virtual        = PIT_BASE,
                .pfn            = __phys_to_pfn(TRICK0_PHYS),
-               .length         = PGDIR_SIZE,
+               .length         = TRICK0_SIZE,
                .type           = MT_DEVICE
        },
 
@@ -271,8 +268,33 @@ static struct platform_device *ebsa110_devices[] = {
        &am79c961_device,
 };
 
+/*
+ * EBSA110 idling methodology:
+ *
+ * We can not execute the "wait for interrupt" instruction since that
+ * will stop our MCLK signal (which provides the clock for the glue
+ * logic, and therefore the timer interrupt).
+ *
+ * Instead, we spin, polling the IRQ_STAT register for the occurrence
+ * of any interrupt with core clock down to the memory clock.
+ */
+static void ebsa110_idle(void)
+{
+       const char *irq_stat = (char *)0xff000000;
+
+       /* disable clock switching */
+       asm volatile ("mcr p15, 0, ip, c15, c2, 2" : : : "cc");
+
+       /* wait for an interrupt to occur */
+       while (!*irq_stat);
+
+       /* enable clock switching */
+       asm volatile ("mcr p15, 0, ip, c15, c1, 2" : : : "cc");
+}
+
 static int __init ebsa110_init(void)
 {
+       arm_pm_idle = ebsa110_idle;
        return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
 }