summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/powergate.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-08-08 21:02:51 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:24 -0800
commit311dd1c318b70e93bcefec15456a10ff2b9eb0ff (patch)
tree4846c9ee915e1e7ca9700055eb6253ad5472907c /arch/arm/mach-tegra/powergate.c
parent6611d8bec94a5b8b667bd8ca2d8205b4416b7e7e (diff)
ARM: tegra: power: Wait for power-gate toggle completion
Bug 857044 Original-Change-Id: I80c8c2183426fbaa8b7d5316c09709c9de7ea39d Reviewed-on: http://git-master/r/45970 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: Karan Jhavar <kjhavar@nvidia.com> Reviewed-by: Narendra Damahe <ndamahe@nvidia.com> Reviewed-by: Krishna Reddy <vdumpa@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Rebase-Id: Rd8c46b56d4ca22e05e40c664329d64f7bd6710f7
Diffstat (limited to 'arch/arm/mach-tegra/powergate.c')
-rw-r--r--arch/arm/mach-tegra/powergate.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
index 23b065c09e12..2e3abef55f86 100644
--- a/arch/arm/mach-tegra/powergate.c
+++ b/arch/arm/mach-tegra/powergate.c
@@ -413,6 +413,11 @@ static int tegra_powergate_set(int id, bool new_state)
{
bool status;
unsigned long flags;
+ /* 10us timeout for toggle operation if it takes affect*/
+ int toggle_timeout = 10;
+ /* 100 * 10 = 1000us timeout for toggle command to take affect in case
+ of contention with h/w initiated CPU power gating */
+ int contention_timeout = 100;
spin_lock_irqsave(&tegra_powergate_lock, flags);
@@ -423,10 +428,33 @@ static int tegra_powergate_set(int id, bool new_state)
return -EINVAL;
}
- pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
+ if (TEGRA_IS_CPU_POWERGATE_ID(id)) {
+ /* CPU ungated in s/w only during boot/resume with outer
+ waiting loop and no contention from other CPUs */
+ pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
+ spin_unlock_irqrestore(&tegra_powergate_lock, flags);
+ return 0;
+ }
+
+ do {
+ pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
+ do {
+ udelay(1);
+ status = !!(pmc_read(PWRGATE_STATUS) & (1 << id));
+
+ toggle_timeout--;
+ } while ((status != new_state) && (toggle_timeout > 0));
+
+ contention_timeout--;
+ } while ((status != new_state) && (contention_timeout > 0));
spin_unlock_irqrestore(&tegra_powergate_lock, flags);
+ if (status != new_state) {
+ WARN(1, "Could not set powergate %d to %d", id, new_state);
+ return -EBUSY;
+ }
+
return 0;
}