xref: /openbmc/linux/drivers/ata/pata_parport/bpck6.c (revision 7cb35296)
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 void bpck6_send_cmd(struct pi_adapter *pi, u8 cmd)
23 {
24 	switch (mode_map[pi->mode]) {
25 	case PPCMODE_UNI_SW:
26 	case PPCMODE_UNI_FW:
27 	case PPCMODE_BI_SW:
28 	case PPCMODE_BI_FW:
29 		parport_write_data(pi->pardev->port, cmd);
30 		parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_AUTOFD);
31 		break;
32 	case PPCMODE_EPP_BYTE:
33 	case PPCMODE_EPP_WORD:
34 	case PPCMODE_EPP_DWORD:
35 		pi->pardev->port->ops->epp_write_addr(pi->pardev->port, &cmd, 1, 0);
36 		break;
37 	}
38 }
39 
40 static u8 bpck6_rd_data_byte(struct pi_adapter *pi)
41 {
42 	u8 data = 0;
43 
44 	switch (mode_map[pi->mode]) {
45 	case PPCMODE_UNI_SW:
46 	case PPCMODE_UNI_FW:
47 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
48 							PARPORT_CONTROL_INIT);
49 		data = parport_read_status(pi->pardev->port);
50 		data = ((data & 0x80) >> 1) | ((data & 0x38) >> 3);
51 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
52 							PARPORT_CONTROL_STROBE);
53 		data |= parport_read_status(pi->pardev->port) & 0xB8;
54 		break;
55 	case PPCMODE_BI_SW:
56 	case PPCMODE_BI_FW:
57 		parport_data_reverse(pi->pardev->port);
58 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
59 				PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
60 		data = parport_read_data(pi->pardev->port);
61 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE, 0);
62 		parport_data_forward(pi->pardev->port);
63 		break;
64 	case PPCMODE_EPP_BYTE:
65 	case PPCMODE_EPP_WORD:
66 	case PPCMODE_EPP_DWORD:
67 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, &data, 1, 0);
68 		break;
69 	}
70 
71 	return data;
72 }
73 
74 static void bpck6_wr_data_byte(struct pi_adapter *pi, u8 data)
75 {
76 	switch (mode_map[pi->mode]) {
77 	case PPCMODE_UNI_SW:
78 	case PPCMODE_UNI_FW:
79 	case PPCMODE_BI_SW:
80 	case PPCMODE_BI_FW:
81 		parport_write_data(pi->pardev->port, data);
82 		parport_frob_control(pi->pardev->port, 0, PARPORT_CONTROL_INIT);
83 		break;
84 	case PPCMODE_EPP_BYTE:
85 	case PPCMODE_EPP_WORD:
86 	case PPCMODE_EPP_DWORD:
87 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, &data, 1, 0);
88 		break;
89 	}
90 }
91 
92 static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg)
93 {
94 	u8 port = cont ? reg | 8 : reg;
95 
96 	bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ);
97 	return bpck6_rd_data_byte(pi);
98 }
99 
100 static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val)
101 {
102 	u8 port = cont ? reg | 8 : reg;
103 
104 	bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE);
105 	bpck6_wr_data_byte(pi, val);
106 }
107 
108 static void bpck6_wait_for_fifo(struct pi_adapter *pi)
109 {
110 	int i;
111 
112 	if (pi->private & fifo_wait) {
113 		for (i = 0; i < 20; i++)
114 			parport_read_status(pi->pardev->port);
115 	}
116 }
117 
118 static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len)
119 {
120 	u8 this, last;
121 
122 	bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
123 	bpck6_wr_data_byte(pi, (u8)len);
124 	bpck6_wr_data_byte(pi, (u8)(len >> 8));
125 	bpck6_wr_data_byte(pi, 0);
126 
127 	bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
128 	bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE);
129 
130 	switch (mode_map[pi->mode]) {
131 	case PPCMODE_UNI_SW:
132 	case PPCMODE_BI_SW:
133 		while (len--) {
134 			parport_write_data(pi->pardev->port, *buf++);
135 			parport_frob_control(pi->pardev->port, 0,
136 							PARPORT_CONTROL_INIT);
137 		}
138 		break;
139 	case PPCMODE_UNI_FW:
140 	case PPCMODE_BI_FW:
141 		bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR);
142 
143 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
144 							PARPORT_CONTROL_STROBE);
145 
146 		last = *buf;
147 
148 		parport_write_data(pi->pardev->port, last);
149 
150 		while (len) {
151 			this = *buf++;
152 			len--;
153 
154 			if (this == last) {
155 				parport_frob_control(pi->pardev->port, 0,
156 							PARPORT_CONTROL_INIT);
157 			} else {
158 				parport_write_data(pi->pardev->port, this);
159 				last = this;
160 			}
161 		}
162 
163 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
164 							0);
165 		bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR);
166 		break;
167 	case PPCMODE_EPP_BYTE:
168 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
169 						len, PARPORT_EPP_FAST_8);
170 		bpck6_wait_for_fifo(pi);
171 		break;
172 	case PPCMODE_EPP_WORD:
173 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
174 						len, PARPORT_EPP_FAST_16);
175 		bpck6_wait_for_fifo(pi);
176 		break;
177 	case PPCMODE_EPP_DWORD:
178 		pi->pardev->port->ops->epp_write_data(pi->pardev->port, buf,
179 						len, PARPORT_EPP_FAST_32);
180 		bpck6_wait_for_fifo(pi);
181 		break;
182 	}
183 
184 	bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
185 }
186 
187 static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len)
188 {
189 	bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
190 	bpck6_wr_data_byte(pi, (u8)len);
191 	bpck6_wr_data_byte(pi, (u8)(len >> 8));
192 	bpck6_wr_data_byte(pi, 0);
193 
194 	bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
195 	bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ);
196 
197 	switch (mode_map[pi->mode]) {
198 	case PPCMODE_UNI_SW:
199 	case PPCMODE_UNI_FW:
200 		while (len) {
201 			u8 d;
202 
203 			parport_frob_control(pi->pardev->port,
204 					PARPORT_CONTROL_STROBE,
205 					PARPORT_CONTROL_INIT); /* DATA STROBE */
206 			d = parport_read_status(pi->pardev->port);
207 			d = ((d & 0x80) >> 1) | ((d & 0x38) >> 3);
208 			parport_frob_control(pi->pardev->port,
209 					PARPORT_CONTROL_STROBE,
210 					PARPORT_CONTROL_STROBE);
211 			d |= parport_read_status(pi->pardev->port) & 0xB8;
212 			*buf++ = d;
213 			len--;
214 		}
215 		break;
216 	case PPCMODE_BI_SW:
217 	case PPCMODE_BI_FW:
218 		parport_data_reverse(pi->pardev->port);
219 		while (len) {
220 			parport_frob_control(pi->pardev->port,
221 				PARPORT_CONTROL_STROBE,
222 				PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT);
223 			*buf++ = parport_read_data(pi->pardev->port);
224 			len--;
225 		}
226 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_STROBE,
227 					0);
228 		parport_data_forward(pi->pardev->port);
229 		break;
230 	case PPCMODE_EPP_BYTE:
231 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
232 						PARPORT_EPP_FAST_8);
233 		break;
234 	case PPCMODE_EPP_WORD:
235 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
236 						PARPORT_EPP_FAST_16);
237 		break;
238 	case PPCMODE_EPP_DWORD:
239 		pi->pardev->port->ops->epp_read_data(pi->pardev->port, buf, len,
240 						PARPORT_EPP_FAST_32);
241 		break;
242 	}
243 
244 	bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
245 }
246 
247 static int bpck6_open(struct pi_adapter *pi)
248 {
249 	u8 i, j, k;
250 
251 	pi->saved_r0 = parport_read_data(pi->pardev->port);
252 	pi->saved_r2 = parport_read_control(pi->pardev->port) & 0x5F;
253 
254 	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
255 						PARPORT_CONTROL_SELECT);
256 	if (pi->saved_r0 == 'b')
257 		parport_write_data(pi->pardev->port, 'x');
258 	parport_write_data(pi->pardev->port, 'b');
259 	parport_write_data(pi->pardev->port, 'p');
260 	parport_write_data(pi->pardev->port, pi->unit);
261 	parport_write_data(pi->pardev->port, ~pi->unit);
262 
263 	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0);
264 	parport_write_control(pi->pardev->port, PARPORT_CONTROL_INIT);
265 
266 	i = mode_map[pi->mode] & 0x0C;
267 	if (i == 0)
268 		i = (mode_map[pi->mode] & 2) | 1;
269 	parport_write_data(pi->pardev->port, i);
270 
271 	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
272 						PARPORT_CONTROL_SELECT);
273 	parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD,
274 						PARPORT_CONTROL_AUTOFD);
275 
276 	j = ((i & 0x08) << 4) | ((i & 0x07) << 3);
277 	k = parport_read_status(pi->pardev->port) & 0xB8;
278 	if (j == k) {
279 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_AUTOFD, 0);
280 		k = (parport_read_status(pi->pardev->port) & 0xB8) ^ 0xB8;
281 		if (j == k) {
282 			if (i & 4)	// EPP
283 				parport_frob_control(pi->pardev->port,
284 					PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, 0);
285 			else				// PPC/ECP
286 				parport_frob_control(pi->pardev->port,
287 					PARPORT_CONTROL_SELECT, 0);
288 
289 			pi->private = 0;
290 
291 			bpck6_send_cmd(pi, ACCESS_REG | ACCESS_WRITE | REG_RAMSIZE);
292 			bpck6_wr_data_byte(pi, RAMSIZE_128K);
293 
294 			bpck6_send_cmd(pi, ACCESS_REG | ACCESS_READ | REG_VERSION);
295 			if ((bpck6_rd_data_byte(pi) & 0x3F) == 0x0C)
296 				pi->private |= fifo_wait;
297 
298 			return 1;
299 		}
300 	}
301 
302 	parport_write_control(pi->pardev->port, pi->saved_r2);
303 	parport_write_data(pi->pardev->port, pi->saved_r0);
304 
305 	return 0; // FAIL
306 }
307 
308 static void bpck6_deselect(struct pi_adapter *pi)
309 {
310 	if (mode_map[pi->mode] & 4)	// EPP
311 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_INIT,
312 							PARPORT_CONTROL_INIT);
313 	else								// PPC/ECP
314 		parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
315 							PARPORT_CONTROL_SELECT);
316 
317 	parport_write_data(pi->pardev->port, pi->saved_r0);
318 	parport_write_control(pi->pardev->port,
319 			pi->saved_r2 | PARPORT_CONTROL_SELECT);
320 	parport_write_control(pi->pardev->port, pi->saved_r2);
321 }
322 
323 static void bpck6_wr_extout(struct pi_adapter *pi, u8 regdata)
324 {
325 	bpck6_send_cmd(pi, REG_VERSION | ACCESS_REG | ACCESS_WRITE);
326 	bpck6_wr_data_byte(pi, (u8)((regdata & 0x03) << 6));
327 }
328 
329 static void bpck6_connect(struct pi_adapter *pi)
330 {
331 	dev_dbg(&pi->dev, "connect\n");
332 
333 	bpck6_open(pi);
334 	bpck6_wr_extout(pi, 0x3);
335 }
336 
337 static void bpck6_disconnect(struct pi_adapter *pi)
338 {
339 	dev_dbg(&pi->dev, "disconnect\n");
340 	bpck6_wr_extout(pi, 0x0);
341 	bpck6_deselect(pi);
342 }
343 
344 static int bpck6_test_port(struct pi_adapter *pi)   /* check for 8-bit port */
345 {
346 	dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n",
347 		pi->pardev->port->modes, pi->pardev->port->base);
348 
349 	/* look at the parport device to see what modes we can use */
350 	if (pi->pardev->port->modes & PARPORT_MODE_EPP)
351 		return 5; /* Can do EPP */
352 	if (pi->pardev->port->modes & PARPORT_MODE_TRISTATE)
353 		return 2;
354 	return 1; /* Just flat SPP */
355 }
356 
357 static int bpck6_probe_unit(struct pi_adapter *pi)
358 {
359 	int out, saved_mode;
360 
361 	dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port);
362 
363 	saved_mode = pi->mode;
364 	/*LOWER DOWN TO UNIDIRECTIONAL*/
365 	pi->mode = 0;
366 
367 	out = bpck6_open(pi);
368 
369 	dev_dbg(&pi->dev, "ppc_open returned %2x\n", out);
370 
371   	if(out)
372  	{
373 		bpck6_deselect(pi);
374 		dev_dbg(&pi->dev, "leaving probe\n");
375 		pi->mode = saved_mode;
376                return(1);
377 	}
378   	else
379   	{
380 		dev_dbg(&pi->dev, "Failed open\n");
381 		pi->mode = saved_mode;
382     		return(0);
383   	}
384 }
385 
386 static void bpck6_log_adapter(struct pi_adapter *pi)
387 {
388 	char *mode_string[5]=
389 		{"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
390 
391 	dev_info(&pi->dev, "Micro Solutions BACKPACK Drive unit %d at 0x%x, mode:%d (%s), delay %d\n",
392 		pi->unit, pi->port, pi->mode, mode_string[pi->mode], pi->delay);
393 }
394 
395 static struct pi_protocol bpck6 = {
396 	.owner		= THIS_MODULE,
397 	.name		= "bpck6",
398 	.max_mode	= 5,
399 	.epp_first	= 2, /* 2-5 use epp (need 8 ports) */
400 	.max_units	= 255,
401 	.write_regr	= bpck6_write_regr,
402 	.read_regr	= bpck6_read_regr,
403 	.write_block	= bpck6_write_block,
404 	.read_block	= bpck6_read_block,
405 	.connect	= bpck6_connect,
406 	.disconnect	= bpck6_disconnect,
407 	.test_port	= bpck6_test_port,
408 	.probe_unit	= bpck6_probe_unit,
409 	.log_adapter	= bpck6_log_adapter,
410 };
411 
412 MODULE_LICENSE("GPL");
413 MODULE_AUTHOR("Micro Solutions Inc.");
414 MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE");
415 module_pata_parport_driver(bpck6);
416