[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