ARM: tegra: add hotplug support
Colin Cross [Sun, 3 Apr 2011 07:57:28 +0000 (00:57 -0700)]
Hotplug uses the same CPU wfi code as cpuidle to put either cpu
into a slightly lower power mode (clock gated, but still powered).
If the remaining cpu enters LP2, the hotplugged cpu will be power
gated until the remaining cpu is active.

Change-Id: Ib7428709043415dc759136cf91668f6f63fe5a5c
Signed-off-by: Colin Cross <ccross@android.com>

arch/arm/mach-tegra/hotplug.c

index f329404..97d9746 100644 (file)
 /*
- *  linux/arch/arm/mach-realview/hotplug.c
+ *  linux/arch/arm/mach-tegra/hotplug.c
  *
- *  Copyright (C) 2002 ARM Ltd.
- *  All Rights Reserved
+ *  Copyright (C) 2010 NVIDIA Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
 #include <linux/kernel.h>
-#include <linux/errno.h>
+#include <linux/io.h>
 #include <linux/smp.h>
 
-#include <asm/cacheflush.h>
+#include <asm/cpu_pm.h>
 
-static inline void cpu_enter_lowpower(void)
-{
-       unsigned int v;
+#include <mach/iomap.h>
 
-       flush_cache_all();
-       asm volatile(
-       "       mcr     p15, 0, %1, c7, c5, 0\n"
-       "       mcr     p15, 0, %1, c7, c10, 4\n"
-       /*
-        * Turn off coherency
-        */
-       "       mrc     p15, 0, %0, c1, c0, 1\n"
-       "       bic     %0, %0, #0x20\n"
-       "       mcr     p15, 0, %0, c1, c0, 1\n"
-       "       mrc     p15, 0, %0, c1, c0, 0\n"
-       "       bic     %0, %0, %2\n"
-       "       mcr     p15, 0, %0, c1, c0, 0\n"
-         : "=&r" (v)
-         : "r" (0), "Ir" (CR_C)
-         : "cc");
-}
+#include "sleep.h"
 
-static inline void cpu_leave_lowpower(void)
-{
-       unsigned int v;
+#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
+#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
+#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
 
-       asm volatile(
-       "mrc    p15, 0, %0, c1, c0, 0\n"
-       "       orr     %0, %0, %1\n"
-       "       mcr     p15, 0, %0, c1, c0, 0\n"
-       "       mrc     p15, 0, %0, c1, c0, 1\n"
-       "       orr     %0, %0, #0x20\n"
-       "       mcr     p15, 0, %0, c1, c0, 1\n"
-         : "=&r" (v)
-         : "Ir" (CR_C)
-         : "cc");
-}
-
-static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
+int platform_cpu_kill(unsigned int cpu)
 {
-       /*
-        * there is no power-control hardware on this platform, so all
-        * we can do is put the core into WFI; this is safe as the calling
-        * code will have already disabled interrupts
-        */
-       for (;;) {
-               /*
-                * here's the WFI
-                */
-               asm(".word      0xe320f003\n"
-                   :
-                   :
-                   : "memory", "cc");
+       unsigned int reg;
 
-               /*if (pen_release == cpu) {*/
-                       /*
-                        * OK, proper wakeup, we're done
-                        */
-                       break;
-               /*}*/
+       do {
+               reg = readl(CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+               cpu_relax();
+       } while (!(reg & (1<<cpu)));
 
-               /*
-                * Getting here, means that we have come out of WFI without
-                * having been woken up - this shouldn't happen
-                *
-                * Just note it happening - when we're woken, we can report
-                * its occurrence.
-                */
-               (*spurious)++;
-       }
-}
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       writel(reg | (1<<(8+cpu)), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
 
-int platform_cpu_kill(unsigned int cpu)
-{
        return 1;
 }
 
-/*
- * platform-specific code to shutdown a CPU
- *
- * Called with IRQs disabled
- */
 void platform_cpu_die(unsigned int cpu)
 {
-       int spurious = 0;
+#ifdef DEBUG
+       unsigned int this_cpu = hard_smp_processor_id();
 
-       /*
-        * we're ready for shutdown now, so do it
-        */
-       cpu_enter_lowpower();
-       platform_do_lowpower(cpu, &spurious);
+       if (cpu != this_cpu) {
+               printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+                          this_cpu, cpu);
+               BUG();
+       }
+#endif
+
+       tegra_sleep_reset();
 
        /*
-        * bring this CPU back into the world of cache
-        * coherency, and then restore interrupts
+        * tegra_cpu_suspend can return through tegra_cpu_resume, but that
+        * should never happen for a hotplugged cpu
         */
-       cpu_leave_lowpower();
-
-       if (spurious)
-               pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
+       BUG();
 }
 
 int platform_cpu_disable(unsigned int cpu)