1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * (c) 1997-1998  Grant R. Guenther <grant@torque.net>
4 *
5 * This is the low level protocol driver for the EPAT parallel
6 * to IDE adapter from Shuttle Technologies.  This adapter is
7 * used in many popular parallel port disk products such as the
8 * SyQuest EZ drives, the Avatar Shark and the Imation SuperDisk.
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/delay.h>
14#include <linux/kernel.h>
15#include <linux/types.h>
16#include <linux/wait.h>
17#include <asm/io.h>
18#include "pata_parport.h"
19
20#define j44(a, b)	(((a >> 4) & 0x0f) + (b & 0xf0))
21#define j53(a, b)	(((a >> 3) & 0x1f) + ((b << 4) & 0xe0))
22
23static int epatc8;
24
25module_param(epatc8, int, 0);
26MODULE_PARM_DESC(epatc8,
27		 "support for the Shuttle EP1284 chip, "
28		 "used in any recent Imation SuperDisk (LS-120) drive.");
29
30/*
31 * cont =  0   IDE register file
32 * cont =  1   IDE control registers
33 * cont =  2   internal EPAT registers
34 */
35static int cont_map[3] = { 0x18, 0x10, 0 };
36
37static void epat_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
38{
39	int r = regr + cont_map[cont];
40
41	switch (pi->mode) {
42	case 0:
43	case 1:
44	case 2:
45		w0(0x60+r); w2(1); w0(val); w2(4);
46		break;
47	case 3:
48	case 4:
49	case 5:
50		w3(0x40+r); w4(val);
51		break;
52	}
53}
54
55static int epat_read_regr(struct pi_adapter *pi, int cont, int regr)
56{
57	int  a, b, r;
58
59	r = regr + cont_map[cont];
60
61	switch (pi->mode) {
62
63	case 0:
64		w0(r); w2(1); w2(3);
65		a = r1(); w2(4); b = r1();
66		return j44(a, b);
67	case 1:
68		w0(0x40+r); w2(1); w2(4);
69		a = r1(); b = r2(); w0(0xff);
70		return j53(a, b);
71	case 2:
72		w0(0x20+r); w2(1); w2(0x25);
73		a = r0(); w2(4);
74		return a;
75	case 3:
76	case 4:
77	case 5:
78		w3(r); w2(0x24); a = r4(); w2(4);
79		return a;
80	}
81
82	return -1;	/* never gets here */
83}
84
85static void epat_read_block(struct pi_adapter *pi, char *buf, int count)
86{
87	int  k, ph, a, b;
88
89	switch (pi->mode) {
90
91	case 0:
92		w0(7); w2(1); w2(3); w0(0xff);
93		ph = 0;
94		for (k = 0; k < count; k++) {
95			if (k == count-1)
96				w0(0xfd);
97			w2(6 + ph); a = r1();
98			if (a & 8) {
99				b = a;
100			} else {
101				w2(4+ph); b = r1();
102			}
103			buf[k] = j44(a, b);
104			ph =  1 - ph;
105		}
106		w0(0); w2(4);
107		break;
108
109	case 1:
110		w0(0x47); w2(1); w2(5); w0(0xff);
111		ph = 0;
112		for (k = 0; k < count; k++) {
113			if (k == count - 1)
114				w0(0xfd);
115			w2(4 + ph);
116			a = r1(); b = r2();
117			buf[k] = j53(a, b);
118			ph = 1 - ph;
119		}
120		w0(0); w2(4);
121		break;
122
123	case 2:
124		w0(0x27); w2(1); w2(0x25); w0(0);
125		ph = 0;
126		for (k = 0; k < count - 1; k++) {
127			w2(0x24 + ph);
128			buf[k] = r0();
129			ph = 1 - ph;
130		}
131		w2(0x26); w2(0x27);
132		buf[count - 1] = r0();
133		w2(0x25); w2(4);
134		break;
135
136	case 3:
137		w3(0x80); w2(0x24);
138		for (k = 0; k < count - 1; k++)
139			buf[k] = r4();
140		w2(4); w3(0xa0); w2(0x24);
141		buf[count - 1] = r4();
142		w2(4);
143		break;
144
145	case 4:
146		w3(0x80); w2(0x24);
147		for (k = 0; k < count / 2 - 1; k++)
148			((u16 *)buf)[k] = r4w();
149		buf[count - 2] = r4();
150		w2(4); w3(0xa0); w2(0x24);
151		buf[count - 1] = r4();
152		w2(4);
153		break;
154
155	case 5:
156		w3(0x80); w2(0x24);
157		for (k = 0; k < count / 4 - 1; k++)
158			((u32 *)buf)[k] = r4l();
159		for (k = count - 4; k < count - 1; k++)
160			buf[k] = r4();
161		w2(4); w3(0xa0); w2(0x24);
162		buf[count - 1] = r4();
163		w2(4);
164		break;
165	}
166}
167
168static void epat_write_block(struct pi_adapter *pi, char *buf, int count)
169{
170	int ph, k;
171
172	switch (pi->mode) {
173	case 0:
174	case 1:
175	case 2:
176		w0(0x67); w2(1); w2(5);
177		ph = 0;
178		for (k = 0; k < count; k++) {
179		  	w0(buf[k]);
180			w2(4 + ph);
181			ph = 1 - ph;
182		}
183		w2(7); w2(4);
184		break;
185	case 3:
186		w3(0xc0);
187		for (k = 0; k < count; k++)
188			w4(buf[k]);
189		w2(4);
190		break;
191	case 4:
192		w3(0xc0);
193		for (k = 0; k < count / 2; k++)
194			w4w(((u16 *)buf)[k]);
195		w2(4);
196		break;
197	case 5:
198		w3(0xc0);
199		for (k = 0; k < count / 4; k++)
200			w4l(((u32 *)buf)[k]);
201		w2(4);
202		break;
203	}
204}
205
206/* these macros access the EPAT registers in native addressing */
207
208#define	WR(r, v)	epat_write_regr(pi, 2, r, v)
209#define	RR(r)		epat_read_regr(pi, 2, r)
210
211/* and these access the IDE task file */
212
213#define WRi(r, v)	epat_write_regr(pi, 0, r, v)
214#define RRi(r)		epat_read_regr(pi, 0, r)
215
216/* FIXME:  the CPP stuff should be fixed to handle multiple EPATs on a chain */
217
218#define CPP(x)					\
219	do {					\
220		w2(4); w0(0x22); w0(0xaa);	\
221		w0(0x55); w0(0); w0(0xff);	\
222		w0(0x87); w0(0x78); w0(x);	\
223		w2(4); w2(5); w2(4); w0(0xff);	\
224	} while (0)
225
226static void epat_connect(struct pi_adapter *pi)
227{
228	pi->saved_r0 = r0();
229	pi->saved_r2 = r2();
230
231 	/* Initialize the chip */
232	CPP(0);
233
234	if (epatc8) {
235		CPP(0x40); CPP(0xe0);
236		w0(0); w2(1); w2(4);
237		WR(0x8, 0x12);
238		WR(0xc, 0x14);
239		WR(0x12, 0x10);
240		WR(0xe, 0xf);
241		WR(0xf, 4);
242		/* WR(0xe,0xa);WR(0xf,4); */
243		WR(0xe, 0xd);
244		WR(0xf, 0);
245		/* CPP(0x30); */
246	}
247
248        /* Connect to the chip */
249	CPP(0xe0);
250	w0(0); w2(1); w2(4); /* Idle into SPP */
251        if (pi->mode >= 3) {
252		w0(0); w2(1); w2(4); w2(0xc);
253		/* Request EPP */
254		w0(0x40); w2(6); w2(7); w2(4); w2(0xc); w2(4);
255        }
256
257	if (!epatc8) {
258		WR(8, 0x10);
259		WR(0xc, 0x14);
260		WR(0xa, 0x38);
261		WR(0x12, 0x10);
262	}
263}
264
265static void epat_disconnect(struct pi_adapter *pi)
266{
267	CPP(0x30);
268	w0(pi->saved_r0);
269	w2(pi->saved_r2);
270}
271
272static int epat_test_proto(struct pi_adapter *pi)
273{
274	int k, j, f, cc;
275	int e[2] = { 0, 0 };
276	char scratch[512];
277
278	epat_connect(pi);
279	cc = RR(0xd);
280	epat_disconnect(pi);
281
282	epat_connect(pi);
283	for (j=0;j<2;j++) {
284		WRi(6, 0xa0 + j * 0x10);
285		for (k = 0; k < 256; k++) {
286			WRi(2, k ^ 0xaa);
287			WRi(3, k ^ 0x55);
288			if (RRi(2) != (k ^ 0xaa))
289				e[j]++;
290		}
291	}
292	epat_disconnect(pi);
293
294	f = 0;
295	epat_connect(pi);
296	WR(0x13, 1); WR(0x13, 0); WR(0xa, 0x11);
297	epat_read_block(pi, scratch, 512);
298
299	for (k = 0; k < 256; k++) {
300		if ((scratch[2 * k] & 0xff) != k)
301			f++;
302		if ((scratch[2 * k + 1] & 0xff) != 0xff - k)
303			f++;
304	}
305	epat_disconnect(pi);
306
307	dev_dbg(&pi->dev,
308		"epat: port 0x%x, mode %d, ccr %x, test=(%d,%d,%d)\n",
309		pi->port, pi->mode, cc, e[0], e[1], f);
310
311	return (e[0] && e[1]) || f;
312}
313
314static void epat_log_adapter(struct pi_adapter *pi)
315{
316	int ver;
317	char *mode_string[6] =
318		{ "4-bit", "5/3", "8-bit", "EPP-8", "EPP-16", "EPP-32" };
319
320	epat_connect(pi);
321	WR(0xa, 0x38);		/* read the version code */
322	ver = RR(0xb);
323	epat_disconnect(pi);
324
325	dev_info(&pi->dev,
326		 "Shuttle EPAT chip %x at 0x%x, mode %d (%s), delay %d\n",
327		 ver, pi->port, pi->mode, mode_string[pi->mode], pi->delay);
328}
329
330static struct pi_protocol epat = {
331	.owner		= THIS_MODULE,
332	.name		= "epat",
333	.max_mode	= 6,
334	.epp_first	= 3,
335	.default_delay	= 1,
336	.max_units	= 1,
337	.write_regr	= epat_write_regr,
338	.read_regr	= epat_read_regr,
339	.write_block	= epat_write_block,
340	.read_block	= epat_read_block,
341	.connect	= epat_connect,
342	.disconnect	= epat_disconnect,
343	.test_proto	= epat_test_proto,
344	.log_adapter	= epat_log_adapter,
345};
346
347static int __init epat_init(void)
348{
349#ifdef CONFIG_PATA_PARPORT_EPATC8
350	epatc8 = 1;
351#endif
352	return pata_parport_register_driver(&epat);
353}
354
355static void __exit epat_exit(void)
356{
357	pata_parport_unregister_driver(&epat);
358}
359
360MODULE_LICENSE("GPL");
361MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
362MODULE_DESCRIPTION("Shuttle Technologies EPAT parallel port IDE adapter "
363		   "protocol driver");
364module_init(epat_init)
365module_exit(epat_exit)
366