diff options
| -rw-r--r-- | arch/arm/mach-omap2/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 177 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/clockdomain.h | 6 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 130 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c | 9 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/io.c | 6 |
6 files changed, 246 insertions, 84 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ee72a9787bf1..759d9ebd79c6 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile | |||
| @@ -102,8 +102,10 @@ obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \ | |||
| 102 | 102 | ||
| 103 | # PRCM clockdomain control | 103 | # PRCM clockdomain control |
| 104 | obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \ | 104 | obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \ |
| 105 | clockdomain2xxx_3xxx.o \ | ||
| 105 | clockdomains2xxx_3xxx_data.o | 106 | clockdomains2xxx_3xxx_data.o |
| 106 | obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \ | 107 | obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \ |
| 108 | clockdomain2xxx_3xxx.o \ | ||
| 107 | clockdomains2xxx_3xxx_data.o | 109 | clockdomains2xxx_3xxx_data.o |
| 108 | obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \ | 110 | obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \ |
| 109 | clockdomains44xx_data.o | 111 | clockdomains44xx_data.o |
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 | */ | ||
| 299 | static 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) | |||
| 430 | int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 459 | int 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) | |||
| 471 | int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 506 | int 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) | |||
| 516 | int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 557 | int 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 | */ |
| 551 | int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | 598 | int 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) | |||
| 594 | int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 627 | int 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) | |||
| 636 | int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 671 | int 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) | |||
| 683 | int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) | 720 | int 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 | */ |
| 717 | int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | 756 | int 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 | /** |
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h index 71ad265cf133..90b6d6a50862 100644 --- a/arch/arm/mach-omap2/clockdomain.h +++ b/arch/arm/mach-omap2/clockdomain.h | |||
| @@ -176,7 +176,11 @@ int omap2_clkdm_sleep(struct clockdomain *clkdm); | |||
| 176 | int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); | 176 | int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); |
| 177 | int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk); | 177 | int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk); |
| 178 | 178 | ||
| 179 | extern void __init omap2_clockdomains_init(void); | 179 | extern void __init omap2xxx_clockdomains_init(void); |
| 180 | extern void __init omap3xxx_clockdomains_init(void); | ||
| 180 | extern void __init omap44xx_clockdomains_init(void); | 181 | extern void __init omap44xx_clockdomains_init(void); |
| 181 | 182 | ||
| 183 | extern struct clkdm_ops omap2_clkdm_operations; | ||
| 184 | extern struct clkdm_ops omap3_clkdm_operations; | ||
| 185 | |||
| 182 | #endif | 186 | #endif |
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c new file mode 100644 index 000000000000..a1fd6fd5a466 --- /dev/null +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | /* | ||
| 2 | * OMAP2 and OMAP3 clockdomain control | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008-2010 Texas Instruments, Inc. | ||
| 5 | * Copyright (C) 2008-2010 Nokia Corporation | ||
| 6 | * | ||
| 7 | * Derived from mach-omap2/clockdomain.c written by Paul Walmsley | ||
| 8 | * Rajendra Nayak <rnayak@ti.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/types.h> | ||
| 16 | #include <plat/prcm.h> | ||
| 17 | #include "prm.h" | ||
| 18 | #include "prm2xxx_3xxx.h" | ||
| 19 | #include "cm.h" | ||
| 20 | #include "cm2xxx_3xxx.h" | ||
| 21 | #include "cm-regbits-24xx.h" | ||
| 22 | #include "cm-regbits-34xx.h" | ||
| 23 | #include "clockdomain.h" | ||
| 24 | |||
| 25 | static int omap2_clkdm_add_wkdep(struct clockdomain *clkdm1, | ||
| 26 | struct clockdomain *clkdm2) | ||
| 27 | { | ||
| 28 | omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit), | ||
| 29 | clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
| 30 | return 0; | ||
| 31 | } | ||
| 32 | |||
| 33 | static int omap2_clkdm_del_wkdep(struct clockdomain *clkdm1, | ||
| 34 | struct clockdomain *clkdm2) | ||
| 35 | { | ||
| 36 | omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | ||
| 37 | clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP); | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | static int omap2_clkdm_read_wkdep(struct clockdomain *clkdm1, | ||
| 42 | struct clockdomain *clkdm2) | ||
| 43 | { | ||
| 44 | return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, | ||
| 45 | PM_WKDEP, (1 << clkdm2->dep_bit)); | ||
| 46 | } | ||
| 47 | |||
| 48 | static int omap2_clkdm_clear_all_wkdeps(struct clockdomain *clkdm) | ||
| 49 | { | ||
| 50 | struct clkdm_dep *cd; | ||
| 51 | u32 mask = 0; | ||
| 52 | |||
| 53 | for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) { | ||
| 54 | if (!omap_chip_is(cd->omap_chip)) | ||
| 55 | continue; | ||
| 56 | if (!cd->clkdm) | ||
| 57 | continue; /* only happens if data is erroneous */ | ||
| 58 | |||
| 59 | /* PRM accesses are slow, so minimize them */ | ||
| 60 | mask |= 1 << cd->clkdm->dep_bit; | ||
| 61 | atomic_set(&cd->wkdep_usecount, 0); | ||
| 62 | } | ||
| 63 | |||
| 64 | omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | ||
| 65 | PM_WKDEP); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int omap3_clkdm_add_sleepdep(struct clockdomain *clkdm1, | ||
| 70 | struct clockdomain *clkdm2) | ||
| 71 | { | ||
| 72 | omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit), | ||
| 73 | clkdm1->pwrdm.ptr->prcm_offs, | ||
| 74 | OMAP3430_CM_SLEEPDEP); | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static int omap3_clkdm_del_sleepdep(struct clockdomain *clkdm1, | ||
| 79 | struct clockdomain *clkdm2) | ||
| 80 | { | ||
| 81 | omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit), | ||
| 82 | clkdm1->pwrdm.ptr->prcm_offs, | ||
| 83 | OMAP3430_CM_SLEEPDEP); | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int omap3_clkdm_read_sleepdep(struct clockdomain *clkdm1, | ||
| 88 | struct clockdomain *clkdm2) | ||
| 89 | { | ||
| 90 | return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, | ||
| 91 | OMAP3430_CM_SLEEPDEP, (1 << clkdm2->dep_bit)); | ||
| 92 | } | ||
| 93 | |||
| 94 | static int omap3_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) | ||
| 95 | { | ||
| 96 | struct clkdm_dep *cd; | ||
| 97 | u32 mask = 0; | ||
| 98 | |||
| 99 | for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) { | ||
| 100 | if (!omap_chip_is(cd->omap_chip)) | ||
| 101 | continue; | ||
| 102 | if (!cd->clkdm) | ||
| 103 | continue; /* only happens if data is erroneous */ | ||
| 104 | |||
| 105 | /* PRM accesses are slow, so minimize them */ | ||
| 106 | mask |= 1 << cd->clkdm->dep_bit; | ||
| 107 | atomic_set(&cd->sleepdep_usecount, 0); | ||
| 108 | } | ||
| 109 | omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, | ||
| 110 | OMAP3430_CM_SLEEPDEP); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | struct clkdm_ops omap2_clkdm_operations = { | ||
| 115 | .clkdm_add_wkdep = omap2_clkdm_add_wkdep, | ||
| 116 | .clkdm_del_wkdep = omap2_clkdm_del_wkdep, | ||
| 117 | .clkdm_read_wkdep = omap2_clkdm_read_wkdep, | ||
| 118 | .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, | ||
| 119 | }; | ||
| 120 | |||
| 121 | struct clkdm_ops omap3_clkdm_operations = { | ||
| 122 | .clkdm_add_wkdep = omap2_clkdm_add_wkdep, | ||
| 123 | .clkdm_del_wkdep = omap2_clkdm_del_wkdep, | ||
| 124 | .clkdm_read_wkdep = omap2_clkdm_read_wkdep, | ||
| 125 | .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps, | ||
| 126 | .clkdm_add_sleepdep = omap3_clkdm_add_sleepdep, | ||
| 127 | .clkdm_del_sleepdep = omap3_clkdm_del_sleepdep, | ||
| 128 | .clkdm_read_sleepdep = omap3_clkdm_read_sleepdep, | ||
| 129 | .clkdm_clear_all_sleepdeps = omap3_clkdm_clear_all_sleepdeps, | ||
| 130 | }; | ||
diff --git a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c index e2a959eab312..ffdfe54f3264 100644 --- a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c +++ b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c | |||
| @@ -854,7 +854,12 @@ static struct clockdomain *clockdomains_omap2[] __initdata = { | |||
| 854 | NULL, | 854 | NULL, |
| 855 | }; | 855 | }; |
| 856 | 856 | ||
| 857 | void __init omap2_clockdomains_init(void) | 857 | void __init omap2xxx_clockdomains_init(void) |
| 858 | { | 858 | { |
| 859 | clkdm_init(clockdomains_omap2, clkdm_autodeps, NULL); | 859 | clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap2_clkdm_operations); |
| 860 | } | ||
| 861 | |||
| 862 | void __init omap3xxx_clockdomains_init(void) | ||
| 863 | { | ||
| 864 | clkdm_init(clockdomains_omap2, clkdm_autodeps, &omap3_clkdm_operations); | ||
| 860 | } | 865 | } |
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index b8b49e4ae928..03f71ec3cd82 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c | |||
| @@ -357,15 +357,15 @@ void __init omap2_init_common_infrastructure(void) | |||
| 357 | 357 | ||
| 358 | if (cpu_is_omap242x()) { | 358 | if (cpu_is_omap242x()) { |
| 359 | omap2xxx_powerdomains_init(); | 359 | omap2xxx_powerdomains_init(); |
| 360 | omap2_clockdomains_init(); | 360 | omap2xxx_clockdomains_init(); |
| 361 | omap2420_hwmod_init(); | 361 | omap2420_hwmod_init(); |
| 362 | } else if (cpu_is_omap243x()) { | 362 | } else if (cpu_is_omap243x()) { |
| 363 | omap2xxx_powerdomains_init(); | 363 | omap2xxx_powerdomains_init(); |
| 364 | omap2_clockdomains_init(); | 364 | omap2xxx_clockdomains_init(); |
| 365 | omap2430_hwmod_init(); | 365 | omap2430_hwmod_init(); |
| 366 | } else if (cpu_is_omap34xx()) { | 366 | } else if (cpu_is_omap34xx()) { |
| 367 | omap3xxx_powerdomains_init(); | 367 | omap3xxx_powerdomains_init(); |
| 368 | omap2_clockdomains_init(); | 368 | omap3xxx_clockdomains_init(); |
| 369 | omap3xxx_hwmod_init(); | 369 | omap3xxx_hwmod_init(); |
| 370 | } else if (cpu_is_omap44xx()) { | 370 | } else if (cpu_is_omap44xx()) { |
| 371 | omap44xx_powerdomains_init(); | 371 | omap44xx_powerdomains_init(); |
