xref: /arm-trusted-firmware/lib/aarch32/cache_helpers.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2016-2021, 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	clean_dcache_range
12*91f16700Schasinglulu	.globl	inv_dcache_range
13*91f16700Schasinglulu	.globl	dcsw_op_louis
14*91f16700Schasinglulu	.globl	dcsw_op_all
15*91f16700Schasinglulu	.globl	dcsw_op_level1
16*91f16700Schasinglulu	.globl	dcsw_op_level2
17*91f16700Schasinglulu	.globl	dcsw_op_level3
18*91f16700Schasinglulu
19*91f16700Schasinglulu/*
20*91f16700Schasinglulu * This macro can be used for implementing various data cache operations `op`
21*91f16700Schasinglulu */
22*91f16700Schasinglulu.macro do_dcache_maintenance_by_mva op, coproc, opc1, CRn, CRm, opc2
23*91f16700Schasinglulu	/* Exit early if size is zero */
24*91f16700Schasinglulu	cmp	r1, #0
25*91f16700Schasinglulu	beq	exit_loop_\op
26*91f16700Schasinglulu	dcache_line_size r2, r3
27*91f16700Schasinglulu	add	r1, r0, r1
28*91f16700Schasinglulu	sub	r3, r2, #1
29*91f16700Schasinglulu	bic	r0, r0, r3
30*91f16700Schasinglululoop_\op:
31*91f16700Schasinglulu	stcopr	r0, \coproc, \opc1, \CRn, \CRm, \opc2
32*91f16700Schasinglulu	add	r0, r0, r2
33*91f16700Schasinglulu	cmp	r0, r1
34*91f16700Schasinglulu	blo	loop_\op
35*91f16700Schasinglulu	dsb	sy
36*91f16700Schasingluluexit_loop_\op:
37*91f16700Schasinglulu	bx	lr
38*91f16700Schasinglulu.endm
39*91f16700Schasinglulu
40*91f16700Schasinglulu	/* ------------------------------------------
41*91f16700Schasinglulu	 * Clean+Invalidate from base address till
42*91f16700Schasinglulu	 * size. 'r0' = addr, 'r1' = size
43*91f16700Schasinglulu	 * ------------------------------------------
44*91f16700Schasinglulu	 */
45*91f16700Schasinglulufunc flush_dcache_range
46*91f16700Schasinglulu	do_dcache_maintenance_by_mva cimvac, DCCIMVAC
47*91f16700Schasingluluendfunc flush_dcache_range
48*91f16700Schasinglulu
49*91f16700Schasinglulu	/* ------------------------------------------
50*91f16700Schasinglulu	 * Clean from base address till size.
51*91f16700Schasinglulu	 * 'r0' = addr, 'r1' = size
52*91f16700Schasinglulu	 * ------------------------------------------
53*91f16700Schasinglulu	 */
54*91f16700Schasinglulufunc clean_dcache_range
55*91f16700Schasinglulu	do_dcache_maintenance_by_mva cmvac, DCCMVAC
56*91f16700Schasingluluendfunc clean_dcache_range
57*91f16700Schasinglulu
58*91f16700Schasinglulu	/* ------------------------------------------
59*91f16700Schasinglulu	 * Invalidate from base address till
60*91f16700Schasinglulu	 * size. 'r0' = addr, 'r1' = size
61*91f16700Schasinglulu	 * ------------------------------------------
62*91f16700Schasinglulu	 */
63*91f16700Schasinglulufunc inv_dcache_range
64*91f16700Schasinglulu	do_dcache_maintenance_by_mva imvac, DCIMVAC
65*91f16700Schasingluluendfunc inv_dcache_range
66*91f16700Schasinglulu
67*91f16700Schasinglulu	/* ----------------------------------------------------------------
68*91f16700Schasinglulu	 * Data cache operations by set/way to the level specified
69*91f16700Schasinglulu	 *
70*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
71*91f16700Schasinglulu	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
72*91f16700Schasinglulu	 * as defined in arch.h
73*91f16700Schasinglulu	 * r1: The cache level to begin operation from
74*91f16700Schasinglulu	 * r2: clidr_el1
75*91f16700Schasinglulu	 * r3: The last cache level to operate on
76*91f16700Schasinglulu	 * and will carry out the operation on each data cache from level 0
77*91f16700Schasinglulu	 * to the level in r3 in sequence
78*91f16700Schasinglulu	 *
79*91f16700Schasinglulu	 * The dcsw_op macro sets up the r2 and r3 parameters based on
80*91f16700Schasinglulu	 * clidr_el1 cache information before invoking the main function
81*91f16700Schasinglulu	 * ----------------------------------------------------------------
82*91f16700Schasinglulu	 */
83*91f16700Schasinglulu
84*91f16700Schasinglulu	.macro	dcsw_op shift, fw, ls
85*91f16700Schasinglulu	ldcopr	r2, CLIDR
86*91f16700Schasinglulu	ubfx	r3, r2, \shift, \fw
87*91f16700Schasinglulu	lsl	r3, r3, \ls
88*91f16700Schasinglulu	mov	r1, #0
89*91f16700Schasinglulu	b	do_dcsw_op
90*91f16700Schasinglulu	.endm
91*91f16700Schasinglulu
92*91f16700Schasinglulufunc do_dcsw_op
93*91f16700Schasinglulu	push	{r4-r12, lr}
94*91f16700Schasinglulu	ldcopr	r8, ID_MMFR4		// stash FEAT_CCIDX identifier in r8
95*91f16700Schasinglulu	ubfx	r8, r8, #ID_MMFR4_CCIDX_SHIFT, #ID_MMFR4_CCIDX_LENGTH
96*91f16700Schasinglulu	adr	r11, dcsw_loop_table	// compute cache op based on the operation type
97*91f16700Schasinglulu	add	r6, r11, r0, lsl #3	// cache op is 2x32-bit instructions
98*91f16700Schasinglululoop1:
99*91f16700Schasinglulu	add	r10, r1, r1, LSR #1	// Work out 3x current cache level
100*91f16700Schasinglulu	mov	r12, r2, LSR r10	// extract cache type bits from clidr
101*91f16700Schasinglulu	and	r12, r12, #7		// mask the bits for current cache only
102*91f16700Schasinglulu	cmp	r12, #2			// see what cache we have at this level
103*91f16700Schasinglulu	blo	level_done		// no cache or only instruction cache at this level
104*91f16700Schasinglulu
105*91f16700Schasinglulu	stcopr	r1, CSSELR		// select current cache level in csselr
106*91f16700Schasinglulu	isb				// isb to sych the new cssr&csidr
107*91f16700Schasinglulu	ldcopr	r12, CCSIDR		// read the new ccsidr
108*91f16700Schasinglulu	and	r10, r12, #7		// extract the length of the cache lines
109*91f16700Schasinglulu	add	r10, r10, #4		// add 4 (r10 = line length offset)
110*91f16700Schasinglulu
111*91f16700Schasinglulu	cmp	r8, #0			// check for FEAT_CCIDX for Associativity
112*91f16700Schasinglulu	beq	1f
113*91f16700Schasinglulu	ubfx	r4, r12, #3, #21 	// r4 = associativity CCSIDR[23:3]
114*91f16700Schasinglulu	b	2f
115*91f16700Schasinglulu1:
116*91f16700Schasinglulu	ubfx	r4, r12, #3, #10 	// r4 = associativity CCSIDR[12:3]
117*91f16700Schasinglulu2:
118*91f16700Schasinglulu	clz	r5, r4			// r5 = the bit position of the way size increment
119*91f16700Schasinglulu	mov	r9, r4			// r9 working copy of the aligned max way number
120*91f16700Schasinglulu
121*91f16700Schasinglululoop2:
122*91f16700Schasinglulu	cmp	r8, #0			// check for FEAT_CCIDX for NumSets
123*91f16700Schasinglulu	beq	3f
124*91f16700Schasinglulu	ldcopr	r12, CCSIDR2		// FEAT_CCIDX numsets is in CCSIDR2
125*91f16700Schasinglulu	ubfx	r7, r12, #0, #24	// r7 = numsets CCSIDR2[23:0]
126*91f16700Schasinglulu	b	loop3
127*91f16700Schasinglulu3:
128*91f16700Schasinglulu	ubfx	r7, r12, #13, #15	// r7 = numsets CCSIDR[27:13]
129*91f16700Schasinglululoop3:
130*91f16700Schasinglulu	orr	r0, r1, r9, LSL r5	// factor in the way number and cache level into r0
131*91f16700Schasinglulu	orr	r0, r0, r7, LSL r10	// factor in the set number
132*91f16700Schasinglulu
133*91f16700Schasinglulu	blx	r6
134*91f16700Schasinglulu	subs	r7, r7, #1		// decrement the set number
135*91f16700Schasinglulu	bhs	loop3
136*91f16700Schasinglulu	subs	r9, r9, #1		// decrement the way number
137*91f16700Schasinglulu	bhs	loop2
138*91f16700Schasinglululevel_done:
139*91f16700Schasinglulu	add	r1, r1, #2		// increment the cache number
140*91f16700Schasinglulu	cmp	r3, r1
141*91f16700Schasinglulu	// Ensure completion of previous cache maintenance instruction. Note
142*91f16700Schasinglulu	// this also mitigates erratum 814220 on Cortex-A7
143*91f16700Schasinglulu	dsb	sy
144*91f16700Schasinglulu	bhi	loop1
145*91f16700Schasinglulu
146*91f16700Schasinglulu	mov	r6, #0
147*91f16700Schasinglulu	stcopr	r6, CSSELR		//select cache level 0 in csselr
148*91f16700Schasinglulu	dsb	sy
149*91f16700Schasinglulu	isb
150*91f16700Schasinglulu	pop	{r4-r12, pc}
151*91f16700Schasinglulu
152*91f16700Schasingluludcsw_loop_table:
153*91f16700Schasinglulu	stcopr	r0, DCISW
154*91f16700Schasinglulu	bx	lr
155*91f16700Schasinglulu	stcopr	r0, DCCISW
156*91f16700Schasinglulu	bx	lr
157*91f16700Schasinglulu	stcopr	r0, DCCSW
158*91f16700Schasinglulu	bx	lr
159*91f16700Schasinglulu
160*91f16700Schasingluluendfunc do_dcsw_op
161*91f16700Schasinglulu
162*91f16700Schasinglulu	/* ---------------------------------------------------------------
163*91f16700Schasinglulu	 * Data cache operations by set/way till PoU.
164*91f16700Schasinglulu	 *
165*91f16700Schasinglulu	 * The function requires :
166*91f16700Schasinglulu	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
167*91f16700Schasinglulu	 * as defined in arch.h
168*91f16700Schasinglulu	 * ---------------------------------------------------------------
169*91f16700Schasinglulu	 */
170*91f16700Schasinglulufunc dcsw_op_louis
171*91f16700Schasinglulu	dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
172*91f16700Schasingluluendfunc	dcsw_op_louis
173*91f16700Schasinglulu
174*91f16700Schasinglulu	/* ---------------------------------------------------------------
175*91f16700Schasinglulu	 * Data cache operations by set/way till PoC.
176*91f16700Schasinglulu	 *
177*91f16700Schasinglulu	 * The function requires :
178*91f16700Schasinglulu	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
179*91f16700Schasinglulu	 * as defined in arch.h
180*91f16700Schasinglulu	 * ---------------------------------------------------------------
181*91f16700Schasinglulu	 */
182*91f16700Schasinglulufunc dcsw_op_all
183*91f16700Schasinglulu	dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT
184*91f16700Schasingluluendfunc	dcsw_op_all
185*91f16700Schasinglulu
186*91f16700Schasinglulu
187*91f16700Schasinglulu	/* ---------------------------------------------------------------
188*91f16700Schasinglulu	 *  Helper macro for data cache operations by set/way for the
189*91f16700Schasinglulu	 *  level specified
190*91f16700Schasinglulu	 * ---------------------------------------------------------------
191*91f16700Schasinglulu	 */
192*91f16700Schasinglulu	.macro	dcsw_op_level level
193*91f16700Schasinglulu	ldcopr	r2, CLIDR
194*91f16700Schasinglulu	mov	r3, \level
195*91f16700Schasinglulu	sub	r1, r3, #2
196*91f16700Schasinglulu	b	do_dcsw_op
197*91f16700Schasinglulu	.endm
198*91f16700Schasinglulu
199*91f16700Schasinglulu	/* ---------------------------------------------------------------
200*91f16700Schasinglulu	 * Data cache operations by set/way for level 1 cache
201*91f16700Schasinglulu	 *
202*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
203*91f16700Schasinglulu	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
204*91f16700Schasinglulu	 * as defined in arch.h
205*91f16700Schasinglulu	 * ---------------------------------------------------------------
206*91f16700Schasinglulu	 */
207*91f16700Schasinglulufunc dcsw_op_level1
208*91f16700Schasinglulu	dcsw_op_level #(1 << LEVEL_SHIFT)
209*91f16700Schasingluluendfunc dcsw_op_level1
210*91f16700Schasinglulu
211*91f16700Schasinglulu	/* ---------------------------------------------------------------
212*91f16700Schasinglulu	 * Data cache operations by set/way for level 2 cache
213*91f16700Schasinglulu	 *
214*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
215*91f16700Schasinglulu	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
216*91f16700Schasinglulu	 * as defined in arch.h
217*91f16700Schasinglulu	 * ---------------------------------------------------------------
218*91f16700Schasinglulu	 */
219*91f16700Schasinglulufunc dcsw_op_level2
220*91f16700Schasinglulu	dcsw_op_level #(2 << LEVEL_SHIFT)
221*91f16700Schasingluluendfunc dcsw_op_level2
222*91f16700Schasinglulu
223*91f16700Schasinglulu	/* ---------------------------------------------------------------
224*91f16700Schasinglulu	 * Data cache operations by set/way for level 3 cache
225*91f16700Schasinglulu	 *
226*91f16700Schasinglulu	 * The main function, do_dcsw_op requires:
227*91f16700Schasinglulu	 * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW),
228*91f16700Schasinglulu	 * as defined in arch.h
229*91f16700Schasinglulu	 * ---------------------------------------------------------------
230*91f16700Schasinglulu	 */
231*91f16700Schasinglulufunc dcsw_op_level3
232*91f16700Schasinglulu	dcsw_op_level #(3 << LEVEL_SHIFT)
233*91f16700Schasingluluendfunc dcsw_op_level3
234