Added watchdog triggering calls in the "mtest" test function.
[platform/kernel/u-boot.git] / cpu / bf533 / flush.S
1 /* Copyright (C) 2003-2007 Analog Devices Inc.
2  *
3  * This file is subject to the terms and conditions of the GNU General Public
4  * License.
5  */
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:
184         IFLUSH [P0++];
185 ieall:
186         NOP;
187         SSYNC;
188         JUMP ifinished;
189
190 /* This is an external function being called by the user
191  * application through __flush_cache_all. Currently this function
192  * serves the purpose of flushing all the pending writes in
193  * in the data cache.
194  */
195
196 ENTRY(_flush_data_cache)
197         [--SP] = ( R7:6, P5:4 );
198         LINK 12;
199         SP += -12;
200         P5.H = (DCPLB_ADDR0 >> 16);
201         P5.L = (DCPLB_ADDR0 & 0xFFFF);
202         P4.H = (DCPLB_DATA0 >> 16);
203         P4.L = (DCPLB_DATA0 & 0xFFFF);
204         R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z);
205         R6 = 16;
206 next:   R0 = [P5++];
207         R1 = [P4++];
208         CC = BITTST(R1, 14);    /* Is it write-through?*/
209         IF CC JUMP skip;        /* If so, ignore it.*/
210         R2 = R1 & R7;           /* Is it a dirty, cached page?*/
211         CC = R2;
212         IF !CC JUMP skip;       /* If not, ignore it.*/
213         [--SP] = RETS;
214         CALL _dcplb_flush;      /* R0 = page, R1 = data*/
215         RETS = [SP++];
216 skip:   R6 += -1;
217         CC = R6;
218         IF CC JUMP next;
219         SSYNC;
220         SP += 12;
221         UNLINK;
222         ( R7:6, P5:4 ) = [SP++];
223         RTS;
224
225 /* This is an internal function to flush all pending
226  * writes in the cache associated with a particular DCPLB.
227  *
228  * R0 -  page's start address
229  * R1 -  CPLB's data field.
230  */
231
232 .align 2
233 ENTRY(_dcplb_flush)
234         [--SP] = ( R7:0, P5:0 );
235         [--SP] = LC0;
236         [--SP] = LT0;
237         [--SP] = LB0;
238         [--SP] = LC1;
239         [--SP] = LT1;
240         [--SP] = LB1;
241
242         /* If it's a 1K or 4K page, then it's quickest to
243          * just systematically flush all the addresses in
244          * the page, regardless of whether they're in the
245          * cache, or dirty. If it's a 1M or 4M page, there
246          * are too many addresses, and we have to search the
247          * cache for lines corresponding to the page.
248          */
249
250         CC = BITTST(R1, 17);    /* 1MB or 4MB */
251         IF !CC JUMP dflush_whole_page;
252
253         /* We're only interested in the page's size, so extract
254          * this from the CPLB (bits 17:16), and scale to give an
255          * offset into the page_size and page_prefix tables.
256          */
257
258         R1 <<= 14;
259         R1 >>= 30;
260         R1 <<= 2;
261
262         /* The page could be mapped into Bank A or Bank B, depending
263          * on (a) whether both banks are configured as cache, and
264          * (b) on whether address bit A[x] is set. x is determined
265          * by DCBS in DMEM_CONTROL
266          */
267
268         R2 = 0;                 /* Default to Bank A (Bank B would be 1)*/
269
270         P0.L = (DMEM_CONTROL & 0xFFFF);
271         P0.H = (DMEM_CONTROL >> 16);
272
273         R3 = [P0];              /* If Bank B is not enabled as cache*/
274         CC = BITTST(R3, 2);     /* then Bank A is our only option.*/
275         IF CC JUMP bank_chosen;
276
277         R4 = 1<<14;             /* If DCBS==0, use A[14].*/
278         R5 = R4 << 7;           /* If DCBS==1, use A[23];*/
279         CC = BITTST(R3, 4);
280         IF CC R4 = R5;          /* R4 now has either bit 14 or bit 23 set.*/
281         R5 = R0 & R4;           /* Use it to test the Page address*/
282         CC = R5;                /* and if that bit is set, we use Bank B,*/
283         R2 = CC;                /* else we use Bank A.*/
284         R2 <<= 23;              /* The Bank selection's at posn 23.*/
285
286 bank_chosen:
287
288         /* We can also determine the sub-bank used, because this is
289          * taken from bits 13:12 of the address.
290          */
291
292         R3 = ((12<<8)|2);               /* Extraction pattern */
293         nop;                            /*Anamoly 05000209*/
294         R4 = EXTRACT(R0, R3.L) (Z);     /* Extract bits*/
295         /* Save in extraction pattern for later deposit.*/
296         R3.H = R4.L << 0;
297
298         /* So:
299          * R0 = Page start
300          * R1 = Page length (actually, offset into size/prefix tables)
301          * R2 = Bank select mask
302          * R3 = sub-bank deposit values
303          *
304          * The cache has 2 Ways, and 64 sets, so we iterate through
305          * the sets, accessing the tag for each Way, for our Bank and
306          * sub-bank, looking for dirty, valid tags that match our
307          * address prefix.
308          */
309
310         P5.L = (DTEST_COMMAND & 0xFFFF);
311         P5.H = (DTEST_COMMAND >> 16);
312         P4.L = (DTEST_DATA0 & 0xFFFF);
313         P4.H = (DTEST_DATA0 >> 16);
314
315         P0.L = page_prefix_table;
316         P0.H = page_prefix_table;
317         P1 = R1;
318         R5 = 0;                 /* Set counter*/
319         P0 = P1 + P0;
320         R4 = [P0];              /* This is the address prefix*/
321
322
323         /* We're reading (bit 1==0) the tag (bit 2==0), and we
324          * don't care about which double-word, since we're only
325          * fetching tags, so we only have to set Set, Bank,
326          * Sub-bank and Way.
327          */
328
329         P2 = 2;
330         LSETUP (fs1, fe1) LC1 = P2;
331 fs1:    P0 = 64;                /* iterate over all sets*/
332         LSETUP (fs0, fe0) LC0 = P0;
333 fs0:    R6 = R5 << 5;           /* Combine set*/
334         R6.H = R3.H << 0 ;      /* and sub-bank*/
335         R6 = R6 | R2;           /* and Bank. Leave Way==0 at first.*/
336         BITSET(R6,14);
337         [P5] = R6;              /* Issue Command*/
338         SSYNC;
339         R7 = [P4];              /* and read Tag.*/
340         CC = BITTST(R7, 0);     /* Check if valid*/
341         IF !CC JUMP fskip;      /* and skip if not.*/
342         CC = BITTST(R7, 1);     /* Check if dirty*/
343         IF !CC JUMP fskip;      /* and skip if not.*/
344
345         /* Compare against the page address. First, plant bits 13:12
346          * into the tag, since those aren't part of the returned data.
347          */
348
349         R7 = DEPOSIT(R7, R3);   /* set 13:12*/
350         R1 = R7 & R4;           /* Mask off lower bits*/
351         CC = R1 == R0;          /* Compare against page start.*/
352         IF !CC JUMP fskip;      /* Skip it if it doesn't match.*/
353
354         /* Tag address matches against page, so this is an entry
355          * we must flush.
356          */
357
358         R7 >>= 10;              /* Mask off the non-address bits*/
359         R7 <<= 10;
360         P3 = R7;
361         SSYNC;
362         FLUSHINV [P3];          /* And flush the entry*/
363 fskip:
364 fe0:    R5 += 1;                /* Advance to next Set*/
365 fe1:    BITSET(R2, 26);         /* Go to next Way.*/
366
367 dfinished:
368         SSYNC;                  /* Ensure the data gets out to mem.*/
369
370         /*Finished. Restore context.*/
371         LB1 = [SP++];
372         LT1 = [SP++];
373         LC1 = [SP++];
374         LB0 = [SP++];
375         LT0 = [SP++];
376         LC0 = [SP++];
377         ( R7:0, P5:0 ) = [SP++];
378         RTS;
379
380 dflush_whole_page:
381
382         /* It's a 1K or 4K page, so quicker to just flush the
383          * entire page.
384          */
385
386         P1 = 32;                /* For 1K pages*/
387         P2 = P1 << 2;           /* For 4K pages*/
388         P0 = R0;                /* Start of page*/
389         CC = BITTST(R1, 16);    /* Whether 1K or 4K*/
390         IF CC P1 = P2;
391         P1 += -1;               /* Unroll one iteration*/
392         SSYNC;
393         FLUSHINV [P0++];        /* because CSYNC can't end loops.*/
394         LSETUP (eall, eall) LC0 = P1;
395 eall:   FLUSHINV [P0++];
396         SSYNC;
397         JUMP dfinished;
398
399 .align 4;
400 page_prefix_table:
401 .byte4  0xFFFFFC00;     /* 1K */
402 .byte4  0xFFFFF000;     /* 4K */
403 .byte4  0xFFF00000;     /* 1M */
404 .byte4  0xFFC00000;     /* 4M */
405 .page_prefix_table.end: