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 #include +#include +#include + #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