]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/bf533/flush.S
Coding Style cleanup
[karo-tx-uboot.git] / cpu / bf533 / 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  * Blackfin BF533/2.6 support : LG Soft India
8  */
9 #define ASSEMBLY
10
11 #include <asm/linkage.h>
12 #include <asm/cplb.h>
13 #include <asm/blackfin.h>
14
15 .text
16
17 /* This is an external function being called by the user
18  * application through __flush_cache_all. Currently this function
19  * serves the purpose of flushing all the pending writes in
20  * in the instruction cache.
21  */
22
23 ENTRY(flush_instruction_cache)
24         [--SP] = ( R7:6, P5:4 );
25         LINK 12;
26         SP += -12;
27         P5.H = (ICPLB_ADDR0 >> 16);
28         P5.L = (ICPLB_ADDR0 & 0xFFFF);
29         P4.H = (ICPLB_DATA0 >> 16);
30         P4.L = (ICPLB_DATA0 & 0xFFFF);
31         R7 = CPLB_VALID | CPLB_L1_CHBL;
32         R6 = 16;
33 inext:  R0 = [P5++];
34         R1 = [P4++];
35         [--SP] =  RETS;
36         CALL icplb_flush;       /* R0 = page, R1 = data*/
37         RETS = [SP++];
38 iskip:  R6 += -1;
39         CC = R6;
40         IF CC JUMP inext;
41         SSYNC;
42         SP += 12;
43         UNLINK;
44         ( R7:6, P5:4 ) = [SP++];
45         RTS;
46
47 /* This is an internal function to flush all pending
48  * writes in the cache associated with a particular ICPLB.
49  *
50  * R0 -  page's start address
51  * R1 -  CPLB's data field.
52  */
53
54 .align 2
55 ENTRY(icplb_flush)
56         [--SP] = ( R7:0, P5:0 );
57         [--SP] = LC0;
58         [--SP] = LT0;
59         [--SP] = LB0;
60         [--SP] = LC1;
61         [--SP] = LT1;
62         [--SP] = LB1;
63
64         /* If it's a 1K or 4K page, then it's quickest to
65          * just systematically flush all the addresses in
66          * the page, regardless of whether they're in the
67          * cache, or dirty. If it's a 1M or 4M page, there
68          * are too many addresses, and we have to search the
69          * cache for lines corresponding to the page.
70          */
71
72         CC = BITTST(R1, 17);    /* 1MB or 4MB */
73         IF !CC JUMP iflush_whole_page;
74
75         /* We're only interested in the page's size, so extract
76          * this from the CPLB (bits 17:16), and scale to give an
77          * offset into the page_size and page_prefix tables.
78          */
79
80         R1 <<= 14;
81         R1 >>= 30;
82         R1 <<= 2;
83
84         /* We can also determine the sub-bank used, because this is
85          * taken from bits 13:12 of the address.
86          */
87
88         R3 = ((12<<8)|2);               /* Extraction pattern */
89         nop;                            /*Anamoly 05000209*/
90         R4 = EXTRACT(R0, R3.L) (Z);     /* Extract bits*/
91         R3.H = R4.L << 0 ;              /* Save in extraction pattern for later deposit.*/
92
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         R3.H = R4.L << 0 ;              /* Save in extraction pattern for later deposit.*/
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: