Turned out that WFI doesn't work reliably on Tegra30 as a trigger for
the power-gating, it causes CPU hang under some circumstances like having
memory controller running of PLLP. The TRM doc states that WFI should be
used for the Big-Little "Cluster Switch", while WFE for the power-gating.
Hence let's use the WFE for CPU0 power-gating, like it is done for the
power-gating of a secondary cores. This fixes CPU hang after entering LP2
with memory running off PLLP.

Acked-by: Peter De Schrijver <[email protected]>
Signed-off-by: Dmitry Osipenko <[email protected]>
---
 arch/arm/mach-tegra/sleep-tegra30.S |  4 +++-
 drivers/soc/tegra/flowctrl.c        | 19 +++++++++++++++++--
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-tegra/sleep-tegra30.S 
b/arch/arm/mach-tegra/sleep-tegra30.S
index 6c28395d8c75..17f7a2a6a494 100644
--- a/arch/arm/mach-tegra/sleep-tegra30.S
+++ b/arch/arm/mach-tegra/sleep-tegra30.S
@@ -683,10 +683,12 @@ tegra30_enter_sleep:
        dsb
        ldr     r0, [r6, r2] /* memory barrier */
 
+       cmp     r10, #TEGRA30
 halted:
        isb
        dsb
-       wfi     /* CPU should be power gated here */
+       wfine   /* CPU should be power gated here */
+       wfeeq
 
        /* !!!FIXME!!! Implement halt failure handler */
        b       halted
diff --git a/drivers/soc/tegra/flowctrl.c b/drivers/soc/tegra/flowctrl.c
index b6bdeef33db1..eb96a3086d6d 100644
--- a/drivers/soc/tegra/flowctrl.c
+++ b/drivers/soc/tegra/flowctrl.c
@@ -91,8 +91,23 @@ void flowctrl_cpu_suspend_enter(unsigned int cpuid)
                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFE_BITMAP;
                /* clear wfi bitmap */
                reg &= ~TEGRA30_FLOW_CTRL_CSR_WFI_BITMAP;
-               /* pwr gating on wfi */
-               reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
+
+               if (tegra_get_chip_id() == TEGRA30) {
+                       /*
+                        * The wfi doesn't work well on Tegra30 because
+                        * CPU hangs under some odd circumstances after
+                        * power-gating (like memory running off PLLP),
+                        * hence use wfe that is working perfectly fine.
+                        * Note that Tegra30 TRM doc clearly stands that
+                        * wfi should be used for the "Cluster Switching",
+                        * while wfe for the power-gating, just like it
+                        * is done on Tegra20.
+                        */
+                       reg |= TEGRA20_FLOW_CTRL_CSR_WFE_CPU0 << cpuid;
+               } else {
+                       /* pwr gating on wfi */
+                       reg |= TEGRA30_FLOW_CTRL_CSR_WFI_CPU0 << cpuid;
+               }
                break;
        }
        reg |= FLOW_CTRL_CSR_INTR_FLAG;                 /* clear intr flag */
-- 
2.22.0

Reply via email to