xref: /openbmc/linux/drivers/ata/pata_parport/epat.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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  
23  static int epatc8;
24  
25  module_param(epatc8, int, 0);
26  MODULE_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   */
35  static int cont_map[3] = { 0x18, 0x10, 0 };
36  
epat_write_regr(struct pi_adapter * pi,int cont,int regr,int val)37  static 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  
epat_read_regr(struct pi_adapter * pi,int cont,int regr)55  static 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  
epat_read_block(struct pi_adapter * pi,char * buf,int count)85  static 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  
epat_write_block(struct pi_adapter * pi,char * buf,int count)168  static 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  
epat_connect(struct pi_adapter * pi)226  static 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  
epat_disconnect(struct pi_adapter * pi)265  static void epat_disconnect(struct pi_adapter *pi)
266  {
267  	CPP(0x30);
268  	w0(pi->saved_r0);
269  	w2(pi->saved_r2);
270  }
271  
epat_test_proto(struct pi_adapter * pi)272  static 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  
epat_log_adapter(struct pi_adapter * pi)314  static 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  
330  static 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  
epat_init(void)347  static 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  
epat_exit(void)355  static void __exit epat_exit(void)
356  {
357  	pata_parport_unregister_driver(&epat);
358  }
359  
360  MODULE_LICENSE("GPL");
361  MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>");
362  MODULE_DESCRIPTION("Shuttle Technologies EPAT parallel port IDE adapter "
363  		   "protocol driver");
364  module_init(epat_init)
365  module_exit(epat_exit)
366