diff options
Diffstat (limited to 'arch/blackfin/lib')
-rw-r--r-- | arch/blackfin/lib/ins.S | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S index eba2343b1b59..d60554dce87b 100644 --- a/arch/blackfin/lib/ins.S +++ b/arch/blackfin/lib/ins.S | |||
@@ -33,7 +33,28 @@ | |||
33 | 33 | ||
34 | .align 2 | 34 | .align 2 |
35 | 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 | |||
36 | ENTRY(_insl) | 56 | ENTRY(_insl) |
57 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
37 | P0 = R0; /* P0 = port */ | 58 | P0 = R0; /* P0 = port */ |
38 | cli R3; | 59 | cli R3; |
39 | P1 = R1; /* P1 = address */ | 60 | P1 = R1; /* P1 = address */ |
@@ -46,9 +67,26 @@ ENTRY(_insl) | |||
46 | .Llong_loop_e: NOP; | 67 | .Llong_loop_e: NOP; |
47 | sti R3; | 68 | sti R3; |
48 | RTS; | 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 | ||
49 | ENDPROC(_insl) | 86 | ENDPROC(_insl) |
50 | 87 | ||
51 | ENTRY(_insw) | 88 | ENTRY(_insw) |
89 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
52 | P0 = R0; /* P0 = port */ | 90 | P0 = R0; /* P0 = port */ |
53 | cli R3; | 91 | cli R3; |
54 | P1 = R1; /* P1 = address */ | 92 | P1 = R1; /* P1 = address */ |
@@ -61,9 +99,26 @@ ENTRY(_insw) | |||
61 | .Lword_loop_e: NOP; | 99 | .Lword_loop_e: NOP; |
62 | sti R3; | 100 | sti R3; |
63 | RTS; | 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 | ||
64 | ENDPROC(_insw) | 118 | ENDPROC(_insw) |
65 | 119 | ||
66 | ENTRY(_insw_8) | 120 | ENTRY(_insw_8) |
121 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
67 | P0 = R0; /* P0 = port */ | 122 | P0 = R0; /* P0 = port */ |
68 | cli R3; | 123 | cli R3; |
69 | P1 = R1; /* P1 = address */ | 124 | P1 = R1; /* P1 = address */ |
@@ -78,9 +133,29 @@ ENTRY(_insw_8) | |||
78 | .Lword8_loop_e: NOP; | 133 | .Lword8_loop_e: NOP; |
79 | sti R3; | 134 | sti R3; |
80 | RTS; | 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 | ||
81 | ENDPROC(_insw_8) | 155 | ENDPROC(_insw_8) |
82 | 156 | ||
83 | ENTRY(_insb) | 157 | ENTRY(_insb) |
158 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
84 | P0 = R0; /* P0 = port */ | 159 | P0 = R0; /* P0 = port */ |
85 | cli R3; | 160 | cli R3; |
86 | P1 = R1; /* P1 = address */ | 161 | P1 = R1; /* P1 = address */ |
@@ -93,9 +168,26 @@ ENTRY(_insb) | |||
93 | .Lbyte_loop_e: NOP; | 168 | .Lbyte_loop_e: NOP; |
94 | sti R3; | 169 | sti R3; |
95 | RTS; | 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 | ||
96 | ENDPROC(_insb) | 187 | ENDPROC(_insb) |
97 | 188 | ||
98 | ENTRY(_insl_16) | 189 | ENTRY(_insl_16) |
190 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | ||
99 | P0 = R0; /* P0 = port */ | 191 | P0 = R0; /* P0 = port */ |
100 | cli R3; | 192 | cli R3; |
101 | P1 = R1; /* P1 = address */ | 193 | P1 = R1; /* P1 = address */ |
@@ -110,4 +202,21 @@ ENTRY(_insl_16) | |||
110 | .Llong16_loop_e: NOP; | 202 | .Llong16_loop_e: NOP; |
111 | sti R3; | 203 | sti R3; |
112 | RTS; | 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 | ||
113 | ENDPROC(_insl_16) | 222 | ENDPROC(_insl_16) |