|
|
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.8 root 27: #include "trace.h"
1.1 root 28:
29: /*
30: * This is the auxio port, chip control and system control part of
31: * chip STP2001 (Slave I/O), also produced as NCR89C105. See
32: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
33: *
34: * This also includes the PMC CPU idle controller.
35: */
36:
37: typedef struct MiscState {
1.1.1.6 root 38: SysBusDevice busdev;
1.1.1.10! root 39: MemoryRegion cfg_iomem;
! 40: MemoryRegion diag_iomem;
! 41: MemoryRegion mdm_iomem;
! 42: MemoryRegion led_iomem;
! 43: MemoryRegion sysctrl_iomem;
! 44: MemoryRegion aux1_iomem;
! 45: MemoryRegion aux2_iomem;
1.1.1.4 root 46: qemu_irq irq;
1.1.1.9 root 47: qemu_irq fdc_tc;
1.1.1.7 root 48: uint32_t dummy;
1.1 root 49: uint8_t config;
50: uint8_t aux1, aux2;
1.1.1.4 root 51: uint8_t diag, mctrl;
1.1.1.7 root 52: uint8_t sysctrl;
1.1.1.4 root 53: uint16_t leds;
1.1 root 54: } MiscState;
55:
1.1.1.6 root 56: typedef struct APCState {
57: SysBusDevice busdev;
1.1.1.10! root 58: MemoryRegion iomem;
1.1.1.6 root 59: qemu_irq cpu_halt;
60: } APCState;
61:
1.1.1.4 root 62: #define MISC_SIZE 1
1.1.1.5 root 63: #define SYSCTRL_SIZE 4
1.1.1.4 root 64:
1.1.1.5 root 65: #define AUX1_TC 0x02
66:
1.1.1.4 root 67: #define AUX2_PWROFF 0x01
68: #define AUX2_PWRINTCLR 0x02
69: #define AUX2_PWRFAIL 0x20
70:
71: #define CFG_PWRINTEN 0x08
72:
73: #define SYS_RESET 0x01
74: #define SYS_RESETSTAT 0x02
1.1 root 75:
76: static void slavio_misc_update_irq(void *opaque)
77: {
78: MiscState *s = opaque;
79:
1.1.1.4 root 80: if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
1.1.1.8 root 81: trace_slavio_misc_update_irq_raise();
1.1.1.4 root 82: qemu_irq_raise(s->irq);
1.1 root 83: } else {
1.1.1.8 root 84: trace_slavio_misc_update_irq_lower();
1.1.1.4 root 85: qemu_irq_lower(s->irq);
1.1 root 86: }
87: }
88:
1.1.1.7 root 89: static void slavio_misc_reset(DeviceState *d)
1.1 root 90: {
1.1.1.7 root 91: MiscState *s = container_of(d, MiscState, busdev.qdev);
1.1 root 92:
1.1.1.2 root 93: // Diagnostic and system control registers not cleared in reset
1.1 root 94: s->config = s->aux1 = s->aux2 = s->mctrl = 0;
95: }
96:
1.1.1.7 root 97: static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
1.1 root 98: {
99: MiscState *s = opaque;
100:
1.1.1.8 root 101: trace_slavio_set_power_fail(power_failing, s->config);
1.1.1.4 root 102: if (power_failing && (s->config & CFG_PWRINTEN)) {
103: s->aux2 |= AUX2_PWRFAIL;
1.1 root 104: } else {
1.1.1.4 root 105: s->aux2 &= ~AUX2_PWRFAIL;
1.1 root 106: }
107: slavio_misc_update_irq(s);
108: }
109:
1.1.1.5 root 110: static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 111: uint64_t val, unsigned size)
1.1.1.5 root 112: {
113: MiscState *s = opaque;
114:
1.1.1.8 root 115: trace_slavio_cfg_mem_writeb(val & 0xff);
1.1.1.5 root 116: s->config = val & 0xff;
117: slavio_misc_update_irq(s);
118: }
119:
1.1.1.10! root 120: static uint64_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr,
! 121: unsigned size)
1.1.1.5 root 122: {
123: MiscState *s = opaque;
124: uint32_t ret = 0;
125:
126: ret = s->config;
1.1.1.8 root 127: trace_slavio_cfg_mem_readb(ret);
1.1.1.5 root 128: return ret;
129: }
130:
1.1.1.10! root 131: static const MemoryRegionOps slavio_cfg_mem_ops = {
! 132: .read = slavio_cfg_mem_readb,
! 133: .write = slavio_cfg_mem_writeb,
! 134: .endianness = DEVICE_NATIVE_ENDIAN,
! 135: .valid = {
! 136: .min_access_size = 1,
! 137: .max_access_size = 1,
! 138: },
1.1.1.5 root 139: };
140:
141: static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 142: uint64_t val, unsigned size)
1.1 root 143: {
144: MiscState *s = opaque;
145:
1.1.1.8 root 146: trace_slavio_diag_mem_writeb(val & 0xff);
1.1.1.5 root 147: s->diag = val & 0xff;
1.1 root 148: }
149:
1.1.1.10! root 150: static uint64_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr,
! 151: unsigned size)
1.1 root 152: {
153: MiscState *s = opaque;
154: uint32_t ret = 0;
155:
1.1.1.5 root 156: ret = s->diag;
1.1.1.8 root 157: trace_slavio_diag_mem_readb(ret);
1.1.1.5 root 158: return ret;
159: }
160:
1.1.1.10! root 161: static const MemoryRegionOps slavio_diag_mem_ops = {
! 162: .read = slavio_diag_mem_readb,
! 163: .write = slavio_diag_mem_writeb,
! 164: .endianness = DEVICE_NATIVE_ENDIAN,
! 165: .valid = {
! 166: .min_access_size = 1,
! 167: .max_access_size = 1,
! 168: },
1.1.1.5 root 169: };
170:
171: static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 172: uint64_t val, unsigned size)
1.1.1.5 root 173: {
174: MiscState *s = opaque;
175:
1.1.1.8 root 176: trace_slavio_mdm_mem_writeb(val & 0xff);
1.1.1.5 root 177: s->mctrl = val & 0xff;
178: }
179:
1.1.1.10! root 180: static uint64_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr,
! 181: unsigned size)
1.1.1.5 root 182: {
183: MiscState *s = opaque;
184: uint32_t ret = 0;
185:
186: ret = s->mctrl;
1.1.1.8 root 187: trace_slavio_mdm_mem_readb(ret);
1.1.1.5 root 188: return ret;
189: }
190:
1.1.1.10! root 191: static const MemoryRegionOps slavio_mdm_mem_ops = {
! 192: .read = slavio_mdm_mem_readb,
! 193: .write = slavio_mdm_mem_writeb,
! 194: .endianness = DEVICE_NATIVE_ENDIAN,
! 195: .valid = {
! 196: .min_access_size = 1,
! 197: .max_access_size = 1,
! 198: },
1.1.1.5 root 199: };
200:
201: static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 202: uint64_t val, unsigned size)
1.1.1.5 root 203: {
204: MiscState *s = opaque;
205:
1.1.1.8 root 206: trace_slavio_aux1_mem_writeb(val & 0xff);
1.1.1.5 root 207: if (val & AUX1_TC) {
208: // Send a pulse to floppy terminal count line
209: if (s->fdc_tc) {
210: qemu_irq_raise(s->fdc_tc);
211: qemu_irq_lower(s->fdc_tc);
1.1.1.4 root 212: }
1.1.1.5 root 213: val &= ~AUX1_TC;
1.1 root 214: }
1.1.1.5 root 215: s->aux1 = val & 0xff;
216: }
217:
1.1.1.10! root 218: static uint64_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr,
! 219: unsigned size)
1.1.1.5 root 220: {
221: MiscState *s = opaque;
222: uint32_t ret = 0;
223:
224: ret = s->aux1;
1.1.1.8 root 225: trace_slavio_aux1_mem_readb(ret);
1.1 root 226: return ret;
227: }
228:
1.1.1.10! root 229: static const MemoryRegionOps slavio_aux1_mem_ops = {
! 230: .read = slavio_aux1_mem_readb,
! 231: .write = slavio_aux1_mem_writeb,
! 232: .endianness = DEVICE_NATIVE_ENDIAN,
! 233: .valid = {
! 234: .min_access_size = 1,
! 235: .max_access_size = 1,
! 236: },
1.1 root 237: };
238:
1.1.1.5 root 239: static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 240: uint64_t val, unsigned size)
1.1.1.5 root 241: {
242: MiscState *s = opaque;
243:
244: val &= AUX2_PWRINTCLR | AUX2_PWROFF;
1.1.1.8 root 245: trace_slavio_aux2_mem_writeb(val & 0xff);
1.1.1.5 root 246: val |= s->aux2 & AUX2_PWRFAIL;
247: if (val & AUX2_PWRINTCLR) // Clear Power Fail int
248: val &= AUX2_PWROFF;
249: s->aux2 = val;
250: if (val & AUX2_PWROFF)
251: qemu_system_shutdown_request();
252: slavio_misc_update_irq(s);
253: }
254:
1.1.1.10! root 255: static uint64_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr,
! 256: unsigned size)
1.1.1.5 root 257: {
258: MiscState *s = opaque;
259: uint32_t ret = 0;
260:
261: ret = s->aux2;
1.1.1.8 root 262: trace_slavio_aux2_mem_readb(ret);
1.1.1.5 root 263: return ret;
264: }
265:
1.1.1.10! root 266: static const MemoryRegionOps slavio_aux2_mem_ops = {
! 267: .read = slavio_aux2_mem_readb,
! 268: .write = slavio_aux2_mem_writeb,
! 269: .endianness = DEVICE_NATIVE_ENDIAN,
! 270: .valid = {
! 271: .min_access_size = 1,
! 272: .max_access_size = 1,
! 273: },
1.1.1.5 root 274: };
275:
1.1.1.10! root 276: static void apc_mem_writeb(void *opaque, target_phys_addr_t addr,
! 277: uint64_t val, unsigned size)
1.1.1.5 root 278: {
1.1.1.6 root 279: APCState *s = opaque;
1.1.1.5 root 280:
1.1.1.8 root 281: trace_apc_mem_writeb(val & 0xff);
1.1.1.5 root 282: qemu_irq_raise(s->cpu_halt);
283: }
284:
1.1.1.10! root 285: static uint64_t apc_mem_readb(void *opaque, target_phys_addr_t addr,
! 286: unsigned size)
1.1.1.5 root 287: {
288: uint32_t ret = 0;
289:
1.1.1.8 root 290: trace_apc_mem_readb(ret);
1.1.1.5 root 291: return ret;
292: }
293:
1.1.1.10! root 294: static const MemoryRegionOps apc_mem_ops = {
! 295: .read = apc_mem_readb,
! 296: .write = apc_mem_writeb,
! 297: .endianness = DEVICE_NATIVE_ENDIAN,
! 298: .valid = {
! 299: .min_access_size = 1,
! 300: .max_access_size = 1,
! 301: }
1.1.1.4 root 302: };
303:
1.1.1.10! root 304: static uint64_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr,
! 305: unsigned size)
1.1.1.4 root 306: {
307: MiscState *s = opaque;
1.1.1.5 root 308: uint32_t ret = 0;
1.1.1.4 root 309:
1.1.1.5 root 310: switch (addr) {
1.1.1.4 root 311: case 0:
312: ret = s->sysctrl;
313: break;
314: default:
315: break;
316: }
1.1.1.8 root 317: trace_slavio_sysctrl_mem_readl(ret);
1.1.1.4 root 318: return ret;
319: }
320:
321: static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 322: uint64_t val, unsigned size)
1.1.1.4 root 323: {
324: MiscState *s = opaque;
325:
1.1.1.8 root 326: trace_slavio_sysctrl_mem_writel(val);
1.1.1.5 root 327: switch (addr) {
1.1.1.4 root 328: case 0:
329: if (val & SYS_RESET) {
330: s->sysctrl = SYS_RESETSTAT;
331: qemu_system_reset_request();
332: }
333: break;
334: default:
335: break;
336: }
337: }
338:
1.1.1.10! root 339: static const MemoryRegionOps slavio_sysctrl_mem_ops = {
! 340: .read = slavio_sysctrl_mem_readl,
! 341: .write = slavio_sysctrl_mem_writel,
! 342: .endianness = DEVICE_NATIVE_ENDIAN,
! 343: .valid = {
! 344: .min_access_size = 4,
! 345: .max_access_size = 4,
! 346: },
1.1.1.4 root 347: };
348:
1.1.1.10! root 349: static uint64_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr,
! 350: unsigned size)
1.1.1.4 root 351: {
352: MiscState *s = opaque;
1.1.1.5 root 353: uint32_t ret = 0;
1.1.1.4 root 354:
1.1.1.5 root 355: switch (addr) {
1.1.1.4 root 356: case 0:
357: ret = s->leds;
358: break;
359: default:
360: break;
361: }
1.1.1.8 root 362: trace_slavio_led_mem_readw(ret);
1.1.1.4 root 363: return ret;
364: }
365:
366: static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr,
1.1.1.10! root 367: uint64_t val, unsigned size)
1.1.1.4 root 368: {
369: MiscState *s = opaque;
370:
1.1.1.8 root 371: trace_slavio_led_mem_readw(val & 0xffff);
1.1.1.5 root 372: switch (addr) {
1.1.1.4 root 373: case 0:
374: s->leds = val;
375: break;
376: default:
377: break;
378: }
379: }
380:
1.1.1.10! root 381: static const MemoryRegionOps slavio_led_mem_ops = {
! 382: .read = slavio_led_mem_readw,
! 383: .write = slavio_led_mem_writew,
! 384: .endianness = DEVICE_NATIVE_ENDIAN,
! 385: .valid = {
! 386: .min_access_size = 2,
! 387: .max_access_size = 2,
! 388: },
1.1 root 389: };
390:
1.1.1.7 root 391: static const VMStateDescription vmstate_misc = {
392: .name ="slavio_misc",
393: .version_id = 1,
394: .minimum_version_id = 1,
395: .minimum_version_id_old = 1,
396: .fields = (VMStateField []) {
397: VMSTATE_UINT32(dummy, MiscState),
398: VMSTATE_UINT8(config, MiscState),
399: VMSTATE_UINT8(aux1, MiscState),
400: VMSTATE_UINT8(aux2, MiscState),
401: VMSTATE_UINT8(diag, MiscState),
402: VMSTATE_UINT8(mctrl, MiscState),
403: VMSTATE_UINT8(sysctrl, MiscState),
404: VMSTATE_END_OF_LIST()
1.1.1.5 root 405: }
1.1.1.7 root 406: };
1.1.1.6 root 407:
1.1.1.7 root 408: static int apc_init1(SysBusDevice *dev)
1.1.1.6 root 409: {
410: APCState *s = FROM_SYSBUS(APCState, dev);
1.1 root 411:
1.1.1.6 root 412: sysbus_init_irq(dev, &s->cpu_halt);
1.1 root 413:
1.1.1.6 root 414: /* Power management (APC) XXX: not a Slavio device */
1.1.1.10! root 415: memory_region_init_io(&s->iomem, &apc_mem_ops, s,
! 416: "apc", MISC_SIZE);
! 417: sysbus_init_mmio(dev, &s->iomem);
1.1.1.7 root 418: return 0;
1.1.1.6 root 419: }
420:
1.1.1.7 root 421: static int slavio_misc_init1(SysBusDevice *dev)
1.1.1.6 root 422: {
423: MiscState *s = FROM_SYSBUS(MiscState, dev);
424:
425: sysbus_init_irq(dev, &s->irq);
426: sysbus_init_irq(dev, &s->fdc_tc);
427:
428: /* 8 bit registers */
429: /* Slavio control */
1.1.1.10! root 430: memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s,
! 431: "configuration", MISC_SIZE);
! 432: sysbus_init_mmio(dev, &s->cfg_iomem);
1.1.1.6 root 433:
434: /* Diagnostics */
1.1.1.10! root 435: memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s,
! 436: "diagnostic", MISC_SIZE);
! 437: sysbus_init_mmio(dev, &s->diag_iomem);
1.1.1.6 root 438:
439: /* Modem control */
1.1.1.10! root 440: memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s,
! 441: "modem", MISC_SIZE);
! 442: sysbus_init_mmio(dev, &s->mdm_iomem);
1.1.1.6 root 443:
444: /* 16 bit registers */
445: /* ss600mp diag LEDs */
1.1.1.10! root 446: memory_region_init_io(&s->led_iomem, &slavio_led_mem_ops, s,
! 447: "leds", MISC_SIZE);
! 448: sysbus_init_mmio(dev, &s->led_iomem);
1.1.1.6 root 449:
450: /* 32 bit registers */
451: /* System control */
1.1.1.10! root 452: memory_region_init_io(&s->sysctrl_iomem, &slavio_sysctrl_mem_ops, s,
! 453: "system-control", MISC_SIZE);
! 454: sysbus_init_mmio(dev, &s->sysctrl_iomem);
1.1.1.6 root 455:
456: /* AUX 1 (Misc System Functions) */
1.1.1.10! root 457: memory_region_init_io(&s->aux1_iomem, &slavio_aux1_mem_ops, s,
! 458: "misc-system-functions", MISC_SIZE);
! 459: sysbus_init_mmio(dev, &s->aux1_iomem);
1.1.1.6 root 460:
461: /* AUX 2 (Software Powerdown Control) */
1.1.1.10! root 462: memory_region_init_io(&s->aux2_iomem, &slavio_aux2_mem_ops, s,
! 463: "software-powerdown-control", MISC_SIZE);
! 464: sysbus_init_mmio(dev, &s->aux2_iomem);
1.1.1.6 root 465:
1.1.1.7 root 466: qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
467:
468: return 0;
1.1.1.6 root 469: }
470:
1.1.1.10! root 471: static void slavio_misc_class_init(ObjectClass *klass, void *data)
! 472: {
! 473: DeviceClass *dc = DEVICE_CLASS(klass);
! 474: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
! 475:
! 476: k->init = slavio_misc_init1;
! 477: dc->reset = slavio_misc_reset;
! 478: dc->vmsd = &vmstate_misc;
! 479: }
! 480:
! 481: static TypeInfo slavio_misc_info = {
! 482: .name = "slavio_misc",
! 483: .parent = TYPE_SYS_BUS_DEVICE,
! 484: .instance_size = sizeof(MiscState),
! 485: .class_init = slavio_misc_class_init,
1.1.1.6 root 486: };
1.1.1.5 root 487:
1.1.1.10! root 488: static void apc_class_init(ObjectClass *klass, void *data)
! 489: {
! 490: SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
! 491:
! 492: k->init = apc_init1;
! 493: }
! 494:
! 495: static TypeInfo apc_info = {
! 496: .name = "apc",
! 497: .parent = TYPE_SYS_BUS_DEVICE,
! 498: .instance_size = sizeof(MiscState),
! 499: .class_init = apc_class_init,
1.1.1.6 root 500: };
501:
1.1.1.10! root 502: static void slavio_misc_register_types(void)
1.1.1.6 root 503: {
1.1.1.10! root 504: type_register_static(&slavio_misc_info);
! 505: type_register_static(&apc_info);
1.1 root 506: }
1.1.1.6 root 507:
1.1.1.10! root 508: type_init(slavio_misc_register_types)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.