[go: nahoru, domu]

cpuidle-kirkwood.c revision dc28094b905a872f8884f1f1c48ca86b3b78583a
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>
21dc28094b905a872f8884f1f1c48ca86b3b78583aPaul Gortmaker#include <linux/export.h>
22e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <asm/proc-fns.h>
23e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#include <mach/kirkwood.h>
24e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
25e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury#define KIRKWOOD_MAX_STATES	2
26e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
27e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic struct cpuidle_driver kirkwood_idle_driver = {
28e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	.name =         "kirkwood_idle",
29e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	.owner =        THIS_MODULE,
30e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury};
31e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
32e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device);
33e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
34e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Actual code that puts the SoC in different idle states */
35e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic int kirkwood_enter_idle(struct cpuidle_device *dev,
36e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury			       struct cpuidle_state *state)
37e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{
38e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	struct timeval before, after;
39e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	int idle_time;
40e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
41e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	local_irq_disable();
42e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	do_gettimeofday(&before);
43e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	if (state == &dev->states[0])
44e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		/* Wait for interrupt state */
45e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		cpu_do_idle();
46e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	else if (state == &dev->states[1]) {
47e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		/*
48e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		 * Following write will put DDR in self refresh.
49e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		 * Note that we have 256 cycles before DDR puts it
50e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		 * self in self-refresh, so the wait-for-interrupt
51e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		 * call afterwards won't get the DDR from self refresh
52e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		 * mode.
53e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		 */
54e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		writel(0x7, DDR_OPERATION_BASE);
55e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		cpu_do_idle();
56e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	}
57e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	do_gettimeofday(&after);
58e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	local_irq_enable();
59e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
60e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury			(after.tv_usec - before.tv_usec);
61e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	return idle_time;
62e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury}
63e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
64e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Initialize CPU idle by registering the idle states */
65e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic int kirkwood_init_cpuidle(void)
66e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{
67e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	struct cpuidle_device *device;
68e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
69e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	cpuidle_register_driver(&kirkwood_idle_driver);
70e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
71e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
72e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->state_count = KIRKWOOD_MAX_STATES;
73e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
74e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	/* Wait for interrupt state */
75e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].enter = kirkwood_enter_idle;
76e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].exit_latency = 1;
77e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].target_residency = 10000;
78e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
79e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[0].name, "WFI");
80e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[0].desc, "Wait for interrupt");
81e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
82e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	/* Wait for interrupt and DDR self refresh state */
83e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].enter = kirkwood_enter_idle;
84e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].exit_latency = 10;
85e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].target_residency = 10000;
86e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
87e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[1].name, "DDR SR");
88e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
89e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
90e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	if (cpuidle_register_device(device)) {
91e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
92e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		return -EIO;
93e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	}
94e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	return 0;
95e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury}
96e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
97e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourydevice_initcall(kirkwood_init_cpuidle);
98