|
|
1.1.1.2 ! root 1: /* $Id: nec765.c,v 1.3 2009/08/29 21:12:47 fredette Exp $ */ 1.1 root 2: 3: /* ic/nec765.c - NEC 765 (and Intel 8207x) implementation: */ 4: 5: /* 6: * Copyright (c) 2006 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: #include <tme/common.h> 1.1.1.2 ! root 37: _TME_RCSID("$Id: nec765.c,v 1.3 2009/08/29 21:12:47 fredette Exp $"); 1.1 root 38: 39: /* includes: */ 40: #undef TME_NEC765_VERSION 41: #define TME_NEC765_VERSION TME_X_VERSION(0, 0) 42: #include <tme/ic/nec765.h> 43: #include <tme/generic/bus-device.h> 44: 45: /* macros: */ 46: 47: /* the different parts: */ 48: #define TME_NEC765_PART_NEC765 (0) 49: #define TME_NEC765_PART_I82072 (1) 50: #define TME_NEC765_PART_I82077 (2) 51: 52: /* register offsets. to keep things simple, all of the register 53: offsets are for the i82077: */ 54: #define TME_NEC765_I82077_REG_STATUS_A (0) 55: #define TME_NEC765_I82077_REG_STATUS_B (1) 56: #define TME_NEC765_I82077_REG_DOR (2) 57: #define TME_NEC765_I82077_REG_TCR (3) 58: #define TME_NEC765_REG_MSR (4) /* read-only */ 59: #define TME_NEC765_REG_DRS (4) /* write-only */ 60: #define TME_NEC765_REG_FIFO (5) 61: #define TME_NEC765_SIZ_REG_NEC765 (2) 62: #define TME_NEC765_SIZ_REG_I82072 (4) 63: #define TME_NEC765_SIZ_REG_I82077 (8) 64: 1.1.1.2 ! root 65: /* the DOR register: */ ! 66: #define TME_NEC765_I82077_DOR_REST TME_BIT(2) ! 67: #define TME_NEC765_I82077_DOR_DMA TME_BIT(3) ! 68: 1.1 root 69: /* the MSR register: */ 70: #define TME_NEC765_MSR_ACTIVE_A TME_BIT(0) /* drive A is active */ 71: #define TME_NEC765_MSR_ACTIVE_B TME_BIT(1) /* drive B is active */ 72: #define TME_NEC765_MSR_CB TME_BIT(4) /* controller is busy */ 73: #define TME_NEC765_MSR_NON_DMA TME_BIT(5) /* non-DMA mode */ 74: #define TME_NEC765_MSR_DIO TME_BIT(6) /* data register is input (CPU should read) */ 75: #define TME_NEC765_MSR_RQM TME_BIT(7) /* request for master */ 76: 77: /* the DRS register: */ 78: #define TME_NEC765_I82072_DRS_MODE_MASK (0x0f) 79: #define TME_NEC765_I82072_DRS_MODE_500KBPS (0x00) 80: #define TME_NEC765_I82072_DRS_MODE_300KBPS (0x01) 81: #define TME_NEC765_I82072_DRS_MODE_250KBPS (0x02) 82: #define TME_NEC765_I82072_DRS_MODE_125KBPS (0x03) 83: #define TME_NEC765_I82072_DRS_PLL TME_BIT(5) 84: #define TME_NEC765_I82072_DRS_POWER TME_BIT(6) 85: #define TME_NEC765_I82072_DRS_RESET TME_BIT(7) /* soft reset */ 86: 87: /* the ST0 register: */ 88: #define TME_NEC765_ST0_UC TME_BIT(4) /* unit check */ 89: #define TME_NEC765_ST0_NR TME_BIT(3) /* unit check */ 90: #define TME_NEC765_ST0_IC_MASK (0xc0) 91: #define TME_NEC765_ST0_IC_NORMAL (0x00) 92: #define TME_NEC765_ST0_IC_ABNORMAL (0x40) 93: #define TME_NEC765_ST0_IC_INVALID (0x80) 94: #define TME_NEC765_ST0_IC_ABNORMAL_POLL (0xc0) 95: 1.1.1.2 ! root 96: /* the ST3 register: */ ! 97: #define TME_NEC765_ST3_RDY TME_BIT(5) ! 98: 1.1 root 99: /* commands: */ 100: #define _TME_NEC765_CMD(nec765, mask, cmd) (((nec765)->tme_nec765_data_fifo[0] & (mask)) == (cmd)) 101: #define TME_NEC765_CMD_TRACK_READ(nec765) _TME_NEC765_CMD(nec765, 0x9f, 0x02) 102: #define TME_NEC765_CMD_FIX_DRIVE_DATA(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x03) 1.1.1.2 ! root 103: #define TME_NEC765_CMD_CALIBRATE(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x07) 1.1 root 104: #define TME_NEC765_CMD_CHECK_INTS(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x08) 105: #define TME_NEC765_CMD_I82072_CONFIG(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x13) 106: /* XXX FIXME - is this right? */ 107: #define TME_NEC765_CMD_I82072_DUMPREG(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x0e) 108: 109: /* this finishes a command: */ 110: #define TME_NEC765_CMD_DONE(nec765) \ 111: do { \ 112: (nec765)->tme_nec765_data_fifo_head = 0; \ 113: (nec765)->tme_nec765_status_fifo_tail = 0; \ 114: (nec765)->tme_nec765_status_fifo_head = 0; \ 115: } while (/* CONSTCOND */ 0) 116: 117: /* this sets a status byte: */ 118: #define TME_NEC765_STATUS(nec765, i, status) \ 119: do { \ 120: if ((i) == 0) { \ 121: TME_NEC765_CMD_DONE(nec765); \ 122: } \ 123: (nec765)->tme_nec765_status_fifo[(i)] = (status); \ 124: (nec765)->tme_nec765_status_fifo_head = (i) + 1; \ 125: } while (/* CONSTCOND */ 0) 126: 127: #define TME_NEC765_LOG_HANDLE(nec765) (&(nec765)->tme_nec765_element->tme_element_log_handle) 128: 129: /* structures: */ 130: 131: /* the card: */ 132: struct tme_nec765 { 133: 134: /* our simple bus device header: */ 135: struct tme_bus_device tme_nec765_device; 136: #define tme_nec765_element tme_nec765_device.tme_bus_device_element 137: 138: /* our socket: */ 139: struct tme_nec765_socket tme_nec765_socket; 140: #define tme_nec765_addr_shift tme_nec765_socket.tme_nec765_socket_addr_shift 141: #define tme_nec765_port_least_lane tme_nec765_socket.tme_nec765_socket_port_least_lane 142: 143: /* the mutex protecting the card: */ 144: tme_mutex_t tme_nec765_mutex; 145: 146: /* the part emulated: */ 147: unsigned int tme_nec765_part; 148: #define TME_NEC765_IS_NEC765(nec765) ((nec765)->tme_nec765_part == TME_NEC765_PART_NEC765) 149: #define TME_NEC765_IS_I82072(nec765) ((nec765)->tme_nec765_part == TME_NEC765_PART_I82072) 150: #define TME_NEC765_IS_I82077(nec765) ((nec765)->tme_nec765_part == TME_NEC765_PART_I82077) 151: 152: /* if the interrupt is currently asserted: */ 153: int tme_nec765_int_asserted; 154: 155: /* the data FIFO: */ 156: tme_uint8_t tme_nec765_data_fifo[512]; 157: unsigned int tme_nec765_data_fifo_head; 158: 159: /* the status FIFO: */ 160: tme_uint8_t tme_nec765_status_fifo[16]; 161: unsigned int tme_nec765_status_fifo_head; 162: unsigned int tme_nec765_status_fifo_tail; 1.1.1.2 ! root 163: ! 164: /* the i82077 DOR: */ ! 165: tme_uint8_t tme_nec765_i82077_dor; 1.1 root 166: }; 167: 168: /* this resets the NEC765: */ 169: static void 1.1.1.2 ! root 170: _tme_nec765_reset(struct tme_nec765 *nec765, int hard) 1.1 root 171: { 172: 173: /* reset the data FIFO: */ 174: nec765->tme_nec765_data_fifo_head = 0; 175: 176: /* reset the status FIFO: */ 177: nec765->tme_nec765_status_fifo_head = 0; 178: nec765->tme_nec765_status_fifo_tail = 0; 179: } 180: 181: /* the nec765 bus cycle handler: */ 182: static int 183: _tme_nec765_bus_cycle(void *_nec765, 184: struct tme_bus_cycle *cycle_init) 185: { 186: struct tme_nec765 *nec765; 187: tme_uint32_t address; 188: tme_uint32_t reg_offset; 189: tme_uint8_t value; 190: unsigned int fifo_head; 191: unsigned int fifo_tail; 192: const char *reg; 193: 194: /* recover our data structure: */ 195: nec765 = (struct tme_nec765 *) _nec765; 196: 197: /* this access must be for eight bits: */ 198: assert (cycle_init->tme_bus_cycle_size == 1); 199: 200: /* get the address: */ 201: address = cycle_init->tme_bus_cycle_address; 202: 203: /* lock the mutex: */ 204: tme_mutex_lock(&nec765->tme_nec765_mutex); 205: 206: /* set the register offset: */ 207: reg_offset 208: = (TME_NEC765_IS_I82077(nec765) 209: ? 0 210: : TME_NEC765_REG_MSR); 211: 212: /* if this is a write: */ 213: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { 214: 215: /* get value being written: */ 216: tme_bus_cycle_xfer_memory(cycle_init, 217: &value - address, 218: address); 219: 220: /* dispatch on the register: */ 221: switch (reg_offset + address) { 222: 223: /* the NetBSD fdc establish_chip_type() writes register number 224: two to distinguish an i82077 from an i82072. on an i82077, 225: this is a write of the DOR; on an i82072, this write gets 226: mapped to register number six here: */ 227: case TME_NEC765_REG_MSR + TME_NEC765_I82077_REG_DOR: 228: 229: /* alias this register number six to the DRS: */ 230: /* FALLTHROUGH */ 231: 232: case TME_NEC765_REG_DRS: 233: 234: /* if we need to soft-reset the chip: */ 235: if (value & TME_NEC765_I82072_DRS_RESET) { 236: _tme_nec765_reset(nec765, FALSE); 237: } 238: 239: reg = "DRS"; 240: break; 241: 242: case TME_NEC765_REG_FIFO: 243: 244: /* add to the data FIFO: */ 245: fifo_head = nec765->tme_nec765_data_fifo_head; 246: assert (fifo_head < sizeof(nec765->tme_nec765_data_fifo)); 247: nec765->tme_nec765_data_fifo[fifo_head] = value; 248: fifo_head++; 249: nec765->tme_nec765_data_fifo_head = fifo_head; 250: 251: /* if we're waiting for a command: */ 252: if (1) { 253: 254: /* the check interrupts command: */ 255: if (TME_NEC765_CMD_CHECK_INTS(nec765)) { 256: 257: /* the check interrupts command is a one-byte command: */ 258: if (fifo_head == sizeof(tme_uint8_t)) { 259: 260: if (nec765->tme_nec765_int_asserted) { 261: TME_NEC765_STATUS(nec765, 0, TME_NEC765_ST0_IC_NORMAL); 262: nec765->tme_nec765_int_asserted = FALSE; 263: } 264: else { 265: TME_NEC765_STATUS(nec765, 0, TME_NEC765_ST0_IC_INVALID); 266: } 1.1.1.2 ! root 267: TME_NEC765_STATUS(nec765, 1, 0x00); /* current cylinder */ 1.1 root 268: } 269: } 270: 271: /* the fix drive data command: */ 272: else if (TME_NEC765_CMD_FIX_DRIVE_DATA(nec765)) { 273: 274: /* the fix drive data command is three-byte command: */ 275: if (fifo_head == (sizeof(tme_uint8_t) * 3)) { 276: 277: /* no status: */ 278: TME_NEC765_CMD_DONE(nec765); 279: } 280: } 281: 282: /* the read track command: */ 283: else if (TME_NEC765_CMD_TRACK_READ(nec765)) { 284: 285: /* the read track command is an eight-byte command: */ 286: if (fifo_head == (sizeof(tme_uint8_t) * 8)) { 287: 288: /* return a unit check, drive not ready ST0: */ 289: TME_NEC765_STATUS(nec765, 0, (TME_NEC765_ST0_UC | TME_NEC765_ST0_NR)); 290: } 291: } 292: 1.1.1.2 ! root 293: /* the calibrate command: */ ! 294: else if (TME_NEC765_CMD_CALIBRATE(nec765)) { ! 295: ! 296: /* the calibrate command is a two-byte command: */ ! 297: if (fifo_head == (sizeof(tme_uint8_t) * 2)) { ! 298: ! 299: /* return an ST3: */ ! 300: TME_NEC765_STATUS(nec765, 0, ! 301: (TME_NEC765_IS_NEC765(nec765) ! 302: ? TME_NEC765_ST3_RDY ! 303: : !TME_NEC765_ST3_RDY)); ! 304: } ! 305: } ! 306: 1.1 root 307: /* the i82072 configure command: */ 308: else if (TME_NEC765_CMD_I82072_CONFIG(nec765)) { 309: 310: /* the i82072 configure command is a four-byte command: */ 311: if (fifo_head == (sizeof(tme_uint8_t) * 4)) { 312: 313: /* no status: */ 314: TME_NEC765_CMD_DONE(nec765); 315: } 316: } 317: 318: /* the i82072 dump registers command: */ 319: else if (TME_NEC765_CMD_I82072_DUMPREG(nec765)) { 320: 321: /* the dump registers command is a one-byte command: */ 322: if (fifo_head == sizeof(tme_uint8_t)) { 323: 324: /* XXX FIXME - this is supposed to return ten status 325: bytes, but we return none instead, which causes the 326: NetBSD fd.c to decide that there are no drives 327: attached: */ 328: TME_NEC765_CMD_DONE(nec765); 329: } 330: } 331: 332: /* otherwise, this is an unknown command: */ 333: else { 334: abort(); 335: } 336: } 337: 338: reg = "FIFO"; 339: break; 340: 1.1.1.2 ! root 341: case TME_NEC765_I82077_REG_DOR: ! 342: if ((value & TME_NEC765_I82077_DOR_REST) == 0) { ! 343: abort(); ! 344: } ! 345: nec765->tme_nec765_i82077_dor = value; ! 346: reg = "DOR"; ! 347: break; ! 348: 1.1 root 349: default: 350: abort(); 351: } 352: tme_log(TME_NEC765_LOG_HANDLE(nec765), 1000, TME_OK, 353: (TME_NEC765_LOG_HANDLE(nec765), 354: _("%s <- 0x%02x"), 355: reg, 356: value)); 357: } 358: 359: /* otherwise, this must be a read: */ 360: else { 361: assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); 362: 363: /* dispatch on the register: */ 364: switch (reg_offset + address) { 365: 366: /* the NetBSD fdc establish_chip_type() reads register number 367: two to distinguish an i82077 from an i82072. on an i82077, 368: this is a read of the DOR; on an i82072, this read gets 369: mapped to register number six here: */ 370: case TME_NEC765_REG_MSR + TME_NEC765_I82077_REG_DOR: 371: 372: /* alias this register number six to the MSR: */ 373: /* FALLTHROUGH */ 374: 375: case TME_NEC765_REG_MSR: 376: 377: /* if we are requesting the master: */ 378: if (1) { 379: 380: value = TME_NEC765_MSR_RQM; 381: 382: /* if we still have status to return: */ 383: if (nec765->tme_nec765_status_fifo_tail 384: < nec765->tme_nec765_status_fifo_head) { 1.1.1.2 ! root 385: value |= TME_NEC765_MSR_DIO; 1.1 root 386: } 387: } 388: 389: reg = "MSR"; 390: break; 391: 392: case TME_NEC765_REG_FIFO: 393: 394: /* if we're returning status: */ 395: fifo_tail = nec765->tme_nec765_status_fifo_tail; 396: if (fifo_tail 397: < nec765->tme_nec765_status_fifo_head) { 398: value = nec765->tme_nec765_status_fifo[fifo_tail]; 399: nec765->tme_nec765_status_fifo_tail = fifo_tail + 1; 400: reg = "FIFO (status)"; 401: } 402: 403: else { 404: abort(); 405: } 406: 407: break; 408: 1.1.1.2 ! root 409: case TME_NEC765_I82077_REG_DOR: ! 410: value = nec765->tme_nec765_i82077_dor; ! 411: reg = "DOR"; ! 412: break; ! 413: 1.1 root 414: default: 415: abort(); 416: } 417: 418: tme_log(TME_NEC765_LOG_HANDLE(nec765), 1000, TME_OK, 419: (TME_NEC765_LOG_HANDLE(nec765), 420: _("%s -> 0x%02x"), 421: reg, 422: value)); 423: 424: /* return the value: */ 425: tme_bus_cycle_xfer_memory(cycle_init, 426: &value - address, 427: address); 428: } 429: 430: /* unlock the mutex: */ 431: tme_mutex_unlock(&nec765->tme_nec765_mutex); 432: 433: /* no faults: */ 434: return (TME_OK); 435: } 436: 437: /* the nec765 TLB filler: */ 438: static int 439: _tme_nec765_tlb_fill(void *_nec765, 440: struct tme_bus_tlb *tlb, 441: tme_bus_addr_t address, 442: unsigned int cycles) 443: { 444: struct tme_nec765 *nec765; 445: 446: /* recover our data structures: */ 447: nec765 = (struct tme_nec765 *) _nec765; 448: 449: /* initialize the TLB entry: */ 450: tme_bus_tlb_initialize(tlb); 451: 452: /* this TLB entry covers only this address: */ 453: /* XXX FIXME - this is because we're lazy and don't want to write 454: the bus cycle handler to size cycles down to a byte: */ 455: tlb->tme_bus_tlb_addr_first = address; 456: tlb->tme_bus_tlb_addr_last = address; 457: 458: /* allow reading and writing: */ 459: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; 460: 461: /* our bus cycle handler: */ 462: tlb->tme_bus_tlb_cycle_private = nec765; 463: tlb->tme_bus_tlb_cycle = _tme_nec765_bus_cycle; 464: 465: return (TME_OK); 466: } 467: 468: /* the new nec765 function: */ 469: static int 470: _tme_nec765_new(struct tme_element *element, 471: const char * const *args, 472: const void *extra, 473: char **_output, 474: unsigned int part) 475: { 476: const struct tme_nec765_socket *socket; 477: struct tme_nec765_socket socket_real; 478: struct tme_nec765 *nec765; 479: int arg_i; 480: int usage; 481: const char *type; 482: 483: /* dispatch on our socket version: */ 484: socket = (const struct tme_nec765_socket *) extra; 485: if (socket == NULL) { 486: tme_output_append_error(_output, _("need an ic socket")); 487: return (ENXIO); 488: } 489: switch (socket->tme_nec765_socket_version) { 490: case TME_NEC765_SOCKET_0: 491: socket_real = *socket; 492: break; 493: default: 494: tme_output_append_error(_output, _("socket type")); 495: return (EOPNOTSUPP); 496: } 497: 498: /* check our arguments: */ 499: usage = 0; 500: arg_i = 1; 501: type = NULL; 502: for (;;) { 503: 504: if (0) { 505: } 506: 507: /* if we ran out of arguments: */ 508: else if (args[arg_i] == NULL) { 509: 510: break; 511: } 512: 513: /* otherwise this is a bad argument: */ 514: else { 515: tme_output_append_error(_output, 516: "%s %s, ", 517: args[arg_i], 518: _("unexpected")); 519: usage = TRUE; 520: break; 521: } 522: } 523: 524: if (usage) { 525: tme_output_append_error(_output, 526: "%s %s", 527: _("usage:"), 528: args[0]); 529: return (EINVAL); 530: } 531: 532: /* start the nec765 structure: */ 533: nec765 = tme_new0(struct tme_nec765, 1); 534: tme_mutex_init(&nec765->tme_nec765_mutex); 535: nec765->tme_nec765_part = part; 536: nec765->tme_nec765_socket = socket_real; 537: nec765->tme_nec765_element = element; 538: _tme_nec765_reset(nec765, TRUE); 539: 540: /* initialize our simple bus device descriptor: */ 541: nec765->tme_nec765_device.tme_bus_device_tlb_fill = _tme_nec765_tlb_fill; 542: nec765->tme_nec765_device.tme_bus_device_address_last 543: = (TME_NEC765_IS_NEC765(nec765) 544: ? TME_NEC765_SIZ_REG_NEC765 545: : TME_NEC765_IS_I82072(nec765) 546: ? TME_NEC765_SIZ_REG_I82072 547: : TME_NEC765_SIZ_REG_I82077) - 1; 548: 549: /* fill the element: */ 550: element->tme_element_private = nec765; 551: element->tme_element_connections_new = tme_bus_device_connections_new; 552: 553: return (TME_OK); 554: } 555: 556: TME_ELEMENT_X_NEW_DECL(tme_ic_,nec765,i82072) { 557: return (_tme_nec765_new(element, args, extra, _output, TME_NEC765_PART_I82072)); 558: } 1.1.1.2 ! root 559: ! 560: TME_ELEMENT_X_NEW_DECL(tme_ic_,nec765,i82077) { ! 561: return (_tme_nec765_new(element, args, extra, _output, TME_NEC765_PART_I82077)); ! 562: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.