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