cpuidle-kirkwood.c revision e50b6befae9ea91c2d190fb78ff1e06a0b950add
1e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* 2e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * arch/arm/mach-kirkwood/cpuidle.c 3e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * 4e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * CPU idle Marvell Kirkwood SoCs 5e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * 6e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * This file is licensed under the terms of the GNU General Public 7e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * License version 2. This program is licensed "as is" without any 8e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * warranty of any kind, whether express or implied. 9e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * 10e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * The cpu idle uses wait-for-interrupt and DDR self refresh in order 11e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * to implement two idle states - 12e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * #1 wait-for-interrupt 13e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * #2 wait-for-interrupt and DDR self refresh 14e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury */ 15e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 16e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/kernel.h> 17e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/init.h> 18e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/platform_device.h> 19e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/cpuidle.h> 20e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <linux/io.h> 21e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <asm/proc-fns.h> 22e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <mach/kirkwood.h> 23e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 24e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#define KIRKWOOD_MAX_STATES 2 25e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 26e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic struct cpuidle_driver kirkwood_idle_driver = { 27e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury .name = "kirkwood_idle", 28e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury .owner = THIS_MODULE, 29e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury}; 30e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 31e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); 32e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 33e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Actual code that puts the SoC in different idle states */ 34e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic int kirkwood_enter_idle(struct cpuidle_device *dev, 35e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury struct cpuidle_state *state) 36e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{ 37e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury struct timeval before, after; 38e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury int idle_time; 39e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 40e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury local_irq_disable(); 41e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury do_gettimeofday(&before); 42e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury if (state == &dev->states[0]) 43e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury /* Wait for interrupt state */ 44e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury cpu_do_idle(); 45e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury else if (state == &dev->states[1]) { 46e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury /* 47e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * Following write will put DDR in self refresh. 48e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * Note that we have 256 cycles before DDR puts it 49e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * self in self-refresh, so the wait-for-interrupt 50e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * call afterwards won't get the DDR from self refresh 51e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury * mode. 52e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury */ 53e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury writel(0x7, DDR_OPERATION_BASE); 54e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury cpu_do_idle(); 55e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury } 56e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury do_gettimeofday(&after); 57e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury local_irq_enable(); 58e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + 59e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury (after.tv_usec - before.tv_usec); 60e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury return idle_time; 61e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury} 62e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 63e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Initialize CPU idle by registering the idle states */ 64e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic int kirkwood_init_cpuidle(void) 65e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{ 66e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury struct cpuidle_device *device; 67e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 68e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury cpuidle_register_driver(&kirkwood_idle_driver); 69e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 70e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); 71e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->state_count = KIRKWOOD_MAX_STATES; 72e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 73e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury /* Wait for interrupt state */ 74e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[0].enter = kirkwood_enter_idle; 75e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[0].exit_latency = 1; 76e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[0].target_residency = 10000; 77e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; 78e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury strcpy(device->states[0].name, "WFI"); 79e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury strcpy(device->states[0].desc, "Wait for interrupt"); 80e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 81e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury /* Wait for interrupt and DDR self refresh state */ 82e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[1].enter = kirkwood_enter_idle; 83e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[1].exit_latency = 10; 84e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[1].target_residency = 10000; 85e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury device->states[1].flags = CPUIDLE_FLAG_TIME_VALID; 86e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury strcpy(device->states[1].name, "DDR SR"); 87e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury strcpy(device->states[1].desc, "WFI and DDR Self Refresh"); 88e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 89e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury if (cpuidle_register_device(device)) { 90e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n"); 91e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury return -EIO; 92e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury } 93e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury return 0; 94e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury} 95e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury 96e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourydevice_initcall(kirkwood_init_cpuidle); 97