Fix for KVMFORNFV-23(Fuel installed KVM kernel blank screens on boot).
[kvmfornfv.git] / kernel / arch / arm / mach-tegra / reset-handler.S
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/init.h>
18 #include <linux/linkage.h>
19
20 #include <soc/tegra/fuse.h>
21
22 #include <asm/asm-offsets.h>
23 #include <asm/cache.h>
24
25 #include "flowctrl.h"
26 #include "iomap.h"
27 #include "reset.h"
28 #include "sleep.h"
29
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  *
42  *      r6: SoC ID
43  *      r8: CPU part number
44  */
45 ENTRY(tegra_resume)
46         check_cpu_part_num 0xc09, r8, r9
47         bleq    v7_invalidate_l1
48
49         cpu_id  r0
50         cmp     r0, #0                          @ CPU0?
51  THUMB( it      ne )
52         bne     cpu_resume                      @ no
53
54         tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
55         /* Are we on Tegra20? */
56         cmp     r6, #TEGRA20
57         beq     1f                              @ Yes
58         /* Clear the flow controller flags for this CPU. */
59         cpu_to_csr_reg r1, r0
60         mov32   r2, TEGRA_FLOW_CTRL_BASE
61         ldr     r1, [r2, r1]
62         /* Clear event & intr flag */
63         orr     r1, r1, \
64                 #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
65         movw    r0, #0x3FFD     @ enable, cluster_switch, immed, bitmaps
66                                 @ & ext flags for CPU power mgnt
67         bic     r1, r1, r0
68         str     r1, [r2]
69 1:
70
71         mov32   r9, 0xc09
72         cmp     r8, r9
73         bne     end_ca9_scu_l2_resume
74 #ifdef CONFIG_HAVE_ARM_SCU
75         /* enable SCU */
76         mov32   r0, TEGRA_ARM_PERIF_BASE
77         ldr     r1, [r0]
78         orr     r1, r1, #1
79         str     r1, [r0]
80 #endif
81
82 #ifdef CONFIG_CACHE_L2X0
83         /* L2 cache resume & re-enable */
84         bl      l2c310_early_resume
85 #endif
86 end_ca9_scu_l2_resume:
87         mov32   r9, 0xc0f
88         cmp     r8, r9
89         bleq    tegra_init_l2_for_a15
90
91         b       cpu_resume
92 ENDPROC(tegra_resume)
93 #endif
94
95         .align L1_CACHE_SHIFT
96 ENTRY(__tegra_cpu_reset_handler_start)
97
98 /*
99  * __tegra_cpu_reset_handler:
100  *
101  * Common handler for all CPU reset events.
102  *
103  * Register usage within the reset handler:
104  *
105  *      Others: scratch
106  *      R6  = SoC ID
107  *      R7  = CPU present (to the OS) mask
108  *      R8  = CPU in LP1 state mask
109  *      R9  = CPU in LP2 state mask
110  *      R10 = CPU number
111  *      R11 = CPU mask
112  *      R12 = pointer to reset handler data
113  *
114  * NOTE: This code is copied to IRAM. All code and data accesses
115  *       must be position-independent.
116  */
117
118         .align L1_CACHE_SHIFT
119 ENTRY(__tegra_cpu_reset_handler)
120
121         cpsid   aif, 0x13                       @ SVC mode, interrupts disabled
122
123         tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
124 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
125 t20_check:
126         cmp     r6, #TEGRA20
127         bne     after_t20_check
128 t20_errata:
129         # Tegra20 is a Cortex-A9 r1p1
130         mrc     p15, 0, r0, c1, c0, 0   @ read system control register
131         orr     r0, r0, #1 << 14        @ erratum 716044
132         mcr     p15, 0, r0, c1, c0, 0   @ write system control register
133         mrc     p15, 0, r0, c15, c0, 1  @ read diagnostic register
134         orr     r0, r0, #1 << 4         @ erratum 742230
135         orr     r0, r0, #1 << 11        @ erratum 751472
136         mcr     p15, 0, r0, c15, c0, 1  @ write diagnostic register
137         b       after_errata
138 after_t20_check:
139 #endif
140 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
141 t30_check:
142         cmp     r6, #TEGRA30
143         bne     after_t30_check
144 t30_errata:
145         # Tegra30 is a Cortex-A9 r2p9
146         mrc     p15, 0, r0, c15, c0, 1  @ read diagnostic register
147         orr     r0, r0, #1 << 6         @ erratum 743622
148         orr     r0, r0, #1 << 11        @ erratum 751472
149         mcr     p15, 0, r0, c15, c0, 1  @ write diagnostic register
150         b       after_errata
151 after_t30_check:
152 #endif
153 after_errata:
154         mrc     p15, 0, r10, c0, c0, 5          @ MPIDR
155         and     r10, r10, #0x3                  @ R10 = CPU number
156         mov     r11, #1
157         mov     r11, r11, lsl r10               @ R11 = CPU mask
158         adr     r12, __tegra_cpu_reset_handler_data
159
160 #ifdef CONFIG_SMP
161         /* Does the OS know about this CPU? */
162         ldr     r7, [r12, #RESET_DATA(MASK_PRESENT)]
163         tst     r7, r11                         @ if !present
164         bleq    __die                           @ CPU not present (to OS)
165 #endif
166
167 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
168         /* Are we on Tegra20? */
169         cmp     r6, #TEGRA20
170         bne     1f
171         /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
172         mov32   r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
173         mov     r0, #CPU_NOT_RESETTABLE
174         cmp     r10, #0
175         strneb  r0, [r5, #__tegra20_cpu1_resettable_status_offset]
176 1:
177 #endif
178
179         /* Waking up from LP1? */
180         ldr     r8, [r12, #RESET_DATA(MASK_LP1)]
181         tst     r8, r11                         @ if in_lp1
182         beq     __is_not_lp1
183         cmp     r10, #0
184         bne     __die                           @ only CPU0 can be here
185         ldr     lr, [r12, #RESET_DATA(STARTUP_LP1)]
186         cmp     lr, #0
187         bleq    __die                           @ no LP1 startup handler
188  THUMB( add     lr, lr, #1 )                    @ switch to Thumb mode
189         bx      lr
190 __is_not_lp1:
191
192         /* Waking up from LP2? */
193         ldr     r9, [r12, #RESET_DATA(MASK_LP2)]
194         tst     r9, r11                         @ if in_lp2
195         beq     __is_not_lp2
196         ldr     lr, [r12, #RESET_DATA(STARTUP_LP2)]
197         cmp     lr, #0
198         bleq    __die                           @ no LP2 startup handler
199         bx      lr
200
201 __is_not_lp2:
202
203 #ifdef CONFIG_SMP
204         /*
205          * Can only be secondary boot (initial or hotplug)
206          * CPU0 can't be here for Tegra20/30
207          */
208         cmp     r6, #TEGRA114
209         beq     __no_cpu0_chk
210         cmp     r10, #0
211         bleq    __die                           @ CPU0 cannot be here
212 __no_cpu0_chk:
213         ldr     lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
214         cmp     lr, #0
215         bleq    __die                           @ no secondary startup handler
216         bx      lr
217 #endif
218
219 /*
220  * We don't know why the CPU reset. Just kill it.
221  * The LR register will contain the address we died at + 4.
222  */
223
224 __die:
225         sub     lr, lr, #4
226         mov32   r7, TEGRA_PMC_BASE
227         str     lr, [r7, #PMC_SCRATCH41]
228
229         mov32   r7, TEGRA_CLK_RESET_BASE
230
231         /* Are we on Tegra20? */
232         cmp     r6, #TEGRA20
233         bne     1f
234
235 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
236         mov32   r0, 0x1111
237         mov     r1, r0, lsl r10
238         str     r1, [r7, #0x340]                @ CLK_RST_CPU_CMPLX_SET
239 #endif
240 1:
241 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
242         mov32   r6, TEGRA_FLOW_CTRL_BASE
243
244         cmp     r10, #0
245         moveq   r1, #FLOW_CTRL_HALT_CPU0_EVENTS
246         moveq   r2, #FLOW_CTRL_CPU0_CSR
247         movne   r1, r10, lsl #3
248         addne   r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
249         addne   r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
250
251         /* Clear CPU "event" and "interrupt" flags and power gate
252            it when halting but not before it is in the "WFI" state. */
253         ldr     r0, [r6, +r2]
254         orr     r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
255         orr     r0, r0, #FLOW_CTRL_CSR_ENABLE
256         str     r0, [r6, +r2]
257
258         /* Unconditionally halt this CPU */
259         mov     r0, #FLOW_CTRL_WAITEVENT
260         str     r0, [r6, +r1]
261         ldr     r0, [r6, +r1]                   @ memory barrier
262
263         dsb
264         isb
265         wfi                                     @ CPU should be power gated here
266
267         /* If the CPU didn't power gate above just kill it's clock. */
268
269         mov     r0, r11, lsl #8
270         str     r0, [r7, #348]                  @ CLK_CPU_CMPLX_SET
271 #endif
272
273         /* If the CPU still isn't dead, just spin here. */
274         b       .
275 ENDPROC(__tegra_cpu_reset_handler)
276
277         .align L1_CACHE_SHIFT
278         .type   __tegra_cpu_reset_handler_data, %object
279         .globl  __tegra_cpu_reset_handler_data
280 __tegra_cpu_reset_handler_data:
281         .rept   TEGRA_RESET_DATA_SIZE
282         .long   0
283         .endr
284         .globl  __tegra20_cpu1_resettable_status_offset
285         .equ    __tegra20_cpu1_resettable_status_offset, \
286                                         . - __tegra_cpu_reset_handler_start
287         .byte   0
288         .align L1_CACHE_SHIFT
289
290 ENTRY(__tegra_cpu_reset_handler_end)