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