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