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