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