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