xref: /openbmc/linux/drivers/ata/pata_parport/frpw.c (revision 5f1145d8)
172f2b0b2SOndrej Zary /*
272f2b0b2SOndrej Zary 	frpw.c	(c) 1996-8  Grant R. Guenther <grant@torque.net>
372f2b0b2SOndrej Zary 		            Under the terms of the GNU General Public License
472f2b0b2SOndrej Zary 
572f2b0b2SOndrej Zary 	frpw.c is a low-level protocol driver for the Freecom "Power"
672f2b0b2SOndrej Zary 	parallel port IDE adapter.
772f2b0b2SOndrej Zary 
872f2b0b2SOndrej Zary 	Some applications of this adapter may require a "printer" reset
972f2b0b2SOndrej Zary 	prior to loading the driver.  This can be done by loading and
1072f2b0b2SOndrej Zary 	unloading the "lp" driver, or it can be done by this driver
1172f2b0b2SOndrej Zary 	if you define FRPW_HARD_RESET.  The latter is not recommended
1272f2b0b2SOndrej Zary 	as it may upset devices on other ports.
1372f2b0b2SOndrej Zary 
1472f2b0b2SOndrej Zary */
1572f2b0b2SOndrej Zary 
1672f2b0b2SOndrej Zary /* Changes:
1772f2b0b2SOndrej Zary 
1872f2b0b2SOndrej Zary         1.01    GRG 1998.05.06 init_proto, release_proto
1972f2b0b2SOndrej Zary 			       fix chip detect
2072f2b0b2SOndrej Zary 			       added EPP-16 and EPP-32
2172f2b0b2SOndrej Zary 	1.02    GRG 1998.09.23 added hard reset to initialisation process
2272f2b0b2SOndrej Zary 	1.03    GRG 1998.12.14 made hard reset conditional
2372f2b0b2SOndrej Zary 
2472f2b0b2SOndrej Zary */
2572f2b0b2SOndrej Zary 
2672f2b0b2SOndrej Zary #define	FRPW_VERSION	"1.03"
2772f2b0b2SOndrej Zary 
2872f2b0b2SOndrej Zary #include <linux/module.h>
2972f2b0b2SOndrej Zary #include <linux/init.h>
3072f2b0b2SOndrej Zary #include <linux/delay.h>
3172f2b0b2SOndrej Zary #include <linux/kernel.h>
3272f2b0b2SOndrej Zary #include <linux/types.h>
3372f2b0b2SOndrej Zary #include <linux/wait.h>
3472f2b0b2SOndrej Zary #include <asm/io.h>
3572f2b0b2SOndrej Zary 
3672f2b0b2SOndrej Zary #include <linux/pata_parport.h>
3772f2b0b2SOndrej Zary 
3872f2b0b2SOndrej Zary #define cec4		w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4);
3972f2b0b2SOndrej Zary #define j44(l,h)	(((l>>4)&0x0f)|(h&0xf0))
4072f2b0b2SOndrej Zary 
4172f2b0b2SOndrej Zary /* cont = 0 - access the IDE register file
4272f2b0b2SOndrej Zary    cont = 1 - access the IDE command set
4372f2b0b2SOndrej Zary */
4472f2b0b2SOndrej Zary 
4572f2b0b2SOndrej Zary static int  cont_map[2] = { 0x08, 0x10 };
4672f2b0b2SOndrej Zary 
47882ff0caSOndrej Zary static int frpw_read_regr(struct pi_adapter *pi, int cont, int regr)
4872f2b0b2SOndrej Zary 
4972f2b0b2SOndrej Zary {	int	h,l,r;
5072f2b0b2SOndrej Zary 
5172f2b0b2SOndrej Zary 	r = regr + cont_map[cont];
5272f2b0b2SOndrej Zary 
5372f2b0b2SOndrej Zary 	w2(4);
5472f2b0b2SOndrej Zary 	w0(r); cec4;
5572f2b0b2SOndrej Zary 	w2(6); l = r1();
5672f2b0b2SOndrej Zary 	w2(4); h = r1();
5772f2b0b2SOndrej Zary 	w2(4);
5872f2b0b2SOndrej Zary 
5972f2b0b2SOndrej Zary 	return j44(l,h);
6072f2b0b2SOndrej Zary 
6172f2b0b2SOndrej Zary }
6272f2b0b2SOndrej Zary 
63882ff0caSOndrej Zary static void frpw_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
6472f2b0b2SOndrej Zary 
6572f2b0b2SOndrej Zary {	int r;
6672f2b0b2SOndrej Zary 
6772f2b0b2SOndrej Zary         r = regr + cont_map[cont];
6872f2b0b2SOndrej Zary 
6972f2b0b2SOndrej Zary 	w2(4); w0(r); cec4;
7072f2b0b2SOndrej Zary 	w0(val);
7172f2b0b2SOndrej Zary 	w2(5);w2(7);w2(5);w2(4);
7272f2b0b2SOndrej Zary }
7372f2b0b2SOndrej Zary 
74882ff0caSOndrej Zary static void frpw_read_block_int(struct pi_adapter *pi, char *buf, int count, int regr)
7572f2b0b2SOndrej Zary 
7672f2b0b2SOndrej Zary {       int     h, l, k, ph;
7772f2b0b2SOndrej Zary 
7872f2b0b2SOndrej Zary         switch(pi->mode) {
7972f2b0b2SOndrej Zary 
8072f2b0b2SOndrej Zary         case 0: w2(4); w0(regr); cec4;
8172f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
8272f2b0b2SOndrej Zary                         w2(6); l = r1();
8372f2b0b2SOndrej Zary                         w2(4); h = r1();
8472f2b0b2SOndrej Zary                         buf[k] = j44(l,h);
8572f2b0b2SOndrej Zary                 }
8672f2b0b2SOndrej Zary                 w2(4);
8772f2b0b2SOndrej Zary                 break;
8872f2b0b2SOndrej Zary 
8972f2b0b2SOndrej Zary         case 1: ph = 2;
9072f2b0b2SOndrej Zary                 w2(4); w0(regr + 0xc0); cec4;
9172f2b0b2SOndrej Zary                 w0(0xff);
9272f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
9372f2b0b2SOndrej Zary                         w2(0xa4 + ph);
9472f2b0b2SOndrej Zary                         buf[k] = r0();
9572f2b0b2SOndrej Zary                         ph = 2 - ph;
9672f2b0b2SOndrej Zary                 }
9772f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4); w2(4);
9872f2b0b2SOndrej Zary                 break;
9972f2b0b2SOndrej Zary 
10072f2b0b2SOndrej Zary         case 2: w2(4); w0(regr + 0x80); cec4;
10172f2b0b2SOndrej Zary                 for (k=0;k<count;k++) buf[k] = r4();
10272f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4);
10372f2b0b2SOndrej Zary                 w2(4);
10472f2b0b2SOndrej Zary                 break;
10572f2b0b2SOndrej Zary 
10672f2b0b2SOndrej Zary 	case 3: w2(4); w0(regr + 0x80); cec4;
10772f2b0b2SOndrej Zary 		for (k=0;k<count-2;k++) buf[k] = r4();
10872f2b0b2SOndrej Zary 		w2(0xac); w2(0xa4);
10972f2b0b2SOndrej Zary 		buf[count-2] = r4();
11072f2b0b2SOndrej Zary 		buf[count-1] = r4();
11172f2b0b2SOndrej Zary 		w2(4);
11272f2b0b2SOndrej Zary 		break;
11372f2b0b2SOndrej Zary 
11472f2b0b2SOndrej Zary 	case 4: w2(4); w0(regr + 0x80); cec4;
11572f2b0b2SOndrej Zary                 for (k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
11672f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4);
11772f2b0b2SOndrej Zary                 buf[count-2] = r4();
11872f2b0b2SOndrej Zary                 buf[count-1] = r4();
11972f2b0b2SOndrej Zary                 w2(4);
12072f2b0b2SOndrej Zary                 break;
12172f2b0b2SOndrej Zary 
12272f2b0b2SOndrej Zary 	case 5: w2(4); w0(regr + 0x80); cec4;
12372f2b0b2SOndrej Zary                 for (k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
12472f2b0b2SOndrej Zary                 buf[count-4] = r4();
12572f2b0b2SOndrej Zary                 buf[count-3] = r4();
12672f2b0b2SOndrej Zary                 w2(0xac); w2(0xa4);
12772f2b0b2SOndrej Zary                 buf[count-2] = r4();
12872f2b0b2SOndrej Zary                 buf[count-1] = r4();
12972f2b0b2SOndrej Zary                 w2(4);
13072f2b0b2SOndrej Zary                 break;
13172f2b0b2SOndrej Zary 
13272f2b0b2SOndrej Zary         }
13372f2b0b2SOndrej Zary }
13472f2b0b2SOndrej Zary 
135882ff0caSOndrej Zary static void frpw_read_block(struct pi_adapter *pi, char *buf, int count)
13672f2b0b2SOndrej Zary 
13772f2b0b2SOndrej Zary {	frpw_read_block_int(pi,buf,count,0x08);
13872f2b0b2SOndrej Zary }
13972f2b0b2SOndrej Zary 
140882ff0caSOndrej Zary static void frpw_write_block(struct pi_adapter *pi, char *buf, int count)
14172f2b0b2SOndrej Zary 
14272f2b0b2SOndrej Zary {	int	k;
14372f2b0b2SOndrej Zary 
14472f2b0b2SOndrej Zary 	switch(pi->mode) {
14572f2b0b2SOndrej Zary 
14672f2b0b2SOndrej Zary 	case 0:
14772f2b0b2SOndrej Zary 	case 1:
14872f2b0b2SOndrej Zary 	case 2: w2(4); w0(8); cec4; w2(5);
14972f2b0b2SOndrej Zary         	for (k=0;k<count;k++) {
15072f2b0b2SOndrej Zary 			w0(buf[k]);
15172f2b0b2SOndrej Zary 			w2(7);w2(5);
15272f2b0b2SOndrej Zary 		}
15372f2b0b2SOndrej Zary 		w2(4);
15472f2b0b2SOndrej Zary 		break;
15572f2b0b2SOndrej Zary 
15672f2b0b2SOndrej Zary 	case 3: w2(4); w0(0xc8); cec4; w2(5);
15772f2b0b2SOndrej Zary 		for (k=0;k<count;k++) w4(buf[k]);
15872f2b0b2SOndrej Zary 		w2(4);
15972f2b0b2SOndrej Zary 		break;
16072f2b0b2SOndrej Zary 
16172f2b0b2SOndrej Zary         case 4: w2(4); w0(0xc8); cec4; w2(5);
16272f2b0b2SOndrej Zary                 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
16372f2b0b2SOndrej Zary                 w2(4);
16472f2b0b2SOndrej Zary                 break;
16572f2b0b2SOndrej Zary 
16672f2b0b2SOndrej Zary         case 5: w2(4); w0(0xc8); cec4; w2(5);
16772f2b0b2SOndrej Zary                 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
16872f2b0b2SOndrej Zary                 w2(4);
16972f2b0b2SOndrej Zary                 break;
17072f2b0b2SOndrej Zary 	}
17172f2b0b2SOndrej Zary }
17272f2b0b2SOndrej Zary 
173882ff0caSOndrej Zary static void frpw_connect(struct pi_adapter *pi)
17472f2b0b2SOndrej Zary 
17572f2b0b2SOndrej Zary {       pi->saved_r0 = r0();
17672f2b0b2SOndrej Zary         pi->saved_r2 = r2();
17772f2b0b2SOndrej Zary 	w2(4);
17872f2b0b2SOndrej Zary }
17972f2b0b2SOndrej Zary 
180882ff0caSOndrej Zary static void frpw_disconnect(struct pi_adapter *pi)
18172f2b0b2SOndrej Zary 
18272f2b0b2SOndrej Zary {       w2(4); w0(0x20); cec4;
18372f2b0b2SOndrej Zary 	w0(pi->saved_r0);
18472f2b0b2SOndrej Zary         w2(pi->saved_r2);
18572f2b0b2SOndrej Zary }
18672f2b0b2SOndrej Zary 
18772f2b0b2SOndrej Zary /* Stub logic to see if PNP string is available - used to distinguish
18872f2b0b2SOndrej Zary    between the Xilinx and ASIC implementations of the Freecom adapter.
18972f2b0b2SOndrej Zary */
19072f2b0b2SOndrej Zary 
191882ff0caSOndrej Zary static int frpw_test_pnp(struct pi_adapter *pi)
19272f2b0b2SOndrej Zary 
19372f2b0b2SOndrej Zary /*  returns chip_type:   0 = Xilinx, 1 = ASIC   */
19472f2b0b2SOndrej Zary 
19572f2b0b2SOndrej Zary {	int olddelay, a, b;
19672f2b0b2SOndrej Zary 
19772f2b0b2SOndrej Zary #ifdef FRPW_HARD_RESET
19872f2b0b2SOndrej Zary         w0(0); w2(8); udelay(50); w2(0xc);   /* parallel bus reset */
19972f2b0b2SOndrej Zary         mdelay(1500);
20072f2b0b2SOndrej Zary #endif
20172f2b0b2SOndrej Zary 
20272f2b0b2SOndrej Zary 	olddelay = pi->delay;
20372f2b0b2SOndrej Zary 	pi->delay = 10;
20472f2b0b2SOndrej Zary 
20572f2b0b2SOndrej Zary 	pi->saved_r0 = r0();
20672f2b0b2SOndrej Zary         pi->saved_r2 = r2();
20772f2b0b2SOndrej Zary 
20872f2b0b2SOndrej Zary 	w2(4); w0(4); w2(6); w2(7);
20972f2b0b2SOndrej Zary 	a = r1() & 0xff; w2(4); b = r1() & 0xff;
21072f2b0b2SOndrej Zary 	w2(0xc); w2(0xe); w2(4);
21172f2b0b2SOndrej Zary 
21272f2b0b2SOndrej Zary 	pi->delay = olddelay;
21372f2b0b2SOndrej Zary         w0(pi->saved_r0);
21472f2b0b2SOndrej Zary         w2(pi->saved_r2);
21572f2b0b2SOndrej Zary 
21672f2b0b2SOndrej Zary 	return ((~a&0x40) && (b&0x40));
21772f2b0b2SOndrej Zary }
21872f2b0b2SOndrej Zary 
21972f2b0b2SOndrej Zary /* We use the pi->private to remember the result of the PNP test.
22072f2b0b2SOndrej Zary    To make this work, private = port*2 + chip.  Yes, I know it's
22172f2b0b2SOndrej Zary    a hack :-(
22272f2b0b2SOndrej Zary */
22372f2b0b2SOndrej Zary 
224882ff0caSOndrej Zary static int frpw_test_proto(struct pi_adapter *pi, char *scratch, int verbose)
22572f2b0b2SOndrej Zary 
22672f2b0b2SOndrej Zary {       int     j, k, r;
22772f2b0b2SOndrej Zary 	int	e[2] = {0,0};
22872f2b0b2SOndrej Zary 
22972f2b0b2SOndrej Zary 	if ((pi->private>>1) != pi->port)
23072f2b0b2SOndrej Zary 	   pi->private = frpw_test_pnp(pi) + 2*pi->port;
23172f2b0b2SOndrej Zary 
23272f2b0b2SOndrej Zary 	if (((pi->private%2) == 0) && (pi->mode > 2)) {
233*5f1145d8SOndrej Zary 		dev_dbg(&pi->dev, "frpw: Xilinx does not support mode %d\n", pi->mode);
23472f2b0b2SOndrej Zary 	   return 1;
23572f2b0b2SOndrej Zary 	}
23672f2b0b2SOndrej Zary 
23772f2b0b2SOndrej Zary 	if (((pi->private%2) == 1) && (pi->mode == 2)) {
238*5f1145d8SOndrej Zary 		dev_dbg(&pi->dev, "frpw: ASIC does not support mode 2\n");
23972f2b0b2SOndrej Zary 	   return 1;
24072f2b0b2SOndrej Zary 	}
24172f2b0b2SOndrej Zary 
24272f2b0b2SOndrej Zary 	frpw_connect(pi);
24372f2b0b2SOndrej Zary 	for (j=0;j<2;j++) {
24472f2b0b2SOndrej Zary                 frpw_write_regr(pi,0,6,0xa0+j*0x10);
24572f2b0b2SOndrej Zary                 for (k=0;k<256;k++) {
24672f2b0b2SOndrej Zary                         frpw_write_regr(pi,0,2,k^0xaa);
24772f2b0b2SOndrej Zary                         frpw_write_regr(pi,0,3,k^0x55);
24872f2b0b2SOndrej Zary                         if (frpw_read_regr(pi,0,2) != (k^0xaa)) e[j]++;
24972f2b0b2SOndrej Zary                         }
25072f2b0b2SOndrej Zary                 }
25172f2b0b2SOndrej Zary 	frpw_disconnect(pi);
25272f2b0b2SOndrej Zary 
25372f2b0b2SOndrej Zary 	frpw_connect(pi);
25472f2b0b2SOndrej Zary         frpw_read_block_int(pi,scratch,512,0x10);
25572f2b0b2SOndrej Zary         r = 0;
25672f2b0b2SOndrej Zary         for (k=0;k<128;k++) if (scratch[k] != k) r++;
25772f2b0b2SOndrej Zary 	frpw_disconnect(pi);
25872f2b0b2SOndrej Zary 
259*5f1145d8SOndrej Zary 	dev_dbg(&pi->dev, "frpw: port 0x%x, chip %ld, mode %d, test=(%d,%d,%d)\n",
260a4f2ff92SOndrej Zary 	       pi->port, (pi->private%2), pi->mode, e[0], e[1], r);
26172f2b0b2SOndrej Zary 
26272f2b0b2SOndrej Zary         return (r || (e[0] && e[1]));
26372f2b0b2SOndrej Zary }
26472f2b0b2SOndrej Zary 
26572f2b0b2SOndrej Zary 
2665b77db9cSOndrej Zary static void frpw_log_adapter(struct pi_adapter *pi)
26772f2b0b2SOndrej Zary 
26872f2b0b2SOndrej Zary {       char    *mode_string[6] = {"4-bit","8-bit","EPP",
26972f2b0b2SOndrej Zary 				   "EPP-8","EPP-16","EPP-32"};
27072f2b0b2SOndrej Zary 
271*5f1145d8SOndrej Zary 	dev_info(&pi->dev, "frpw %s, Freecom (%s) adapter at 0x%x, ",
27272f2b0b2SOndrej Zary 		FRPW_VERSION,((pi->private%2) == 0)?"Xilinx":"ASIC",pi->port);
273*5f1145d8SOndrej Zary 	dev_info(&pi->dev, "mode %d (%s), delay %d\n", pi->mode,
27472f2b0b2SOndrej Zary 		mode_string[pi->mode],pi->delay);
27572f2b0b2SOndrej Zary 
27672f2b0b2SOndrej Zary }
27772f2b0b2SOndrej Zary 
27872f2b0b2SOndrej Zary static struct pi_protocol frpw = {
27972f2b0b2SOndrej Zary 	.owner		= THIS_MODULE,
28072f2b0b2SOndrej Zary 	.name		= "frpw",
28172f2b0b2SOndrej Zary 	.max_mode	= 6,
28272f2b0b2SOndrej Zary 	.epp_first	= 2,
28372f2b0b2SOndrej Zary 	.default_delay	= 2,
28472f2b0b2SOndrej Zary 	.max_units	= 1,
28572f2b0b2SOndrej Zary 	.write_regr	= frpw_write_regr,
28672f2b0b2SOndrej Zary 	.read_regr	= frpw_read_regr,
28772f2b0b2SOndrej Zary 	.write_block	= frpw_write_block,
28872f2b0b2SOndrej Zary 	.read_block	= frpw_read_block,
28972f2b0b2SOndrej Zary 	.connect	= frpw_connect,
29072f2b0b2SOndrej Zary 	.disconnect	= frpw_disconnect,
29172f2b0b2SOndrej Zary 	.test_proto	= frpw_test_proto,
29272f2b0b2SOndrej Zary 	.log_adapter	= frpw_log_adapter,
29372f2b0b2SOndrej Zary };
29472f2b0b2SOndrej Zary 
29572f2b0b2SOndrej Zary MODULE_LICENSE("GPL");
2962c08ec0fSOndrej Zary module_pata_parport_driver(frpw);
297