diff options
Diffstat (limited to 'arch/arm/mach-tegra/hotplug.c')
| -rw-r--r-- | arch/arm/mach-tegra/hotplug.c | 140 |
1 files changed, 31 insertions, 109 deletions
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c index 8e7f115aa21..ff26af26bd0 100644 --- a/arch/arm/mach-tegra/hotplug.c +++ b/arch/arm/mach-tegra/hotplug.c @@ -1,100 +1,32 @@ /* - * linux/arch/arm/mach-realview/hotplug.c - * * Copyright (C) 2002 ARM Ltd. * All Rights Reserved + * Copyright (c) 2010, 2012-2013, NVIDIA Corporation. All rights reserved. * * 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/smp.h> -#include <linux/completion.h> - -#include <asm/cacheflush.h> +#include <linux/clk/tegra.h> -static DECLARE_COMPLETION(cpu_killed); +#include <asm/smp_plat.h> -static inline void cpu_enter_lowpower(void) -{ - unsigned int v; +#include "fuse.h" +#include "sleep.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, #0x04\n" - " mcr p15, 0, %0, c1, c0, 0\n" - : "=&r" (v) - : "r" (0) - : "cc"); -} +static void (*tegra_hotplug_shutdown)(void); -static inline void cpu_leave_lowpower(void) +int tegra_cpu_kill(unsigned cpu) { - unsigned int v; + cpu = cpu_logical_map(cpu); - asm volatile( - "mrc p15, 0, %0, c1, c0, 0\n" - " orr %0, %0, #0x04\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) - : - : "cc"); -} - -static inline void platform_do_lowpower(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"); + /* Clock gate the CPU */ + tegra_wait_cpu_in_reset(cpu); + tegra_disable_cpu_clock(cpu); - /*if (pen_release == cpu) {*/ - /* - * OK, proper wakeup, we're done - */ - break; - /*}*/ - - /* - * getting here, means that we have come out of WFI without - * having been woken up - this shouldn't happen - * - * The trouble is, letting people know about this is not really - * possible, since we are currently running incoherently, and - * therefore cannot safely call printk() or anything else - */ -#ifdef DEBUG - printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu); -#endif - } -} - -int platform_cpu_kill(unsigned int cpu) -{ - return wait_for_completion_timeout(&cpu_killed, 5000); + return 1; } /* @@ -102,39 +34,29 @@ int platform_cpu_kill(unsigned int cpu) * * Called with IRQs disabled */ -void platform_cpu_die(unsigned int cpu) +void __ref tegra_cpu_die(unsigned int cpu) { -#ifdef DEBUG - unsigned int this_cpu = hard_smp_processor_id(); - - if (cpu != this_cpu) { - printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n", - this_cpu, cpu); - BUG(); - } -#endif - - printk(KERN_NOTICE "CPU%u: shutdown\n", cpu); - complete(&cpu_killed); + /* Clean L1 data cache */ + tegra_disable_clean_inv_dcache(TEGRA_FLUSH_CACHE_LOUIS); - /* - * we're ready for shutdown now, so do it - */ - cpu_enter_lowpower(); - platform_do_lowpower(cpu); + /* Shut down the current CPU. */ + tegra_hotplug_shutdown(); - /* - * bring this CPU back into the world of cache - * coherency, and then restore interrupts - */ - cpu_leave_lowpower(); + /* Should never return here. */ + BUG(); } -int platform_cpu_disable(unsigned int cpu) +void __init tegra_hotplug_init(void) { - /* - * we don't allow CPU 0 to be shutdown (it is still too special - * e.g. clock tick interrupts) - */ - return cpu == 0 ? -EPERM : 0; + if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) + return; + + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && tegra_chip_id == TEGRA20) + tegra_hotplug_shutdown = tegra20_hotplug_shutdown; + if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC) && tegra_chip_id == TEGRA30) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; + if (IS_ENABLED(CONFIG_ARCH_TEGRA_114_SOC) && tegra_chip_id == TEGRA114) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; + if (IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) && tegra_chip_id == TEGRA124) + tegra_hotplug_shutdown = tegra30_hotplug_shutdown; } |
