[go: nahoru, domu]

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