diff options
author | Scott Williams <scwilliams@nvidia.com> | 2011-02-02 10:32:42 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-04-26 15:51:40 -0700 |
commit | 7df947103b10608106d2b10fbc951af68926438e (patch) | |
tree | 0d9e914ae54859f4ebb590a26b91d74adcadbf64 /arch/arm/mach-tegra/cpuidle-t2.c | |
parent | 4c609cbf4d1f0cf1a3f78c72695e3168b6088a4a (diff) |
arm: tegra: Redesign Tegra CPU reset handling
- Add a single unified handler for all CPU resets.
- Don't write boot confirmation notification to the reset vector.
- Write the EVP CPU reset vector only once per cold/warm boot session.
- Don't allow Tegra3 LP2 until all CPUs have booted.
- Don't restart online secondary CPUs that are also in LP2 state
when restarting CPU0 for Tegra3.
- Prevent the compiler from rearranging order-sensitive register
writes in boot_secondary().
- Fix incorrect return status in tegra_powergate_is_powered().
- In LP2 entry code, if a WFI request fails, retry a limited number
of times.
- Eliminate duplicate macro definitions.
- Improve commentary in assembly functions.
Bug 786290
Bug 790458
Original-Change-Id: I7582112938aa80303d1b8b1d1948d278ca662043
Reviewed-on: http://git-master/r/18091
Tested-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Narendra Damahe <ndamahe@nvidia.com>
Tested-by: Jin Qian <jqian@nvidia.com>
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Change-Id: I56a686e2e9fc00e61e97eec4fbf5a49944ffa77c
Diffstat (limited to 'arch/arm/mach-tegra/cpuidle-t2.c')
-rw-r--r-- | arch/arm/mach-tegra/cpuidle-t2.c | 24 |
1 files changed, 10 insertions, 14 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t2.c b/arch/arm/mach-tegra/cpuidle-t2.c index de964da19893..05db87ec5e62 100644 --- a/arch/arm/mach-tegra/cpuidle-t2.c +++ b/arch/arm/mach-tegra/cpuidle-t2.c @@ -3,7 +3,7 @@ * * CPU idle driver for Tegra2 CPUs * - * Copyright (c) 2010, NVIDIA Corporation. + * Copyright (c) 2010-2011, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +47,7 @@ #include <mach/suspend.h> #include "power.h" +#include "reset.h" #define TEGRA_CPUIDLE_BOTH_IDLE INT_QUAD_RES_24 #define TEGRA_CPUIDLE_TEAR_DOWN INT_QUAD_RES_25 @@ -139,7 +140,7 @@ static int tegra_tear_down_cpu1(void) /* Signal to CPU1 to tear down */ tegra_legacy_force_irq_set(TEGRA_CPUIDLE_TEAR_DOWN); - /* At this point, CPU0 can no longer abort LP2, but CP1 can */ + /* At this point, CPU0 can no longer abort LP2, but CPU1 can */ /* TODO: any way not to poll here? Use the LP2 timer to wfi? */ /* takes ~80 us */ while (!tegra_cpu_in_reset(1) && @@ -164,20 +165,16 @@ void callGenericSMC(u32 param0, u32 param1, u32 param2); static void tegra_wake_cpu1(void) { - unsigned long boot_vector; - unsigned long old_boot_vector; unsigned long timeout; #ifndef CONFIG_TRUSTED_FOUNDATIONS u32 reg; - static void __iomem *vector_base = (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100); #endif - boot_vector = virt_to_phys(tegra_hotplug_startup); #if CONFIG_TRUSTED_FOUNDATIONS +#error TrustedLogic Change Required callGenericSMC(0xFFFFFFFC, 0xFFFFFFE5, boot_vector); #else - old_boot_vector = readl(vector_base); - writel(boot_vector, vector_base); + writel(~0, EVP_CPU_RSVD_VECTOR); /* enable cpu clock on cpu */ reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX); @@ -192,13 +189,10 @@ static void tegra_wake_cpu1(void) timeout = jiffies + msecs_to_jiffies(1000); while (time_before(jiffies, timeout)) { - if (readl(vector_base) != boot_vector) + if (readl(EVP_CPU_RSVD_VECTOR) != ~0) break; udelay(10); } - - /* put the old boot vector back */ - writel(old_boot_vector, vector_base); #endif /* CPU1 is now started */ @@ -359,14 +353,16 @@ void tegra_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, twd_ctrl = readl(twd_base + 0x8); twd_load = readl(twd_base + 0); + cpu_set(dev->cpu, tegra_cpu_lp2_map); flush_cache_all(); + tegra_cpu_reset_handler_flush(false); barrier(); __cortex_a9_save(0); /* CPU1 is in reset, waiting for CPU0 to boot it, possibly after LP2 */ - /* CPU0 booted CPU1 out of reset */ barrier(); + cpu_clear(dev->cpu, tegra_cpu_lp2_map); writel(twd_ctrl, twd_base + 0x8); writel(twd_load, twd_base + 0); gic_cpu_init(0, IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x100); @@ -374,7 +370,7 @@ void tegra_idle_enter_lp2_cpu_n(struct cpuidle_device *dev, tegra_legacy_force_irq_clr(TEGRA_CPUIDLE_BOTH_IDLE); - writel(smp_processor_id(), EVP_CPU_RESET_VECTOR); + writel(smp_processor_id(), EVP_CPU_RSVD_VECTOR); start_critical_timings(); /* |