]>
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 | * Licensed under the GPL-2 or later. |
1394f032 BW |
7 | */ |
8 | ||
9 | #include <linux/linkage.h> | |
1394f032 BW |
10 | #include <asm/blackfin.h> |
11 | #include <asm/cache.h> | |
ded963a4 | 12 | #include <asm/page.h> |
1394f032 | 13 | |
78f28a0a MF |
14 | /* 05000443 - IFLUSH cannot be last instruction in hardware loop */ |
15 | #if ANOMALY_05000443 | |
16 | # define BROK_FLUSH_INST "IFLUSH" | |
17 | #else | |
18 | # define BROK_FLUSH_INST "no anomaly! yeah!" | |
19 | #endif | |
20 | ||
ded963a4 MF |
21 | /* Since all L1 caches work the same way, we use the same method for flushing |
22 | * them. Only the actual flush instruction differs. We write this in asm as | |
23 | * GCC can be hard to coax into writing nice hardware loops. | |
1394f032 | 24 | * |
ded963a4 MF |
25 | * Also, we assume the following register setup: |
26 | * R0 = start address | |
27 | * R1 = end address | |
1394f032 | 28 | */ |
78f28a0a | 29 | .macro do_flush flushins:req label |
ded963a4 | 30 | |
39e96c88 MF |
31 | R2 = -L1_CACHE_BYTES; |
32 | ||
33 | /* start = (start & -L1_CACHE_BYTES) */ | |
34 | R0 = R0 & R2; | |
35 | ||
ded963a4 MF |
36 | /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */ |
37 | R1 += -1; | |
ded963a4 MF |
38 | R1 = R1 & R2; |
39 | R1 += L1_CACHE_BYTES; | |
40 | ||
41 | /* count = (end - start) >> L1_CACHE_SHIFT */ | |
42 | R2 = R1 - R0; | |
43 | R2 >>= L1_CACHE_SHIFT; | |
44 | P1 = R2; | |
45 | ||
46 | .ifnb \label | |
47 | \label : | |
48 | .endif | |
49 | P0 = R0; | |
78f28a0a | 50 | |
ded963a4 | 51 | LSETUP (1f, 2f) LC1 = P1; |
1394f032 | 52 | 1: |
78f28a0a | 53 | .ifeqs "\flushins", BROK_FLUSH_INST |
ded963a4 | 54 | \flushins [P0++]; |
be1229b4 MF |
55 | nop; |
56 | nop; | |
78f28a0a MF |
57 | 2: nop; |
58 | .else | |
2cf85113 | 59 | 2: \flushins [P0++]; |
78f28a0a | 60 | .endif |
ded963a4 | 61 | |
1394f032 | 62 | RTS; |
ded963a4 | 63 | .endm |
1394f032 | 64 | |
820b127d MF |
65 | #ifdef CONFIG_ICACHE_FLUSH_L1 |
66 | .section .l1.text | |
67 | #else | |
68 | .text | |
69 | #endif | |
70 | ||
ded963a4 | 71 | /* Invalidate all instruction cache lines assocoiated with this memory area */ |
c6345ab1 SZ |
72 | #ifdef CONFIG_SMP |
73 | # define _blackfin_icache_flush_range _blackfin_icache_flush_range_l1 | |
74 | #endif | |
ded963a4 | 75 | ENTRY(_blackfin_icache_flush_range) |
78f28a0a | 76 | do_flush IFLUSH |
ded963a4 | 77 | ENDPROC(_blackfin_icache_flush_range) |
1394f032 | 78 | |
c6345ab1 SZ |
79 | #ifdef CONFIG_SMP |
80 | .text | |
81 | # undef _blackfin_icache_flush_range | |
82 | ENTRY(_blackfin_icache_flush_range) | |
83 | p0.L = LO(DSPID); | |
84 | p0.H = HI(DSPID); | |
85 | r3 = [p0]; | |
86 | r3 = r3.b (z); | |
87 | p2 = r3; | |
88 | p0.L = _blackfin_iflush_l1_entry; | |
89 | p0.H = _blackfin_iflush_l1_entry; | |
90 | p0 = p0 + (p2 << 2); | |
91 | p1 = [p0]; | |
92 | jump (p1); | |
93 | ENDPROC(_blackfin_icache_flush_range) | |
94 | #endif | |
95 | ||
820b127d MF |
96 | #ifdef CONFIG_DCACHE_FLUSH_L1 |
97 | .section .l1.text | |
98 | #else | |
99 | .text | |
100 | #endif | |
101 | ||
1394f032 | 102 | /* Throw away all D-cached data in specified region without any obligation to |
ded963a4 MF |
103 | * write them back. Since the Blackfin ISA does not have an "invalidate" |
104 | * instruction, we use flush/invalidate. Perhaps as a speed optimization we | |
105 | * could bang on the DTEST MMRs ... | |
1394f032 | 106 | */ |
1394f032 | 107 | ENTRY(_blackfin_dcache_invalidate_range) |
ded963a4 | 108 | do_flush FLUSHINV |
51be24c3 | 109 | ENDPROC(_blackfin_dcache_invalidate_range) |
1394f032 | 110 | |
ded963a4 | 111 | /* Flush all data cache lines assocoiated with this memory area */ |
1394f032 | 112 | ENTRY(_blackfin_dcache_flush_range) |
78f28a0a | 113 | do_flush FLUSH, .Ldfr |
51be24c3 | 114 | ENDPROC(_blackfin_dcache_flush_range) |
1394f032 | 115 | |
ded963a4 MF |
116 | /* Our headers convert the page structure to an address, so just need to flush |
117 | * its contents like normal. We know the start address is page aligned (which | |
118 | * greater than our cache alignment), as is the end address. So just jump into | |
119 | * the middle of the dcache flush function. | |
120 | */ | |
1394f032 BW |
121 | ENTRY(_blackfin_dflush_page) |
122 | P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); | |
ded963a4 | 123 | jump .Ldfr; |
51be24c3 | 124 | ENDPROC(_blackfin_dflush_page) |