1/* MN10300 CPU core caching routines, using indirect regs on cache controller
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/sys.h>
13#include <linux/linkage.h>
14#include <asm/smp.h>
15#include <asm/page.h>
16#include <asm/cache.h>
17#include <asm/irqflags.h>
18
19	.am33_2
20
21#ifndef CONFIG_SMP
22	.globl mn10300_dcache_flush
23	.globl mn10300_dcache_flush_page
24	.globl mn10300_dcache_flush_range
25	.globl mn10300_dcache_flush_range2
26	.globl mn10300_dcache_flush_inv
27	.globl mn10300_dcache_flush_inv_page
28	.globl mn10300_dcache_flush_inv_range
29	.globl mn10300_dcache_flush_inv_range2
30
31mn10300_dcache_flush		= mn10300_local_dcache_flush
32mn10300_dcache_flush_page	= mn10300_local_dcache_flush_page
33mn10300_dcache_flush_range	= mn10300_local_dcache_flush_range
34mn10300_dcache_flush_range2	= mn10300_local_dcache_flush_range2
35mn10300_dcache_flush_inv	= mn10300_local_dcache_flush_inv
36mn10300_dcache_flush_inv_page	= mn10300_local_dcache_flush_inv_page
37mn10300_dcache_flush_inv_range	= mn10300_local_dcache_flush_inv_range
38mn10300_dcache_flush_inv_range2	= mn10300_local_dcache_flush_inv_range2
39
40#endif /* !CONFIG_SMP */
41
42###############################################################################
43#
44# void mn10300_local_dcache_flush(void)
45# Flush the entire data cache back to RAM
46#
47###############################################################################
48	ALIGN
49	.globl	mn10300_local_dcache_flush
50        .type	mn10300_local_dcache_flush,@function
51mn10300_local_dcache_flush:
52	movhu	(CHCTR),d0
53	btst	CHCTR_DCEN,d0
54	beq	mn10300_local_dcache_flush_end
55
56	mov	DCPGCR,a0
57
58	LOCAL_CLI_SAVE(d1)
59
60	# wait for busy bit of area purge
61	setlb
62	mov	(a0),d0
63	btst	DCPGCR_DCPGBSY,d0
64	lne
65
66	# set mask
67	clr	d0
68	mov	d0,(DCPGMR)
69
70	# area purge
71	#
72	# DCPGCR = DCPGCR_DCP
73	#
74	mov	DCPGCR_DCP,d0
75	mov	d0,(a0)
76
77	# wait for busy bit of area purge
78	setlb
79	mov	(a0),d0
80	btst	DCPGCR_DCPGBSY,d0
81	lne
82
83	LOCAL_IRQ_RESTORE(d1)
84
85mn10300_local_dcache_flush_end:
86	ret	[],0
87	.size	mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
88
89###############################################################################
90#
91# void mn10300_local_dcache_flush_page(unsigned long start)
92# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
93# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
94# Flush a range of addresses on a page in the dcache
95#
96###############################################################################
97	ALIGN
98	.globl	mn10300_local_dcache_flush_page
99	.globl	mn10300_local_dcache_flush_range
100	.globl	mn10300_local_dcache_flush_range2
101	.type	mn10300_local_dcache_flush_page,@function
102	.type	mn10300_local_dcache_flush_range,@function
103	.type	mn10300_local_dcache_flush_range2,@function
104mn10300_local_dcache_flush_page:
105	and	~(PAGE_SIZE-1),d0
106	mov	PAGE_SIZE,d1
107mn10300_local_dcache_flush_range2:
108	add	d0,d1
109mn10300_local_dcache_flush_range:
110	movm	[d2,d3,a2],(sp)
111
112	movhu	(CHCTR),d2
113	btst	CHCTR_DCEN,d2
114	beq	mn10300_local_dcache_flush_range_end
115
116	# calculate alignsize
117	#
118	# alignsize = L1_CACHE_BYTES;
119	# for (i = (end - start - 1) / L1_CACHE_BYTES ;  i > 0; i >>= 1)
120	#     alignsize <<= 1;
121	# d2 = alignsize;
122	#
123	mov	L1_CACHE_BYTES,d2
124	sub	d0,d1,d3
125	add	-1,d3
126	lsr	L1_CACHE_SHIFT,d3
127	beq	2f
1281:
129	add     d2,d2
130	lsr     1,d3
131	bne     1b
1322:
133	mov	d1,a1		# a1 = end
134
135	LOCAL_CLI_SAVE(d3)
136	mov	DCPGCR,a0
137
138	# wait for busy bit of area purge
139	setlb
140	mov	(a0),d1
141	btst	DCPGCR_DCPGBSY,d1
142	lne
143
144	# determine the mask
145	mov	d2,d1
146	add	-1,d1
147	not	d1		# d1 = mask = ~(alignsize-1)
148	mov	d1,(DCPGMR)
149
150	and	d1,d0,a2	# a2 = mask & start
151
152dcpgloop:
153	# area purge
154	mov	a2,d0
155	or	DCPGCR_DCP,d0
156	mov	d0,(a0)		# DCPGCR = (mask & start) | DCPGCR_DCP
157
158	# wait for busy bit of area purge
159	setlb
160	mov	(a0),d1
161	btst	DCPGCR_DCPGBSY,d1
162	lne
163
164	# check purge of end address
165	add	d2,a2		# a2 += alignsize
166	cmp	a1,a2		# if (a2 < end) goto dcpgloop
167	bns	dcpgloop
168
169	LOCAL_IRQ_RESTORE(d3)
170
171mn10300_local_dcache_flush_range_end:
172	ret	[d2,d3,a2],12
173
174	.size	mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
175	.size	mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
176	.size	mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
177
178###############################################################################
179#
180# void mn10300_local_dcache_flush_inv(void)
181# Flush the entire data cache and invalidate all entries
182#
183###############################################################################
184	ALIGN
185	.globl	mn10300_local_dcache_flush_inv
186	.type	mn10300_local_dcache_flush_inv,@function
187mn10300_local_dcache_flush_inv:
188	movhu	(CHCTR),d0
189	btst	CHCTR_DCEN,d0
190	beq	mn10300_local_dcache_flush_inv_end
191
192	mov	DCPGCR,a0
193
194	LOCAL_CLI_SAVE(d1)
195
196	# wait for busy bit of area purge & invalidate
197	setlb
198	mov	(a0),d0
199	btst	DCPGCR_DCPGBSY,d0
200	lne
201
202	# set the mask to cover everything
203	clr	d0
204	mov	d0,(DCPGMR)
205
206	# area purge & invalidate
207	mov	DCPGCR_DCP|DCPGCR_DCI,d0
208	mov	d0,(a0)
209
210	# wait for busy bit of area purge & invalidate
211	setlb
212	mov	(a0),d0
213	btst	DCPGCR_DCPGBSY,d0
214	lne
215
216	LOCAL_IRQ_RESTORE(d1)
217
218mn10300_local_dcache_flush_inv_end:
219	ret	[],0
220	.size	mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
221
222###############################################################################
223#
224# void mn10300_local_dcache_flush_inv_page(unsigned long start)
225# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
226# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
227# Flush and invalidate a range of addresses on a page in the dcache
228#
229###############################################################################
230	ALIGN
231	.globl	mn10300_local_dcache_flush_inv_page
232	.globl	mn10300_local_dcache_flush_inv_range
233	.globl	mn10300_local_dcache_flush_inv_range2
234	.type	mn10300_local_dcache_flush_inv_page,@function
235	.type	mn10300_local_dcache_flush_inv_range,@function
236	.type	mn10300_local_dcache_flush_inv_range2,@function
237mn10300_local_dcache_flush_inv_page:
238	and	~(PAGE_SIZE-1),d0
239	mov	PAGE_SIZE,d1
240mn10300_local_dcache_flush_inv_range2:
241	add	d0,d1
242mn10300_local_dcache_flush_inv_range:
243	movm	[d2,d3,a2],(sp)
244
245	movhu	(CHCTR),d2
246	btst	CHCTR_DCEN,d2
247	beq	mn10300_local_dcache_flush_inv_range_end
248
249	# calculate alignsize
250	#
251	# alignsize = L1_CACHE_BYTES;
252	# for (i = (end - start - 1) / L1_CACHE_BYTES; i > 0; i >>= 1)
253	#     alignsize <<= 1;
254	# d2 = alignsize
255	#
256	mov	L1_CACHE_BYTES,d2
257	sub	d0,d1,d3
258	add	-1,d3
259	lsr	L1_CACHE_SHIFT,d3
260	beq	2f
2611:
262	add     d2,d2
263	lsr     1,d3
264	bne     1b
2652:
266	mov	d1,a1		# a1 = end
267
268	LOCAL_CLI_SAVE(d3)
269	mov	DCPGCR,a0
270
271	# wait for busy bit of area purge & invalidate
272	setlb
273	mov	(a0),d1
274	btst	DCPGCR_DCPGBSY,d1
275	lne
276
277	# set the mask
278	mov	d2,d1
279	add	-1,d1
280	not	d1		# d1 = mask = ~(alignsize-1)
281	mov	d1,(DCPGMR)
282
283	and	d1,d0,a2	# a2 = mask & start
284
285dcpgivloop:
286	# area purge & invalidate
287	mov	a2,d0
288	or	DCPGCR_DCP|DCPGCR_DCI,d0
289	mov	d0,(a0)		# DCPGCR = (mask & start)|DCPGCR_DCP|DCPGCR_DCI
290
291	# wait for busy bit of area purge & invalidate
292	setlb
293	mov	(a0),d1
294	btst	DCPGCR_DCPGBSY,d1
295	lne
296
297	# check purge & invalidate of end address
298	add	d2,a2		# a2 += alignsize
299	cmp	a1,a2		# if (a2 < end) goto dcpgivloop
300	bns	dcpgivloop
301
302	LOCAL_IRQ_RESTORE(d3)
303
304mn10300_local_dcache_flush_inv_range_end:
305	ret	[d2,d3,a2],12
306	.size	mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
307	.size	mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
308	.size	mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
309