1/*-
2 * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com>
3 * Copyright 2014 Michal Meloun <meloun@miracle.cz>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29#include "assym.s"
30
31#include <machine/asm.h>
32#include <machine/asmacros.h>
33#include <machine/armreg.h>
34#include <machine/sysreg.h>
35
36#define GET_PCB(tmp) \
37	mrc	CP15_TPIDRPRW(tmp); \
38	add	tmp, tmp, #(TD_PCB)
39
40/*
41 * Define cache functions used by startup code, which counts on the fact that
42 * only r0-r3,r12 (ip) are modified and no stack space is used.  These functions
43 * must be called with interrupts disabled.  Moreover, these work only with
44 * caches integrated to CPU (accessible via CP15); systems with an external L2
45 * cache controller such as a PL310 need separate calls to that device driver
46 * to affect L2 caches.  This is not a factor during early kernel startup, as
47 * any external L2 cache controller has not been enabled yet.
48 */
49
50/* Invalidate D cache to PoC. (aka all cache levels)*/
51ASENTRY_NP(dcache_inv_poc_all)
52#if __ARM_ARCH == 6
53	mcr	CP15_DCIALL
54	DSB
55	bx	lr
56#else
57	mrc	CP15_CLIDR(r0)
58	ands	r0, r0, #0x07000000
59	mov	r0, r0, lsr #23		/* Get LoC 'naturally' aligned for */
60	beq	4f			/* use in the CSSELR register below */
61
621:	sub	r0, #2
63	mcr	CP15_CSSELR(r0)		/* set cache level */
64	isb
65	mrc	CP15_CCSIDR(r0)		/* read CCSIDR */
66
67	ubfx	r2, r0, #13, #15	/* get num sets - 1 from CCSIDR */
68	ubfx	r3, r0, #3, #10		/* get num ways - 1 from CCSIDR */
69	clz	r1, r3			/* number of bits to MSB of way */
70	lsl	r3, r3, r1		/* shift into position  */
71	mov	ip, #1
72	lsl	ip, ip, r1		/* ip now contains the way decr  */
73
74	ubfx	r0, r0, #0, #3		/* get linesize from CCSIDR  */
75	add	r0, r0, #4		/* apply bias  */
76	lsl	r2, r2, r0		/* shift sets by log2(linesize)  */
77	add	r3, r3, r2		/* merge numsets - 1 with numways - 1 */
78	sub	ip, ip, r2		/* subtract numsets - 1 from way decr */
79	mov	r1, #1
80	lsl	r1, r1, r0		/* r1 now contains the set decr */
81	mov	r2, ip			/* r2 now contains set way decr */
82
83	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
842:	mcr	CP15_DCISW(r3)		/* invalidate line */
85	movs	r0, r3			/* get current way/set */
86	beq	3f			/* at 0 means we are done */
87	movs	r0, r0, lsl #10		/* clear way bits leaving only set bits*/
88	subne	r3, r3, r1		/* non-zero?, decrement set */
89	subeq	r3, r3, r2		/* zero?, decrement way  and restore set count */
90	b	2b
91
923:
93	mrc	CP15_CSSELR(r0)		/* get cache level */
94	teq	r0, #0
95	bne	1b
96
974:	dsb				/* wait for stores to finish */
98	mov	r0, #0
99	mcr	CP15_CSSELR(r0)
100	isb
101	bx	lr
102#endif /* __ARM_ARCH == 6 */
103END(dcache_inv_poc_all)
104
105/* Invalidate D cache to PoU. (aka L1 cache only)*/
106ASENTRY_NP(dcache_inv_pou_all)
107#if __ARM_ARCH == 6
108	mcr	CP15_DCIALL
109	DSB
110	bx	lr
111#else
112	mrc	CP15_CLIDR(r0)
113	ands	r0, r0, #0x38000000
114	mov	r0, r0, lsr #26		/* Get LoUU (naturally aligned) */
115	beq	4f
116
1171:	sub	r0, #2
118	mcr	CP15_CSSELR(r0)		/* set cache level */
119	isb
120	mrc	CP15_CCSIDR(r0)		/* read CCSIDR */
121
122	ubfx	r2, r0, #13, #15	/* get num sets - 1 from CCSIDR */
123	ubfx	r3, r0, #3, #10		/* get num ways - 1 from CCSIDR */
124	clz	r1, r3			/* number of bits to MSB of way */
125	lsl	r3, r3, r1		/* shift into position  */
126	mov	ip, #1
127	lsl	ip, ip, r1		/* ip now contains the way decr  */
128
129	ubfx	r0, r0, #0, #3		/* get linesize from CCSIDR  */
130	add	r0, r0, #4		/* apply bias  */
131	lsl	r2, r2, r0		/* shift sets by log2(linesize)  */
132	add	r3, r3, r2		/* merge numsets - 1 with numways - 1 */
133	sub	ip, ip, r2		/* subtract numsets - 1 from way decr */
134	mov	r1, #1
135	lsl	r1, r1, r0		/* r1 now contains the set decr */
136	mov	r2, ip			/* r2 now contains set way decr */
137
138	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
1392:	mcr	CP15_DCISW(r3)		/* invalidate line */
140	movs	r0, r3			/* get current way/set */
141	beq	3f			/* at 0 means we are done */
142	movs	r0, r0, lsl #10		/* clear way bits leaving only set bits*/
143	subne	r3, r3, r1		/* non-zero?, decrement set */
144	subeq	r3, r3, r2		/* zero?, decrement way  and restore set count */
145	b	2b
146
1473:
148	mrc	CP15_CSSELR(r0)		/* get cache level */
149	teq	r0, #0
150	bne	1b
151
1524:	dsb				/* wait for stores to finish */
153	mov	r0, #0
154	mcr	CP15_CSSELR(r0)
155	bx	lr
156#endif
157END(dcache_inv_pou_all)
158
159/* Write back and Invalidate D cache to PoC. */
160ASENTRY_NP(dcache_wbinv_poc_all)
161#if __ARM_ARCH == 6
162	mcr	CP15_DCCIALL
163	DSB
164	bx	lr
165#else
166	mrc	CP15_CLIDR(r0)
167	ands	r0, r0, #0x07000000
168	beq	4f
169	mov	r0, #0			/* Clean from inner to outer levels */
170
1711:	mcr	CP15_CSSELR(r0)		/* set cache level */
172	isb
173	mrc	CP15_CCSIDR(r0)		/* read CCSIDR */
174
175	ubfx	r2, r0, #13, #15	/* get num sets - 1 from CCSIDR */
176	ubfx	r3, r0, #3, #10		/* get num ways - 1 from CCSIDR */
177	clz	r1, r3			/* number of bits to MSB of way */
178	lsl	r3, r3, r1		/* shift into position  */
179	mov	ip, #1
180	lsl	ip, ip, r1		/* ip now contains the way decr  */
181
182	ubfx	r0, r0, #0, #3		/* get linesize from CCSIDR  */
183	add	r0, r0, #4		/* apply bias  */
184	lsl	r2, r2, r0		/* shift sets by log2(linesize)  */
185	add	r3, r3, r2		/* merge numsets - 1 with numways - 1 */
186	sub	ip, ip, r2		/* subtract numsets - 1 from way decr */
187	mov	r1, #1
188	lsl	r1, r1, r0		/* r1 now contains the set decr */
189	mov	r2, ip			/* r2 now contains set way decr */
190
191	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
1922:	mcr	CP15_DCCISW(r3)		/* clean and invalidate line */
193	movs	r0, r3			/* get current way/set */
194	beq	3f			/* at 0 means we are done */
195	movs	r0, r0, lsl #10		/* clear way bits leaving only set bits*/
196	subne	r3, r3, r1		/* non-zero?, decrement set */
197	subeq	r3, r3, r2		/* zero?, decrement way  and restore set count */
198	b	2b
199
2003:
201	mrc	CP15_CSSELR(r0)		/* get cache level */
202	add	r0, r0, #2		/* next level */
203	mrc	CP15_CLIDR(r1)
204	ands	r1, r1, #0x07000000
205	mov	r1, r1, lsr #23		/* Get LoC (naturally aligned) */
206	cmp 	r1, r0
207	bne	1b
208
2094:	dsb				/* wait for stores to finish */
210	mov	r0, #0
211	mcr	CP15_CSSELR(r0)
212	bx	lr
213#endif /* __ARM_ARCH == 6 */
214END(dcache_wbinv_poc_all)
215
216ASENTRY_NP(dcache_wb_pou_checked)
217	ldr	ip, .Lcpuinfo
218	ldr	ip, [ip, #DCACHE_LINE_SIZE]
219
220	GET_PCB(r2)
221	ldr	r2, [r2]
222
223	adr	r3, _C_LABEL(cachebailout)
224	str	r3, [r2, #PCB_ONFAULT]
2251:
226	mcr	CP15_DCCMVAC(r0)
227	add	r0, r0, ip
228	subs	r1, r1, ip
229	bhi	1b
230	DSB
231	mov	r0, #0
232	str	r0, [r2, #PCB_ONFAULT]
233	mov	r0, #1			/* cannot be faulting address */
234	RET
235
236.Lcpuinfo:
237	.word	cpuinfo
238END(dcache_wb_pou_checked)
239
240ASENTRY_NP(icache_inv_pou_checked)
241	ldr	ip, .Lcpuinfo
242	ldr	ip, [ip, #ICACHE_LINE_SIZE]
243
244	GET_PCB(r2)
245	ldr	r2, [r2]
246
247	adr	r3, _C_LABEL(cachebailout)
248	str	r3, [r2, #PCB_ONFAULT]
249
2501:
251	mcr	CP15_ICIMVAU(r0)
252	add	r0, r0, ip
253	subs	r1, r1, ip
254	bhi	1b
255	DSB
256	ISB
257	mov	r0, #0
258	str	r0, [r2, #PCB_ONFAULT]
259	mov	r0, #1			/* cannot be faulting address */
260	RET
261END(icache_inv_pou_checked)
262
263/* label must be global as trap-v6.c references it */
264	.global	_C_LABEL(cachebailout)
265_C_LABEL(cachebailout):
266	DSB
267	ISB
268	mov	r1, #0
269	str	r1, [r2, #PCB_ONFAULT]
270	RET
271