[go: nahoru, domu]

cpuidle-kirkwood.c revision e978aa7d7d57d04eb5f88a7507c4fb98577def77
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,
35e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar			       int index)
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);
42e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar	if (index == 0)
43e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		/* Wait for interrupt state */
44e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		cpu_do_idle();
45e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar	else if (index == 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);
60e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar
61e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar	/* Update last residency */
62e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar	dev->last_residency = idle_time;
63e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar
64e978aa7d7d57d04eb5f88a7507c4fb98577def77Deepthi Dharwar	return index;
65e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury}
66e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
67e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury/* Initialize CPU idle by registering the idle states */
68e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourystatic int kirkwood_init_cpuidle(void)
69e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury{
70e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	struct cpuidle_device *device;
71e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
72e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	cpuidle_register_driver(&kirkwood_idle_driver);
73e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
74e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id());
75e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->state_count = KIRKWOOD_MAX_STATES;
76e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
77e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	/* Wait for interrupt state */
78e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].enter = kirkwood_enter_idle;
79e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].exit_latency = 1;
80e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].target_residency = 10000;
81e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[0].flags = CPUIDLE_FLAG_TIME_VALID;
82e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[0].name, "WFI");
83e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[0].desc, "Wait for interrupt");
84e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
85e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	/* Wait for interrupt and DDR self refresh state */
86e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].enter = kirkwood_enter_idle;
87e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].exit_latency = 10;
88e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].target_residency = 10000;
89e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	device->states[1].flags = CPUIDLE_FLAG_TIME_VALID;
90e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[1].name, "DDR SR");
91e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	strcpy(device->states[1].desc, "WFI and DDR Self Refresh");
92e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
93e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	if (cpuidle_register_device(device)) {
94e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		printk(KERN_ERR "kirkwood_init_cpuidle: Failed registering\n");
95e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury		return -EIO;
96e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	}
97e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury	return 0;
98e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury}
99e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khoury
100e50b6befae9ea91c2d190fb78ff1e06a0b950addRabeeh Khourydevice_initcall(kirkwood_init_cpuidle);
101