diff options
author | Tony Lindgren <tony@atomide.com> | 2013-01-30 17:03:05 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2013-01-30 17:03:05 -0500 |
commit | 0e084c9c843320995b0e219f02880f910d439b37 (patch) | |
tree | fe541c1d636f9666104f7753d0435c4681685ef9 /arch/arm | |
parent | 7b4bc07991564dfcdfd9e6e7cbebc9bf337111eb (diff) | |
parent | 562e54d13b6e0b17f72c9e629e1fd0b71e2a8a36 (diff) |
Merge tag 'omap-cleanup-b-for-3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into omap-for-v3.9/pm
Several OMAP2+ power management fixes, optimizations, and cleanup.
This series is a prerequisite for the functional powerdomain
conversion series.
Basic test logs for this branch are here:
http://www.pwsan.com/omap/testlogs/pm_cleanup_fixes_3.9/20130129150017/
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 569 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.h | 17 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cm2xxx.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cm3xxx.c | 14 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cminst44xx.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 79 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-mpuss-lowpower.c | 44 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm-debug.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 65 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm24xx.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.c | 232 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.h | 52 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomains2xxx_data.c | 9 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomains3xxx_data.c | 44 | ||||
-rw-r--r-- | arch/arm/mach-omap2/prm2xxx_3xxx.c | 3 |
17 files changed, 710 insertions, 494 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index 7faf82d4e85c..2da3b5ec010c 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c | |||
@@ -92,8 +92,6 @@ static int _clkdm_register(struct clockdomain *clkdm) | |||
92 | 92 | ||
93 | pwrdm_add_clkdm(pwrdm, clkdm); | 93 | pwrdm_add_clkdm(pwrdm, clkdm); |
94 | 94 | ||
95 | spin_lock_init(&clkdm->lock); | ||
96 | |||
97 | pr_debug("clockdomain: registered %s\n", clkdm->name); | 95 | pr_debug("clockdomain: registered %s\n", clkdm->name); |
98 | 96 | ||
99 | return 0; | 97 | return 0; |
@@ -122,7 +120,7 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, | |||
122 | return cd; | 120 | return cd; |
123 | } | 121 | } |
124 | 122 | ||
125 | /* | 123 | /** |
126 | * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store | 124 | * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store |
127 | * @autodep: struct clkdm_autodep * to resolve | 125 | * @autodep: struct clkdm_autodep * to resolve |
128 | * | 126 | * |
@@ -154,88 +152,206 @@ static void _autodep_lookup(struct clkdm_autodep *autodep) | |||
154 | autodep->clkdm.ptr = clkdm; | 152 | autodep->clkdm.ptr = clkdm; |
155 | } | 153 | } |
156 | 154 | ||
157 | /* | 155 | /** |
158 | * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable | 156 | * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms |
159 | * @clkdm: struct clockdomain * | 157 | * @clkdm: clockdomain that we are resolving dependencies for |
158 | * @clkdm_deps: ptr to array of struct clkdm_deps to resolve | ||
160 | * | 159 | * |
161 | * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' | 160 | * Iterates through @clkdm_deps, looking up the struct clockdomain named by |
162 | * in hardware-supervised mode. Meant to be called from clock framework | 161 | * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. |
163 | * when a clock inside clockdomain 'clkdm' is enabled. No return value. | 162 | * No return value. |
163 | */ | ||
164 | static void _resolve_clkdm_deps(struct clockdomain *clkdm, | ||
165 | struct clkdm_dep *clkdm_deps) | ||
166 | { | ||
167 | struct clkdm_dep *cd; | ||
168 | |||
169 | for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { | ||
170 | if (cd->clkdm) | ||
171 | continue; | ||
172 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); | ||
173 | |||
174 | WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", | ||
175 | clkdm->name, cd->clkdm_name); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless) | ||
181 | * @clkdm1: wake this struct clockdomain * up (dependent) | ||
182 | * @clkdm2: when this struct clockdomain * wakes up (source) | ||
164 | * | 183 | * |
165 | * XXX autodeps are deprecated and should be removed at the earliest | 184 | * When the clockdomain represented by @clkdm2 wakes up, wake up |
166 | * opportunity | 185 | * @clkdm1. Implemented in hardware on the OMAP, this feature is |
186 | * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. | ||
187 | * Returns -EINVAL if presented with invalid clockdomain pointers, | ||
188 | * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon | ||
189 | * success. | ||
167 | */ | 190 | */ |
168 | void _clkdm_add_autodeps(struct clockdomain *clkdm) | 191 | static int _clkdm_add_wkdep(struct clockdomain *clkdm1, |
192 | struct clockdomain *clkdm2) | ||
169 | { | 193 | { |
170 | struct clkdm_autodep *autodep; | 194 | struct clkdm_dep *cd; |
195 | int ret = 0; | ||
171 | 196 | ||
172 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) | 197 | if (!clkdm1 || !clkdm2) |
173 | return; | 198 | return -EINVAL; |
174 | 199 | ||
175 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | 200 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
176 | if (IS_ERR(autodep->clkdm.ptr)) | 201 | if (IS_ERR(cd)) |
177 | continue; | 202 | ret = PTR_ERR(cd); |
178 | 203 | ||
179 | pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", | 204 | if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) |
180 | clkdm->name, autodep->clkdm.ptr->name); | 205 | ret = -EINVAL; |
206 | |||
207 | if (ret) { | ||
208 | pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", | ||
209 | clkdm1->name, clkdm2->name); | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | cd->wkdep_usecount++; | ||
214 | if (cd->wkdep_usecount == 1) { | ||
215 | pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", | ||
216 | clkdm1->name, clkdm2->name); | ||
181 | 217 | ||
182 | clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); | 218 | ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); |
183 | clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); | ||
184 | } | 219 | } |
220 | |||
221 | return ret; | ||
185 | } | 222 | } |
186 | 223 | ||
187 | /* | 224 | /** |
188 | * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm | 225 | * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless) |
189 | * @clkdm: struct clockdomain * | 226 | * @clkdm1: wake this struct clockdomain * up (dependent) |
227 | * @clkdm2: when this struct clockdomain * wakes up (source) | ||
190 | * | 228 | * |
191 | * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' | 229 | * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 |
192 | * in hardware-supervised mode. Meant to be called from clock framework | 230 | * wakes up. Returns -EINVAL if presented with invalid clockdomain |
193 | * when a clock inside clockdomain 'clkdm' is disabled. No return value. | 231 | * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or |
232 | * 0 upon success. | ||
233 | */ | ||
234 | static int _clkdm_del_wkdep(struct clockdomain *clkdm1, | ||
235 | struct clockdomain *clkdm2) | ||
236 | { | ||
237 | struct clkdm_dep *cd; | ||
238 | int ret = 0; | ||
239 | |||
240 | if (!clkdm1 || !clkdm2) | ||
241 | return -EINVAL; | ||
242 | |||
243 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | ||
244 | if (IS_ERR(cd)) | ||
245 | ret = PTR_ERR(cd); | ||
246 | |||
247 | if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) | ||
248 | ret = -EINVAL; | ||
249 | |||
250 | if (ret) { | ||
251 | pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", | ||
252 | clkdm1->name, clkdm2->name); | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | cd->wkdep_usecount--; | ||
257 | if (cd->wkdep_usecount == 0) { | ||
258 | pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", | ||
259 | clkdm1->name, clkdm2->name); | ||
260 | |||
261 | ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); | ||
262 | } | ||
263 | |||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless) | ||
269 | * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) | ||
270 | * @clkdm2: when this struct clockdomain * is active (source) | ||
194 | * | 271 | * |
195 | * XXX autodeps are deprecated and should be removed at the earliest | 272 | * Prevent @clkdm1 from automatically going inactive (and then to |
196 | * opportunity | 273 | * retention or off) if @clkdm2 is active. Returns -EINVAL if |
274 | * presented with invalid clockdomain pointers or called on a machine | ||
275 | * that does not support software-configurable hardware sleep | ||
276 | * dependencies, -ENOENT if the specified dependency cannot be set in | ||
277 | * hardware, or 0 upon success. | ||
197 | */ | 278 | */ |
198 | void _clkdm_del_autodeps(struct clockdomain *clkdm) | 279 | static int _clkdm_add_sleepdep(struct clockdomain *clkdm1, |
280 | struct clockdomain *clkdm2) | ||
199 | { | 281 | { |
200 | struct clkdm_autodep *autodep; | 282 | struct clkdm_dep *cd; |
283 | int ret = 0; | ||
201 | 284 | ||
202 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) | 285 | if (!clkdm1 || !clkdm2) |
203 | return; | 286 | return -EINVAL; |
204 | 287 | ||
205 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | 288 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
206 | if (IS_ERR(autodep->clkdm.ptr)) | 289 | if (IS_ERR(cd)) |
207 | continue; | 290 | ret = PTR_ERR(cd); |
208 | 291 | ||
209 | pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", | 292 | if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) |
210 | clkdm->name, autodep->clkdm.ptr->name); | 293 | ret = -EINVAL; |
211 | 294 | ||
212 | clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); | 295 | if (ret) { |
213 | clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); | 296 | pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", |
297 | clkdm1->name, clkdm2->name); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | cd->sleepdep_usecount++; | ||
302 | if (cd->sleepdep_usecount == 1) { | ||
303 | pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", | ||
304 | clkdm1->name, clkdm2->name); | ||
305 | |||
306 | ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); | ||
214 | } | 307 | } |
308 | |||
309 | return ret; | ||
215 | } | 310 | } |
216 | 311 | ||
217 | /** | 312 | /** |
218 | * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms | 313 | * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless) |
219 | * @clkdm: clockdomain that we are resolving dependencies for | 314 | * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) |
220 | * @clkdm_deps: ptr to array of struct clkdm_deps to resolve | 315 | * @clkdm2: when this struct clockdomain * is active (source) |
221 | * | 316 | * |
222 | * Iterates through @clkdm_deps, looking up the struct clockdomain named by | 317 | * Allow @clkdm1 to automatically go inactive (and then to retention or |
223 | * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. | 318 | * off), independent of the activity state of @clkdm2. Returns -EINVAL |
224 | * No return value. | 319 | * if presented with invalid clockdomain pointers or called on a machine |
320 | * that does not support software-configurable hardware sleep dependencies, | ||
321 | * -ENOENT if the specified dependency cannot be cleared in hardware, or | ||
322 | * 0 upon success. | ||
225 | */ | 323 | */ |
226 | static void _resolve_clkdm_deps(struct clockdomain *clkdm, | 324 | static int _clkdm_del_sleepdep(struct clockdomain *clkdm1, |
227 | struct clkdm_dep *clkdm_deps) | 325 | struct clockdomain *clkdm2) |
228 | { | 326 | { |
229 | struct clkdm_dep *cd; | 327 | struct clkdm_dep *cd; |
328 | int ret = 0; | ||
230 | 329 | ||
231 | for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { | 330 | if (!clkdm1 || !clkdm2) |
232 | if (cd->clkdm) | 331 | return -EINVAL; |
233 | continue; | ||
234 | cd->clkdm = _clkdm_lookup(cd->clkdm_name); | ||
235 | 332 | ||
236 | WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", | 333 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); |
237 | clkdm->name, cd->clkdm_name); | 334 | if (IS_ERR(cd)) |
335 | ret = PTR_ERR(cd); | ||
336 | |||
337 | if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) | ||
338 | ret = -EINVAL; | ||
339 | |||
340 | if (ret) { | ||
341 | pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", | ||
342 | clkdm1->name, clkdm2->name); | ||
343 | return ret; | ||
238 | } | 344 | } |
345 | |||
346 | cd->sleepdep_usecount--; | ||
347 | if (cd->sleepdep_usecount == 0) { | ||
348 | pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", | ||
349 | clkdm1->name, clkdm2->name); | ||
350 | |||
351 | ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); | ||
352 | } | ||
353 | |||
354 | return ret; | ||
239 | } | 355 | } |
240 | 356 | ||
241 | /* Public functions */ | 357 | /* Public functions */ |
@@ -456,30 +572,18 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) | |||
456 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 572 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
457 | { | 573 | { |
458 | struct clkdm_dep *cd; | 574 | struct clkdm_dep *cd; |
459 | int ret = 0; | 575 | int ret; |
460 | 576 | ||
461 | if (!clkdm1 || !clkdm2) | 577 | if (!clkdm1 || !clkdm2) |
462 | return -EINVAL; | 578 | return -EINVAL; |
463 | 579 | ||
464 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 580 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
465 | if (IS_ERR(cd)) | 581 | if (IS_ERR(cd)) |
466 | ret = PTR_ERR(cd); | 582 | return PTR_ERR(cd); |
467 | 583 | ||
468 | if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) | 584 | pwrdm_lock(cd->clkdm->pwrdm.ptr); |
469 | ret = -EINVAL; | 585 | ret = _clkdm_add_wkdep(clkdm1, clkdm2); |
470 | 586 | pwrdm_unlock(cd->clkdm->pwrdm.ptr); | |
471 | if (ret) { | ||
472 | pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", | ||
473 | clkdm1->name, clkdm2->name); | ||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | if (atomic_inc_return(&cd->wkdep_usecount) == 1) { | ||
478 | pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", | ||
479 | clkdm1->name, clkdm2->name); | ||
480 | |||
481 | ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); | ||
482 | } | ||
483 | 587 | ||
484 | return ret; | 588 | return ret; |
485 | } | 589 | } |
@@ -497,30 +601,18 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
497 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 601 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
498 | { | 602 | { |
499 | struct clkdm_dep *cd; | 603 | struct clkdm_dep *cd; |
500 | int ret = 0; | 604 | int ret; |
501 | 605 | ||
502 | if (!clkdm1 || !clkdm2) | 606 | if (!clkdm1 || !clkdm2) |
503 | return -EINVAL; | 607 | return -EINVAL; |
504 | 608 | ||
505 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); | 609 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
506 | if (IS_ERR(cd)) | 610 | if (IS_ERR(cd)) |
507 | ret = PTR_ERR(cd); | 611 | return PTR_ERR(cd); |
508 | 612 | ||
509 | if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) | 613 | pwrdm_lock(cd->clkdm->pwrdm.ptr); |
510 | ret = -EINVAL; | 614 | ret = _clkdm_del_wkdep(clkdm1, clkdm2); |
511 | 615 | pwrdm_unlock(cd->clkdm->pwrdm.ptr); | |
512 | if (ret) { | ||
513 | pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", | ||
514 | clkdm1->name, clkdm2->name); | ||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | if (atomic_dec_return(&cd->wkdep_usecount) == 0) { | ||
519 | pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", | ||
520 | clkdm1->name, clkdm2->name); | ||
521 | |||
522 | ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); | ||
523 | } | ||
524 | 616 | ||
525 | return ret; | 617 | return ret; |
526 | } | 618 | } |
@@ -560,7 +652,7 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
560 | return ret; | 652 | return ret; |
561 | } | 653 | } |
562 | 654 | ||
563 | /* XXX It's faster to return the atomic wkdep_usecount */ | 655 | /* XXX It's faster to return the wkdep_usecount */ |
564 | return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); | 656 | return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); |
565 | } | 657 | } |
566 | 658 | ||
@@ -600,30 +692,18 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | |||
600 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 692 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
601 | { | 693 | { |
602 | struct clkdm_dep *cd; | 694 | struct clkdm_dep *cd; |
603 | int ret = 0; | 695 | int ret; |
604 | 696 | ||
605 | if (!clkdm1 || !clkdm2) | 697 | if (!clkdm1 || !clkdm2) |
606 | return -EINVAL; | 698 | return -EINVAL; |
607 | 699 | ||
608 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 700 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
609 | if (IS_ERR(cd)) | 701 | if (IS_ERR(cd)) |
610 | ret = PTR_ERR(cd); | 702 | return PTR_ERR(cd); |
611 | 703 | ||
612 | if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) | 704 | pwrdm_lock(cd->clkdm->pwrdm.ptr); |
613 | ret = -EINVAL; | 705 | ret = _clkdm_add_sleepdep(clkdm1, clkdm2); |
614 | 706 | pwrdm_unlock(cd->clkdm->pwrdm.ptr); | |
615 | if (ret) { | ||
616 | pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", | ||
617 | clkdm1->name, clkdm2->name); | ||
618 | return ret; | ||
619 | } | ||
620 | |||
621 | if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { | ||
622 | pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", | ||
623 | clkdm1->name, clkdm2->name); | ||
624 | |||
625 | ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); | ||
626 | } | ||
627 | 707 | ||
628 | return ret; | 708 | return ret; |
629 | } | 709 | } |
@@ -643,30 +723,18 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
643 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 723 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) |
644 | { | 724 | { |
645 | struct clkdm_dep *cd; | 725 | struct clkdm_dep *cd; |
646 | int ret = 0; | 726 | int ret; |
647 | 727 | ||
648 | if (!clkdm1 || !clkdm2) | 728 | if (!clkdm1 || !clkdm2) |
649 | return -EINVAL; | 729 | return -EINVAL; |
650 | 730 | ||
651 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); | 731 | cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); |
652 | if (IS_ERR(cd)) | 732 | if (IS_ERR(cd)) |
653 | ret = PTR_ERR(cd); | 733 | return PTR_ERR(cd); |
654 | 734 | ||
655 | if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) | 735 | pwrdm_lock(cd->clkdm->pwrdm.ptr); |
656 | ret = -EINVAL; | 736 | ret = _clkdm_del_sleepdep(clkdm1, clkdm2); |
657 | 737 | pwrdm_unlock(cd->clkdm->pwrdm.ptr); | |
658 | if (ret) { | ||
659 | pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", | ||
660 | clkdm1->name, clkdm2->name); | ||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { | ||
665 | pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", | ||
666 | clkdm1->name, clkdm2->name); | ||
667 | |||
668 | ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); | ||
669 | } | ||
670 | 738 | ||
671 | return ret; | 739 | return ret; |
672 | } | 740 | } |
@@ -708,7 +776,7 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | |||
708 | return ret; | 776 | return ret; |
709 | } | 777 | } |
710 | 778 | ||
711 | /* XXX It's faster to return the atomic sleepdep_usecount */ | 779 | /* XXX It's faster to return the sleepdep_usecount */ |
712 | return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); | 780 | return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); |
713 | } | 781 | } |
714 | 782 | ||
@@ -734,18 +802,17 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | |||
734 | } | 802 | } |
735 | 803 | ||
736 | /** | 804 | /** |
737 | * clkdm_sleep - force clockdomain sleep transition | 805 | * clkdm_sleep_nolock - force clockdomain sleep transition (lockless) |
738 | * @clkdm: struct clockdomain * | 806 | * @clkdm: struct clockdomain * |
739 | * | 807 | * |
740 | * Instruct the CM to force a sleep transition on the specified | 808 | * Instruct the CM to force a sleep transition on the specified |
741 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if | 809 | * clockdomain @clkdm. Only for use by the powerdomain code. Returns |
742 | * clockdomain does not support software-initiated sleep; 0 upon | 810 | * -EINVAL if @clkdm is NULL or if clockdomain does not support |
743 | * success. | 811 | * software-initiated sleep; 0 upon success. |
744 | */ | 812 | */ |
745 | int clkdm_sleep(struct clockdomain *clkdm) | 813 | int clkdm_sleep_nolock(struct clockdomain *clkdm) |
746 | { | 814 | { |
747 | int ret; | 815 | int ret; |
748 | unsigned long flags; | ||
749 | 816 | ||
750 | if (!clkdm) | 817 | if (!clkdm) |
751 | return -EINVAL; | 818 | return -EINVAL; |
@@ -761,26 +828,45 @@ int clkdm_sleep(struct clockdomain *clkdm) | |||
761 | 828 | ||
762 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); | 829 | pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); |
763 | 830 | ||
764 | spin_lock_irqsave(&clkdm->lock, flags); | ||
765 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; | 831 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; |
766 | ret = arch_clkdm->clkdm_sleep(clkdm); | 832 | ret = arch_clkdm->clkdm_sleep(clkdm); |
767 | spin_unlock_irqrestore(&clkdm->lock, flags); | 833 | ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
834 | |||
768 | return ret; | 835 | return ret; |
769 | } | 836 | } |
770 | 837 | ||
771 | /** | 838 | /** |
772 | * clkdm_wakeup - force clockdomain wakeup transition | 839 | * clkdm_sleep - force clockdomain sleep transition |
773 | * @clkdm: struct clockdomain * | 840 | * @clkdm: struct clockdomain * |
774 | * | 841 | * |
775 | * Instruct the CM to force a wakeup transition on the specified | 842 | * Instruct the CM to force a sleep transition on the specified |
776 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the | 843 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if |
777 | * clockdomain does not support software-controlled wakeup; 0 upon | 844 | * clockdomain does not support software-initiated sleep; 0 upon |
778 | * success. | 845 | * success. |
779 | */ | 846 | */ |
780 | int clkdm_wakeup(struct clockdomain *clkdm) | 847 | int clkdm_sleep(struct clockdomain *clkdm) |
848 | { | ||
849 | int ret; | ||
850 | |||
851 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
852 | ret = clkdm_sleep_nolock(clkdm); | ||
853 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
854 | |||
855 | return ret; | ||
856 | } | ||
857 | |||
858 | /** | ||
859 | * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless) | ||
860 | * @clkdm: struct clockdomain * | ||
861 | * | ||
862 | * Instruct the CM to force a wakeup transition on the specified | ||
863 | * clockdomain @clkdm. Only for use by the powerdomain code. Returns | ||
864 | * -EINVAL if @clkdm is NULL or if the clockdomain does not support | ||
865 | * software-controlled wakeup; 0 upon success. | ||
866 | */ | ||
867 | int clkdm_wakeup_nolock(struct clockdomain *clkdm) | ||
781 | { | 868 | { |
782 | int ret; | 869 | int ret; |
783 | unsigned long flags; | ||
784 | 870 | ||
785 | if (!clkdm) | 871 | if (!clkdm) |
786 | return -EINVAL; | 872 | return -EINVAL; |
@@ -796,28 +882,46 @@ int clkdm_wakeup(struct clockdomain *clkdm) | |||
796 | 882 | ||
797 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); | 883 | pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); |
798 | 884 | ||
799 | spin_lock_irqsave(&clkdm->lock, flags); | ||
800 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; | 885 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; |
801 | ret = arch_clkdm->clkdm_wakeup(clkdm); | 886 | ret = arch_clkdm->clkdm_wakeup(clkdm); |
802 | ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); | 887 | ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
803 | spin_unlock_irqrestore(&clkdm->lock, flags); | 888 | |
804 | return ret; | 889 | return ret; |
805 | } | 890 | } |
806 | 891 | ||
807 | /** | 892 | /** |
808 | * clkdm_allow_idle - enable hwsup idle transitions for clkdm | 893 | * clkdm_wakeup - force clockdomain wakeup transition |
809 | * @clkdm: struct clockdomain * | 894 | * @clkdm: struct clockdomain * |
810 | * | 895 | * |
811 | * Allow the hardware to automatically switch the clockdomain @clkdm into | 896 | * Instruct the CM to force a wakeup transition on the specified |
812 | * active or idle states, as needed by downstream clocks. If the | 897 | * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the |
898 | * clockdomain does not support software-controlled wakeup; 0 upon | ||
899 | * success. | ||
900 | */ | ||
901 | int clkdm_wakeup(struct clockdomain *clkdm) | ||
902 | { | ||
903 | int ret; | ||
904 | |||
905 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
906 | ret = clkdm_wakeup_nolock(clkdm); | ||
907 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
908 | |||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | /** | ||
913 | * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm | ||
914 | * @clkdm: struct clockdomain * | ||
915 | * | ||
916 | * Allow the hardware to automatically switch the clockdomain @clkdm | ||
917 | * into active or idle states, as needed by downstream clocks. If the | ||
813 | * clockdomain has any downstream clocks enabled in the clock | 918 | * clockdomain has any downstream clocks enabled in the clock |
814 | * framework, wkdep/sleepdep autodependencies are added; this is so | 919 | * framework, wkdep/sleepdep autodependencies are added; this is so |
815 | * device drivers can read and write to the device. No return value. | 920 | * device drivers can read and write to the device. Only for use by |
921 | * the powerdomain code. No return value. | ||
816 | */ | 922 | */ |
817 | void clkdm_allow_idle(struct clockdomain *clkdm) | 923 | void clkdm_allow_idle_nolock(struct clockdomain *clkdm) |
818 | { | 924 | { |
819 | unsigned long flags; | ||
820 | |||
821 | if (!clkdm) | 925 | if (!clkdm) |
822 | return; | 926 | return; |
823 | 927 | ||
@@ -833,11 +937,26 @@ void clkdm_allow_idle(struct clockdomain *clkdm) | |||
833 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", | 937 | pr_debug("clockdomain: enabling automatic idle transitions for %s\n", |
834 | clkdm->name); | 938 | clkdm->name); |
835 | 939 | ||
836 | spin_lock_irqsave(&clkdm->lock, flags); | ||
837 | clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; | 940 | clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; |
838 | arch_clkdm->clkdm_allow_idle(clkdm); | 941 | arch_clkdm->clkdm_allow_idle(clkdm); |
839 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 942 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
840 | spin_unlock_irqrestore(&clkdm->lock, flags); | 943 | } |
944 | |||
945 | /** | ||
946 | * clkdm_allow_idle - enable hwsup idle transitions for clkdm | ||
947 | * @clkdm: struct clockdomain * | ||
948 | * | ||
949 | * Allow the hardware to automatically switch the clockdomain @clkdm into | ||
950 | * active or idle states, as needed by downstream clocks. If the | ||
951 | * clockdomain has any downstream clocks enabled in the clock | ||
952 | * framework, wkdep/sleepdep autodependencies are added; this is so | ||
953 | * device drivers can read and write to the device. No return value. | ||
954 | */ | ||
955 | void clkdm_allow_idle(struct clockdomain *clkdm) | ||
956 | { | ||
957 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
958 | clkdm_allow_idle_nolock(clkdm); | ||
959 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
841 | } | 960 | } |
842 | 961 | ||
843 | /** | 962 | /** |
@@ -847,12 +966,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm) | |||
847 | * Prevent the hardware from automatically switching the clockdomain | 966 | * Prevent the hardware from automatically switching the clockdomain |
848 | * @clkdm into inactive or idle states. If the clockdomain has | 967 | * @clkdm into inactive or idle states. If the clockdomain has |
849 | * downstream clocks enabled in the clock framework, wkdep/sleepdep | 968 | * downstream clocks enabled in the clock framework, wkdep/sleepdep |
850 | * autodependencies are removed. No return value. | 969 | * autodependencies are removed. Only for use by the powerdomain |
970 | * code. No return value. | ||
851 | */ | 971 | */ |
852 | void clkdm_deny_idle(struct clockdomain *clkdm) | 972 | void clkdm_deny_idle_nolock(struct clockdomain *clkdm) |
853 | { | 973 | { |
854 | unsigned long flags; | ||
855 | |||
856 | if (!clkdm) | 974 | if (!clkdm) |
857 | return; | 975 | return; |
858 | 976 | ||
@@ -868,11 +986,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm) | |||
868 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", | 986 | pr_debug("clockdomain: disabling automatic idle transitions for %s\n", |
869 | clkdm->name); | 987 | clkdm->name); |
870 | 988 | ||
871 | spin_lock_irqsave(&clkdm->lock, flags); | ||
872 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; | 989 | clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; |
873 | arch_clkdm->clkdm_deny_idle(clkdm); | 990 | arch_clkdm->clkdm_deny_idle(clkdm); |
874 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 991 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
875 | spin_unlock_irqrestore(&clkdm->lock, flags); | 992 | } |
993 | |||
994 | /** | ||
995 | * clkdm_deny_idle - disable hwsup idle transitions for clkdm | ||
996 | * @clkdm: struct clockdomain * | ||
997 | * | ||
998 | * Prevent the hardware from automatically switching the clockdomain | ||
999 | * @clkdm into inactive or idle states. If the clockdomain has | ||
1000 | * downstream clocks enabled in the clock framework, wkdep/sleepdep | ||
1001 | * autodependencies are removed. No return value. | ||
1002 | */ | ||
1003 | void clkdm_deny_idle(struct clockdomain *clkdm) | ||
1004 | { | ||
1005 | pwrdm_lock(clkdm->pwrdm.ptr); | ||
1006 | clkdm_deny_idle_nolock(clkdm); | ||
1007 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
876 | } | 1008 | } |
877 | 1009 | ||
878 | /** | 1010 | /** |
@@ -889,14 +1021,11 @@ void clkdm_deny_idle(struct clockdomain *clkdm) | |||
889 | bool clkdm_in_hwsup(struct clockdomain *clkdm) | 1021 | bool clkdm_in_hwsup(struct clockdomain *clkdm) |
890 | { | 1022 | { |
891 | bool ret; | 1023 | bool ret; |
892 | unsigned long flags; | ||
893 | 1024 | ||
894 | if (!clkdm) | 1025 | if (!clkdm) |
895 | return false; | 1026 | return false; |
896 | 1027 | ||
897 | spin_lock_irqsave(&clkdm->lock, flags); | ||
898 | ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; | 1028 | ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; |
899 | spin_unlock_irqrestore(&clkdm->lock, flags); | ||
900 | 1029 | ||
901 | return ret; | 1030 | return ret; |
902 | } | 1031 | } |
@@ -918,30 +1047,91 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm) | |||
918 | return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false; | 1047 | return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false; |
919 | } | 1048 | } |
920 | 1049 | ||
1050 | /* Public autodep handling functions (deprecated) */ | ||
1051 | |||
1052 | /** | ||
1053 | * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable | ||
1054 | * @clkdm: struct clockdomain * | ||
1055 | * | ||
1056 | * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' | ||
1057 | * in hardware-supervised mode. Meant to be called from clock framework | ||
1058 | * when a clock inside clockdomain 'clkdm' is enabled. No return value. | ||
1059 | * | ||
1060 | * XXX autodeps are deprecated and should be removed at the earliest | ||
1061 | * opportunity | ||
1062 | */ | ||
1063 | void clkdm_add_autodeps(struct clockdomain *clkdm) | ||
1064 | { | ||
1065 | struct clkdm_autodep *autodep; | ||
1066 | |||
1067 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) | ||
1068 | return; | ||
1069 | |||
1070 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | ||
1071 | if (IS_ERR(autodep->clkdm.ptr)) | ||
1072 | continue; | ||
1073 | |||
1074 | pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", | ||
1075 | clkdm->name, autodep->clkdm.ptr->name); | ||
1076 | |||
1077 | _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); | ||
1078 | _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | /** | ||
1083 | * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm | ||
1084 | * @clkdm: struct clockdomain * | ||
1085 | * | ||
1086 | * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' | ||
1087 | * in hardware-supervised mode. Meant to be called from clock framework | ||
1088 | * when a clock inside clockdomain 'clkdm' is disabled. No return value. | ||
1089 | * | ||
1090 | * XXX autodeps are deprecated and should be removed at the earliest | ||
1091 | * opportunity | ||
1092 | */ | ||
1093 | void clkdm_del_autodeps(struct clockdomain *clkdm) | ||
1094 | { | ||
1095 | struct clkdm_autodep *autodep; | ||
1096 | |||
1097 | if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) | ||
1098 | return; | ||
1099 | |||
1100 | for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { | ||
1101 | if (IS_ERR(autodep->clkdm.ptr)) | ||
1102 | continue; | ||
1103 | |||
1104 | pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", | ||
1105 | clkdm->name, autodep->clkdm.ptr->name); | ||
1106 | |||
1107 | _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); | ||
1108 | _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); | ||
1109 | } | ||
1110 | } | ||
1111 | |||
921 | /* Clockdomain-to-clock/hwmod framework interface code */ | 1112 | /* Clockdomain-to-clock/hwmod framework interface code */ |
922 | 1113 | ||
923 | static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) | 1114 | static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) |
924 | { | 1115 | { |
925 | unsigned long flags; | ||
926 | |||
927 | if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) | 1116 | if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) |
928 | return -EINVAL; | 1117 | return -EINVAL; |
929 | 1118 | ||
930 | spin_lock_irqsave(&clkdm->lock, flags); | 1119 | pwrdm_lock(clkdm->pwrdm.ptr); |
931 | 1120 | ||
932 | /* | 1121 | /* |
933 | * For arch's with no autodeps, clkcm_clk_enable | 1122 | * For arch's with no autodeps, clkcm_clk_enable |
934 | * should be called for every clock instance or hwmod that is | 1123 | * should be called for every clock instance or hwmod that is |
935 | * enabled, so the clkdm can be force woken up. | 1124 | * enabled, so the clkdm can be force woken up. |
936 | */ | 1125 | */ |
937 | if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { | 1126 | clkdm->usecount++; |
938 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1127 | if (clkdm->usecount > 1 && autodeps) { |
1128 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
939 | return 0; | 1129 | return 0; |
940 | } | 1130 | } |
941 | 1131 | ||
942 | arch_clkdm->clkdm_clk_enable(clkdm); | 1132 | arch_clkdm->clkdm_clk_enable(clkdm); |
943 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 1133 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
944 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1134 | pwrdm_unlock(clkdm->pwrdm.ptr); |
945 | 1135 | ||
946 | pr_debug("clockdomain: %s: enabled\n", clkdm->name); | 1136 | pr_debug("clockdomain: %s: enabled\n", clkdm->name); |
947 | 1137 | ||
@@ -990,36 +1180,34 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) | |||
990 | */ | 1180 | */ |
991 | int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) | 1181 | int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) |
992 | { | 1182 | { |
993 | unsigned long flags; | ||
994 | |||
995 | if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) | 1183 | if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) |
996 | return -EINVAL; | 1184 | return -EINVAL; |
997 | 1185 | ||
998 | spin_lock_irqsave(&clkdm->lock, flags); | 1186 | pwrdm_lock(clkdm->pwrdm.ptr); |
999 | 1187 | ||
1000 | /* corner case: disabling unused clocks */ | 1188 | /* corner case: disabling unused clocks */ |
1001 | if ((__clk_get_enable_count(clk) == 0) && | 1189 | if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0) |
1002 | (atomic_read(&clkdm->usecount) == 0)) | ||
1003 | goto ccd_exit; | 1190 | goto ccd_exit; |
1004 | 1191 | ||
1005 | if (atomic_read(&clkdm->usecount) == 0) { | 1192 | if (clkdm->usecount == 0) { |
1006 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1193 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1007 | WARN_ON(1); /* underflow */ | 1194 | WARN_ON(1); /* underflow */ |
1008 | return -ERANGE; | 1195 | return -ERANGE; |
1009 | } | 1196 | } |
1010 | 1197 | ||
1011 | if (atomic_dec_return(&clkdm->usecount) > 0) { | 1198 | clkdm->usecount--; |
1012 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1199 | if (clkdm->usecount > 0) { |
1200 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
1013 | return 0; | 1201 | return 0; |
1014 | } | 1202 | } |
1015 | 1203 | ||
1016 | arch_clkdm->clkdm_clk_disable(clkdm); | 1204 | arch_clkdm->clkdm_clk_disable(clkdm); |
1017 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 1205 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
1018 | 1206 | ||
1019 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); | 1207 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); |
1020 | 1208 | ||
1021 | ccd_exit: | 1209 | ccd_exit: |
1022 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1210 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1023 | 1211 | ||
1024 | return 0; | 1212 | return 0; |
1025 | } | 1213 | } |
@@ -1072,8 +1260,6 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh) | |||
1072 | */ | 1260 | */ |
1073 | int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) | 1261 | int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) |
1074 | { | 1262 | { |
1075 | unsigned long flags; | ||
1076 | |||
1077 | /* The clkdm attribute does not exist yet prior OMAP4 */ | 1263 | /* The clkdm attribute does not exist yet prior OMAP4 */ |
1078 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | 1264 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) |
1079 | return 0; | 1265 | return 0; |
@@ -1086,22 +1272,23 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) | |||
1086 | if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) | 1272 | if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) |
1087 | return -EINVAL; | 1273 | return -EINVAL; |
1088 | 1274 | ||
1089 | spin_lock_irqsave(&clkdm->lock, flags); | 1275 | pwrdm_lock(clkdm->pwrdm.ptr); |
1090 | 1276 | ||
1091 | if (atomic_read(&clkdm->usecount) == 0) { | 1277 | if (clkdm->usecount == 0) { |
1092 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1278 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1093 | WARN_ON(1); /* underflow */ | 1279 | WARN_ON(1); /* underflow */ |
1094 | return -ERANGE; | 1280 | return -ERANGE; |
1095 | } | 1281 | } |
1096 | 1282 | ||
1097 | if (atomic_dec_return(&clkdm->usecount) > 0) { | 1283 | clkdm->usecount--; |
1098 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1284 | if (clkdm->usecount > 0) { |
1285 | pwrdm_unlock(clkdm->pwrdm.ptr); | ||
1099 | return 0; | 1286 | return 0; |
1100 | } | 1287 | } |
1101 | 1288 | ||
1102 | arch_clkdm->clkdm_clk_disable(clkdm); | 1289 | arch_clkdm->clkdm_clk_disable(clkdm); |
1103 | pwrdm_state_switch(clkdm->pwrdm.ptr); | 1290 | pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); |
1104 | spin_unlock_irqrestore(&clkdm->lock, flags); | 1291 | pwrdm_unlock(clkdm->pwrdm.ptr); |
1105 | 1292 | ||
1106 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); | 1293 | pr_debug("clockdomain: %s: disabled\n", clkdm->name); |
1107 | 1294 | ||
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index bc42446e23ab..2da37656a693 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h | |||
@@ -15,7 +15,6 @@ | |||
15 | #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H | 15 | #define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H |
16 | 16 | ||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/spinlock.h> | ||
19 | 18 | ||
20 | #include "powerdomain.h" | 19 | #include "powerdomain.h" |
21 | #include "clock.h" | 20 | #include "clock.h" |
@@ -92,8 +91,8 @@ struct clkdm_autodep { | |||
92 | struct clkdm_dep { | 91 | struct clkdm_dep { |
93 | const char *clkdm_name; | 92 | const char *clkdm_name; |
94 | struct clockdomain *clkdm; | 93 | struct clockdomain *clkdm; |
95 | atomic_t wkdep_usecount; | 94 | s16 wkdep_usecount; |
96 | atomic_t sleepdep_usecount; | 95 | s16 sleepdep_usecount; |
97 | }; | 96 | }; |
98 | 97 | ||
99 | /* Possible flags for struct clockdomain._flags */ | 98 | /* Possible flags for struct clockdomain._flags */ |
@@ -137,9 +136,8 @@ struct clockdomain { | |||
137 | const u16 clkdm_offs; | 136 | const u16 clkdm_offs; |
138 | struct clkdm_dep *wkdep_srcs; | 137 | struct clkdm_dep *wkdep_srcs; |
139 | struct clkdm_dep *sleepdep_srcs; | 138 | struct clkdm_dep *sleepdep_srcs; |
140 | atomic_t usecount; | 139 | int usecount; |
141 | struct list_head node; | 140 | struct list_head node; |
142 | spinlock_t lock; | ||
143 | }; | 141 | }; |
144 | 142 | ||
145 | /** | 143 | /** |
@@ -196,12 +194,16 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); | |||
196 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); | 194 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); |
197 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); | 195 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); |
198 | 196 | ||
197 | void clkdm_allow_idle_nolock(struct clockdomain *clkdm); | ||
199 | void clkdm_allow_idle(struct clockdomain *clkdm); | 198 | void clkdm_allow_idle(struct clockdomain *clkdm); |
199 | void clkdm_deny_idle_nolock(struct clockdomain *clkdm); | ||
200 | void clkdm_deny_idle(struct clockdomain *clkdm); | 200 | void clkdm_deny_idle(struct clockdomain *clkdm); |
201 | bool clkdm_in_hwsup(struct clockdomain *clkdm); | 201 | bool clkdm_in_hwsup(struct clockdomain *clkdm); |
202 | bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); | 202 | bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); |
203 | 203 | ||
204 | int clkdm_wakeup_nolock(struct clockdomain *clkdm); | ||
204 | int clkdm_wakeup(struct clockdomain *clkdm); | 205 | int clkdm_wakeup(struct clockdomain *clkdm); |
206 | int clkdm_sleep_nolock(struct clockdomain *clkdm); | ||
205 | int clkdm_sleep(struct clockdomain *clkdm); | 207 | int clkdm_sleep(struct clockdomain *clkdm); |
206 | 208 | ||
207 | int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); | 209 | int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); |
@@ -214,8 +216,9 @@ extern void __init omap243x_clockdomains_init(void); | |||
214 | extern void __init omap3xxx_clockdomains_init(void); | 216 | extern void __init omap3xxx_clockdomains_init(void); |
215 | extern void __init am33xx_clockdomains_init(void); | 217 | extern void __init am33xx_clockdomains_init(void); |
216 | extern void __init omap44xx_clockdomains_init(void); | 218 | extern void __init omap44xx_clockdomains_init(void); |
217 | extern void _clkdm_add_autodeps(struct clockdomain *clkdm); | 219 | |
218 | extern void _clkdm_del_autodeps(struct clockdomain *clkdm); | 220 | extern void clkdm_add_autodeps(struct clockdomain *clkdm); |
221 | extern void clkdm_del_autodeps(struct clockdomain *clkdm); | ||
219 | 222 | ||
220 | extern struct clkdm_ops omap2_clkdm_operations; | 223 | extern struct clkdm_ops omap2_clkdm_operations; |
221 | extern struct clkdm_ops omap3_clkdm_operations; | 224 | extern struct clkdm_ops omap3_clkdm_operations; |
diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c index db650690e9d0..6774a53a3874 100644 --- a/arch/arm/mach-omap2/cm2xxx.c +++ b/arch/arm/mach-omap2/cm2xxx.c | |||
@@ -273,9 +273,6 @@ int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift) | |||
273 | 273 | ||
274 | static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm) | 274 | static void omap2xxx_clkdm_allow_idle(struct clockdomain *clkdm) |
275 | { | 275 | { |
276 | if (atomic_read(&clkdm->usecount) > 0) | ||
277 | _clkdm_add_autodeps(clkdm); | ||
278 | |||
279 | omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 276 | omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
280 | clkdm->clktrctrl_mask); | 277 | clkdm->clktrctrl_mask); |
281 | } | 278 | } |
@@ -284,9 +281,6 @@ static void omap2xxx_clkdm_deny_idle(struct clockdomain *clkdm) | |||
284 | { | 281 | { |
285 | omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 282 | omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
286 | clkdm->clktrctrl_mask); | 283 | clkdm->clktrctrl_mask); |
287 | |||
288 | if (atomic_read(&clkdm->usecount) > 0) | ||
289 | _clkdm_del_autodeps(clkdm); | ||
290 | } | 284 | } |
291 | 285 | ||
292 | static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) | 286 | static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) |
@@ -298,18 +292,8 @@ static int omap2xxx_clkdm_clk_enable(struct clockdomain *clkdm) | |||
298 | 292 | ||
299 | hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 293 | hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
300 | clkdm->clktrctrl_mask); | 294 | clkdm->clktrctrl_mask); |
301 | 295 | if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) | |
302 | if (hwsup) { | 296 | omap2xxx_clkdm_wakeup(clkdm); |
303 | /* Disable HW transitions when we are changing deps */ | ||
304 | omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
305 | clkdm->clktrctrl_mask); | ||
306 | _clkdm_add_autodeps(clkdm); | ||
307 | omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
308 | clkdm->clktrctrl_mask); | ||
309 | } else { | ||
310 | if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) | ||
311 | omap2xxx_clkdm_wakeup(clkdm); | ||
312 | } | ||
313 | 297 | ||
314 | return 0; | 298 | return 0; |
315 | } | 299 | } |
@@ -324,17 +308,8 @@ static int omap2xxx_clkdm_clk_disable(struct clockdomain *clkdm) | |||
324 | hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 308 | hwsup = omap2xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
325 | clkdm->clktrctrl_mask); | 309 | clkdm->clktrctrl_mask); |
326 | 310 | ||
327 | if (hwsup) { | 311 | if (!hwsup && clkdm->flags & CLKDM_CAN_FORCE_SLEEP) |
328 | /* Disable HW transitions when we are changing deps */ | 312 | omap2xxx_clkdm_sleep(clkdm); |
329 | omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
330 | clkdm->clktrctrl_mask); | ||
331 | _clkdm_del_autodeps(clkdm); | ||
332 | omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | ||
333 | clkdm->clktrctrl_mask); | ||
334 | } else { | ||
335 | if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP) | ||
336 | omap2xxx_clkdm_sleep(clkdm); | ||
337 | } | ||
338 | 313 | ||
339 | return 0; | 314 | return 0; |
340 | } | 315 | } |
diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c index c2086f2e86b6..9061c307d915 100644 --- a/arch/arm/mach-omap2/cm3xxx.c +++ b/arch/arm/mach-omap2/cm3xxx.c | |||
@@ -186,7 +186,7 @@ static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | |||
186 | continue; /* only happens if data is erroneous */ | 186 | continue; /* only happens if data is erroneous */ |
187 | 187 | ||
188 | mask |= 1 << cd->clkdm->dep_bit; | 188 | mask |= 1 << cd->clkdm->dep_bit; |
189 | atomic_set(&cd->sleepdep_usecount, 0); | 189 | cd->sleepdep_usecount = 0; |
190 | } | 190 | } |
191 | omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | 191 | omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, |
192 | OMAP3430_CM_SLEEPDEP); | 192 | OMAP3430_CM_SLEEPDEP); |
@@ -209,8 +209,8 @@ static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm) | |||
209 | 209 | ||
210 | static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm) | 210 | static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm) |
211 | { | 211 | { |
212 | if (atomic_read(&clkdm->usecount) > 0) | 212 | if (clkdm->usecount > 0) |
213 | _clkdm_add_autodeps(clkdm); | 213 | clkdm_add_autodeps(clkdm); |
214 | 214 | ||
215 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 215 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
216 | clkdm->clktrctrl_mask); | 216 | clkdm->clktrctrl_mask); |
@@ -221,8 +221,8 @@ static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm) | |||
221 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 221 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
222 | clkdm->clktrctrl_mask); | 222 | clkdm->clktrctrl_mask); |
223 | 223 | ||
224 | if (atomic_read(&clkdm->usecount) > 0) | 224 | if (clkdm->usecount > 0) |
225 | _clkdm_del_autodeps(clkdm); | 225 | clkdm_del_autodeps(clkdm); |
226 | } | 226 | } |
227 | 227 | ||
228 | static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) | 228 | static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) |
@@ -250,7 +250,7 @@ static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm) | |||
250 | /* Disable HW transitions when we are changing deps */ | 250 | /* Disable HW transitions when we are changing deps */ |
251 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 251 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
252 | clkdm->clktrctrl_mask); | 252 | clkdm->clktrctrl_mask); |
253 | _clkdm_add_autodeps(clkdm); | 253 | clkdm_add_autodeps(clkdm); |
254 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 254 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
255 | clkdm->clktrctrl_mask); | 255 | clkdm->clktrctrl_mask); |
256 | } else { | 256 | } else { |
@@ -287,7 +287,7 @@ static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm) | |||
287 | /* Disable HW transitions when we are changing deps */ | 287 | /* Disable HW transitions when we are changing deps */ |
288 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 288 | omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
289 | clkdm->clktrctrl_mask); | 289 | clkdm->clktrctrl_mask); |
290 | _clkdm_del_autodeps(clkdm); | 290 | clkdm_del_autodeps(clkdm); |
291 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, | 291 | omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs, |
292 | clkdm->clktrctrl_mask); | 292 | clkdm->clktrctrl_mask); |
293 | } else { | 293 | } else { |
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c index 7f9a464f01e9..f0290f5566fe 100644 --- a/arch/arm/mach-omap2/cminst44xx.c +++ b/arch/arm/mach-omap2/cminst44xx.c | |||
@@ -393,7 +393,7 @@ static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm) | |||
393 | continue; /* only happens if data is erroneous */ | 393 | continue; /* only happens if data is erroneous */ |
394 | 394 | ||
395 | mask |= 1 << cd->clkdm->dep_bit; | 395 | mask |= 1 << cd->clkdm->dep_bit; |
396 | atomic_set(&cd->wkdep_usecount, 0); | 396 | cd->wkdep_usecount = 0; |
397 | } | 397 | } |
398 | 398 | ||
399 | omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition, | 399 | omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition, |
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 22590dbe8f14..80392fca86c6 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -36,40 +36,66 @@ | |||
36 | 36 | ||
37 | /* Mach specific information to be recorded in the C-state driver_data */ | 37 | /* Mach specific information to be recorded in the C-state driver_data */ |
38 | struct omap3_idle_statedata { | 38 | struct omap3_idle_statedata { |
39 | u32 mpu_state; | 39 | u8 mpu_state; |
40 | u32 core_state; | 40 | u8 core_state; |
41 | u8 per_min_state; | ||
42 | u8 flags; | ||
41 | }; | 43 | }; |
42 | 44 | ||
43 | static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; | 45 | static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; |
44 | 46 | ||
47 | /* | ||
48 | * Possible flag bits for struct omap3_idle_statedata.flags: | ||
49 | * | ||
50 | * OMAP_CPUIDLE_CX_NO_CLKDM_IDLE: don't allow the MPU clockdomain to go | ||
51 | * inactive. This in turn prevents the MPU DPLL from entering autoidle | ||
52 | * mode, so wakeup latency is greatly reduced, at the cost of additional | ||
53 | * energy consumption. This also prevents the CORE clockdomain from | ||
54 | * entering idle. | ||
55 | */ | ||
56 | #define OMAP_CPUIDLE_CX_NO_CLKDM_IDLE BIT(0) | ||
57 | |||
58 | /* | ||
59 | * Prevent PER OFF if CORE is not in RETention or OFF as this would | ||
60 | * disable PER wakeups completely. | ||
61 | */ | ||
45 | static struct omap3_idle_statedata omap3_idle_data[] = { | 62 | static struct omap3_idle_statedata omap3_idle_data[] = { |
46 | { | 63 | { |
47 | .mpu_state = PWRDM_POWER_ON, | 64 | .mpu_state = PWRDM_POWER_ON, |
48 | .core_state = PWRDM_POWER_ON, | 65 | .core_state = PWRDM_POWER_ON, |
66 | /* In C1 do not allow PER state lower than CORE state */ | ||
67 | .per_min_state = PWRDM_POWER_ON, | ||
68 | .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE, | ||
49 | }, | 69 | }, |
50 | { | 70 | { |
51 | .mpu_state = PWRDM_POWER_ON, | 71 | .mpu_state = PWRDM_POWER_ON, |
52 | .core_state = PWRDM_POWER_ON, | 72 | .core_state = PWRDM_POWER_ON, |
73 | .per_min_state = PWRDM_POWER_RET, | ||
53 | }, | 74 | }, |
54 | { | 75 | { |
55 | .mpu_state = PWRDM_POWER_RET, | 76 | .mpu_state = PWRDM_POWER_RET, |
56 | .core_state = PWRDM_POWER_ON, | 77 | .core_state = PWRDM_POWER_ON, |
78 | .per_min_state = PWRDM_POWER_RET, | ||
57 | }, | 79 | }, |
58 | { | 80 | { |
59 | .mpu_state = PWRDM_POWER_OFF, | 81 | .mpu_state = PWRDM_POWER_OFF, |
60 | .core_state = PWRDM_POWER_ON, | 82 | .core_state = PWRDM_POWER_ON, |
83 | .per_min_state = PWRDM_POWER_RET, | ||
61 | }, | 84 | }, |
62 | { | 85 | { |
63 | .mpu_state = PWRDM_POWER_RET, | 86 | .mpu_state = PWRDM_POWER_RET, |
64 | .core_state = PWRDM_POWER_RET, | 87 | .core_state = PWRDM_POWER_RET, |
88 | .per_min_state = PWRDM_POWER_OFF, | ||
65 | }, | 89 | }, |
66 | { | 90 | { |
67 | .mpu_state = PWRDM_POWER_OFF, | 91 | .mpu_state = PWRDM_POWER_OFF, |
68 | .core_state = PWRDM_POWER_RET, | 92 | .core_state = PWRDM_POWER_RET, |
93 | .per_min_state = PWRDM_POWER_OFF, | ||
69 | }, | 94 | }, |
70 | { | 95 | { |
71 | .mpu_state = PWRDM_POWER_OFF, | 96 | .mpu_state = PWRDM_POWER_OFF, |
72 | .core_state = PWRDM_POWER_OFF, | 97 | .core_state = PWRDM_POWER_OFF, |
98 | .per_min_state = PWRDM_POWER_OFF, | ||
73 | }, | 99 | }, |
74 | }; | 100 | }; |
75 | 101 | ||
@@ -80,27 +106,25 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, | |||
80 | int index) | 106 | int index) |
81 | { | 107 | { |
82 | struct omap3_idle_statedata *cx = &omap3_idle_data[index]; | 108 | struct omap3_idle_statedata *cx = &omap3_idle_data[index]; |
83 | u32 mpu_state = cx->mpu_state, core_state = cx->core_state; | ||
84 | 109 | ||
85 | local_fiq_disable(); | 110 | local_fiq_disable(); |
86 | 111 | ||
87 | pwrdm_set_next_pwrst(mpu_pd, mpu_state); | ||
88 | pwrdm_set_next_pwrst(core_pd, core_state); | ||
89 | |||
90 | if (omap_irq_pending() || need_resched()) | 112 | if (omap_irq_pending() || need_resched()) |
91 | goto return_sleep_time; | 113 | goto return_sleep_time; |
92 | 114 | ||
93 | /* Deny idle for C1 */ | 115 | /* Deny idle for C1 */ |
94 | if (index == 0) { | 116 | if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) { |
95 | clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); | 117 | clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); |
96 | clkdm_deny_idle(core_pd->pwrdm_clkdms[0]); | 118 | } else { |
119 | pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state); | ||
120 | pwrdm_set_next_pwrst(core_pd, cx->core_state); | ||
97 | } | 121 | } |
98 | 122 | ||
99 | /* | 123 | /* |
100 | * Call idle CPU PM enter notifier chain so that | 124 | * Call idle CPU PM enter notifier chain so that |
101 | * VFP context is saved. | 125 | * VFP context is saved. |
102 | */ | 126 | */ |
103 | if (mpu_state == PWRDM_POWER_OFF) | 127 | if (cx->mpu_state == PWRDM_POWER_OFF) |
104 | cpu_pm_enter(); | 128 | cpu_pm_enter(); |
105 | 129 | ||
106 | /* Execute ARM wfi */ | 130 | /* Execute ARM wfi */ |
@@ -110,17 +134,15 @@ static int __omap3_enter_idle(struct cpuidle_device *dev, | |||
110 | * Call idle CPU PM enter notifier chain to restore | 134 | * Call idle CPU PM enter notifier chain to restore |
111 | * VFP context. | 135 | * VFP context. |
112 | */ | 136 | */ |
113 | if (pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) | 137 | if (cx->mpu_state == PWRDM_POWER_OFF && |
138 | pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) | ||
114 | cpu_pm_exit(); | 139 | cpu_pm_exit(); |
115 | 140 | ||
116 | /* Re-allow idle for C1 */ | 141 | /* Re-allow idle for C1 */ |
117 | if (index == 0) { | 142 | if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) |
118 | clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); | 143 | clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); |
119 | clkdm_allow_idle(core_pd->pwrdm_clkdms[0]); | ||
120 | } | ||
121 | 144 | ||
122 | return_sleep_time: | 145 | return_sleep_time: |
123 | |||
124 | local_fiq_enable(); | 146 | local_fiq_enable(); |
125 | 147 | ||
126 | return index; | 148 | return index; |
@@ -185,7 +207,7 @@ static int next_valid_state(struct cpuidle_device *dev, | |||
185 | * Start search from the next (lower) state. | 207 | * Start search from the next (lower) state. |
186 | */ | 208 | */ |
187 | for (idx = index - 1; idx >= 0; idx--) { | 209 | for (idx = index - 1; idx >= 0; idx--) { |
188 | cx = &omap3_idle_data[idx]; | 210 | cx = &omap3_idle_data[idx]; |
189 | if ((cx->mpu_state >= mpu_deepest_state) && | 211 | if ((cx->mpu_state >= mpu_deepest_state) && |
190 | (cx->core_state >= core_deepest_state)) { | 212 | (cx->core_state >= core_deepest_state)) { |
191 | next_index = idx; | 213 | next_index = idx; |
@@ -209,10 +231,9 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
209 | struct cpuidle_driver *drv, | 231 | struct cpuidle_driver *drv, |
210 | int index) | 232 | int index) |
211 | { | 233 | { |
212 | int new_state_idx; | 234 | int new_state_idx, ret; |
213 | u32 core_next_state, per_next_state = 0, per_saved_state = 0; | 235 | u8 per_next_state, per_saved_state; |
214 | struct omap3_idle_statedata *cx; | 236 | struct omap3_idle_statedata *cx; |
215 | int ret; | ||
216 | 237 | ||
217 | /* | 238 | /* |
218 | * Use only C1 if CAM is active. | 239 | * Use only C1 if CAM is active. |
@@ -233,25 +254,13 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
233 | 254 | ||
234 | /* Program PER state */ | 255 | /* Program PER state */ |
235 | cx = &omap3_idle_data[new_state_idx]; | 256 | cx = &omap3_idle_data[new_state_idx]; |
236 | core_next_state = cx->core_state; | ||
237 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | ||
238 | if (new_state_idx == 0) { | ||
239 | /* In C1 do not allow PER state lower than CORE state */ | ||
240 | if (per_next_state < core_next_state) | ||
241 | per_next_state = core_next_state; | ||
242 | } else { | ||
243 | /* | ||
244 | * Prevent PER OFF if CORE is not in RETention or OFF as this | ||
245 | * would disable PER wakeups completely. | ||
246 | */ | ||
247 | if ((per_next_state == PWRDM_POWER_OFF) && | ||
248 | (core_next_state > PWRDM_POWER_RET)) | ||
249 | per_next_state = PWRDM_POWER_RET; | ||
250 | } | ||
251 | 257 | ||
252 | /* Are we changing PER target state? */ | 258 | per_next_state = pwrdm_read_next_pwrst(per_pd); |
253 | if (per_next_state != per_saved_state) | 259 | per_saved_state = per_next_state; |
260 | if (per_next_state < cx->per_min_state) { | ||
261 | per_next_state = cx->per_min_state; | ||
254 | pwrdm_set_next_pwrst(per_pd, per_next_state); | 262 | pwrdm_set_next_pwrst(per_pd, per_next_state); |
263 | } | ||
255 | 264 | ||
256 | ret = omap3_enter_idle(dev, drv, new_state_idx); | 265 | ret = omap3_enter_idle(dev, drv, new_state_idx); |
257 | 266 | ||
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c index aac46bfdbeb2..8bcb64bcdcdb 100644 --- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c +++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c | |||
@@ -87,37 +87,6 @@ static inline void set_cpu_wakeup_addr(unsigned int cpu_id, u32 addr) | |||
87 | } | 87 | } |
88 | 88 | ||
89 | /* | 89 | /* |
90 | * Set the CPUx powerdomain's previous power state | ||
91 | */ | ||
92 | static inline void set_cpu_next_pwrst(unsigned int cpu_id, | ||
93 | unsigned int power_state) | ||
94 | { | ||
95 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); | ||
96 | |||
97 | pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Read CPU's previous power state | ||
102 | */ | ||
103 | static inline unsigned int read_cpu_prev_pwrst(unsigned int cpu_id) | ||
104 | { | ||
105 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); | ||
106 | |||
107 | return pwrdm_read_prev_pwrst(pm_info->pwrdm); | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Clear the CPUx powerdomain's previous power state | ||
112 | */ | ||
113 | static inline void clear_cpu_prev_pwrst(unsigned int cpu_id) | ||
114 | { | ||
115 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu_id); | ||
116 | |||
117 | pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Store the SCU power status value to scratchpad memory | 90 | * Store the SCU power status value to scratchpad memory |
122 | */ | 91 | */ |
123 | static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) | 92 | static void scu_pwrst_prepare(unsigned int cpu_id, unsigned int cpu_state) |
@@ -230,6 +199,7 @@ static void save_l2x0_context(void) | |||
230 | */ | 199 | */ |
231 | int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) | 200 | int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) |
232 | { | 201 | { |
202 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); | ||
233 | unsigned int save_state = 0; | 203 | unsigned int save_state = 0; |
234 | unsigned int wakeup_cpu; | 204 | unsigned int wakeup_cpu; |
235 | 205 | ||
@@ -268,7 +238,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) | |||
268 | save_state = 2; | 238 | save_state = 2; |
269 | 239 | ||
270 | cpu_clear_prev_logic_pwrst(cpu); | 240 | cpu_clear_prev_logic_pwrst(cpu); |
271 | set_cpu_next_pwrst(cpu, power_state); | 241 | pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); |
272 | set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); | 242 | set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume)); |
273 | scu_pwrst_prepare(cpu, power_state); | 243 | scu_pwrst_prepare(cpu, power_state); |
274 | l2x0_pwrst_prepare(cpu, save_state); | 244 | l2x0_pwrst_prepare(cpu, save_state); |
@@ -286,7 +256,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) | |||
286 | * domain transition | 256 | * domain transition |
287 | */ | 257 | */ |
288 | wakeup_cpu = smp_processor_id(); | 258 | wakeup_cpu = smp_processor_id(); |
289 | set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON); | 259 | pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); |
290 | 260 | ||
291 | pwrdm_post_transition(NULL); | 261 | pwrdm_post_transition(NULL); |
292 | 262 | ||
@@ -300,8 +270,8 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state) | |||
300 | */ | 270 | */ |
301 | int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) | 271 | int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) |
302 | { | 272 | { |
303 | unsigned int cpu_state = 0; | ||
304 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); | 273 | struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu); |
274 | unsigned int cpu_state = 0; | ||
305 | 275 | ||
306 | if (omap_rev() == OMAP4430_REV_ES1_0) | 276 | if (omap_rev() == OMAP4430_REV_ES1_0) |
307 | return -ENXIO; | 277 | return -ENXIO; |
@@ -309,8 +279,8 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) | |||
309 | if (power_state == PWRDM_POWER_OFF) | 279 | if (power_state == PWRDM_POWER_OFF) |
310 | cpu_state = 1; | 280 | cpu_state = 1; |
311 | 281 | ||
312 | clear_cpu_prev_pwrst(cpu); | 282 | pwrdm_clear_all_prev_pwrst(pm_info->pwrdm); |
313 | set_cpu_next_pwrst(cpu, power_state); | 283 | pwrdm_set_next_pwrst(pm_info->pwrdm, power_state); |
314 | set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup)); | 284 | set_cpu_wakeup_addr(cpu, virt_to_phys(pm_info->secondary_startup)); |
315 | scu_pwrst_prepare(cpu, power_state); | 285 | scu_pwrst_prepare(cpu, power_state); |
316 | 286 | ||
@@ -321,7 +291,7 @@ int __cpuinit omap4_hotplug_cpu(unsigned int cpu, unsigned int power_state) | |||
321 | */ | 291 | */ |
322 | omap4_finish_suspend(cpu_state); | 292 | omap4_finish_suspend(cpu_state); |
323 | 293 | ||
324 | set_cpu_next_pwrst(cpu, PWRDM_POWER_ON); | 294 | pwrdm_set_next_pwrst(pm_info->pwrdm, PWRDM_POWER_ON); |
325 | return 0; | 295 | return 0; |
326 | } | 296 | } |
327 | 297 | ||
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index e2c291f52f92..6db89ae92389 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c | |||
@@ -83,10 +83,8 @@ static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) | |||
83 | strncmp(clkdm->name, "dpll", 4) == 0) | 83 | strncmp(clkdm->name, "dpll", 4) == 0) |
84 | return 0; | 84 | return 0; |
85 | 85 | ||
86 | seq_printf(s, "%s->%s (%d)", clkdm->name, | 86 | seq_printf(s, "%s->%s (%d)\n", clkdm->name, clkdm->pwrdm.ptr->name, |
87 | clkdm->pwrdm.ptr->name, | 87 | clkdm->usecount); |
88 | atomic_read(&clkdm->usecount)); | ||
89 | seq_printf(s, "\n"); | ||
90 | 88 | ||
91 | return 0; | 89 | return 0; |
92 | } | 90 | } |
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 9627547ee72a..9a9be3c9f208 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -106,80 +106,19 @@ static void __init omap2_init_processor_devices(void) | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | /* Types of sleep_switch used in omap_set_pwrdm_state */ | ||
110 | #define FORCEWAKEUP_SWITCH 0 | ||
111 | #define LOWPOWERSTATE_SWITCH 1 | ||
112 | |||
113 | int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) | 109 | int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused) |
114 | { | 110 | { |
111 | /* XXX The usecount test is racy */ | ||
115 | if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) && | 112 | if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) && |
116 | !(clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)) | 113 | !(clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)) |
117 | clkdm_allow_idle(clkdm); | 114 | clkdm_allow_idle(clkdm); |
118 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && | 115 | else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP && |
119 | atomic_read(&clkdm->usecount) == 0) | 116 | clkdm->usecount == 0) |
120 | clkdm_sleep(clkdm); | 117 | clkdm_sleep(clkdm); |
121 | return 0; | 118 | return 0; |
122 | } | 119 | } |
123 | 120 | ||
124 | /* | 121 | /* |
125 | * This sets pwrdm state (other than mpu & core. Currently only ON & | ||
126 | * RET are supported. | ||
127 | */ | ||
128 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst) | ||
129 | { | ||
130 | u8 curr_pwrst, next_pwrst; | ||
131 | int sleep_switch = -1, ret = 0, hwsup = 0; | ||
132 | |||
133 | if (!pwrdm || IS_ERR(pwrdm)) | ||
134 | return -EINVAL; | ||
135 | |||
136 | while (!(pwrdm->pwrsts & (1 << pwrst))) { | ||
137 | if (pwrst == PWRDM_POWER_OFF) | ||
138 | return ret; | ||
139 | pwrst--; | ||
140 | } | ||
141 | |||
142 | next_pwrst = pwrdm_read_next_pwrst(pwrdm); | ||
143 | if (next_pwrst == pwrst) | ||
144 | return ret; | ||
145 | |||
146 | curr_pwrst = pwrdm_read_pwrst(pwrdm); | ||
147 | if (curr_pwrst < PWRDM_POWER_ON) { | ||
148 | if ((curr_pwrst > pwrst) && | ||
149 | (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) { | ||
150 | sleep_switch = LOWPOWERSTATE_SWITCH; | ||
151 | } else { | ||
152 | hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); | ||
153 | clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); | ||
154 | sleep_switch = FORCEWAKEUP_SWITCH; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | ret = pwrdm_set_next_pwrst(pwrdm, pwrst); | ||
159 | if (ret) | ||
160 | pr_err("%s: unable to set power state of powerdomain: %s\n", | ||
161 | __func__, pwrdm->name); | ||
162 | |||
163 | switch (sleep_switch) { | ||
164 | case FORCEWAKEUP_SWITCH: | ||
165 | if (hwsup) | ||
166 | clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); | ||
167 | else | ||
168 | clkdm_sleep(pwrdm->pwrdm_clkdms[0]); | ||
169 | break; | ||
170 | case LOWPOWERSTATE_SWITCH: | ||
171 | pwrdm_set_lowpwrstchange(pwrdm); | ||
172 | pwrdm_wait_transition(pwrdm); | ||
173 | pwrdm_state_switch(pwrdm); | ||
174 | break; | ||
175 | } | ||
176 | |||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | |||
181 | |||
182 | /* | ||
183 | * This API is to be called during init to set the various voltage | 122 | * This API is to be called during init to set the various voltage |
184 | * domains to the voltage as per the opp table. Typically we boot up | 123 | * domains to the voltage as per the opp table. Typically we boot up |
185 | * at the nominal voltage. So this function finds out the rate of | 124 | * at the nominal voltage. So this function finds out the rate of |
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index c22503b17abd..7bdd22afce69 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h | |||
@@ -33,7 +33,6 @@ static inline int omap4_idle_init(void) | |||
33 | extern void *omap3_secure_ram_storage; | 33 | extern void *omap3_secure_ram_storage; |
34 | extern void omap3_pm_off_mode_enable(int); | 34 | extern void omap3_pm_off_mode_enable(int); |
35 | extern void omap_sram_idle(void); | 35 | extern void omap_sram_idle(void); |
36 | extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state); | ||
37 | extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused); | 36 | extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused); |
38 | extern int (*omap_pm_suspend)(void); | 37 | extern int (*omap_pm_suspend)(void); |
39 | 38 | ||
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c index 909ef53ba2ea..b2a4df623545 100644 --- a/arch/arm/mach-omap2/pm24xx.c +++ b/arch/arm/mach-omap2/pm24xx.c | |||
@@ -90,11 +90,7 @@ static int omap2_enter_full_retention(void) | |||
90 | omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); | 90 | omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2); |
91 | omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); | 91 | omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); |
92 | 92 | ||
93 | /* | 93 | pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); |
94 | * Set MPU powerdomain's next power state to RETENTION; | ||
95 | * preserve logic state during retention | ||
96 | */ | ||
97 | pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); | ||
98 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); | 94 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); |
99 | 95 | ||
100 | /* Workaround to kill USB */ | 96 | /* Workaround to kill USB */ |
@@ -137,6 +133,9 @@ no_sleep: | |||
137 | /* Mask future PRCM-to-MPU interrupts */ | 133 | /* Mask future PRCM-to-MPU interrupts */ |
138 | omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); | 134 | omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET); |
139 | 135 | ||
136 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | ||
137 | pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON); | ||
138 | |||
140 | return 0; | 139 | return 0; |
141 | } | 140 | } |
142 | 141 | ||
@@ -173,17 +172,16 @@ static void omap2_enter_mpu_retention(void) | |||
173 | omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); | 172 | omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST); |
174 | 173 | ||
175 | /* Try to enter MPU retention */ | 174 | /* Try to enter MPU retention */ |
176 | omap2_prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) | | 175 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); |
177 | OMAP_LOGICRETSTATE_MASK, | 176 | |
178 | MPU_MOD, OMAP2_PM_PWSTCTRL); | ||
179 | } else { | 177 | } else { |
180 | /* Block MPU retention */ | 178 | /* Block MPU retention */ |
181 | 179 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | |
182 | omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD, | ||
183 | OMAP2_PM_PWSTCTRL); | ||
184 | } | 180 | } |
185 | 181 | ||
186 | omap2_sram_idle(); | 182 | omap2_sram_idle(); |
183 | |||
184 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON); | ||
187 | } | 185 | } |
188 | 186 | ||
189 | static int omap2_can_sleep(void) | 187 | static int omap2_can_sleep(void) |
@@ -238,25 +236,17 @@ static void __init prcm_setup_regs(void) | |||
238 | for (i = 0; i < num_mem_banks; i++) | 236 | for (i = 0; i < num_mem_banks; i++) |
239 | pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); | 237 | pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET); |
240 | 238 | ||
241 | /* Set CORE powerdomain's next power state to RETENTION */ | 239 | pwrdm_set_logic_retst(core_pwrdm, PWRDM_POWER_RET); |
242 | pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET); | ||
243 | 240 | ||
244 | /* | ||
245 | * Set MPU powerdomain's next power state to RETENTION; | ||
246 | * preserve logic state during retention | ||
247 | */ | ||
248 | pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); | 241 | pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET); |
249 | pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET); | ||
250 | 242 | ||
251 | /* Force-power down DSP, GFX powerdomains */ | 243 | /* Force-power down DSP, GFX powerdomains */ |
252 | 244 | ||
253 | pwrdm = clkdm_get_pwrdm(dsp_clkdm); | 245 | pwrdm = clkdm_get_pwrdm(dsp_clkdm); |
254 | pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); | 246 | pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); |
255 | clkdm_sleep(dsp_clkdm); | ||
256 | 247 | ||
257 | pwrdm = clkdm_get_pwrdm(gfx_clkdm); | 248 | pwrdm = clkdm_get_pwrdm(gfx_clkdm); |
258 | pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); | 249 | pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF); |
259 | clkdm_sleep(gfx_clkdm); | ||
260 | 250 | ||
261 | /* Enable hardware-supervised idle for all clkdms */ | 251 | /* Enable hardware-supervised idle for all clkdms */ |
262 | clkdm_for_each(omap_pm_clkdms_setup, NULL); | 252 | clkdm_for_each(omap_pm_clkdms_setup, NULL); |
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index dea62a9aad07..8e61d80bf6b3 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/spinlock.h> | ||
22 | #include <trace/events/power.h> | 23 | #include <trace/events/power.h> |
23 | 24 | ||
24 | #include "cm2xxx_3xxx.h" | 25 | #include "cm2xxx_3xxx.h" |
@@ -42,6 +43,16 @@ enum { | |||
42 | PWRDM_STATE_PREV, | 43 | PWRDM_STATE_PREV, |
43 | }; | 44 | }; |
44 | 45 | ||
46 | /* | ||
47 | * Types of sleep_switch used internally in omap_set_pwrdm_state() | ||
48 | * and its associated static functions | ||
49 | * | ||
50 | * XXX Better documentation is needed here | ||
51 | */ | ||
52 | #define ALREADYACTIVE_SWITCH 0 | ||
53 | #define FORCEWAKEUP_SWITCH 1 | ||
54 | #define LOWPOWERSTATE_SWITCH 2 | ||
55 | #define ERROR_SWITCH 3 | ||
45 | 56 | ||
46 | /* pwrdm_list contains all registered struct powerdomains */ | 57 | /* pwrdm_list contains all registered struct powerdomains */ |
47 | static LIST_HEAD(pwrdm_list); | 58 | static LIST_HEAD(pwrdm_list); |
@@ -101,6 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) | |||
101 | pwrdm->voltdm.ptr = voltdm; | 112 | pwrdm->voltdm.ptr = voltdm; |
102 | INIT_LIST_HEAD(&pwrdm->voltdm_node); | 113 | INIT_LIST_HEAD(&pwrdm->voltdm_node); |
103 | voltdm_add_pwrdm(voltdm, pwrdm); | 114 | voltdm_add_pwrdm(voltdm, pwrdm); |
115 | spin_lock_init(&pwrdm->_lock); | ||
104 | 116 | ||
105 | list_add(&pwrdm->node, &pwrdm_list); | 117 | list_add(&pwrdm->node, &pwrdm_list); |
106 | 118 | ||
@@ -112,7 +124,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm) | |||
112 | for (i = 0; i < pwrdm->banks; i++) | 124 | for (i = 0; i < pwrdm->banks; i++) |
113 | pwrdm->ret_mem_off_counter[i] = 0; | 125 | pwrdm->ret_mem_off_counter[i] = 0; |
114 | 126 | ||
115 | pwrdm_wait_transition(pwrdm); | 127 | arch_pwrdm->pwrdm_wait_transition(pwrdm); |
116 | pwrdm->state = pwrdm_read_pwrst(pwrdm); | 128 | pwrdm->state = pwrdm_read_pwrst(pwrdm); |
117 | pwrdm->state_counter[pwrdm->state] = 1; | 129 | pwrdm->state_counter[pwrdm->state] = 1; |
118 | 130 | ||
@@ -143,7 +155,7 @@ static void _update_logic_membank_counters(struct powerdomain *pwrdm) | |||
143 | static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) | 155 | static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) |
144 | { | 156 | { |
145 | 157 | ||
146 | int prev, state, trace_state = 0; | 158 | int prev, next, state, trace_state = 0; |
147 | 159 | ||
148 | if (pwrdm == NULL) | 160 | if (pwrdm == NULL) |
149 | return -EINVAL; | 161 | return -EINVAL; |
@@ -164,9 +176,10 @@ static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag) | |||
164 | * If the power domain did not hit the desired state, | 176 | * If the power domain did not hit the desired state, |
165 | * generate a trace event with both the desired and hit states | 177 | * generate a trace event with both the desired and hit states |
166 | */ | 178 | */ |
167 | if (state != prev) { | 179 | next = pwrdm_read_next_pwrst(pwrdm); |
180 | if (next != prev) { | ||
168 | trace_state = (PWRDM_TRACE_STATES_FLAG | | 181 | trace_state = (PWRDM_TRACE_STATES_FLAG | |
169 | ((state & OMAP_POWERSTATE_MASK) << 8) | | 182 | ((next & OMAP_POWERSTATE_MASK) << 8) | |
170 | ((prev & OMAP_POWERSTATE_MASK) << 0)); | 183 | ((prev & OMAP_POWERSTATE_MASK) << 0)); |
171 | trace_power_domain_target(pwrdm->name, trace_state, | 184 | trace_power_domain_target(pwrdm->name, trace_state, |
172 | smp_processor_id()); | 185 | smp_processor_id()); |
@@ -199,6 +212,80 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) | |||
199 | return 0; | 212 | return 0; |
200 | } | 213 | } |
201 | 214 | ||
215 | /** | ||
216 | * _pwrdm_save_clkdm_state_and_activate - prepare for power state change | ||
217 | * @pwrdm: struct powerdomain * to operate on | ||
218 | * @curr_pwrst: current power state of @pwrdm | ||
219 | * @pwrst: power state to switch to | ||
220 | * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised | ||
221 | * | ||
222 | * Determine whether the powerdomain needs to be turned on before | ||
223 | * attempting to switch power states. Called by | ||
224 | * omap_set_pwrdm_state(). NOTE that if the powerdomain contains | ||
225 | * multiple clockdomains, this code assumes that the first clockdomain | ||
226 | * supports software-supervised wakeup mode - potentially a problem. | ||
227 | * Returns the power state switch mode currently in use (see the | ||
228 | * "Types of sleep_switch" comment above). | ||
229 | */ | ||
230 | static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm, | ||
231 | u8 curr_pwrst, u8 pwrst, | ||
232 | bool *hwsup) | ||
233 | { | ||
234 | u8 sleep_switch; | ||
235 | |||
236 | if (curr_pwrst < 0) { | ||
237 | WARN_ON(1); | ||
238 | sleep_switch = ERROR_SWITCH; | ||
239 | } else if (curr_pwrst < PWRDM_POWER_ON) { | ||
240 | if (curr_pwrst > pwrst && | ||
241 | pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && | ||
242 | arch_pwrdm->pwrdm_set_lowpwrstchange) { | ||
243 | sleep_switch = LOWPOWERSTATE_SWITCH; | ||
244 | } else { | ||
245 | *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); | ||
246 | clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]); | ||
247 | sleep_switch = FORCEWAKEUP_SWITCH; | ||
248 | } | ||
249 | } else { | ||
250 | sleep_switch = ALREADYACTIVE_SWITCH; | ||
251 | } | ||
252 | |||
253 | return sleep_switch; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change | ||
258 | * @pwrdm: struct powerdomain * to operate on | ||
259 | * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate() | ||
260 | * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode? | ||
261 | * | ||
262 | * Restore the clockdomain state perturbed by | ||
263 | * _pwrdm_save_clkdm_state_and_activate(), and call the power state | ||
264 | * bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if | ||
265 | * the powerdomain contains multiple clockdomains, this assumes that | ||
266 | * the first associated clockdomain supports either | ||
267 | * hardware-supervised idle control in the register, or | ||
268 | * software-supervised sleep. No return value. | ||
269 | */ | ||
270 | static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm, | ||
271 | u8 sleep_switch, bool hwsup) | ||
272 | { | ||
273 | switch (sleep_switch) { | ||
274 | case FORCEWAKEUP_SWITCH: | ||
275 | if (hwsup) | ||
276 | clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]); | ||
277 | else | ||
278 | clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]); | ||
279 | break; | ||
280 | case LOWPOWERSTATE_SWITCH: | ||
281 | if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && | ||
282 | arch_pwrdm->pwrdm_set_lowpwrstchange) | ||
283 | arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); | ||
284 | pwrdm_state_switch_nolock(pwrdm); | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | |||
202 | /* Public functions */ | 289 | /* Public functions */ |
203 | 290 | ||
204 | /** | 291 | /** |
@@ -275,6 +362,30 @@ int pwrdm_complete_init(void) | |||
275 | } | 362 | } |
276 | 363 | ||
277 | /** | 364 | /** |
365 | * pwrdm_lock - acquire a Linux spinlock on a powerdomain | ||
366 | * @pwrdm: struct powerdomain * to lock | ||
367 | * | ||
368 | * Acquire the powerdomain spinlock on @pwrdm. No return value. | ||
369 | */ | ||
370 | void pwrdm_lock(struct powerdomain *pwrdm) | ||
371 | __acquires(&pwrdm->_lock) | ||
372 | { | ||
373 | spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags); | ||
374 | } | ||
375 | |||
376 | /** | ||
377 | * pwrdm_unlock - release a Linux spinlock on a powerdomain | ||
378 | * @pwrdm: struct powerdomain * to unlock | ||
379 | * | ||
380 | * Release the powerdomain spinlock on @pwrdm. No return value. | ||
381 | */ | ||
382 | void pwrdm_unlock(struct powerdomain *pwrdm) | ||
383 | __releases(&pwrdm->_lock) | ||
384 | { | ||
385 | spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags); | ||
386 | } | ||
387 | |||
388 | /** | ||
278 | * pwrdm_lookup - look up a powerdomain by name, return a pointer | 389 | * pwrdm_lookup - look up a powerdomain by name, return a pointer |
279 | * @name: name of powerdomain | 390 | * @name: name of powerdomain |
280 | * | 391 | * |
@@ -920,65 +1031,27 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm) | |||
920 | return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; | 1031 | return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; |
921 | } | 1032 | } |
922 | 1033 | ||
923 | /** | 1034 | int pwrdm_state_switch_nolock(struct powerdomain *pwrdm) |
924 | * pwrdm_set_lowpwrstchange - Request a low power state change | ||
925 | * @pwrdm: struct powerdomain * | ||
926 | * | ||
927 | * Allows a powerdomain to transtion to a lower power sleep state | ||
928 | * from an existing sleep state without waking up the powerdomain. | ||
929 | * Returns -EINVAL if the powerdomain pointer is null or if the | ||
930 | * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0 | ||
931 | * upon success. | ||
932 | */ | ||
933 | int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm) | ||
934 | { | ||
935 | int ret = -EINVAL; | ||
936 | |||
937 | if (!pwrdm) | ||
938 | return -EINVAL; | ||
939 | |||
940 | if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) | ||
941 | return -EINVAL; | ||
942 | |||
943 | pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n", | ||
944 | pwrdm->name); | ||
945 | |||
946 | if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange) | ||
947 | ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); | ||
948 | |||
949 | return ret; | ||
950 | } | ||
951 | |||
952 | /** | ||
953 | * pwrdm_wait_transition - wait for powerdomain power transition to finish | ||
954 | * @pwrdm: struct powerdomain * to wait for | ||
955 | * | ||
956 | * If the powerdomain @pwrdm is in the process of a state transition, | ||
957 | * spin until it completes the power transition, or until an iteration | ||
958 | * bailout value is reached. Returns -EINVAL if the powerdomain | ||
959 | * pointer is null, -EAGAIN if the bailout value was reached, or | ||
960 | * returns 0 upon success. | ||
961 | */ | ||
962 | int pwrdm_wait_transition(struct powerdomain *pwrdm) | ||
963 | { | 1035 | { |
964 | int ret = -EINVAL; | 1036 | int ret; |
965 | 1037 | ||
966 | if (!pwrdm) | 1038 | if (!pwrdm || !arch_pwrdm) |
967 | return -EINVAL; | 1039 | return -EINVAL; |
968 | 1040 | ||
969 | if (arch_pwrdm && arch_pwrdm->pwrdm_wait_transition) | 1041 | ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); |
970 | ret = arch_pwrdm->pwrdm_wait_transition(pwrdm); | 1042 | if (!ret) |
1043 | ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); | ||
971 | 1044 | ||
972 | return ret; | 1045 | return ret; |
973 | } | 1046 | } |
974 | 1047 | ||
975 | int pwrdm_state_switch(struct powerdomain *pwrdm) | 1048 | int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm) |
976 | { | 1049 | { |
977 | int ret; | 1050 | int ret; |
978 | 1051 | ||
979 | ret = pwrdm_wait_transition(pwrdm); | 1052 | pwrdm_lock(pwrdm); |
980 | if (!ret) | 1053 | ret = pwrdm_state_switch_nolock(pwrdm); |
981 | ret = _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW); | 1054 | pwrdm_unlock(pwrdm); |
982 | 1055 | ||
983 | return ret; | 1056 | return ret; |
984 | } | 1057 | } |
@@ -1004,6 +1077,61 @@ int pwrdm_post_transition(struct powerdomain *pwrdm) | |||
1004 | } | 1077 | } |
1005 | 1078 | ||
1006 | /** | 1079 | /** |
1080 | * omap_set_pwrdm_state - change a powerdomain's current power state | ||
1081 | * @pwrdm: struct powerdomain * to change the power state of | ||
1082 | * @pwrst: power state to change to | ||
1083 | * | ||
1084 | * Change the current hardware power state of the powerdomain | ||
1085 | * represented by @pwrdm to the power state represented by @pwrst. | ||
1086 | * Returns -EINVAL if @pwrdm is null or invalid or if the | ||
1087 | * powerdomain's current power state could not be read, or returns 0 | ||
1088 | * upon success or if @pwrdm does not support @pwrst or any | ||
1089 | * lower-power state. XXX Should not return 0 if the @pwrdm does not | ||
1090 | * support @pwrst or any lower-power state: this should be an error. | ||
1091 | */ | ||
1092 | int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst) | ||
1093 | { | ||
1094 | u8 curr_pwrst, next_pwrst, sleep_switch; | ||
1095 | int ret = 0; | ||
1096 | bool hwsup = false; | ||
1097 | |||
1098 | if (!pwrdm || IS_ERR(pwrdm)) | ||
1099 | return -EINVAL; | ||
1100 | |||
1101 | while (!(pwrdm->pwrsts & (1 << pwrst))) { | ||
1102 | if (pwrst == PWRDM_POWER_OFF) | ||
1103 | return ret; | ||
1104 | pwrst--; | ||
1105 | } | ||
1106 | |||
1107 | pwrdm_lock(pwrdm); | ||
1108 | |||
1109 | curr_pwrst = pwrdm_read_pwrst(pwrdm); | ||
1110 | next_pwrst = pwrdm_read_next_pwrst(pwrdm); | ||
1111 | if (curr_pwrst == pwrst && next_pwrst == pwrst) | ||
1112 | goto osps_out; | ||
1113 | |||
1114 | sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, | ||
1115 | pwrst, &hwsup); | ||
1116 | if (sleep_switch == ERROR_SWITCH) { | ||
1117 | ret = -EINVAL; | ||
1118 | goto osps_out; | ||
1119 | } | ||
1120 | |||
1121 | ret = pwrdm_set_next_pwrst(pwrdm, pwrst); | ||
1122 | if (ret) | ||
1123 | pr_err("%s: unable to set power state of powerdomain: %s\n", | ||
1124 | __func__, pwrdm->name); | ||
1125 | |||
1126 | _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); | ||
1127 | |||
1128 | osps_out: | ||
1129 | pwrdm_unlock(pwrdm); | ||
1130 | |||
1131 | return ret; | ||
1132 | } | ||
1133 | |||
1134 | /** | ||
1007 | * pwrdm_get_context_loss_count - get powerdomain's context loss count | 1135 | * pwrdm_get_context_loss_count - get powerdomain's context loss count |
1008 | * @pwrdm: struct powerdomain * to wait for | 1136 | * @pwrdm: struct powerdomain * to wait for |
1009 | * | 1137 | * |
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h index 5277d56eb37f..140c36074fed 100644 --- a/arch/arm/mach-omap2/powerdomain.h +++ b/arch/arm/mach-omap2/powerdomain.h | |||
@@ -19,8 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/list.h> | 21 | #include <linux/list.h> |
22 | 22 | #include <linux/spinlock.h> | |
23 | #include <linux/atomic.h> | ||
24 | 23 | ||
25 | #include "voltage.h" | 24 | #include "voltage.h" |
26 | 25 | ||
@@ -44,18 +43,20 @@ | |||
44 | #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) | 43 | #define PWRSTS_OFF_RET_ON (PWRSTS_OFF_RET | PWRSTS_ON) |
45 | 44 | ||
46 | 45 | ||
47 | /* Powerdomain flags */ | 46 | /* |
48 | #define PWRDM_HAS_HDWR_SAR (1 << 0) /* hardware save-and-restore support */ | 47 | * Powerdomain flags (struct powerdomain.flags) |
49 | #define PWRDM_HAS_MPU_QUIRK (1 << 1) /* MPU pwr domain has MEM bank 0 bits | 48 | * |
50 | * in MEM bank 1 position. This is | 49 | * PWRDM_HAS_HDWR_SAR - powerdomain has hardware save-and-restore support |
51 | * true for OMAP3430 | 50 | * |
52 | */ | 51 | * PWRDM_HAS_MPU_QUIRK - MPU pwr domain has MEM bank 0 bits in MEM |
53 | #define PWRDM_HAS_LOWPOWERSTATECHANGE (1 << 2) /* | 52 | * bank 1 position. This is true for OMAP3430 |
54 | * support to transition from a | 53 | * |
55 | * sleep state to a lower sleep | 54 | * PWRDM_HAS_LOWPOWERSTATECHANGE - can transition from a sleep state |
56 | * state without waking up the | 55 | * to a lower sleep state without waking up the powerdomain |
57 | * powerdomain | 56 | */ |
58 | */ | 57 | #define PWRDM_HAS_HDWR_SAR BIT(0) |
58 | #define PWRDM_HAS_MPU_QUIRK BIT(1) | ||
59 | #define PWRDM_HAS_LOWPOWERSTATECHANGE BIT(2) | ||
59 | 60 | ||
60 | /* | 61 | /* |
61 | * Number of memory banks that are power-controllable. On OMAP4430, the | 62 | * Number of memory banks that are power-controllable. On OMAP4430, the |
@@ -103,6 +104,8 @@ struct powerdomain; | |||
103 | * @state_counter: | 104 | * @state_counter: |
104 | * @timer: | 105 | * @timer: |
105 | * @state_timer: | 106 | * @state_timer: |
107 | * @_lock: spinlock used to serialize powerdomain and some clockdomain ops | ||
108 | * @_lock_flags: stored flags when @_lock is taken | ||
106 | * | 109 | * |
107 | * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. | 110 | * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. |
108 | */ | 111 | */ |
@@ -127,7 +130,8 @@ struct powerdomain { | |||
127 | unsigned state_counter[PWRDM_MAX_PWRSTS]; | 130 | unsigned state_counter[PWRDM_MAX_PWRSTS]; |
128 | unsigned ret_logic_off_counter; | 131 | unsigned ret_logic_off_counter; |
129 | unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; | 132 | unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; |
130 | 133 | spinlock_t _lock; | |
134 | unsigned long _lock_flags; | ||
131 | const u8 pwrstctrl_offs; | 135 | const u8 pwrstctrl_offs; |
132 | const u8 pwrstst_offs; | 136 | const u8 pwrstst_offs; |
133 | const u32 logicretstate_mask; | 137 | const u32 logicretstate_mask; |
@@ -162,6 +166,16 @@ struct powerdomain { | |||
162 | * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd | 166 | * @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd |
163 | * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep | 167 | * @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep |
164 | * @pwrdm_wait_transition: Wait for a pd state transition to complete | 168 | * @pwrdm_wait_transition: Wait for a pd state transition to complete |
169 | * | ||
170 | * Regarding @pwrdm_set_lowpwrstchange: On the OMAP2 and 3-family | ||
171 | * chips, a powerdomain's power state is not allowed to directly | ||
172 | * transition from one low-power state (e.g., CSWR) to another | ||
173 | * low-power state (e.g., OFF) without first waking up the | ||
174 | * powerdomain. This wastes energy. So OMAP4 chips support the | ||
175 | * ability to transition a powerdomain power state directly from one | ||
176 | * low-power state to another. The function pointed to by | ||
177 | * @pwrdm_set_lowpwrstchange is intended to configure the OMAP4 | ||
178 | * hardware powerdomain state machine to enable this feature. | ||
165 | */ | 179 | */ |
166 | struct pwrdm_ops { | 180 | struct pwrdm_ops { |
167 | int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); | 181 | int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst); |
@@ -225,15 +239,15 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm); | |||
225 | int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); | 239 | int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); |
226 | bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); | 240 | bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); |
227 | 241 | ||
228 | int pwrdm_wait_transition(struct powerdomain *pwrdm); | 242 | int pwrdm_state_switch_nolock(struct powerdomain *pwrdm); |
229 | |||
230 | int pwrdm_state_switch(struct powerdomain *pwrdm); | 243 | int pwrdm_state_switch(struct powerdomain *pwrdm); |
231 | int pwrdm_pre_transition(struct powerdomain *pwrdm); | 244 | int pwrdm_pre_transition(struct powerdomain *pwrdm); |
232 | int pwrdm_post_transition(struct powerdomain *pwrdm); | 245 | int pwrdm_post_transition(struct powerdomain *pwrdm); |
233 | int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm); | ||
234 | int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); | 246 | int pwrdm_get_context_loss_count(struct powerdomain *pwrdm); |
235 | bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); | 247 | bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm); |
236 | 248 | ||
249 | extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state); | ||
250 | |||
237 | extern void omap242x_powerdomains_init(void); | 251 | extern void omap242x_powerdomains_init(void); |
238 | extern void omap243x_powerdomains_init(void); | 252 | extern void omap243x_powerdomains_init(void); |
239 | extern void omap3xxx_powerdomains_init(void); | 253 | extern void omap3xxx_powerdomains_init(void); |
@@ -253,5 +267,7 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank); | |||
253 | extern struct powerdomain wkup_omap2_pwrdm; | 267 | extern struct powerdomain wkup_omap2_pwrdm; |
254 | extern struct powerdomain gfx_omap2_pwrdm; | 268 | extern struct powerdomain gfx_omap2_pwrdm; |
255 | 269 | ||
270 | extern void pwrdm_lock(struct powerdomain *pwrdm); | ||
271 | extern void pwrdm_unlock(struct powerdomain *pwrdm); | ||
256 | 272 | ||
257 | #endif | 273 | #endif |
diff --git a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c index d3a5399091ad..7b946f1005b1 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_3xxx_data.c | |||
@@ -54,12 +54,12 @@ struct powerdomain gfx_omap2_pwrdm = { | |||
54 | .pwrsts_mem_on = { | 54 | .pwrsts_mem_on = { |
55 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 55 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
56 | }, | 56 | }, |
57 | .voltdm = { .name = "core" }, | 57 | .voltdm = { .name = "core" }, |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct powerdomain wkup_omap2_pwrdm = { | 60 | struct powerdomain wkup_omap2_pwrdm = { |
61 | .name = "wkup_pwrdm", | 61 | .name = "wkup_pwrdm", |
62 | .prcm_offs = WKUP_MOD, | 62 | .prcm_offs = WKUP_MOD, |
63 | .pwrsts = PWRSTS_ON, | 63 | .pwrsts = PWRSTS_ON, |
64 | .voltdm = { .name = "wakeup" }, | 64 | .voltdm = { .name = "wakeup" }, |
65 | }; | 65 | }; |
diff --git a/arch/arm/mach-omap2/powerdomains2xxx_data.c b/arch/arm/mach-omap2/powerdomains2xxx_data.c index ba520d4f7c7b..578eef86fcf2 100644 --- a/arch/arm/mach-omap2/powerdomains2xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains2xxx_data.c | |||
@@ -38,7 +38,7 @@ static struct powerdomain dsp_pwrdm = { | |||
38 | .pwrsts_mem_on = { | 38 | .pwrsts_mem_on = { |
39 | [0] = PWRSTS_ON, | 39 | [0] = PWRSTS_ON, |
40 | }, | 40 | }, |
41 | .voltdm = { .name = "core" }, | 41 | .voltdm = { .name = "core" }, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | static struct powerdomain mpu_24xx_pwrdm = { | 44 | static struct powerdomain mpu_24xx_pwrdm = { |
@@ -53,13 +53,14 @@ static struct powerdomain mpu_24xx_pwrdm = { | |||
53 | .pwrsts_mem_on = { | 53 | .pwrsts_mem_on = { |
54 | [0] = PWRSTS_ON, | 54 | [0] = PWRSTS_ON, |
55 | }, | 55 | }, |
56 | .voltdm = { .name = "core" }, | 56 | .voltdm = { .name = "core" }, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static struct powerdomain core_24xx_pwrdm = { | 59 | static struct powerdomain core_24xx_pwrdm = { |
60 | .name = "core_pwrdm", | 60 | .name = "core_pwrdm", |
61 | .prcm_offs = CORE_MOD, | 61 | .prcm_offs = CORE_MOD, |
62 | .pwrsts = PWRSTS_OFF_RET_ON, | 62 | .pwrsts = PWRSTS_OFF_RET_ON, |
63 | .pwrsts_logic_ret = PWRSTS_RET, | ||
63 | .banks = 3, | 64 | .banks = 3, |
64 | .pwrsts_mem_ret = { | 65 | .pwrsts_mem_ret = { |
65 | [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */ | 66 | [0] = PWRSTS_OFF_RET, /* MEM1RETSTATE */ |
@@ -71,7 +72,7 @@ static struct powerdomain core_24xx_pwrdm = { | |||
71 | [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ | 72 | [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ |
72 | [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ | 73 | [2] = PWRSTS_OFF_RET_ON, /* MEM3ONSTATE */ |
73 | }, | 74 | }, |
74 | .voltdm = { .name = "core" }, | 75 | .voltdm = { .name = "core" }, |
75 | }; | 76 | }; |
76 | 77 | ||
77 | 78 | ||
@@ -93,7 +94,7 @@ static struct powerdomain mdm_pwrdm = { | |||
93 | .pwrsts_mem_on = { | 94 | .pwrsts_mem_on = { |
94 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 95 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
95 | }, | 96 | }, |
96 | .voltdm = { .name = "core" }, | 97 | .voltdm = { .name = "core" }, |
97 | }; | 98 | }; |
98 | 99 | ||
99 | /* | 100 | /* |
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c index 8b23d234fb55..f0e14e9efe5a 100644 --- a/arch/arm/mach-omap2/powerdomains3xxx_data.c +++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c | |||
@@ -50,7 +50,7 @@ static struct powerdomain iva2_pwrdm = { | |||
50 | [2] = PWRSTS_OFF_ON, | 50 | [2] = PWRSTS_OFF_ON, |
51 | [3] = PWRSTS_ON, | 51 | [3] = PWRSTS_ON, |
52 | }, | 52 | }, |
53 | .voltdm = { .name = "mpu_iva" }, | 53 | .voltdm = { .name = "mpu_iva" }, |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static struct powerdomain mpu_3xxx_pwrdm = { | 56 | static struct powerdomain mpu_3xxx_pwrdm = { |
@@ -66,7 +66,7 @@ static struct powerdomain mpu_3xxx_pwrdm = { | |||
66 | .pwrsts_mem_on = { | 66 | .pwrsts_mem_on = { |
67 | [0] = PWRSTS_OFF_ON, | 67 | [0] = PWRSTS_OFF_ON, |
68 | }, | 68 | }, |
69 | .voltdm = { .name = "mpu_iva" }, | 69 | .voltdm = { .name = "mpu_iva" }, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static struct powerdomain mpu_am35x_pwrdm = { | 72 | static struct powerdomain mpu_am35x_pwrdm = { |
@@ -82,7 +82,7 @@ static struct powerdomain mpu_am35x_pwrdm = { | |||
82 | .pwrsts_mem_on = { | 82 | .pwrsts_mem_on = { |
83 | [0] = PWRSTS_ON, | 83 | [0] = PWRSTS_ON, |
84 | }, | 84 | }, |
85 | .voltdm = { .name = "mpu_iva" }, | 85 | .voltdm = { .name = "mpu_iva" }, |
86 | }; | 86 | }; |
87 | 87 | ||
88 | /* | 88 | /* |
@@ -109,7 +109,7 @@ static struct powerdomain core_3xxx_pre_es3_1_pwrdm = { | |||
109 | [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ | 109 | [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ |
110 | [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ | 110 | [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ |
111 | }, | 111 | }, |
112 | .voltdm = { .name = "core" }, | 112 | .voltdm = { .name = "core" }, |
113 | }; | 113 | }; |
114 | 114 | ||
115 | static struct powerdomain core_3xxx_es3_1_pwrdm = { | 115 | static struct powerdomain core_3xxx_es3_1_pwrdm = { |
@@ -131,7 +131,7 @@ static struct powerdomain core_3xxx_es3_1_pwrdm = { | |||
131 | [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ | 131 | [0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */ |
132 | [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ | 132 | [1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */ |
133 | }, | 133 | }, |
134 | .voltdm = { .name = "core" }, | 134 | .voltdm = { .name = "core" }, |
135 | }; | 135 | }; |
136 | 136 | ||
137 | static struct powerdomain core_am35x_pwrdm = { | 137 | static struct powerdomain core_am35x_pwrdm = { |
@@ -148,7 +148,7 @@ static struct powerdomain core_am35x_pwrdm = { | |||
148 | [0] = PWRSTS_ON, /* MEM1ONSTATE */ | 148 | [0] = PWRSTS_ON, /* MEM1ONSTATE */ |
149 | [1] = PWRSTS_ON, /* MEM2ONSTATE */ | 149 | [1] = PWRSTS_ON, /* MEM2ONSTATE */ |
150 | }, | 150 | }, |
151 | .voltdm = { .name = "core" }, | 151 | .voltdm = { .name = "core" }, |
152 | }; | 152 | }; |
153 | 153 | ||
154 | static struct powerdomain dss_pwrdm = { | 154 | static struct powerdomain dss_pwrdm = { |
@@ -163,7 +163,7 @@ static struct powerdomain dss_pwrdm = { | |||
163 | .pwrsts_mem_on = { | 163 | .pwrsts_mem_on = { |
164 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 164 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
165 | }, | 165 | }, |
166 | .voltdm = { .name = "core" }, | 166 | .voltdm = { .name = "core" }, |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static struct powerdomain dss_am35x_pwrdm = { | 169 | static struct powerdomain dss_am35x_pwrdm = { |
@@ -178,7 +178,7 @@ static struct powerdomain dss_am35x_pwrdm = { | |||
178 | .pwrsts_mem_on = { | 178 | .pwrsts_mem_on = { |
179 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 179 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
180 | }, | 180 | }, |
181 | .voltdm = { .name = "core" }, | 181 | .voltdm = { .name = "core" }, |
182 | }; | 182 | }; |
183 | 183 | ||
184 | /* | 184 | /* |
@@ -199,7 +199,7 @@ static struct powerdomain sgx_pwrdm = { | |||
199 | .pwrsts_mem_on = { | 199 | .pwrsts_mem_on = { |
200 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 200 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
201 | }, | 201 | }, |
202 | .voltdm = { .name = "core" }, | 202 | .voltdm = { .name = "core" }, |
203 | }; | 203 | }; |
204 | 204 | ||
205 | static struct powerdomain sgx_am35x_pwrdm = { | 205 | static struct powerdomain sgx_am35x_pwrdm = { |
@@ -214,7 +214,7 @@ static struct powerdomain sgx_am35x_pwrdm = { | |||
214 | .pwrsts_mem_on = { | 214 | .pwrsts_mem_on = { |
215 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 215 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
216 | }, | 216 | }, |
217 | .voltdm = { .name = "core" }, | 217 | .voltdm = { .name = "core" }, |
218 | }; | 218 | }; |
219 | 219 | ||
220 | static struct powerdomain cam_pwrdm = { | 220 | static struct powerdomain cam_pwrdm = { |
@@ -229,7 +229,7 @@ static struct powerdomain cam_pwrdm = { | |||
229 | .pwrsts_mem_on = { | 229 | .pwrsts_mem_on = { |
230 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 230 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
231 | }, | 231 | }, |
232 | .voltdm = { .name = "core" }, | 232 | .voltdm = { .name = "core" }, |
233 | }; | 233 | }; |
234 | 234 | ||
235 | static struct powerdomain per_pwrdm = { | 235 | static struct powerdomain per_pwrdm = { |
@@ -244,7 +244,7 @@ static struct powerdomain per_pwrdm = { | |||
244 | .pwrsts_mem_on = { | 244 | .pwrsts_mem_on = { |
245 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 245 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
246 | }, | 246 | }, |
247 | .voltdm = { .name = "core" }, | 247 | .voltdm = { .name = "core" }, |
248 | }; | 248 | }; |
249 | 249 | ||
250 | static struct powerdomain per_am35x_pwrdm = { | 250 | static struct powerdomain per_am35x_pwrdm = { |
@@ -259,13 +259,13 @@ static struct powerdomain per_am35x_pwrdm = { | |||
259 | .pwrsts_mem_on = { | 259 | .pwrsts_mem_on = { |
260 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 260 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
261 | }, | 261 | }, |
262 | .voltdm = { .name = "core" }, | 262 | .voltdm = { .name = "core" }, |
263 | }; | 263 | }; |
264 | 264 | ||
265 | static struct powerdomain emu_pwrdm = { | 265 | static struct powerdomain emu_pwrdm = { |
266 | .name = "emu_pwrdm", | 266 | .name = "emu_pwrdm", |
267 | .prcm_offs = OMAP3430_EMU_MOD, | 267 | .prcm_offs = OMAP3430_EMU_MOD, |
268 | .voltdm = { .name = "core" }, | 268 | .voltdm = { .name = "core" }, |
269 | }; | 269 | }; |
270 | 270 | ||
271 | static struct powerdomain neon_pwrdm = { | 271 | static struct powerdomain neon_pwrdm = { |
@@ -273,7 +273,7 @@ static struct powerdomain neon_pwrdm = { | |||
273 | .prcm_offs = OMAP3430_NEON_MOD, | 273 | .prcm_offs = OMAP3430_NEON_MOD, |
274 | .pwrsts = PWRSTS_OFF_RET_ON, | 274 | .pwrsts = PWRSTS_OFF_RET_ON, |
275 | .pwrsts_logic_ret = PWRSTS_RET, | 275 | .pwrsts_logic_ret = PWRSTS_RET, |
276 | .voltdm = { .name = "mpu_iva" }, | 276 | .voltdm = { .name = "mpu_iva" }, |
277 | }; | 277 | }; |
278 | 278 | ||
279 | static struct powerdomain neon_am35x_pwrdm = { | 279 | static struct powerdomain neon_am35x_pwrdm = { |
@@ -281,7 +281,7 @@ static struct powerdomain neon_am35x_pwrdm = { | |||
281 | .prcm_offs = OMAP3430_NEON_MOD, | 281 | .prcm_offs = OMAP3430_NEON_MOD, |
282 | .pwrsts = PWRSTS_ON, | 282 | .pwrsts = PWRSTS_ON, |
283 | .pwrsts_logic_ret = PWRSTS_ON, | 283 | .pwrsts_logic_ret = PWRSTS_ON, |
284 | .voltdm = { .name = "mpu_iva" }, | 284 | .voltdm = { .name = "mpu_iva" }, |
285 | }; | 285 | }; |
286 | 286 | ||
287 | static struct powerdomain usbhost_pwrdm = { | 287 | static struct powerdomain usbhost_pwrdm = { |
@@ -303,37 +303,37 @@ static struct powerdomain usbhost_pwrdm = { | |||
303 | .pwrsts_mem_on = { | 303 | .pwrsts_mem_on = { |
304 | [0] = PWRSTS_ON, /* MEMONSTATE */ | 304 | [0] = PWRSTS_ON, /* MEMONSTATE */ |
305 | }, | 305 | }, |
306 | .voltdm = { .name = "core" }, | 306 | .voltdm = { .name = "core" }, |
307 | }; | 307 | }; |
308 | 308 | ||
309 | static struct powerdomain dpll1_pwrdm = { | 309 | static struct powerdomain dpll1_pwrdm = { |
310 | .name = "dpll1_pwrdm", | 310 | .name = "dpll1_pwrdm", |
311 | .prcm_offs = MPU_MOD, | 311 | .prcm_offs = MPU_MOD, |
312 | .voltdm = { .name = "mpu_iva" }, | 312 | .voltdm = { .name = "mpu_iva" }, |
313 | }; | 313 | }; |
314 | 314 | ||
315 | static struct powerdomain dpll2_pwrdm = { | 315 | static struct powerdomain dpll2_pwrdm = { |
316 | .name = "dpll2_pwrdm", | 316 | .name = "dpll2_pwrdm", |
317 | .prcm_offs = OMAP3430_IVA2_MOD, | 317 | .prcm_offs = OMAP3430_IVA2_MOD, |
318 | .voltdm = { .name = "mpu_iva" }, | 318 | .voltdm = { .name = "mpu_iva" }, |
319 | }; | 319 | }; |
320 | 320 | ||
321 | static struct powerdomain dpll3_pwrdm = { | 321 | static struct powerdomain dpll3_pwrdm = { |
322 | .name = "dpll3_pwrdm", | 322 | .name = "dpll3_pwrdm", |
323 | .prcm_offs = PLL_MOD, | 323 | .prcm_offs = PLL_MOD, |
324 | .voltdm = { .name = "core" }, | 324 | .voltdm = { .name = "core" }, |
325 | }; | 325 | }; |
326 | 326 | ||
327 | static struct powerdomain dpll4_pwrdm = { | 327 | static struct powerdomain dpll4_pwrdm = { |
328 | .name = "dpll4_pwrdm", | 328 | .name = "dpll4_pwrdm", |
329 | .prcm_offs = PLL_MOD, | 329 | .prcm_offs = PLL_MOD, |
330 | .voltdm = { .name = "core" }, | 330 | .voltdm = { .name = "core" }, |
331 | }; | 331 | }; |
332 | 332 | ||
333 | static struct powerdomain dpll5_pwrdm = { | 333 | static struct powerdomain dpll5_pwrdm = { |
334 | .name = "dpll5_pwrdm", | 334 | .name = "dpll5_pwrdm", |
335 | .prcm_offs = PLL_MOD, | 335 | .prcm_offs = PLL_MOD, |
336 | .voltdm = { .name = "core" }, | 336 | .voltdm = { .name = "core" }, |
337 | }; | 337 | }; |
338 | 338 | ||
339 | /* As powerdomains are added or removed above, this list must also be changed */ | 339 | /* As powerdomains are added or removed above, this list must also be changed */ |
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c index a3e121f94a86..947f6adfed0c 100644 --- a/arch/arm/mach-omap2/prm2xxx_3xxx.c +++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c | |||
@@ -210,6 +210,7 @@ int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1, | |||
210 | PM_WKDEP, (1 << clkdm2->dep_bit)); | 210 | PM_WKDEP, (1 << clkdm2->dep_bit)); |
211 | } | 211 | } |
212 | 212 | ||
213 | /* XXX Caller must hold the clkdm's powerdomain lock */ | ||
213 | int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | 214 | int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) |
214 | { | 215 | { |
215 | struct clkdm_dep *cd; | 216 | struct clkdm_dep *cd; |
@@ -221,7 +222,7 @@ int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | |||
221 | 222 | ||
222 | /* PRM accesses are slow, so minimize them */ | 223 | /* PRM accesses are slow, so minimize them */ |
223 | mask |= 1 << cd->clkdm->dep_bit; | 224 | mask |= 1 << cd->clkdm->dep_bit; |
224 | atomic_set(&cd->wkdep_usecount, 0); | 225 | cd->wkdep_usecount = 0; |
225 | } | 226 | } |
226 | 227 | ||
227 | omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | 228 | omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, |