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