]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.0.8/arm-tegra20-store-cpu-resettable-status-in-iram.patch
5.0-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.0.8 / arm-tegra20-store-cpu-resettable-status-in-iram.patch
CommitLineData
56c71b2c
GKH
1From 4d48edb3c3e1234d6b3fcdfb9ac24d7c6de449cb Mon Sep 17 00:00:00 2001
2From: Dmitry Osipenko <digetx@gmail.com>
3Date: Thu, 15 Jan 2015 13:58:57 +0300
4Subject: ARM: tegra20: Store CPU "resettable" status in IRAM
5
6From: Dmitry Osipenko <digetx@gmail.com>
7
8commit 4d48edb3c3e1234d6b3fcdfb9ac24d7c6de449cb upstream.
9
10Commit 7232398abc6a ("ARM: tegra: Convert PMC to a driver") changed tegra_resume()
11location storing from late to early and, as a result, broke suspend on Tegra20.
12PMC scratch register 41 is used by tegra LP1 resume code for retrieving stored
13physical memory address of common resume function and in the same time used by
14tegra20_cpu_shutdown() (shared by Tegra20 cpuidle driver and platform SMP code),
15which is storing CPU1 "resettable" status. It implies strict order of scratch
16register usage, otherwise resume function address is lost on Tegra20 after
17disabling non-boot CPU's on suspend. Fix it by storing "resettable" status in
18IRAM instead of PMC scratch register.
19
20Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
21Fixes: 7232398abc6a (ARM: tegra: Convert PMC to a driver)
22Signed-off-by: Thierry Reding <treding@nvidia.com>
23Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
24
25---
26 arch/arm/mach-tegra/cpuidle-tegra20.c | 5 +---
27 arch/arm/mach-tegra/reset-handler.S | 10 ++++++---
28 arch/arm/mach-tegra/reset.h | 4 +++
29 arch/arm/mach-tegra/sleep-tegra20.S | 37 +++++++++++++++++++---------------
30 arch/arm/mach-tegra/sleep.h | 4 +++
31 5 files changed, 38 insertions(+), 22 deletions(-)
32
33--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
34+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
35@@ -35,6 +35,7 @@
36 #include "iomap.h"
37 #include "irq.h"
38 #include "pm.h"
39+#include "reset.h"
40 #include "sleep.h"
41
42 #ifdef CONFIG_PM_SLEEP
43@@ -71,15 +72,13 @@ static struct cpuidle_driver tegra_idle_
44
45 #ifdef CONFIG_PM_SLEEP
46 #ifdef CONFIG_SMP
47-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
48-
49 static int tegra20_reset_sleeping_cpu_1(void)
50 {
51 int ret = 0;
52
53 tegra_pen_lock();
54
55- if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
56+ if (readb(tegra20_cpu1_resettable_status) == CPU_RESETTABLE)
57 tegra20_cpu_shutdown(1);
58 else
59 ret = -EINVAL;
60--- a/arch/arm/mach-tegra/reset-handler.S
61+++ b/arch/arm/mach-tegra/reset-handler.S
62@@ -169,10 +169,10 @@ after_errata:
63 cmp r6, #TEGRA20
64 bne 1f
65 /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
66- mov32 r5, TEGRA_PMC_BASE
67- mov r0, #0
68+ mov32 r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
69+ mov r0, #CPU_NOT_RESETTABLE
70 cmp r10, #0
71- strne r0, [r5, #PMC_SCRATCH41]
72+ strneb r0, [r5, #__tegra20_cpu1_resettable_status_offset]
73 1:
74 #endif
75
76@@ -281,6 +281,10 @@ __tegra_cpu_reset_handler_data:
77 .rept TEGRA_RESET_DATA_SIZE
78 .long 0
79 .endr
80+ .globl __tegra20_cpu1_resettable_status_offset
81+ .equ __tegra20_cpu1_resettable_status_offset, \
82+ . - __tegra_cpu_reset_handler_start
83+ .byte 0
84 .align L1_CACHE_SHIFT
85
86 ENTRY(__tegra_cpu_reset_handler_end)
87--- a/arch/arm/mach-tegra/reset.h
88+++ b/arch/arm/mach-tegra/reset.h
89@@ -35,6 +35,7 @@ extern unsigned long __tegra_cpu_reset_h
90
91 void __tegra_cpu_reset_handler_start(void);
92 void __tegra_cpu_reset_handler(void);
93+void __tegra20_cpu1_resettable_status_offset(void);
94 void __tegra_cpu_reset_handler_end(void);
95 void tegra_secondary_startup(void);
96
97@@ -47,6 +48,9 @@ void tegra_secondary_startup(void);
98 (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
99 ((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_LP2] - \
100 (u32)__tegra_cpu_reset_handler_start)))
101+#define tegra20_cpu1_resettable_status \
102+ (IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
103+ (u32)__tegra20_cpu1_resettable_status_offset))
104 #endif
105
106 #define tegra_cpu_reset_handler_offset \
107--- a/arch/arm/mach-tegra/sleep-tegra20.S
108+++ b/arch/arm/mach-tegra/sleep-tegra20.S
109@@ -97,9 +97,10 @@ ENDPROC(tegra20_hotplug_shutdown)
110 ENTRY(tegra20_cpu_shutdown)
111 cmp r0, #0
112 reteq lr @ must not be called for CPU 0
113- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
114+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
115+ ldr r2, =__tegra20_cpu1_resettable_status_offset
116 mov r12, #CPU_RESETTABLE
117- str r12, [r1]
118+ strb r12, [r1, r2]
119
120 cpu_to_halt_reg r1, r0
121 ldr r3, =TEGRA_FLOW_CTRL_VIRT
122@@ -182,38 +183,41 @@ ENDPROC(tegra_pen_unlock)
123 /*
124 * tegra20_cpu_clear_resettable(void)
125 *
126- * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
127+ * Called to clear the "resettable soon" flag in IRAM variable when
128 * it is expected that the secondary CPU will be idle soon.
129 */
130 ENTRY(tegra20_cpu_clear_resettable)
131- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
132+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
133+ ldr r2, =__tegra20_cpu1_resettable_status_offset
134 mov r12, #CPU_NOT_RESETTABLE
135- str r12, [r1]
136+ strb r12, [r1, r2]
137 ret lr
138 ENDPROC(tegra20_cpu_clear_resettable)
139
140 /*
141 * tegra20_cpu_set_resettable_soon(void)
142 *
143- * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
144+ * Called to set the "resettable soon" flag in IRAM variable when
145 * it is expected that the secondary CPU will be idle soon.
146 */
147 ENTRY(tegra20_cpu_set_resettable_soon)
148- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
149+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
150+ ldr r2, =__tegra20_cpu1_resettable_status_offset
151 mov r12, #CPU_RESETTABLE_SOON
152- str r12, [r1]
153+ strb r12, [r1, r2]
154 ret lr
155 ENDPROC(tegra20_cpu_set_resettable_soon)
156
157 /*
158 * tegra20_cpu_is_resettable_soon(void)
159 *
160- * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
161+ * Returns true if the "resettable soon" flag in IRAM variable has been
162 * set because it is expected that the secondary CPU will be idle soon.
163 */
164 ENTRY(tegra20_cpu_is_resettable_soon)
165- mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
166- ldr r12, [r1]
167+ mov32 r1, TEGRA_IRAM_RESET_BASE_VIRT
168+ ldr r2, =__tegra20_cpu1_resettable_status_offset
169+ ldrb r12, [r1, r2]
170 cmp r12, #CPU_RESETTABLE_SOON
171 moveq r0, #1
172 movne r0, #0
173@@ -256,9 +260,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish
174 mov r0, #TEGRA_FLUSH_CACHE_LOUIS
175 bl tegra_disable_clean_inv_dcache
176
177- mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
178+ mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
179+ ldr r4, =__tegra20_cpu1_resettable_status_offset
180 mov r3, #CPU_RESETTABLE
181- str r3, [r0]
182+ strb r3, [r0, r4]
183
184 bl tegra_cpu_do_idle
185
186@@ -274,10 +279,10 @@ ENTRY(tegra20_sleep_cpu_secondary_finish
187
188 bl tegra_pen_lock
189
190- mov32 r3, TEGRA_PMC_VIRT
191- add r0, r3, #PMC_SCRATCH41
192+ mov32 r0, TEGRA_IRAM_RESET_BASE_VIRT
193+ ldr r4, =__tegra20_cpu1_resettable_status_offset
194 mov r3, #CPU_NOT_RESETTABLE
195- str r3, [r0]
196+ strb r3, [r0, r4]
197
198 bl tegra_pen_unlock
199
200--- a/arch/arm/mach-tegra/sleep.h
201+++ b/arch/arm/mach-tegra/sleep.h
202@@ -18,6 +18,7 @@
203 #define __MACH_TEGRA_SLEEP_H
204
205 #include "iomap.h"
206+#include "irammap.h"
207
208 #define TEGRA_ARM_PERIF_VIRT (TEGRA_ARM_PERIF_BASE - IO_CPU_PHYS \
209 + IO_CPU_VIRT)
210@@ -29,6 +30,9 @@
211 + IO_APB_VIRT)
212 #define TEGRA_PMC_VIRT (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
213
214+#define TEGRA_IRAM_RESET_BASE_VIRT (IO_IRAM_VIRT + \
215+ TEGRA_IRAM_RESET_HANDLER_OFFSET)
216+
217 /* PMC_SCRATCH37-39 and 41 are used for tegra_pen_lock and idle */
218 #define PMC_SCRATCH37 0x130
219 #define PMC_SCRATCH38 0x134