aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clockdomain.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/mach-omap2/clockdomain.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c489
1 files changed, 153 insertions, 336 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 5d80cb897489..6cb6c03293df 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -13,7 +13,6 @@
13 */ 13 */
14#undef DEBUG 14#undef DEBUG
15 15
16#include <linux/module.h>
17#include <linux/kernel.h> 16#include <linux/kernel.h>
18#include <linux/device.h> 17#include <linux/device.h>
19#include <linux/list.h> 18#include <linux/list.h>
@@ -27,14 +26,8 @@
27 26
28#include <linux/bitops.h> 27#include <linux/bitops.h>
29 28
30#include "prm.h"
31#include "prm-regbits-24xx.h"
32#include "cm.h"
33
34#include <plat/clock.h> 29#include <plat/clock.h>
35#include <plat/powerdomain.h> 30#include "clockdomain.h"
36#include <plat/clockdomain.h>
37#include <plat/prcm.h>
38 31
39/* clkdm_list contains all registered struct clockdomains */ 32/* clkdm_list contains all registered struct clockdomains */
40static LIST_HEAD(clkdm_list); 33static LIST_HEAD(clkdm_list);
@@ -42,6 +35,7 @@ static LIST_HEAD(clkdm_list);
42/* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ 35/* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
43static struct clkdm_autodep *autodeps; 36static struct clkdm_autodep *autodeps;
44 37
38static struct clkdm_ops *arch_clkdm;
45 39
46/* Private functions */ 40/* Private functions */
47 41
@@ -141,6 +135,9 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
141 * clockdomain is in hardware-supervised mode. Meant to be called 135 * clockdomain is in hardware-supervised mode. Meant to be called
142 * once at clockdomain layer initialization, since these should remain 136 * once at clockdomain layer initialization, since these should remain
143 * fixed for a particular architecture. No return value. 137 * fixed for a particular architecture. No return value.
138 *
139 * XXX autodeps are deprecated and should be removed at the earliest
140 * opportunity
144 */ 141 */
145static void _autodep_lookup(struct clkdm_autodep *autodep) 142static void _autodep_lookup(struct clkdm_autodep *autodep)
146{ 143{
@@ -168,12 +165,15 @@ static void _autodep_lookup(struct clkdm_autodep *autodep)
168 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' 165 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
169 * in hardware-supervised mode. Meant to be called from clock framework 166 * in hardware-supervised mode. Meant to be called from clock framework
170 * when a clock inside clockdomain 'clkdm' is enabled. No return value. 167 * when a clock inside clockdomain 'clkdm' is enabled. No return value.
168 *
169 * XXX autodeps are deprecated and should be removed at the earliest
170 * opportunity
171 */ 171 */
172static void _clkdm_add_autodeps(struct clockdomain *clkdm) 172void _clkdm_add_autodeps(struct clockdomain *clkdm)
173{ 173{
174 struct clkdm_autodep *autodep; 174 struct clkdm_autodep *autodep;
175 175
176 if (!autodeps) 176 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
177 return; 177 return;
178 178
179 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 179 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
@@ -199,12 +199,15 @@ static void _clkdm_add_autodeps(struct clockdomain *clkdm)
199 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' 199 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
200 * in hardware-supervised mode. Meant to be called from clock framework 200 * in hardware-supervised mode. Meant to be called from clock framework
201 * when a clock inside clockdomain 'clkdm' is disabled. No return value. 201 * when a clock inside clockdomain 'clkdm' is disabled. No return value.
202 *
203 * XXX autodeps are deprecated and should be removed at the earliest
204 * opportunity
202 */ 205 */
203static void _clkdm_del_autodeps(struct clockdomain *clkdm) 206void _clkdm_del_autodeps(struct clockdomain *clkdm)
204{ 207{
205 struct clkdm_autodep *autodep; 208 struct clkdm_autodep *autodep;
206 209
207 if (!autodeps) 210 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
208 return; 211 return;
209 212
210 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 213 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
@@ -223,138 +226,39 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm)
223 } 226 }
224} 227}
225 228
226/*
227 * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit
228 * @clkdm: struct clockdomain *
229 * @enable: int 0 to disable, 1 to enable
230 *
231 * Internal helper for actually switching the bit that controls hwsup
232 * idle transitions for clkdm.
233 */
234static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
235{
236 u32 bits, v;
237
238 if (cpu_is_omap24xx()) {
239 if (enable)
240 bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
241 else
242 bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
243 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
244 if (enable)
245 bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
246 else
247 bits = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
248 } else {
249 BUG();
250 }
251
252 bits = bits << __ffs(clkdm->clktrctrl_mask);
253
254 v = __raw_readl(clkdm->clkstctrl_reg);
255 v &= ~(clkdm->clktrctrl_mask);
256 v |= bits;
257 __raw_writel(v, clkdm->clkstctrl_reg);
258
259}
260
261/** 229/**
262 * _init_wkdep_usecount - initialize wkdep usecounts to match hardware 230 * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
263 * @clkdm: clockdomain to initialize wkdep usecounts 231 * @clkdm: clockdomain that we are resolving dependencies for
232 * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
264 * 233 *
265 * Initialize the wakeup dependency usecount variables for clockdomain @clkdm. 234 * Iterates through @clkdm_deps, looking up the struct clockdomain named by
266 * If a wakeup dependency is present in the hardware, the usecount will be 235 * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
267 * set to 1; otherwise, it will be set to 0. Software should clear all 236 * No return value.
268 * software wakeup dependencies prior to calling this function if it wishes
269 * to ensure that all usecounts start at 0. No return value.
270 */ 237 */
271static void _init_wkdep_usecount(struct clockdomain *clkdm) 238static void _resolve_clkdm_deps(struct clockdomain *clkdm,
239 struct clkdm_dep *clkdm_deps)
272{ 240{
273 u32 v;
274 struct clkdm_dep *cd; 241 struct clkdm_dep *cd;
275 242
276 if (!clkdm->wkdep_srcs) 243 for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
277 return;
278
279 for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
280 if (!omap_chip_is(cd->omap_chip)) 244 if (!omap_chip_is(cd->omap_chip))
281 continue; 245 continue;
282 246 if (cd->clkdm)
283 if (!cd->clkdm && cd->clkdm_name)
284 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
285
286 if (!cd->clkdm) {
287 WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
288 "found\n", clkdm->name, cd->clkdm_name);
289 continue; 247 continue;
290 } 248 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
291
292 v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
293 PM_WKDEP,
294 (1 << cd->clkdm->dep_bit));
295 249
296 if (v) 250 WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
297 pr_debug("clockdomain: %s: wakeup dependency already " 251 clkdm->name, cd->clkdm_name);
298 "set to wake up when %s wakes\n",
299 clkdm->name, cd->clkdm->name);
300
301 atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
302 } 252 }
303} 253}
304 254
305/**
306 * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
307 * @clkdm: clockdomain to initialize sleepdep usecounts
308 *
309 * Initialize the sleep dependency usecount variables for clockdomain @clkdm.
310 * If a sleep dependency is present in the hardware, the usecount will be
311 * set to 1; otherwise, it will be set to 0. Software should clear all
312 * software sleep dependencies prior to calling this function if it wishes
313 * to ensure that all usecounts start at 0. No return value.
314 */
315static void _init_sleepdep_usecount(struct clockdomain *clkdm)
316{
317 u32 v;
318 struct clkdm_dep *cd;
319
320 if (!cpu_is_omap34xx())
321 return;
322
323 if (!clkdm->sleepdep_srcs)
324 return;
325
326 for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
327 if (!omap_chip_is(cd->omap_chip))
328 continue;
329
330 if (!cd->clkdm && cd->clkdm_name)
331 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
332
333 if (!cd->clkdm) {
334 WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
335 "not found\n", clkdm->name, cd->clkdm_name);
336 continue;
337 }
338
339 v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
340 OMAP3430_CM_SLEEPDEP,
341 (1 << cd->clkdm->dep_bit));
342
343 if (v)
344 pr_debug("clockdomain: %s: sleep dependency already "
345 "set to prevent from idling until %s "
346 "idles\n", clkdm->name, cd->clkdm->name);
347
348 atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
349 }
350};
351
352/* Public functions */ 255/* Public functions */
353 256
354/** 257/**
355 * clkdm_init - set up the clockdomain layer 258 * clkdm_init - set up the clockdomain layer
356 * @clkdms: optional pointer to an array of clockdomains to register 259 * @clkdms: optional pointer to an array of clockdomains to register
357 * @init_autodeps: optional pointer to an array of autodeps to register 260 * @init_autodeps: optional pointer to an array of autodeps to register
261 * @custom_funcs: func pointers for arch specific implementations
358 * 262 *
359 * Set up internal state. If a pointer to an array of clockdomains 263 * Set up internal state. If a pointer to an array of clockdomains
360 * @clkdms was supplied, loop through the list of clockdomains, 264 * @clkdms was supplied, loop through the list of clockdomains,
@@ -363,12 +267,18 @@ static void _init_sleepdep_usecount(struct clockdomain *clkdm)
363 * @init_autodeps was provided, register those. No return value. 267 * @init_autodeps was provided, register those. No return value.
364 */ 268 */
365void clkdm_init(struct clockdomain **clkdms, 269void clkdm_init(struct clockdomain **clkdms,
366 struct clkdm_autodep *init_autodeps) 270 struct clkdm_autodep *init_autodeps,
271 struct clkdm_ops *custom_funcs)
367{ 272{
368 struct clockdomain **c = NULL; 273 struct clockdomain **c = NULL;
369 struct clockdomain *clkdm; 274 struct clockdomain *clkdm;
370 struct clkdm_autodep *autodep = NULL; 275 struct clkdm_autodep *autodep = NULL;
371 276
277 if (!custom_funcs)
278 WARN(1, "No custom clkdm functions registered\n");
279 else
280 arch_clkdm = custom_funcs;
281
372 if (clkdms) 282 if (clkdms)
373 for (c = clkdms; *c; c++) 283 for (c = clkdms; *c; c++)
374 _clkdm_register(*c); 284 _clkdm_register(*c);
@@ -379,12 +289,20 @@ void clkdm_init(struct clockdomain **clkdms,
379 _autodep_lookup(autodep); 289 _autodep_lookup(autodep);
380 290
381 /* 291 /*
382 * Ensure that the *dep_usecount registers reflect the current 292 * Put all clockdomains into software-supervised mode; PM code
383 * state of the PRCM. 293 * should later enable hardware-supervised mode as appropriate
384 */ 294 */
385 list_for_each_entry(clkdm, &clkdm_list, node) { 295 list_for_each_entry(clkdm, &clkdm_list, node) {
386 _init_wkdep_usecount(clkdm); 296 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
387 _init_sleepdep_usecount(clkdm); 297 clkdm_wakeup(clkdm);
298 else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
299 clkdm_deny_idle(clkdm);
300
301 _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
302 clkdm_clear_all_wkdeps(clkdm);
303
304 _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
305 clkdm_clear_all_sleepdeps(clkdm);
388 } 306 }
389} 307}
390 308
@@ -480,26 +398,32 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
480int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 398int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
481{ 399{
482 struct clkdm_dep *cd; 400 struct clkdm_dep *cd;
401 int ret = 0;
483 402
484 if (!clkdm1 || !clkdm2) 403 if (!clkdm1 || !clkdm2)
485 return -EINVAL; 404 return -EINVAL;
486 405
487 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 406 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
488 if (IS_ERR(cd)) { 407 if (IS_ERR(cd))
408 ret = PTR_ERR(cd);
409
410 if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
411 ret = -EINVAL;
412
413 if (ret) {
489 pr_debug("clockdomain: hardware cannot set/clear wake up of " 414 pr_debug("clockdomain: hardware cannot set/clear wake up of "
490 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 415 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
491 return PTR_ERR(cd); 416 return ret;
492 } 417 }
493 418
494 if (atomic_inc_return(&cd->wkdep_usecount) == 1) { 419 if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
495 pr_debug("clockdomain: hardware will wake up %s when %s wakes " 420 pr_debug("clockdomain: hardware will wake up %s when %s wakes "
496 "up\n", clkdm1->name, clkdm2->name); 421 "up\n", clkdm1->name, clkdm2->name);
497 422
498 prm_set_mod_reg_bits((1 << clkdm2->dep_bit), 423 ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
499 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
500 } 424 }
501 425
502 return 0; 426 return ret;
503} 427}
504 428
505/** 429/**
@@ -515,26 +439,32 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
515int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 439int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
516{ 440{
517 struct clkdm_dep *cd; 441 struct clkdm_dep *cd;
442 int ret = 0;
518 443
519 if (!clkdm1 || !clkdm2) 444 if (!clkdm1 || !clkdm2)
520 return -EINVAL; 445 return -EINVAL;
521 446
522 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 447 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
523 if (IS_ERR(cd)) { 448 if (IS_ERR(cd))
449 ret = PTR_ERR(cd);
450
451 if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
452 ret = -EINVAL;
453
454 if (ret) {
524 pr_debug("clockdomain: hardware cannot set/clear wake up of " 455 pr_debug("clockdomain: hardware cannot set/clear wake up of "
525 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 456 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
526 return PTR_ERR(cd); 457 return ret;
527 } 458 }
528 459
529 if (atomic_dec_return(&cd->wkdep_usecount) == 0) { 460 if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
530 pr_debug("clockdomain: hardware will no longer wake up %s " 461 pr_debug("clockdomain: hardware will no longer wake up %s "
531 "after %s wakes up\n", clkdm1->name, clkdm2->name); 462 "after %s wakes up\n", clkdm1->name, clkdm2->name);
532 463
533 prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 464 ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
534 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
535 } 465 }
536 466
537 return 0; 467 return ret;
538} 468}
539 469
540/** 470/**
@@ -554,20 +484,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
554int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 484int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
555{ 485{
556 struct clkdm_dep *cd; 486 struct clkdm_dep *cd;
487 int ret = 0;
557 488
558 if (!clkdm1 || !clkdm2) 489 if (!clkdm1 || !clkdm2)
559 return -EINVAL; 490 return -EINVAL;
560 491
561 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 492 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
562 if (IS_ERR(cd)) { 493 if (IS_ERR(cd))
494 ret = PTR_ERR(cd);
495
496 if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
497 ret = -EINVAL;
498
499 if (ret) {
563 pr_debug("clockdomain: hardware cannot set/clear wake up of " 500 pr_debug("clockdomain: hardware cannot set/clear wake up of "
564 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 501 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
565 return PTR_ERR(cd); 502 return ret;
566 } 503 }
567 504
568 /* XXX It's faster to return the atomic wkdep_usecount */ 505 /* XXX It's faster to return the atomic wkdep_usecount */
569 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, 506 return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
570 (1 << clkdm2->dep_bit));
571} 507}
572 508
573/** 509/**
@@ -582,24 +518,13 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
582 */ 518 */
583int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) 519int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
584{ 520{
585 struct clkdm_dep *cd;
586 u32 mask = 0;
587
588 if (!clkdm) 521 if (!clkdm)
589 return -EINVAL; 522 return -EINVAL;
590 523
591 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { 524 if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
592 if (!omap_chip_is(cd->omap_chip)) 525 return -EINVAL;
593 continue;
594
595 /* PRM accesses are slow, so minimize them */
596 mask |= 1 << cd->clkdm->dep_bit;
597 atomic_set(&cd->wkdep_usecount, 0);
598 }
599
600 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
601 526
602 return 0; 527 return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
603} 528}
604 529
605/** 530/**
@@ -617,31 +542,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
617int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 542int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
618{ 543{
619 struct clkdm_dep *cd; 544 struct clkdm_dep *cd;
620 545 int ret = 0;
621 if (!cpu_is_omap34xx())
622 return -EINVAL;
623 546
624 if (!clkdm1 || !clkdm2) 547 if (!clkdm1 || !clkdm2)
625 return -EINVAL; 548 return -EINVAL;
626 549
627 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 550 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
628 if (IS_ERR(cd)) { 551 if (IS_ERR(cd))
552 ret = PTR_ERR(cd);
553
554 if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
555 ret = -EINVAL;
556
557 if (ret) {
629 pr_debug("clockdomain: hardware cannot set/clear sleep " 558 pr_debug("clockdomain: hardware cannot set/clear sleep "
630 "dependency affecting %s from %s\n", clkdm1->name, 559 "dependency affecting %s from %s\n", clkdm1->name,
631 clkdm2->name); 560 clkdm2->name);
632 return PTR_ERR(cd); 561 return ret;
633 } 562 }
634 563
635 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { 564 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
636 pr_debug("clockdomain: will prevent %s from sleeping if %s " 565 pr_debug("clockdomain: will prevent %s from sleeping if %s "
637 "is active\n", clkdm1->name, clkdm2->name); 566 "is active\n", clkdm1->name, clkdm2->name);
638 567
639 cm_set_mod_reg_bits((1 << clkdm2->dep_bit), 568 ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
640 clkdm1->pwrdm.ptr->prcm_offs,
641 OMAP3430_CM_SLEEPDEP);
642 } 569 }
643 570
644 return 0; 571 return ret;
645} 572}
646 573
647/** 574/**
@@ -659,19 +586,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
659int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 586int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
660{ 587{
661 struct clkdm_dep *cd; 588 struct clkdm_dep *cd;
662 589 int ret = 0;
663 if (!cpu_is_omap34xx())
664 return -EINVAL;
665 590
666 if (!clkdm1 || !clkdm2) 591 if (!clkdm1 || !clkdm2)
667 return -EINVAL; 592 return -EINVAL;
668 593
669 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 594 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
670 if (IS_ERR(cd)) { 595 if (IS_ERR(cd))
596 ret = PTR_ERR(cd);
597
598 if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
599 ret = -EINVAL;
600
601 if (ret) {
671 pr_debug("clockdomain: hardware cannot set/clear sleep " 602 pr_debug("clockdomain: hardware cannot set/clear sleep "
672 "dependency affecting %s from %s\n", clkdm1->name, 603 "dependency affecting %s from %s\n", clkdm1->name,
673 clkdm2->name); 604 clkdm2->name);
674 return PTR_ERR(cd); 605 return ret;
675 } 606 }
676 607
677 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { 608 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
@@ -679,12 +610,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
679 "sleeping if %s is active\n", clkdm1->name, 610 "sleeping if %s is active\n", clkdm1->name,
680 clkdm2->name); 611 clkdm2->name);
681 612
682 cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 613 ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
683 clkdm1->pwrdm.ptr->prcm_offs,
684 OMAP3430_CM_SLEEPDEP);
685 } 614 }
686 615
687 return 0; 616 return ret;
688} 617}
689 618
690/** 619/**
@@ -706,25 +635,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
706int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 635int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
707{ 636{
708 struct clkdm_dep *cd; 637 struct clkdm_dep *cd;
709 638 int ret = 0;
710 if (!cpu_is_omap34xx())
711 return -EINVAL;
712 639
713 if (!clkdm1 || !clkdm2) 640 if (!clkdm1 || !clkdm2)
714 return -EINVAL; 641 return -EINVAL;
715 642
716 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 643 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
717 if (IS_ERR(cd)) { 644 if (IS_ERR(cd))
645 ret = PTR_ERR(cd);
646
647 if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
648 ret = -EINVAL;
649
650 if (ret) {
718 pr_debug("clockdomain: hardware cannot set/clear sleep " 651 pr_debug("clockdomain: hardware cannot set/clear sleep "
719 "dependency affecting %s from %s\n", clkdm1->name, 652 "dependency affecting %s from %s\n", clkdm1->name,
720 clkdm2->name); 653 clkdm2->name);
721 return PTR_ERR(cd); 654 return ret;
722 } 655 }
723 656
724 /* XXX It's faster to return the atomic sleepdep_usecount */ 657 /* XXX It's faster to return the atomic sleepdep_usecount */
725 return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, 658 return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
726 OMAP3430_CM_SLEEPDEP,
727 (1 << clkdm2->dep_bit));
728} 659}
729 660
730/** 661/**
@@ -739,54 +670,17 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
739 */ 670 */
740int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) 671int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
741{ 672{
742 struct clkdm_dep *cd;
743 u32 mask = 0;
744
745 if (!cpu_is_omap34xx())
746 return -EINVAL;
747
748 if (!clkdm) 673 if (!clkdm)
749 return -EINVAL; 674 return -EINVAL;
750 675
751 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { 676 if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
752 if (!omap_chip_is(cd->omap_chip))
753 continue;
754
755 /* PRM accesses are slow, so minimize them */
756 mask |= 1 << cd->clkdm->dep_bit;
757 atomic_set(&cd->sleepdep_usecount, 0);
758 }
759
760 prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
761 OMAP3430_CM_SLEEPDEP);
762
763 return 0;
764}
765
766/**
767 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
768 * @clkdm: struct clkdm * of a clockdomain
769 *
770 * Return the clockdomain @clkdm current state transition mode from the
771 * corresponding domain CM_CLKSTCTRL register. Returns -EINVAL if @clkdm
772 * is NULL or the current mode upon success.
773 */
774static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
775{
776 u32 v;
777
778 if (!clkdm)
779 return -EINVAL; 677 return -EINVAL;
780 678
781 v = __raw_readl(clkdm->clkstctrl_reg); 679 return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
782 v &= clkdm->clktrctrl_mask;
783 v >>= __ffs(clkdm->clktrctrl_mask);
784
785 return v;
786} 680}
787 681
788/** 682/**
789 * omap2_clkdm_sleep - force clockdomain sleep transition 683 * clkdm_sleep - force clockdomain sleep transition
790 * @clkdm: struct clockdomain * 684 * @clkdm: struct clockdomain *
791 * 685 *
792 * Instruct the CM to force a sleep transition on the specified 686 * Instruct the CM to force a sleep transition on the specified
@@ -794,7 +688,7 @@ static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
794 * clockdomain does not support software-initiated sleep; 0 upon 688 * clockdomain does not support software-initiated sleep; 0 upon
795 * success. 689 * success.
796 */ 690 */
797int omap2_clkdm_sleep(struct clockdomain *clkdm) 691int clkdm_sleep(struct clockdomain *clkdm)
798{ 692{
799 if (!clkdm) 693 if (!clkdm)
800 return -EINVAL; 694 return -EINVAL;
@@ -805,32 +699,16 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm)
805 return -EINVAL; 699 return -EINVAL;
806 } 700 }
807 701
808 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 702 if (!arch_clkdm || !arch_clkdm->clkdm_sleep)
809 703 return -EINVAL;
810 if (cpu_is_omap24xx()) {
811
812 cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
813 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
814
815 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
816
817 u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP <<
818 __ffs(clkdm->clktrctrl_mask));
819
820 u32 v = __raw_readl(clkdm->clkstctrl_reg);
821 v &= ~(clkdm->clktrctrl_mask);
822 v |= bits;
823 __raw_writel(v, clkdm->clkstctrl_reg);
824 704
825 } else { 705 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
826 BUG();
827 };
828 706
829 return 0; 707 return arch_clkdm->clkdm_sleep(clkdm);
830} 708}
831 709
832/** 710/**
833 * omap2_clkdm_wakeup - force clockdomain wakeup transition 711 * clkdm_wakeup - force clockdomain wakeup transition
834 * @clkdm: struct clockdomain * 712 * @clkdm: struct clockdomain *
835 * 713 *
836 * Instruct the CM to force a wakeup transition on the specified 714 * Instruct the CM to force a wakeup transition on the specified
@@ -838,7 +716,7 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm)
838 * clockdomain does not support software-controlled wakeup; 0 upon 716 * clockdomain does not support software-controlled wakeup; 0 upon
839 * success. 717 * success.
840 */ 718 */
841int omap2_clkdm_wakeup(struct clockdomain *clkdm) 719int clkdm_wakeup(struct clockdomain *clkdm)
842{ 720{
843 if (!clkdm) 721 if (!clkdm)
844 return -EINVAL; 722 return -EINVAL;
@@ -849,32 +727,16 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
849 return -EINVAL; 727 return -EINVAL;
850 } 728 }
851 729
852 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 730 if (!arch_clkdm || !arch_clkdm->clkdm_wakeup)
853 731 return -EINVAL;
854 if (cpu_is_omap24xx()) {
855
856 cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
857 clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
858
859 } else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
860
861 u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP <<
862 __ffs(clkdm->clktrctrl_mask));
863
864 u32 v = __raw_readl(clkdm->clkstctrl_reg);
865 v &= ~(clkdm->clktrctrl_mask);
866 v |= bits;
867 __raw_writel(v, clkdm->clkstctrl_reg);
868 732
869 } else { 733 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
870 BUG();
871 };
872 734
873 return 0; 735 return arch_clkdm->clkdm_wakeup(clkdm);
874} 736}
875 737
876/** 738/**
877 * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm 739 * clkdm_allow_idle - enable hwsup idle transitions for clkdm
878 * @clkdm: struct clockdomain * 740 * @clkdm: struct clockdomain *
879 * 741 *
880 * Allow the hardware to automatically switch the clockdomain @clkdm into 742 * Allow the hardware to automatically switch the clockdomain @clkdm into
@@ -883,7 +745,7 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
883 * framework, wkdep/sleepdep autodependencies are added; this is so 745 * framework, wkdep/sleepdep autodependencies are added; this is so
884 * device drivers can read and write to the device. No return value. 746 * device drivers can read and write to the device. No return value.
885 */ 747 */
886void omap2_clkdm_allow_idle(struct clockdomain *clkdm) 748void clkdm_allow_idle(struct clockdomain *clkdm)
887{ 749{
888 if (!clkdm) 750 if (!clkdm)
889 return; 751 return;
@@ -894,28 +756,18 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
894 return; 756 return;
895 } 757 }
896 758
759 if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle)
760 return;
761
897 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 762 pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
898 clkdm->name); 763 clkdm->name);
899 764
900 /* 765 arch_clkdm->clkdm_allow_idle(clkdm);
901 * XXX This should be removed once TI adds wakeup/sleep
902 * dependency code and data for OMAP4.
903 */
904 if (cpu_is_omap44xx()) {
905 WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
906 "support is not yet implemented\n");
907 } else {
908 if (atomic_read(&clkdm->usecount) > 0)
909 _clkdm_add_autodeps(clkdm);
910 }
911
912 _omap2_clkdm_set_hwsup(clkdm, 1);
913
914 pwrdm_clkdm_state_switch(clkdm); 766 pwrdm_clkdm_state_switch(clkdm);
915} 767}
916 768
917/** 769/**
918 * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm 770 * clkdm_deny_idle - disable hwsup idle transitions for clkdm
919 * @clkdm: struct clockdomain * 771 * @clkdm: struct clockdomain *
920 * 772 *
921 * Prevent the hardware from automatically switching the clockdomain 773 * Prevent the hardware from automatically switching the clockdomain
@@ -923,7 +775,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
923 * downstream clocks enabled in the clock framework, wkdep/sleepdep 775 * downstream clocks enabled in the clock framework, wkdep/sleepdep
924 * autodependencies are removed. No return value. 776 * autodependencies are removed. No return value.
925 */ 777 */
926void omap2_clkdm_deny_idle(struct clockdomain *clkdm) 778void clkdm_deny_idle(struct clockdomain *clkdm)
927{ 779{
928 if (!clkdm) 780 if (!clkdm)
929 return; 781 return;
@@ -934,29 +786,20 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
934 return; 786 return;
935 } 787 }
936 788
789 if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle)
790 return;
791
937 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 792 pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
938 clkdm->name); 793 clkdm->name);
939 794
940 _omap2_clkdm_set_hwsup(clkdm, 0); 795 arch_clkdm->clkdm_deny_idle(clkdm);
941
942 /*
943 * XXX This should be removed once TI adds wakeup/sleep
944 * dependency code and data for OMAP4.
945 */
946 if (cpu_is_omap44xx()) {
947 WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
948 "support is not yet implemented\n");
949 } else {
950 if (atomic_read(&clkdm->usecount) > 0)
951 _clkdm_del_autodeps(clkdm);
952 }
953} 796}
954 797
955 798
956/* Clockdomain-to-clock framework interface code */ 799/* Clockdomain-to-clock framework interface code */
957 800
958/** 801/**
959 * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm 802 * clkdm_clk_enable - add an enabled downstream clock to this clkdm
960 * @clkdm: struct clockdomain * 803 * @clkdm: struct clockdomain *
961 * @clk: struct clk * of the enabled downstream clock 804 * @clk: struct clk * of the enabled downstream clock
962 * 805 *
@@ -969,10 +812,8 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
969 * by on-chip processors. Returns -EINVAL if passed null pointers; 812 * by on-chip processors. Returns -EINVAL if passed null pointers;
970 * returns 0 upon success or if the clockdomain is in hwsup idle mode. 813 * returns 0 upon success or if the clockdomain is in hwsup idle mode.
971 */ 814 */
972int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) 815int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
973{ 816{
974 int v;
975
976 /* 817 /*
977 * XXX Rewrite this code to maintain a list of enabled 818 * XXX Rewrite this code to maintain a list of enabled
978 * downstream clocks for debugging purposes? 819 * downstream clocks for debugging purposes?
@@ -981,6 +822,9 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
981 if (!clkdm || !clk) 822 if (!clkdm || !clk)
982 return -EINVAL; 823 return -EINVAL;
983 824
825 if (!arch_clkdm || !arch_clkdm->clkdm_clk_enable)
826 return -EINVAL;
827
984 if (atomic_inc_return(&clkdm->usecount) > 1) 828 if (atomic_inc_return(&clkdm->usecount) > 1)
985 return 0; 829 return 0;
986 830
@@ -989,21 +833,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
989 pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name, 833 pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
990 clk->name); 834 clk->name);
991 835
992 if (!clkdm->clkstctrl_reg) 836 arch_clkdm->clkdm_clk_enable(clkdm);
993 return 0;
994
995 v = omap2_clkdm_clktrctrl_read(clkdm);
996
997 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
998 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
999 /* Disable HW transitions when we are changing deps */
1000 _omap2_clkdm_set_hwsup(clkdm, 0);
1001 _clkdm_add_autodeps(clkdm);
1002 _omap2_clkdm_set_hwsup(clkdm, 1);
1003 } else {
1004 omap2_clkdm_wakeup(clkdm);
1005 }
1006
1007 pwrdm_wait_transition(clkdm->pwrdm.ptr); 837 pwrdm_wait_transition(clkdm->pwrdm.ptr);
1008 pwrdm_clkdm_state_switch(clkdm); 838 pwrdm_clkdm_state_switch(clkdm);
1009 839
@@ -1011,7 +841,7 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
1011} 841}
1012 842
1013/** 843/**
1014 * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm 844 * clkdm_clk_disable - remove an enabled downstream clock from this clkdm
1015 * @clkdm: struct clockdomain * 845 * @clkdm: struct clockdomain *
1016 * @clk: struct clk * of the disabled downstream clock 846 * @clk: struct clk * of the disabled downstream clock
1017 * 847 *
@@ -1024,10 +854,8 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
1024 * is enabled; or returns 0 upon success or if the clockdomain is in 854 * is enabled; or returns 0 upon success or if the clockdomain is in
1025 * hwsup idle mode. 855 * hwsup idle mode.
1026 */ 856 */
1027int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 857int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
1028{ 858{
1029 int v;
1030
1031 /* 859 /*
1032 * XXX Rewrite this code to maintain a list of enabled 860 * XXX Rewrite this code to maintain a list of enabled
1033 * downstream clocks for debugging purposes? 861 * downstream clocks for debugging purposes?
@@ -1036,6 +864,9 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
1036 if (!clkdm || !clk) 864 if (!clkdm || !clk)
1037 return -EINVAL; 865 return -EINVAL;
1038 866
867 if (!arch_clkdm || !arch_clkdm->clkdm_clk_disable)
868 return -EINVAL;
869
1039#ifdef DEBUG 870#ifdef DEBUG
1040 if (atomic_read(&clkdm->usecount) == 0) { 871 if (atomic_read(&clkdm->usecount) == 0) {
1041 WARN_ON(1); /* underflow */ 872 WARN_ON(1); /* underflow */
@@ -1051,21 +882,7 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
1051 pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name, 882 pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
1052 clk->name); 883 clk->name);
1053 884
1054 if (!clkdm->clkstctrl_reg) 885 arch_clkdm->clkdm_clk_disable(clkdm);
1055 return 0;
1056
1057 v = omap2_clkdm_clktrctrl_read(clkdm);
1058
1059 if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
1060 (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
1061 /* Disable HW transitions when we are changing deps */
1062 _omap2_clkdm_set_hwsup(clkdm, 0);
1063 _clkdm_del_autodeps(clkdm);
1064 _omap2_clkdm_set_hwsup(clkdm, 1);
1065 } else {
1066 omap2_clkdm_sleep(clkdm);
1067 }
1068
1069 pwrdm_clkdm_state_switch(clkdm); 886 pwrdm_clkdm_state_switch(clkdm);
1070 887
1071 return 0; 888 return 0;