Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6] / 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         cli R3;
60         P1 = R1;        /* P1 = address */
61         P2 = R2;        /* P2 = count */
62         SSYNC;
63         LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
64 .Llong_loop_s:  R0 = [P0];
65                 [P1++] = R0;
66                 NOP;
67 .Llong_loop_e:  NOP;
68         sti R3;
69         RTS;
70 #else
71         P0 = R0;        /* P0 = port */
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
84         RTS;
85 #endif
86 ENDPROC(_insl)
87
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
153         RTS;
154 #endif
155 ENDPROC(_insw_8)
156
157 ENTRY(_insb)
158 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
159         P0 = R0;        /* P0 = port */
160         cli R3;
161         P1 = R1;        /* P1 = address */
162         P2 = R2;        /* P2 = count */
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
185         RTS;
186 #endif
187 ENDPROC(_insb)
188
189 ENTRY(_insl_16)
190 #ifdef CONFIG_BFIN_INS_LOWOVERHEAD
191         P0 = R0;        /* P0 = port */
192         cli R3;
193         P1 = R1;        /* P1 = address */
194         P2 = R2;        /* P2 = count */
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)