]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/blackfin/flush.S
Big white-space cleanup.
[karo-tx-uboot.git] / cpu / blackfin / flush.S
1 /* flush.S - low level cache flushing routines
2  * Copyright (C) 2003-2007 Analog Devices Inc.
3  * Licensed under the GPL-2 or later.
4  */
5
6 #include <config.h>
7 #include <asm/blackfin.h>
8 #include <asm/cplb.h>
9 #include <asm/mach-common/bits/mpu.h>
10
11 .text
12
13 /* This is an external function being called by the user
14  * application through __flush_cache_all. Currently this function
15  * serves the purpose of flushing all the pending writes in
16  * in the data cache.
17  */
18
19 ENTRY(_flush_data_cache)
20         [--SP] = ( R7:6, P5:4 );
21         LINK 12;
22         SP += -12;
23         P5.H = HI(DCPLB_ADDR0);
24         P5.L = LO(DCPLB_ADDR0);
25         P4.H = HI(DCPLB_DATA0);
26         P4.L = LO(DCPLB_DATA0);
27         R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z);
28         R6 = 16;
29 .Lnext: R0 = [P5++];
30         R1 = [P4++];
31         CC = BITTST(R1, 14);    /* Is it write-through?*/
32         IF CC JUMP .Lskip;      /* If so, ignore it.*/
33         R2 = R1 & R7;           /* Is it a dirty, cached page?*/
34         CC = R2;
35         IF !CC JUMP .Lskip;     /* If not, ignore it.*/
36         [--SP] = RETS;
37         CALL _dcplb_flush;      /* R0 = page, R1 = data*/
38         RETS = [SP++];
39 .Lskip: R6 += -1;
40         CC = R6;
41         IF CC JUMP .Lnext;
42         SSYNC;
43         SP += 12;
44         UNLINK;
45         ( R7:6, P5:4 ) = [SP++];
46         RTS;
47 ENDPROC(_flush_data_cache)
48
49 /* This is an internal function to flush all pending
50  * writes in the cache associated with a particular DCPLB.
51  *
52  * R0 -  page's start address
53  * R1 -  CPLB's data field.
54  */
55
56 .align 2
57 ENTRY(_dcplb_flush)
58         [--SP] = ( R7:0, P5:0 );
59         [--SP] = LC0;
60         [--SP] = LT0;
61         [--SP] = LB0;
62         [--SP] = LC1;
63         [--SP] = LT1;
64         [--SP] = LB1;
65
66         /* If it's a 1K or 4K page, then it's quickest to
67          * just systematically flush all the addresses in
68          * the page, regardless of whether they're in the
69          * cache, or dirty. If it's a 1M or 4M page, there
70          * are too many addresses, and we have to search the
71          * cache for lines corresponding to the page.
72          */
73
74         CC = BITTST(R1, 17);    /* 1MB or 4MB */
75         IF !CC JUMP .Ldflush_whole_page;
76
77         /* We're only interested in the page's size, so extract
78          * this from the CPLB (bits 17:16), and scale to give an
79          * offset into the page_size and page_prefix tables.
80          */
81
82         R1 <<= 14;
83         R1 >>= 30;
84         R1 <<= 2;
85
86         /* The page could be mapped into Bank A or Bank B, depending
87          * on (a) whether both banks are configured as cache, and
88          * (b) on whether address bit A[x] is set. x is determined
89          * by DCBS in DMEM_CONTROL
90          */
91
92         R2 = 0;                 /* Default to Bank A (Bank B would be 1)*/
93
94         P0.L = LO(DMEM_CONTROL);
95         P0.H = HI(DMEM_CONTROL);
96
97         R3 = [P0];              /* If Bank B is not enabled as cache*/
98         CC = BITTST(R3, 2);     /* then Bank A is our only option.*/
99         IF CC JUMP .Lbank_chosen;
100
101         R4 = 1<<14;             /* If DCBS==0, use A[14].*/
102         R5 = R4 << 7;           /* If DCBS==1, use A[23];*/
103         CC = BITTST(R3, 4);
104         IF CC R4 = R5;          /* R4 now has either bit 14 or bit 23 set.*/
105         R5 = R0 & R4;           /* Use it to test the Page address*/
106         CC = R5;                /* and if that bit is set, we use Bank B,*/
107         R2 = CC;                /* else we use Bank A.*/
108         R2 <<= 23;              /* The Bank selection's at posn 23.*/
109
110 .Lbank_chosen:
111
112         /* We can also determine the sub-bank used, because this is
113          * taken from bits 13:12 of the address.
114          */
115
116         R3 = ((12<<8)|2);               /* Extraction pattern */
117         nop;                            /*Anamoly 05000209*/
118         R4 = EXTRACT(R0, R3.L) (Z);     /* Extract bits*/
119         /* Save in extraction pattern for later deposit.*/
120         R3.H = R4.L << 0;
121
122         /* So:
123          * R0 = Page start
124          * R1 = Page length (actually, offset into size/prefix tables)
125          * R2 = Bank select mask
126          * R3 = sub-bank deposit values
127          *
128          * The cache has 2 Ways, and 64 sets, so we iterate through
129          * the sets, accessing the tag for each Way, for our Bank and
130          * sub-bank, looking for dirty, valid tags that match our
131          * address prefix.
132          */
133
134         P5.L = LO(DTEST_COMMAND);
135         P5.H = HI(DTEST_COMMAND);
136         P4.L = LO(DTEST_DATA0);
137         P4.H = HI(DTEST_DATA0);
138
139         P0.L = page_prefix_table;
140         P0.H = page_prefix_table;
141         P1 = R1;
142         R5 = 0;                 /* Set counter*/
143         P0 = P1 + P0;
144         R4 = [P0];              /* This is the address prefix*/
145
146
147         /* We're reading (bit 1==0) the tag (bit 2==0), and we
148          * don't care about which double-word, since we're only
149          * fetching tags, so we only have to set Set, Bank,
150          * Sub-bank and Way.
151          */
152
153         P2 = 2;
154         LSETUP (.Lfs1, .Lfe1) LC1 = P2;
155 .Lfs1:  P0 = 64;                /* iterate over all sets*/
156         LSETUP (.Lfs0, .Lfe0) LC0 = P0;
157 .Lfs0:  R6 = R5 << 5;           /* Combine set*/
158         R6.H = R3.H << 0 ;      /* and sub-bank*/
159         R6 = R6 | R2;           /* and Bank. Leave Way==0 at first.*/
160         BITSET(R6,14);
161         [P5] = R6;              /* Issue Command*/
162         SSYNC;
163         R7 = [P4];              /* and read Tag.*/
164         CC = BITTST(R7, 0);     /* Check if valid*/
165         IF !CC JUMP .Lfskip;    /* and skip if not.*/
166         CC = BITTST(R7, 1);     /* Check if dirty*/
167         IF !CC JUMP .Lfskip;    /* and skip if not.*/
168
169         /* Compare against the page address. First, plant bits 13:12
170          * into the tag, since those aren't part of the returned data.
171          */
172
173         R7 = DEPOSIT(R7, R3);   /* set 13:12*/
174         R1 = R7 & R4;           /* Mask off lower bits*/
175         CC = R1 == R0;          /* Compare against page start.*/
176         IF !CC JUMP .Lfskip;    /* Skip it if it doesn't match.*/
177
178         /* Tag address matches against page, so this is an entry
179          * we must flush.
180          */
181
182         R7 >>= 10;              /* Mask off the non-address bits*/
183         R7 <<= 10;
184         P3 = R7;
185         SSYNC;
186         FLUSHINV [P3];          /* And flush the entry*/
187 .Lfskip:
188 .Lfe0:  R5 += 1;                /* Advance to next Set*/
189 .Lfe1:  BITSET(R2, 26);         /* Go to next Way.*/
190
191 .Ldfinished:
192         SSYNC;                  /* Ensure the data gets out to mem.*/
193
194         /*Finished. Restore context.*/
195         LB1 = [SP++];
196         LT1 = [SP++];
197         LC1 = [SP++];
198         LB0 = [SP++];
199         LT0 = [SP++];
200         LC0 = [SP++];
201         ( R7:0, P5:0 ) = [SP++];
202         RTS;
203
204 .Ldflush_whole_page:
205
206         /* It's a 1K or 4K page, so quicker to just flush the
207          * entire page.
208          */
209
210         P1 = 32;                /* For 1K pages*/
211         P2 = P1 << 2;           /* For 4K pages*/
212         P0 = R0;                /* Start of page*/
213         CC = BITTST(R1, 16);    /* Whether 1K or 4K*/
214         IF CC P1 = P2;
215         P1 += -1;               /* Unroll one iteration*/
216         SSYNC;
217         FLUSHINV [P0++];        /* because CSYNC can't end loops.*/
218         LSETUP (.Leall, .Leall) LC0 = P1;
219 .Leall: FLUSHINV [P0++];
220         SSYNC;
221         JUMP .Ldfinished;
222 ENDPROC(_dcplb_flush)
223
224 .align 4;
225 page_prefix_table:
226 .byte4  0xFFFFFC00;     /* 1K */
227 .byte4  0xFFFFF000;     /* 4K */
228 .byte4  0xFFF00000;     /* 1M */
229 .byte4  0xFFC00000;     /* 4M */
230 .page_prefix_table.end: