1/* MN10300 CPU core caching routines, using direct tag flushing
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	# read the addresses tagged in the cache's tag RAM and attempt to flush
57	# those addresses specifically
58	# - we rely on the hardware to filter out invalid tag entry addresses
59	mov	DCACHE_TAG(0,0),a0		# dcache tag RAM access address
60	mov	DCACHE_PURGE(0,0),a1		# dcache purge request address
61	mov	L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1  # total number of entries
62
63mn10300_local_dcache_flush_loop:
64	mov	(a0),d0
65	and	L1_CACHE_TAG_MASK,d0
66	or	L1_CACHE_TAG_VALID,d0		# retain valid entries in the
67						# cache
68	mov	d0,(a1)				# conditional purge
69
70	add	L1_CACHE_BYTES,a0
71	add	L1_CACHE_BYTES,a1
72	add	-1,d1
73	bne	mn10300_local_dcache_flush_loop
74
75mn10300_local_dcache_flush_end:
76	ret	[],0
77	.size	mn10300_local_dcache_flush,.-mn10300_local_dcache_flush
78
79###############################################################################
80#
81# void mn10300_local_dcache_flush_page(unsigned long start)
82# void mn10300_local_dcache_flush_range(unsigned long start, unsigned long end)
83# void mn10300_local_dcache_flush_range2(unsigned long start, unsigned long size)
84# Flush a range of addresses on a page in the dcache
85#
86###############################################################################
87	ALIGN
88	.globl	mn10300_local_dcache_flush_page
89	.globl	mn10300_local_dcache_flush_range
90	.globl	mn10300_local_dcache_flush_range2
91	.type	mn10300_local_dcache_flush_page,@function
92	.type	mn10300_local_dcache_flush_range,@function
93	.type	mn10300_local_dcache_flush_range2,@function
94mn10300_local_dcache_flush_page:
95	and	~(PAGE_SIZE-1),d0
96	mov	PAGE_SIZE,d1
97mn10300_local_dcache_flush_range2:
98	add	d0,d1
99mn10300_local_dcache_flush_range:
100	movm	[d2],(sp)
101
102	movhu	(CHCTR),d2
103	btst	CHCTR_DCEN,d2
104	beq	mn10300_local_dcache_flush_range_end
105
106	sub	d0,d1,a0
107	cmp	MN10300_DCACHE_FLUSH_BORDER,a0
108	ble	1f
109
110	movm	(sp),[d2]
111	bra	mn10300_local_dcache_flush
1121:
113
114	# round start addr down
115	and	L1_CACHE_TAG_MASK,d0
116	mov	d0,a1
117
118	add	L1_CACHE_BYTES,d1			# round end addr up
119	and	L1_CACHE_TAG_MASK,d1
120
121	# write a request to flush all instances of an address from the cache
122	mov	DCACHE_PURGE(0,0),a0
123	mov	a1,d0
124	and	L1_CACHE_TAG_ENTRY,d0
125	add	d0,a0				# starting dcache purge control
126						# reg address
127
128	sub	a1,d1
129	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
130						# examine
131
132	or	L1_CACHE_TAG_VALID,a1		# retain valid entries in the
133						# cache
134
135mn10300_local_dcache_flush_range_loop:
136	mov	a1,(L1_CACHE_WAYDISP*0,a0)	# conditionally purge this line
137						# all ways
138
139	add	L1_CACHE_BYTES,a0
140	add	L1_CACHE_BYTES,a1
141	and	~L1_CACHE_WAYDISP,a0		# make sure way stay on way 0
142	add	-1,d1
143	bne	mn10300_local_dcache_flush_range_loop
144
145mn10300_local_dcache_flush_range_end:
146	ret	[d2],4
147
148	.size	mn10300_local_dcache_flush_page,.-mn10300_local_dcache_flush_page
149	.size	mn10300_local_dcache_flush_range,.-mn10300_local_dcache_flush_range
150	.size	mn10300_local_dcache_flush_range2,.-mn10300_local_dcache_flush_range2
151
152###############################################################################
153#
154# void mn10300_local_dcache_flush_inv(void)
155# Flush the entire data cache and invalidate all entries
156#
157###############################################################################
158	ALIGN
159	.globl	mn10300_local_dcache_flush_inv
160	.type	mn10300_local_dcache_flush_inv,@function
161mn10300_local_dcache_flush_inv:
162	movhu	(CHCTR),d0
163	btst	CHCTR_DCEN,d0
164	beq	mn10300_local_dcache_flush_inv_end
165
166	mov	L1_CACHE_NENTRIES,d1
167	clr	a1
168
169mn10300_local_dcache_flush_inv_loop:
170	mov	(DCACHE_PURGE_WAY0(0),a1),d0	# unconditional purge
171	mov	(DCACHE_PURGE_WAY1(0),a1),d0	# unconditional purge
172	mov	(DCACHE_PURGE_WAY2(0),a1),d0	# unconditional purge
173	mov	(DCACHE_PURGE_WAY3(0),a1),d0	# unconditional purge
174
175	add	L1_CACHE_BYTES,a1
176	add	-1,d1
177	bne	mn10300_local_dcache_flush_inv_loop
178
179mn10300_local_dcache_flush_inv_end:
180	ret	[],0
181	.size	mn10300_local_dcache_flush_inv,.-mn10300_local_dcache_flush_inv
182
183###############################################################################
184#
185# void mn10300_local_dcache_flush_inv_page(unsigned long start)
186# void mn10300_local_dcache_flush_inv_range(unsigned long start, unsigned long end)
187# void mn10300_local_dcache_flush_inv_range2(unsigned long start, unsigned long size)
188# Flush and invalidate a range of addresses on a page in the dcache
189#
190###############################################################################
191	ALIGN
192	.globl	mn10300_local_dcache_flush_inv_page
193	.globl	mn10300_local_dcache_flush_inv_range
194	.globl	mn10300_local_dcache_flush_inv_range2
195	.type	mn10300_local_dcache_flush_inv_page,@function
196	.type	mn10300_local_dcache_flush_inv_range,@function
197	.type	mn10300_local_dcache_flush_inv_range2,@function
198mn10300_local_dcache_flush_inv_page:
199	and	~(PAGE_SIZE-1),d0
200	mov	PAGE_SIZE,d1
201mn10300_local_dcache_flush_inv_range2:
202	add	d0,d1
203mn10300_local_dcache_flush_inv_range:
204	movm	[d2],(sp)
205
206	movhu	(CHCTR),d2
207	btst	CHCTR_DCEN,d2
208	beq	mn10300_local_dcache_flush_inv_range_end
209
210	sub	d0,d1,a0
211	cmp	MN10300_DCACHE_FLUSH_INV_BORDER,a0
212	ble	1f
213
214	movm	(sp),[d2]
215	bra	mn10300_local_dcache_flush_inv
2161:
217
218	and	L1_CACHE_TAG_MASK,d0		# round start addr down
219	mov	d0,a1
220
221	add	L1_CACHE_BYTES,d1		# round end addr up
222	and	L1_CACHE_TAG_MASK,d1
223
224	# write a request to flush and invalidate all instances of an address
225	# from the cache
226	mov	DCACHE_PURGE(0,0),a0
227	mov	a1,d0
228	and	L1_CACHE_TAG_ENTRY,d0
229	add	d0,a0				# starting dcache purge control
230						# reg address
231
232	sub	a1,d1
233	lsr	L1_CACHE_SHIFT,d1		# total number of entries to
234						# examine
235
236mn10300_local_dcache_flush_inv_range_loop:
237	mov	a1,(L1_CACHE_WAYDISP*0,a0)	# conditionally purge this line
238						# in all ways
239
240	add	L1_CACHE_BYTES,a0
241	add	L1_CACHE_BYTES,a1
242	and	~L1_CACHE_WAYDISP,a0		# make sure way stay on way 0
243	add	-1,d1
244	bne	mn10300_local_dcache_flush_inv_range_loop
245
246mn10300_local_dcache_flush_inv_range_end:
247	ret	[d2],4
248	.size	mn10300_local_dcache_flush_inv_page,.-mn10300_local_dcache_flush_inv_page
249	.size	mn10300_local_dcache_flush_inv_range,.-mn10300_local_dcache_flush_inv_range
250	.size	mn10300_local_dcache_flush_inv_range2,.-mn10300_local_dcache_flush_inv_range2
251