xref: /arm-trusted-firmware/lib/aarch64/cache_helpers.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu *
4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu */
6*91f16700Schasinglulu
7*91f16700Schasinglulu#include <arch.h>
8*91f16700Schasinglulu#include <asm_macros.S>
9*91f16700Schasinglulu
10*91f16700Schasinglulu	.globl	flush_dcache_range
11*91f16700Schasinglulu	.globl	flush_dcache_to_popa_range
12*91f16700Schasinglulu	.globl	clean_dcache_range
13*91f16700Schasinglulu	.globl	inv_dcache_range
14*91f16700Schasinglulu	.globl	dcsw_op_louis
15*91f16700Schasinglulu	.globl	dcsw_op_all
16*91f16700Schasinglulu	.globl	dcsw_op_level1
17*91f16700Schasinglulu	.globl	dcsw_op_level2
18*91f16700Schasinglulu	.globl	dcsw_op_level3
19*91f16700Schasinglulu
20*91f16700Schasinglulu/*
21*91f16700Schasinglulu * This macro can be used for implementing various data cache operations `op`
22*91f16700Schasinglulu */
23*91f16700Schasinglulu.macro do_dcache_maintenance_by_mva op
24*91f16700Schasinglulu	/* Exit early if size is zero */
25*91f16700Schasinglulu	cbz	x1, exit_loop_\op
26*91f16700Schasinglulu	dcache_line_size x2, x3
27*91f16700Schasinglulu	add	x1, x0, x1
28*91f16700Schasinglulu	sub	x3, x2, #1
29*91f16700Schasinglulu	bic	x0, x0, x3
30*91f16700Schasinglululoop_\op:
31*91f16700Schasinglulu	dc	\op, x0
32*91f16700Schasinglulu	add	x0, x0, x2
33*91f16700Schasinglulu	cmp	x0, x1
34*91f16700Schasinglulu	b.lo	loop_\op
35*91f16700Schasinglulu	dsb	sy
36*91f16700Schasingluluexit_loop_\op:
37*91f16700Schasinglulu	ret
38*91f16700Schasinglulu.endm
39*91f16700Schasinglulu
40*91f16700Schasinglulu.macro check_plat_can_cmo
41*91f16700Schasinglulu#if CONDITIONAL_CMO
42*91f16700Schasinglulu	mov	x3, x30
43*91f16700Schasinglulu	mov	x2, x0
44*91f16700Schasinglulu	bl	plat_can_cmo
45*91f16700Schasinglulu	mov	x30, x3
46*91f16700Schasinglulu	cbnz	x0, 1f
47*91f16700Schasinglulu	ret
48*91f16700Schasinglulu1:
49*91f16700Schasinglulu	mov	 x0, x2
50*91f16700Schasinglulu#endif
51*91f16700Schasinglulu.endm
52*91f16700Schasinglulu	/* ------------------------------------------
53*91f16700Schasinglulu	 * Clean+Invalidate from base address till
54*91f16700Schasinglulu	 * size. 'x0' = addr, 'x1' = size
55*91f16700Schasinglulu	 * ------------------------------------------
56*91f16700Schasinglulu	 */
57*91f16700Schasinglulufunc flush_dcache_range
58*91f16700Schasinglulu	check_plat_can_cmo
59*91f16700Schasinglulu	do_dcache_maintenance_by_mva civac
60*91f16700Schasingluluendfunc flush_dcache_range
61*91f16700Schasinglulu
62*91f16700Schasinglulu	/* ------------------------------------------
63*91f16700Schasinglulu	 * Clean from base address till size.
64*91f16700Schasinglulu	 * 'x0' = addr, 'x1' = size
65*91f16700Schasinglulu	 * ------------------------------------------
66*91f16700Schasinglulu	 */
67*91f16700Schasinglulufunc clean_dcache_range
68*91f16700Schasinglulu	check_plat_can_cmo
69*91f16700Schasinglulu	do_dcache_maintenance_by_mva cvac
70*91f16700Schasingluluendfunc clean_dcache_range
71*91f16700Schasinglulu
72*91f16700Schasinglulu	/* ------------------------------------------
73*91f16700Schasinglulu	 * Invalidate from base address till
74*91f16700Schasinglulu	 * size. 'x0' = addr, 'x1' = size
75*91f16700Schasinglulu	 * ------------------------------------------
76*91f16700Schasinglulu	 */
77*91f16700Schasinglulufunc inv_dcache_range
78*91f16700Schasinglulu	check_plat_can_cmo
79*91f16700Schasinglulu	do_dcache_maintenance_by_mva ivac
80*91f16700Schasingluluendfunc inv_dcache_range
81*91f16700Schasinglulu
82*91f16700Schasinglulu
83*91f16700Schasinglulu	/*
84*91f16700Schasinglulu	 * On implementations with FEAT_MTE2,
85*91f16700Schasinglulu	 * Root firmware must issue DC_CIGDPAPA instead of DC_CIPAPA ,
86*91f16700Schasinglulu	 * in order to additionally clean and invalidate Allocation Tags
87*91f16700Schasinglulu	 * associated with the affected locations.
88*91f16700Schasinglulu	 *
89*91f16700Schasinglulu	 * ------------------------------------------
90*91f16700Schasinglulu	 * Clean+Invalidate by PA to POPA
91*91f16700Schasinglulu	 * from base address till size.
92*91f16700Schasinglulu	 * 'x0' = addr, 'x1' = size
93*91f16700Schasinglulu	 * ------------------------------------------
94*91f16700Schasinglulu	 */
95*91f16700Schasinglulufunc flush_dcache_to_popa_range
96*91f16700Schasinglulu	/* Exit early if size is zero */
97*91f16700Schasinglulu	cbz	x1, exit_loop_dc_cipapa
98*91f16700Schasinglulu	check_plat_can_cmo
99*91f16700Schasinglulu	dcache_line_size x2, x3
100*91f16700Schasinglulu	sub	x3, x2, #1
101*91f16700Schasinglulu	bic	x0, x0, x3
102*91f16700Schasinglulu	add	x1, x1, x0
103*91f16700Schasinglululoop_dc_cipapa:
104*91f16700Schasinglulu	sys	#6, c7, c14, #1, x0 /* DC CIPAPA,<Xt> */
105*91f16700Schasinglulu	add	x0, x0, x2
106*91f16700Schasinglulu	cmp	x0, x1
107*91f16700Schasinglulu	b.lo	loop_dc_cipapa
108*91f16700Schasinglulu	dsb	osh
109*91f16700Schasingluluexit_loop_dc_cipapa:
110*91f16700Schasinglulu	ret
111*91f16700Schasingluluendfunc	flush_dcache_to_popa_range
112*91f16700Schasinglulu
113*91f16700Schasinglulu	/* ---------------------------------------------------------------
114*91f16700Schasinglulu	 * Data cache operations by set/way to the level specified
115*91f16700Schasinglulu	 *
116*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
117*91f16700Schasinglulu	 * x0: The operation type (0-2), as defined in arch.h
118*91f16700Schasinglulu	 * x3: The last cache level to operate on
119*91f16700Schasinglulu	 * x9: clidr_el1
120*91f16700Schasinglulu	 * x10: The cache level to begin operation from
121*91f16700Schasinglulu	 * and will carry out the operation on each data cache from level 0
122*91f16700Schasinglulu	 * to the level in x3 in sequence
123*91f16700Schasinglulu	 *
124*91f16700Schasinglulu	 * The dcsw_op macro sets up the x3 and x9 parameters based on
125*91f16700Schasinglulu	 * clidr_el1 cache information before invoking the main function
126*91f16700Schasinglulu	 * ---------------------------------------------------------------
127*91f16700Schasinglulu	 */
128*91f16700Schasinglulu
129*91f16700Schasinglulu	.macro	dcsw_op shift, fw, ls
130*91f16700Schasinglulu	mrs	x9, clidr_el1
131*91f16700Schasinglulu	ubfx	x3, x9, \shift, \fw
132*91f16700Schasinglulu	lsl	x3, x3, \ls
133*91f16700Schasinglulu	mov	x10, xzr
134*91f16700Schasinglulu	b	do_dcsw_op
135*91f16700Schasinglulu	.endm
136*91f16700Schasinglulu
137*91f16700Schasinglulufunc do_dcsw_op
138*91f16700Schasinglulu	cbz	x3, exit
139*91f16700Schasinglulu	mrs	x12, ID_AA64MMFR2_EL1	// stash FEAT_CCIDX identifier in x12
140*91f16700Schasinglulu	ubfx	x12, x12, #ID_AA64MMFR2_EL1_CCIDX_SHIFT, #ID_AA64MMFR2_EL1_CCIDX_LENGTH
141*91f16700Schasinglulu	adr	x14, dcsw_loop_table	// compute inner loop address
142*91f16700Schasinglulu	add	x14, x14, x0, lsl #5	// inner loop is 8x32-bit instructions
143*91f16700Schasinglulu#if ENABLE_BTI
144*91f16700Schasinglulu	add	x14, x14, x0, lsl #2	// inner loop is + "bti j" instruction
145*91f16700Schasinglulu#endif
146*91f16700Schasinglulu	mov	x0, x9
147*91f16700Schasinglulu	mov	w8, #1
148*91f16700Schasinglululoop1:
149*91f16700Schasinglulu	add	x2, x10, x10, lsr #1	// work out 3x current cache level
150*91f16700Schasinglulu	lsr	x1, x0, x2		// extract cache type bits from clidr
151*91f16700Schasinglulu	and	x1, x1, #7		// mask the bits for current cache only
152*91f16700Schasinglulu	cmp	x1, #2			// see what cache we have at this level
153*91f16700Schasinglulu	b.lo	level_done		// nothing to do if no cache or icache
154*91f16700Schasinglulu
155*91f16700Schasinglulu	msr	csselr_el1, x10		// select current cache level in csselr
156*91f16700Schasinglulu	isb				// isb to sych the new cssr&csidr
157*91f16700Schasinglulu	mrs	x1, ccsidr_el1		// read the new ccsidr
158*91f16700Schasinglulu	and	x2, x1, #7		// extract the length of the cache lines
159*91f16700Schasinglulu	add	x2, x2, #4		// add 4 (line length offset)
160*91f16700Schasinglulu
161*91f16700Schasinglulu	cbz	x12, 1f			// check for FEAT_CCIDX for Associativity
162*91f16700Schasinglulu	ubfx	x4, x1, #3, #21 	// x4 = associativity CCSIDR_EL1[23:3]
163*91f16700Schasinglulu	b 	2f
164*91f16700Schasinglulu1:
165*91f16700Schasinglulu	ubfx	x4, x1, #3, #10 	// x4 = associativity CCSIDR_EL1[12:3]
166*91f16700Schasinglulu2:
167*91f16700Schasinglulu	clz	w5, w4			// bit position of way size increment
168*91f16700Schasinglulu	lsl	w9, w4, w5		// w9 = aligned max way number
169*91f16700Schasinglulu	lsl	w16, w8, w5		// w16 = way number loop decrement
170*91f16700Schasinglulu	orr	w9, w10, w9		// w9 = combine way and cache number
171*91f16700Schasinglulu
172*91f16700Schasinglulu	cbz	x12, 3f			// check for FEAT_CCIDX for NumSets
173*91f16700Schasinglulu	ubfx	x6, x1, #32, #24	// x6 (w6) = numsets CCSIDR_EL1[55:32]
174*91f16700Schasinglulu					// ISA will not allow x->w ubfx
175*91f16700Schasinglulu	b	4f
176*91f16700Schasinglulu3:
177*91f16700Schasinglulu	ubfx	w6, w1, #13, #15	// w6 = numsets CCSIDR_EL1[27:13]
178*91f16700Schasinglulu4:
179*91f16700Schasinglulu	lsl	w17, w8, w2		// w17 = set number loop decrement
180*91f16700Schasinglulu	dsb	sy			// barrier before we start this level
181*91f16700Schasinglulu	br	x14			// jump to DC operation specific loop
182*91f16700Schasinglulu
183*91f16700Schasinglulu	.macro	dcsw_loop _op
184*91f16700Schasinglulu#if ENABLE_BTI
185*91f16700Schasinglulu	bti	j
186*91f16700Schasinglulu#endif
187*91f16700Schasinglululoop2_\_op:
188*91f16700Schasinglulu	lsl	w7, w6, w2		// w7 = aligned max set number
189*91f16700Schasinglulu
190*91f16700Schasinglululoop3_\_op:
191*91f16700Schasinglulu	orr	w11, w9, w7		// combine cache, way and set number
192*91f16700Schasinglulu	dc	\_op, x11
193*91f16700Schasinglulu	subs	w7, w7, w17		// decrement set number
194*91f16700Schasinglulu	b.hs	loop3_\_op
195*91f16700Schasinglulu
196*91f16700Schasinglulu	subs	x9, x9, x16		// decrement way number
197*91f16700Schasinglulu	b.hs	loop2_\_op
198*91f16700Schasinglulu
199*91f16700Schasinglulu	b	level_done
200*91f16700Schasinglulu	.endm
201*91f16700Schasinglulu
202*91f16700Schasinglululevel_done:
203*91f16700Schasinglulu	add	x10, x10, #2		// increment cache number
204*91f16700Schasinglulu	cmp	x3, x10
205*91f16700Schasinglulu	b.hi	loop1
206*91f16700Schasinglulu	msr	csselr_el1, xzr		// select cache level 0 in csselr
207*91f16700Schasinglulu	dsb	sy			// barrier to complete final cache operation
208*91f16700Schasinglulu	isb
209*91f16700Schasingluluexit:
210*91f16700Schasinglulu	ret
211*91f16700Schasingluluendfunc do_dcsw_op
212*91f16700Schasinglulu
213*91f16700Schasingluludcsw_loop_table:
214*91f16700Schasinglulu	dcsw_loop isw
215*91f16700Schasinglulu	dcsw_loop cisw
216*91f16700Schasinglulu	dcsw_loop csw
217*91f16700Schasinglulu
218*91f16700Schasinglulu
219*91f16700Schasinglulufunc dcsw_op_louis
220*91f16700Schasinglulu	check_plat_can_cmo
221*91f16700Schasinglulu	dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
222*91f16700Schasingluluendfunc dcsw_op_louis
223*91f16700Schasinglulu
224*91f16700Schasinglulu
225*91f16700Schasinglulufunc dcsw_op_all
226*91f16700Schasinglulu	check_plat_can_cmo
227*91f16700Schasinglulu	dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
228*91f16700Schasingluluendfunc dcsw_op_all
229*91f16700Schasinglulu
230*91f16700Schasinglulu	/* ---------------------------------------------------------------
231*91f16700Schasinglulu	 *  Helper macro for data cache operations by set/way for the
232*91f16700Schasinglulu	 *  level specified
233*91f16700Schasinglulu	 * ---------------------------------------------------------------
234*91f16700Schasinglulu	 */
235*91f16700Schasinglulu	.macro dcsw_op_level level
236*91f16700Schasinglulu	mrs	x9, clidr_el1
237*91f16700Schasinglulu	mov	x3, \level
238*91f16700Schasinglulu	sub	x10, x3, #2
239*91f16700Schasinglulu	b	do_dcsw_op
240*91f16700Schasinglulu	.endm
241*91f16700Schasinglulu
242*91f16700Schasinglulu	/* ---------------------------------------------------------------
243*91f16700Schasinglulu	 * Data cache operations by set/way for level 1 cache
244*91f16700Schasinglulu	 *
245*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
246*91f16700Schasinglulu	 * x0: The operation type (0-2), as defined in arch.h
247*91f16700Schasinglulu	 * ---------------------------------------------------------------
248*91f16700Schasinglulu	 */
249*91f16700Schasinglulufunc dcsw_op_level1
250*91f16700Schasinglulu	check_plat_can_cmo
251*91f16700Schasinglulu	dcsw_op_level #(1 << LEVEL_SHIFT)
252*91f16700Schasingluluendfunc dcsw_op_level1
253*91f16700Schasinglulu
254*91f16700Schasinglulu	/* ---------------------------------------------------------------
255*91f16700Schasinglulu	 * Data cache operations by set/way for level 2 cache
256*91f16700Schasinglulu	 *
257*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
258*91f16700Schasinglulu	 * x0: The operation type (0-2), as defined in arch.h
259*91f16700Schasinglulu	 * ---------------------------------------------------------------
260*91f16700Schasinglulu	 */
261*91f16700Schasinglulufunc dcsw_op_level2
262*91f16700Schasinglulu	check_plat_can_cmo
263*91f16700Schasinglulu	dcsw_op_level #(2 << LEVEL_SHIFT)
264*91f16700Schasingluluendfunc dcsw_op_level2
265*91f16700Schasinglulu
266*91f16700Schasinglulu	/* ---------------------------------------------------------------
267*91f16700Schasinglulu	 * Data cache operations by set/way for level 3 cache
268*91f16700Schasinglulu	 *
269*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
270*91f16700Schasinglulu	 * x0: The operation type (0-2), as defined in arch.h
271*91f16700Schasinglulu	 * ---------------------------------------------------------------
272*91f16700Schasinglulu	 */
273*91f16700Schasinglulufunc dcsw_op_level3
274*91f16700Schasinglulu	check_plat_can_cmo
275*91f16700Schasinglulu	dcsw_op_level #(3 << LEVEL_SHIFT)
276*91f16700Schasingluluendfunc dcsw_op_level3
277