1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * (c) 1997-1998 Grant R. Guenther <grant@torque.net> |
4 | * |
5 | * epia.c is a low-level protocol driver for Shuttle Technologies |
6 | * EPIA parallel to IDE adapter chip. This device is now obsolete |
7 | * and has been replaced with the EPAT chip, which is supported |
8 | * by epat.c, however, some devices based on EPIA are still |
9 | * available. |
10 | */ |
11 | |
12 | #include <linux/module.h> |
13 | #include <linux/init.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/types.h> |
17 | #include <linux/wait.h> |
18 | #include <asm/io.h> |
19 | #include "pata_parport.h" |
20 | |
21 | /* |
22 | * mode codes: 0 nybble reads on port 1, 8-bit writes |
23 | * 1 5/3 reads on ports 1 & 2, 8-bit writes |
24 | * 2 8-bit reads and writes |
25 | * 3 8-bit EPP mode |
26 | * 4 16-bit EPP |
27 | * 5 32-bit EPP |
28 | */ |
29 | |
30 | #define j44(a, b) (((a >> 4) & 0x0f) + (b & 0xf0)) |
31 | #define j53(a, b) (((a >> 3) & 0x1f) + ((b << 4) & 0xe0)) |
32 | |
33 | /* |
34 | * cont = 0 IDE register file |
35 | * cont = 1 IDE control registers |
36 | */ |
37 | static int cont_map[2] = { 0, 0x80 }; |
38 | |
39 | static int epia_read_regr(struct pi_adapter *pi, int cont, int regr) |
40 | { |
41 | int a, b, r; |
42 | |
43 | regr += cont_map[cont]; |
44 | |
45 | switch (pi->mode) { |
46 | case 0: |
47 | r = regr ^ 0x39; |
48 | w0(r); w2(1); w2(3); w0(r); |
49 | a = r1(); w2(1); b = r1(); w2(4); |
50 | return j44(a, b); |
51 | case 1: |
52 | r = regr ^ 0x31; |
53 | w0(r); w2(1); w0(r & 0x37); |
54 | w2(3); w2(5); w0(r | 0xf0); |
55 | a = r1(); b = r2(); w2(4); |
56 | return j53(a, b); |
57 | case 2: |
58 | r = regr^0x29; |
59 | w0(r); w2(1); w2(0X21); w2(0x23); |
60 | a = r0(); w2(4); |
61 | return a; |
62 | case 3: |
63 | case 4: |
64 | case 5: |
65 | w3(regr); w2(0x24); a = r4(); w2(4); |
66 | return a; |
67 | } |
68 | |
69 | return -1; |
70 | } |
71 | |
72 | static void epia_write_regr(struct pi_adapter *pi, int cont, int regr, int val) |
73 | { |
74 | int r; |
75 | |
76 | regr += cont_map[cont]; |
77 | |
78 | switch (pi->mode) { |
79 | case 0: |
80 | case 1: |
81 | case 2: |
82 | r = regr ^ 0x19; |
83 | w0(r); w2(1); w0(val); w2(3); w2(4); |
84 | break; |
85 | case 3: |
86 | case 4: |
87 | case 5: |
88 | r = regr ^ 0x40; |
89 | w3(r); w4(val); w2(4); |
90 | break; |
91 | } |
92 | } |
93 | |
94 | #define WR(r, v) epia_write_regr(pi, 0, r, v) |
95 | #define RR(r) epia_read_regr(pi, 0, r) |
96 | |
97 | /* |
98 | * The use of register 0x84 is entirely unclear - it seems to control |
99 | * some EPP counters ... currently we know about 3 different block |
100 | * sizes: the standard 512 byte reads and writes, 12 byte writes and |
101 | * 2048 byte reads (the last two being used in the CDrom drivers. |
102 | */ |
103 | static void epia_connect(struct pi_adapter *pi) |
104 | { |
105 | pi->saved_r0 = r0(); |
106 | pi->saved_r2 = r2(); |
107 | |
108 | w2(4); w0(0xa0); w0(0x50); w0(0xc0); w0(0x30); w0(0xa0); w0(0); |
109 | w2(1); w2(4); |
110 | if (pi->mode >= 3) { |
111 | w0(0xa); w2(1); w2(4); w0(0x82); w2(4); w2(0xc); w2(4); |
112 | w2(0x24); w2(0x26); w2(4); |
113 | } |
114 | WR(0x86, 8); |
115 | } |
116 | |
117 | static void epia_disconnect(struct pi_adapter *pi) |
118 | { |
119 | /* WR(0x84,0x10); */ |
120 | w0(pi->saved_r0); |
121 | w2(1); w2(4); |
122 | w0(pi->saved_r0); |
123 | w2(pi->saved_r2); |
124 | } |
125 | |
126 | static void epia_read_block(struct pi_adapter *pi, char *buf, int count) |
127 | |
128 | { |
129 | int k, ph, a, b; |
130 | |
131 | switch (pi->mode) { |
132 | case 0: |
133 | w0(0x81); w2(1); w2(3); w0(0xc1); |
134 | ph = 1; |
135 | for (k = 0; k < count; k++) { |
136 | w2(2+ph); a = r1(); |
137 | w2(4+ph); b = r1(); |
138 | buf[k] = j44(a, b); |
139 | ph = 1 - ph; |
140 | } |
141 | w0(0); w2(4); |
142 | break; |
143 | case 1: |
144 | w0(0x91); w2(1); w0(0x10); w2(3); |
145 | w0(0x51); w2(5); w0(0xd1); |
146 | ph = 1; |
147 | for (k = 0; k < count; k++) { |
148 | w2(4 + ph); |
149 | a = r1(); b = r2(); |
150 | buf[k] = j53(a, b); |
151 | ph = 1 - ph; |
152 | } |
153 | w0(0); w2(4); |
154 | break; |
155 | case 2: |
156 | w0(0x89); w2(1); w2(0x23); w2(0x21); |
157 | ph = 1; |
158 | for (k = 0; k < count; k++) { |
159 | w2(0x24 + ph); |
160 | buf[k] = r0(); |
161 | ph = 1 - ph; |
162 | } |
163 | w2(6); w2(4); |
164 | break; |
165 | case 3: |
166 | if (count > 512) |
167 | WR(0x84, 3); |
168 | w3(0); w2(0x24); |
169 | for (k = 0; k < count; k++) |
170 | buf[k] = r4(); |
171 | w2(4); WR(0x84, 0); |
172 | break; |
173 | case 4: |
174 | if (count > 512) |
175 | WR(0x84, 3); |
176 | w3(0); w2(0x24); |
177 | for (k = 0; k < count / 2; k++) |
178 | ((u16 *)buf)[k] = r4w(); |
179 | w2(4); WR(0x84, 0); |
180 | break; |
181 | case 5: |
182 | if (count > 512) |
183 | WR(0x84, 3); |
184 | w3(0); w2(0x24); |
185 | for (k = 0; k < count / 4; k++) |
186 | ((u32 *)buf)[k] = r4l(); |
187 | w2(4); WR(0x84, 0); |
188 | break; |
189 | } |
190 | } |
191 | |
192 | static void epia_write_block(struct pi_adapter *pi, char *buf, int count) |
193 | { |
194 | int ph, k, last, d; |
195 | |
196 | switch (pi->mode) { |
197 | case 0: |
198 | case 1: |
199 | case 2: |
200 | w0(0xa1); w2(1); w2(3); w2(1); w2(5); |
201 | ph = 0; last = 0x8000; |
202 | for (k = 0; k < count; k++) { |
203 | d = buf[k]; |
204 | if (d != last) { |
205 | last = d; |
206 | w0(d); |
207 | } |
208 | w2(4 + ph); |
209 | ph = 1 - ph; |
210 | } |
211 | w2(7); w2(4); |
212 | break; |
213 | case 3: |
214 | if (count < 512) |
215 | WR(0x84, 1); |
216 | w3(0x40); |
217 | for (k = 0; k < count; k++) |
218 | w4(buf[k]); |
219 | if (count < 512) |
220 | WR(0x84, 0); |
221 | break; |
222 | case 4: |
223 | if (count < 512) |
224 | WR(0x84, 1); |
225 | w3(0x40); |
226 | for (k = 0; k < count / 2; k++) |
227 | w4w(((u16 *)buf)[k]); |
228 | if (count < 512) |
229 | WR(0x84, 0); |
230 | break; |
231 | case 5: |
232 | if (count < 512) |
233 | WR(0x84, 1); |
234 | w3(0x40); |
235 | for (k = 0; k < count / 4; k++) |
236 | w4l(((u32 *)buf)[k]); |
237 | if (count < 512) |
238 | WR(0x84, 0); |
239 | break; |
240 | } |
241 | } |
242 | |
243 | static int epia_test_proto(struct pi_adapter *pi) |
244 | { |
245 | int j, k, f; |
246 | int e[2] = { 0, 0 }; |
247 | char scratch[512]; |
248 | |
249 | epia_connect(pi); |
250 | for (j = 0; j < 2; j++) { |
251 | WR(6, 0xa0 + j * 0x10); |
252 | for (k = 0; k < 256; k++) { |
253 | WR(2, k ^ 0xaa); |
254 | WR(3, k ^ 0x55); |
255 | if (RR(2) != (k ^ 0xaa)) |
256 | e[j]++; |
257 | } |
258 | WR(2, 1); WR(3, 1); |
259 | } |
260 | epia_disconnect(pi); |
261 | |
262 | f = 0; |
263 | epia_connect(pi); |
264 | WR(0x84, 8); |
265 | epia_read_block(pi, buf: scratch, count: 512); |
266 | for (k = 0; k < 256; k++) { |
267 | if ((scratch[2 * k] & 0xff) != ((k + 1) & 0xff)) |
268 | f++; |
269 | if ((scratch[2 * k + 1] & 0xff) != ((-2 - k) & 0xff)) |
270 | f++; |
271 | } |
272 | WR(0x84, 0); |
273 | epia_disconnect(pi); |
274 | |
275 | dev_dbg(&pi->dev, "epia: port 0x%x, mode %d, test=(%d,%d,%d)\n" , |
276 | pi->port, pi->mode, e[0], e[1], f); |
277 | |
278 | return (e[0] && e[1]) || f; |
279 | } |
280 | |
281 | |
282 | static void epia_log_adapter(struct pi_adapter *pi) |
283 | { |
284 | char *mode[6] = { "4-bit" , "5/3" , "8-bit" , "EPP-8" , "EPP-16" , "EPP-32" }; |
285 | |
286 | dev_info(&pi->dev, |
287 | "Shuttle EPIA at 0x%x, mode %d (%s), delay %d\n" , |
288 | pi->port, pi->mode, mode[pi->mode], pi->delay); |
289 | } |
290 | |
291 | static struct pi_protocol epia = { |
292 | .owner = THIS_MODULE, |
293 | .name = "epia" , |
294 | .max_mode = 6, |
295 | .epp_first = 3, |
296 | .default_delay = 1, |
297 | .max_units = 1, |
298 | .write_regr = epia_write_regr, |
299 | .read_regr = epia_read_regr, |
300 | .write_block = epia_write_block, |
301 | .read_block = epia_read_block, |
302 | .connect = epia_connect, |
303 | .disconnect = epia_disconnect, |
304 | .test_proto = epia_test_proto, |
305 | .log_adapter = epia_log_adapter, |
306 | }; |
307 | |
308 | MODULE_LICENSE("GPL" ); |
309 | MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>" ); |
310 | MODULE_DESCRIPTION("Shuttle Technologies EPIA parallel port IDE adapter " |
311 | "protocol driver" ); |
312 | module_pata_parport_driver(epia); |
313 | |