aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-11-30 01:49:30 -0500
committerOlof Johansson <olof@lixom.net>2012-11-30 01:49:30 -0500
commit9121dfca73d81fa886f15610cac2bf372391f3eb (patch)
tree9aff09bb821f632ea6b7a1117c094d662eb2ecd3 /arch/arm/mach-omap2/omap_hwmod.c
parent77f9db89c928773e5fb1df0df4d13d5cc8abd178 (diff)
parent8b9c1ac2e11a9fb3a5a8860fb7570ff7633aa7f7 (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.c145
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
651static 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 */
662static int _add_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) 677static 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 */
686static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) 706static 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 */
2028static 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 */
2050static 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 */
3414int omap_hwmod_count_resources(struct omap_hwmod *oh) 3478int 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 */
3922int omap_hwmod_get_context_loss_count(struct omap_hwmod *oh) 3998int 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;