[Balloon] Playing with 13MHz

Top Page
Attachments:
Message as email
+ (text/plain)
Delete this message
Reply to this message
Author: Bob Dunlop
Date:  
To: Balloon Board
Subject: [Balloon] Playing with 13MHz
Hi,

Since there's been a little bit of discussion about 13MHz operation
on the IRC channel here's a patch I've been playing with to switch
the system in and out of 13MHz operation when idle.

It works for me (saves about 200mW on a Compulab board) but I have done
no analysis of RAM timings etc. A similar patch to add 13Mhz as a
cpufreq stepping left my system stuck at 13MHz and I havn't worked out
why yet.



--- linux-2.6.git/arch/arm/mach-pxa/pxa27x.c.orig    2007-10-29 13:06:25.000000000 +0000
+++ linux-2.6.git/arch/arm/mach-pxa/pxa27x.c    2007-10-29 13:08:53.000000000 +0000
@@ -25,6 +25,9 @@
 #include <asm/arch/pm.h>
 #include <asm/arch/dma.h>


+#include <asm/arch/system.h>
+#include <asm/mach/time.h>
+
 #include "generic.h"
 #include "devices.h"
 #include "clock.h"
@@ -32,6 +35,10 @@
 /* Crystal clock: 13MHz */
 #define BASE_CLK    13000000


+#define CCLKCFG_FCS         0x2
+#define CCCR_CPDIS            0x80000000    /* Disable CPU PLL */
+
+
 /*
  * Get the clock frequency as reflected by CCSR and the turbo flag.
  * We assume these values have been applied via a fcs.
@@ -43,6 +50,13 @@
     unsigned int l, L, m, M, n2, N, S;
            int cccr_a, t, ht, b;


+    if ( CCCR & CCCR_CPDIS )
+    {
+        if (info)
+             printk( KERN_INFO "CPU PLL disabled (13MHz operation)\n");
+        return BASE_CLK / 1000;
+    }
+
     ccsr = CCSR;
     cccr_a = CCCR & (1 << 25);


@@ -312,6 +326,61 @@
}
#endif

+/*
+ *    Try to save power by entering 13MHz operation during the idle loop
+ */
+void pxa27x_enter_13M(void)
+{
+    unsigned int cclkcfg;
+    unsigned int unused;
+
+    /* Disable CPU PLL */
+    CCCR |= CCCR_CPDIS;
+
+    /* Set the frequency change flag */
+    __asm__ __volatile__ ( "mrc p14, 0, %0, c6, c0, 0" : "=r" (cclkcfg) );
+    cclkcfg |= CCLKCFG_FCS;
+    __asm__ __volatile__ ( "mcr p14, 0, %1, c6, c0, 0" : "=&r" (unused)
+                            : "r" (cclkcfg) );
+}
+
+void pxa27x_leave_13M(void)
+{
+    unsigned int cclkcfg;
+    unsigned int unused;
+
+    /* Enable CPU PLL */
+    CCCR &= ~CCCR_CPDIS;
+
+    /* Set the frequency change flag */
+    __asm__ __volatile__ ( "mrc p14, 0, %0, c6, c0, 0" : "=r" (cclkcfg) );
+    cclkcfg |= CCLKCFG_FCS;
+    __asm__ __volatile__ ( "mcr p14, 0, %1, c6, c0, 0" : "=&r" (unused)
+                            : "r" (cclkcfg) );
+}
+
+static void pxa27x_idle(void)
+{
+    local_irq_disable();
+    if ( CCCR & CCCR_CPDIS )
+    {
+        if (!need_resched()) {
+            timer_dyn_reprogram();
+            arch_idle();
+        }
+    }
+    else
+    {
+        pxa27x_enter_13M();
+        if (!need_resched()) {
+            timer_dyn_reprogram();
+            arch_idle();
+        }
+        pxa27x_leave_13M();
+    }
+    local_irq_enable();
+}
+
 /* PXA27x:  Various gpios can issue wakeup events.  This logic only
  * handles the simple cases, not the WEMUX2 and WEMUX3 options
  */
@@ -455,6 +524,8 @@
 #ifdef CONFIG_PM
         pxa27x_init_pm();
 #endif
+        pm_idle = pxa27x_idle;
+
         ret = platform_add_devices(devices, ARRAY_SIZE(devices));
     }
     return ret;
-- 
        Bob Dunlop
    Guralp Systems Limited
    http://www.guralp.com