|
|
1.1 ! root 1: /* $Id: nec765.c,v 1.2 2007/01/07 23:31:17 fredette Exp $ */ ! 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> ! 37: _TME_RCSID("$Id: nec765.c,v 1.2 2007/01/07 23:31:17 fredette Exp $"); ! 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: ! 65: /* the MSR register: */ ! 66: #define TME_NEC765_MSR_ACTIVE_A TME_BIT(0) /* drive A is active */ ! 67: #define TME_NEC765_MSR_ACTIVE_B TME_BIT(1) /* drive B is active */ ! 68: #define TME_NEC765_MSR_CB TME_BIT(4) /* controller is busy */ ! 69: #define TME_NEC765_MSR_NON_DMA TME_BIT(5) /* non-DMA mode */ ! 70: #define TME_NEC765_MSR_DIO TME_BIT(6) /* data register is input (CPU should read) */ ! 71: #define TME_NEC765_MSR_RQM TME_BIT(7) /* request for master */ ! 72: ! 73: /* the DRS register: */ ! 74: #define TME_NEC765_I82072_DRS_MODE_MASK (0x0f) ! 75: #define TME_NEC765_I82072_DRS_MODE_500KBPS (0x00) ! 76: #define TME_NEC765_I82072_DRS_MODE_300KBPS (0x01) ! 77: #define TME_NEC765_I82072_DRS_MODE_250KBPS (0x02) ! 78: #define TME_NEC765_I82072_DRS_MODE_125KBPS (0x03) ! 79: #define TME_NEC765_I82072_DRS_PLL TME_BIT(5) ! 80: #define TME_NEC765_I82072_DRS_POWER TME_BIT(6) ! 81: #define TME_NEC765_I82072_DRS_RESET TME_BIT(7) /* soft reset */ ! 82: ! 83: /* the ST0 register: */ ! 84: #define TME_NEC765_ST0_UC TME_BIT(4) /* unit check */ ! 85: #define TME_NEC765_ST0_NR TME_BIT(3) /* unit check */ ! 86: #define TME_NEC765_ST0_IC_MASK (0xc0) ! 87: #define TME_NEC765_ST0_IC_NORMAL (0x00) ! 88: #define TME_NEC765_ST0_IC_ABNORMAL (0x40) ! 89: #define TME_NEC765_ST0_IC_INVALID (0x80) ! 90: #define TME_NEC765_ST0_IC_ABNORMAL_POLL (0xc0) ! 91: ! 92: /* commands: */ ! 93: #define _TME_NEC765_CMD(nec765, mask, cmd) (((nec765)->tme_nec765_data_fifo[0] & (mask)) == (cmd)) ! 94: #define TME_NEC765_CMD_TRACK_READ(nec765) _TME_NEC765_CMD(nec765, 0x9f, 0x02) ! 95: #define TME_NEC765_CMD_FIX_DRIVE_DATA(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x03) ! 96: #define TME_NEC765_CMD_CHECK_INTS(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x08) ! 97: #define TME_NEC765_CMD_I82072_CONFIG(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x13) ! 98: /* XXX FIXME - is this right? */ ! 99: #define TME_NEC765_CMD_I82072_DUMPREG(nec765) _TME_NEC765_CMD(nec765, 0xff, 0x0e) ! 100: ! 101: /* this finishes a command: */ ! 102: #define TME_NEC765_CMD_DONE(nec765) \ ! 103: do { \ ! 104: (nec765)->tme_nec765_data_fifo_head = 0; \ ! 105: (nec765)->tme_nec765_status_fifo_tail = 0; \ ! 106: (nec765)->tme_nec765_status_fifo_head = 0; \ ! 107: } while (/* CONSTCOND */ 0) ! 108: ! 109: /* this sets a status byte: */ ! 110: #define TME_NEC765_STATUS(nec765, i, status) \ ! 111: do { \ ! 112: if ((i) == 0) { \ ! 113: TME_NEC765_CMD_DONE(nec765); \ ! 114: } \ ! 115: (nec765)->tme_nec765_status_fifo[(i)] = (status); \ ! 116: (nec765)->tme_nec765_status_fifo_head = (i) + 1; \ ! 117: } while (/* CONSTCOND */ 0) ! 118: ! 119: #define TME_NEC765_LOG_HANDLE(nec765) (&(nec765)->tme_nec765_element->tme_element_log_handle) ! 120: ! 121: /* structures: */ ! 122: ! 123: /* the card: */ ! 124: struct tme_nec765 { ! 125: ! 126: /* our simple bus device header: */ ! 127: struct tme_bus_device tme_nec765_device; ! 128: #define tme_nec765_element tme_nec765_device.tme_bus_device_element ! 129: ! 130: /* our socket: */ ! 131: struct tme_nec765_socket tme_nec765_socket; ! 132: #define tme_nec765_addr_shift tme_nec765_socket.tme_nec765_socket_addr_shift ! 133: #define tme_nec765_port_least_lane tme_nec765_socket.tme_nec765_socket_port_least_lane ! 134: ! 135: /* the mutex protecting the card: */ ! 136: tme_mutex_t tme_nec765_mutex; ! 137: ! 138: /* the part emulated: */ ! 139: unsigned int tme_nec765_part; ! 140: #define TME_NEC765_IS_NEC765(nec765) ((nec765)->tme_nec765_part == TME_NEC765_PART_NEC765) ! 141: #define TME_NEC765_IS_I82072(nec765) ((nec765)->tme_nec765_part == TME_NEC765_PART_I82072) ! 142: #define TME_NEC765_IS_I82077(nec765) ((nec765)->tme_nec765_part == TME_NEC765_PART_I82077) ! 143: ! 144: /* if the interrupt is currently asserted: */ ! 145: int tme_nec765_int_asserted; ! 146: ! 147: /* the data FIFO: */ ! 148: tme_uint8_t tme_nec765_data_fifo[512]; ! 149: unsigned int tme_nec765_data_fifo_head; ! 150: ! 151: /* the status FIFO: */ ! 152: tme_uint8_t tme_nec765_status_fifo[16]; ! 153: unsigned int tme_nec765_status_fifo_head; ! 154: unsigned int tme_nec765_status_fifo_tail; ! 155: }; ! 156: ! 157: /* this resets the NEC765: */ ! 158: static void ! 159: _tme_nec765_reset(struct tme_nec765 *nec765, int soft) ! 160: { ! 161: ! 162: /* reset the data FIFO: */ ! 163: nec765->tme_nec765_data_fifo_head = 0; ! 164: ! 165: /* reset the status FIFO: */ ! 166: nec765->tme_nec765_status_fifo_head = 0; ! 167: nec765->tme_nec765_status_fifo_tail = 0; ! 168: } ! 169: ! 170: /* the nec765 bus cycle handler: */ ! 171: static int ! 172: _tme_nec765_bus_cycle(void *_nec765, ! 173: struct tme_bus_cycle *cycle_init) ! 174: { ! 175: struct tme_nec765 *nec765; ! 176: tme_uint32_t address; ! 177: tme_uint32_t reg_offset; ! 178: tme_uint8_t value; ! 179: unsigned int fifo_head; ! 180: unsigned int fifo_tail; ! 181: const char *reg; ! 182: ! 183: /* recover our data structure: */ ! 184: nec765 = (struct tme_nec765 *) _nec765; ! 185: ! 186: /* this access must be for eight bits: */ ! 187: assert (cycle_init->tme_bus_cycle_size == 1); ! 188: ! 189: /* get the address: */ ! 190: address = cycle_init->tme_bus_cycle_address; ! 191: ! 192: /* lock the mutex: */ ! 193: tme_mutex_lock(&nec765->tme_nec765_mutex); ! 194: ! 195: /* set the register offset: */ ! 196: reg_offset ! 197: = (TME_NEC765_IS_I82077(nec765) ! 198: ? 0 ! 199: : TME_NEC765_REG_MSR); ! 200: ! 201: /* if this is a write: */ ! 202: if (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) { ! 203: ! 204: /* get value being written: */ ! 205: tme_bus_cycle_xfer_memory(cycle_init, ! 206: &value - address, ! 207: address); ! 208: ! 209: /* dispatch on the register: */ ! 210: switch (reg_offset + address) { ! 211: ! 212: /* the NetBSD fdc establish_chip_type() writes register number ! 213: two to distinguish an i82077 from an i82072. on an i82077, ! 214: this is a write of the DOR; on an i82072, this write gets ! 215: mapped to register number six here: */ ! 216: case TME_NEC765_REG_MSR + TME_NEC765_I82077_REG_DOR: ! 217: ! 218: /* alias this register number six to the DRS: */ ! 219: /* FALLTHROUGH */ ! 220: ! 221: case TME_NEC765_REG_DRS: ! 222: ! 223: /* if we need to soft-reset the chip: */ ! 224: if (value & TME_NEC765_I82072_DRS_RESET) { ! 225: _tme_nec765_reset(nec765, FALSE); ! 226: } ! 227: ! 228: reg = "DRS"; ! 229: break; ! 230: ! 231: case TME_NEC765_REG_FIFO: ! 232: ! 233: /* add to the data FIFO: */ ! 234: fifo_head = nec765->tme_nec765_data_fifo_head; ! 235: assert (fifo_head < sizeof(nec765->tme_nec765_data_fifo)); ! 236: nec765->tme_nec765_data_fifo[fifo_head] = value; ! 237: fifo_head++; ! 238: nec765->tme_nec765_data_fifo_head = fifo_head; ! 239: ! 240: /* if we're waiting for a command: */ ! 241: if (1) { ! 242: ! 243: /* the check interrupts command: */ ! 244: if (TME_NEC765_CMD_CHECK_INTS(nec765)) { ! 245: ! 246: /* the check interrupts command is a one-byte command: */ ! 247: if (fifo_head == sizeof(tme_uint8_t)) { ! 248: ! 249: if (nec765->tme_nec765_int_asserted) { ! 250: TME_NEC765_STATUS(nec765, 0, TME_NEC765_ST0_IC_NORMAL); ! 251: nec765->tme_nec765_int_asserted = FALSE; ! 252: } ! 253: else { ! 254: TME_NEC765_STATUS(nec765, 0, TME_NEC765_ST0_IC_INVALID); ! 255: } ! 256: } ! 257: } ! 258: ! 259: /* the fix drive data command: */ ! 260: else if (TME_NEC765_CMD_FIX_DRIVE_DATA(nec765)) { ! 261: ! 262: /* the fix drive data command is three-byte command: */ ! 263: if (fifo_head == (sizeof(tme_uint8_t) * 3)) { ! 264: ! 265: /* no status: */ ! 266: TME_NEC765_CMD_DONE(nec765); ! 267: } ! 268: } ! 269: ! 270: /* the read track command: */ ! 271: else if (TME_NEC765_CMD_TRACK_READ(nec765)) { ! 272: ! 273: /* the read track command is an eight-byte command: */ ! 274: if (fifo_head == (sizeof(tme_uint8_t) * 8)) { ! 275: ! 276: /* return a unit check, drive not ready ST0: */ ! 277: TME_NEC765_STATUS(nec765, 0, (TME_NEC765_ST0_UC | TME_NEC765_ST0_NR)); ! 278: } ! 279: } ! 280: ! 281: /* the i82072 configure command: */ ! 282: else if (TME_NEC765_CMD_I82072_CONFIG(nec765)) { ! 283: ! 284: /* the i82072 configure command is a four-byte command: */ ! 285: if (fifo_head == (sizeof(tme_uint8_t) * 4)) { ! 286: ! 287: /* no status: */ ! 288: TME_NEC765_CMD_DONE(nec765); ! 289: } ! 290: } ! 291: ! 292: /* the i82072 dump registers command: */ ! 293: else if (TME_NEC765_CMD_I82072_DUMPREG(nec765)) { ! 294: ! 295: /* the dump registers command is a one-byte command: */ ! 296: if (fifo_head == sizeof(tme_uint8_t)) { ! 297: ! 298: /* XXX FIXME - this is supposed to return ten status ! 299: bytes, but we return none instead, which causes the ! 300: NetBSD fd.c to decide that there are no drives ! 301: attached: */ ! 302: TME_NEC765_CMD_DONE(nec765); ! 303: } ! 304: } ! 305: ! 306: /* otherwise, this is an unknown command: */ ! 307: else { ! 308: abort(); ! 309: } ! 310: } ! 311: ! 312: reg = "FIFO"; ! 313: break; ! 314: ! 315: default: ! 316: abort(); ! 317: } ! 318: tme_log(TME_NEC765_LOG_HANDLE(nec765), 1000, TME_OK, ! 319: (TME_NEC765_LOG_HANDLE(nec765), ! 320: _("%s <- 0x%02x"), ! 321: reg, ! 322: value)); ! 323: } ! 324: ! 325: /* otherwise, this must be a read: */ ! 326: else { ! 327: assert (cycle_init->tme_bus_cycle_type == TME_BUS_CYCLE_READ); ! 328: ! 329: /* dispatch on the register: */ ! 330: switch (reg_offset + address) { ! 331: ! 332: /* the NetBSD fdc establish_chip_type() reads register number ! 333: two to distinguish an i82077 from an i82072. on an i82077, ! 334: this is a read of the DOR; on an i82072, this read gets ! 335: mapped to register number six here: */ ! 336: case TME_NEC765_REG_MSR + TME_NEC765_I82077_REG_DOR: ! 337: ! 338: /* alias this register number six to the MSR: */ ! 339: /* FALLTHROUGH */ ! 340: ! 341: case TME_NEC765_REG_MSR: ! 342: ! 343: /* if we are requesting the master: */ ! 344: if (1) { ! 345: ! 346: value = TME_NEC765_MSR_RQM; ! 347: ! 348: /* if we still have status to return: */ ! 349: if (nec765->tme_nec765_status_fifo_tail ! 350: < nec765->tme_nec765_status_fifo_head) { ! 351: value |= (TME_NEC765_MSR_DIO ! 352: | TME_NEC765_MSR_CB); ! 353: } ! 354: } ! 355: ! 356: reg = "MSR"; ! 357: break; ! 358: ! 359: case TME_NEC765_REG_FIFO: ! 360: ! 361: /* if we're returning status: */ ! 362: fifo_tail = nec765->tme_nec765_status_fifo_tail; ! 363: if (fifo_tail ! 364: < nec765->tme_nec765_status_fifo_head) { ! 365: value = nec765->tme_nec765_status_fifo[fifo_tail]; ! 366: nec765->tme_nec765_status_fifo_tail = fifo_tail + 1; ! 367: reg = "FIFO (status)"; ! 368: } ! 369: ! 370: else { ! 371: abort(); ! 372: } ! 373: ! 374: break; ! 375: ! 376: default: ! 377: abort(); ! 378: } ! 379: ! 380: tme_log(TME_NEC765_LOG_HANDLE(nec765), 1000, TME_OK, ! 381: (TME_NEC765_LOG_HANDLE(nec765), ! 382: _("%s -> 0x%02x"), ! 383: reg, ! 384: value)); ! 385: ! 386: /* return the value: */ ! 387: tme_bus_cycle_xfer_memory(cycle_init, ! 388: &value - address, ! 389: address); ! 390: } ! 391: ! 392: /* unlock the mutex: */ ! 393: tme_mutex_unlock(&nec765->tme_nec765_mutex); ! 394: ! 395: /* no faults: */ ! 396: return (TME_OK); ! 397: } ! 398: ! 399: /* the nec765 TLB filler: */ ! 400: static int ! 401: _tme_nec765_tlb_fill(void *_nec765, ! 402: struct tme_bus_tlb *tlb, ! 403: tme_bus_addr_t address, ! 404: unsigned int cycles) ! 405: { ! 406: struct tme_nec765 *nec765; ! 407: ! 408: /* recover our data structures: */ ! 409: nec765 = (struct tme_nec765 *) _nec765; ! 410: ! 411: /* initialize the TLB entry: */ ! 412: tme_bus_tlb_initialize(tlb); ! 413: ! 414: /* this TLB entry covers only this address: */ ! 415: /* XXX FIXME - this is because we're lazy and don't want to write ! 416: the bus cycle handler to size cycles down to a byte: */ ! 417: tlb->tme_bus_tlb_addr_first = address; ! 418: tlb->tme_bus_tlb_addr_last = address; ! 419: ! 420: /* allow reading and writing: */ ! 421: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE; ! 422: ! 423: /* our bus cycle handler: */ ! 424: tlb->tme_bus_tlb_cycle_private = nec765; ! 425: tlb->tme_bus_tlb_cycle = _tme_nec765_bus_cycle; ! 426: ! 427: return (TME_OK); ! 428: } ! 429: ! 430: /* the new nec765 function: */ ! 431: static int ! 432: _tme_nec765_new(struct tme_element *element, ! 433: const char * const *args, ! 434: const void *extra, ! 435: char **_output, ! 436: unsigned int part) ! 437: { ! 438: const struct tme_nec765_socket *socket; ! 439: struct tme_nec765_socket socket_real; ! 440: struct tme_nec765 *nec765; ! 441: int arg_i; ! 442: int usage; ! 443: const char *type; ! 444: ! 445: /* dispatch on our socket version: */ ! 446: socket = (const struct tme_nec765_socket *) extra; ! 447: if (socket == NULL) { ! 448: tme_output_append_error(_output, _("need an ic socket")); ! 449: return (ENXIO); ! 450: } ! 451: switch (socket->tme_nec765_socket_version) { ! 452: case TME_NEC765_SOCKET_0: ! 453: socket_real = *socket; ! 454: break; ! 455: default: ! 456: tme_output_append_error(_output, _("socket type")); ! 457: return (EOPNOTSUPP); ! 458: } ! 459: ! 460: /* check our arguments: */ ! 461: usage = 0; ! 462: arg_i = 1; ! 463: type = NULL; ! 464: for (;;) { ! 465: ! 466: if (0) { ! 467: } ! 468: ! 469: /* if we ran out of arguments: */ ! 470: else if (args[arg_i] == NULL) { ! 471: ! 472: break; ! 473: } ! 474: ! 475: /* otherwise this is a bad argument: */ ! 476: else { ! 477: tme_output_append_error(_output, ! 478: "%s %s, ", ! 479: args[arg_i], ! 480: _("unexpected")); ! 481: usage = TRUE; ! 482: break; ! 483: } ! 484: } ! 485: ! 486: if (usage) { ! 487: tme_output_append_error(_output, ! 488: "%s %s", ! 489: _("usage:"), ! 490: args[0]); ! 491: return (EINVAL); ! 492: } ! 493: ! 494: /* start the nec765 structure: */ ! 495: nec765 = tme_new0(struct tme_nec765, 1); ! 496: tme_mutex_init(&nec765->tme_nec765_mutex); ! 497: nec765->tme_nec765_part = part; ! 498: nec765->tme_nec765_socket = socket_real; ! 499: nec765->tme_nec765_element = element; ! 500: _tme_nec765_reset(nec765, TRUE); ! 501: ! 502: /* initialize our simple bus device descriptor: */ ! 503: nec765->tme_nec765_device.tme_bus_device_tlb_fill = _tme_nec765_tlb_fill; ! 504: nec765->tme_nec765_device.tme_bus_device_address_last ! 505: = (TME_NEC765_IS_NEC765(nec765) ! 506: ? TME_NEC765_SIZ_REG_NEC765 ! 507: : TME_NEC765_IS_I82072(nec765) ! 508: ? TME_NEC765_SIZ_REG_I82072 ! 509: : TME_NEC765_SIZ_REG_I82077) - 1; ! 510: ! 511: /* fill the element: */ ! 512: element->tme_element_private = nec765; ! 513: element->tme_element_connections_new = tme_bus_device_connections_new; ! 514: ! 515: return (TME_OK); ! 516: } ! 517: ! 518: TME_ELEMENT_X_NEW_DECL(tme_ic_,nec765,i82072) { ! 519: return (_tme_nec765_new(element, args, extra, _output, TME_NEC765_PART_I82072)); ! 520: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.