|
|
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.