aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2015-01-15 05:58:57 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-10 12:49:34 -0400
commit3544f27efa25890516158c8e13d21e878969d125 (patch)
treeec76dc958d12241534c2b35cd5ac83b4bfb74f06
parent3f3587c4ff8c828aac436237aeca8694a26defd3 (diff)
ARM: tegra20: Store CPU "resettable" status in IRAM
commit 4d48edb3c3e1234d6b3fcdfb9ac24d7c6de449cb upstream. Commit 7232398abc6a ("ARM: tegra: Convert PMC to a driver") changed tegra_resume() location storing from late to early and, as a result, broke suspend on Tegra20. PMC scratch register 41 is used by tegra LP1 resume code for retrieving stored physical memory address of common resume function and in the same time used by tegra20_cpu_shutdown() (shared by Tegra20 cpuidle driver and platform SMP code), which is storing CPU1 "resettable" status. It implies strict order of scratch register usage, otherwise resume function address is lost on Tegra20 after disabling non-boot CPU's on suspend. Fix it by storing "resettable" status in IRAM instead of PMC scratch register. Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Fixes: 7232398abc6a (ARM: tegra: Convert PMC to a driver) Signed-off-by: Thierry Reding <treding@nvidia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c5
-rw-r--r--arch/arm/mach-tegra/reset-handler.S10
-rw-r--r--arch/arm/mach-tegra/reset.h4
-rw-r--r--arch/arm/mach-tegra/sleep-tegra20.S37
-rw-r--r--arch/arm/mach-tegra/sleep.h4
5 files changed, 38 insertions, 22 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index 88de2dce2e87..7469347b1749 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -34,6 +34,7 @@
34#include "iomap.h" 34#include "iomap.h"
35#include "irq.h" 35#include "irq.h"
36#include "pm.h" 36#include "pm.h"
37#include "reset.h"
37#include "sleep.h" 38#include "sleep.h"
38 39
39#ifdef CONFIG_PM_SLEEP 40#ifdef CONFIG_PM_SLEEP
@@ -70,15 +71,13 @@ static struct cpuidle_driver tegra_idle_driver = {
70 71
71#ifdef CONFIG_PM_SLEEP 72#ifdef CONFIG_PM_SLEEP
72#ifdef CONFIG_SMP 73#ifdef CONFIG_SMP
73static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
74
75static int tegra20_reset_sleeping_cpu_1(void) 74static int tegra20_reset_sleeping_cpu_1(void)
76{ 75{
77 int ret = 0; 76 int ret = 0;
78 77
79 tegra_pen_lock(); 78 tegra_pen_lock();
80 79
81 if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE) 80 if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE)
82 tegra20_cpu_shutdown(1); 81 tegra20_cpu_shutdown(1);
83 else 82 else
84 ret = -EINVAL; 83 ret = -EINVAL;
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 71be4af5e975..e3070fdab80b 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -169,10 +169,10 @@ after_errata:
169 cmp r6, #TEGRA20 169 cmp r6, #TEGRA20
170 bne 1f 170 bne 1f
171 /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */ 171 /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
172 mov32 r5, TEGRA_PMC_BASE 172 mov32 r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
173 mov r0, #0 173 mov r0, #CPU_NOT_RESETTABLE
174 cmp r10, #0 174 cmp r10, #0
175 strne r0, [r5, #PMC_SCRATCH41] 175 strneb r0, [r5, #__tegra20_cpu1_resettable_status_offset]
1761: 1761:
177#endif 177#endif
178 178
@@ -281,6 +281,10 @@ __tegra_cpu_reset_handler_data:
281 .rept TEGRA_RESET_DATA_SIZE 281 .rept TEGRA_RESET_DATA_SIZE
282 .long 0 282 .long 0
283 .endr 283 .endr
284 .globl __tegra20_cpu1_resettable_status_offset
285 .equ __tegra20_cpu1_resettable_status_offset, \
286 . - __tegra_cpu_reset_handler_start
287 .byte 0
284 .align L1_CACHE_SHIFT 288 .align L1_CACHE_SHIFT
285 289
286ENTRY(__tegra_cpu_reset_handler_end) 290ENTRY(__tegra_cpu_reset_handler_end)
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
index 76a93434c6ee..29c3dec0126a 100644
--- a/arch/arm/mach-tegra/reset.h
+++ b/arch/arm/mach-tegra/reset.h
@@ -35,6 +35,7 @@ extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
35 35
36void __tegra_cpu_reset_handler_start(void); 36void __tegra_cpu_reset_handler_start(void);
37void __tegra_cpu_reset_handler(void); 37void __tegra_cpu_reset_handler(void);
38void __tegra20_cpu1_resettable_status_offset(void);
38void __tegra_cpu_reset_handler_end(void); 39void __tegra_cpu_reset_handler_end(void);
39void tegra_secondary_startup(void); 40void tegra_secondary_startup(void);
40 41
@@ -47,6 +48,9 @@ void tegra_secondary_startup(void);
47 (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \ 48 (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
48 ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \ 49 ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
49 (u32)__tegra_cpu_reset_handler_start))) 50 (u32)__tegra_cpu_reset_handler_start)))
51#define tegra20_cpu1_resettable_status \
52 (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
53 (u32)__tegra20_cpu1_resettable_status_offset))
50#endif 54#endif
51 55
52#define tegra_cpu_reset_handler_offset \ 56#define tegra_cpu_reset_handler_offset \
diff --git a/arch/arm/mach-tegra/sleep-tegra20.S b/arch/arm/mach-tegra/sleep-tegra20.S
index be4bc5f853f5..e6b684e14322 100644
--- a/arch/arm/mach-tegra/sleep-tegra20.S
+++ b/arch/arm/mach-tegra/sleep-tegra20.S
@@ -97,9 +97,10 @@ ENDPROC(tegra20_hotplug_shutdown)
97ENTRY(tegra20_cpu_shutdown) 97ENTRY(tegra20_cpu_shutdown)
98 cmp r0, #0 98 cmp r0, #0
99 reteq lr @ must not be called for CPU 0 99 reteq lr @ must not be called for CPU 0
100 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 100 mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
101 ldr r2, =__tegra20_cpu1_resettable_status_offset
101 mov r12, #CPU_RESETTABLE 102 mov r12, #CPU_RESETTABLE
102 str r12, [r1] 103 strb r12, [r1, r2]
103 104
104 cpu_to_halt_reg r1, r0 105 cpu_to_halt_reg r1, r0
105 ldr r3, =TEGRA_FLOW_CTRL_VIRT 106 ldr r3, =TEGRA_FLOW_CTRL_VIRT
@@ -182,38 +183,41 @@ ENDPROC(tegra_pen_unlock)
182/* 183/*
183 * tegra20_cpu_clear_resettable(void) 184 * tegra20_cpu_clear_resettable(void)
184 * 185 *
185 * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when 186 * Called to clear the "resettable soon" flag in IRAM variable when
186 * it is expected that the secondary CPU will be idle soon. 187 * it is expected that the secondary CPU will be idle soon.
187 */ 188 */
188ENTRY(tegra20_cpu_clear_resettable) 189ENTRY(tegra20_cpu_clear_resettable)
189 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 190 mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
191 ldr r2, =__tegra20_cpu1_resettable_status_offset
190 mov r12, #CPU_NOT_RESETTABLE 192 mov r12, #CPU_NOT_RESETTABLE
191 str r12, [r1] 193 strb r12, [r1, r2]
192 ret lr 194 ret lr
193ENDPROC(tegra20_cpu_clear_resettable) 195ENDPROC(tegra20_cpu_clear_resettable)
194 196
195/* 197/*
196 * tegra20_cpu_set_resettable_soon(void) 198 * tegra20_cpu_set_resettable_soon(void)
197 * 199 *
198 * Called to set the "resettable soon" flag in PMC_SCRATCH41 when 200 * Called to set the "resettable soon" flag in IRAM variable when
199 * it is expected that the secondary CPU will be idle soon. 201 * it is expected that the secondary CPU will be idle soon.
200 */ 202 */
201ENTRY(tegra20_cpu_set_resettable_soon) 203ENTRY(tegra20_cpu_set_resettable_soon)
202 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 204 mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
205 ldr r2, =__tegra20_cpu1_resettable_status_offset
203 mov r12, #CPU_RESETTABLE_SOON 206 mov r12, #CPU_RESETTABLE_SOON
204 str r12, [r1] 207 strb r12, [r1, r2]
205 ret lr 208 ret lr
206ENDPROC(tegra20_cpu_set_resettable_soon) 209ENDPROC(tegra20_cpu_set_resettable_soon)
207 210
208/* 211/*
209 * tegra20_cpu_is_resettable_soon(void) 212 * tegra20_cpu_is_resettable_soon(void)
210 * 213 *
211 * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been 214 * Returns true if the "resettable soon" flag in IRAM variable has been
212 * set because it is expected that the secondary CPU will be idle soon. 215 * set because it is expected that the secondary CPU will be idle soon.
213 */ 216 */
214ENTRY(tegra20_cpu_is_resettable_soon) 217ENTRY(tegra20_cpu_is_resettable_soon)
215 mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41 218 mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
216 ldr r12, [r1] 219 ldr r2, =__tegra20_cpu1_resettable_status_offset
220 ldrb r12, [r1, r2]
217 cmp r12, #CPU_RESETTABLE_SOON 221 cmp r12, #CPU_RESETTABLE_SOON
218 moveq r0, #1 222 moveq r0, #1
219 movne r0, #0 223 movne r0, #0
@@ -256,9 +260,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
256 mov r0, #TEGRA_FLUSH_CACHE_LOUIS 260 mov r0, #TEGRA_FLUSH_CACHE_LOUIS
257 bl tegra_disable_clean_inv_dcache 261 bl tegra_disable_clean_inv_dcache
258 262
259 mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41 263 mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
264 ldr r4, =__tegra20_cpu1_resettable_status_offset
260 mov r3, #CPU_RESETTABLE 265 mov r3, #CPU_RESETTABLE
261 str r3, [r0] 266 strb r3, [r0, r4]
262 267
263 bl tegra_cpu_do_idle 268 bl tegra_cpu_do_idle
264 269
@@ -274,10 +279,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish)
274 279
275 bl tegra_pen_lock 280 bl tegra_pen_lock
276 281
277 mov32 r3, TEGRA_PMC_VIRT 282 mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
278 add r0, r3, #PMC_SCRATCH41 283 ldr r4, =__tegra20_cpu1_resettable_status_offset
279 mov r3, #CPU_NOT_RESETTABLE 284 mov r3, #CPU_NOT_RESETTABLE
280 str r3, [r0] 285 strb r3, [r0, r4]
281 286
282 bl tegra_pen_unlock 287 bl tegra_pen_unlock
283 288
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index 92d46ec1361a..0d59360d891d 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -18,6 +18,7 @@
18#define __MACH_TEGRA_SLEEP_H 18#define __MACH_TEGRA_SLEEP_H
19 19
20#include "iomap.h" 20#include "iomap.h"
21#include "irammap.h"
21 22
22#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \ 23#define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
23 + IO_CPU_VIRT) 24 + IO_CPU_VIRT)
@@ -29,6 +30,9 @@
29 + IO_APB_VIRT) 30 + IO_APB_VIRT)
30#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT) 31#define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
31 32
33#define TEGRA_IRAM_RESET_BASE_VIRT (IO_IRAM_VIRT + \
34 TEGRA_IRAM_RESET_HANDLER_OFFSET)
35
32/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */ 36/* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
33#define PMC_SCRATCH37 0x130 37#define PMC_SCRATCH37 0x130
34#define PMC_SCRATCH38 0x134 38#define PMC_SCRATCH38 0x134