]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - drivers/ata/pata_parport/bpck6.c
ata: pata_parport: Add missing protocol modules description
[thirdparty/kernel/stable.git] / drivers / ata / pata_parport / bpck6.c
CommitLineData
ec52d524 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4 2/*
ec52d524
DLM
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 */
1da177e4 11
1da177e4
LT
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
1da177e4 15#include <linux/types.h>
1da177e4 16#include <linux/parport.h>
fe027ff9 17#include "pata_parport.h"
1da177e4 18
a427ad2a
OZ
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
140b2603
DLM
60static int mode_map[] = { PPCMODE_UNI_FW, PPCMODE_BI_FW, PPCMODE_EPP_BYTE,
61 PPCMODE_EPP_WORD, PPCMODE_EPP_DWORD };
a427ad2a 62
b0406278
OZ
63static 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
57419737
OZ
81static 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
7cb35296
OZ
115static 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
882ff0ca 133static int bpck6_read_regr(struct pi_adapter *pi, int cont, int reg)
1da177e4 134{
2ee865ce
OZ
135 u8 port = cont ? reg | 8 : reg;
136
b0406278 137 bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_READ);
57419737 138 return bpck6_rd_data_byte(pi);
1da177e4
LT
139}
140
882ff0ca 141static void bpck6_write_regr(struct pi_adapter *pi, int cont, int reg, int val)
1da177e4 142{
ba98c566
OZ
143 u8 port = cont ? reg | 8 : reg;
144
b0406278 145 bpck6_send_cmd(pi, port | ACCESS_PORT | ACCESS_WRITE);
7cb35296 146 bpck6_wr_data_byte(pi, val);
1da177e4
LT
147}
148
144e7799
OZ
149static 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
882ff0ca 159static void bpck6_write_block(struct pi_adapter *pi, char *buf, int len)
1da177e4 160{
99c40a70
OZ
161 u8 this, last;
162
b0406278 163 bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
7cb35296
OZ
164 bpck6_wr_data_byte(pi, (u8)len);
165 bpck6_wr_data_byte(pi, (u8)(len >> 8));
166 bpck6_wr_data_byte(pi, 0);
4e21c863 167
b0406278
OZ
168 bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
169 bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_WRITE);
99c40a70
OZ
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:
b0406278 182 bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_FASTWR);
99c40a70
OZ
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);
b0406278 206 bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_FASTWR);
99c40a70
OZ
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);
144e7799 211 bpck6_wait_for_fifo(pi);
99c40a70
OZ
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);
144e7799 216 bpck6_wait_for_fifo(pi);
99c40a70
OZ
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);
144e7799 221 bpck6_wait_for_fifo(pi);
99c40a70
OZ
222 break;
223 }
224
b0406278 225 bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
1da177e4
LT
226}
227
882ff0ca 228static void bpck6_read_block(struct pi_adapter *pi, char *buf, int len)
1da177e4 229{
b0406278 230 bpck6_send_cmd(pi, REG_BLKSIZE | ACCESS_REG | ACCESS_WRITE);
7cb35296
OZ
231 bpck6_wr_data_byte(pi, (u8)len);
232 bpck6_wr_data_byte(pi, (u8)(len >> 8));
233 bpck6_wr_data_byte(pi, 0);
3967def8 234
b0406278
OZ
235 bpck6_send_cmd(pi, CMD_PREFIX_SET | PREFIX_IO16 | PREFIX_BLK);
236 bpck6_send_cmd(pi, ATA_REG_DATA | ACCESS_PORT | ACCESS_READ);
db24d743
OZ
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
b0406278 285 bpck6_send_cmd(pi, CMD_PREFIX_RESET | PREFIX_IO16 | PREFIX_BLK);
1da177e4
LT
286}
287
7c97e468
OZ
288static int bpck6_open(struct pi_adapter *pi)
289{
cad40b2a
OZ
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;
083ad04d
OZ
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
ec52d524
DLM
327 if (i & 4) {
328 /* EPP */
083ad04d
OZ
329 parport_frob_control(pi->pardev->port,
330 PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT, 0);
ec52d524
DLM
331 } else {
332 /* PPC/ECP */
083ad04d 333 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT, 0);
ec52d524 334 }
083ad04d
OZ
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;
7c97e468 346
083ad04d 347fail:
cad40b2a
OZ
348 parport_write_control(pi->pardev->port, pi->saved_r2);
349 parport_write_data(pi->pardev->port, pi->saved_r0);
7c97e468 350
ec52d524 351 return 0;
7c97e468
OZ
352}
353
82e16f82
OZ
354static void bpck6_deselect(struct pi_adapter *pi)
355{
ec52d524
DLM
356 if (mode_map[pi->mode] & 4) {
357 /* EPP */
82e16f82 358 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_INIT,
ec52d524
DLM
359 PARPORT_CONTROL_INIT);
360 } else {
361 /* PPC/ECP */
82e16f82 362 parport_frob_control(pi->pardev->port, PARPORT_CONTROL_SELECT,
ec52d524
DLM
363 PARPORT_CONTROL_SELECT);
364 }
82e16f82
OZ
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
9e75963a
OZ
372static void bpck6_wr_extout(struct pi_adapter *pi, u8 regdata)
373{
b0406278 374 bpck6_send_cmd(pi, REG_VERSION | ACCESS_REG | ACCESS_WRITE);
7cb35296 375 bpck6_wr_data_byte(pi, (u8)((regdata & 0x03) << 6));
9e75963a
OZ
376}
377
882ff0ca 378static void bpck6_connect(struct pi_adapter *pi)
1da177e4 379{
5f1145d8 380 dev_dbg(&pi->dev, "connect\n");
1da177e4 381
7c97e468 382 bpck6_open(pi);
9e75963a 383 bpck6_wr_extout(pi, 0x3);
1da177e4
LT
384}
385
882ff0ca 386static void bpck6_disconnect(struct pi_adapter *pi)
1da177e4 387{
5f1145d8 388 dev_dbg(&pi->dev, "disconnect\n");
9e75963a 389 bpck6_wr_extout(pi, 0x0);
82e16f82 390 bpck6_deselect(pi);
1da177e4
LT
391}
392
ec52d524
DLM
393/* check for 8-bit port */
394static int bpck6_test_port(struct pi_adapter *pi)
1da177e4 395{
5f1145d8 396 dev_dbg(&pi->dev, "PARPORT indicates modes=%x for lp=0x%lx\n",
62972285 397 pi->pardev->port->modes, pi->pardev->port->base);
1da177e4 398
62972285
OZ
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)
1da177e4 403 return 2;
62972285 404 return 1; /* Just flat SPP */
1da177e4
LT
405}
406
882ff0ca 407static int bpck6_probe_unit(struct pi_adapter *pi)
1da177e4 408{
baa6f0f8 409 int out, saved_mode;
1da177e4 410
5f1145d8 411 dev_dbg(&pi->dev, "PROBE UNIT %x on port:%x\n", pi->unit, pi->port);
1da177e4 412
baa6f0f8 413 saved_mode = pi->mode;
1da177e4 414 /*LOWER DOWN TO UNIDIRECTIONAL*/
baa6f0f8 415 pi->mode = 0;
1da177e4 416
7c97e468 417 out = bpck6_open(pi);
1da177e4 418
5f1145d8 419 dev_dbg(&pi->dev, "ppc_open returned %2x\n", out);
1da177e4 420
ec52d524 421 if (out) {
82e16f82 422 bpck6_deselect(pi);
5f1145d8 423 dev_dbg(&pi->dev, "leaving probe\n");
baa6f0f8 424 pi->mode = saved_mode;
ec52d524 425 return 1;
1da177e4 426 }
ec52d524
DLM
427
428 dev_dbg(&pi->dev, "Failed open\n");
429 pi->mode = saved_mode;
430
431 return 0;
1da177e4
LT
432}
433
5b77db9c 434static void bpck6_log_adapter(struct pi_adapter *pi)
1da177e4 435{
ec52d524 436 char *mode_string[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" };
1da177e4 437
ec52d524
DLM
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);
1da177e4
LT
441}
442
1da177e4
LT
443static 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,
1da177e4
LT
458};
459
1da177e4
LT
460MODULE_LICENSE("GPL");
461MODULE_AUTHOR("Micro Solutions Inc.");
cec148c2
DLM
462MODULE_DESCRIPTION("Micro Solutions BACKPACK parallel port IDE adapter "
463 "(version 6 drives) protocol driver");
2c08ec0f 464module_pata_parport_driver(bpck6);