diff options
author | Olof Johansson <olof@lixom.net> | 2012-11-30 01:49:30 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2012-11-30 01:49:30 -0500 |
commit | 9121dfca73d81fa886f15610cac2bf372391f3eb (patch) | |
tree | 9aff09bb821f632ea6b7a1117c094d662eb2ecd3 /arch/arm/mach-omap2/omap_hwmod.c | |
parent | 77f9db89c928773e5fb1df0df4d13d5cc8abd178 (diff) | |
parent | 8b9c1ac2e11a9fb3a5a8860fb7570ff7633aa7f7 (diff) |
Merge tag 'omap-for-v3.8/devel-prcm-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/pm2
From Tony Lindgren:
omap prcm changes via Paul Walmsley <paul@pwsan.com>:
Some miscellaneous OMAP hwmod changes for 3.8, along with a PRM
change needed for one of the hwmod patches to function.
Basic test logs for this branch on top of Tony's
omap-for-v3.8/clock branch at commit
558a0780b0a04862a678f7823215424b4e5501f9 are here:
http://www.pwsan.com/omap/testlogs/hwmod_devel_a_3.8/20121121161522/
However, omap-for-v3.8/clock at 558a0780 does not include some fixes
that are needed for a successful test. With several reverts,
fixes, and workarounds applied, the following test logs were
obtained:
http://www.pwsan.com/omap/testlogs/TEST_hwmod_devel_a_3.8/20121121162719/
which indicate that the series tests cleanly.
* tag 'omap-for-v3.8/devel-prcm-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (49 commits)
ARM: OMAP2+: omap_device: Correct resource handling for DT boot
ARM: OMAP2+: hwmod: Add possibility to count hwmod resources based on type
ARM: OMAP2+: hwmod: Add support for per hwmod/module context lost count
ARM: OMAP2+: PRM: initialize some PRM functions early
ARM: OMAP2+: clock: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP2xxx: clock: drop obsolete clock data
ARM: OMAP2: clock: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP3+: DPLL: drop !CONFIG_COMMON_CLK sections
ARM: AM33xx: clock: drop obsolete clock data
ARM: OMAP3xxx: clk: drop obsolete clock data
ARM: OMAP3: clock: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP44xx: clock: drop obsolete clock data
ARM: OMAP4: clock: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP: hwmod: Cleanup !CONFIG_COMMON_CLK parts
ARM: OMAP: clock: Switch to COMMON clk
ARM: OMAP2: clock: Add 24xx data using common struct clk
ARM: OMAP3: clock: Add 3xxx data using common struct clk
ARM: AM33XX: clock: add clock data in common clock format
ARM: OMAP4: clock: Add 44xx data using common struct clk
ARM: OMAP2+: clock: add OMAP CCF convenience macros to mach-omap2/clock.h
...
Some context conflicts due to nearby changes resolved in
arch/arm/mach-omap2/io.c.
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 145 |
1 files changed, 113 insertions, 32 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b3b00f43dd7c..4653efb87a27 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -130,7 +130,7 @@ | |||
130 | #include <linux/kernel.h> | 130 | #include <linux/kernel.h> |
131 | #include <linux/errno.h> | 131 | #include <linux/errno.h> |
132 | #include <linux/io.h> | 132 | #include <linux/io.h> |
133 | #include <linux/clk.h> | 133 | #include <linux/clk-provider.h> |
134 | #include <linux/delay.h> | 134 | #include <linux/delay.h> |
135 | #include <linux/err.h> | 135 | #include <linux/err.h> |
136 | #include <linux/list.h> | 136 | #include <linux/list.h> |
@@ -187,6 +187,8 @@ struct omap_hwmod_soc_ops { | |||
187 | int (*is_hardreset_asserted)(struct omap_hwmod *oh, | 187 | int (*is_hardreset_asserted)(struct omap_hwmod *oh, |
188 | struct omap_hwmod_rst_info *ohri); | 188 | struct omap_hwmod_rst_info *ohri); |
189 | int (*init_clkdm)(struct omap_hwmod *oh); | 189 | int (*init_clkdm)(struct omap_hwmod *oh); |
190 | void (*update_context_lost)(struct omap_hwmod *oh); | ||
191 | int (*get_context_lost)(struct omap_hwmod *oh); | ||
190 | }; | 192 | }; |
191 | 193 | ||
192 | /* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */ | 194 | /* soc_ops: adapts the omap_hwmod code to the currently-booted SoC */ |
@@ -646,6 +648,19 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) | |||
646 | return 0; | 648 | return 0; |
647 | } | 649 | } |
648 | 650 | ||
651 | static struct clockdomain *_get_clkdm(struct omap_hwmod *oh) | ||
652 | { | ||
653 | struct clk_hw_omap *clk; | ||
654 | |||
655 | if (oh->clkdm) { | ||
656 | return oh->clkdm; | ||
657 | } else if (oh->_clk) { | ||
658 | clk = to_clk_hw_omap(__clk_get_hw(oh->_clk)); | ||
659 | return clk->clkdm; | ||
660 | } | ||
661 | return NULL; | ||
662 | } | ||
663 | |||
649 | /** | 664 | /** |
650 | * _add_initiator_dep: prevent @oh from smart-idling while @init_oh is active | 665 | * _add_initiator_dep: prevent @oh from smart-idling while @init_oh is active |
651 | * @oh: struct omap_hwmod * | 666 | * @oh: struct omap_hwmod * |
@@ -661,13 +676,18 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v) | |||
661 | */ | 676 | */ |
662 | static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | 677 | static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) |
663 | { | 678 | { |
664 | if (!oh->_clk) | 679 | struct clockdomain *clkdm, *init_clkdm; |
680 | |||
681 | clkdm = _get_clkdm(oh); | ||
682 | init_clkdm = _get_clkdm(init_oh); | ||
683 | |||
684 | if (!clkdm || !init_clkdm) | ||
665 | return -EINVAL; | 685 | return -EINVAL; |
666 | 686 | ||
667 | if (oh->_clk->clkdm && oh->_clk->clkdm->flags & CLKDM_NO_AUTODEPS) | 687 | if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS) |
668 | return 0; | 688 | return 0; |
669 | 689 | ||
670 | return clkdm_add_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); | 690 | return clkdm_add_sleepdep(clkdm, init_clkdm); |
671 | } | 691 | } |
672 | 692 | ||
673 | /** | 693 | /** |
@@ -685,13 +705,18 @@ static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | |||
685 | */ | 705 | */ |
686 | static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | 706 | static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) |
687 | { | 707 | { |
688 | if (!oh->_clk) | 708 | struct clockdomain *clkdm, *init_clkdm; |
709 | |||
710 | clkdm = _get_clkdm(oh); | ||
711 | init_clkdm = _get_clkdm(init_oh); | ||
712 | |||
713 | if (!clkdm || !init_clkdm) | ||
689 | return -EINVAL; | 714 | return -EINVAL; |
690 | 715 | ||
691 | if (oh->_clk->clkdm && oh->_clk->clkdm->flags & CLKDM_NO_AUTODEPS) | 716 | if (clkdm && clkdm->flags & CLKDM_NO_AUTODEPS) |
692 | return 0; | 717 | return 0; |
693 | 718 | ||
694 | return clkdm_del_sleepdep(oh->_clk->clkdm, init_oh->_clk->clkdm); | 719 | return clkdm_del_sleepdep(clkdm, init_clkdm); |
695 | } | 720 | } |
696 | 721 | ||
697 | /** | 722 | /** |
@@ -725,7 +750,7 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
725 | */ | 750 | */ |
726 | clk_prepare(oh->_clk); | 751 | clk_prepare(oh->_clk); |
727 | 752 | ||
728 | if (!oh->_clk->clkdm) | 753 | if (!_get_clkdm(oh)) |
729 | pr_debug("omap_hwmod: %s: missing clockdomain for %s.\n", | 754 | pr_debug("omap_hwmod: %s: missing clockdomain for %s.\n", |
730 | oh->name, oh->main_clk); | 755 | oh->name, oh->main_clk); |
731 | 756 | ||
@@ -1308,6 +1333,7 @@ static void _enable_sysc(struct omap_hwmod *oh) | |||
1308 | u8 idlemode, sf; | 1333 | u8 idlemode, sf; |
1309 | u32 v; | 1334 | u32 v; |
1310 | bool clkdm_act; | 1335 | bool clkdm_act; |
1336 | struct clockdomain *clkdm; | ||
1311 | 1337 | ||
1312 | if (!oh->class->sysc) | 1338 | if (!oh->class->sysc) |
1313 | return; | 1339 | return; |
@@ -1327,11 +1353,9 @@ static void _enable_sysc(struct omap_hwmod *oh) | |||
1327 | v = oh->_sysc_cache; | 1353 | v = oh->_sysc_cache; |
1328 | sf = oh->class->sysc->sysc_flags; | 1354 | sf = oh->class->sysc->sysc_flags; |
1329 | 1355 | ||
1356 | clkdm = _get_clkdm(oh); | ||
1330 | if (sf & SYSC_HAS_SIDLEMODE) { | 1357 | if (sf & SYSC_HAS_SIDLEMODE) { |
1331 | clkdm_act = ((oh->clkdm && | 1358 | clkdm_act = (clkdm && clkdm->flags & CLKDM_ACTIVE_WITH_MPU); |
1332 | oh->clkdm->flags & CLKDM_ACTIVE_WITH_MPU) || | ||
1333 | (oh->_clk && oh->_clk->clkdm && | ||
1334 | oh->_clk->clkdm->flags & CLKDM_ACTIVE_WITH_MPU)); | ||
1335 | if (clkdm_act && !(oh->class->sysc->idlemodes & | 1359 | if (clkdm_act && !(oh->class->sysc->idlemodes & |
1336 | (SIDLE_SMART | SIDLE_SMART_WKUP))) | 1360 | (SIDLE_SMART | SIDLE_SMART_WKUP))) |
1337 | idlemode = HWMOD_IDLEMODE_FORCE; | 1361 | idlemode = HWMOD_IDLEMODE_FORCE; |
@@ -1533,11 +1557,12 @@ static int _init_clocks(struct omap_hwmod *oh, void *data) | |||
1533 | 1557 | ||
1534 | pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); | 1558 | pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); |
1535 | 1559 | ||
1560 | if (soc_ops.init_clkdm) | ||
1561 | ret |= soc_ops.init_clkdm(oh); | ||
1562 | |||
1536 | ret |= _init_main_clk(oh); | 1563 | ret |= _init_main_clk(oh); |
1537 | ret |= _init_interface_clks(oh); | 1564 | ret |= _init_interface_clks(oh); |
1538 | ret |= _init_opt_clks(oh); | 1565 | ret |= _init_opt_clks(oh); |
1539 | if (soc_ops.init_clkdm) | ||
1540 | ret |= soc_ops.init_clkdm(oh); | ||
1541 | 1566 | ||
1542 | if (!ret) | 1567 | if (!ret) |
1543 | oh->_state = _HWMOD_STATE_CLKS_INITED; | 1568 | oh->_state = _HWMOD_STATE_CLKS_INITED; |
@@ -1992,6 +2017,42 @@ static void _reconfigure_io_chain(void) | |||
1992 | } | 2017 | } |
1993 | 2018 | ||
1994 | /** | 2019 | /** |
2020 | * _omap4_update_context_lost - increment hwmod context loss counter if | ||
2021 | * hwmod context was lost, and clear hardware context loss reg | ||
2022 | * @oh: hwmod to check for context loss | ||
2023 | * | ||
2024 | * If the PRCM indicates that the hwmod @oh lost context, increment | ||
2025 | * our in-memory context loss counter, and clear the RM_*_CONTEXT | ||
2026 | * bits. No return value. | ||
2027 | */ | ||
2028 | static void _omap4_update_context_lost(struct omap_hwmod *oh) | ||
2029 | { | ||
2030 | if (oh->prcm.omap4.flags & HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT) | ||
2031 | return; | ||
2032 | |||
2033 | if (!prm_was_any_context_lost_old(oh->clkdm->pwrdm.ptr->prcm_partition, | ||
2034 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2035 | oh->prcm.omap4.context_offs)) | ||
2036 | return; | ||
2037 | |||
2038 | oh->prcm.omap4.context_lost_counter++; | ||
2039 | prm_clear_context_loss_flags_old(oh->clkdm->pwrdm.ptr->prcm_partition, | ||
2040 | oh->clkdm->pwrdm.ptr->prcm_offs, | ||
2041 | oh->prcm.omap4.context_offs); | ||
2042 | } | ||
2043 | |||
2044 | /** | ||
2045 | * _omap4_get_context_lost - get context loss counter for a hwmod | ||
2046 | * @oh: hwmod to get context loss counter for | ||
2047 | * | ||
2048 | * Returns the in-memory context loss counter for a hwmod. | ||
2049 | */ | ||
2050 | static int _omap4_get_context_lost(struct omap_hwmod *oh) | ||
2051 | { | ||
2052 | return oh->prcm.omap4.context_lost_counter; | ||
2053 | } | ||
2054 | |||
2055 | /** | ||
1995 | * _enable - enable an omap_hwmod | 2056 | * _enable - enable an omap_hwmod |
1996 | * @oh: struct omap_hwmod * | 2057 | * @oh: struct omap_hwmod * |
1997 | * | 2058 | * |
@@ -2074,6 +2135,9 @@ static int _enable(struct omap_hwmod *oh) | |||
2074 | if (soc_ops.enable_module) | 2135 | if (soc_ops.enable_module) |
2075 | soc_ops.enable_module(oh); | 2136 | soc_ops.enable_module(oh); |
2076 | 2137 | ||
2138 | if (soc_ops.update_context_lost) | ||
2139 | soc_ops.update_context_lost(oh); | ||
2140 | |||
2077 | r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) : | 2141 | r = (soc_ops.wait_target_ready) ? soc_ops.wait_target_ready(oh) : |
2078 | -EINVAL; | 2142 | -EINVAL; |
2079 | if (!r) { | 2143 | if (!r) { |
@@ -3398,7 +3462,7 @@ int omap_hwmod_reset(struct omap_hwmod *oh) | |||
3398 | /** | 3462 | /** |
3399 | * omap_hwmod_count_resources - count number of struct resources needed by hwmod | 3463 | * omap_hwmod_count_resources - count number of struct resources needed by hwmod |
3400 | * @oh: struct omap_hwmod * | 3464 | * @oh: struct omap_hwmod * |
3401 | * @res: pointer to the first element of an array of struct resource to fill | 3465 | * @flags: Type of resources to include when counting (IRQ/DMA/MEM) |
3402 | * | 3466 | * |
3403 | * Count the number of struct resource array elements necessary to | 3467 | * Count the number of struct resource array elements necessary to |
3404 | * contain omap_hwmod @oh resources. Intended to be called by code | 3468 | * contain omap_hwmod @oh resources. Intended to be called by code |
@@ -3411,20 +3475,25 @@ int omap_hwmod_reset(struct omap_hwmod *oh) | |||
3411 | * resource IDs. | 3475 | * resource IDs. |
3412 | * | 3476 | * |
3413 | */ | 3477 | */ |
3414 | int omap_hwmod_count_resources(struct omap_hwmod *oh) | 3478 | int omap_hwmod_count_resources(struct omap_hwmod *oh, unsigned long flags) |
3415 | { | 3479 | { |
3416 | struct omap_hwmod_ocp_if *os; | 3480 | int ret = 0; |
3417 | struct list_head *p; | ||
3418 | int ret; | ||
3419 | int i = 0; | ||
3420 | 3481 | ||
3421 | ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh); | 3482 | if (flags & IORESOURCE_IRQ) |
3483 | ret += _count_mpu_irqs(oh); | ||
3422 | 3484 | ||
3423 | p = oh->slave_ports.next; | 3485 | if (flags & IORESOURCE_DMA) |
3486 | ret += _count_sdma_reqs(oh); | ||
3424 | 3487 | ||
3425 | while (i < oh->slaves_cnt) { | 3488 | if (flags & IORESOURCE_MEM) { |
3426 | os = _fetch_next_ocp_if(&p, &i); | 3489 | int i = 0; |
3427 | ret += _count_ocp_if_addr_spaces(os); | 3490 | struct omap_hwmod_ocp_if *os; |
3491 | struct list_head *p = oh->slave_ports.next; | ||
3492 | |||
3493 | while (i < oh->slaves_cnt) { | ||
3494 | os = _fetch_next_ocp_if(&p, &i); | ||
3495 | ret += _count_ocp_if_addr_spaces(os); | ||
3496 | } | ||
3428 | } | 3497 | } |
3429 | 3498 | ||
3430 | return ret; | 3499 | return ret; |
@@ -3591,10 +3660,15 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) | |||
3591 | { | 3660 | { |
3592 | struct clk *c; | 3661 | struct clk *c; |
3593 | struct omap_hwmod_ocp_if *oi; | 3662 | struct omap_hwmod_ocp_if *oi; |
3663 | struct clockdomain *clkdm; | ||
3664 | struct clk_hw_omap *clk; | ||
3594 | 3665 | ||
3595 | if (!oh) | 3666 | if (!oh) |
3596 | return NULL; | 3667 | return NULL; |
3597 | 3668 | ||
3669 | if (oh->clkdm) | ||
3670 | return oh->clkdm->pwrdm.ptr; | ||
3671 | |||
3598 | if (oh->_clk) { | 3672 | if (oh->_clk) { |
3599 | c = oh->_clk; | 3673 | c = oh->_clk; |
3600 | } else { | 3674 | } else { |
@@ -3604,11 +3678,12 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh) | |||
3604 | c = oi->_clk; | 3678 | c = oi->_clk; |
3605 | } | 3679 | } |
3606 | 3680 | ||
3607 | if (!c->clkdm) | 3681 | clk = to_clk_hw_omap(__clk_get_hw(c)); |
3682 | clkdm = clk->clkdm; | ||
3683 | if (!clkdm) | ||
3608 | return NULL; | 3684 | return NULL; |
3609 | 3685 | ||
3610 | return c->clkdm->pwrdm.ptr; | 3686 | return clkdm->pwrdm.ptr; |
3611 | |||
3612 | } | 3687 | } |
3613 | 3688 | ||
3614 | /** | 3689 | /** |
@@ -3913,17 +3988,21 @@ ohsps_unlock: | |||
3913 | * omap_hwmod_get_context_loss_count - get lost context count | 3988 | * omap_hwmod_get_context_loss_count - get lost context count |
3914 | * @oh: struct omap_hwmod * | 3989 | * @oh: struct omap_hwmod * |
3915 | * | 3990 | * |
3916 | * Query the powerdomain of of @oh to get the context loss | 3991 | * Returns the context loss count of associated @oh |
3917 | * count for this device. | 3992 | * upon success, or zero if no context loss data is available. |
3918 | * | 3993 | * |
3919 | * Returns the context loss count of the powerdomain assocated with @oh | 3994 | * On OMAP4, this queries the per-hwmod context loss register, |
3920 | * upon success, or zero if no powerdomain exists for @oh. | 3995 | * assuming one exists. If not, or on OMAP2/3, this queries the |
3996 | * enclosing powerdomain context loss count. | ||
3921 | */ | 3997 | */ |
3922 | int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) | 3998 | int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) |
3923 | { | 3999 | { |
3924 | struct powerdomain *pwrdm; | 4000 | struct powerdomain *pwrdm; |
3925 | int ret = 0; | 4001 | int ret = 0; |
3926 | 4002 | ||
4003 | if (soc_ops.get_context_lost) | ||
4004 | return soc_ops.get_context_lost(oh); | ||
4005 | |||
3927 | pwrdm = omap_hwmod_get_pwrdm(oh); | 4006 | pwrdm = omap_hwmod_get_pwrdm(oh); |
3928 | if (pwrdm) | 4007 | if (pwrdm) |
3929 | ret = pwrdm_get_context_loss_count(pwrdm); | 4008 | ret = pwrdm_get_context_loss_count(pwrdm); |
@@ -4038,6 +4117,8 @@ void __init omap_hwmod_init(void) | |||
4038 | soc_ops.deassert_hardreset = _omap4_deassert_hardreset; | 4117 | soc_ops.deassert_hardreset = _omap4_deassert_hardreset; |
4039 | soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; | 4118 | soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted; |
4040 | soc_ops.init_clkdm = _init_clkdm; | 4119 | soc_ops.init_clkdm = _init_clkdm; |
4120 | soc_ops.update_context_lost = _omap4_update_context_lost; | ||
4121 | soc_ops.get_context_lost = _omap4_get_context_lost; | ||
4041 | } else if (soc_is_am33xx()) { | 4122 | } else if (soc_is_am33xx()) { |
4042 | soc_ops.enable_module = _am33xx_enable_module; | 4123 | soc_ops.enable_module = _am33xx_enable_module; |
4043 | soc_ops.disable_module = _am33xx_disable_module; | 4124 | soc_ops.disable_module = _am33xx_disable_module; |