mm: make wait_on_page_writeback() wait for multiple pending writebacks
[linux/fpc-iii.git] / arch / arm / mach-tegra / reset-handler.S
blob06ca44b09381b303afeab5862fa7ad19415904dc
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (c) 2012, NVIDIA Corporation. All rights reserved.
4  */
6 #include <linux/init.h>
7 #include <linux/linkage.h>
9 #include <soc/tegra/flowctrl.h>
10 #include <soc/tegra/fuse.h>
12 #include <asm/assembler.h>
13 #include <asm/asm-offsets.h>
14 #include <asm/cache.h>
16 #include "iomap.h"
17 #include "reset.h"
18 #include "sleep.h"
20 #define PMC_SCRATCH41   0x140
22 #ifdef CONFIG_PM_SLEEP
24  *      tegra_resume
25  *
26  *        CPU boot vector when restarting the a CPU following
27  *        an LP2 transition. Also branched to by LP0 and LP1 resume after
28  *        re-enabling sdram.
29  *
30  *      r6: SoC ID
31  *      r8: CPU part number
32  */
33 ENTRY(tegra_resume)
34         check_cpu_part_num 0xc09, r8, r9
35         bleq    v7_invalidate_l1
37         cpu_id  r0
38         cmp     r0, #0                          @ CPU0?
39  THUMB( it      ne )
40         bne     cpu_resume                      @ no
42         tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
43         /* Are we on Tegra20? */
44         cmp     r6, #TEGRA20
45         beq     1f                              @ Yes
46         /* Clear the flow controller flags for this CPU. */
47         cpu_to_csr_reg r3, r0
48         mov32   r2, TEGRA_FLOW_CTRL_BASE
49         ldr     r1, [r2, r3]
50         /* Clear event & intr flag */
51         orr     r1, r1, \
52                 #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
53         movw    r0, #0x3FFD     @ enable, cluster_switch, immed, bitmaps
54                                 @ & ext flags for CPU power mgnt
55         bic     r1, r1, r0
56         str     r1, [r2, r3]
59         mov32   r9, 0xc09
60         cmp     r8, r9
61         bne     end_ca9_scu_l2_resume
62 #ifdef CONFIG_HAVE_ARM_SCU
63         /* enable SCU */
64         mov32   r0, TEGRA_ARM_PERIF_BASE
65         ldr     r1, [r0]
66         orr     r1, r1, #1
67         str     r1, [r0]
68 #endif
69         bl      tegra_resume_trusted_foundations
71 #ifdef CONFIG_CACHE_L2X0
72         /* L2 cache resume & re-enable */
73         bl      l2c310_early_resume
74 #endif
75 end_ca9_scu_l2_resume:
76         mov32   r9, 0xc0f
77         cmp     r8, r9
78         bleq    tegra_init_l2_for_a15
80         b       cpu_resume
81 ENDPROC(tegra_resume)
84  *      tegra_resume_trusted_foundations
85  *
86  *        Trusted Foundations firmware initialization.
87  *
88  *      Doesn't return if firmware presents.
89  *      Corrupted registers: r1, r2
90  */
91 ENTRY(tegra_resume_trusted_foundations)
92         /* Check whether Trusted Foundations firmware presents. */
93         mov32   r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
94         ldr     r1, =__tegra_cpu_reset_handler_data_offset + \
95                                                         RESET_DATA(TF_PRESENT)
96         ldr     r1, [r2, r1]
97         cmp     r1, #0
98         reteq   lr
100  .arch_extension sec
101         /*
102          * First call after suspend wakes firmware. No arguments required
103          * for some firmware versions. Downstream kernel of ASUS TF300T uses
104          * r0=3 for the wake-up notification.
105          */
106         mov     r0, #3
107         smc     #0
109         b       cpu_resume
110 ENDPROC(tegra_resume_trusted_foundations)
111 #endif
113         .align L1_CACHE_SHIFT
114 ENTRY(__tegra_cpu_reset_handler_start)
117  * __tegra_cpu_reset_handler:
119  * Common handler for all CPU reset events.
121  * Register usage within the reset handler:
123  *      Others: scratch
124  *      R6  = SoC ID
125  *      R7  = CPU present (to the OS) mask
126  *      R8  = CPU in LP1 state mask
127  *      R9  = CPU in LP2 state mask
128  *      R10 = CPU number
129  *      R11 = CPU mask
130  *      R12 = pointer to reset handler data
132  * NOTE: This code is copied to IRAM. All code and data accesses
133  *       must be position-independent.
134  */
136         .arm
137         .align L1_CACHE_SHIFT
138 ENTRY(__tegra_cpu_reset_handler)
140         cpsid   aif, 0x13                       @ SVC mode, interrupts disabled
142         tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
144         adr     r12, __tegra_cpu_reset_handler_data
145         ldr     r5, [r12, #RESET_DATA(TF_PRESENT)]
146         cmp     r5, #0
147         bne     after_errata
149 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
150 t20_check:
151         cmp     r6, #TEGRA20
152         bne     after_t20_check
153 t20_errata:
154         # Tegra20 is a Cortex-A9 r1p1
155         mrc     p15, 0, r0, c1, c0, 0   @ read system control register
156         orr     r0, r0, #1 << 14        @ erratum 716044
157         mcr     p15, 0, r0, c1, c0, 0   @ write system control register
158         mrc     p15, 0, r0, c15, c0, 1  @ read diagnostic register
159         orr     r0, r0, #1 << 4         @ erratum 742230
160         orr     r0, r0, #1 << 11        @ erratum 751472
161         mcr     p15, 0, r0, c15, c0, 1  @ write diagnostic register
162         b       after_errata
163 after_t20_check:
164 #endif
165 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
166 t30_check:
167         cmp     r6, #TEGRA30
168         bne     after_t30_check
169 t30_errata:
170         # Tegra30 is a Cortex-A9 r2p9
171         mrc     p15, 0, r0, c15, c0, 1  @ read diagnostic register
172         orr     r0, r0, #1 << 6         @ erratum 743622
173         orr     r0, r0, #1 << 11        @ erratum 751472
174         mcr     p15, 0, r0, c15, c0, 1  @ write diagnostic register
175         b       after_errata
176 after_t30_check:
177 #endif
178 after_errata:
179         mrc     p15, 0, r10, c0, c0, 5          @ MPIDR
180         and     r10, r10, #0x3                  @ R10 = CPU number
181         mov     r11, #1
182         mov     r11, r11, lsl r10               @ R11 = CPU mask
184 #ifdef CONFIG_SMP
185         /* Does the OS know about this CPU? */
186         ldr     r7, [r12, #RESET_DATA(MASK_PRESENT)]
187         tst     r7, r11                         @ if !present
188         bleq    __die                           @ CPU not present (to OS)
189 #endif
191         /* Waking up from LP1? */
192         ldr     r8, [r12, #RESET_DATA(MASK_LP1)]
193         tst     r8, r11                         @ if in_lp1
194         beq     __is_not_lp1
195         cmp     r10, #0
196         bne     __die                           @ only CPU0 can be here
197         ldr     lr, [r12, #RESET_DATA(STARTUP_LP1)]
198         cmp     lr, #0
199         bleq    __die                           @ no LP1 startup handler
200  THUMB( add     lr, lr, #1 )                    @ switch to Thumb mode
201         bx      lr
202 __is_not_lp1:
204         /* Waking up from LP2? */
205         ldr     r9, [r12, #RESET_DATA(MASK_LP2)]
206         tst     r9, r11                         @ if in_lp2
207         beq     __is_not_lp2
208         ldr     lr, [r12, #RESET_DATA(STARTUP_LP2)]
209         cmp     lr, #0
210         bleq    __die                           @ no LP2 startup handler
211         bx      lr
213 __is_not_lp2:
215 #ifdef CONFIG_SMP
216         /*
217          * Can only be secondary boot (initial or hotplug)
218          * CPU0 can't be here for Tegra20/30
219          */
220         cmp     r6, #TEGRA114
221         beq     __no_cpu0_chk
222         cmp     r10, #0
223         bleq    __die                           @ CPU0 cannot be here
224 __no_cpu0_chk:
225         ldr     lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
226         cmp     lr, #0
227         bleq    __die                           @ no secondary startup handler
228         bx      lr
229 #endif
232  * We don't know why the CPU reset. Just kill it.
233  * The LR register will contain the address we died at + 4.
234  */
236 __die:
237         sub     lr, lr, #4
238         mov32   r7, TEGRA_PMC_BASE
239         str     lr, [r7, #PMC_SCRATCH41]
241         mov32   r7, TEGRA_CLK_RESET_BASE
243         /* Are we on Tegra20? */
244         cmp     r6, #TEGRA20
245         bne     1f
247 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
248         mov32   r0, 0x1111
249         mov     r1, r0, lsl r10
250         str     r1, [r7, #0x340]                @ CLK_RST_CPU_CMPLX_SET
251 #endif
253 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
254         mov32   r6, TEGRA_FLOW_CTRL_BASE
256         cmp     r10, #0
257         moveq   r1, #FLOW_CTRL_HALT_CPU0_EVENTS
258         moveq   r2, #FLOW_CTRL_CPU0_CSR
259         movne   r1, r10, lsl #3
260         addne   r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
261         addne   r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
263         /* Clear CPU "event" and "interrupt" flags and power gate
264            it when halting but not before it is in the "WFI" state. */
265         ldr     r0, [r6, +r2]
266         orr     r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
267         orr     r0, r0, #FLOW_CTRL_CSR_ENABLE
268         str     r0, [r6, +r2]
270         /* Unconditionally halt this CPU */
271         mov     r0, #FLOW_CTRL_WAITEVENT
272         str     r0, [r6, +r1]
273         ldr     r0, [r6, +r1]                   @ memory barrier
275         dsb
276         isb
277         wfi                                     @ CPU should be power gated here
279         /* If the CPU didn't power gate above just kill it's clock. */
281         mov     r0, r11, lsl #8
282         str     r0, [r7, #348]                  @ CLK_CPU_CMPLX_SET
283 #endif
285         /* If the CPU still isn't dead, just spin here. */
286         b       .
287 ENDPROC(__tegra_cpu_reset_handler)
289         .align L1_CACHE_SHIFT
290         .type   __tegra_cpu_reset_handler_data, %object
291         .globl  __tegra_cpu_reset_handler_data
292         .globl  __tegra_cpu_reset_handler_data_offset
293         .equ    __tegra_cpu_reset_handler_data_offset, \
294                                         . - __tegra_cpu_reset_handler_start
295 __tegra_cpu_reset_handler_data:
296         .rept   TEGRA_RESET_DATA_SIZE
297         .long   0
298         .endr
299         .align L1_CACHE_SHIFT
301 ENTRY(__tegra_cpu_reset_handler_end)