Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / mn10300 / mm / cache-flush-by-reg.S
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
31 mn10300_dcache_flush            = mn10300_local_dcache_flush
32 mn10300_dcache_flush_page       = mn10300_local_dcache_flush_page
33 mn10300_dcache_flush_range      = mn10300_local_dcache_flush_range
34 mn10300_dcache_flush_range2     = mn10300_local_dcache_flush_range2
35 mn10300_dcache_flush_inv        = mn10300_local_dcache_flush_inv
36 mn10300_dcache_flush_inv_page   = mn10300_local_dcache_flush_inv_page
37 mn10300_dcache_flush_inv_range  = mn10300_local_dcache_flush_inv_range
38 mn10300_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
51 mn10300_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
85 mn10300_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
104 mn10300_local_dcache_flush_page:
105         and     ~(PAGE_SIZE-1),d0
106         mov     PAGE_SIZE,d1
107 mn10300_local_dcache_flush_range2:
108         add     d0,d1
109 mn10300_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
128 1:
129         add     d2,d2
130         lsr     1,d3
131         bne     1b
132 2:
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
152 dcpgloop:
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
171 mn10300_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
187 mn10300_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
218 mn10300_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
237 mn10300_local_dcache_flush_inv_page:
238         and     ~(PAGE_SIZE-1),d0
239         mov     PAGE_SIZE,d1
240 mn10300_local_dcache_flush_inv_range2:
241         add     d0,d1
242 mn10300_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
261 1:
262         add     d2,d2
263         lsr     1,d3
264         bne     1b
265 2:
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
285 dcpgivloop:
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
304 mn10300_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