aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/headsmp.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/headsmp.S')
-rw-r--r--arch/arm/mach-tegra/headsmp.S387
1 files changed, 332 insertions, 55 deletions
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index b5349b2f13d..4a9f03ffd97 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -1,61 +1,338 @@
1/*
2 * arch/arm/mach-tegra/headsmp.S
3 *
4 * CPU initialization routines for Tegra SoCs
5 *
6 * Copyright (c) 2009-2011, NVIDIA Corporation.
7 * Copyright (c) 2011 Google, Inc.
8 * Author: Colin Cross <ccross@android.com>
9 * Gary King <gking@nvidia.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 */
20
1#include <linux/linkage.h> 21#include <linux/linkage.h>
2#include <linux/init.h> 22#include <linux/init.h>
3 23
4 .section ".text.head", "ax" 24#include <asm/assembler.h>
5 __CPUINIT 25#include <asm/cache.h>
6 26#include <asm/page.h>
7/* 27
8 * Tegra specific entry point for secondary CPUs. 28#include <mach/iomap.h>
9 * The secondary kernel init calls v7_flush_dcache_all before it enables 29#include <mach/io.h>
10 * the L1; however, the L1 comes out of reset in an undefined state, so 30
11 * the clean + invalidate performed by v7_flush_dcache_all causes a bunch 31#include "asm_macros.h"
12 * of cache lines with uninitialized data and uninitialized tags to get 32#include "reset.h"
13 * written out to memory, which does really unpleasant things to the main 33#include "sleep.h"
14 * processor. We fix this by performing an invalidate, rather than a 34
15 * clean + invalidate, before jumping into the kernel. 35#define DEBUG_CPU_RESET_HANDLER 0 /* Non-zero enables debug code */
16 */ 36
17ENTRY(v7_invalidate_l1) 37#define PMC_SCRATCH41 0x140
18 mov r0, #0 38
19 mcr p15, 2, r0, c0, c0, 0 39#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
20 mrc p15, 1, r0, c0, c0, 0
21
22 ldr r1, =0x7fff
23 and r2, r1, r0, lsr #13
24
25 ldr r1, =0x3ff
26
27 and r3, r1, r0, lsr #3 @ NumWays - 1
28 add r2, r2, #1 @ NumSets
29
30 and r0, r0, #0x7
31 add r0, r0, #4 @ SetShift
32
33 clz r1, r3 @ WayShift
34 add r4, r3, #1 @ NumWays
351: sub r2, r2, #1 @ NumSets--
36 mov r3, r4 @ Temp = NumWays
372: subs r3, r3, #1 @ Temp--
38 mov r5, r3, lsl r1
39 mov r6, r2, lsl r0
40 orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
41 mcr p15, 0, r5, c7, c6, 2
42 bgt 2b
43 cmp r2, #0
44 bgt 1b
45 dsb
46 isb
47 mov pc, lr
48ENDPROC(v7_invalidate_l1)
49 40
41
42#ifdef CONFIG_SMP
43/*
44 * tegra_secondary_startup
45 *
46 * Initial secondary processor boot vector; jumps to kernel's
47 * secondary_startup routine. Used for initial boot and hotplug
48 * of secondary CPUs.
49 */
50ENTRY(tegra_secondary_startup) 50ENTRY(tegra_secondary_startup)
51 msr cpsr_fsxc, #0xd3 51 bl __invalidate_cpu_state
52 bl v7_invalidate_l1 52 b secondary_startup
53 mrc p15, 0, r0, c0, c0, 5
54 and r0, r0, #15
55 ldr r1, =0x6000f100
56 str r0, [r1]
571: ldr r2, [r1]
58 cmp r0, r2
59 beq 1b
60 b secondary_startup
61ENDPROC(tegra_secondary_startup) 53ENDPROC(tegra_secondary_startup)
54#endif
55
56#ifdef CONFIG_PM_SLEEP
57/*
58 * tegra_resume
59 *
60 * CPU boot vector when restarting the a CPU following
61 * an LP2 transition. Also branched to by LP0 and LP1 resume after
62 * re-enabling sdram.
63 */
64ENTRY(tegra_resume)
65 bl __invalidate_cpu_state
66
67 cpu_id r0
68 cmp r0, #0 @ CPU0?
69 bne tegra_cpu_resume_phys @ no
70
71#ifndef CONFIG_ARCH_TEGRA_2x_SOC
72 @ Clear the flow controller flags for this CPU.
73 mov32 r2, TEGRA_FLOW_CTRL_BASE+8 @ CPU0 CSR
74 ldr r1, [r2]
75 orr r1, r1, #(1 << 15) | (1 << 14) @ write to clear event & intr
76 movw r0, #0x0FFD @ enable, cluster_switch, immed, & bitmaps
77 bic r1, r1, r0
78 str r1, [r2]
79#endif
80
81 /* enable SCU */
82 mov32 r0, TEGRA_ARM_PERIF_BASE
83 ldr r1, [r0]
84 orr r1, r1, #1
85#if defined(CONFIG_HAVE_ARM_SCU)
86 orr r1, r1, #(1 << 3) @ Enabled SCU speculative line fill.
87#endif
88 str r1, [r0]
89
90#ifdef CONFIG_TRUSTED_FOUNDATIONS
91 /* wake up (should have specified args?) */
92 bl tegra_generic_smc
93#endif
94
95 b tegra_cpu_resume_phys
96ENDPROC(tegra_resume)
97#endif
98
99/*
100 * __invalidate_cpu_state
101 *
102 * Invalidates volatile CPU state (SCU tags, caches, branch address
103 * arrays, exclusive monitor, etc.) so that they can be safely enabled
104 * instruction caching and branch predicition enabled
105 */
106__invalidate_cpu_state:
107 clrex
108 mov r0, #0
109 mcr p15, 0, r0, c1, c0, 1 @ disable SMP, prefetch, broadcast
110 isb
111 mcr p15, 0, r0, c7, c5, 0 @ invalidate BTAC, i-cache
112 mcr p15, 0, r0, c7, c5, 6 @ invalidate branch pred array
113 mcr p15, 0, r0, c8, c7, 0 @ invalidate unified TLB
114 dsb
115 isb
116
117 cpu_id r0
118 cmp r0, #0
119 mov32 r1, (TEGRA_ARM_PERIF_BASE + 0xC)
120 movne r0, r0, lsl #2
121 movne r2, #0xf
122 movne r2, r2, lsl r0
123 strne r2, [r1] @ invalidate SCU tags for CPU
124
125 dsb
126 mov r0, #0x1800
127 mcr p15, 0, r0, c1, c0, 0 @ enable branch prediction, i-cache
128 isb
129 /* fall through */
130
131/*
132 * tegra_invalidate_l1
133 *
134 * Invalidates the L1 data cache (no clean) during initial boot of a cpu
135 *
136 * Corrupted registers: r0-r6
137 */
138tegra_invalidate_l1:
139 mov r0, #0
140 mcr p15, 2, r0, c0, c0, 0
141 mrc p15, 1, r0, c0, c0, 0
142
143 movw r1, #0x7fff
144 and r2, r1, r0, lsr #13
145
146 movw r1, #0x3ff
147
148 and r3, r1, r0, lsr #3 @ NumWays - 1
149 add r2, r2, #1 @ NumSets
150
151 and r0, r0, #0x7
152 add r0, r0, #4 @ SetShift
153
154 clz r1, r3 @ WayShift
155 add r4, r3, #1 @ NumWays
1561: sub r2, r2, #1 @ NumSets--
157 mov r3, r4 @ Temp = NumWays
1582: subs r3, r3, #1 @ Temp--
159 mov r5, r3, lsl r1
160 mov r6, r2, lsl r0
161 orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
162 mcr p15, 0, r5, c7, c6, 2
163 bgt 2b
164 cmp r2, #0
165 bgt 1b
166 dsb
167 isb
168 mov pc, lr
169
170/*
171 * __tegra_cpu_reset_handler_halt_failed:
172 *
173 * Alternate entry point for reset handler for cases where the
174 * WFI halt failed to take effect.
175 *
176 */
177 .align L1_CACHE_SHIFT
178ENTRY(__tegra_cpu_reset_handler_start)
179
180/*
181 * __tegra_cpu_reset_handler:
182 *
183 * Common handler for all CPU reset events.
184 *
185 * Register usage within the reset handler:
186 *
187 * R7 = CPU present (to the OS) mask
188 * R8 = CPU in LP1 state mask
189 * R9 = CPU in LP2 state mask
190 * R10 = CPU number
191 * R11 = CPU mask
192 * R12 = pointer to reset handler data
193 *
194 * NOTE: This code is copied to IRAM. All code and data accesses
195 * must be position-independent.
196 */
197
198 .align L1_CACHE_SHIFT
199ENTRY(__tegra_cpu_reset_handler)
200
201#if DEBUG_CPU_RESET_HANDLER
202 b .
203#endif
204#ifndef CONFIG_TRUSTED_FOUNDATIONS
205 cpsid aif, 0x13 @ SVC mode, interrupts disabled
206 mrc p15, 0, r0, c0, c0, 0 @ read main ID register
207 and r5, r0, #0x00f00000 @ variant
208 and r6, r0, #0x0000000f @ revision
209 orr r6, r6, r5, lsr #20-4 @ combine variant and revision
210#ifdef CONFIG_ARM_ERRATA_743622
211 teq r6, #0x20 @ present in r2p0
212 teqne r6, #0x21 @ present in r2p1
213 teqne r6, #0x22 @ present in r2p2
214 teqne r6, #0x27 @ present in r2p7
215 teqne r6, #0x29 @ present in r2p9
216 mrceq p15, 0, r10, c15, c0, 1 @ read diagnostic register
217 orreq r10, r10, #1 << 6 @ set bit #6
218 mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
219#endif
220#endif
221 mrc p15, 0, r10, c0, c0, 5 @ MPIDR
222 and r10, r10, #0x3 @ R10 = CPU number
223 mov r11, #1
224 mov r11, r11, lsl r10 @ R11 = CPU mask
225 adr r12, __tegra_cpu_reset_handler_data
226
227#ifdef CONFIG_SMP
228 /* Does the OS know about this CPU? */
229 ldr r7, [r12, #RESET_DATA(MASK_PRESENT)]
230 tst r7, r11 @ if !present
231 bleq __die @ CPU not present (to OS)
232#endif
233
234#ifdef CONFIG_ARCH_TEGRA_2x_SOC
235 /* If CPU1, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
236 mov32 r6, TEGRA_PMC_BASE
237 mov r0, #0
238 cmp r10, #0
239 strne r0, [r6, #PMC_SCRATCH41]
240#endif
241
242#ifdef CONFIG_PM_SLEEP
243 /* Waking up from LP1? */
244 ldr r8, [r12, #RESET_DATA(MASK_LP1)]
245 tst r8, r11 @ if in_lp1
246 beq __is_not_lp1
247 cmp r10, #0
248 bne __die @ only CPU0 can be here
249 ldr lr, [r12, #RESET_DATA(STARTUP_LP1)]
250 cmp lr, #0
251 bleq __die @ no LP1 startup handler
252 bx lr
253__is_not_lp1:
254#endif
255
256 /* Waking up from LP2? */
257 ldr r9, [r12, #RESET_DATA(MASK_LP2)]
258 tst r9, r11 @ if in_lp2
259 beq __is_not_lp2
260 ldr lr, [r12, #RESET_DATA(STARTUP_LP2)]
261 cmp lr, #0
262 bleq __die @ no LP2 startup handler
263 bx lr
264
265__is_not_lp2:
266
267#ifdef CONFIG_SMP
268 /* Can only be secondary boot (initial or hotplug) but CPU 0
269 cannot be here. */
270 cmp r10, #0
271 bleq __die @ CPU0 cannot be here
272 ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
273 cmp lr, #0
274 bleq __die @ no secondary startup handler
275 bx lr
276#endif
277
278/*
279 * We don't know why the CPU reset. Just kill it.
280 * The LR register will contain the address we died at + 4.
281 */
282
283__die:
284 sub lr, lr, #4
285 mov32 r7, TEGRA_PMC_BASE
286 str lr, [r7, #PMC_SCRATCH41]
287
288 mov32 r7, TEGRA_CLK_RESET_BASE
289
290#ifdef CONFIG_ARCH_TEGRA_2x_SOC
291 mov32 r0, 0x1111
292 mov r1, r0, lsl r10
293 str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET
294#else
295 mov32 r6, TEGRA_FLOW_CTRL_BASE
296
297 cmp r10, #0
298 moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS
299 moveq r2, #FLOW_CTRL_CPU0_CSR
300 movne r1, r10, lsl #3
301 addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
302 addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
303
304 /* Clear CPU "event" and "interrupt" flags and power gate
305 it when halting but not before it is in the "WFI" state. */
306 ldr r0, [r6, +r2]
307 orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
308 orr r0, r0, #FLOW_CTRL_CSR_ENABLE
309 str r0, [r6, +r2]
310
311 /* Unconditionally halt this CPU */
312 mov r0, #FLOW_CTRL_WAITEVENT
313 str r0, [r6, +r1]
314 ldr r0, [r6, +r1] @ memory barrier
315
316 dsb
317 isb
318 wfi @ CPU should be power gated here
319
320 /* If the CPU didn't power gate above just kill it's clock. */
321
322 mov r0, r11, lsl #8
323 str r0, [r7, #348] @ CLK_CPU_CMPLX_SET
324#endif
325 /* If the CPU still isn't dead, just spin here. */
326 b .
327
328ENDPROC(__tegra_cpu_reset_handler)
329 .align L1_CACHE_SHIFT
330 .type __tegra_cpu_reset_handler_data, %object
331 .globl __tegra_cpu_reset_handler_data
332__tegra_cpu_reset_handler_data:
333 .rept TEGRA_RESET_DATA_SIZE
334 .long 0
335 .endr
336 .size __tegra_cpu_reset_handler_data, . - __tegra_cpu_reset_handler_data
337 .align L1_CACHE_SHIFT
338ENTRY(__tegra_cpu_reset_handler_end)