]> git.sur5r.net Git - u-boot/blob - arch/arm/cpu/armv8/cache.S
SPDX: Convert all of our single license tags to Linux Kernel style
[u-boot] / arch / arm / cpu / armv8 / cache.S
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3  * (C) Copyright 2013
4  * David Feng <fenghua@phytium.com.cn>
5  *
6  * This file is based on sample code from ARMv8 ARM.
7  */
8
9 #include <asm-offsets.h>
10 #include <config.h>
11 #include <asm/macro.h>
12 #include <asm/system.h>
13 #include <linux/linkage.h>
14
15 /*
16  * void __asm_dcache_level(level)
17  *
18  * flush or invalidate one level cache.
19  *
20  * x0: cache level
21  * x1: 0 clean & invalidate, 1 invalidate only
22  * x2~x9: clobbered
23  */
24 .pushsection .text.__asm_dcache_level, "ax"
25 ENTRY(__asm_dcache_level)
26         lsl     x12, x0, #1
27         msr     csselr_el1, x12         /* select cache level */
28         isb                             /* sync change of cssidr_el1 */
29         mrs     x6, ccsidr_el1          /* read the new cssidr_el1 */
30         and     x2, x6, #7              /* x2 <- log2(cache line size)-4 */
31         add     x2, x2, #4              /* x2 <- log2(cache line size) */
32         mov     x3, #0x3ff
33         and     x3, x3, x6, lsr #3      /* x3 <- max number of #ways */
34         clz     w5, w3                  /* bit position of #ways */
35         mov     x4, #0x7fff
36         and     x4, x4, x6, lsr #13     /* x4 <- max number of #sets */
37         /* x12 <- cache level << 1 */
38         /* x2 <- line length offset */
39         /* x3 <- number of cache ways - 1 */
40         /* x4 <- number of cache sets - 1 */
41         /* x5 <- bit position of #ways */
42
43 loop_set:
44         mov     x6, x3                  /* x6 <- working copy of #ways */
45 loop_way:
46         lsl     x7, x6, x5
47         orr     x9, x12, x7             /* map way and level to cisw value */
48         lsl     x7, x4, x2
49         orr     x9, x9, x7              /* map set number to cisw value */
50         tbz     w1, #0, 1f
51         dc      isw, x9
52         b       2f
53 1:      dc      cisw, x9                /* clean & invalidate by set/way */
54 2:      subs    x6, x6, #1              /* decrement the way */
55         b.ge    loop_way
56         subs    x4, x4, #1              /* decrement the set */
57         b.ge    loop_set
58
59         ret
60 ENDPROC(__asm_dcache_level)
61 .popsection
62
63 /*
64  * void __asm_flush_dcache_all(int invalidate_only)
65  *
66  * x0: 0 clean & invalidate, 1 invalidate only
67  *
68  * flush or invalidate all data cache by SET/WAY.
69  */
70 .pushsection .text.__asm_dcache_all, "ax"
71 ENTRY(__asm_dcache_all)
72         mov     x1, x0
73         dsb     sy
74         mrs     x10, clidr_el1          /* read clidr_el1 */
75         lsr     x11, x10, #24
76         and     x11, x11, #0x7          /* x11 <- loc */
77         cbz     x11, finished           /* if loc is 0, exit */
78         mov     x15, lr
79         mov     x0, #0                  /* start flush at cache level 0 */
80         /* x0  <- cache level */
81         /* x10 <- clidr_el1 */
82         /* x11 <- loc */
83         /* x15 <- return address */
84
85 loop_level:
86         lsl     x12, x0, #1
87         add     x12, x12, x0            /* x0 <- tripled cache level */
88         lsr     x12, x10, x12
89         and     x12, x12, #7            /* x12 <- cache type */
90         cmp     x12, #2
91         b.lt    skip                    /* skip if no cache or icache */
92         bl      __asm_dcache_level      /* x1 = 0 flush, 1 invalidate */
93 skip:
94         add     x0, x0, #1              /* increment cache level */
95         cmp     x11, x0
96         b.gt    loop_level
97
98         mov     x0, #0
99         msr     csselr_el1, x0          /* restore csselr_el1 */
100         dsb     sy
101         isb
102         mov     lr, x15
103
104 finished:
105         ret
106 ENDPROC(__asm_dcache_all)
107 .popsection
108
109 .pushsection .text.__asm_flush_dcache_all, "ax"
110 ENTRY(__asm_flush_dcache_all)
111         mov     x0, #0
112         b       __asm_dcache_all
113 ENDPROC(__asm_flush_dcache_all)
114 .popsection
115
116 .pushsection .text.__asm_invalidate_dcache_all, "ax"
117 ENTRY(__asm_invalidate_dcache_all)
118         mov     x0, #0x1
119         b       __asm_dcache_all
120 ENDPROC(__asm_invalidate_dcache_all)
121 .popsection
122
123 /*
124  * void __asm_flush_dcache_range(start, end)
125  *
126  * clean & invalidate data cache in the range
127  *
128  * x0: start address
129  * x1: end address
130  */
131 .pushsection .text.__asm_flush_dcache_range, "ax"
132 ENTRY(__asm_flush_dcache_range)
133         mrs     x3, ctr_el0
134         lsr     x3, x3, #16
135         and     x3, x3, #0xf
136         mov     x2, #4
137         lsl     x2, x2, x3              /* cache line size */
138
139         /* x2 <- minimal cache line size in cache system */
140         sub     x3, x2, #1
141         bic     x0, x0, x3
142 1:      dc      civac, x0       /* clean & invalidate data or unified cache */
143         add     x0, x0, x2
144         cmp     x0, x1
145         b.lo    1b
146         dsb     sy
147         ret
148 ENDPROC(__asm_flush_dcache_range)
149 .popsection
150 /*
151  * void __asm_invalidate_dcache_range(start, end)
152  *
153  * invalidate data cache in the range
154  *
155  * x0: start address
156  * x1: end address
157  */
158 .pushsection .text.__asm_invalidate_dcache_range, "ax"
159 ENTRY(__asm_invalidate_dcache_range)
160         mrs     x3, ctr_el0
161         ubfm    x3, x3, #16, #19
162         mov     x2, #4
163         lsl     x2, x2, x3              /* cache line size */
164
165         /* x2 <- minimal cache line size in cache system */
166         sub     x3, x2, #1
167         bic     x0, x0, x3
168 1:      dc      ivac, x0        /* invalidate data or unified cache */
169         add     x0, x0, x2
170         cmp     x0, x1
171         b.lo    1b
172         dsb     sy
173         ret
174 ENDPROC(__asm_invalidate_dcache_range)
175 .popsection
176
177 /*
178  * void __asm_invalidate_icache_all(void)
179  *
180  * invalidate all tlb entries.
181  */
182 .pushsection .text.__asm_invalidate_icache_all, "ax"
183 ENTRY(__asm_invalidate_icache_all)
184         ic      ialluis
185         isb     sy
186         ret
187 ENDPROC(__asm_invalidate_icache_all)
188 .popsection
189
190 .pushsection .text.__asm_invalidate_l3_dcache, "ax"
191 ENTRY(__asm_invalidate_l3_dcache)
192         mov     x0, #0                  /* return status as success */
193         ret
194 ENDPROC(__asm_invalidate_l3_dcache)
195         .weak   __asm_invalidate_l3_dcache
196 .popsection
197
198 .pushsection .text.__asm_flush_l3_dcache, "ax"
199 ENTRY(__asm_flush_l3_dcache)
200         mov     x0, #0                  /* return status as success */
201         ret
202 ENDPROC(__asm_flush_l3_dcache)
203         .weak   __asm_flush_l3_dcache
204 .popsection
205
206 .pushsection .text.__asm_invalidate_l3_icache, "ax"
207 ENTRY(__asm_invalidate_l3_icache)
208         mov     x0, #0                  /* return status as success */
209         ret
210 ENDPROC(__asm_invalidate_l3_icache)
211         .weak   __asm_invalidate_l3_icache
212 .popsection
213
214 /*
215  * void __asm_switch_ttbr(ulong new_ttbr)
216  *
217  * Safely switches to a new page table.
218  */
219 .pushsection .text.__asm_switch_ttbr, "ax"
220 ENTRY(__asm_switch_ttbr)
221         /* x2 = SCTLR (alive throghout the function) */
222         switch_el x4, 3f, 2f, 1f
223 3:      mrs     x2, sctlr_el3
224         b       0f
225 2:      mrs     x2, sctlr_el2
226         b       0f
227 1:      mrs     x2, sctlr_el1
228 0:
229
230         /* Unset CR_M | CR_C | CR_I from SCTLR to disable all caches */
231         movn    x1, #(CR_M | CR_C | CR_I)
232         and     x1, x2, x1
233         switch_el x4, 3f, 2f, 1f
234 3:      msr     sctlr_el3, x1
235         b       0f
236 2:      msr     sctlr_el2, x1
237         b       0f
238 1:      msr     sctlr_el1, x1
239 0:      isb
240
241         /* This call only clobbers x30 (lr) and x9 (unused) */
242         mov     x3, x30
243         bl      __asm_invalidate_tlb_all
244
245         /* From here on we're running safely with caches disabled */
246
247         /* Set TTBR to our first argument */
248         switch_el x4, 3f, 2f, 1f
249 3:      msr     ttbr0_el3, x0
250         b       0f
251 2:      msr     ttbr0_el2, x0
252         b       0f
253 1:      msr     ttbr0_el1, x0
254 0:      isb
255
256         /* Restore original SCTLR and thus enable caches again */
257         switch_el x4, 3f, 2f, 1f
258 3:      msr     sctlr_el3, x2
259         b       0f
260 2:      msr     sctlr_el2, x2
261         b       0f
262 1:      msr     sctlr_el1, x2
263 0:      isb
264
265         ret     x3
266 ENDPROC(__asm_switch_ttbr)
267 .popsection