ARM: tegra: Redesign Tegra CPU reset handling
[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/cache.h>
25 #include <asm/page.h>
26
27 #include "flowctrl.h"
28 #include "iomap.h"
29 #include "reset.h"
30 #include "sleep.h"
31
32 #define DEBUG_CPU_RESET_HANDLER 0       /* Non-zero enables debug code */
33
34 #define APB_MISC_GP_HIDREV      0x804
35 #define PMC_SCRATCH41   0x140
36
37 #define RESET_DATA(x)   ((TEGRA_RESET_##x)*4)
38
39         .section ".text.head", "ax"
40         __CPUINIT
41
42 /*
43  *   The secondary kernel init calls v7_flush_dcache_all before it enables
44  *   the L1; however, the L1 comes out of reset in an undefined state, so
45  *   the clean + invalidate performed by v7_flush_dcache_all causes a bunch
46  *   of cache lines with uninitialized data and uninitialized tags to get
47  *   written out to memory, which does really unpleasant things to the main
48  *   processor.  We fix this by performing an invalidate, rather than a
49  *   clean + invalidate, before jumping into the kernel.
50  */
51 ENTRY(v7_invalidate_l1)
52         mov     r0, #0
53         mcr     p15, 2, r0, c0, c0, 0
54         mrc     p15, 1, r0, c0, c0, 0
55
56         ldr     r1, =0x7fff
57         and     r2, r1, r0, lsr #13
58
59         ldr     r1, =0x3ff
60
61         and     r3, r1, r0, lsr #3  @ NumWays - 1
62         add     r2, r2, #1          @ NumSets
63
64         and     r0, r0, #0x7
65         add     r0, r0, #4          @ SetShift
66
67         clz     r1, r3              @ WayShift
68         add     r4, r3, #1          @ NumWays
69 1:      sub     r2, r2, #1          @ NumSets--
70         mov     r3, r4              @ Temp = NumWays
71 2:      subs    r3, r3, #1          @ Temp--
72         mov     r5, r3, lsl r1
73         mov     r6, r2, lsl r0
74         orr     r5, r5, r6          @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
75         mcr     p15, 0, r5, c7, c6, 2
76         bgt     2b
77         cmp     r2, #0
78         bgt     1b
79         dsb
80         isb
81         mov     pc, lr
82 ENDPROC(v7_invalidate_l1)
83
84
85 #ifdef CONFIG_SMP
86 /* 
87  *      tegra_secondary_startup
88  *
89  *       Initial secondary processor boot vector; jumps to kernel's
90  *       secondary_startup routine. Used for initial boot and hotplug
91  *       of secondary CPUs.
92  */
93 ENTRY(tegra_secondary_startup)
94         bl      v7_invalidate_l1
95         /* Enable coresight */
96         mov32   r0, 0xC5ACCE55
97         mcr     p14, 0, r0, c7, c12, 6
98         b       secondary_startup
99 ENDPROC(tegra_secondary_startup)
100 #endif
101
102 #ifdef CONFIG_PM_SLEEP
103 /*
104  *      tegra_resume
105  *
106  *        CPU boot vector when restarting the a CPU following
107  *        an LP2 transition. Also branched to by LP0 and LP1 resume after
108  *        re-enabling sdram.
109  */
110 ENTRY(tegra_resume)
111         bl      tegra_enable_coresite
112         bl      tegra_invalidate_l1
113
114         cpu_id  r0
115         cmp     r0, #0                          @ CPU0?
116         bne     cpu_resume                      @ no
117
118 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
119         @ Clear the flow controller flags for this CPU.
120         mov32   r2, TEGRA_FLOW_CTRL_BASE+8      @ CPU0 CSR
121         ldr     r1, [r2]
122         orr     r1, r1, #(1 << 15) | (1 << 14)  @ write to clear event & intr
123         movw    r0, #0x0FFD     @ enable, cluster_switch, immed, & bitmaps
124         bic     r1, r1, r0
125         str     r1, [r2]
126 #endif
127
128         /* enable SCU */
129         mov32   r0, TEGRA_ARM_PERIF_BASE
130         ldr     r1, [r0]
131         orr     r1, r1, #1
132         str     r1, [r0]
133
134         b       cpu_resume
135 ENDPROC(tegra_resume)
136 #endif
137
138         .align L1_CACHE_SHIFT
139 ENTRY(__tegra_cpu_reset_handler_start)
140
141 /*
142  * __tegra_cpu_reset_handler:
143  *
144  * Common handler for all CPU reset events.
145  *
146  * Register usage within the reset handler:
147  *
148  *      R7  = CPU present (to the OS) mask
149  *      R8  = CPU in LP1 state mask
150  *      R9  = CPU in LP2 state mask
151  *      R10 = CPU number
152  *      R11 = CPU mask
153  *      R12 = pointer to reset handler data
154  *
155  * NOTE: This code is copied to IRAM. All code and data accesses
156  *       must be position-independent.
157  */
158
159         .align L1_CACHE_SHIFT
160 ENTRY(__tegra_cpu_reset_handler)
161
162 #if DEBUG_CPU_RESET_HANDLER
163         mov32   r0, 0xC5ACCE55
164         mcr     p14, 0, r0, c7, c12, 6          @ Enable CoreSight access
165         b       .
166 #endif
167         cpsid   aif, 0x13                       @ SVC mode, interrupts disabled
168         mrc     p15, 0, r10, c0, c0, 5          @ MPIDR
169         and     r10, r10, #0x3                  @ R10 = CPU number
170         mov     r11, #1
171         mov     r11, r11, lsl r10               @ R11 = CPU mask
172         adr     r12, __tegra_cpu_reset_handler_data
173
174 #ifdef CONFIG_SMP
175         /* Does the OS know about this CPU? */
176         ldr     r7, [r12, #RESET_DATA(MASK_PRESENT)]
177         tst     r7, r11                         @ if !present
178         bleq    __die                           @ CPU not present (to OS)
179 #endif
180
181 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
182         /* Are we on Tegra20? */
183         mov32   r6, TEGRA_APB_MISC_BASE
184         ldr     r0, [r6, #APB_MISC_GP_HIDREV]
185         and     r0, r0, #0xff00
186         cmp     r0, #(0x20 << 8)
187         bne     1f
188         /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
189         mov32   r6, TEGRA_PMC_BASE
190         mov     r0, #0
191         cmp     r10, #0
192         strne   r0, [r6, #PMC_SCRATCH41]
193 1:
194 #endif
195
196 #ifdef CONFIG_PM_SLEEP
197         /* Waking up from LP1? */
198         ldr     r8, [r12, #RESET_DATA(MASK_LP1)]
199         tst     r8, r11                         @ if in_lp1
200         beq     __is_not_lp1
201         cmp     r10, #0
202         bne     __die                           @ only CPU0 can be here
203         ldr     lr, [r12, #RESET_DATA(STARTUP_LP1)]
204         cmp     lr, #0
205         bleq    __die                           @ no LP1 startup handler
206         bx      lr
207 __is_not_lp1:
208 #endif
209
210         /* Waking up from LP2? */
211         ldr     r9, [r12, #RESET_DATA(MASK_LP2)]
212         tst     r9, r11                         @ if in_lp2
213         beq     __is_not_lp2
214 #if defined(CONFIG_SMP) && defined(CONFIG_ARCH_TEGRA_2x_SOC)
215         /* Tegra2 CPU1 LP2 wakeup uses the secondary startup handler */
216         cmp     r10, #1
217         bne     __is_not_lp2
218 #endif
219         ldr     lr, [r12, #RESET_DATA(STARTUP_LP2)]
220         cmp     lr, #0
221         bleq    __die                           @ no LP2 startup handler
222         bx      lr
223
224 __is_not_lp2:
225 #ifdef CONFIG_SMP
226         /*
227          * Can only be secondary boot (initial or hotplug) but CPU 0
228          * cannot be here.
229          */
230         cmp     r10, #0
231         bleq    __die                           @ CPU0 cannot be here
232         ldr     lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
233         cmp     lr, #0
234         bleq    __die                           @ no secondary startup handler
235         bx      lr
236 #endif
237
238 /*
239  * We don't know why the CPU reset. Just kill it.
240  * The LR register will contain the address we died at + 4.
241  */
242
243 __die:
244         sub     lr, lr, #4
245         mov32   r7, TEGRA_PMC_BASE
246         str     lr, [r7, #PMC_SCRATCH41]
247
248         mov32   r7, TEGRA_CLK_RESET_BASE
249
250         /* Are we on Tegra20? */
251         mov32   r6, TEGRA_APB_MISC_BASE
252         ldr     r0, [r6, #APB_MISC_GP_HIDREV]
253         and     r0, r0, #0xff00
254         cmp     r0, #(0x20 << 8)
255         bne     1f
256
257 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
258         mov32   r0, 0x1111
259         mov     r1, r0, lsl r10
260         str     r1, [r7, #0x340]                @ CLK_RST_CPU_CMPLX_SET
261 #endif
262 1:
263 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
264         mov32   r6, TEGRA_FLOW_CTRL_BASE
265
266         cmp     r10, #0
267         moveq   r1, #FLOW_CTRL_HALT_CPU0_EVENTS
268         moveq   r2, #FLOW_CTRL_CPU0_CSR
269         movne   r1, r10, lsl #3
270         addne   r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
271         addne   r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
272
273         /* Clear CPU "event" and "interrupt" flags and power gate
274            it when halting but not before it is in the "WFI" state. */
275         ldr     r0, [r6, +r2]
276         orr     r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
277         orr     r0, r0, #FLOW_CTRL_CSR_ENABLE
278         str     r0, [r6, +r2]
279
280         /* Unconditionally halt this CPU */
281         mov     r0, #FLOW_CTRL_WAITEVENT
282         str     r0, [r6, +r1]
283         ldr     r0, [r6, +r1]                   @ memory barrier
284
285         dsb
286         isb
287         wfi                                     @ CPU should be power gated here
288
289         /* If the CPU didn't power gate above just kill it's clock. */
290
291         mov     r0, r11, lsl #8
292         str     r0, [r7, #348]                  @ CLK_CPU_CMPLX_SET
293 #endif
294
295         /* If the CPU still isn't dead, just spin here. */
296         b       .
297 ENDPROC(__tegra_cpu_reset_handler)
298
299         .align L1_CACHE_SHIFT
300         .type   __tegra_cpu_reset_handler_data, %object
301         .globl  __tegra_cpu_reset_handler_data
302 __tegra_cpu_reset_handler_data:
303         .rept   TEGRA_RESET_DATA_SIZE
304         .long   0
305         .endr
306         .align L1_CACHE_SHIFT
307
308 ENTRY(__tegra_cpu_reset_handler_end)