summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/pm-t3.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-10-10 20:32:49 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:49:24 -0800
commit9bfcca7af6db9bbaa9496d453168c384ca768eb5 (patch)
treed79f2cbe28a71f6a386964e2fb76e704eea6ecd3 /arch/arm/mach-tegra/pm-t3.c
parent86ff7b4c0fe36fe06df6386aee577fd660471b39 (diff)
ARM: tegra: power: Force FW bit when SMP is enabled.
Set FW bit in CP15 auxiliary control register after LP=>G CPU mode switch if SMP bit in the same register is set. On Tegra3 in LP mode FW bit is always zero, even though SMP bit is retained. Hence, this change recovers FW bit on return from LP to G-mode. Change-Id: I9f0021ab90866cb8686d73eb6ad5bbedbb2ceb90 Reviewed-on: http://git-master/r/57203 Reviewed-by: Krishna Reddy <vdumpa@nvidia.com> Reviewed-by: Scott Williams <scwilliams@nvidia.com> Tested-by: Aleksandr Frid <afrid@nvidia.com> Reviewed-by: Antti Miettinen <amiettinen@nvidia.com> Tested-by: Antti Miettinen <amiettinen@nvidia.com> Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com> Rebase-Id: R37dbe2079eafcfb47babaf41b53818a9130d2bbe
Diffstat (limited to 'arch/arm/mach-tegra/pm-t3.c')
-rw-r--r--arch/arm/mach-tegra/pm-t3.c31
1 files changed, 25 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c
index f41b429d3fcc..5d55a9e2111f 100644
--- a/arch/arm/mach-tegra/pm-t3.c
+++ b/arch/arm/mach-tegra/pm-t3.c
@@ -225,15 +225,31 @@ done:
writel(reg, FLOW_CTRL_CPU_CSR(0));
}
+
+static void cluster_switch_epilog_actlr(void)
+{
+ u32 actlr;
+
+ /* TLB maintenance broadcast bit (FW) is stubbed out on LP CPU (reads
+ as zero, writes ignored). Hence, it is not preserved across G=>LP=>G
+ switch by CPU save/restore code, but SMP bit is restored correctly.
+ Synchronize these two bits here after LP=>G transition. Note that
+ only CPU0 core is powered on before and after the switch. See also
+ bug 807595. */
+
+ __asm__("mrc p15, 0, %0, c1, c0, 1\n" : "=r" (actlr));
+
+ if (actlr & (0x1 << 6)) {
+ actlr |= 0x1;
+ __asm__("mcr p15, 0, %0, c1, c0, 1\n" : : "r" (actlr));
+ }
+}
+
static void cluster_switch_epilog_gic(void)
{
unsigned int max_irq, i;
void __iomem *gic_base = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
- /* Nothing to do if currently running on the LP CPU. */
- if (is_lp_cluster())
- return;
-
/* Reprogram the interrupt affinity because the on the LP CPU,
the interrupt distributor affinity regsiters are stubbed out
by ARM (reads as zero, writes ignored). So when the LP CPU
@@ -261,8 +277,11 @@ void tegra_cluster_switch_epilog(unsigned int flags)
FLOW_CTRL_CPU_CSR_SWITCH_CLUSTER);
writel(reg, FLOW_CTRL_CPU_CSR(0));
- /* Perform post-switch clean-up of the interrupt distributor */
- cluster_switch_epilog_gic();
+ /* Perform post-switch LP=>G clean-up */
+ if (!is_lp_cluster()) {
+ cluster_switch_epilog_actlr();
+ cluster_switch_epilog_gic();
+ }
#if DEBUG_CLUSTER_SWITCH
{