summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/hotplug.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-04-03 00:57:28 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:34:22 -0800
commita1c4cc2df7fc4f286763514de76a2b5396a4c58e (patch)
tree8120f8b50b2233d5f00520a879f01a8d10f5805e /arch/arm/mach-tegra/hotplug.c
parentc00ce39eeac1324289f2e849409e78c739917bc0 (diff)
ARM: tegra: add hotplug support
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>
Diffstat (limited to 'arch/arm/mach-tegra/hotplug.c')
-rw-r--r--arch/arm/mach-tegra/hotplug.c122
1 files changed, 33 insertions, 89 deletions
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index f3294040d357..97d9746cee25 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -1,119 +1,63 @@
/*
- * 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)