Merge with /home/wd/git/u-boot/custodian/u-boot-mpc86xx
[platform/kernel/u-boot.git] / cpu / bf537 / flush.S
1 /* Copyright (C) 2003 Analog Devices, Inc. All Rights Reserved.
2  * Copyright (C) 2004 LG SOft India. All Rights Reserved.
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.
6  */
7 #define ASSEMBLY
8
9 #include <asm/linkage.h>
10 #include <asm/cplb.h>
11 #include <config.h>
12 #include <asm/blackfin.h>
13
14 .text
15
16 /* This is an external function being called by the user
17  * application through __flush_cache_all. Currently this function
18  * serves the purpose of flushing all the pending writes in
19  * in the instruction cache.
20  */
21
22 ENTRY(_flush_instruction_cache)
23         [--SP] = ( R7:6, P5:4 );
24         LINK 12;
25         SP += -12;
26         P5.H = (ICPLB_ADDR0 >> 16);
27         P5.L = (ICPLB_ADDR0 & 0xFFFF);
28         P4.H = (ICPLB_DATA0 >> 16);
29         P4.L = (ICPLB_DATA0 & 0xFFFF);
30         R7 = CPLB_VALID | CPLB_L1_CHBL;
31         R6 = 16;
32 inext:  R0 = [P5++];
33         R1 = [P4++];
34         [--SP] =  RETS;
35         CALL _icplb_flush;      /* R0 = page, R1 = data*/
36         RETS = [SP++];
37 iskip:  R6 += -1;
38         CC = R6;
39         IF CC JUMP inext;
40         SSYNC;
41         SP += 12;
42         UNLINK;
43         ( R7:6, P5:4 ) = [SP++];
44         RTS;
45
46 /* This is an internal function to flush all pending
47  * writes in the cache associated with a particular ICPLB.
48  *
49  * R0 -  page's start address
50  * R1 -  CPLB's data field.
51  */
52
53 .align 2
54 ENTRY(_icplb_flush)
55         [--SP] = ( R7:0, P5:0 );
56         [--SP] = LC0;
57         [--SP] = LT0;
58         [--SP] = LB0;
59         [--SP] = LC1;
60         [--SP] = LT1;
61         [--SP] = LB1;
62
63         /* If it's a 1K or 4K page, then it's quickest to
64          * just systematically flush all the addresses in
65          * the page, regardless of whether they're in the
66          * cache, or dirty. If it's a 1M or 4M page, there
67          * are too many addresses, and we have to search the
68          * cache for lines corresponding to the page.
69          */
70
71         CC = BITTST(R1, 17);    /* 1MB or 4MB */
72         IF !CC JUMP iflush_whole_page;
73
74         /* We're only interested in the page's size, so extract
75          * this from the CPLB (bits 17:16), and scale to give an
76          * offset into the page_size and page_prefix tables.
77          */
78
79         R1 <<= 14;
80         R1 >>= 30;
81         R1 <<= 2;
82
83         /* We can also determine the sub-bank used, because this is
84          * taken from bits 13:12 of the address.
85          */
86
87         R3 = ((12<<8)|2);               /* Extraction pattern */
88         nop;                            /* Anamoly 05000209 */
89         R4 = EXTRACT(R0, R3.L) (Z);     /* Extract bits */
90
91         /* Save in extraction pattern for later deposit. */
92         R3.H = R4.L << 0;
93
94         /* So:
95          * R0 = Page start
96          * R1 = Page length (actually, offset into size/prefix tables)
97          * R3 = sub-bank deposit values
98          *
99          * The cache has 2 Ways, and 64 sets, so we iterate through
100          * the sets, accessing the tag for each Way, for our Bank and
101          * sub-bank, looking for dirty, valid tags that match our
102          * address prefix.
103          */
104
105         P5.L = (ITEST_COMMAND & 0xFFFF);
106         P5.H = (ITEST_COMMAND >> 16);
107         P4.L = (ITEST_DATA0 & 0xFFFF);
108         P4.H = (ITEST_DATA0 >> 16);
109
110         P0.L = page_prefix_table;
111         P0.H = page_prefix_table;
112         P1 = R1;
113         R5 = 0;                 /* Set counter*/
114         P0 = P1 + P0;
115         R4 = [P0];              /* This is the address prefix*/
116
117         /* We're reading (bit 1==0) the tag (bit 2==0), and we
118          * don't care about which double-word, since we're only
119          * fetching tags, so we only have to set Set, Bank,
120          * Sub-bank and Way.
121          */
122
123         P2 = 4;
124         LSETUP (ifs1, ife1) LC1 = P2;
125 ifs1:   P0 = 32;                /* iterate over all sets*/
126         LSETUP (ifs0, ife0) LC0 = P0;
127 ifs0:   R6 = R5 << 5;           /* Combine set*/
128         R6.H = R3.H << 0 ;      /* and sub-bank*/
129         [P5] = R6;              /* Issue Command*/
130         SSYNC;                  /* CSYNC will not work here :(*/
131         R7 = [P4];              /* and read Tag.*/
132         CC = BITTST(R7, 0);     /* Check if valid*/
133         IF !CC JUMP ifskip;     /* and skip if not.*/
134
135         /* Compare against the page address. First, plant bits 13:12
136          * into the tag, since those aren't part of the returned data.
137          */
138
139         R7 = DEPOSIT(R7, R3);   /* set 13:12*/
140         R1 = R7 & R4;           /* Mask off lower bits*/
141         CC = R1 == R0;          /* Compare against page start.*/
142         IF !CC JUMP ifskip;     /* Skip it if it doesn't match.*/
143
144         /* Tag address matches against page, so this is an entry
145          * we must flush.
146          */
147
148         R7 >>= 10;              /* Mask off the non-address bits*/
149         R7 <<= 10;
150         P3 = R7;
151         IFLUSH [P3];            /* And flush the entry*/
152 ifskip:
153 ife0:   R5 += 1;                /* Advance to next Set*/
154 ife1:   NOP;
155
156 ifinished:
157         SSYNC;                  /* Ensure the data gets out to mem.*/
158
159         /*Finished. Restore context.*/
160         LB1 = [SP++];
161         LT1 = [SP++];
162         LC1 = [SP++];
163         LB0 = [SP++];
164         LT0 = [SP++];
165         LC0 = [SP++];
166         ( R7:0, P5:0 ) = [SP++];
167         RTS;
168
169 iflush_whole_page:
170         /* It's a 1K or 4K page, so quicker to just flush the
171          * entire page.
172          */
173
174         P1 = 32;                /* For 1K pages*/
175         P2 = P1 << 2;           /* For 4K pages*/
176         P0 = R0;                /* Start of page*/
177         CC = BITTST(R1, 16);    /* Whether 1K or 4K*/
178         IF CC P1 = P2;
179         P1 += -1;               /* Unroll one iteration*/
180         SSYNC;
181         IFLUSH [P0++];          /* because CSYNC can't end loops.*/
182         LSETUP (isall, ieall) LC0 = P1;
183 isall:IFLUSH [P0++];
184 ieall: NOP;
185         SSYNC;
186         JUMP ifinished;
187
188 /* This is an external function being called by the user
189  * application through __flush_cache_all. Currently this function
190  * serves the purpose of flushing all the pending writes in
191  * in the data cache.
192  */
193
194 ENTRY(_flush_data_cache)
195         [--SP] = ( R7:6, P5:4 );
196         LINK 12;
197         SP += -12;
198         P5.H = (DCPLB_ADDR0 >> 16);
199         P5.L = (DCPLB_ADDR0 & 0xFFFF);
200         P4.H = (DCPLB_DATA0 >> 16);
201         P4.L = (DCPLB_DATA0 & 0xFFFF);
202         R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z);
203         R6 = 16;
204 next:   R0 = [P5++];
205         R1 = [P4++];
206         CC = BITTST(R1, 14);    /* Is it write-through?*/
207         IF CC JUMP skip;        /* If so, ignore it.*/
208         R2 = R1 & R7;           /* Is it a dirty, cached page?*/
209         CC = R2;
210         IF !CC JUMP skip;       /* If not, ignore it.*/
211         [--SP] = RETS;
212         CALL _dcplb_flush;      /* R0 = page, R1 = data*/
213         RETS = [SP++];
214 skip:   R6 += -1;
215         CC = R6;
216         IF CC JUMP next;
217         SSYNC;
218         SP += 12;
219         UNLINK;
220         ( R7:6, P5:4 ) = [SP++];
221         RTS;
222
223 /* This is an internal function to flush all pending
224  * writes in the cache associated with a particular DCPLB.
225  *
226  * R0 -  page's start address
227  * R1 -  CPLB's data field.
228  */
229
230 .align 2
231 ENTRY(_dcplb_flush)
232         [--SP] = ( R7:0, P5:0 );
233         [--SP] = LC0;
234         [--SP] = LT0;
235         [--SP] = LB0;
236         [--SP] = LC1;
237         [--SP] = LT1;
238         [--SP] = LB1;
239
240         /* If it's a 1K or 4K page, then it's quickest to
241          * just systematically flush all the addresses in
242          * the page, regardless of whether they're in the
243          * cache, or dirty. If it's a 1M or 4M page, there
244          * are too many addresses, and we have to search the
245          * cache for lines corresponding to the page.
246          */
247
248         CC = BITTST(R1, 17);    /* 1MB or 4MB */
249         IF !CC JUMP dflush_whole_page;
250
251         /* We're only interested in the page's size, so extract
252          * this from the CPLB (bits 17:16), and scale to give an
253          * offset into the page_size and page_prefix tables.
254          */
255
256         R1 <<= 14;
257         R1 >>= 30;
258         R1 <<= 2;
259
260         /* The page could be mapped into Bank A or Bank B, depending
261          * on (a) whether both banks are configured as cache, and
262          * (b) on whether address bit A[x] is set. x is determined
263          * by DCBS in DMEM_CONTROL
264          */
265
266         R2 = 0;                 /* Default to Bank A (Bank B would be 1)*/
267
268         P0.L = (DMEM_CONTROL & 0xFFFF);
269         P0.H = (DMEM_CONTROL >> 16);
270
271         R3 = [P0];              /* If Bank B is not enabled as cache*/
272         CC = BITTST(R3, 2);     /* then Bank A is our only option.*/
273         IF CC JUMP bank_chosen;
274
275         R4 = 1<<14;             /* If DCBS==0, use A[14].*/
276         R5 = R4 << 7;           /* If DCBS==1, use A[23];*/
277         CC = BITTST(R3, 4);
278         IF CC R4 = R5;          /* R4 now has either bit 14 or bit 23 set.*/
279         R5 = R0 & R4;           /* Use it to test the Page address*/
280         CC = R5;                /* and if that bit is set, we use Bank B,*/
281         R2 = CC;                /* else we use Bank A.*/
282         R2 <<= 23;              /* The Bank selection's at posn 23.*/
283
284 bank_chosen:
285
286         /* We can also determine the sub-bank used, because this is
287          * taken from bits 13:12 of the address.
288          */
289
290         R3 = ((12<<8)|2);               /* Extraction pattern */
291         nop;                            /*Anamoly 05000209*/
292         R4 = EXTRACT(R0, R3.L) (Z);     /* Extract bits*/
293         /* Save in extraction pattern for later deposit.*/
294         R3.H = R4.L << 0;
295
296         /* So:
297          * R0 = Page start
298          * R1 = Page length (actually, offset into size/prefix tables)
299          * R2 = Bank select mask
300          * R3 = sub-bank deposit values
301          *
302          * The cache has 2 Ways, and 64 sets, so we iterate through
303          * the sets, accessing the tag for each Way, for our Bank and
304          * sub-bank, looking for dirty, valid tags that match our
305          * address prefix.
306          */
307
308         P5.L = (DTEST_COMMAND & 0xFFFF);
309         P5.H = (DTEST_COMMAND >> 16);
310         P4.L = (DTEST_DATA0 & 0xFFFF);
311         P4.H = (DTEST_DATA0 >> 16);
312
313         P0.L = page_prefix_table;
314         P0.H = page_prefix_table;
315         P1 = R1;
316         R5 = 0;                 /* Set counter*/
317         P0 = P1 + P0;
318         R4 = [P0];              /* This is the address prefix*/
319
320
321         /* We're reading (bit 1==0) the tag (bit 2==0), and we
322          * don't care about which double-word, since we're only
323          * fetching tags, so we only have to set Set, Bank,
324          * Sub-bank and Way.
325          */
326
327         P2 = 2;
328         LSETUP (fs1, fe1) LC1 = P2;
329 fs1:    P0 = 64;                /* iterate over all sets*/
330         LSETUP (fs0, fe0) LC0 = P0;
331 fs0:    R6 = R5 << 5;           /* Combine set*/
332         R6.H = R3.H << 0 ;      /* and sub-bank*/
333         R6 = R6 | R2;           /* and Bank. Leave Way==0 at first.*/
334         BITSET(R6,14);
335         [P5] = R6;              /* Issue Command*/
336         SSYNC;
337         R7 = [P4];              /* and read Tag.*/
338         CC = BITTST(R7, 0);     /* Check if valid*/
339         IF !CC JUMP fskip;      /* and skip if not.*/
340         CC = BITTST(R7, 1);     /* Check if dirty*/
341         IF !CC JUMP fskip;      /* and skip if not.*/
342
343         /* Compare against the page address. First, plant bits 13:12
344          * into the tag, since those aren't part of the returned data.
345          */
346
347         R7 = DEPOSIT(R7, R3);   /* set 13:12*/
348         R1 = R7 & R4;           /* Mask off lower bits*/
349         CC = R1 == R0;          /* Compare against page start.*/
350         IF !CC JUMP fskip;      /* Skip it if it doesn't match.*/
351
352         /* Tag address matches against page, so this is an entry
353          * we must flush.
354          */
355
356         R7 >>= 10;              /* Mask off the non-address bits*/
357         R7 <<= 10;
358         P3 = R7;
359         SSYNC;
360         FLUSHINV [P3];          /* And flush the entry*/
361 fskip:
362 fe0:    R5 += 1;                /* Advance to next Set*/
363 fe1:    BITSET(R2, 26);         /* Go to next Way.*/
364
365 dfinished:
366         SSYNC;                  /* Ensure the data gets out to mem.*/
367
368         /*Finished. Restore context.*/
369         LB1 = [SP++];
370         LT1 = [SP++];
371         LC1 = [SP++];
372         LB0 = [SP++];
373         LT0 = [SP++];
374         LC0 = [SP++];
375         ( R7:0, P5:0 ) = [SP++];
376         RTS;
377
378 dflush_whole_page:
379
380         /* It's a 1K or 4K page, so quicker to just flush the
381          * entire page.
382          */
383
384         P1 = 32;                /* For 1K pages*/
385         P2 = P1 << 2;           /* For 4K pages*/
386         P0 = R0;                /* Start of page*/
387         CC = BITTST(R1, 16);    /* Whether 1K or 4K*/
388         IF CC P1 = P2;
389         P1 += -1;               /* Unroll one iteration*/
390         SSYNC;
391         FLUSHINV [P0++];        /* because CSYNC can't end loops.*/
392         LSETUP (eall, eall) LC0 = P1;
393 eall:   FLUSHINV [P0++];
394         SSYNC;
395         JUMP dfinished;
396
397 .align 4;
398 page_prefix_table:
399 .byte4  0xFFFFFC00;     /* 1K */
400 .byte4  0xFFFFF000;     /* 4K */
401 .byte4  0xFFF00000;     /* 1M */
402 .byte4  0xFFC00000;     /* 4M */
403 .page_prefix_table.end: