1239268Sgonzo/*-
2262420Sian * Copyright (c) 2010 Per Odlund <per.odlund@armagedon.se>
3239268Sgonzo * Copyright (C) 2011 MARVELL INTERNATIONAL LTD.
4239268Sgonzo * All rights reserved.
5239268Sgonzo *
6239268Sgonzo * Developed by Semihalf.
7239268Sgonzo *
8239268Sgonzo * Redistribution and use in source and binary forms, with or without
9239268Sgonzo * modification, are permitted provided that the following conditions
10239268Sgonzo * are met:
11239268Sgonzo * 1. Redistributions of source code must retain the above copyright
12239268Sgonzo *    notice, this list of conditions and the following disclaimer.
13239268Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
14239268Sgonzo *    notice, this list of conditions and the following disclaimer in the
15239268Sgonzo *    documentation and/or other materials provided with the distribution.
16239268Sgonzo * 3. Neither the name of MARVELL nor the names of contributors
17239268Sgonzo *    may be used to endorse or promote products derived from this software
18239268Sgonzo *    without specific prior written permission.
19239268Sgonzo *
20239268Sgonzo * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21239268Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22239268Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23239268Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24239268Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25239268Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26239268Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27239268Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28239268Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29239268Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30239268Sgonzo * SUCH DAMAGE.
31239268Sgonzo */
32239268Sgonzo
33239268Sgonzo#include <machine/asm.h>
34239268Sgonzo__FBSDID("$FreeBSD: stable/11/sys/arm/arm/cpufunc_asm_armv7.S 307344 2016-10-15 08:27:54Z mmel $");
35239268Sgonzo
36272209Sandrew#include <machine/sysreg.h>
37272209Sandrew
38239268Sgonzo	.cpu cortex-a8
39239268Sgonzo
40239268Sgonzo.Lcoherency_level:
41239268Sgonzo	.word	_C_LABEL(arm_cache_loc)
42239268Sgonzo.Lcache_type:
43239268Sgonzo	.word	_C_LABEL(arm_cache_type)
44278518Szbb.Larmv7_dcache_line_size:
45278518Szbb	.word	_C_LABEL(arm_dcache_min_line_size)
46278518Szbb.Larmv7_icache_line_size:
47278518Szbb	.word	_C_LABEL(arm_icache_min_line_size)
48278518Szbb.Larmv7_idcache_line_size:
49278518Szbb	.word	_C_LABEL(arm_idcache_min_line_size)
50239268Sgonzo.Lway_mask:
51239268Sgonzo	.word	0x3ff
52239268Sgonzo.Lmax_index:
53239268Sgonzo	.word	0x7fff
54239268Sgonzo.Lpage_mask:
55239268Sgonzo	.word	0xfff
56239268Sgonzo
57239268Sgonzo#define PT_NOS          (1 << 5)
58239268Sgonzo#define PT_S 	        (1 << 1)
59239268Sgonzo#define PT_INNER_NC	0
60239268Sgonzo#define PT_INNER_WT	(1 << 0)
61239268Sgonzo#define PT_INNER_WB	((1 << 0) | (1 << 6))
62239268Sgonzo#define PT_INNER_WBWA	(1 << 6)
63239268Sgonzo#define PT_OUTER_NC	0
64239268Sgonzo#define PT_OUTER_WT	(2 << 3)
65239268Sgonzo#define PT_OUTER_WB	(3 << 3)
66239268Sgonzo#define PT_OUTER_WBWA	(1 << 3)
67283366Sandrew
68239268Sgonzo#ifdef SMP
69256707Scognet#define PT_ATTR	(PT_S|PT_INNER_WBWA|PT_OUTER_WBWA|PT_NOS)
70239268Sgonzo#else
71256707Scognet#define PT_ATTR	(PT_INNER_WBWA|PT_OUTER_WBWA)
72239268Sgonzo#endif
73239268Sgonzo
74239268SgonzoENTRY(armv7_setttb)
75239268Sgonzo 	dsb
76239268Sgonzo	orr 	r0, r0, #PT_ATTR
77272209Sandrew 	mcr	CP15_TTBR0(r0)
78264128Sian	isb
79243107Scognet#ifdef SMP
80272209Sandrew 	mcr	CP15_TLBIALLIS
81243107Scognet#else
82272209Sandrew 	mcr     CP15_TLBIALL
83243107Scognet#endif
84239268Sgonzo 	dsb
85239268Sgonzo 	isb
86239268Sgonzo	RET
87248361SandrewEND(armv7_setttb)
88239268Sgonzo
89239268SgonzoENTRY(armv7_tlb_flushID)
90239268Sgonzo	dsb
91239268Sgonzo#ifdef SMP
92272209Sandrew	mcr	CP15_TLBIALLIS
93272209Sandrew	mcr	CP15_BPIALLIS
94239268Sgonzo#else
95272209Sandrew	mcr	CP15_TLBIALL
96272209Sandrew	mcr	CP15_BPIALL
97239268Sgonzo#endif
98239268Sgonzo	dsb
99239268Sgonzo	isb
100239268Sgonzo	mov	pc, lr
101248361SandrewEND(armv7_tlb_flushID)
102239268Sgonzo
103239268SgonzoENTRY(armv7_tlb_flushID_SE)
104239268Sgonzo	ldr	r1, .Lpage_mask
105239268Sgonzo	bic	r0, r0, r1
106239268Sgonzo#ifdef SMP
107272209Sandrew	mcr	CP15_TLBIMVAAIS(r0)
108272209Sandrew	mcr	CP15_BPIALLIS
109239268Sgonzo#else
110272209Sandrew	mcr	CP15_TLBIMVA(r0)
111272209Sandrew	mcr	CP15_BPIALL
112239268Sgonzo#endif
113239268Sgonzo	dsb
114239268Sgonzo	isb
115239268Sgonzo	mov	pc, lr
116248361SandrewEND(armv7_tlb_flushID_SE)
117239268Sgonzo
118239268Sgonzo/* Based on algorithm from ARM Architecture Reference Manual */
119239268SgonzoENTRY(armv7_dcache_wbinv_all)
120239268Sgonzo	stmdb	sp!, {r4, r5, r6, r7, r8, r9}
121239268Sgonzo
122239268Sgonzo	/* Get cache level */
123239268Sgonzo	ldr	r0, .Lcoherency_level
124239268Sgonzo	ldr	r3, [r0]
125239268Sgonzo	cmp	r3, #0
126239268Sgonzo	beq	Finished
127239268Sgonzo	/* For each cache level */
128239268Sgonzo	mov	r8, #0
129239268SgonzoLoop1:
130239268Sgonzo	/* Get cache type for given level */
131239268Sgonzo	mov	r2, r8, lsl #2
132239268Sgonzo	add	r2, r2, r2
133239268Sgonzo	ldr	r0, .Lcache_type
134239268Sgonzo	ldr	r1, [r0, r2]
135239268Sgonzo
136239268Sgonzo	/* Get line size */
137239268Sgonzo	and	r2, r1, #7
138239268Sgonzo	add	r2, r2, #4
139239268Sgonzo
140239268Sgonzo	/* Get number of ways */
141239268Sgonzo	ldr	r4, .Lway_mask
142239268Sgonzo	ands	r4, r4, r1, lsr #3
143239268Sgonzo	clz	r5, r4
144239268Sgonzo
145239268Sgonzo	/* Get max index */
146239268Sgonzo	ldr	r7, .Lmax_index
147239268Sgonzo	ands	r7, r7, r1, lsr #13
148239268SgonzoLoop2:
149239268Sgonzo	mov	r9, r4
150239268SgonzoLoop3:
151239268Sgonzo	mov	r6, r8, lsl #1
152239268Sgonzo	orr	r6, r6, r9, lsl r5
153239268Sgonzo	orr	r6, r6, r7, lsl r2
154239268Sgonzo
155239268Sgonzo	/* Clean and invalidate data cache by way/index */
156272209Sandrew	mcr	CP15_DCCISW(r6)
157239268Sgonzo	subs	r9, r9, #1
158239268Sgonzo	bge	Loop3
159239268Sgonzo	subs	r7, r7, #1
160239268Sgonzo	bge	Loop2
161239268SgonzoSkip:
162239268Sgonzo	add	r8, r8, #1
163239268Sgonzo	cmp	r3, r8
164239268Sgonzo	bne Loop1
165239268SgonzoFinished:
166239268Sgonzo	dsb
167239268Sgonzo	ldmia	sp!, {r4, r5, r6, r7, r8, r9}
168239268Sgonzo	RET
169248361SandrewEND(armv7_dcache_wbinv_all)
170239268Sgonzo
171239268SgonzoENTRY(armv7_idcache_wbinv_all)
172239268Sgonzo	stmdb	sp!, {lr}
173239268Sgonzo	bl armv7_dcache_wbinv_all
174243107Scognet#ifdef SMP
175272209Sandrew	mcr	CP15_ICIALLUIS
176243107Scognet#else
177272209Sandrew	mcr	CP15_ICIALLU
178243107Scognet#endif
179239268Sgonzo	dsb
180239268Sgonzo	isb
181239268Sgonzo	ldmia	sp!, {lr}
182239268Sgonzo	RET
183248361SandrewEND(armv7_idcache_wbinv_all)
184239268Sgonzo
185239268SgonzoENTRY(armv7_dcache_wb_range)
186278518Szbb	ldr	ip, .Larmv7_dcache_line_size
187278518Szbb	ldr	ip, [ip]
188239268Sgonzo	sub	r3, ip, #1
189239268Sgonzo	and	r2, r0, r3
190239268Sgonzo	add	r1, r1, r2
191239268Sgonzo	bic	r0, r0, r3
192239268Sgonzo.Larmv7_wb_next:
193272209Sandrew	mcr	CP15_DCCMVAC(r0)
194239268Sgonzo	add	r0, r0, ip
195239268Sgonzo	subs	r1, r1, ip
196239268Sgonzo	bhi	.Larmv7_wb_next
197239268Sgonzo	dsb				/* data synchronization barrier */
198239268Sgonzo	RET
199248361SandrewEND(armv7_dcache_wb_range)
200239268Sgonzo
201239268SgonzoENTRY(armv7_dcache_wbinv_range)
202278518Szbb	ldr     ip, .Larmv7_dcache_line_size
203278518Szbb	ldr     ip, [ip]
204239268Sgonzo	sub     r3, ip, #1
205239268Sgonzo	and     r2, r0, r3
206239268Sgonzo	add     r1, r1, r2
207239268Sgonzo	bic     r0, r0, r3
208239268Sgonzo.Larmv7_wbinv_next:
209272209Sandrew	mcr	CP15_DCCIMVAC(r0)
210239268Sgonzo	add	r0, r0, ip
211239268Sgonzo	subs	r1, r1, ip
212239268Sgonzo	bhi	.Larmv7_wbinv_next
213239268Sgonzo	dsb				/* data synchronization barrier */
214239268Sgonzo	RET
215248361SandrewEND(armv7_dcache_wbinv_range)
216239268Sgonzo
217239268Sgonzo/*
218239268Sgonzo * Note, we must not invalidate everything.  If the range is too big we
219239268Sgonzo * must use wb-inv of the entire cache.
220239268Sgonzo */
221239268SgonzoENTRY(armv7_dcache_inv_range)
222278518Szbb	ldr     ip, .Larmv7_dcache_line_size
223278518Szbb	ldr     ip, [ip]
224239268Sgonzo	sub     r3, ip, #1
225239268Sgonzo	and     r2, r0, r3
226239268Sgonzo	add     r1, r1, r2
227239268Sgonzo	bic     r0, r0, r3
228239268Sgonzo.Larmv7_inv_next:
229272209Sandrew	mcr	CP15_DCIMVAC(r0)
230239268Sgonzo	add	r0, r0, ip
231239268Sgonzo	subs	r1, r1, ip
232239268Sgonzo	bhi	.Larmv7_inv_next
233239268Sgonzo	dsb				/* data synchronization barrier */
234239268Sgonzo	RET
235248361SandrewEND(armv7_dcache_inv_range)
236239268Sgonzo
237239268SgonzoENTRY(armv7_idcache_wbinv_range)
238278518Szbb	ldr     ip, .Larmv7_idcache_line_size
239278518Szbb	ldr     ip, [ip]
240239268Sgonzo	sub     r3, ip, #1
241239268Sgonzo	and     r2, r0, r3
242239268Sgonzo	add     r1, r1, r2
243239268Sgonzo	bic     r0, r0, r3
244239268Sgonzo.Larmv7_id_wbinv_next:
245272209Sandrew	mcr	CP15_ICIMVAU(r0)
246272209Sandrew	mcr	CP15_DCCIMVAC(r0)
247239268Sgonzo	add	r0, r0, ip
248239268Sgonzo	subs	r1, r1, ip
249239268Sgonzo	bhi	.Larmv7_id_wbinv_next
250279810Sian	dsb				/* data synchronization barrier */
251239268Sgonzo	isb				/* instruction synchronization barrier */
252239268Sgonzo	RET
253248361SandrewEND(armv7_idcache_wbinv_range)
254239268Sgonzo
255264994Sian
256239268SgonzoENTRY_NP(armv7_icache_sync_range)
257278518Szbb	ldr	ip, .Larmv7_icache_line_size
258278518Szbb	ldr	ip, [ip]
259282418Sian	sub	r3, ip, #1		/* Address need not be aligned, but */
260282418Sian	and	r2, r0, r3		/* round length up if op spans line */
261282418Sian	add	r1, r1, r2		/* boundary: len += addr & linemask; */
262239268Sgonzo.Larmv7_sync_next:
263279810Sian	mcr	CP15_DCCMVAC(r0)
264272209Sandrew	mcr	CP15_ICIMVAU(r0)
265239268Sgonzo	add	r0, r0, ip
266239268Sgonzo	subs	r1, r1, ip
267239268Sgonzo	bhi	.Larmv7_sync_next
268279810Sian	dsb				/* data synchronization barrier */
269239268Sgonzo	isb				/* instruction synchronization barrier */
270239268Sgonzo	RET
271248361SandrewEND(armv7_icache_sync_range)
272239268Sgonzo
273239268SgonzoENTRY(armv7_cpu_sleep)
274239268Sgonzo	dsb				/* data synchronization barrier */
275239268Sgonzo	wfi  				/* wait for interrupt */
276239268Sgonzo	RET
277248361SandrewEND(armv7_cpu_sleep)
278239268Sgonzo
279239268SgonzoENTRY(armv7_context_switch)
280239268Sgonzo	dsb
281239268Sgonzo	orr     r0, r0, #PT_ATTR
282272209Sandrew
283272209Sandrew	mcr	CP15_TTBR0(r0)
284264128Sian	isb
285243107Scognet#ifdef SMP
286272209Sandrew	mcr	CP15_TLBIALLIS
287243107Scognet#else
288272209Sandrew	mcr	CP15_TLBIALL
289243107Scognet#endif
290239268Sgonzo	dsb
291239268Sgonzo	isb
292239268Sgonzo	RET
293248361SandrewEND(armv7_context_switch)
294239268Sgonzo
295239268SgonzoENTRY(armv7_drain_writebuf)
296239268Sgonzo	dsb
297239268Sgonzo	RET
298248361SandrewEND(armv7_drain_writebuf)
299239268Sgonzo
300239268SgonzoENTRY(armv7_auxctrl)
301272209Sandrew	mrc	CP15_ACTLR(r2)
302239268Sgonzo	bic r3, r2, r0	/* Clear bits */
303239268Sgonzo	eor r3, r3, r1  /* XOR bits */
304239268Sgonzo
305239268Sgonzo	teq r2, r3
306272209Sandrew	mcrne	CP15_ACTLR(r3)
307239268Sgonzo	mov r0, r2
308239268Sgonzo	RET
309248361SandrewEND(armv7_auxctrl)
310248361Sandrew
311265784Sian/*
312265784Sian * Invalidate all I+D+branch cache.  Used by startup code, which counts
313265784Sian * on the fact that only r0-r3,ip are modified and no stack space is used.
314265784Sian */
315262420SianENTRY(armv7_idcache_inv_all)
316262420Sian	mov     r0, #0
317272209Sandrew	mcr	CP15_CSSELR(r0)		@ set cache level to L1
318272209Sandrew	mrc	CP15_CCSIDR(r0)
319262420Sian
320262420Sian	ubfx    r2, r0, #13, #15        @ get num sets - 1 from CCSIDR
321262420Sian	ubfx    r3, r0, #3, #10         @ get numways - 1 from CCSIDR
322262420Sian	clz     r1, r3                  @ number of bits to MSB of way
323262420Sian	lsl     r3, r3, r1              @ shift into position
324262420Sian	mov     ip, #1                  @
325262420Sian	lsl     ip, ip, r1              @ ip now contains the way decr
326262420Sian
327262420Sian	ubfx    r0, r0, #0, #3          @ get linesize from CCSIDR
328262420Sian	add     r0, r0, #4              @ apply bias
329262420Sian	lsl     r2, r2, r0              @ shift sets by log2(linesize)
330262420Sian	add     r3, r3, r2              @ merge numsets - 1 with numways - 1
331262420Sian	sub     ip, ip, r2              @ subtract numsets - 1 from way decr
332262420Sian	mov     r1, #1
333262420Sian	lsl     r1, r1, r0              @ r1 now contains the set decr
334262420Sian	mov     r2, ip                  @ r2 now contains set way decr
335262420Sian
336262420Sian	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
337272209Sandrew1:	mcr	CP15_DCISW(r3)		@ invalidate line
338262420Sian	movs    r0, r3                  @ get current way/set
339262420Sian	beq     2f                      @ at 0 means we are done.
340262420Sian	movs    r0, r0, lsl #10         @ clear way bits leaving only set bits
341262420Sian	subne   r3, r3, r1              @ non-zero?, decrement set #
342262420Sian	subeq   r3, r3, r2              @ zero?, decrement way # and restore set count
343262420Sian	b       1b
344262420Sian
345262420Sian2:	dsb                             @ wait for stores to finish
346262420Sian	mov     r0, #0                  @ and ...
347272209Sandrew	mcr	CP15_ICIALLU		@ invalidate instruction+branch cache
348262420Sian	isb                             @ instruction sync barrier
349262420Sian	bx      lr                      @ return
350269390SianEND(armv7_idcache_inv_all)
351262420Sian
352