1276336Sian/*-
2276336Sian * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com>
3276336Sian * Copyright 2014 Michal Meloun <meloun@miracle.cz>
4276336Sian * All rights reserved.
5276336Sian *
6276336Sian * Redistribution and use in source and binary forms, with or without
7276336Sian * modification, are permitted provided that the following conditions
8276336Sian * are met:
9276336Sian * 1. Redistributions of source code must retain the above copyright
10276336Sian *    notice, this list of conditions and the following disclaimer.
11276336Sian * 2. Redistributions in binary form must reproduce the above copyright
12276336Sian *    notice, this list of conditions and the following disclaimer in the
13276336Sian *    documentation and/or other materials provided with the distribution.
14276336Sian *
15276336Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16276336Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17276336Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18276336Sian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19276336Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20276336Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21276336Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22276336Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23276336Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24276336Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25276336Sian * SUCH DAMAGE.
26276336Sian *
27276336Sian * $FreeBSD$
28276336Sian */
29283947Sian#include "assym.s"
30276336Sian
31276336Sian#include <machine/asm.h>
32276336Sian#include <machine/asmacros.h>
33276336Sian#include <machine/armreg.h>
34276336Sian#include <machine/sysreg.h>
35276336Sian
36283947Sian#define GET_PCB(tmp) \
37295920Sskra	mrc	CP15_TPIDRPRW(tmp); \
38295920Sskra	add	tmp, tmp, #(TD_PCB)
39283947Sian
40283366Sandrew/*
41276336Sian * Define cache functions used by startup code, which counts on the fact that
42276350Sian * only r0-r3,r12 (ip) are modified and no stack space is used.  These functions
43283366Sandrew * must be called with interrupts disabled.  Moreover, these work only with
44276350Sian * caches integrated to CPU (accessible via CP15); systems with an external L2
45276350Sian * cache controller such as a PL310 need separate calls to that device driver
46276350Sian * to affect L2 caches.  This is not a factor during early kernel startup, as
47276350Sian * any external L2 cache controller has not been enabled yet.
48276336Sian */
49276336Sian
50276336Sian/* Invalidate D cache to PoC. (aka all cache levels)*/
51276350SianASENTRY_NP(dcache_inv_poc_all)
52276394Sian#if __ARM_ARCH == 6
53276394Sian	mcr	CP15_DCIALL
54276394Sian	DSB
55276394Sian	bx	lr
56276394Sian#else
57276336Sian	mrc	CP15_CLIDR(r0)
58276336Sian	ands	r0, r0, #0x07000000
59276394Sian	mov	r0, r0, lsr #23		/* Get LoC 'naturally' aligned for */
60276394Sian	beq	4f			/* use in the CSSELR register below */
61276336Sian
62276394Sian1:	sub	r0, #2
63276394Sian	mcr	CP15_CSSELR(r0)		/* set cache level */
64276336Sian	isb
65276336Sian	mrc	CP15_CCSIDR(r0)		/* read CCSIDR */
66276336Sian
67276336Sian	ubfx	r2, r0, #13, #15	/* get num sets - 1 from CCSIDR */
68276336Sian	ubfx	r3, r0, #3, #10		/* get num ways - 1 from CCSIDR */
69276336Sian	clz	r1, r3			/* number of bits to MSB of way */
70276336Sian	lsl	r3, r3, r1		/* shift into position  */
71276336Sian	mov	ip, #1
72276336Sian	lsl	ip, ip, r1		/* ip now contains the way decr  */
73276336Sian
74276336Sian	ubfx	r0, r0, #0, #3		/* get linesize from CCSIDR  */
75276336Sian	add	r0, r0, #4		/* apply bias  */
76276336Sian	lsl	r2, r2, r0		/* shift sets by log2(linesize)  */
77276336Sian	add	r3, r3, r2		/* merge numsets - 1 with numways - 1 */
78276336Sian	sub	ip, ip, r2		/* subtract numsets - 1 from way decr */
79276336Sian	mov	r1, #1
80276336Sian	lsl	r1, r1, r0		/* r1 now contains the set decr */
81276336Sian	mov	r2, ip			/* r2 now contains set way decr */
82276336Sian
83276336Sian	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
84276336Sian2:	mcr	CP15_DCISW(r3)		/* invalidate line */
85276336Sian	movs	r0, r3			/* get current way/set */
86276336Sian	beq	3f			/* at 0 means we are done */
87276336Sian	movs	r0, r0, lsl #10		/* clear way bits leaving only set bits*/
88276336Sian	subne	r3, r3, r1		/* non-zero?, decrement set */
89276336Sian	subeq	r3, r3, r2		/* zero?, decrement way  and restore set count */
90276336Sian	b	2b
91276336Sian
92276336Sian3:
93276336Sian	mrc	CP15_CSSELR(r0)		/* get cache level */
94276394Sian	teq	r0, #0
95276394Sian	bne	1b
96276336Sian
97276336Sian4:	dsb				/* wait for stores to finish */
98276336Sian	mov	r0, #0
99276336Sian	mcr	CP15_CSSELR(r0)
100276336Sian	isb
101276336Sian	bx	lr
102276394Sian#endif /* __ARM_ARCH == 6 */
103276336SianEND(dcache_inv_poc_all)
104276336Sian
105276336Sian/* Invalidate D cache to PoU. (aka L1 cache only)*/
106276350SianASENTRY_NP(dcache_inv_pou_all)
107276394Sian#if __ARM_ARCH == 6
108276394Sian	mcr	CP15_DCIALL
109276394Sian	DSB
110276394Sian	bx	lr
111276394Sian#else
112276336Sian	mrc	CP15_CLIDR(r0)
113276444Sian	ands	r0, r0, #0x38000000
114276336Sian	mov	r0, r0, lsr #26		/* Get LoUU (naturally aligned) */
115276336Sian	beq	4f
116276336Sian
117276394Sian1:	sub	r0, #2
118276394Sian	mcr	CP15_CSSELR(r0)		/* set cache level */
119276336Sian	isb
120276336Sian	mrc	CP15_CCSIDR(r0)		/* read CCSIDR */
121276336Sian
122276336Sian	ubfx	r2, r0, #13, #15	/* get num sets - 1 from CCSIDR */
123276336Sian	ubfx	r3, r0, #3, #10		/* get num ways - 1 from CCSIDR */
124276336Sian	clz	r1, r3			/* number of bits to MSB of way */
125276336Sian	lsl	r3, r3, r1		/* shift into position  */
126276336Sian	mov	ip, #1
127276336Sian	lsl	ip, ip, r1		/* ip now contains the way decr  */
128276336Sian
129276336Sian	ubfx	r0, r0, #0, #3		/* get linesize from CCSIDR  */
130276336Sian	add	r0, r0, #4		/* apply bias  */
131276336Sian	lsl	r2, r2, r0		/* shift sets by log2(linesize)  */
132276336Sian	add	r3, r3, r2		/* merge numsets - 1 with numways - 1 */
133276336Sian	sub	ip, ip, r2		/* subtract numsets - 1 from way decr */
134276336Sian	mov	r1, #1
135276336Sian	lsl	r1, r1, r0		/* r1 now contains the set decr */
136276336Sian	mov	r2, ip			/* r2 now contains set way decr */
137276336Sian
138276336Sian	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
139276394Sian2:	mcr	CP15_DCISW(r3)		/* invalidate line */
140276336Sian	movs	r0, r3			/* get current way/set */
141276336Sian	beq	3f			/* at 0 means we are done */
142276336Sian	movs	r0, r0, lsl #10		/* clear way bits leaving only set bits*/
143276336Sian	subne	r3, r3, r1		/* non-zero?, decrement set */
144276336Sian	subeq	r3, r3, r2		/* zero?, decrement way  and restore set count */
145276336Sian	b	2b
146276336Sian
147276336Sian3:
148276336Sian	mrc	CP15_CSSELR(r0)		/* get cache level */
149276394Sian	teq	r0, #0
150276394Sian	bne	1b
151276336Sian
152276336Sian4:	dsb				/* wait for stores to finish */
153276336Sian	mov	r0, #0
154276336Sian	mcr	CP15_CSSELR(r0)
155276336Sian	bx	lr
156276394Sian#endif
157276336SianEND(dcache_inv_pou_all)
158276336Sian
159276336Sian/* Write back and Invalidate D cache to PoC. */
160276350SianASENTRY_NP(dcache_wbinv_poc_all)
161276394Sian#if __ARM_ARCH == 6
162276394Sian	mcr	CP15_DCCIALL
163276394Sian	DSB
164276394Sian	bx	lr
165276394Sian#else
166276336Sian	mrc	CP15_CLIDR(r0)
167276336Sian	ands	r0, r0, #0x07000000
168276336Sian	beq	4f
169276394Sian	mov	r0, #0			/* Clean from inner to outer levels */
170276336Sian
171276336Sian1:	mcr	CP15_CSSELR(r0)		/* set cache level */
172276336Sian	isb
173276336Sian	mrc	CP15_CCSIDR(r0)		/* read CCSIDR */
174276336Sian
175276336Sian	ubfx	r2, r0, #13, #15	/* get num sets - 1 from CCSIDR */
176276336Sian	ubfx	r3, r0, #3, #10		/* get num ways - 1 from CCSIDR */
177276336Sian	clz	r1, r3			/* number of bits to MSB of way */
178276336Sian	lsl	r3, r3, r1		/* shift into position  */
179276336Sian	mov	ip, #1
180276336Sian	lsl	ip, ip, r1		/* ip now contains the way decr  */
181276336Sian
182276336Sian	ubfx	r0, r0, #0, #3		/* get linesize from CCSIDR  */
183276336Sian	add	r0, r0, #4		/* apply bias  */
184276336Sian	lsl	r2, r2, r0		/* shift sets by log2(linesize)  */
185276336Sian	add	r3, r3, r2		/* merge numsets - 1 with numways - 1 */
186276336Sian	sub	ip, ip, r2		/* subtract numsets - 1 from way decr */
187276336Sian	mov	r1, #1
188276336Sian	lsl	r1, r1, r0		/* r1 now contains the set decr */
189276336Sian	mov	r2, ip			/* r2 now contains set way decr */
190276336Sian
191276336Sian	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
192276394Sian2:	mcr	CP15_DCCISW(r3)		/* clean and invalidate line */
193276336Sian	movs	r0, r3			/* get current way/set */
194276336Sian	beq	3f			/* at 0 means we are done */
195276336Sian	movs	r0, r0, lsl #10		/* clear way bits leaving only set bits*/
196276336Sian	subne	r3, r3, r1		/* non-zero?, decrement set */
197276336Sian	subeq	r3, r3, r2		/* zero?, decrement way  and restore set count */
198276336Sian	b	2b
199276336Sian
200276336Sian3:
201276336Sian	mrc	CP15_CSSELR(r0)		/* get cache level */
202276336Sian	add	r0, r0, #2		/* next level */
203276336Sian	mrc	CP15_CLIDR(r1)
204276336Sian	ands	r1, r1, #0x07000000
205276336Sian	mov	r1, r1, lsr #23		/* Get LoC (naturally aligned) */
206276336Sian	cmp 	r1, r0
207276394Sian	bne	1b
208276336Sian
209276336Sian4:	dsb				/* wait for stores to finish */
210276336Sian	mov	r0, #0
211276336Sian	mcr	CP15_CSSELR(r0)
212276336Sian	bx	lr
213276394Sian#endif /* __ARM_ARCH == 6 */
214276336SianEND(dcache_wbinv_poc_all)
215283947Sian
216283947SianASENTRY_NP(dcache_wb_pou_checked)
217283947Sian	ldr	ip, .Lcpuinfo
218283947Sian	ldr	ip, [ip, #DCACHE_LINE_SIZE]
219283947Sian
220283947Sian	GET_PCB(r2)
221283947Sian	ldr	r2, [r2]
222283947Sian
223283947Sian	adr	r3, _C_LABEL(cachebailout)
224283947Sian	str	r3, [r2, #PCB_ONFAULT]
225283947Sian1:
226283947Sian	mcr	CP15_DCCMVAC(r0)
227283947Sian	add	r0, r0, ip
228283947Sian	subs	r1, r1, ip
229283947Sian	bhi	1b
230283947Sian	DSB
231283947Sian	mov	r0, #0
232283947Sian	str	r0, [r2, #PCB_ONFAULT]
233283947Sian	mov	r0, #1			/* cannot be faulting address */
234283947Sian	RET
235283947Sian
236283947Sian.Lcpuinfo:
237283947Sian	.word	cpuinfo
238283947SianEND(dcache_wb_pou_checked)
239283947Sian
240283947SianASENTRY_NP(icache_inv_pou_checked)
241283947Sian	ldr	ip, .Lcpuinfo
242283947Sian	ldr	ip, [ip, #ICACHE_LINE_SIZE]
243283947Sian
244283947Sian	GET_PCB(r2)
245283947Sian	ldr	r2, [r2]
246283947Sian
247283947Sian	adr	r3, _C_LABEL(cachebailout)
248283947Sian	str	r3, [r2, #PCB_ONFAULT]
249283947Sian
250283947Sian1:
251283947Sian	mcr	CP15_ICIMVAU(r0)
252283947Sian	add	r0, r0, ip
253283947Sian	subs	r1, r1, ip
254283947Sian	bhi	1b
255283947Sian	DSB
256283947Sian	ISB
257283947Sian	mov	r0, #0
258283947Sian	str	r0, [r2, #PCB_ONFAULT]
259283947Sian	mov	r0, #1			/* cannot be faulting address */
260283947Sian	RET
261283947SianEND(icache_inv_pou_checked)
262283947Sian
263283947Sian/* label must be global as trap-v6.c references it */
264283947Sian	.global	_C_LABEL(cachebailout)
265283947Sian_C_LABEL(cachebailout):
266283947Sian	DSB
267283947Sian	ISB
268283947Sian	mov	r1, #0
269283947Sian	str	r1, [r2, #PCB_ONFAULT]
270283947Sian	RET
271