diff options
author | Paul Walmsley <paul@pwsan.com> | 2012-09-23 17:28:28 -0600 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2012-09-23 17:28:28 -0600 |
commit | b71c72178e24118214f21567a15adcad61b4238a (patch) | |
tree | 65d550588f5c76db32905c6ceddc2dc20ef0a1cd /arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | |
parent | 5c3e4ec48586f6dfb482f1c524748948ba14021e (diff) | |
download | op-kernel-dev-b71c72178e24118214f21567a15adcad61b4238a.zip op-kernel-dev-b71c72178e24118214f21567a15adcad61b4238a.tar.gz |
ARM: OMAP2+: clockdomain/hwmod: add workaround for EMU clockdomain idle problems
The idle status of the IP blocks and clocks inside the EMU clockdomain
isn't taken into account by the PRCM hardware when deciding whether
the clockdomain is idle. Add a workaround flag in the clockdomain
code, CLKDM_MISSING_IDLE_REPORTING, to deal with this problem, and add
the code necessary to support it.
If CLKDM_MISSING_IDLE_REPORTING is set on a clockdomain, the
clockdomain will be forced active whenever an IP block inside that
clockdomain is in use, even if the clockdomain supports
hardware-supervised idle. When the kernel indicates that the last
active IP block inside the clockdomain is no longer used, the
clockdomain will be forced idle, or, if that mode is not supported in
the hardware, it will be placed into hardware-supervised idle.
This patch is an equal collaboration with Jon Hunter
<jon-hunter@ti.com>. Ming Lei <ming.lei@canonical.com>, Will Deacon
<will.deacon@arm.com>, Madhav Vij <mvij@ti.com>, Kevin Hilman
<khilman@ti.com>, Benoît Cousson <b-cousson@ti.com>, and Santosh
Shilimkar <santosh.shilimkar@ti.com> all made essential contributions
to the understanding of EMU clockdomain power management on OMAP.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Jon Hunter <jon-hunter@ti.com>
Cc: Ming Lei <ming.lei@canonical.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Madhav Vij <mvij@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Cc: Benoît Cousson <b-cousson@ti.com>
Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
Tested-by: Jon Hunter <jon-hunter@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain2xxx_3xxx.c')
-rw-r--r-- | arch/arm/mach-omap2/clockdomain2xxx_3xxx.c | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c index f99e65c..9a7792a 100644 --- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c +++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c @@ -162,6 +162,19 @@ static void _disable_hwsup(struct clockdomain *clkdm) clkdm->clktrctrl_mask); } +static int omap3_clkdm_sleep(struct clockdomain *clkdm) +{ + omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + return 0; +} + +static int omap3_clkdm_wakeup(struct clockdomain *clkdm) +{ + omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs, + clkdm->clktrctrl_mask); + return 0; +} static int omap2_clkdm_clk_enable(struct clockdomain *clkdm) { @@ -170,6 +183,17 @@ static int omap2_clkdm_clk_enable(struct clockdomain *clkdm) if (!clkdm->clktrctrl_mask) return 0; + /* + * The CLKDM_MISSING_IDLE_REPORTING flag documentation has + * more details on the unpleasant problem this is working + * around + */ + if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING && + !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { + _enable_hwsup(clkdm); + return 0; + } + hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -193,6 +217,17 @@ static int omap2_clkdm_clk_disable(struct clockdomain *clkdm) if (!clkdm->clktrctrl_mask) return 0; + /* + * The CLKDM_MISSING_IDLE_REPORTING flag documentation has + * more details on the unpleasant problem this is working + * around + */ + if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) && + (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { + omap3_clkdm_wakeup(clkdm); + return 0; + } + hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs, clkdm->clktrctrl_mask); @@ -209,20 +244,6 @@ static int omap2_clkdm_clk_disable(struct clockdomain *clkdm) return 0; } -static int omap3_clkdm_sleep(struct clockdomain *clkdm) -{ - omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - return 0; -} - -static int omap3_clkdm_wakeup(struct clockdomain *clkdm) -{ - omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs, - clkdm->clktrctrl_mask); - return 0; -} - static void omap3_clkdm_allow_idle(struct clockdomain *clkdm) { if (atomic_read(&clkdm->usecount) > 0) |