]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/blackfin/lib/ins.S
1b84b21ca7d1f7f653c9532ba85523d14bee8923
[linux-2.6-omap-h63xx.git] / arch / blackfin / lib / ins.S
1 /*
2  * File:         arch/blackfin/lib/ins.S
3  * Based on:
4  * Author:       Bas Vermeulen <bas@buyways.nl>
5  *
6  * Created:      Tue Mar 22 15:27:24 CEST 2005
7  * Description:  Implementation of ins{bwl} for BlackFin processors using zero overhead loops.
8  *
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  */
30
31 #include <linux/linkage.h>
32 #include <asm/blackfin.h>
33
34 .align 2
35
36 /*
37  * 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
39  * external bus), and re-issued after the interrupt occurs.
40  *
41  * If a FIFO is sitting on the end of the read, it will see two reads,
42  * when the core only sees one. The FIFO receives the read which is cancelled,
43  * and not delivered to the core.
44  *
45  * To solve this, interrupts are turned off before reads occur to I/O space.
46  * There are 3 versions of all these functions
47  *  - turns interrupts off every read (higher overhead, but lower latency)
48  *  - turns interrupts off every loop (low overhead, but longer latency)
49  *  - DMA version, which do not suffer from this issue. DMA versions have
50  *      different name (prefixed by dma_ ), and are located in
51  *      ../kernel/bfin_dma_5xx.c
52  * Using the dma related functions are recommended for transfering large
53  * buffers in/out of FIFOs.
54  */
55
56 ENTRY(_insl)
57 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
58         P0 = R0;        /* P0 = port */
59 #ifdef CONFIG_IPIPE
60         [--sp] = rets
61         [--sp] = (P5:0);
62         sp += -12
63         call ___ipipe_stall_root_raw
64         sp += 12
65         (P5:0) = [sp++];
66 #else
67         cli R3;
68 #endif
69         P1 = R1;        /* P1 = address */
70         P2 = R2;        /* P2 = count */
71         SSYNC;
72         LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
73 .Llong_loop_s:  R0 = [P0];
74                 [P1++] = R0;
75                 NOP;
76 .Llong_loop_e:  NOP;
77 #ifdef CONFIG_IPIPE
78         sp += -12
79         call ___ipipe_unstall_root_raw
80         sp += 12
81         rets = [sp++]
82 #else
83         sti R3;
84 #endif
85         RTS;
86 #else
87         P0 = R0;        /* P0 = port */
88         P1 = R1;        /* P1 = address */
89         P2 = R2;        /* P2 = count */
90         SSYNC;
91         LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
92 .Llong_loop_s:
93 #ifdef CONFIG_IPIPE
94         [--sp] = rets
95         [--sp] = (P5:0);
96         sp += -12
97         call ___ipipe_stall_root_raw
98         sp += 12
99         (P5:0) = [sp++];
100 #else
101         CLI R3;
102 #endif
103         NOP; NOP; NOP;
104         R0 = [P0];
105         [P1++] = R0;
106 .Llong_loop_e:
107 #ifdef CONFIG_IPIPE
108         sp += -12
109         call ___ipipe_unstall_root_raw
110         sp += 12
111         rets = [sp++]
112 #else
113         STI R3;
114 #endif
115         RTS;
116 #endif
117 ENDPROC(_insl)
118
119 ENTRY(_insw)
120 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
121         P0 = R0;        /* P0 = port */
122 #ifdef CONFIG_IPIPE
123         [--sp] = rets
124         [--sp] = (P5:0);
125         sp += -12
126         call ___ipipe_stall_root_raw
127         sp += 12
128         (P5:0) = [sp++];
129 #else
130         cli R3;
131 #endif
132         P1 = R1;        /* P1 = address */
133         P2 = R2;        /* P2 = count */
134         SSYNC;
135         LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
136 .Lword_loop_s:  R0 = W[P0];
137                 W[P1++] = R0;
138                 NOP;
139 .Lword_loop_e:  NOP;
140 #ifdef CONFIG_IPIPE
141         sp += -12
142         call ___ipipe_unstall_root_raw
143         sp += 12
144         rets = [sp++]
145 #else
146         sti R3;
147 #endif
148         RTS;
149 #else
150         P0 = R0;        /* P0 = port */
151         P1 = R1;        /* P1 = address */
152         P2 = R2;        /* P2 = count */
153         SSYNC;
154         LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
155 .Lword_loop_s:
156 #ifdef CONFIG_IPIPE
157         [--sp] = rets
158         [--sp] = (P5:0);
159         sp += -12
160         call ___ipipe_stall_root_raw
161         sp += 12
162         (P5:0) = [sp++];
163 #else
164         CLI R3;
165 #endif
166         NOP; NOP; NOP;
167         R0 = W[P0];
168         W[P1++] = R0;
169 .Lword_loop_e:
170 #ifdef CONFIG_IPIPE
171         sp += -12
172         call ___ipipe_unstall_root_raw
173         sp += 12
174         rets = [sp++]
175 #else
176         STI R3;
177 #endif
178         RTS;
179
180 #endif
181 ENDPROC(_insw)
182
183 ENTRY(_insw_8)
184 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
185         P0 = R0;        /* P0 = port */
186 #ifdef CONFIG_IPIPE
187         [--sp] = rets
188         [--sp] = (P5:0);
189         sp += -12
190         call ___ipipe_stall_root_raw
191         sp += 12
192         (P5:0) = [sp++];
193 #else
194         cli R3;
195 #endif
196         P1 = R1;        /* P1 = address */
197         P2 = R2;        /* P2 = count */
198         SSYNC;
199         LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2;
200 .Lword8_loop_s:  R0 = W[P0];
201                 B[P1++] = R0;
202                 R0 = R0 >> 8;
203                 B[P1++] = R0;
204                 NOP;
205 .Lword8_loop_e: NOP;
206 #ifdef CONFIG_IPIPE
207         sp += -12
208         call ___ipipe_unstall_root_raw
209         sp += 12
210         rets = [sp++]
211 #else
212         sti R3;
213 #endif
214         RTS;
215 #else
216         P0 = R0;        /* P0 = port */
217         P1 = R1;        /* P1 = address */
218         P2 = R2;        /* P2 = count */
219         SSYNC;
220         LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2;
221 .Lword8_loop_s:
222 #ifdef CONFIG_IPIPE
223         [--sp] = rets
224         [--sp] = (P5:0);
225         sp += -12
226         call ___ipipe_stall_root_raw
227         sp += 12
228         (P5:0) = [sp++];
229 #else
230         CLI R3;
231 #endif
232         NOP; NOP; NOP;
233         R0 = W[P0];
234         B[P1++] = R0;
235         R0 = R0 >> 8;
236         B[P1++] = R0;
237         NOP;
238 .Lword8_loop_e:
239 #ifdef CONFIG_IPIPE
240         sp += -12
241         call ___ipipe_unstall_root_raw
242         sp += 12
243         rets = [sp++]
244 #else
245         STI R3;
246 #endif
247         RTS;
248 #endif
249 ENDPROC(_insw_8)
250
251 ENTRY(_insb)
252 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
253         P0 = R0;        /* P0 = port */
254 #ifdef CONFIG_IPIPE
255         [--sp] = rets
256         [--sp] = (P5:0);
257         sp += -12
258         call ___ipipe_stall_root_raw
259         sp += 12
260         (P5:0) = [sp++];
261 #else
262         cli R3;
263 #endif
264         P1 = R1;        /* P1 = address */
265         P2 = R2;        /* P2 = count */
266         SSYNC;
267         LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
268 .Lbyte_loop_s:  R0 = B[P0];
269                 B[P1++] = R0;
270                 NOP;
271 .Lbyte_loop_e:  NOP;
272 #ifdef CONFIG_IPIPE
273         sp += -12
274         call ___ipipe_unstall_root_raw
275         sp += 12
276         rets = [sp++]
277 #else
278         sti R3;
279 #endif
280         RTS;
281 #else
282         P0 = R0;        /* P0 = port */
283         P1 = R1;        /* P1 = address */
284         P2 = R2;        /* P2 = count */
285         SSYNC;
286         LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
287 .Lbyte_loop_s:
288 #ifdef CONFIG_IPIPE
289         [--sp] = rets
290         [--sp] = (P5:0);
291         sp += -12
292         call ___ipipe_stall_root_raw
293         sp += 12
294         (P5:0) = [sp++];
295 #else
296         CLI R3;
297 #endif
298         NOP; NOP; NOP;
299         R0 = B[P0];
300         B[P1++] = R0;
301 .Lbyte_loop_e:
302 #ifdef CONFIG_IPIPE
303         sp += -12
304         call ___ipipe_unstall_root_raw
305         sp += 12
306         rets = [sp++]
307 #else
308         STI R3;
309 #endif
310         RTS;
311 #endif
312 ENDPROC(_insb)
313
314 ENTRY(_insl_16)
315 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
316         P0 = R0;        /* P0 = port */
317 #ifdef CONFIG_IPIPE
318         [--sp] = rets
319         [--sp] = (P5:0);
320         sp += -12
321         call ___ipipe_stall_root_raw
322         sp += 12
323         (P5:0) = [sp++];
324 #else
325         cli R3;
326 #endif
327         P1 = R1;        /* P1 = address */
328         P2 = R2;        /* P2 = count */
329         SSYNC;
330         LSETUP( .Llong16_loop_s, .Llong16_loop_e) LC0 = P2;
331 .Llong16_loop_s:  R0 = [P0];
332                   W[P1++] = R0;
333                   R0 = R0 >> 16;
334                   W[P1++] = R0;
335                   NOP;
336 .Llong16_loop_e:  NOP;
337 #ifdef CONFIG_IPIPE
338         sp += -12
339         call ___ipipe_unstall_root_raw
340         sp += 12
341         rets = [sp++]
342 #else
343         sti R3;
344 #endif
345         RTS;
346 #else
347         P0 = R0;        /* P0 = port */
348         P1 = R1;        /* P1 = address */
349         P2 = R2;        /* P2 = count */
350         SSYNC;
351         LSETUP( .Llong16_loop_s, .Llong16_loop_e) LC0 = P2;
352 .Llong16_loop_s:
353 #ifdef CONFIG_IPIPE
354         [--sp] = rets
355         [--sp] = (P5:0);
356         sp += -12
357         call ___ipipe_stall_root_raw
358         sp += 12
359         (P5:0) = [sp++];
360 #else
361         CLI R3;
362 #endif
363         NOP; NOP; NOP;
364         R0 = [P0];
365         W[P1++] = R0;
366         R0 = R0 >> 16;
367         W[P1++] = R0;
368 .Llong16_loop_e:
369 #ifdef CONFIG_IPIPE
370         sp += -12
371         call ___ipipe_unstall_root_raw
372         sp += 12
373         rets = [sp++]
374 #else
375         STI R3;
376 #endif
377         RTS;
378 #endif
379 ENDPROC(_insl_16)