aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clockdomain.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c177
1 files changed, 99 insertions, 78 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index f70b06ae8664..895c153c18e0 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -287,6 +287,32 @@ static void _disable_hwsup(struct clockdomain *clkdm)
287 BUG(); 287 BUG();
288} 288}
289 289
290/**
291 * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
292 * @clkdm: clockdomain that we are resolving dependencies for
293 * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
294 *
295 * Iterates through @clkdm_deps, looking up the struct clockdomain named by
296 * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
297 * No return value.
298 */
299static void _resolve_clkdm_deps(struct clockdomain *clkdm,
300 struct clkdm_dep *clkdm_deps)
301{
302 struct clkdm_dep *cd;
303
304 for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
305 if (!omap_chip_is(cd->omap_chip))
306 continue;
307 if (cd->clkdm)
308 continue;
309 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
310
311 WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
312 clkdm->name, cd->clkdm_name);
313 }
314}
315
290/* Public functions */ 316/* Public functions */
291 317
292/** 318/**
@@ -333,7 +359,10 @@ void clkdm_init(struct clockdomain **clkdms,
333 else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO) 359 else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
334 omap2_clkdm_deny_idle(clkdm); 360 omap2_clkdm_deny_idle(clkdm);
335 361
362 _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
336 clkdm_clear_all_wkdeps(clkdm); 363 clkdm_clear_all_wkdeps(clkdm);
364
365 _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
337 clkdm_clear_all_sleepdeps(clkdm); 366 clkdm_clear_all_sleepdeps(clkdm);
338 } 367 }
339} 368}
@@ -430,6 +459,7 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
430int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 459int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
431{ 460{
432 struct clkdm_dep *cd; 461 struct clkdm_dep *cd;
462 int ret = 0;
433 463
434 if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { 464 if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
435 pr_err("clockdomain: %s/%s: %s: not yet implemented\n", 465 pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
@@ -441,21 +471,26 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
441 return -EINVAL; 471 return -EINVAL;
442 472
443 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 473 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
444 if (IS_ERR(cd)) { 474 if (IS_ERR(cd))
475 ret = PTR_ERR(cd);
476
477 if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
478 ret = -EINVAL;
479
480 if (ret) {
445 pr_debug("clockdomain: hardware cannot set/clear wake up of " 481 pr_debug("clockdomain: hardware cannot set/clear wake up of "
446 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 482 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
447 return PTR_ERR(cd); 483 return ret;
448 } 484 }
449 485
450 if (atomic_inc_return(&cd->wkdep_usecount) == 1) { 486 if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
451 pr_debug("clockdomain: hardware will wake up %s when %s wakes " 487 pr_debug("clockdomain: hardware will wake up %s when %s wakes "
452 "up\n", clkdm1->name, clkdm2->name); 488 "up\n", clkdm1->name, clkdm2->name);
453 489
454 omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit), 490 ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
455 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
456 } 491 }
457 492
458 return 0; 493 return ret;
459} 494}
460 495
461/** 496/**
@@ -471,6 +506,7 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
471int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 506int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
472{ 507{
473 struct clkdm_dep *cd; 508 struct clkdm_dep *cd;
509 int ret = 0;
474 510
475 if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { 511 if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
476 pr_err("clockdomain: %s/%s: %s: not yet implemented\n", 512 pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
@@ -482,21 +518,26 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
482 return -EINVAL; 518 return -EINVAL;
483 519
484 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 520 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
485 if (IS_ERR(cd)) { 521 if (IS_ERR(cd))
522 ret = PTR_ERR(cd);
523
524 if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
525 ret = -EINVAL;
526
527 if (ret) {
486 pr_debug("clockdomain: hardware cannot set/clear wake up of " 528 pr_debug("clockdomain: hardware cannot set/clear wake up of "
487 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 529 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
488 return PTR_ERR(cd); 530 return ret;
489 } 531 }
490 532
491 if (atomic_dec_return(&cd->wkdep_usecount) == 0) { 533 if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
492 pr_debug("clockdomain: hardware will no longer wake up %s " 534 pr_debug("clockdomain: hardware will no longer wake up %s "
493 "after %s wakes up\n", clkdm1->name, clkdm2->name); 535 "after %s wakes up\n", clkdm1->name, clkdm2->name);
494 536
495 omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 537 ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
496 clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
497 } 538 }
498 539
499 return 0; 540 return ret;
500} 541}
501 542
502/** 543/**
@@ -516,6 +557,7 @@ int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
516int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 557int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
517{ 558{
518 struct clkdm_dep *cd; 559 struct clkdm_dep *cd;
560 int ret = 0;
519 561
520 if (!clkdm1 || !clkdm2) 562 if (!clkdm1 || !clkdm2)
521 return -EINVAL; 563 return -EINVAL;
@@ -527,15 +569,20 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
527 } 569 }
528 570
529 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 571 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
530 if (IS_ERR(cd)) { 572 if (IS_ERR(cd))
573 ret = PTR_ERR(cd);
574
575 if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
576 ret = -EINVAL;
577
578 if (ret) {
531 pr_debug("clockdomain: hardware cannot set/clear wake up of " 579 pr_debug("clockdomain: hardware cannot set/clear wake up of "
532 "%s when %s wakes up\n", clkdm1->name, clkdm2->name); 580 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
533 return PTR_ERR(cd); 581 return ret;
534 } 582 }
535 583
536 /* XXX It's faster to return the atomic wkdep_usecount */ 584 /* XXX It's faster to return the atomic wkdep_usecount */
537 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP, 585 return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
538 (1 << clkdm2->dep_bit));
539} 586}
540 587
541/** 588/**
@@ -550,9 +597,6 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
550 */ 597 */
551int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) 598int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
552{ 599{
553 struct clkdm_dep *cd;
554 u32 mask = 0;
555
556 if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) { 600 if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
557 pr_err("clockdomain: %s: %s: not yet implemented\n", 601 pr_err("clockdomain: %s: %s: not yet implemented\n",
558 clkdm->name, __func__); 602 clkdm->name, __func__);
@@ -562,21 +606,10 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
562 if (!clkdm) 606 if (!clkdm)
563 return -EINVAL; 607 return -EINVAL;
564 608
565 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { 609 if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
566 if (!omap_chip_is(cd->omap_chip)) 610 return -EINVAL;
567 continue;
568
569 if (!cd->clkdm && cd->clkdm_name)
570 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
571
572 /* PRM accesses are slow, so minimize them */
573 mask |= 1 << cd->clkdm->dep_bit;
574 atomic_set(&cd->wkdep_usecount, 0);
575 }
576
577 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
578 611
579 return 0; 612 return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
580} 613}
581 614
582/** 615/**
@@ -594,31 +627,33 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
594int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 627int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
595{ 628{
596 struct clkdm_dep *cd; 629 struct clkdm_dep *cd;
597 630 int ret = 0;
598 if (!cpu_is_omap34xx())
599 return -EINVAL;
600 631
601 if (!clkdm1 || !clkdm2) 632 if (!clkdm1 || !clkdm2)
602 return -EINVAL; 633 return -EINVAL;
603 634
604 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 635 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
605 if (IS_ERR(cd)) { 636 if (IS_ERR(cd))
637 ret = PTR_ERR(cd);
638
639 if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
640 ret = -EINVAL;
641
642 if (ret) {
606 pr_debug("clockdomain: hardware cannot set/clear sleep " 643 pr_debug("clockdomain: hardware cannot set/clear sleep "
607 "dependency affecting %s from %s\n", clkdm1->name, 644 "dependency affecting %s from %s\n", clkdm1->name,
608 clkdm2->name); 645 clkdm2->name);
609 return PTR_ERR(cd); 646 return ret;
610 } 647 }
611 648
612 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) { 649 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
613 pr_debug("clockdomain: will prevent %s from sleeping if %s " 650 pr_debug("clockdomain: will prevent %s from sleeping if %s "
614 "is active\n", clkdm1->name, clkdm2->name); 651 "is active\n", clkdm1->name, clkdm2->name);
615 652
616 omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit), 653 ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
617 clkdm1->pwrdm.ptr->prcm_offs,
618 OMAP3430_CM_SLEEPDEP);
619 } 654 }
620 655
621 return 0; 656 return ret;
622} 657}
623 658
624/** 659/**
@@ -636,19 +671,23 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
636int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 671int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
637{ 672{
638 struct clkdm_dep *cd; 673 struct clkdm_dep *cd;
639 674 int ret = 0;
640 if (!cpu_is_omap34xx())
641 return -EINVAL;
642 675
643 if (!clkdm1 || !clkdm2) 676 if (!clkdm1 || !clkdm2)
644 return -EINVAL; 677 return -EINVAL;
645 678
646 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 679 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
647 if (IS_ERR(cd)) { 680 if (IS_ERR(cd))
681 ret = PTR_ERR(cd);
682
683 if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
684 ret = -EINVAL;
685
686 if (ret) {
648 pr_debug("clockdomain: hardware cannot set/clear sleep " 687 pr_debug("clockdomain: hardware cannot set/clear sleep "
649 "dependency affecting %s from %s\n", clkdm1->name, 688 "dependency affecting %s from %s\n", clkdm1->name,
650 clkdm2->name); 689 clkdm2->name);
651 return PTR_ERR(cd); 690 return ret;
652 } 691 }
653 692
654 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) { 693 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
@@ -656,12 +695,10 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
656 "sleeping if %s is active\n", clkdm1->name, 695 "sleeping if %s is active\n", clkdm1->name,
657 clkdm2->name); 696 clkdm2->name);
658 697
659 omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), 698 ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
660 clkdm1->pwrdm.ptr->prcm_offs,
661 OMAP3430_CM_SLEEPDEP);
662 } 699 }
663 700
664 return 0; 701 return ret;
665} 702}
666 703
667/** 704/**
@@ -683,25 +720,27 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
683int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 720int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
684{ 721{
685 struct clkdm_dep *cd; 722 struct clkdm_dep *cd;
686 723 int ret = 0;
687 if (!cpu_is_omap34xx())
688 return -EINVAL;
689 724
690 if (!clkdm1 || !clkdm2) 725 if (!clkdm1 || !clkdm2)
691 return -EINVAL; 726 return -EINVAL;
692 727
693 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 728 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
694 if (IS_ERR(cd)) { 729 if (IS_ERR(cd))
730 ret = PTR_ERR(cd);
731
732 if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
733 ret = -EINVAL;
734
735 if (ret) {
695 pr_debug("clockdomain: hardware cannot set/clear sleep " 736 pr_debug("clockdomain: hardware cannot set/clear sleep "
696 "dependency affecting %s from %s\n", clkdm1->name, 737 "dependency affecting %s from %s\n", clkdm1->name,
697 clkdm2->name); 738 clkdm2->name);
698 return PTR_ERR(cd); 739 return ret;
699 } 740 }
700 741
701 /* XXX It's faster to return the atomic sleepdep_usecount */ 742 /* XXX It's faster to return the atomic sleepdep_usecount */
702 return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, 743 return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
703 OMAP3430_CM_SLEEPDEP,
704 (1 << clkdm2->dep_bit));
705} 744}
706 745
707/** 746/**
@@ -716,31 +755,13 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
716 */ 755 */
717int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) 756int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
718{ 757{
719 struct clkdm_dep *cd;
720 u32 mask = 0;
721
722 if (!cpu_is_omap34xx())
723 return -EINVAL;
724
725 if (!clkdm) 758 if (!clkdm)
726 return -EINVAL; 759 return -EINVAL;
727 760
728 for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { 761 if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
729 if (!omap_chip_is(cd->omap_chip)) 762 return -EINVAL;
730 continue;
731
732 if (!cd->clkdm && cd->clkdm_name)
733 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
734
735 /* PRM accesses are slow, so minimize them */
736 mask |= 1 << cd->clkdm->dep_bit;
737 atomic_set(&cd->sleepdep_usecount, 0);
738 }
739
740 omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
741 OMAP3430_CM_SLEEPDEP);
742 763
743 return 0; 764 return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
744} 765}
745 766
746/** 767/**