diff options
Diffstat (limited to 'arch/arm/mach-omap2/cpuidle34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 133 |
1 files changed, 85 insertions, 48 deletions
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 4bf6e6e8b100..1fe35c24fba2 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -88,17 +88,21 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm, | |||
88 | /** | 88 | /** |
89 | * omap3_enter_idle - Programs OMAP3 to enter the specified state | 89 | * omap3_enter_idle - Programs OMAP3 to enter the specified state |
90 | * @dev: cpuidle device | 90 | * @dev: cpuidle device |
91 | * @state: The target state to be programmed | 91 | * @drv: cpuidle driver |
92 | * @index: the index of state to be entered | ||
92 | * | 93 | * |
93 | * Called from the CPUidle framework to program the device to the | 94 | * Called from the CPUidle framework to program the device to the |
94 | * specified target state selected by the governor. | 95 | * specified target state selected by the governor. |
95 | */ | 96 | */ |
96 | static int omap3_enter_idle(struct cpuidle_device *dev, | 97 | static int omap3_enter_idle(struct cpuidle_device *dev, |
97 | struct cpuidle_state *state) | 98 | struct cpuidle_driver *drv, |
99 | int index) | ||
98 | { | 100 | { |
99 | struct omap3_idle_statedata *cx = cpuidle_get_statedata(state); | 101 | struct omap3_idle_statedata *cx = |
102 | cpuidle_get_statedata(&dev->states_usage[index]); | ||
100 | struct timespec ts_preidle, ts_postidle, ts_idle; | 103 | struct timespec ts_preidle, ts_postidle, ts_idle; |
101 | u32 mpu_state = cx->mpu_state, core_state = cx->core_state; | 104 | u32 mpu_state = cx->mpu_state, core_state = cx->core_state; |
105 | int idle_time; | ||
102 | 106 | ||
103 | /* Used to keep track of the total time in idle */ | 107 | /* Used to keep track of the total time in idle */ |
104 | getnstimeofday(&ts_preidle); | 108 | getnstimeofday(&ts_preidle); |
@@ -113,7 +117,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, | |||
113 | goto return_sleep_time; | 117 | goto return_sleep_time; |
114 | 118 | ||
115 | /* Deny idle for C1 */ | 119 | /* Deny idle for C1 */ |
116 | if (state == &dev->states[0]) { | 120 | if (index == 0) { |
117 | pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); | 121 | pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); |
118 | pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); | 122 | pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); |
119 | } | 123 | } |
@@ -122,7 +126,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev, | |||
122 | omap_sram_idle(); | 126 | omap_sram_idle(); |
123 | 127 | ||
124 | /* Re-allow idle for C1 */ | 128 | /* Re-allow idle for C1 */ |
125 | if (state == &dev->states[0]) { | 129 | if (index == 0) { |
126 | pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); | 130 | pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); |
127 | pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); | 131 | pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); |
128 | } | 132 | } |
@@ -134,28 +138,38 @@ return_sleep_time: | |||
134 | local_irq_enable(); | 138 | local_irq_enable(); |
135 | local_fiq_enable(); | 139 | local_fiq_enable(); |
136 | 140 | ||
137 | return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; | 141 | idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \ |
142 | USEC_PER_SEC; | ||
143 | |||
144 | /* Update cpuidle counters */ | ||
145 | dev->last_residency = idle_time; | ||
146 | |||
147 | return index; | ||
138 | } | 148 | } |
139 | 149 | ||
140 | /** | 150 | /** |
141 | * next_valid_state - Find next valid C-state | 151 | * next_valid_state - Find next valid C-state |
142 | * @dev: cpuidle device | 152 | * @dev: cpuidle device |
143 | * @state: Currently selected C-state | 153 | * @drv: cpuidle driver |
154 | * @index: Index of currently selected c-state | ||
144 | * | 155 | * |
145 | * If the current state is valid, it is returned back to the caller. | 156 | * If the state corresponding to index is valid, index is returned back |
146 | * Else, this function searches for a lower c-state which is still | 157 | * to the caller. Else, this function searches for a lower c-state which is |
147 | * valid. | 158 | * still valid (as defined in omap3_power_states[]) and returns its index. |
148 | * | 159 | * |
149 | * A state is valid if the 'valid' field is enabled and | 160 | * A state is valid if the 'valid' field is enabled and |
150 | * if it satisfies the enable_off_mode condition. | 161 | * if it satisfies the enable_off_mode condition. |
151 | */ | 162 | */ |
152 | static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, | 163 | static int next_valid_state(struct cpuidle_device *dev, |
153 | struct cpuidle_state *curr) | 164 | struct cpuidle_driver *drv, |
165 | int index) | ||
154 | { | 166 | { |
155 | struct cpuidle_state *next = NULL; | 167 | struct cpuidle_state_usage *curr_usage = &dev->states_usage[index]; |
156 | struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr); | 168 | struct cpuidle_state *curr = &drv->states[index]; |
169 | struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage); | ||
157 | u32 mpu_deepest_state = PWRDM_POWER_RET; | 170 | u32 mpu_deepest_state = PWRDM_POWER_RET; |
158 | u32 core_deepest_state = PWRDM_POWER_RET; | 171 | u32 core_deepest_state = PWRDM_POWER_RET; |
172 | int next_index = -1; | ||
159 | 173 | ||
160 | if (enable_off_mode) { | 174 | if (enable_off_mode) { |
161 | mpu_deepest_state = PWRDM_POWER_OFF; | 175 | mpu_deepest_state = PWRDM_POWER_OFF; |
@@ -172,20 +186,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, | |||
172 | if ((cx->valid) && | 186 | if ((cx->valid) && |
173 | (cx->mpu_state >= mpu_deepest_state) && | 187 | (cx->mpu_state >= mpu_deepest_state) && |
174 | (cx->core_state >= core_deepest_state)) { | 188 | (cx->core_state >= core_deepest_state)) { |
175 | return curr; | 189 | return index; |
176 | } else { | 190 | } else { |
177 | int idx = OMAP3_NUM_STATES - 1; | 191 | int idx = OMAP3_NUM_STATES - 1; |
178 | 192 | ||
179 | /* Reach the current state starting at highest C-state */ | 193 | /* Reach the current state starting at highest C-state */ |
180 | for (; idx >= 0; idx--) { | 194 | for (; idx >= 0; idx--) { |
181 | if (&dev->states[idx] == curr) { | 195 | if (&drv->states[idx] == curr) { |
182 | next = &dev->states[idx]; | 196 | next_index = idx; |
183 | break; | 197 | break; |
184 | } | 198 | } |
185 | } | 199 | } |
186 | 200 | ||
187 | /* Should never hit this condition */ | 201 | /* Should never hit this condition */ |
188 | WARN_ON(next == NULL); | 202 | WARN_ON(next_index == -1); |
189 | 203 | ||
190 | /* | 204 | /* |
191 | * Drop to next valid state. | 205 | * Drop to next valid state. |
@@ -193,41 +207,44 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev, | |||
193 | */ | 207 | */ |
194 | idx--; | 208 | idx--; |
195 | for (; idx >= 0; idx--) { | 209 | for (; idx >= 0; idx--) { |
196 | cx = cpuidle_get_statedata(&dev->states[idx]); | 210 | cx = cpuidle_get_statedata(&dev->states_usage[idx]); |
197 | if ((cx->valid) && | 211 | if ((cx->valid) && |
198 | (cx->mpu_state >= mpu_deepest_state) && | 212 | (cx->mpu_state >= mpu_deepest_state) && |
199 | (cx->core_state >= core_deepest_state)) { | 213 | (cx->core_state >= core_deepest_state)) { |
200 | next = &dev->states[idx]; | 214 | next_index = idx; |
201 | break; | 215 | break; |
202 | } | 216 | } |
203 | } | 217 | } |
204 | /* | 218 | /* |
205 | * C1 is always valid. | 219 | * C1 is always valid. |
206 | * So, no need to check for 'next==NULL' outside this loop. | 220 | * So, no need to check for 'next_index == -1' outside |
221 | * this loop. | ||
207 | */ | 222 | */ |
208 | } | 223 | } |
209 | 224 | ||
210 | return next; | 225 | return next_index; |
211 | } | 226 | } |
212 | 227 | ||
213 | /** | 228 | /** |
214 | * omap3_enter_idle_bm - Checks for any bus activity | 229 | * omap3_enter_idle_bm - Checks for any bus activity |
215 | * @dev: cpuidle device | 230 | * @dev: cpuidle device |
216 | * @state: The target state to be programmed | 231 | * @drv: cpuidle driver |
232 | * @index: array index of target state to be programmed | ||
217 | * | 233 | * |
218 | * This function checks for any pending activity and then programs | 234 | * This function checks for any pending activity and then programs |
219 | * the device to the specified or a safer state. | 235 | * the device to the specified or a safer state. |
220 | */ | 236 | */ |
221 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, | 237 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, |
222 | struct cpuidle_state *state) | 238 | struct cpuidle_driver *drv, |
239 | int index) | ||
223 | { | 240 | { |
224 | struct cpuidle_state *new_state; | 241 | int new_state_idx; |
225 | u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; | 242 | u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; |
226 | struct omap3_idle_statedata *cx; | 243 | struct omap3_idle_statedata *cx; |
227 | int ret; | 244 | int ret; |
228 | 245 | ||
229 | if (!omap3_can_sleep()) { | 246 | if (!omap3_can_sleep()) { |
230 | new_state = dev->safe_state; | 247 | new_state_idx = drv->safe_state_index; |
231 | goto select_state; | 248 | goto select_state; |
232 | } | 249 | } |
233 | 250 | ||
@@ -237,7 +254,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
237 | */ | 254 | */ |
238 | cam_state = pwrdm_read_pwrst(cam_pd); | 255 | cam_state = pwrdm_read_pwrst(cam_pd); |
239 | if (cam_state == PWRDM_POWER_ON) { | 256 | if (cam_state == PWRDM_POWER_ON) { |
240 | new_state = dev->safe_state; | 257 | new_state_idx = drv->safe_state_index; |
241 | goto select_state; | 258 | goto select_state; |
242 | } | 259 | } |
243 | 260 | ||
@@ -253,7 +270,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
253 | * Prevent PER off if CORE is not in retention or off as this | 270 | * Prevent PER off if CORE is not in retention or off as this |
254 | * would disable PER wakeups completely. | 271 | * would disable PER wakeups completely. |
255 | */ | 272 | */ |
256 | cx = cpuidle_get_statedata(state); | 273 | cx = cpuidle_get_statedata(&dev->states_usage[index]); |
257 | core_next_state = cx->core_state; | 274 | core_next_state = cx->core_state; |
258 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | 275 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); |
259 | if ((per_next_state == PWRDM_POWER_OFF) && | 276 | if ((per_next_state == PWRDM_POWER_OFF) && |
@@ -264,11 +281,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
264 | if (per_next_state != per_saved_state) | 281 | if (per_next_state != per_saved_state) |
265 | pwrdm_set_next_pwrst(per_pd, per_next_state); | 282 | pwrdm_set_next_pwrst(per_pd, per_next_state); |
266 | 283 | ||
267 | new_state = next_valid_state(dev, state); | 284 | new_state_idx = next_valid_state(dev, drv, index); |
268 | 285 | ||
269 | select_state: | 286 | select_state: |
270 | dev->last_state = new_state; | 287 | ret = omap3_enter_idle(dev, drv, new_state_idx); |
271 | ret = omap3_enter_idle(dev, new_state); | ||
272 | 288 | ||
273 | /* Restore original PER state if it was modified */ | 289 | /* Restore original PER state if it was modified */ |
274 | if (per_next_state != per_saved_state) | 290 | if (per_next_state != per_saved_state) |
@@ -301,22 +317,31 @@ struct cpuidle_driver omap3_idle_driver = { | |||
301 | .owner = THIS_MODULE, | 317 | .owner = THIS_MODULE, |
302 | }; | 318 | }; |
303 | 319 | ||
304 | /* Helper to fill the C-state common data and register the driver_data */ | 320 | /* Helper to fill the C-state common data*/ |
305 | static inline struct omap3_idle_statedata *_fill_cstate( | 321 | static inline void _fill_cstate(struct cpuidle_driver *drv, |
306 | struct cpuidle_device *dev, | ||
307 | int idx, const char *descr) | 322 | int idx, const char *descr) |
308 | { | 323 | { |
309 | struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; | 324 | struct cpuidle_state *state = &drv->states[idx]; |
310 | struct cpuidle_state *state = &dev->states[idx]; | ||
311 | 325 | ||
312 | state->exit_latency = cpuidle_params_table[idx].exit_latency; | 326 | state->exit_latency = cpuidle_params_table[idx].exit_latency; |
313 | state->target_residency = cpuidle_params_table[idx].target_residency; | 327 | state->target_residency = cpuidle_params_table[idx].target_residency; |
314 | state->flags = CPUIDLE_FLAG_TIME_VALID; | 328 | state->flags = CPUIDLE_FLAG_TIME_VALID; |
315 | state->enter = omap3_enter_idle_bm; | 329 | state->enter = omap3_enter_idle_bm; |
316 | cx->valid = cpuidle_params_table[idx].valid; | ||
317 | sprintf(state->name, "C%d", idx + 1); | 330 | sprintf(state->name, "C%d", idx + 1); |
318 | strncpy(state->desc, descr, CPUIDLE_DESC_LEN); | 331 | strncpy(state->desc, descr, CPUIDLE_DESC_LEN); |
319 | cpuidle_set_statedata(state, cx); | 332 | |
333 | } | ||
334 | |||
335 | /* Helper to register the driver_data */ | ||
336 | static inline struct omap3_idle_statedata *_fill_cstate_usage( | ||
337 | struct cpuidle_device *dev, | ||
338 | int idx) | ||
339 | { | ||
340 | struct omap3_idle_statedata *cx = &omap3_idle_data[idx]; | ||
341 | struct cpuidle_state_usage *state_usage = &dev->states_usage[idx]; | ||
342 | |||
343 | cx->valid = cpuidle_params_table[idx].valid; | ||
344 | cpuidle_set_statedata(state_usage, cx); | ||
320 | 345 | ||
321 | return cx; | 346 | return cx; |
322 | } | 347 | } |
@@ -330,6 +355,7 @@ static inline struct omap3_idle_statedata *_fill_cstate( | |||
330 | int __init omap3_idle_init(void) | 355 | int __init omap3_idle_init(void) |
331 | { | 356 | { |
332 | struct cpuidle_device *dev; | 357 | struct cpuidle_device *dev; |
358 | struct cpuidle_driver *drv = &omap3_idle_driver; | ||
333 | struct omap3_idle_statedata *cx; | 359 | struct omap3_idle_statedata *cx; |
334 | 360 | ||
335 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); | 361 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); |
@@ -337,44 +363,52 @@ int __init omap3_idle_init(void) | |||
337 | per_pd = pwrdm_lookup("per_pwrdm"); | 363 | per_pd = pwrdm_lookup("per_pwrdm"); |
338 | cam_pd = pwrdm_lookup("cam_pwrdm"); | 364 | cam_pd = pwrdm_lookup("cam_pwrdm"); |
339 | 365 | ||
340 | cpuidle_register_driver(&omap3_idle_driver); | 366 | |
367 | drv->safe_state_index = -1; | ||
341 | dev = &per_cpu(omap3_idle_dev, smp_processor_id()); | 368 | dev = &per_cpu(omap3_idle_dev, smp_processor_id()); |
342 | 369 | ||
343 | /* C1 . MPU WFI + Core active */ | 370 | /* C1 . MPU WFI + Core active */ |
344 | cx = _fill_cstate(dev, 0, "MPU ON + CORE ON"); | 371 | _fill_cstate(drv, 0, "MPU ON + CORE ON"); |
345 | (&dev->states[0])->enter = omap3_enter_idle; | 372 | (&drv->states[0])->enter = omap3_enter_idle; |
346 | dev->safe_state = &dev->states[0]; | 373 | drv->safe_state_index = 0; |
374 | cx = _fill_cstate_usage(dev, 0); | ||
347 | cx->valid = 1; /* C1 is always valid */ | 375 | cx->valid = 1; /* C1 is always valid */ |
348 | cx->mpu_state = PWRDM_POWER_ON; | 376 | cx->mpu_state = PWRDM_POWER_ON; |
349 | cx->core_state = PWRDM_POWER_ON; | 377 | cx->core_state = PWRDM_POWER_ON; |
350 | 378 | ||
351 | /* C2 . MPU WFI + Core inactive */ | 379 | /* C2 . MPU WFI + Core inactive */ |
352 | cx = _fill_cstate(dev, 1, "MPU ON + CORE ON"); | 380 | _fill_cstate(drv, 1, "MPU ON + CORE ON"); |
381 | cx = _fill_cstate_usage(dev, 1); | ||
353 | cx->mpu_state = PWRDM_POWER_ON; | 382 | cx->mpu_state = PWRDM_POWER_ON; |
354 | cx->core_state = PWRDM_POWER_ON; | 383 | cx->core_state = PWRDM_POWER_ON; |
355 | 384 | ||
356 | /* C3 . MPU CSWR + Core inactive */ | 385 | /* C3 . MPU CSWR + Core inactive */ |
357 | cx = _fill_cstate(dev, 2, "MPU RET + CORE ON"); | 386 | _fill_cstate(drv, 2, "MPU RET + CORE ON"); |
387 | cx = _fill_cstate_usage(dev, 2); | ||
358 | cx->mpu_state = PWRDM_POWER_RET; | 388 | cx->mpu_state = PWRDM_POWER_RET; |
359 | cx->core_state = PWRDM_POWER_ON; | 389 | cx->core_state = PWRDM_POWER_ON; |
360 | 390 | ||
361 | /* C4 . MPU OFF + Core inactive */ | 391 | /* C4 . MPU OFF + Core inactive */ |
362 | cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON"); | 392 | _fill_cstate(drv, 3, "MPU OFF + CORE ON"); |
393 | cx = _fill_cstate_usage(dev, 3); | ||
363 | cx->mpu_state = PWRDM_POWER_OFF; | 394 | cx->mpu_state = PWRDM_POWER_OFF; |
364 | cx->core_state = PWRDM_POWER_ON; | 395 | cx->core_state = PWRDM_POWER_ON; |
365 | 396 | ||
366 | /* C5 . MPU RET + Core RET */ | 397 | /* C5 . MPU RET + Core RET */ |
367 | cx = _fill_cstate(dev, 4, "MPU RET + CORE RET"); | 398 | _fill_cstate(drv, 4, "MPU RET + CORE RET"); |
399 | cx = _fill_cstate_usage(dev, 4); | ||
368 | cx->mpu_state = PWRDM_POWER_RET; | 400 | cx->mpu_state = PWRDM_POWER_RET; |
369 | cx->core_state = PWRDM_POWER_RET; | 401 | cx->core_state = PWRDM_POWER_RET; |
370 | 402 | ||
371 | /* C6 . MPU OFF + Core RET */ | 403 | /* C6 . MPU OFF + Core RET */ |
372 | cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET"); | 404 | _fill_cstate(drv, 5, "MPU OFF + CORE RET"); |
405 | cx = _fill_cstate_usage(dev, 5); | ||
373 | cx->mpu_state = PWRDM_POWER_OFF; | 406 | cx->mpu_state = PWRDM_POWER_OFF; |
374 | cx->core_state = PWRDM_POWER_RET; | 407 | cx->core_state = PWRDM_POWER_RET; |
375 | 408 | ||
376 | /* C7 . MPU OFF + Core OFF */ | 409 | /* C7 . MPU OFF + Core OFF */ |
377 | cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF"); | 410 | _fill_cstate(drv, 6, "MPU OFF + CORE OFF"); |
411 | cx = _fill_cstate_usage(dev, 6); | ||
378 | /* | 412 | /* |
379 | * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot | 413 | * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot |
380 | * enable OFF mode in a stable form for previous revisions. | 414 | * enable OFF mode in a stable form for previous revisions. |
@@ -388,6 +422,9 @@ int __init omap3_idle_init(void) | |||
388 | cx->mpu_state = PWRDM_POWER_OFF; | 422 | cx->mpu_state = PWRDM_POWER_OFF; |
389 | cx->core_state = PWRDM_POWER_OFF; | 423 | cx->core_state = PWRDM_POWER_OFF; |
390 | 424 | ||
425 | drv->state_count = OMAP3_NUM_STATES; | ||
426 | cpuidle_register_driver(&omap3_idle_driver); | ||
427 | |||
391 | dev->state_count = OMAP3_NUM_STATES; | 428 | dev->state_count = OMAP3_NUM_STATES; |
392 | if (cpuidle_register_device(dev)) { | 429 | if (cpuidle_register_device(dev)) { |
393 | printk(KERN_ERR "%s: CPUidle register device failed\n", | 430 | printk(KERN_ERR "%s: CPUidle register device failed\n", |