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