xref: /openbmc/linux/drivers/ata/pata_parport/epia.c (revision 882ff0ca)
172f2b0b2SOndrej Zary /*
272f2b0b2SOndrej Zary         epia.c    (c) 1997-8  Grant R. Guenther <grant@torque.net>
372f2b0b2SOndrej Zary                               Under the terms of the GNU General Public License.
472f2b0b2SOndrej Zary 
572f2b0b2SOndrej Zary         epia.c is a low-level protocol driver for Shuttle Technologies
672f2b0b2SOndrej Zary 	EPIA parallel to IDE adapter chip.  This device is now obsolete
772f2b0b2SOndrej Zary 	and has been replaced with the EPAT chip, which is supported
872f2b0b2SOndrej Zary 	by epat.c, however, some devices based on EPIA are still
972f2b0b2SOndrej Zary 	available.
1072f2b0b2SOndrej Zary 
1172f2b0b2SOndrej Zary */
1272f2b0b2SOndrej Zary 
1372f2b0b2SOndrej Zary /* Changes:
1472f2b0b2SOndrej Zary 
1572f2b0b2SOndrej Zary         1.01    GRG 1998.05.06 init_proto, release_proto
1672f2b0b2SOndrej Zary 	1.02    GRG 1998.06.17 support older versions of EPIA
1772f2b0b2SOndrej Zary 
1872f2b0b2SOndrej Zary */
1972f2b0b2SOndrej Zary 
2072f2b0b2SOndrej Zary #define EPIA_VERSION      "1.02"
2172f2b0b2SOndrej Zary 
2272f2b0b2SOndrej Zary #include <linux/module.h>
2372f2b0b2SOndrej Zary #include <linux/init.h>
2472f2b0b2SOndrej Zary #include <linux/delay.h>
2572f2b0b2SOndrej Zary #include <linux/kernel.h>
2672f2b0b2SOndrej Zary #include <linux/types.h>
2772f2b0b2SOndrej Zary #include <linux/wait.h>
2872f2b0b2SOndrej Zary #include <asm/io.h>
2972f2b0b2SOndrej Zary 
3072f2b0b2SOndrej Zary #include <linux/pata_parport.h>
3172f2b0b2SOndrej Zary 
3272f2b0b2SOndrej Zary /* mode codes:  0  nybble reads on port 1, 8-bit writes
3372f2b0b2SOndrej Zary                 1  5/3 reads on ports 1 & 2, 8-bit writes
3472f2b0b2SOndrej Zary                 2  8-bit reads and writes
3572f2b0b2SOndrej Zary                 3  8-bit EPP mode
3672f2b0b2SOndrej Zary 		4  16-bit EPP
3772f2b0b2SOndrej Zary 		5  32-bit EPP
3872f2b0b2SOndrej Zary */
3972f2b0b2SOndrej Zary 
4072f2b0b2SOndrej Zary #define j44(a,b)                (((a>>4)&0x0f)+(b&0xf0))
4172f2b0b2SOndrej Zary #define j53(a,b)                (((a>>3)&0x1f)+((b<<4)&0xe0))
4272f2b0b2SOndrej Zary 
4372f2b0b2SOndrej Zary /* cont =  0   IDE register file
4472f2b0b2SOndrej Zary    cont =  1   IDE control registers
4572f2b0b2SOndrej Zary */
4672f2b0b2SOndrej Zary 
4772f2b0b2SOndrej Zary static int cont_map[2] = { 0, 0x80 };
4872f2b0b2SOndrej Zary 
49*882ff0caSOndrej Zary static int epia_read_regr(struct pi_adapter *pi, int cont, int regr)
5072f2b0b2SOndrej Zary 
5172f2b0b2SOndrej Zary {       int     a, b, r;
5272f2b0b2SOndrej Zary 
5372f2b0b2SOndrej Zary 	regr += cont_map[cont];
5472f2b0b2SOndrej Zary 
5572f2b0b2SOndrej Zary         switch (pi->mode)  {
5672f2b0b2SOndrej Zary 
5772f2b0b2SOndrej Zary         case 0: r = regr^0x39;
5872f2b0b2SOndrej Zary                 w0(r); w2(1); w2(3); w0(r);
5972f2b0b2SOndrej Zary                 a = r1(); w2(1); b = r1(); w2(4);
6072f2b0b2SOndrej Zary                 return j44(a,b);
6172f2b0b2SOndrej Zary 
6272f2b0b2SOndrej Zary         case 1: r = regr^0x31;
6372f2b0b2SOndrej Zary                 w0(r); w2(1); w0(r&0x37);
6472f2b0b2SOndrej Zary                 w2(3); w2(5); w0(r|0xf0);
6572f2b0b2SOndrej Zary                 a = r1(); b = r2(); w2(4);
6672f2b0b2SOndrej Zary                 return j53(a,b);
6772f2b0b2SOndrej Zary 
6872f2b0b2SOndrej Zary         case 2: r = regr^0x29;
6972f2b0b2SOndrej Zary                 w0(r); w2(1); w2(0X21); w2(0x23);
7072f2b0b2SOndrej Zary                 a = r0(); w2(4);
7172f2b0b2SOndrej Zary                 return a;
7272f2b0b2SOndrej Zary 
7372f2b0b2SOndrej Zary 	case 3:
7472f2b0b2SOndrej Zary 	case 4:
7572f2b0b2SOndrej Zary         case 5: w3(regr); w2(0x24); a = r4(); w2(4);
7672f2b0b2SOndrej Zary                 return a;
7772f2b0b2SOndrej Zary 
7872f2b0b2SOndrej Zary         }
7972f2b0b2SOndrej Zary         return -1;
8072f2b0b2SOndrej Zary }
8172f2b0b2SOndrej Zary 
82*882ff0caSOndrej Zary static void epia_write_regr(struct pi_adapter *pi, int cont, int regr, int val)
8372f2b0b2SOndrej Zary 
8472f2b0b2SOndrej Zary {       int  r;
8572f2b0b2SOndrej Zary 
8672f2b0b2SOndrej Zary 	regr += cont_map[cont];
8772f2b0b2SOndrej Zary 
8872f2b0b2SOndrej Zary         switch (pi->mode)  {
8972f2b0b2SOndrej Zary 
9072f2b0b2SOndrej Zary         case 0:
9172f2b0b2SOndrej Zary         case 1:
9272f2b0b2SOndrej Zary         case 2: r = regr^0x19;
9372f2b0b2SOndrej Zary                 w0(r); w2(1); w0(val); w2(3); w2(4);
9472f2b0b2SOndrej Zary                 break;
9572f2b0b2SOndrej Zary 
9672f2b0b2SOndrej Zary 	case 3:
9772f2b0b2SOndrej Zary 	case 4:
9872f2b0b2SOndrej Zary         case 5: r = regr^0x40;
9972f2b0b2SOndrej Zary                 w3(r); w4(val); w2(4);
10072f2b0b2SOndrej Zary                 break;
10172f2b0b2SOndrej Zary         }
10272f2b0b2SOndrej Zary }
10372f2b0b2SOndrej Zary 
10472f2b0b2SOndrej Zary #define WR(r,v)         epia_write_regr(pi,0,r,v)
10572f2b0b2SOndrej Zary #define RR(r)           (epia_read_regr(pi,0,r))
10672f2b0b2SOndrej Zary 
10772f2b0b2SOndrej Zary /* The use of register 0x84 is entirely unclear - it seems to control
10872f2b0b2SOndrej Zary    some EPP counters ...  currently we know about 3 different block
10972f2b0b2SOndrej Zary    sizes:  the standard 512 byte reads and writes, 12 byte writes and
11072f2b0b2SOndrej Zary    2048 byte reads (the last two being used in the CDrom drivers.
11172f2b0b2SOndrej Zary */
11272f2b0b2SOndrej Zary 
113*882ff0caSOndrej Zary static void epia_connect(struct pi_adapter *pi)
11472f2b0b2SOndrej Zary 
11572f2b0b2SOndrej Zary {       pi->saved_r0 = r0();
11672f2b0b2SOndrej Zary         pi->saved_r2 = r2();
11772f2b0b2SOndrej Zary 
11872f2b0b2SOndrej Zary         w2(4); w0(0xa0); w0(0x50); w0(0xc0); w0(0x30); w0(0xa0); w0(0);
11972f2b0b2SOndrej Zary         w2(1); w2(4);
12072f2b0b2SOndrej Zary         if (pi->mode >= 3) {
12172f2b0b2SOndrej Zary                 w0(0xa); w2(1); w2(4); w0(0x82); w2(4); w2(0xc); w2(4);
12272f2b0b2SOndrej Zary                 w2(0x24); w2(0x26); w2(4);
12372f2b0b2SOndrej Zary         }
12472f2b0b2SOndrej Zary         WR(0x86,8);
12572f2b0b2SOndrej Zary }
12672f2b0b2SOndrej Zary 
127*882ff0caSOndrej Zary static void epia_disconnect(struct pi_adapter *pi)
12872f2b0b2SOndrej Zary 
12972f2b0b2SOndrej Zary {       /* WR(0x84,0x10); */
13072f2b0b2SOndrej Zary         w0(pi->saved_r0);
13172f2b0b2SOndrej Zary         w2(1); w2(4);
13272f2b0b2SOndrej Zary         w0(pi->saved_r0);
13372f2b0b2SOndrej Zary         w2(pi->saved_r2);
13472f2b0b2SOndrej Zary }
13572f2b0b2SOndrej Zary 
136*882ff0caSOndrej Zary static void epia_read_block(struct pi_adapter *pi, char *buf, int count)
13772f2b0b2SOndrej Zary 
13872f2b0b2SOndrej Zary {       int     k, ph, a, b;
13972f2b0b2SOndrej Zary 
14072f2b0b2SOndrej Zary         switch (pi->mode) {
14172f2b0b2SOndrej Zary 
14272f2b0b2SOndrej Zary         case 0: w0(0x81); w2(1); w2(3); w0(0xc1);
14372f2b0b2SOndrej Zary                 ph = 1;
14472f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
14572f2b0b2SOndrej Zary                         w2(2+ph); a = r1();
14672f2b0b2SOndrej Zary                         w2(4+ph); b = r1();
14772f2b0b2SOndrej Zary                         buf[k] = j44(a,b);
14872f2b0b2SOndrej Zary                         ph = 1 - ph;
14972f2b0b2SOndrej Zary                 }
15072f2b0b2SOndrej Zary                 w0(0); w2(4);
15172f2b0b2SOndrej Zary                 break;
15272f2b0b2SOndrej Zary 
15372f2b0b2SOndrej Zary         case 1: w0(0x91); w2(1); w0(0x10); w2(3);
15472f2b0b2SOndrej Zary                 w0(0x51); w2(5); w0(0xd1);
15572f2b0b2SOndrej Zary                 ph = 1;
15672f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
15772f2b0b2SOndrej Zary                         w2(4+ph);
15872f2b0b2SOndrej Zary                         a = r1(); b = r2();
15972f2b0b2SOndrej Zary                         buf[k] = j53(a,b);
16072f2b0b2SOndrej Zary                         ph = 1 - ph;
16172f2b0b2SOndrej Zary                 }
16272f2b0b2SOndrej Zary                 w0(0); w2(4);
16372f2b0b2SOndrej Zary                 break;
16472f2b0b2SOndrej Zary 
16572f2b0b2SOndrej Zary         case 2: w0(0x89); w2(1); w2(0x23); w2(0x21);
16672f2b0b2SOndrej Zary                 ph = 1;
16772f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
16872f2b0b2SOndrej Zary                         w2(0x24+ph);
16972f2b0b2SOndrej Zary                         buf[k] = r0();
17072f2b0b2SOndrej Zary                         ph = 1 - ph;
17172f2b0b2SOndrej Zary                 }
17272f2b0b2SOndrej Zary                 w2(6); w2(4);
17372f2b0b2SOndrej Zary                 break;
17472f2b0b2SOndrej Zary 
17572f2b0b2SOndrej Zary         case 3: if (count > 512) WR(0x84,3);
17672f2b0b2SOndrej Zary 		w3(0); w2(0x24);
17772f2b0b2SOndrej Zary                 for (k=0;k<count;k++) buf[k] = r4();
17872f2b0b2SOndrej Zary                 w2(4); WR(0x84,0);
17972f2b0b2SOndrej Zary                 break;
18072f2b0b2SOndrej Zary 
18172f2b0b2SOndrej Zary         case 4: if (count > 512) WR(0x84,3);
18272f2b0b2SOndrej Zary 		w3(0); w2(0x24);
18372f2b0b2SOndrej Zary 		for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w();
18472f2b0b2SOndrej Zary                 w2(4); WR(0x84,0);
18572f2b0b2SOndrej Zary                 break;
18672f2b0b2SOndrej Zary 
18772f2b0b2SOndrej Zary         case 5: if (count > 512) WR(0x84,3);
18872f2b0b2SOndrej Zary 		w3(0); w2(0x24);
18972f2b0b2SOndrej Zary                 for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l();
19072f2b0b2SOndrej Zary                 w2(4); WR(0x84,0);
19172f2b0b2SOndrej Zary                 break;
19272f2b0b2SOndrej Zary 
19372f2b0b2SOndrej Zary         }
19472f2b0b2SOndrej Zary }
19572f2b0b2SOndrej Zary 
196*882ff0caSOndrej Zary static void epia_write_block(struct pi_adapter *pi, char *buf, int count)
19772f2b0b2SOndrej Zary 
19872f2b0b2SOndrej Zary {       int     ph, k, last, d;
19972f2b0b2SOndrej Zary 
20072f2b0b2SOndrej Zary         switch (pi->mode) {
20172f2b0b2SOndrej Zary 
20272f2b0b2SOndrej Zary         case 0:
20372f2b0b2SOndrej Zary         case 1:
20472f2b0b2SOndrej Zary         case 2: w0(0xa1); w2(1); w2(3); w2(1); w2(5);
20572f2b0b2SOndrej Zary                 ph = 0;  last = 0x8000;
20672f2b0b2SOndrej Zary                 for (k=0;k<count;k++) {
20772f2b0b2SOndrej Zary                         d = buf[k];
20872f2b0b2SOndrej Zary                         if (d != last) { last = d; w0(d); }
20972f2b0b2SOndrej Zary                         w2(4+ph);
21072f2b0b2SOndrej Zary                         ph = 1 - ph;
21172f2b0b2SOndrej Zary                 }
21272f2b0b2SOndrej Zary                 w2(7); w2(4);
21372f2b0b2SOndrej Zary                 break;
21472f2b0b2SOndrej Zary 
21572f2b0b2SOndrej Zary         case 3: if (count < 512) WR(0x84,1);
21672f2b0b2SOndrej Zary 		w3(0x40);
21772f2b0b2SOndrej Zary                 for (k=0;k<count;k++) w4(buf[k]);
21872f2b0b2SOndrej Zary 		if (count < 512) WR(0x84,0);
21972f2b0b2SOndrej Zary                 break;
22072f2b0b2SOndrej Zary 
22172f2b0b2SOndrej Zary         case 4: if (count < 512) WR(0x84,1);
22272f2b0b2SOndrej Zary 		w3(0x40);
22372f2b0b2SOndrej Zary                 for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
22472f2b0b2SOndrej Zary 		if (count < 512) WR(0x84,0);
22572f2b0b2SOndrej Zary                 break;
22672f2b0b2SOndrej Zary 
22772f2b0b2SOndrej Zary         case 5: if (count < 512) WR(0x84,1);
22872f2b0b2SOndrej Zary 		w3(0x40);
22972f2b0b2SOndrej Zary                 for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
23072f2b0b2SOndrej Zary 		if (count < 512) WR(0x84,0);
23172f2b0b2SOndrej Zary                 break;
23272f2b0b2SOndrej Zary 
23372f2b0b2SOndrej Zary         }
23472f2b0b2SOndrej Zary 
23572f2b0b2SOndrej Zary }
23672f2b0b2SOndrej Zary 
237*882ff0caSOndrej Zary static int epia_test_proto(struct pi_adapter *pi, char *scratch, int verbose)
23872f2b0b2SOndrej Zary 
23972f2b0b2SOndrej Zary {       int     j, k, f;
24072f2b0b2SOndrej Zary 	int	e[2] = {0,0};
24172f2b0b2SOndrej Zary 
24272f2b0b2SOndrej Zary         epia_connect(pi);
24372f2b0b2SOndrej Zary         for (j=0;j<2;j++) {
24472f2b0b2SOndrej Zary             WR(6,0xa0+j*0x10);
24572f2b0b2SOndrej Zary             for (k=0;k<256;k++) {
24672f2b0b2SOndrej Zary                 WR(2,k^0xaa);
24772f2b0b2SOndrej Zary                 WR(3,k^0x55);
24872f2b0b2SOndrej Zary                 if (RR(2) != (k^0xaa)) e[j]++;
24972f2b0b2SOndrej Zary                 }
25072f2b0b2SOndrej Zary 	    WR(2,1); WR(3,1);
25172f2b0b2SOndrej Zary             }
25272f2b0b2SOndrej Zary         epia_disconnect(pi);
25372f2b0b2SOndrej Zary 
25472f2b0b2SOndrej Zary         f = 0;
25572f2b0b2SOndrej Zary         epia_connect(pi);
25672f2b0b2SOndrej Zary         WR(0x84,8);
25772f2b0b2SOndrej Zary         epia_read_block(pi,scratch,512);
25872f2b0b2SOndrej Zary         for (k=0;k<256;k++) {
25972f2b0b2SOndrej Zary             if ((scratch[2*k] & 0xff) != ((k+1) & 0xff)) f++;
26072f2b0b2SOndrej Zary             if ((scratch[2*k+1] & 0xff) != ((-2-k) & 0xff)) f++;
26172f2b0b2SOndrej Zary         }
26272f2b0b2SOndrej Zary         WR(0x84,0);
26372f2b0b2SOndrej Zary         epia_disconnect(pi);
26472f2b0b2SOndrej Zary 
26572f2b0b2SOndrej Zary         if (verbose)  {
266a4f2ff92SOndrej Zary 		printk("epia: port 0x%x, mode %d, test=(%d,%d,%d)\n",
267a4f2ff92SOndrej Zary 		       pi->port, pi->mode, e[0], e[1], f);
26872f2b0b2SOndrej Zary         }
26972f2b0b2SOndrej Zary 
27072f2b0b2SOndrej Zary         return (e[0] && e[1]) || f;
27172f2b0b2SOndrej Zary 
27272f2b0b2SOndrej Zary }
27372f2b0b2SOndrej Zary 
27472f2b0b2SOndrej Zary 
275*882ff0caSOndrej Zary static void epia_log_adapter(struct pi_adapter *pi, char *scratch, int verbose)
27672f2b0b2SOndrej Zary 
27772f2b0b2SOndrej Zary {       char    *mode_string[6] = {"4-bit","5/3","8-bit",
27872f2b0b2SOndrej Zary 				   "EPP-8","EPP-16","EPP-32"};
27972f2b0b2SOndrej Zary 
280a4f2ff92SOndrej Zary 	printk("epia %s, Shuttle EPIA at 0x%x, ", EPIA_VERSION, pi->port);
28172f2b0b2SOndrej Zary         printk("mode %d (%s), delay %d\n",pi->mode,
28272f2b0b2SOndrej Zary 		mode_string[pi->mode],pi->delay);
28372f2b0b2SOndrej Zary 
28472f2b0b2SOndrej Zary }
28572f2b0b2SOndrej Zary 
28672f2b0b2SOndrej Zary static struct pi_protocol epia = {
28772f2b0b2SOndrej Zary 	.owner		= THIS_MODULE,
28872f2b0b2SOndrej Zary 	.name		= "epia",
28972f2b0b2SOndrej Zary 	.max_mode	= 6,
29072f2b0b2SOndrej Zary 	.epp_first	= 3,
29172f2b0b2SOndrej Zary 	.default_delay	= 1,
29272f2b0b2SOndrej Zary 	.max_units	= 1,
29372f2b0b2SOndrej Zary 	.write_regr	= epia_write_regr,
29472f2b0b2SOndrej Zary 	.read_regr	= epia_read_regr,
29572f2b0b2SOndrej Zary 	.write_block	= epia_write_block,
29672f2b0b2SOndrej Zary 	.read_block	= epia_read_block,
29772f2b0b2SOndrej Zary 	.connect	= epia_connect,
29872f2b0b2SOndrej Zary 	.disconnect	= epia_disconnect,
29972f2b0b2SOndrej Zary 	.test_proto	= epia_test_proto,
30072f2b0b2SOndrej Zary 	.log_adapter	= epia_log_adapter,
30172f2b0b2SOndrej Zary };
30272f2b0b2SOndrej Zary 
30372f2b0b2SOndrej Zary MODULE_LICENSE("GPL");
3042c08ec0fSOndrej Zary module_pata_parport_driver(epia);
305