|
|
1.1 root 1: /*
2: * QEMU Sparc SLAVIO aux io port emulation
1.1.1.4 root 3: *
1.1 root 4: * Copyright (c) 2005 Fabrice Bellard
1.1.1.4 root 5: *
1.1 root 6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
1.1.1.6 root 24:
1.1.1.4 root 25: #include "sysemu.h"
1.1.1.6 root 26: #include "sysbus.h"
1.1.1.4 root 27:
1.1 root 28: /* debug misc */
29: //#define DEBUG_MISC
30:
31: /*
32: * This is the auxio port, chip control and system control part of
33: * chip STP2001 (Slave I/O), also produced as NCR89C105. See
34: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
35: *
36: * This also includes the PMC CPU idle controller.
37: */
38:
39: #ifdef DEBUG_MISC
1.1.1.6 root 40: #define MISC_DPRINTF(fmt, ...) \
41: do { printf("MISC: " fmt , ## __VA_ARGS__); } while (0)
1.1 root 42: #else
1.1.1.6 root 43: #define MISC_DPRINTF(fmt, ...)
1.1 root 44: #endif
45:
46: typedef struct MiscState {
1.1.1.6 root 47: SysBusDevice busdev;
1.1.1.4 root 48: qemu_irq irq;
1.1.1.7 ! root 49: uint32_t dummy;
1.1 root 50: uint8_t config;
51: uint8_t aux1, aux2;
1.1.1.4 root 52: uint8_t diag, mctrl;
1.1.1.7 ! root 53: uint8_t sysctrl;
1.1.1.4 root 54: uint16_t leds;
1.1.1.5 root 55: qemu_irq fdc_tc;
1.1 root 56: } MiscState;
57:
1.1.1.6 root 58: typedef struct APCState {
59: SysBusDevice busdev;
60: qemu_irq cpu_halt;
61: } APCState;
62:
1.1.1.4 root 63: #define MISC_SIZE 1
1.1.1.5 root 64: #define SYSCTRL_SIZE 4
1.1.1.4 root 65:
1.1.1.5 root 66: #define AUX1_TC 0x02
67:
1.1.1.4 root 68: #define AUX2_PWROFF 0x01
69: #define AUX2_PWRINTCLR 0x02
70: #define AUX2_PWRFAIL 0x20
71:
72: #define CFG_PWRINTEN 0x08
73:
74: #define SYS_RESET 0x01
75: #define SYS_RESETSTAT 0x02
1.1 root 76:
77: static void slavio_misc_update_irq(void *opaque)
78: {
79: MiscState *s = opaque;
80:
1.1.1.4 root 81: if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
82: MISC_DPRINTF("Raise IRQ\n");
83: qemu_irq_raise(s->irq);
1.1 root 84: } else {
1.1.1.4 root 85: MISC_DPRINTF("Lower IRQ\n");
86: qemu_irq_lower(s->irq);
1.1 root 87: }
88: }
89:
1.1.1.7 ! root 90: static void slavio_misc_reset(DeviceState *d)
1.1 root 91: {
1.1.1.7 ! root 92: MiscState *s = container_of(d, MiscState, busdev.qdev);
1.1 root 93:
1.1.1.2 root 94: // Diagnostic and system control registers not cleared in reset
1.1 root 95: s->config = s->aux1 = s->aux2 = s->mctrl = 0;
96: }
97:
1.1.1.7 ! root 98: static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
1.1 root 99: {
100: MiscState *s = opaque;
101:
102: MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
1.1.1.4 root 103: if (power_failing && (s->config & CFG_PWRINTEN)) {
104: s->aux2 |= AUX2_PWRFAIL;
1.1 root 105: } else {
1.1.1.4 root 106: s->aux2 &= ~AUX2_PWRFAIL;
1.1 root 107: }
108: slavio_misc_update_irq(s);
109: }
110:
1.1.1.5 root 111: static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
112: uint32_t val)
113: {
114: MiscState *s = opaque;
115:
116: MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
117: s->config = val & 0xff;
118: slavio_misc_update_irq(s);
119: }
120:
121: static uint32_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr)
122: {
123: MiscState *s = opaque;
124: uint32_t ret = 0;
125:
126: ret = s->config;
127: MISC_DPRINTF("Read config %2.2x\n", ret);
128: return ret;
129: }
130:
1.1.1.7 ! root 131: static CPUReadMemoryFunc * const slavio_cfg_mem_read[3] = {
1.1.1.5 root 132: slavio_cfg_mem_readb,
133: NULL,
134: NULL,
135: };
136:
1.1.1.7 ! root 137: static CPUWriteMemoryFunc * const slavio_cfg_mem_write[3] = {
1.1.1.5 root 138: slavio_cfg_mem_writeb,
139: NULL,
140: NULL,
141: };
142:
143: static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.4 root 144: uint32_t val)
1.1 root 145: {
146: MiscState *s = opaque;
147:
1.1.1.5 root 148: MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
149: s->diag = val & 0xff;
1.1 root 150: }
151:
1.1.1.5 root 152: static uint32_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr)
1.1 root 153: {
154: MiscState *s = opaque;
155: uint32_t ret = 0;
156:
1.1.1.5 root 157: ret = s->diag;
158: MISC_DPRINTF("Read diag %2.2x\n", ret);
159: return ret;
160: }
161:
1.1.1.7 ! root 162: static CPUReadMemoryFunc * const slavio_diag_mem_read[3] = {
1.1.1.5 root 163: slavio_diag_mem_readb,
164: NULL,
165: NULL,
166: };
167:
1.1.1.7 ! root 168: static CPUWriteMemoryFunc * const slavio_diag_mem_write[3] = {
1.1.1.5 root 169: slavio_diag_mem_writeb,
170: NULL,
171: NULL,
172: };
173:
174: static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
175: uint32_t val)
176: {
177: MiscState *s = opaque;
178:
179: MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
180: s->mctrl = val & 0xff;
181: }
182:
183: static uint32_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr)
184: {
185: MiscState *s = opaque;
186: uint32_t ret = 0;
187:
188: ret = s->mctrl;
189: MISC_DPRINTF("Read modem control %2.2x\n", ret);
190: return ret;
191: }
192:
1.1.1.7 ! root 193: static CPUReadMemoryFunc * const slavio_mdm_mem_read[3] = {
1.1.1.5 root 194: slavio_mdm_mem_readb,
195: NULL,
196: NULL,
197: };
198:
1.1.1.7 ! root 199: static CPUWriteMemoryFunc * const slavio_mdm_mem_write[3] = {
1.1.1.5 root 200: slavio_mdm_mem_writeb,
201: NULL,
202: NULL,
203: };
204:
205: static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
206: uint32_t val)
207: {
208: MiscState *s = opaque;
209:
210: MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
211: if (val & AUX1_TC) {
212: // Send a pulse to floppy terminal count line
213: if (s->fdc_tc) {
214: qemu_irq_raise(s->fdc_tc);
215: qemu_irq_lower(s->fdc_tc);
1.1.1.4 root 216: }
1.1.1.5 root 217: val &= ~AUX1_TC;
1.1 root 218: }
1.1.1.5 root 219: s->aux1 = val & 0xff;
220: }
221:
222: static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr)
223: {
224: MiscState *s = opaque;
225: uint32_t ret = 0;
226:
227: ret = s->aux1;
228: MISC_DPRINTF("Read aux1 %2.2x\n", ret);
229:
1.1 root 230: return ret;
231: }
232:
1.1.1.7 ! root 233: static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = {
1.1.1.5 root 234: slavio_aux1_mem_readb,
235: NULL,
236: NULL,
237: };
238:
1.1.1.7 ! root 239: static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = {
1.1.1.5 root 240: slavio_aux1_mem_writeb,
1.1.1.4 root 241: NULL,
242: NULL,
1.1 root 243: };
244:
1.1.1.5 root 245: static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
246: uint32_t val)
247: {
248: MiscState *s = opaque;
249:
250: val &= AUX2_PWRINTCLR | AUX2_PWROFF;
251: MISC_DPRINTF("Write aux2 %2.2x\n", val);
252: val |= s->aux2 & AUX2_PWRFAIL;
253: if (val & AUX2_PWRINTCLR) // Clear Power Fail int
254: val &= AUX2_PWROFF;
255: s->aux2 = val;
256: if (val & AUX2_PWROFF)
257: qemu_system_shutdown_request();
258: slavio_misc_update_irq(s);
259: }
260:
261: static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr)
262: {
263: MiscState *s = opaque;
264: uint32_t ret = 0;
265:
266: ret = s->aux2;
267: MISC_DPRINTF("Read aux2 %2.2x\n", ret);
268:
269: return ret;
270: }
271:
1.1.1.7 ! root 272: static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = {
1.1.1.5 root 273: slavio_aux2_mem_readb,
274: NULL,
275: NULL,
276: };
277:
1.1.1.7 ! root 278: static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = {
1.1.1.5 root 279: slavio_aux2_mem_writeb,
280: NULL,
281: NULL,
282: };
283:
284: static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
285: {
1.1.1.6 root 286: APCState *s = opaque;
1.1.1.5 root 287:
288: MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
289: qemu_irq_raise(s->cpu_halt);
290: }
291:
292: static uint32_t apc_mem_readb(void *opaque, target_phys_addr_t addr)
293: {
294: uint32_t ret = 0;
295:
296: MISC_DPRINTF("Read power management %2.2x\n", ret);
297: return ret;
298: }
299:
1.1.1.7 ! root 300: static CPUReadMemoryFunc * const apc_mem_read[3] = {
1.1.1.5 root 301: apc_mem_readb,
302: NULL,
303: NULL,
304: };
305:
1.1.1.7 ! root 306: static CPUWriteMemoryFunc * const apc_mem_write[3] = {
1.1.1.5 root 307: apc_mem_writeb,
1.1.1.4 root 308: NULL,
309: NULL,
310: };
311:
312: static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr)
313: {
314: MiscState *s = opaque;
1.1.1.5 root 315: uint32_t ret = 0;
1.1.1.4 root 316:
1.1.1.5 root 317: switch (addr) {
1.1.1.4 root 318: case 0:
319: ret = s->sysctrl;
320: break;
321: default:
322: break;
323: }
1.1.1.5 root 324: MISC_DPRINTF("Read system control %08x\n", ret);
1.1.1.4 root 325: return ret;
326: }
327:
328: static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
329: uint32_t val)
330: {
331: MiscState *s = opaque;
332:
1.1.1.5 root 333: MISC_DPRINTF("Write system control %08x\n", val);
334: switch (addr) {
1.1.1.4 root 335: case 0:
336: if (val & SYS_RESET) {
337: s->sysctrl = SYS_RESETSTAT;
338: qemu_system_reset_request();
339: }
340: break;
341: default:
342: break;
343: }
344: }
345:
1.1.1.7 ! root 346: static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = {
1.1.1.4 root 347: NULL,
348: NULL,
349: slavio_sysctrl_mem_readl,
350: };
351:
1.1.1.7 ! root 352: static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = {
1.1.1.4 root 353: NULL,
354: NULL,
355: slavio_sysctrl_mem_writel,
356: };
357:
358: static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr)
359: {
360: MiscState *s = opaque;
1.1.1.5 root 361: uint32_t ret = 0;
1.1.1.4 root 362:
1.1.1.5 root 363: switch (addr) {
1.1.1.4 root 364: case 0:
365: ret = s->leds;
366: break;
367: default:
368: break;
369: }
1.1.1.5 root 370: MISC_DPRINTF("Read diagnostic LED %04x\n", ret);
1.1.1.4 root 371: return ret;
372: }
373:
374: static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
375: uint32_t val)
376: {
377: MiscState *s = opaque;
378:
1.1.1.5 root 379: MISC_DPRINTF("Write diagnostic LED %04x\n", val & 0xffff);
380: switch (addr) {
1.1.1.4 root 381: case 0:
382: s->leds = val;
383: break;
384: default:
385: break;
386: }
387: }
388:
1.1.1.7 ! root 389: static CPUReadMemoryFunc * const slavio_led_mem_read[3] = {
1.1.1.4 root 390: NULL,
391: slavio_led_mem_readw,
392: NULL,
393: };
394:
1.1.1.7 ! root 395: static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = {
1.1.1.4 root 396: NULL,
397: slavio_led_mem_writew,
398: NULL,
1.1 root 399: };
400:
1.1.1.7 ! root 401: static const VMStateDescription vmstate_misc = {
! 402: .name ="slavio_misc",
! 403: .version_id = 1,
! 404: .minimum_version_id = 1,
! 405: .minimum_version_id_old = 1,
! 406: .fields = (VMStateField []) {
! 407: VMSTATE_UINT32(dummy, MiscState),
! 408: VMSTATE_UINT8(config, MiscState),
! 409: VMSTATE_UINT8(aux1, MiscState),
! 410: VMSTATE_UINT8(aux2, MiscState),
! 411: VMSTATE_UINT8(diag, MiscState),
! 412: VMSTATE_UINT8(mctrl, MiscState),
! 413: VMSTATE_UINT8(sysctrl, MiscState),
! 414: VMSTATE_END_OF_LIST()
1.1.1.5 root 415: }
1.1.1.7 ! root 416: };
1.1.1.6 root 417:
1.1.1.7 ! root 418: static int apc_init1(SysBusDevice *dev)
1.1.1.6 root 419: {
420: APCState *s = FROM_SYSBUS(APCState, dev);
421: int io;
1.1 root 422:
1.1.1.6 root 423: sysbus_init_irq(dev, &s->cpu_halt);
1.1 root 424:
1.1.1.6 root 425: /* Power management (APC) XXX: not a Slavio device */
426: io = cpu_register_io_memory(apc_mem_read, apc_mem_write, s);
427: sysbus_init_mmio(dev, MISC_SIZE, io);
1.1.1.7 ! root 428: return 0;
1.1.1.6 root 429: }
430:
1.1.1.7 ! root 431: static int slavio_misc_init1(SysBusDevice *dev)
1.1.1.6 root 432: {
433: MiscState *s = FROM_SYSBUS(MiscState, dev);
434: int io;
435:
436: sysbus_init_irq(dev, &s->irq);
437: sysbus_init_irq(dev, &s->fdc_tc);
438:
439: /* 8 bit registers */
440: /* Slavio control */
441: io = cpu_register_io_memory(slavio_cfg_mem_read,
442: slavio_cfg_mem_write, s);
443: sysbus_init_mmio(dev, MISC_SIZE, io);
444:
445: /* Diagnostics */
446: io = cpu_register_io_memory(slavio_diag_mem_read,
447: slavio_diag_mem_write, s);
448: sysbus_init_mmio(dev, MISC_SIZE, io);
449:
450: /* Modem control */
451: io = cpu_register_io_memory(slavio_mdm_mem_read,
452: slavio_mdm_mem_write, s);
453: sysbus_init_mmio(dev, MISC_SIZE, io);
454:
455: /* 16 bit registers */
456: /* ss600mp diag LEDs */
457: io = cpu_register_io_memory(slavio_led_mem_read,
458: slavio_led_mem_write, s);
459: sysbus_init_mmio(dev, MISC_SIZE, io);
460:
461: /* 32 bit registers */
462: /* System control */
463: io = cpu_register_io_memory(slavio_sysctrl_mem_read,
464: slavio_sysctrl_mem_write, s);
465: sysbus_init_mmio(dev, SYSCTRL_SIZE, io);
466:
467: /* AUX 1 (Misc System Functions) */
468: io = cpu_register_io_memory(slavio_aux1_mem_read,
469: slavio_aux1_mem_write, s);
470: sysbus_init_mmio(dev, MISC_SIZE, io);
471:
472: /* AUX 2 (Software Powerdown Control) */
473: io = cpu_register_io_memory(slavio_aux2_mem_read,
474: slavio_aux2_mem_write, s);
475: sysbus_init_mmio(dev, MISC_SIZE, io);
476:
1.1.1.7 ! root 477: qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
! 478:
! 479: return 0;
1.1.1.6 root 480: }
481:
482: static SysBusDeviceInfo slavio_misc_info = {
483: .init = slavio_misc_init1,
484: .qdev.name = "slavio_misc",
485: .qdev.size = sizeof(MiscState),
1.1.1.7 ! root 486: .qdev.vmsd = &vmstate_misc,
! 487: .qdev.reset = slavio_misc_reset,
1.1.1.6 root 488: };
1.1.1.5 root 489:
1.1.1.6 root 490: static SysBusDeviceInfo apc_info = {
491: .init = apc_init1,
492: .qdev.name = "apc",
493: .qdev.size = sizeof(MiscState),
494: };
495:
496: static void slavio_misc_register_devices(void)
497: {
498: sysbus_register_withprop(&slavio_misc_info);
499: sysbus_register_withprop(&apc_info);
1.1 root 500: }
1.1.1.6 root 501:
502: device_init(slavio_misc_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.