1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * (c) 1996-1998 Grant R. Guenther <grant@torque.net> 4 * 5 * bpck.c is a low-level protocol driver for the MicroSolutions 6 * "backpack" parallel port IDE adapter. 7 */ 8 9 #include <linux/module.h> 10 #include <linux/init.h> 11 #include <linux/delay.h> 12 #include <linux/kernel.h> 13 #include <linux/types.h> 14 #include <linux/wait.h> 15 #include <asm/io.h> 16 #include "pata_parport.h" 17 18 #undef r2 19 #undef w2 20 #undef PC 21 22 #define PC pi->private 23 #define r2() (PC=(in_p(2) & 0xff)) 24 #define w2(byte) {out_p(2,byte); PC = byte;} 25 #define t2(pat) {PC ^= pat; out_p(2,PC);} 26 #define e2() {PC &= 0xfe; out_p(2,PC);} 27 #define o2() {PC |= 1; out_p(2,PC);} 28 29 #define j44(l,h) (((l>>3)&0x7)|((l>>4)&0x8)|((h<<1)&0x70)|(h&0x80)) 30 31 /* 32 * cont = 0 - access the IDE register file 33 * cont = 1 - access the IDE command set 34 * cont = 2 - use internal bpck register addressing 35 */ 36 static int cont_map[3] = { 0x40, 0x48, 0 }; 37 38 static int bpck_read_regr(struct pi_adapter *pi, int cont, int regr) 39 { 40 int r, l, h; 41 42 r = regr + cont_map[cont]; 43 44 switch (pi->mode) { 45 case 0: 46 w0(r & 0xf); w0(r); t2(2); t2(4); 47 l = r1(); 48 t2(4); 49 h = r1(); 50 return j44(l, h); 51 case 1: 52 w0(r & 0xf); w0(r); t2(2); 53 e2(); t2(0x20); 54 t2(4); h = r0(); 55 t2(1); t2(0x20); 56 return h; 57 case 2: 58 case 3: 59 case 4: 60 w0(r); w2(9); w2(0); w2(0x20); 61 h = r4(); 62 w2(0); 63 return h; 64 65 } 66 return -1; 67 } 68 69 static void bpck_write_regr(struct pi_adapter *pi, int cont, int regr, int val) 70 { 71 int r; 72 73 r = regr + cont_map[cont]; 74 75 switch (pi->mode) { 76 case 0: 77 case 1: w0(r); 78 t2(2); 79 w0(val); 80 o2(); t2(4); t2(1); 81 break; 82 case 2: 83 case 3: 84 case 4: w0(r); w2(9); w2(0); 85 w0(val); w2(1); w2(3); w2(0); 86 break; 87 88 } 89 } 90 91 /* These macros access the bpck registers in native addressing */ 92 93 #define WR(r,v) bpck_write_regr(pi,2,r,v) 94 #define RR(r) (bpck_read_regr(pi,2,r)) 95 96 static void bpck_write_block(struct pi_adapter *pi, char *buf, int count) 97 { 98 int i; 99 100 switch (pi->mode) { 101 102 case 0: 103 WR(4, 0x40); 104 w0(0x40); t2(2); t2(1); 105 for (i = 0; i < count; i++) { 106 w0(buf[i]); 107 t2(4); 108 } 109 WR(4, 0); 110 break; 111 112 case 1: 113 WR(4, 0x50); 114 w0(0x40); t2(2); t2(1); 115 for (i = 0; i < count; i++) { 116 w0(buf[i]); 117 t2(4); 118 } 119 WR(4, 0x10); 120 break; 121 122 case 2: 123 WR(4, 0x48); 124 w0(0x40); w2(9); w2(0); w2(1); 125 for (i = 0; i < count; i++) 126 w4(buf[i]); 127 w2(0); 128 WR(4, 8); 129 break; 130 131 case 3: 132 WR(4, 0x48); 133 w0(0x40); w2(9); w2(0); w2(1); 134 for (i = 0; i < count / 2; i++) 135 w4w(((u16 *)buf)[i]); 136 w2(0); 137 WR(4, 8); 138 break; 139 140 case 4: 141 WR(4, 0x48); 142 w0(0x40); w2(9); w2(0); w2(1); 143 for (i = 0; i < count / 4; i++) 144 w4l(((u32 *)buf)[i]); 145 w2(0); 146 WR(4, 8); 147 break; 148 } 149 } 150 151 static void bpck_read_block(struct pi_adapter *pi, char *buf, int count) 152 { 153 int i, l, h; 154 155 switch (pi->mode) { 156 157 case 0: 158 WR(4, 0x40); 159 w0(0x40); t2(2); 160 for (i = 0; i < count; i++) { 161 t2(4); l = r1(); 162 t2(4); h = r1(); 163 buf[i] = j44(l, h); 164 } 165 WR(4, 0); 166 break; 167 168 case 1: 169 WR(4, 0x50); 170 w0(0x40); t2(2); t2(0x20); 171 for (i = 0; i < count; i++) { 172 t2(4); 173 buf[i] = r0(); 174 } 175 t2(1); t2(0x20); 176 WR(4, 0x10); 177 break; 178 179 case 2: 180 WR(4, 0x48); 181 w0(0x40); w2(9); w2(0); w2(0x20); 182 for (i = 0; i < count; i++) 183 buf[i] = r4(); 184 w2(0); 185 WR(4, 8); 186 break; 187 188 case 3: 189 WR(4, 0x48); 190 w0(0x40); w2(9); w2(0); w2(0x20); 191 for (i = 0; i < count / 2; i++) 192 ((u16 *)buf)[i] = r4w(); 193 w2(0); 194 WR(4, 8); 195 break; 196 197 case 4: 198 WR(4, 0x48); 199 w0(0x40); w2(9); w2(0); w2(0x20); 200 for (i = 0; i < count / 4; i++) 201 ((u32 *)buf)[i] = r4l(); 202 w2(0); 203 WR(4, 8); 204 break; 205 206 } 207 } 208 209 static int bpck_probe_unit(struct pi_adapter *pi) 210 { 211 int o1, o0, f7, id; 212 int t, s; 213 214 id = pi->unit; 215 s = 0; 216 w2(4); w2(0xe); r2(); t2(2); 217 o1 = r1()&0xf8; 218 o0 = r0(); 219 w0(255-id); w2(4); w0(id); 220 t2(8); t2(8); t2(8); 221 t2(2); t = r1()&0xf8; 222 f7 = ((id % 8) == 7); 223 if ((f7) || (t != o1)) { 224 t2(2); 225 s = r1() & 0xf8; 226 } 227 if ((t == o1) && ((!f7) || (s == o1))) { 228 w2(0x4c); w0(o0); 229 return 0; 230 } 231 t2(8); w0(0); t2(2); w2(0x4c); w0(o0); 232 return 1; 233 } 234 235 static void bpck_connect(struct pi_adapter *pi) 236 { 237 pi->saved_r0 = r0(); 238 w0(0xff-pi->unit); w2(4); w0(pi->unit); 239 t2(8); t2(8); t2(8); 240 t2(2); t2(2); 241 242 switch (pi->mode) { 243 case 0: 244 t2(8); WR(4, 0); 245 break; 246 case 1: 247 t2(8); WR(4, 0x10); 248 break; 249 case 2: 250 case 3: 251 case 4: 252 w2(0); WR(4, 8); 253 break; 254 } 255 256 WR(5,8); 257 258 /* 259 * Possibly wrong, purpose unknown (fiddle with ESS logic ???) 260 * if (pi->devtype == PI_PCD) { 261 */ 262 WR(0x46, 0x10); 263 WR(0x4c, 0x38); 264 WR(0x4d, 0x88); 265 WR(0x46, 0xa0); 266 WR(0x41, 0); 267 WR(0x4e, 8); 268 /* } */ 269 } 270 271 static void bpck_disconnect(struct pi_adapter *pi) 272 { 273 w0(0); 274 if (pi->mode >= 2) { 275 w2(9); w2(0); 276 } else { 277 t2(2); 278 } 279 w2(0x4c); w0(pi->saved_r0); 280 } 281 282 static void bpck_force_spp(struct pi_adapter *pi) 283 { 284 /* This fakes the EPP protocol to turn off EPP ... */ 285 pi->saved_r0 = r0(); 286 w0(0xff-pi->unit); w2(4); w0(pi->unit); 287 t2(8); t2(8); t2(8); 288 t2(2); t2(2); 289 290 w2(0); 291 w0(4); w2(9); w2(0); 292 w0(0); w2(1); w2(3); w2(0); 293 w0(0); w2(9); w2(0); 294 w2(0x4c); w0(pi->saved_r0); 295 } 296 297 #define TEST_LEN 16 298 299 static int bpck_test_proto(struct pi_adapter *pi) 300 { 301 int i, e, l, h, om; 302 char buf[TEST_LEN]; 303 304 bpck_force_spp(pi); 305 306 switch (pi->mode) { 307 308 case 0: 309 bpck_connect(pi); 310 WR(0x13, 0x7f); 311 w0(0x13); t2(2); 312 for (i = 0; i < TEST_LEN; i++) { 313 t2(4); l = r1(); 314 t2(4); h = r1(); 315 buf[i] = j44(l, h); 316 } 317 bpck_disconnect(pi); 318 break; 319 320 case 1: 321 bpck_connect(pi); 322 WR(0x13, 0x7f); 323 w0(0x13); t2(2); t2(0x20); 324 for (i = 0; i < TEST_LEN; i++) { 325 t2(4); 326 buf[i] = r0(); 327 } 328 t2(1); t2(0x20); 329 bpck_disconnect(pi); 330 break; 331 332 case 2: 333 case 3: 334 case 4: 335 om = pi->mode; 336 pi->mode = 0; 337 bpck_connect(pi); 338 WR(7, 3); 339 WR(4, 8); 340 bpck_disconnect(pi); 341 342 pi->mode = om; 343 bpck_connect(pi); 344 w0(0x13); w2(9); w2(1); w0(0); w2(3); w2(0); w2(0xe0); 345 346 switch (pi->mode) { 347 case 2: 348 for (i = 0; i < TEST_LEN; i++) 349 buf[i] = r4(); 350 break; 351 case 3: 352 for (i = 0; i < TEST_LEN / 2; i++) 353 ((u16 *)buf)[i] = r4w(); 354 break; 355 case 4: 356 for (i = 0; i < TEST_LEN / 4; i++) 357 ((u32 *)buf)[i] = r4l(); 358 break; 359 } 360 361 w2(0); 362 WR(7, 0); 363 bpck_disconnect(pi); 364 break; 365 366 } 367 368 dev_dbg(&pi->dev, "bpck: 0x%x unit %d mode %d: ", 369 pi->port, pi->unit, pi->mode); 370 print_hex_dump_debug("bpck: ", DUMP_PREFIX_NONE, TEST_LEN, 1, buf, 371 TEST_LEN, false); 372 373 e = 0; 374 for (i = 0; i < TEST_LEN; i++) { 375 if (buf[i] != i + 1) 376 e++; 377 } 378 379 return e; 380 } 381 382 static void bpck_read_eeprom(struct pi_adapter *pi, char *buf) 383 { 384 int i, j, k, p, v, f, om, od; 385 386 bpck_force_spp(pi); 387 388 om = pi->mode; od = pi->delay; 389 pi->mode = 0; pi->delay = 6; 390 391 bpck_connect(pi); 392 393 WR(4, 0); 394 for (i = 0; i < 64; i++) { 395 WR(6, 8); 396 WR(6, 0xc); 397 p = 0x100; 398 for (k = 0; k < 9; k++) { 399 f = (((i + 0x180) & p) != 0) * 2; 400 WR(6, f + 0xc); 401 WR(6, f + 0xd); 402 WR(6, f + 0xc); 403 p = (p >> 1); 404 } 405 for (j = 0; j < 2; j++) { 406 v = 0; 407 for (k = 0; k < 8; k++) { 408 WR(6, 0xc); 409 WR(6, 0xd); 410 WR(6, 0xc); 411 f = RR(0); 412 v = 2 * v + (f == 0x84); 413 } 414 buf[2 * i + 1 - j] = v; 415 } 416 } 417 WR(6, 8); 418 WR(6, 0); 419 WR(5, 8); 420 421 bpck_disconnect(pi); 422 423 if (om >= 2) { 424 bpck_connect(pi); 425 WR(7, 3); 426 WR(4, 8); 427 bpck_disconnect(pi); 428 } 429 430 pi->mode = om; pi->delay = od; 431 } 432 433 static int bpck_test_port(struct pi_adapter *pi) 434 { 435 int i, r, m; 436 437 /* Check for 8-bit port */ 438 w2(0x2c); i = r0(); w0(255-i); r = r0(); w0(i); 439 m = -1; 440 if (r == i) 441 m = 2; 442 if (r == (255-i)) 443 m = 0; 444 445 w2(0xc); 446 i = r0(); 447 w0(255-i); 448 r = r0(); 449 w0(i); 450 if (r != (255-i)) 451 m = -1; 452 453 if (m == 0) { 454 w2(6); 455 w2(0xc); 456 r = r0(); 457 w0(0xaa); 458 w0(r); 459 w0(0xaa); 460 } 461 if (m == 2) { 462 w2(0x26); 463 w2(0xc); 464 } 465 466 if (m == -1) 467 return 0; 468 469 return 5; 470 } 471 472 static void bpck_log_adapter(struct pi_adapter *pi) 473 { 474 char *mode_str[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" }; 475 char scratch[128]; 476 477 bpck_read_eeprom(pi,scratch); 478 print_hex_dump_bytes("bpck EEPROM: ", DUMP_PREFIX_NONE, scratch, 128); 479 dev_info(&pi->dev, 480 "backpack %8.8s unit %d at 0x%x, mode %d (%s), delay %d\n", 481 &scratch[110], pi->unit, pi->port, pi->mode, 482 mode_str[pi->mode], pi->delay); 483 } 484 485 static struct pi_protocol bpck = { 486 .owner = THIS_MODULE, 487 .name = "bpck", 488 .max_mode = 5, 489 .epp_first = 2, 490 .default_delay = 4, 491 .max_units = 255, 492 .write_regr = bpck_write_regr, 493 .read_regr = bpck_read_regr, 494 .write_block = bpck_write_block, 495 .read_block = bpck_read_block, 496 .connect = bpck_connect, 497 .disconnect = bpck_disconnect, 498 .test_port = bpck_test_port, 499 .probe_unit = bpck_probe_unit, 500 .test_proto = bpck_test_proto, 501 .log_adapter = bpck_log_adapter, 502 }; 503 504 MODULE_LICENSE("GPL"); 505 MODULE_AUTHOR("Grant R. Guenther <grant@torque.net>"); 506 MODULE_DESCRIPTION("MicroSolutions BACKPACK parallel port IDE adapter protocol driver"); 507 module_pata_parport_driver(bpck); 508