diff options
Diffstat (limited to 'arch/blackfin/lib/ins.S')
-rw-r--r-- | arch/blackfin/lib/ins.S | 272 |
1 files changed, 84 insertions, 188 deletions
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S index d60554dce87..1863a6ba507 100644 --- a/arch/blackfin/lib/ins.S +++ b/arch/blackfin/lib/ins.S | |||
@@ -1,31 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * File: arch/blackfin/lib/ins.S | 2 | * arch/blackfin/lib/ins.S - ins{bwl} using hardware loops |
3 | * Based on: | ||
4 | * Author: Bas Vermeulen <bas@buyways.nl> | ||
5 | * | 3 | * |
6 | * Created: Tue Mar 22 15:27:24 CEST 2005 | 4 | * Copyright 2004-2008 Analog Devices Inc. |
7 | * Description: Implementation of ins{bwl} for BlackFin processors using zero overhead loops. | 5 | * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl> |
8 | * | 6 | * Licensed under the GPL-2 or later. |
9 | * Modified: | ||
10 | * Copyright 2004-2008 Analog Devices Inc. | ||
11 | * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl> | ||
12 | * | ||
13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, see the file COPYING, or write | ||
27 | * to the Free Software Foundation, Inc., | ||
28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
29 | */ | 7 | */ |
30 | 8 | ||
31 | #include <linux/linkage.h> | 9 | #include <linux/linkage.h> |
@@ -33,6 +11,46 @@ | |||
33 | 11 | ||
34 | .align 2 | 12 | .align 2 |
35 | 13 | ||
14 | #ifdef CONFIG_IPIPE | ||
15 | # define DO_CLI \ | ||
16 | [--sp] = rets; \ | ||
17 | [--sp] = (P5:0); \ | ||
18 | sp += -12; \ | ||
19 | call ___ipipe_stall_root_raw; \ | ||
20 | sp += 12; \ | ||
21 | (P5:0) = [sp++]; | ||
22 | # define CLI_INNER_NOP | ||
23 | #else | ||
24 | # define DO_CLI cli R3; | ||
25 | # define CLI_INNER_NOP nop; nop; nop; | ||
26 | #endif | ||
27 | |||
28 | #ifdef CONFIG_IPIPE | ||
29 | # define DO_STI \ | ||
30 | sp += -12; \ | ||
31 | call ___ipipe_unstall_root_raw; \ | ||
32 | sp += 12; \ | ||
33 | 2: rets = [sp++]; | ||
34 | #else | ||
35 | # define DO_STI 2: sti R3; | ||
36 | #endif | ||
37 | |||
38 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
39 | # define CLI_OUTER DO_CLI; | ||
40 | # define STI_OUTER DO_STI; | ||
41 | # define CLI_INNER 1: | ||
42 | # if ANOMALY_05000416 | ||
43 | # define STI_INNER nop; 2: nop; | ||
44 | # else | ||
45 | # define STI_INNER 2: | ||
46 | # endif | ||
47 | #else | ||
48 | # define CLI_OUTER | ||
49 | # define STI_OUTER | ||
50 | # define CLI_INNER 1: DO_CLI; CLI_INNER_NOP; | ||
51 | # define STI_INNER DO_STI; | ||
52 | #endif | ||
53 | |||
36 | /* | 54 | /* |
37 | * Reads on the Blackfin are speculative. In Blackfin terms, this means they | 55 | * Reads on the Blackfin are speculative. In Blackfin terms, this means they |
38 | * can be interrupted at any time (even after they have been issued on to the | 56 | * can be interrupted at any time (even after they have been issued on to the |
@@ -53,170 +71,48 @@ | |||
53 | * buffers in/out of FIFOs. | 71 | * buffers in/out of FIFOs. |
54 | */ | 72 | */ |
55 | 73 | ||
56 | ENTRY(_insl) | 74 | #define COMMON_INS(func, ops) \ |
57 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | 75 | ENTRY(_ins##func) \ |
58 | P0 = R0; /* P0 = port */ | 76 | P0 = R0; /* P0 = port */ \ |
59 | cli R3; | 77 | CLI_OUTER; /* 3 instructions before first read access */ \ |
60 | P1 = R1; /* P1 = address */ | 78 | P1 = R1; /* P1 = address */ \ |
61 | P2 = R2; /* P2 = count */ | 79 | P2 = R2; /* P2 = count */ \ |
62 | SSYNC; | 80 | SSYNC; \ |
63 | LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2; | 81 | \ |
64 | .Llong_loop_s: R0 = [P0]; | 82 | LSETUP(1f, 2f) LC0 = P2; \ |
65 | [P1++] = R0; | 83 | CLI_INNER; \ |
66 | NOP; | 84 | ops; \ |
67 | .Llong_loop_e: NOP; | 85 | STI_INNER; \ |
68 | sti R3; | 86 | \ |
69 | RTS; | 87 | STI_OUTER; \ |
70 | #else | 88 | RTS; \ |
71 | P0 = R0; /* P0 = port */ | 89 | ENDPROC(_ins##func) |
72 | P1 = R1; /* P1 = address */ | ||
73 | P2 = R2; /* P2 = count */ | ||
74 | SSYNC; | ||
75 | LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2; | ||
76 | .Llong_loop_s: | ||
77 | CLI R3; | ||
78 | NOP; NOP; NOP; | ||
79 | R0 = [P0]; | ||
80 | [P1++] = R0; | ||
81 | .Llong_loop_e: | ||
82 | STI R3; | ||
83 | 90 | ||
84 | RTS; | 91 | COMMON_INS(l, \ |
85 | #endif | 92 | R0 = [P0]; \ |
86 | ENDPROC(_insl) | 93 | [P1++] = R0; \ |
87 | 94 | ) | |
88 | ENTRY(_insw) | ||
89 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
90 | P0 = R0; /* P0 = port */ | ||
91 | cli R3; | ||
92 | P1 = R1; /* P1 = address */ | ||
93 | P2 = R2; /* P2 = count */ | ||
94 | SSYNC; | ||
95 | LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2; | ||
96 | .Lword_loop_s: R0 = W[P0]; | ||
97 | W[P1++] = R0; | ||
98 | NOP; | ||
99 | .Lword_loop_e: NOP; | ||
100 | sti R3; | ||
101 | RTS; | ||
102 | #else | ||
103 | P0 = R0; /* P0 = port */ | ||
104 | P1 = R1; /* P1 = address */ | ||
105 | P2 = R2; /* P2 = count */ | ||
106 | SSYNC; | ||
107 | LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2; | ||
108 | .Lword_loop_s: | ||
109 | CLI R3; | ||
110 | NOP; NOP; NOP; | ||
111 | R0 = W[P0]; | ||
112 | W[P1++] = R0; | ||
113 | .Lword_loop_e: | ||
114 | STI R3; | ||
115 | RTS; | ||
116 | |||
117 | #endif | ||
118 | ENDPROC(_insw) | ||
119 | |||
120 | ENTRY(_insw_8) | ||
121 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
122 | P0 = R0; /* P0 = port */ | ||
123 | cli R3; | ||
124 | P1 = R1; /* P1 = address */ | ||
125 | P2 = R2; /* P2 = count */ | ||
126 | SSYNC; | ||
127 | LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2; | ||
128 | .Lword8_loop_s: R0 = W[P0]; | ||
129 | B[P1++] = R0; | ||
130 | R0 = R0 >> 8; | ||
131 | B[P1++] = R0; | ||
132 | NOP; | ||
133 | .Lword8_loop_e: NOP; | ||
134 | sti R3; | ||
135 | RTS; | ||
136 | #else | ||
137 | P0 = R0; /* P0 = port */ | ||
138 | P1 = R1; /* P1 = address */ | ||
139 | P2 = R2; /* P2 = count */ | ||
140 | SSYNC; | ||
141 | LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2; | ||
142 | .Lword8_loop_s: | ||
143 | CLI R3; | ||
144 | NOP; NOP; NOP; | ||
145 | R0 = W[P0]; | ||
146 | B[P1++] = R0; | ||
147 | R0 = R0 >> 8; | ||
148 | B[P1++] = R0; | ||
149 | NOP; | ||
150 | .Lword8_loop_e: | ||
151 | STI R3; | ||
152 | 95 | ||
153 | RTS; | 96 | COMMON_INS(w, \ |
154 | #endif | 97 | R0 = W[P0]; \ |
155 | ENDPROC(_insw_8) | 98 | W[P1++] = R0; \ |
99 | ) | ||
156 | 100 | ||
157 | ENTRY(_insb) | 101 | COMMON_INS(w_8, \ |
158 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | 102 | R0 = W[P0]; \ |
159 | P0 = R0; /* P0 = port */ | 103 | B[P1++] = R0; \ |
160 | cli R3; | 104 | R0 = R0 >> 8; \ |
161 | P1 = R1; /* P1 = address */ | 105 | B[P1++] = R0; \ |
162 | P2 = R2; /* P2 = count */ | 106 | ) |
163 | SSYNC; | ||
164 | LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2; | ||
165 | .Lbyte_loop_s: R0 = B[P0]; | ||
166 | B[P1++] = R0; | ||
167 | NOP; | ||
168 | .Lbyte_loop_e: NOP; | ||
169 | sti R3; | ||
170 | RTS; | ||
171 | #else | ||
172 | P0 = R0; /* P0 = port */ | ||
173 | P1 = R1; /* P1 = address */ | ||
174 | P2 = R2; /* P2 = count */ | ||
175 | SSYNC; | ||
176 | LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2; | ||
177 | .Lbyte_loop_s: | ||
178 | CLI R3; | ||
179 | NOP; NOP; NOP; | ||
180 | R0 = B[P0]; | ||
181 | B[P1++] = R0; | ||
182 | .Lbyte_loop_e: | ||
183 | STI R3; | ||
184 | 107 | ||
185 | RTS; | 108 | COMMON_INS(b, \ |
186 | #endif | 109 | R0 = B[P0]; \ |
187 | ENDPROC(_insb) | 110 | B[P1++] = R0; \ |
111 | ) | ||
188 | 112 | ||
189 | ENTRY(_insl_16) | 113 | COMMON_INS(l_16, \ |
190 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | 114 | R0 = [P0]; \ |
191 | P0 = R0; /* P0 = port */ | 115 | W[P1++] = R0; \ |
192 | cli R3; | 116 | R0 = R0 >> 16; \ |
193 | P1 = R1; /* P1 = address */ | 117 | W[P1++] = R0; \ |
194 | P2 = R2; /* P2 = count */ | 118 | ) |
195 | SSYNC; | ||
196 | LSETUP( .Llong16_loop_s, .Llong16_loop_e) LC0 = P2; | ||
197 | .Llong16_loop_s: R0 = [P0]; | ||
198 | W[P1++] = R0; | ||
199 | R0 = R0 >> 16; | ||
200 | W[P1++] = R0; | ||
201 | NOP; | ||
202 | .Llong16_loop_e: NOP; | ||
203 | sti R3; | ||
204 | RTS; | ||
205 | #else | ||
206 | P0 = R0; /* P0 = port */ | ||
207 | P1 = R1; /* P1 = address */ | ||
208 | P2 = R2; /* P2 = count */ | ||
209 | SSYNC; | ||
210 | LSETUP( .Llong16_loop_s, .Llong16_loop_e) LC0 = P2; | ||
211 | .Llong16_loop_s: | ||
212 | CLI R3; | ||
213 | NOP; NOP; NOP; | ||
214 | R0 = [P0]; | ||
215 | W[P1++] = R0; | ||
216 | R0 = R0 >> 16; | ||
217 | W[P1++] = R0; | ||
218 | .Llong16_loop_e: | ||
219 | STI R3; | ||
220 | RTS; | ||
221 | #endif | ||
222 | ENDPROC(_insl_16) | ||