aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2013-03-04 19:05:57 -0500
committerStephen Warren <swarren@nvidia.com>2013-03-11 16:29:22 -0400
commit02e75d648899df96b79a4f98380679f48b91e3d4 (patch)
treef85fbd3ebbd817acda092e7d2afd4798dafef8e2
parentc34f30e588d310a70f994659c06f0a31dfdcfc15 (diff)
ARM: tegra: remove save/restore of CPU diag register
Prior to this change, {save,restore}_cpu_arch_register() collaborated to maintain the value of the CPU diagnostic register across power cycles. This was required to maintain any CPU errata workaround enable bits in that register. However, now that the Tegra reset vector code always enables all required workarounds, there is no need to save and restore the diagnostic register; it is always explicitly programmed in the required manner. Hence, remove the save/restore logic. This has the advantage that the kernel always directly controls the value of this register every boot, rather than relying on a bootloader or other kernel code having previously written the correct value into it. This makes CPU0 (which was previously saved/restored) and CPUn (which should have been set up by the reset vector) be controlled in exactly the same way, which is easier to debug/find/... In particular, when converting Tegra to a multi-platform kernel, the CPU0 diagnostic register value initially comes from the bootloader. Most Tegra bootloaders don't yet enable all required CPU bug workarounds. The previous commit updates the kernel to do so on any CPU power cycle. However, the save/restore code ends up over-writing the value with the old bootloader-driven value instead of the now more-likely-to-be-correct kernel value! Even irrespective of multi-platform conversion, this change limits the kernel's exposure to any WARs the bootloader didn't enable for CPU0: on the very first LP2 transition (CPU power-saving which power-cycles the CPU), the correct value will be enabled. Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c4
-rw-r--r--arch/arm/mach-tegra/pm.c19
2 files changed, 0 insertions, 23 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 8b50cf4ddd6f..80445ed33d95 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -102,12 +102,8 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
102 102
103 smp_wmb(); 103 smp_wmb();
104 104
105 save_cpu_arch_register();
106
107 cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); 105 cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
108 106
109 restore_cpu_arch_register();
110
111 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu); 107 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
112 108
113 return true; 109 return true;
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 523604de666f..0494f739c95f 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -46,26 +46,11 @@
46#define PMC_CPUPWROFF_TIMER 0xcc 46#define PMC_CPUPWROFF_TIMER 0xcc
47 47
48#ifdef CONFIG_PM_SLEEP 48#ifdef CONFIG_PM_SLEEP
49static unsigned int g_diag_reg;
50static DEFINE_SPINLOCK(tegra_lp2_lock); 49static DEFINE_SPINLOCK(tegra_lp2_lock);
51static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); 50static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
52static struct clk *tegra_pclk; 51static struct clk *tegra_pclk;
53void (*tegra_tear_down_cpu)(void); 52void (*tegra_tear_down_cpu)(void);
54 53
55void save_cpu_arch_register(void)
56{
57 /* read diagnostic register */
58 asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
59 return;
60}
61
62void restore_cpu_arch_register(void)
63{
64 /* write diagnostic register */
65 asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
66 return;
67}
68
69static void set_power_timers(unsigned long us_on, unsigned long us_off) 54static void set_power_timers(unsigned long us_on, unsigned long us_off)
70{ 55{
71 unsigned long long ticks; 56 unsigned long long ticks;
@@ -119,8 +104,6 @@ static void restore_cpu_complex(void)
119 tegra_cpu_clock_resume(); 104 tegra_cpu_clock_resume();
120 105
121 flowctrl_cpu_suspend_exit(cpu); 106 flowctrl_cpu_suspend_exit(cpu);
122
123 restore_cpu_arch_register();
124} 107}
125 108
126/* 109/*
@@ -145,8 +128,6 @@ static void suspend_cpu_complex(void)
145 tegra_cpu_clock_suspend(); 128 tegra_cpu_clock_suspend();
146 129
147 flowctrl_cpu_suspend_enter(cpu); 130 flowctrl_cpu_suspend_enter(cpu);
148
149 save_cpu_arch_register();
150} 131}
151 132
152void tegra_clear_cpu_in_lp2(int phy_cpu_id) 133void tegra_clear_cpu_in_lp2(int phy_cpu_id)