ARM: tegra: Update secondary CPU power up procedure
Alex Frid [Sat, 12 Feb 2011 02:17:28 +0000 (18:17 -0800)]
- Wait for power up status confirmation after secondary CPU was
un-gated by flow controller (instead of directly UN-gating CPU
again if the 1st status check failed).
- Enable CPU clock only after power up is confirmed.
- Insert propagation delays before and after removing clamps.

Original-Change-Id: I81cd1479bdb49163eeb9a369fc165cede49eb71a
Reviewed-on: http://git-master/r/19372
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Original-Change-Id: I061738a5c5f46299cccfcb264d9b5bd838694305

Rebase-Id: R8f3d1364c016aaf4d9856add97612dc7ac77aa6e

arch/arm/mach-tegra/platsmp.c

index 1f91d4d..e903da7 100644 (file)
@@ -76,7 +76,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
 
 int boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-       u32 reg;
        int status;
 
        if (is_lp_cluster()) {
@@ -113,16 +112,20 @@ int boot_secondary(unsigned int cpu, struct task_struct *idle)
           is now driving reset. */
        flowctrl_writel(0, FLOW_CTRL_HALT_CPU(cpu));
 
-       /* enable cpu clock on cpu */
-       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-       writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-       dmb();
-
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+       {
+               /* enable cpu clock on cpu */
+               u32 reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+               writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+               dmb();
+       }
+#endif
        status = power_up_cpu(cpu);
        if (status)
                goto done;
 
        dmb();
+       udelay(10);     /* power up delay */
        writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
 
 done:
@@ -168,11 +171,24 @@ static bool is_cpu_powered(unsigned int cpu)
 static int power_up_cpu(unsigned int cpu)
 {
        int ret;
+       u32 reg;
        unsigned long timeout;
 
        BUG_ON(cpu == smp_processor_id());
        BUG_ON(is_lp_cluster());
 
+       /* This function is entered after CPU has been already un-gated by
+          flow controller. Wait for confirmation that cpu is powered and
+          remove clamps. */
+       timeout = jiffies + HZ;
+       do {
+               if (is_cpu_powered(cpu))
+                       goto remove_clamps;
+               udelay(10);
+       } while (time_before(jiffies, timeout));
+
+       /* Flow controller did not work as expected - try directly toggle
+          power gates. Bail out if direct power on also failed */
        if (!is_cpu_powered(cpu))
        {
                ret = tegra_powergate_power_on(TEGRA_CPU_POWERGATE_ID(cpu));
@@ -192,6 +208,13 @@ static int power_up_cpu(unsigned int cpu)
        }
 
 remove_clamps:
+       /* now CPU is up: enable clock, propagate reset, and remove clamps */
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       barrier();
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+
+       udelay(10);
        ret = tegra_powergate_remove_clamping(TEGRA_CPU_POWERGATE_ID(cpu));
 fail:
        return ret;