]>
Commit | Line | Data |
---|---|---|
56c71b2c GKH |
1 | From 4d48edb3c3e1234d6b3fcdfb9ac24d7c6de449cb Mon Sep 17 00:00:00 2001 |
2 | From: Dmitry Osipenko <digetx@gmail.com> | |
3 | Date: Thu, 15 Jan 2015 13:58:57 +0300 | |
4 | Subject: ARM: tegra20: Store CPU "resettable" status in IRAM | |
5 | ||
6 | From: Dmitry Osipenko <digetx@gmail.com> | |
7 | ||
8 | commit 4d48edb3c3e1234d6b3fcdfb9ac24d7c6de449cb upstream. | |
9 | ||
10 | Commit 7232398abc6a ("ARM: tegra: Convert PMC to a driver") changed tegra_resume() | |
11 | location storing from late to early and, as a result, broke suspend on Tegra20. | |
12 | PMC scratch register 41 is used by tegra LP1 resume code for retrieving stored | |
13 | physical memory address of common resume function and in the same time used by | |
14 | tegra20_cpu_shutdown() (shared by Tegra20 cpuidle driver and platform SMP code), | |
15 | which is storing CPU1 "resettable" status. It implies strict order of scratch | |
16 | register usage, otherwise resume function address is lost on Tegra20 after | |
17 | disabling non-boot CPU's on suspend. Fix it by storing "resettable" status in | |
18 | IRAM instead of PMC scratch register. | |
19 | ||
20 | Signed-off-by: Dmitry Osipenko <digetx@gmail.com> | |
21 | Fixes: 7232398abc6a (ARM: tegra: Convert PMC to a driver) | |
22 | Signed-off-by: Thierry Reding <treding@nvidia.com> | |
23 | Signed-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 |