arm: tegra: optimize L2 enable/disable paths for secureos
[linux-3.10.git] / arch / arm / mach-tegra / sleep.S
1 /*
2  * arch/arm/mach-tegra/sleep.S
3  *
4  * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
5  * Copyright (c) 2011, Google, Inc.
6  *
7  * Author: Colin Cross <ccross@android.com>
8  *         Gary King <gking@nvidia.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
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  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23  */
24
25 #include <linux/const.h>
26 #include <linux/init.h>
27 #include <linux/linkage.h>
28
29 #include <asm/assembler.h>
30 #include <asm/cache.h>
31 #include <asm/domain.h>
32 #include <asm/memory.h>
33 #include <asm/page.h>
34 #include <asm/ptrace.h>
35 #include <asm/asm-offsets.h>
36 #include <asm/glue-cache.h>
37 #include <asm/glue-proc.h>
38 #include <asm/cp15.h>
39
40 #include "iomap.h"
41
42 #include "sleep.h"
43 #include "flowctrl.h"
44
45 #define CLK_RESET_CCLK_BURST            0x20
46 #define CLK_RESET_CCLK_DIVIDER          0x24
47
48 #define TEGRA_PMC_VIRT          (TEGRA_PMC_BASE - IO_APB_PHYS + IO_APB_VIRT)
49
50 #define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
51                                         + IO_PPSB_VIRT)
52
53 /*
54  * tegra_pen_lock
55  *
56  * spinlock implementation with no atomic test-and-set and no coherence
57  * using Peterson's algorithm on strongly-ordered registers
58  * used to synchronize a cpu waking up from wfi with entering lp2 on idle
59  *
60  * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
61  * on cpu 0:
62  * SCRATCH38 = r2 = flag[0]
63  * SCRATCH39 = r3 = flag[1]
64  * on cpu1:
65  * SCRATCH39 = r2 = flag[1]
66  * SCRATCH38 = r3 = flag[0]
67  *
68  * must be called with MMU on
69  * corrupts r0-r3, r12
70  */
71 ENTRY(tegra_pen_lock)
72         mov32   r3, TEGRA_PMC_VIRT
73         cpu_id  r0
74         add     r1, r3, #PMC_SCRATCH37
75         cmp     r0, #0
76         addeq   r2, r3, #PMC_SCRATCH38
77         addeq   r3, r3, #PMC_SCRATCH39
78         addne   r2, r3, #PMC_SCRATCH39
79         addne   r3, r3, #PMC_SCRATCH38
80
81         mov     r12, #1
82         str     r12, [r2]               @ flag[cpu] = 1
83         dsb
84         str     r12, [r1]               @ !turn = cpu
85 1:      dsb
86         ldr     r12, [r3]
87         cmp     r12, #1                 @ flag[!cpu] == 1?
88         ldreq   r12, [r1]
89         cmpeq   r12, r0                 @ !turn == cpu?
90         beq     1b                      @ while !turn == cpu && flag[!cpu] == 1
91
92         mov     pc, lr                  @ locked
93 ENDPROC(tegra_pen_lock)
94
95 ENTRY(tegra_pen_unlock)
96         dsb
97         mov32   r3, TEGRA_PMC_VIRT
98         cpu_id  r0
99         cmp     r0, #0
100         addeq   r2, r3, #PMC_SCRATCH38
101         addne   r2, r3, #PMC_SCRATCH39
102         mov     r12, #0
103         str     r12, [r2]
104         mov     pc, lr
105 ENDPROC(tegra_pen_unlock)
106
107
108 /*
109  * tegra_cpu_exit_coherency
110  *
111  * Exits SMP coherency.
112  * corrupts r4-r5
113  */
114 ENTRY(tegra_cpu_exit_coherency)
115         exit_smp r4, r5
116         mov     pc, lr
117 ENDPROC(tegra_cpu_exit_coherency)
118
119 /*
120  * tegra_flush_l1_cache
121  *
122  * clean & invalidate the L1 cache
123  *
124  * The flush_cache_all flushes all caches within level of coherence, this
125  * may not be desired if all we need is to flush L1 only. Therefore this
126  * function is implemented to flush the L1 cache only.
127  *
128  * Corrupted registers: r0-r7, r9-r11
129  */
130 ENTRY(tegra_flush_l1_cache)
131         stmfd   sp!, {r4-r5, r7, r9-r11, lr}
132         dmb                                     @ ensure ordering with previous memory accesses
133         mov     r10, #0
134 #ifdef CONFIG_PREEMPT
135         save_and_disable_irqs_notrace r9
136 #endif
137         mcr     p15, 2, r10, c0, c0, 0          @ select cache level 0
138         isb
139         mrc     p15, 1, r1, c0, c0, 0           @ read the new csidr
140 #ifdef CONFIG_PREEMPT
141         restore_irqs_notrace r9
142 #endif
143         and     r2, r1, #7                                      @ extract the length of the cache lines
144         add     r2, r2, #4                                      @ add 4 (line length offset)
145         ldr     r4, =0x3ff
146         ands    r4, r4, r1, lsr #3              @ find maximum number on the way size
147         clz     r5, r4                                          @ find bit position of way size increment
148         ldr     r7, =0x7fff
149         ands    r7, r7, r1, lsr #13             @ extract max number of the index size
150 1001:
151         mov     r9, r4                                          @ create working copy of max way size
152 1002:
153         orr     r11, r10, r9, lsl r5            @ factor way and cache number into r11
154         orr     r11, r11, r7, lsl r2            @ factor index number into r11
155         mcr     p15, 0, r11, c7, c14, 2         @ op=c10/c14, clean/flush by set/way
156         subs    r9, r9, #1                              @ decrement the way
157         bge     1002b
158         subs    r7, r7, #1                              @ decrement the index
159         bge     1001b
160         mcr     p15, 2, r10, c0, c0, 0          @ restore cache level 0
161         isb
162         dsb
163         ldmfd   sp!, {r4-r5, r7, r9-r11, lr}
164         mov     pc, lr
165 ENDPROC(tegra_flush_l1_cache)
166
167 #ifdef CONFIG_PM_SLEEP
168 /*
169  * tegra_sleep_cpu_finish(unsigned long int)
170  *
171  * enters suspend in LP2 by turning off the mmu and jumping to
172  * tegra?_tear_down_cpu
173  */
174 ENTRY(tegra_sleep_cpu_finish)
175         bl      tegra_cpu_exit_coherency
176
177 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
178         mov32   r1, tegra2_tear_down_cpu
179 #else
180         mov32   r1, tegra3_tear_down_cpu
181 #endif
182         add     r1, r1, r0
183         b       tegra_turn_off_mmu
184 ENDPROC(tegra_sleep_cpu_finish)
185
186 /*
187  * tegra_turn_off_mmu
188  *
189  * r0 = v2p
190  * r1 = physical address to jump to with mmu off
191  */
192 ENTRY(tegra_turn_off_mmu)
193         /*
194          * change page table pointer to tegra_pgd_phys, so that IRAM
195          * and MMU shut-off will be mapped virtual == physical
196          */
197         mrc     p15, 0, r2, c2, c0, 0   @ TTB 0
198         mov32   r3, ~PAGE_MASK
199         and     r2, r2, r3
200         ldr     r3, tegra_pgd_phys_address
201         ldr     r3, [r3]
202         orr     r3, r3, r2
203         mov     r2, #0
204         mcr     p15, 0, r2, c13, c0, 1  @ reserved context
205         isb
206         mcr     p15, 0, r3, c2, c0, 0   @ TTB 0
207         isb
208
209         mov     r2, #0
210         mcr     p15, 0, r2, c8, c3, 0   @ invalidate TLB
211         mcr     p15, 0, r2, c7, c5, 6   @ flush BTAC
212         mcr     p15, 0, r2, c7, c5, 0   @ flush instruction cache
213
214         mov32   r3, tegra_shut_off_mmu
215         add     r3, r3, r0
216         mov     r0, r1
217         mov     pc, r3
218 ENDPROC(tegra_turn_off_mmu)
219
220 tegra_pgd_phys_address:
221         .word   tegra_pgd_phys
222
223 /*
224  * tegra_shut_off_mmu
225  *
226  * r0 = physical address to jump to with mmu off
227  *
228  * called with VA=PA mapping
229  * turns off MMU, icache, dcache and branch prediction
230  */
231         .align  L1_CACHE_SHIFT
232 tegra_shut_off_mmu:
233         mrc     p15, 0, r3, c1, c0, 0
234         movw    r2, #CR_I | CR_Z | CR_C | CR_M
235         bic     r3, r3, r2
236         dsb
237         mcr     p15, 0, r3, c1, c0, 0
238         isb
239         mov     pc, r0
240
241 /*
242  * tegra_cpu_clk32k
243  *
244  * In LP2 the normal cpu clock pllx will be turned off. Switch the CPU to pllp
245  */
246 ENTRY(tegra_cpu_pllp)
247         /* in LP2 idle (SDRAM active), set the CPU burst policy to PLLP */
248         mov32   r5, TEGRA_CLK_RESET_BASE
249         mov     r0, #(2 << 28)                  @ burst policy = run mode
250         orr     r0, r0, #(4 << 4)               @ use PLLP in run mode burst
251         str     r0, [r5, #CLK_RESET_CCLK_BURST]
252         mov     r0, #0
253         str     r0, [r5, #CLK_RESET_CCLK_DIVIDER]
254         mov     pc, lr
255 ENDPROC(tegra_cpu_pllp)
256 #endif
257
258 #ifdef CONFIG_TRUSTED_FOUNDATIONS
259 /*
260  * Issue SMC with ctx kept on an uncached stack
261  */
262 .macro smc_issue_smc tmp
263         cpu_id  \tmp
264         cmp     \tmp, #0
265         bne     .
266         mov     r3, #0
267         mov     r4, #0
268         dsb
269         smc     #0
270 .endm
271
272 ENTRY(tegra_generic_smc_uncached)
273 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_CACHE_L2X0)
274         mov32   r3, tegra_cpu_context           @ borrow CPU0's non-cached
275         ldr     r3, [r3]                        @ context grows up
276         stmia   r3, {r4-r12, sp, lr}
277
278         smc_issue_smc r5
279
280         mov32   r3, tegra_cpu_context           @ borrow CPU0's non-cached
281         ldr     r3, [r3]                        @ context grows up
282         ldmia   r3, {r4-r12, sp, pc}
283 #else
284         mov     pc, lr
285 #endif
286 ENDPROC(tegra_generic_smc_uncached)
287
288 /*
289  * Issue SMC with ctx kept on a cacheable stack
290  *     (args in R0, R1, R2 and R3 holds save/restore ptr)
291  */
292 ENTRY(tegra_generic_smc_cached)
293         stmia   r3, {r4-r12, sp, lr}
294         adr     r4, __tegra_smc_current_ctx     @ save current ptr
295         str     r3, [r4]
296
297         smc_issue_smc r5
298
299         adr     r4, __tegra_smc_current_ctx     @ restore from saved ptr
300         ldr     r3, [r4]
301         ldmia   r3, {r4-r12, sp, pc}
302 ENDPROC(tegra_generic_smc_cached)
303         .type   __tegra_smc_current_ctx, %object
304 __tegra_smc_current_ctx:
305         .long   0
306         .size   __tegra_smc_current_ctx, . - __tegra_smc_current_ctx
307
308 #define TEGRA_SMC_SAVED_WORDS   11
309
310 /* SMC issued using the current cacheable SP stack */
311 ENTRY(tegra_generic_smc)
312         mov     r3, sp                                  @ use current stack
313         sub     r3, #(TEGRA_SMC_SAVED_WORDS << 2)       @ context grows up
314         b       tegra_generic_smc_cached
315 ENDPROC(tegra_generic_smc)
316
317 /* SMC issued using a local cacheable stack */
318 ENTRY(tegra_generic_smc_local)
319         adr     r3, __tegra_smc_stack                   @ use local stack
320         b       tegra_generic_smc_cached
321 ENDPROC(tegra_generic_smc_local)
322
323         .align  L1_CACHE_SHIFT
324         .type   __tegra_smc_stack, %object
325 __tegra_smc_stack:
326         .rept   TEGRA_SMC_SAVED_WORDS
327         .long   0
328         .endr
329         .size   __tegra_smc_stack, . - __tegra_smc_stack
330 #endif