Commit | Line | Data |
---|---|---|
1394f032 | 1 | /* |
ded963a4 | 2 | * Blackfin cache control code |
1394f032 | 3 | * |
ded963a4 | 4 | * Copyright 2004-2008 Analog Devices Inc. |
1394f032 | 5 | * |
ded963a4 | 6 | * Enter bugs at http://blackfin.uclinux.org/ |
1394f032 | 7 | * |
ded963a4 | 8 | * Licensed under the GPL-2 or later. |
1394f032 BW |
9 | */ |
10 | ||
11 | #include <linux/linkage.h> | |
1394f032 BW |
12 | #include <asm/blackfin.h> |
13 | #include <asm/cache.h> | |
ded963a4 | 14 | #include <asm/page.h> |
1394f032 BW |
15 | |
16 | .text | |
1394f032 | 17 | |
ded963a4 MF |
18 | /* Since all L1 caches work the same way, we use the same method for flushing |
19 | * them. Only the actual flush instruction differs. We write this in asm as | |
20 | * GCC can be hard to coax into writing nice hardware loops. | |
1394f032 | 21 | * |
ded963a4 MF |
22 | * Also, we assume the following register setup: |
23 | * R0 = start address | |
24 | * R1 = end address | |
1394f032 | 25 | */ |
ded963a4 MF |
26 | .macro do_flush flushins:req optflushins optnopins label |
27 | ||
39e96c88 MF |
28 | R2 = -L1_CACHE_BYTES; |
29 | ||
30 | /* start = (start & -L1_CACHE_BYTES) */ | |
31 | R0 = R0 & R2; | |
32 | ||
ded963a4 MF |
33 | /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */ |
34 | R1 += -1; | |
ded963a4 MF |
35 | R1 = R1 & R2; |
36 | R1 += L1_CACHE_BYTES; | |
37 | ||
38 | /* count = (end - start) >> L1_CACHE_SHIFT */ | |
39 | R2 = R1 - R0; | |
40 | R2 >>= L1_CACHE_SHIFT; | |
41 | P1 = R2; | |
42 | ||
43 | .ifnb \label | |
44 | \label : | |
45 | .endif | |
46 | P0 = R0; | |
47 | LSETUP (1f, 2f) LC1 = P1; | |
1394f032 | 48 | 1: |
ded963a4 MF |
49 | .ifnb \optflushins |
50 | \optflushins [P0]; | |
51 | .endif | |
52 | .ifb \optnopins | |
53 | 2: | |
54 | .endif | |
55 | \flushins [P0++]; | |
56 | .ifnb \optnopins | |
57 | 2: \optnopins; | |
58 | .endif | |
59 | ||
1394f032 | 60 | RTS; |
ded963a4 | 61 | .endm |
1394f032 | 62 | |
ded963a4 MF |
63 | /* Invalidate all instruction cache lines assocoiated with this memory area */ |
64 | ENTRY(_blackfin_icache_flush_range) | |
65 | do_flush IFLUSH, , nop | |
66 | ENDPROC(_blackfin_icache_flush_range) | |
1394f032 | 67 | |
ded963a4 | 68 | /* Flush all cache lines assocoiated with this area of memory. */ |
1394f032 | 69 | ENTRY(_blackfin_icache_dcache_flush_range) |
7f6b2e7b | 70 | do_flush FLUSH, IFLUSH |
51be24c3 | 71 | ENDPROC(_blackfin_icache_dcache_flush_range) |
1394f032 BW |
72 | |
73 | /* Throw away all D-cached data in specified region without any obligation to | |
ded963a4 MF |
74 | * write them back. Since the Blackfin ISA does not have an "invalidate" |
75 | * instruction, we use flush/invalidate. Perhaps as a speed optimization we | |
76 | * could bang on the DTEST MMRs ... | |
1394f032 | 77 | */ |
1394f032 | 78 | ENTRY(_blackfin_dcache_invalidate_range) |
ded963a4 | 79 | do_flush FLUSHINV |
51be24c3 | 80 | ENDPROC(_blackfin_dcache_invalidate_range) |
1394f032 | 81 | |
ded963a4 | 82 | /* Flush all data cache lines assocoiated with this memory area */ |
1394f032 | 83 | ENTRY(_blackfin_dcache_flush_range) |
ded963a4 | 84 | do_flush FLUSH, , , .Ldfr |
51be24c3 | 85 | ENDPROC(_blackfin_dcache_flush_range) |
1394f032 | 86 | |
ded963a4 MF |
87 | /* Our headers convert the page structure to an address, so just need to flush |
88 | * its contents like normal. We know the start address is page aligned (which | |
89 | * greater than our cache alignment), as is the end address. So just jump into | |
90 | * the middle of the dcache flush function. | |
91 | */ | |
1394f032 BW |
92 | ENTRY(_blackfin_dflush_page) |
93 | P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); | |
ded963a4 | 94 | jump .Ldfr; |
51be24c3 | 95 | ENDPROC(_blackfin_dflush_page) |