diff options
author | Rajendra Nayak <rnayak@ti.com> | 2008-10-08 08:00:58 -0400 |
---|---|---|
committer | Kevin Hilman <khilman@deeprootsystems.com> | 2009-11-11 17:42:48 -0500 |
commit | 99e6a4d22f7c7bda0cd8978333c2e85fba02f181 (patch) | |
tree | 22a31df1b559cfa4a43a0babf23d4d84ab290a37 /arch/arm | |
parent | f265dc4c5d39f2bd369d97c87a7bd89061b159d4 (diff) |
OMAP3: PM: CPUidle: base driver and support for C1-C2
Basic CPUidle driver for OMAP3 with deepest sleep state supported
being MPU CSWR.
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 255 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm34xx.c | 4 |
4 files changed, 260 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 8cb16777661a..1d54ad349bfd 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile | |||
@@ -31,7 +31,7 @@ obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o | |||
31 | ifeq ($(CONFIG_PM),y) | 31 | ifeq ($(CONFIG_PM),y) |
32 | obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o | 32 | obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o |
33 | obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o | 33 | obj-$(CONFIG_ARCH_OMAP24XX) += sleep24xx.o |
34 | obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o | 34 | obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o |
35 | obj-$(CONFIG_PM_DEBUG) += pm-debug.o | 35 | obj-$(CONFIG_PM_DEBUG) += pm-debug.o |
36 | endif | 36 | endif |
37 | 37 | ||
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c new file mode 100644 index 000000000000..858b216b63b6 --- /dev/null +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-omap2/cpuidle34xx.c | ||
3 | * | ||
4 | * OMAP3 CPU IDLE Routines | ||
5 | * | ||
6 | * Copyright (C) 2008 Texas Instruments, Inc. | ||
7 | * Rajendra Nayak <rnayak@ti.com> | ||
8 | * | ||
9 | * Copyright (C) 2007 Texas Instruments, Inc. | ||
10 | * Karthik Dasu <karthik-dp@ti.com> | ||
11 | * | ||
12 | * Copyright (C) 2006 Nokia Corporation | ||
13 | * Tony Lindgren <tony@atomide.com> | ||
14 | * | ||
15 | * Copyright (C) 2005 Texas Instruments, Inc. | ||
16 | * Richard Woodruff <r-woodruff2@ti.com> | ||
17 | * | ||
18 | * Based on pm.c for omap2 | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License version 2 as | ||
22 | * published by the Free Software Foundation. | ||
23 | */ | ||
24 | |||
25 | #include <linux/cpuidle.h> | ||
26 | |||
27 | #include <plat/prcm.h> | ||
28 | #include <plat/powerdomain.h> | ||
29 | |||
30 | #ifdef CONFIG_CPU_IDLE | ||
31 | |||
32 | #define OMAP3_MAX_STATES 7 | ||
33 | #define OMAP3_STATE_C1 1 /* C1 - MPU WFI + Core active */ | ||
34 | #define OMAP3_STATE_C2 2 /* C2 - MPU CSWR + Core active */ | ||
35 | #define OMAP3_STATE_C3 3 /* C3 - MPU OFF + Core active */ | ||
36 | #define OMAP3_STATE_C4 4 /* C4 - MPU RET + Core RET */ | ||
37 | #define OMAP3_STATE_C5 5 /* C5 - MPU OFF + Core RET */ | ||
38 | #define OMAP3_STATE_C6 6 /* C6 - MPU OFF + Core OFF */ | ||
39 | |||
40 | struct omap3_processor_cx { | ||
41 | u8 valid; | ||
42 | u8 type; | ||
43 | u32 sleep_latency; | ||
44 | u32 wakeup_latency; | ||
45 | u32 mpu_state; | ||
46 | u32 core_state; | ||
47 | u32 threshold; | ||
48 | u32 flags; | ||
49 | }; | ||
50 | |||
51 | struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; | ||
52 | struct omap3_processor_cx current_cx_state; | ||
53 | struct powerdomain *mpu_pd; | ||
54 | |||
55 | static int omap3_idle_bm_check(void) | ||
56 | { | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * omap3_enter_idle - Programs OMAP3 to enter the specified state | ||
62 | * @dev: cpuidle device | ||
63 | * @state: The target state to be programmed | ||
64 | * | ||
65 | * Called from the CPUidle framework to program the device to the | ||
66 | * specified target state selected by the governor. | ||
67 | */ | ||
68 | static int omap3_enter_idle(struct cpuidle_device *dev, | ||
69 | struct cpuidle_state *state) | ||
70 | { | ||
71 | struct omap3_processor_cx *cx = cpuidle_get_statedata(state); | ||
72 | struct timespec ts_preidle, ts_postidle, ts_idle; | ||
73 | |||
74 | current_cx_state = *cx; | ||
75 | |||
76 | /* Used to keep track of the total time in idle */ | ||
77 | getnstimeofday(&ts_preidle); | ||
78 | |||
79 | local_irq_disable(); | ||
80 | local_fiq_disable(); | ||
81 | |||
82 | /* Program MPU to target state */ | ||
83 | if (cx->mpu_state < PWRDM_POWER_ON) | ||
84 | pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state); | ||
85 | |||
86 | /* Execute ARM wfi */ | ||
87 | omap_sram_idle(); | ||
88 | |||
89 | /* Program MPU to ON */ | ||
90 | if (cx->mpu_state < PWRDM_POWER_ON) | ||
91 | pwrdm_set_next_pwrst(mpu_pd, PWRDM_POWER_ON); | ||
92 | |||
93 | getnstimeofday(&ts_postidle); | ||
94 | ts_idle = timespec_sub(ts_postidle, ts_preidle); | ||
95 | |||
96 | local_irq_enable(); | ||
97 | local_fiq_enable(); | ||
98 | |||
99 | return timespec_to_ns(&ts_idle); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * omap3_enter_idle_bm - Checks for any bus activity | ||
104 | * @dev: cpuidle device | ||
105 | * @state: The target state to be programmed | ||
106 | * | ||
107 | * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This | ||
108 | * function checks for any pending activity and then programs the | ||
109 | * device to the specified or a safer state. | ||
110 | */ | ||
111 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, | ||
112 | struct cpuidle_state *state) | ||
113 | { | ||
114 | if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { | ||
115 | if (dev->safe_state) | ||
116 | return dev->safe_state->enter(dev, dev->safe_state); | ||
117 | } | ||
118 | return omap3_enter_idle(dev, state); | ||
119 | } | ||
120 | |||
121 | DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); | ||
122 | |||
123 | /* omap3_init_power_states - Initialises the OMAP3 specific C states. | ||
124 | * | ||
125 | * Below is the desciption of each C state. | ||
126 | * C1 . MPU WFI + Core active | ||
127 | * C2 . MPU CSWR + Core active | ||
128 | * C3 . MPU OFF + Core active | ||
129 | * C4 . MPU CSWR + Core CSWR | ||
130 | * C5 . MPU OFF + Core CSWR | ||
131 | * C6 . MPU OFF + Core OFF | ||
132 | */ | ||
133 | void omap_init_power_states(void) | ||
134 | { | ||
135 | /* C1 . MPU WFI + Core active */ | ||
136 | omap3_power_states[OMAP3_STATE_C1].valid = 1; | ||
137 | omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1; | ||
138 | omap3_power_states[OMAP3_STATE_C1].sleep_latency = 10; | ||
139 | omap3_power_states[OMAP3_STATE_C1].wakeup_latency = 10; | ||
140 | omap3_power_states[OMAP3_STATE_C1].threshold = 30; | ||
141 | omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON; | ||
142 | omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON; | ||
143 | omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID; | ||
144 | |||
145 | /* C2 . MPU CSWR + Core active */ | ||
146 | omap3_power_states[OMAP3_STATE_C2].valid = 1; | ||
147 | omap3_power_states[OMAP3_STATE_C2].type = OMAP3_STATE_C2; | ||
148 | omap3_power_states[OMAP3_STATE_C2].sleep_latency = 50; | ||
149 | omap3_power_states[OMAP3_STATE_C2].wakeup_latency = 50; | ||
150 | omap3_power_states[OMAP3_STATE_C2].threshold = 300; | ||
151 | omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_RET; | ||
152 | omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; | ||
153 | omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; | ||
154 | |||
155 | /* C3 . MPU OFF + Core active */ | ||
156 | omap3_power_states[OMAP3_STATE_C3].valid = 0; | ||
157 | omap3_power_states[OMAP3_STATE_C3].type = OMAP3_STATE_C3; | ||
158 | omap3_power_states[OMAP3_STATE_C3].sleep_latency = 1500; | ||
159 | omap3_power_states[OMAP3_STATE_C3].wakeup_latency = 1800; | ||
160 | omap3_power_states[OMAP3_STATE_C3].threshold = 4000; | ||
161 | omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_OFF; | ||
162 | omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON; | ||
163 | omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID; | ||
164 | |||
165 | /* C4 . MPU CSWR + Core CSWR*/ | ||
166 | omap3_power_states[OMAP3_STATE_C4].valid = 0; | ||
167 | omap3_power_states[OMAP3_STATE_C4].type = OMAP3_STATE_C4; | ||
168 | omap3_power_states[OMAP3_STATE_C4].sleep_latency = 2500; | ||
169 | omap3_power_states[OMAP3_STATE_C4].wakeup_latency = 7500; | ||
170 | omap3_power_states[OMAP3_STATE_C4].threshold = 12000; | ||
171 | omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_RET; | ||
172 | omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_RET; | ||
173 | omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID | | ||
174 | CPUIDLE_FLAG_CHECK_BM; | ||
175 | |||
176 | /* C5 . MPU OFF + Core CSWR */ | ||
177 | omap3_power_states[OMAP3_STATE_C5].valid = 0; | ||
178 | omap3_power_states[OMAP3_STATE_C5].type = OMAP3_STATE_C5; | ||
179 | omap3_power_states[OMAP3_STATE_C5].sleep_latency = 3000; | ||
180 | omap3_power_states[OMAP3_STATE_C5].wakeup_latency = 8500; | ||
181 | omap3_power_states[OMAP3_STATE_C5].threshold = 15000; | ||
182 | omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_OFF; | ||
183 | omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET; | ||
184 | omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID | | ||
185 | CPUIDLE_FLAG_CHECK_BM; | ||
186 | |||
187 | /* C6 . MPU OFF + Core OFF */ | ||
188 | omap3_power_states[OMAP3_STATE_C6].valid = 0; | ||
189 | omap3_power_states[OMAP3_STATE_C6].type = OMAP3_STATE_C6; | ||
190 | omap3_power_states[OMAP3_STATE_C6].sleep_latency = 10000; | ||
191 | omap3_power_states[OMAP3_STATE_C6].wakeup_latency = 30000; | ||
192 | omap3_power_states[OMAP3_STATE_C6].threshold = 300000; | ||
193 | omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF; | ||
194 | omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_OFF; | ||
195 | omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID | | ||
196 | CPUIDLE_FLAG_CHECK_BM; | ||
197 | } | ||
198 | |||
199 | struct cpuidle_driver omap3_idle_driver = { | ||
200 | .name = "omap3_idle", | ||
201 | .owner = THIS_MODULE, | ||
202 | }; | ||
203 | |||
204 | /** | ||
205 | * omap3_idle_init - Init routine for OMAP3 idle | ||
206 | * | ||
207 | * Registers the OMAP3 specific cpuidle driver with the cpuidle | ||
208 | * framework with the valid set of states. | ||
209 | */ | ||
210 | int omap3_idle_init(void) | ||
211 | { | ||
212 | int i, count = 0; | ||
213 | struct omap3_processor_cx *cx; | ||
214 | struct cpuidle_state *state; | ||
215 | struct cpuidle_device *dev; | ||
216 | |||
217 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); | ||
218 | |||
219 | omap_init_power_states(); | ||
220 | cpuidle_register_driver(&omap3_idle_driver); | ||
221 | |||
222 | dev = &per_cpu(omap3_idle_dev, smp_processor_id()); | ||
223 | |||
224 | for (i = 1; i < OMAP3_MAX_STATES; i++) { | ||
225 | cx = &omap3_power_states[i]; | ||
226 | state = &dev->states[count]; | ||
227 | |||
228 | if (!cx->valid) | ||
229 | continue; | ||
230 | cpuidle_set_statedata(state, cx); | ||
231 | state->exit_latency = cx->sleep_latency + cx->wakeup_latency; | ||
232 | state->target_residency = cx->threshold; | ||
233 | state->flags = cx->flags; | ||
234 | state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ? | ||
235 | omap3_enter_idle_bm : omap3_enter_idle; | ||
236 | if (cx->type == OMAP3_STATE_C1) | ||
237 | dev->safe_state = state; | ||
238 | sprintf(state->name, "C%d", count+1); | ||
239 | count++; | ||
240 | } | ||
241 | |||
242 | if (!count) | ||
243 | return -EINVAL; | ||
244 | dev->state_count = count; | ||
245 | |||
246 | if (cpuidle_register_device(dev)) { | ||
247 | printk(KERN_ERR "%s: CPUidle register device failed\n", | ||
248 | __func__); | ||
249 | return -EIO; | ||
250 | } | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | device_initcall(omap3_idle_init); | ||
255 | #endif /* CONFIG_CPU_IDLE */ | ||
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 7eb769f4ef30..2edf1ba12dca 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h | |||
@@ -18,6 +18,7 @@ extern u32 sleep_while_idle; | |||
18 | 18 | ||
19 | extern void *omap3_secure_ram_storage; | 19 | extern void *omap3_secure_ram_storage; |
20 | extern void omap3_pm_off_mode_enable(int); | 20 | extern void omap3_pm_off_mode_enable(int); |
21 | extern void omap_sram_idle(void); | ||
21 | 22 | ||
22 | extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); | 23 | extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); |
23 | extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); | 24 | extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); |
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c index 01b95eaae75a..0c49db8afa99 100644 --- a/arch/arm/mach-omap2/pm34xx.c +++ b/arch/arm/mach-omap2/pm34xx.c | |||
@@ -318,7 +318,7 @@ static void restore_table_entry(void) | |||
318 | restore_control_register(control_reg_value); | 318 | restore_control_register(control_reg_value); |
319 | } | 319 | } |
320 | 320 | ||
321 | static void omap_sram_idle(void) | 321 | void omap_sram_idle(void) |
322 | { | 322 | { |
323 | /* Variable to tell what needs to be saved and restored | 323 | /* Variable to tell what needs to be saved and restored |
324 | * in omap_sram_idle*/ | 324 | * in omap_sram_idle*/ |
@@ -1101,7 +1101,9 @@ static int __init omap3_pm_init(void) | |||
1101 | suspend_set_ops(&omap_pm_ops); | 1101 | suspend_set_ops(&omap_pm_ops); |
1102 | #endif /* CONFIG_SUSPEND */ | 1102 | #endif /* CONFIG_SUSPEND */ |
1103 | 1103 | ||
1104 | #ifndef CONFIG_CPU_IDLE | ||
1104 | pm_idle = omap3_pm_idle; | 1105 | pm_idle = omap3_pm_idle; |
1106 | #endif | ||
1105 | 1107 | ||
1106 | pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm); | 1108 | pwrdm_add_wkdep(neon_pwrdm, mpu_pwrdm); |
1107 | /* | 1109 | /* |