aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/reset-handler.S
diff options
context:
space:
mode:
authorJoseph Lo <josephl@nvidia.com>2013-01-04 04:32:22 -0500
committerStephen Warren <swarren@nvidia.com>2013-01-28 13:14:06 -0500
commit9e32366fe51fea464adb21c244f372d55207e13c (patch)
tree2afe44644ee7d424bab09d1d30d640d42eb84e02 /arch/arm/mach-tegra/reset-handler.S
parent8c627fa6583a4894189a47a0bf868f7848b51748 (diff)
ARM: tegra: make device can run on UP
The reset handler code is used for either UP or SMP. To make Tegra device can compile for UP. It needs to be moved to another file that is not SMP only. This is because the reset handler also be needed by CPU idle "powered-down" mode. So we also need to put the reset handler init function in non-SMP only and init them always. And currently the implementation of the reset handler to know which CPU is OK to bring up was identital with "cpu_present_mask". But the "cpu_present_mask" did not initialize yet when the reset handler init function was moved to init early function. We use the "cpu_possible_mask" to replace "cpu_present_mask". Then it can work on both UP and SMP case. Signed-off-by: Joseph Lo <josephl@nvidia.com> [swarren: dropped the move of v7_invalidate_l1() from one file to another, to avoid conflicts with Pavel's cleanup of this function, adjust Makefile so each line only contains 1 file.] Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/reset-handler.S')
-rw-r--r--arch/arm/mach-tegra/reset-handler.S239
1 files changed, 239 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
new file mode 100644
index 000000000000..54382ceade4a
--- /dev/null
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -0,0 +1,239 @@
1/*
2 * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <linux/linkage.h>
18#include <linux/init.h>
19
20#include <asm/cache.h>
21#include <asm/asm-offsets.h>
22#include <asm/hardware/cache-l2x0.h>
23
24#include "flowctrl.h"
25#include "iomap.h"
26#include "reset.h"
27#include "sleep.h"
28
29#define APB_MISC_GP_HIDREV 0x804
30#define PMC_SCRATCH41 0x140
31
32#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
33
34#ifdef CONFIG_PM_SLEEP
35/*
36 * tegra_resume
37 *
38 * CPU boot vector when restarting the a CPU following
39 * an LP2 transition. Also branched to by LP0 and LP1 resume after
40 * re-enabling sdram.
41 */
42ENTRY(tegra_resume)
43 bl v7_invalidate_l1
44 /* Enable coresight */
45 mov32 r0, 0xC5ACCE55
46 mcr p14, 0, r0, c7, c12, 6
47
48 cpu_id r0
49 cmp r0, #0 @ CPU0?
50 bne cpu_resume @ no
51
52#ifdef CONFIG_ARCH_TEGRA_3x_SOC
53 /* Are we on Tegra20? */
54 mov32 r6, TEGRA_APB_MISC_BASE
55 ldr r0, [r6, #APB_MISC_GP_HIDREV]
56 and r0, r0, #0xff00
57 cmp r0, #(0x20 << 8)
58 beq 1f @ Yes
59 /* Clear the flow controller flags for this CPU. */
60 mov32 r2, TEGRA_FLOW_CTRL_BASE + FLOW_CTRL_CPU0_CSR @ CPU0 CSR
61 ldr r1, [r2]
62 /* Clear event & intr flag */
63 orr r1, r1, \
64 #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
65 movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
66 bic r1, r1, r0
67 str r1, [r2]
681:
69#endif
70
71#ifdef CONFIG_HAVE_ARM_SCU
72 /* enable SCU */
73 mov32 r0, TEGRA_ARM_PERIF_BASE
74 ldr r1, [r0]
75 orr r1, r1, #1
76 str r1, [r0]
77#endif
78
79 /* L2 cache resume & re-enable */
80 l2_cache_resume r0, r1, r2, l2x0_saved_regs_addr
81
82 b cpu_resume
83ENDPROC(tegra_resume)
84#endif
85
86#ifdef CONFIG_CACHE_L2X0
87 .globl l2x0_saved_regs_addr
88l2x0_saved_regs_addr:
89 .long 0
90#endif
91
92 .align L1_CACHE_SHIFT
93ENTRY(__tegra_cpu_reset_handler_start)
94
95/*
96 * __tegra_cpu_reset_handler:
97 *
98 * Common handler for all CPU reset events.
99 *
100 * Register usage within the reset handler:
101 *
102 * R7 = CPU present (to the OS) mask
103 * R8 = CPU in LP1 state mask
104 * R9 = CPU in LP2 state mask
105 * R10 = CPU number
106 * R11 = CPU mask
107 * R12 = pointer to reset handler data
108 *
109 * NOTE: This code is copied to IRAM. All code and data accesses
110 * must be position-independent.
111 */
112
113 .align L1_CACHE_SHIFT
114ENTRY(__tegra_cpu_reset_handler)
115
116 cpsid aif, 0x13 @ SVC mode, interrupts disabled
117 mrc p15, 0, r10, c0, c0, 5 @ MPIDR
118 and r10, r10, #0x3 @ R10 = CPU number
119 mov r11, #1
120 mov r11, r11, lsl r10 @ R11 = CPU mask
121 adr r12, __tegra_cpu_reset_handler_data
122
123#ifdef CONFIG_SMP
124 /* Does the OS know about this CPU? */
125 ldr r7, [r12, #RESET_DATA(MASK_PRESENT)]
126 tst r7, r11 @ if !present
127 bleq __die @ CPU not present (to OS)
128#endif
129
130#ifdef CONFIG_ARCH_TEGRA_2x_SOC
131 /* Are we on Tegra20? */
132 mov32 r6, TEGRA_APB_MISC_BASE
133 ldr r0, [r6, #APB_MISC_GP_HIDREV]
134 and r0, r0, #0xff00
135 cmp r0, #(0x20 << 8)
136 bne 1f
137 /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
138 mov32 r6, TEGRA_PMC_BASE
139 mov r0, #0
140 cmp r10, #0
141 strne r0, [r6, #PMC_SCRATCH41]
1421:
143#endif
144
145 /* Waking up from LP2? */
146 ldr r9, [r12, #RESET_DATA(MASK_LP2)]
147 tst r9, r11 @ if in_lp2
148 beq __is_not_lp2
149 ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
150 cmp lr, #0
151 bleq __die @ no LP2 startup handler
152 bx lr
153
154__is_not_lp2:
155
156#ifdef CONFIG_SMP
157 /*
158 * Can only be secondary boot (initial or hotplug) but CPU 0
159 * cannot be here.
160 */
161 cmp r10, #0
162 bleq __die @ CPU0 cannot be here
163 ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
164 cmp lr, #0
165 bleq __die @ no secondary startup handler
166 bx lr
167#endif
168
169/*
170 * We don't know why the CPU reset. Just kill it.
171 * The LR register will contain the address we died at + 4.
172 */
173
174__die:
175 sub lr, lr, #4
176 mov32 r7, TEGRA_PMC_BASE
177 str lr, [r7, #PMC_SCRATCH41]
178
179 mov32 r7, TEGRA_CLK_RESET_BASE
180
181 /* Are we on Tegra20? */
182 mov32 r6, TEGRA_APB_MISC_BASE
183 ldr r0, [r6, #APB_MISC_GP_HIDREV]
184 and r0, r0, #0xff00
185 cmp r0, #(0x20 << 8)
186 bne 1f
187
188#ifdef CONFIG_ARCH_TEGRA_2x_SOC
189 mov32 r0, 0x1111
190 mov r1, r0, lsl r10
191 str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET
192#endif
1931:
194#ifdef CONFIG_ARCH_TEGRA_3x_SOC
195 mov32 r6, TEGRA_FLOW_CTRL_BASE
196
197 cmp r10, #0
198 moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS
199 moveq r2, #FLOW_CTRL_CPU0_CSR
200 movne r1, r10, lsl #3
201 addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
202 addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
203
204 /* Clear CPU "event" and "interrupt" flags and power gate
205 it when halting but not before it is in the "WFI" state. */
206 ldr r0, [r6, +r2]
207 orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
208 orr r0, r0, #FLOW_CTRL_CSR_ENABLE
209 str r0, [r6, +r2]
210
211 /* Unconditionally halt this CPU */
212 mov r0, #FLOW_CTRL_WAITEVENT
213 str r0, [r6, +r1]
214 ldr r0, [r6, +r1] @ memory barrier
215
216 dsb
217 isb
218 wfi @ CPU should be power gated here
219
220 /* If the CPU didn't power gate above just kill it's clock. */
221
222 mov r0, r11, lsl #8
223 str r0, [r7, #348] @ CLK_CPU_CMPLX_SET
224#endif
225
226 /* If the CPU still isn't dead, just spin here. */
227 b .
228ENDPROC(__tegra_cpu_reset_handler)
229
230 .align L1_CACHE_SHIFT
231 .type __tegra_cpu_reset_handler_data, %object
232 .globl __tegra_cpu_reset_handler_data
233__tegra_cpu_reset_handler_data:
234 .rept TEGRA_RESET_DATA_SIZE
235 .long 0
236 .endr
237 .align L1_CACHE_SHIFT
238
239ENTRY(__tegra_cpu_reset_handler_end)