xref: /openbmc/linux/drivers/ata/pata_parport/bpck6.c (revision 7c97e468)
1 /*
2 	backpack.c (c) 2001 Micro Solutions Inc.
3 		Released under the terms of the GNU General Public license
4 
5 	backpack.c is a low-level protocol driver for the Micro Solutions
6 		"BACKPACK" parallel port IDE adapter
7 		(Works on Series 6 drives)
8 
9 	Written by: Ken Hahn     (linux-dev@micro-solutions.com)
10 	            Clive Turvey (linux-dev@micro-solutions.com)
11 
12 */
13 
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/types.h>
18 #include <linux/parport.h>
19 #include "pata_parport.h"
20 #include "ppc6lnx.c"
21 
22 static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg)
23 {
24 	u8 port = cont ? reg | 8 : reg;
25 
26 	ppc6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ);
27 	return ppc6_rd_data_byte(pi);
28 }
29 
30 static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val)
31 {
32 	u8 port = cont ? reg | 8 : reg;
33 
34 	ppc6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE);
35 	ppc6_wr_data_byte(pi, val);
36 }
37 
38 static void bpck6_wait_for_fifo(struct pi_adapter *pi)
39 {
40 	int i;
41 
42 	if (pi->private & fifo_wait) {
43 		for (i = 0; i < 20; i++)
44 			parport_read_status(pi->pardev->port);
45 	}
46 }
47 
48 static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len)
49 {
50 	u8 this, last;
51 
52 	ppc6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
53 	ppc6_wr_data_byte(pi, (u8)len);
54 	ppc6_wr_data_byte(pi, (u8)(len >> 8));
55 	ppc6_wr_data_byte(pi, 0);
56 
57 	ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
58 	ppc6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE);
59 
60 	switch (mode_map[pi->mode]) {
61 	case PPCMODE_UNI_SW:
62 	case PPCMODE_BI_SW:
63 		while (len--) {
64 			parport_write_data(pi->pardev->port, *buf++);
65 			parport_frob_control(pi->pardev->port, 0,
66 							PARPORT_CONTROL_INIT);
67 		}
68 		break;
69 	case PPCMODE_UNI_FW:
70 	case PPCMODE_BI_FW:
71 		ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR);
72 
73 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
74 							PARPORT_CONTROL_STROBE);
75 
76 		last = *buf;
77 
78 		parport_write_data(pi->pardev->port, last);
79 
80 		while (len) {
81 			this = *buf++;
82 			len--;
83 
84 			if (this == last) {
85 				parport_frob_control(pi->pardev->port, 0,
86 							PARPORT_CONTROL_INIT);
87 			} else {
88 				parport_write_data(pi->pardev->port, this);
89 				last = this;
90 			}
91 		}
92 
93 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
94 							0);
95 		ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR);
96 		break;
97 	case PPCMODE_EPP_BYTE:
98 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
99 						len, PARPORT_EPP_FAST_8);
100 		bpck6_wait_for_fifo(pi);
101 		break;
102 	case PPCMODE_EPP_WORD:
103 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
104 						len, PARPORT_EPP_FAST_16);
105 		bpck6_wait_for_fifo(pi);
106 		break;
107 	case PPCMODE_EPP_DWORD:
108 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
109 						len, PARPORT_EPP_FAST_32);
110 		bpck6_wait_for_fifo(pi);
111 		break;
112 	}
113 
114 	ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
115 }
116 
117 static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len)
118 {
119 	ppc6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
120 	ppc6_wr_data_byte(pi, (u8)len);
121 	ppc6_wr_data_byte(pi, (u8)(len >> 8));
122 	ppc6_wr_data_byte(pi, 0);
123 
124 	ppc6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
125 	ppc6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ);
126 
127 	switch (mode_map[pi->mode]) {
128 	case PPCMODE_UNI_SW:
129 	case PPCMODE_UNI_FW:
130 		while (len) {
131 			u8 d;
132 
133 			parport_frob_control(pi->pardev->port,
134 					PARPORT_CONTROL_STROBE,
135 					PARPORT_CONTROL_INIT); /* DATA STROBE */
136 			d = parport_read_status(pi->pardev->port);
137 			d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
138 			parport_frob_control(pi->pardev->port,
139 					PARPORT_CONTROL_STROBE,
140 					PARPORT_CONTROL_STROBE);
141 			d |= parport_read_status(pi->pardev->port) & 0xB8;
142 			*buf++ = d;
143 			len--;
144 		}
145 		break;
146 	case PPCMODE_BI_SW:
147 	case PPCMODE_BI_FW:
148 		parport_data_reverse(pi->pardev->port);
149 		while (len) {
150 			parport_frob_control(pi->pardev->port,
151 				PARPORT_CONTROL_STROBE,
152 				PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
153 			*buf++ = parport_read_data(pi->pardev->port);
154 			len--;
155 		}
156 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
157 					0);
158 		parport_data_forward(pi->pardev->port);
159 		break;
160 	case PPCMODE_EPP_BYTE:
161 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
162 						PARPORT_EPP_FAST_8);
163 		break;
164 	case PPCMODE_EPP_WORD:
165 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
166 						PARPORT_EPP_FAST_16);
167 		break;
168 	case PPCMODE_EPP_DWORD:
169 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
170 						PARPORT_EPP_FAST_32);
171 		break;
172 	}
173 
174 	ppc6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
175 }
176 
177 static int bpck6_open(struct pi_adapter *pi)
178 {
179 	int ret = ppc6_select(pi);
180 
181 	if (ret == 0)
182 		return ret;
183 
184 	pi->private = 0;
185 
186 	ppc6_send_cmd(pi, ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE);
187 	ppc6_wr_data_byte(pi, RAMSIZE_128K);
188 
189 	ppc6_send_cmd(pi, ACCESS_REG | ACCESS_READ | REG_VERSION);
190 	if ((ppc6_rd_data_byte(pi) & 0x3F) == 0x0C)
191 		pi->private |= fifo_wait;
192 
193 	return ret;
194 }
195 
196 static void bpck6_wr_extout(struct pi_adapter *pi, u8 regdata)
197 {
198 	ppc6_send_cmd(pi, REG_VERSION | ACCESS_REG | ACCESS_WRITE);
199 	ppc6_wr_data_byte(pi, (u8)((regdata & 0x03) << 6));
200 }
201 
202 static void bpck6_connect(struct pi_adapter *pi)
203 {
204 	dev_dbg(&pi->dev, "connect\n");
205 
206 	bpck6_open(pi);
207 	bpck6_wr_extout(pi, 0x3);
208 }
209 
210 static void bpck6_disconnect(struct pi_adapter *pi)
211 {
212 	dev_dbg(&pi->dev, "disconnect\n");
213 	bpck6_wr_extout(pi, 0x0);
214 	ppc6_deselect(pi);
215 }
216 
217 static int bpck6_test_port(struct pi_adapter *pi)   /* check for 8-bit port */
218 {
219 	dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n",
220 		pi->pardev->port->modes, pi->pardev->port->base);
221 
222 	/* look at the parport device to see what modes we can use */
223 	if (pi->pardev->port->modes & PARPORT_MODE_EPP)
224 		return 5; /* Can do EPP */
225 	if (pi->pardev->port->modes & PARPORT_MODE_TRISTATE)
226 		return 2;
227 	return 1; /* Just flat SPP */
228 }
229 
230 static int bpck6_probe_unit(struct pi_adapter *pi)
231 {
232 	int out, saved_mode;
233 
234 	dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port);
235 
236 	saved_mode = pi->mode;
237 	/*LOWER DOWN TO UNIDIRECTIONAL*/
238 	pi->mode = 0;
239 
240 	out = bpck6_open(pi);
241 
242 	dev_dbg(&pi->dev, "ppc_open returned %2x\n", out);
243 
244   	if(out)
245  	{
246 		ppc6_deselect(pi);
247 		dev_dbg(&pi->dev, "leaving probe\n");
248 		pi->mode = saved_mode;
249                return(1);
250 	}
251   	else
252   	{
253 		dev_dbg(&pi->dev, "Failed open\n");
254 		pi->mode = saved_mode;
255     		return(0);
256   	}
257 }
258 
259 static void bpck6_log_adapter(struct pi_adapter *pi)
260 {
261 	char *mode_string[5]=
262 		{"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
263 
264 	dev_info(&pi->dev, "Micro Solutions BACKPACK Drive unit %d at 0x%x, mode:%d (%s), delay %d\n",
265 		pi->unit, pi->port, pi->mode, mode_string[pi->mode], pi->delay);
266 }
267 
268 static struct pi_protocol bpck6 = {
269 	.owner		= THIS_MODULE,
270 	.name		= "bpck6",
271 	.max_mode	= 5,
272 	.epp_first	= 2, /* 2-5 use epp (need 8 ports) */
273 	.max_units	= 255,
274 	.write_regr	= bpck6_write_regr,
275 	.read_regr	= bpck6_read_regr,
276 	.write_block	= bpck6_write_block,
277 	.read_block	= bpck6_read_block,
278 	.connect	= bpck6_connect,
279 	.disconnect	= bpck6_disconnect,
280 	.test_port	= bpck6_test_port,
281 	.probe_unit	= bpck6_probe_unit,
282 	.log_adapter	= bpck6_log_adapter,
283 };
284 
285 MODULE_LICENSE("GPL");
286 MODULE_AUTHOR("Micro Solutions Inc.");
287 MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
288 module_pata_parport_driver(bpck6);
289