aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/hotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/hotplug.c')
-rw-r--r--arch/arm/mach-imx/hotplug.c58
1 files changed, 42 insertions, 16 deletions
diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c
index 89493abd497..b35e99cc5e5 100644
--- a/arch/arm/mach-imx/hotplug.c
+++ b/arch/arm/mach-imx/hotplug.c
@@ -11,12 +11,31 @@
*/
#include <linux/errno.h>
-#include <asm/cacheflush.h>
-#include <mach/common.h>
+#include <linux/jiffies.h>
+#include <asm/cp15.h>
+#include <asm/proc-fns.h>
-int platform_cpu_kill(unsigned int cpu)
+#include "common.h"
+
+static inline void cpu_enter_lowpower(void)
{
- return 1;
+ unsigned int v;
+
+ 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, %3\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), "Ir" (0x40)
+ : "cc");
}
/*
@@ -24,21 +43,28 @@ int platform_cpu_kill(unsigned int cpu)
*
* Called with IRQs disabled
*/
-void platform_cpu_die(unsigned int cpu)
+void imx_cpu_die(unsigned int cpu)
{
- flush_cache_all();
- imx_enable_cpu(cpu, false);
- cpu_do_idle();
+ cpu_enter_lowpower();
+ /*
+ * We use the cpu jumping argument register to sync with
+ * imx_cpu_kill() which is running on cpu0 and waiting for
+ * the register being cleared to kill the cpu.
+ */
+ imx_set_cpu_arg(cpu, ~0);
- /* We should never return from idle */
- panic("cpu %d unexpectedly exit from shutdown\n", cpu);
+ while (1)
+ cpu_do_idle();
}
-int platform_cpu_disable(unsigned int cpu)
+int imx_cpu_kill(unsigned int cpu)
{
- /*
- * we don't allow CPU 0 to be shutdown (it is still too special
- * e.g. clock tick interrupts)
- */
- return cpu == 0 ? -EPERM : 0;
+ unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+ while (imx_get_cpu_arg(cpu) == 0)
+ if (time_after(jiffies, timeout))
+ return 0;
+ imx_enable_cpu(cpu, false);
+ imx_set_cpu_arg(cpu, 0);
+ return 1;
}