1 /* 2 * QEMU Sparc SLAVIO aux io port emulation 3 * 4 * Copyright (c) 2005 Fabrice Bellard 5 * 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 */ 24 25 #include "sysemu/sysemu.h" 26 #include "hw/sysbus.h" 27 #include "trace.h" 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 { 38 SysBusDevice busdev; 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; 46 qemu_irq irq; 47 qemu_irq fdc_tc; 48 uint32_t dummy; 49 uint8_t config; 50 uint8_t aux1, aux2; 51 uint8_t diag, mctrl; 52 uint8_t sysctrl; 53 uint16_t leds; 54 } MiscState; 55 56 typedef struct APCState { 57 SysBusDevice busdev; 58 MemoryRegion iomem; 59 qemu_irq cpu_halt; 60 } APCState; 61 62 #define MISC_SIZE 1 63 #define SYSCTRL_SIZE 4 64 65 #define AUX1_TC 0x02 66 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 75 76 static void slavio_misc_update_irq(void *opaque) 77 { 78 MiscState *s = opaque; 79 80 if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) { 81 trace_slavio_misc_update_irq_raise(); 82 qemu_irq_raise(s->irq); 83 } else { 84 trace_slavio_misc_update_irq_lower(); 85 qemu_irq_lower(s->irq); 86 } 87 } 88 89 static void slavio_misc_reset(DeviceState *d) 90 { 91 MiscState *s = container_of(d, MiscState, busdev.qdev); 92 93 // Diagnostic and system control registers not cleared in reset 94 s->config = s->aux1 = s->aux2 = s->mctrl = 0; 95 } 96 97 static void slavio_set_power_fail(void *opaque, int irq, int power_failing) 98 { 99 MiscState *s = opaque; 100 101 trace_slavio_set_power_fail(power_failing, s->config); 102 if (power_failing && (s->config & CFG_PWRINTEN)) { 103 s->aux2 |= AUX2_PWRFAIL; 104 } else { 105 s->aux2 &= ~AUX2_PWRFAIL; 106 } 107 slavio_misc_update_irq(s); 108 } 109 110 static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr, 111 uint64_t val, unsigned size) 112 { 113 MiscState *s = opaque; 114 115 trace_slavio_cfg_mem_writeb(val & 0xff); 116 s->config = val & 0xff; 117 slavio_misc_update_irq(s); 118 } 119 120 static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr, 121 unsigned size) 122 { 123 MiscState *s = opaque; 124 uint32_t ret = 0; 125 126 ret = s->config; 127 trace_slavio_cfg_mem_readb(ret); 128 return ret; 129 } 130 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 }, 139 }; 140 141 static void slavio_diag_mem_writeb(void *opaque, hwaddr addr, 142 uint64_t val, unsigned size) 143 { 144 MiscState *s = opaque; 145 146 trace_slavio_diag_mem_writeb(val & 0xff); 147 s->diag = val & 0xff; 148 } 149 150 static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr, 151 unsigned size) 152 { 153 MiscState *s = opaque; 154 uint32_t ret = 0; 155 156 ret = s->diag; 157 trace_slavio_diag_mem_readb(ret); 158 return ret; 159 } 160 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 }, 169 }; 170 171 static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr, 172 uint64_t val, unsigned size) 173 { 174 MiscState *s = opaque; 175 176 trace_slavio_mdm_mem_writeb(val & 0xff); 177 s->mctrl = val & 0xff; 178 } 179 180 static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr, 181 unsigned size) 182 { 183 MiscState *s = opaque; 184 uint32_t ret = 0; 185 186 ret = s->mctrl; 187 trace_slavio_mdm_mem_readb(ret); 188 return ret; 189 } 190 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 }, 199 }; 200 201 static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr, 202 uint64_t val, unsigned size) 203 { 204 MiscState *s = opaque; 205 206 trace_slavio_aux1_mem_writeb(val & 0xff); 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); 212 } 213 val &= ~AUX1_TC; 214 } 215 s->aux1 = val & 0xff; 216 } 217 218 static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr, 219 unsigned size) 220 { 221 MiscState *s = opaque; 222 uint32_t ret = 0; 223 224 ret = s->aux1; 225 trace_slavio_aux1_mem_readb(ret); 226 return ret; 227 } 228 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 }, 237 }; 238 239 static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr, 240 uint64_t val, unsigned size) 241 { 242 MiscState *s = opaque; 243 244 val &= AUX2_PWRINTCLR | AUX2_PWROFF; 245 trace_slavio_aux2_mem_writeb(val & 0xff); 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 255 static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr, 256 unsigned size) 257 { 258 MiscState *s = opaque; 259 uint32_t ret = 0; 260 261 ret = s->aux2; 262 trace_slavio_aux2_mem_readb(ret); 263 return ret; 264 } 265 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 }, 274 }; 275 276 static void apc_mem_writeb(void *opaque, hwaddr addr, 277 uint64_t val, unsigned size) 278 { 279 APCState *s = opaque; 280 281 trace_apc_mem_writeb(val & 0xff); 282 qemu_irq_raise(s->cpu_halt); 283 } 284 285 static uint64_t apc_mem_readb(void *opaque, hwaddr addr, 286 unsigned size) 287 { 288 uint32_t ret = 0; 289 290 trace_apc_mem_readb(ret); 291 return ret; 292 } 293 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 } 302 }; 303 304 static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr, 305 unsigned size) 306 { 307 MiscState *s = opaque; 308 uint32_t ret = 0; 309 310 switch (addr) { 311 case 0: 312 ret = s->sysctrl; 313 break; 314 default: 315 break; 316 } 317 trace_slavio_sysctrl_mem_readl(ret); 318 return ret; 319 } 320 321 static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr, 322 uint64_t val, unsigned size) 323 { 324 MiscState *s = opaque; 325 326 trace_slavio_sysctrl_mem_writel(val); 327 switch (addr) { 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 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 }, 347 }; 348 349 static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr, 350 unsigned size) 351 { 352 MiscState *s = opaque; 353 uint32_t ret = 0; 354 355 switch (addr) { 356 case 0: 357 ret = s->leds; 358 break; 359 default: 360 break; 361 } 362 trace_slavio_led_mem_readw(ret); 363 return ret; 364 } 365 366 static void slavio_led_mem_writew(void *opaque, hwaddr addr, 367 uint64_t val, unsigned size) 368 { 369 MiscState *s = opaque; 370 371 trace_slavio_led_mem_writew(val & 0xffff); 372 switch (addr) { 373 case 0: 374 s->leds = val; 375 break; 376 default: 377 break; 378 } 379 } 380 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 }, 389 }; 390 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() 405 } 406 }; 407 408 static int apc_init1(SysBusDevice *dev) 409 { 410 APCState *s = FROM_SYSBUS(APCState, dev); 411 412 sysbus_init_irq(dev, &s->cpu_halt); 413 414 /* Power management (APC) XXX: not a Slavio device */ 415 memory_region_init_io(&s->iomem, OBJECT(s), &apc_mem_ops, s, 416 "apc", MISC_SIZE); 417 sysbus_init_mmio(dev, &s->iomem); 418 return 0; 419 } 420 421 static int slavio_misc_init1(SysBusDevice *dev) 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 */ 430 memory_region_init_io(&s->cfg_iomem, OBJECT(s), &slavio_cfg_mem_ops, s, 431 "configuration", MISC_SIZE); 432 sysbus_init_mmio(dev, &s->cfg_iomem); 433 434 /* Diagnostics */ 435 memory_region_init_io(&s->diag_iomem, OBJECT(s), &slavio_diag_mem_ops, s, 436 "diagnostic", MISC_SIZE); 437 sysbus_init_mmio(dev, &s->diag_iomem); 438 439 /* Modem control */ 440 memory_region_init_io(&s->mdm_iomem, OBJECT(s), &slavio_mdm_mem_ops, s, 441 "modem", MISC_SIZE); 442 sysbus_init_mmio(dev, &s->mdm_iomem); 443 444 /* 16 bit registers */ 445 /* ss600mp diag LEDs */ 446 memory_region_init_io(&s->led_iomem, OBJECT(s), &slavio_led_mem_ops, s, 447 "leds", MISC_SIZE); 448 sysbus_init_mmio(dev, &s->led_iomem); 449 450 /* 32 bit registers */ 451 /* System control */ 452 memory_region_init_io(&s->sysctrl_iomem, OBJECT(s), &slavio_sysctrl_mem_ops, s, 453 "system-control", MISC_SIZE); 454 sysbus_init_mmio(dev, &s->sysctrl_iomem); 455 456 /* AUX 1 (Misc System Functions) */ 457 memory_region_init_io(&s->aux1_iomem, OBJECT(s), &slavio_aux1_mem_ops, s, 458 "misc-system-functions", MISC_SIZE); 459 sysbus_init_mmio(dev, &s->aux1_iomem); 460 461 /* AUX 2 (Software Powerdown Control) */ 462 memory_region_init_io(&s->aux2_iomem, OBJECT(s), &slavio_aux2_mem_ops, s, 463 "software-powerdown-control", MISC_SIZE); 464 sysbus_init_mmio(dev, &s->aux2_iomem); 465 466 qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1); 467 468 return 0; 469 } 470 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 const 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, 486 }; 487 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 const TypeInfo apc_info = { 496 .name = "apc", 497 .parent = TYPE_SYS_BUS_DEVICE, 498 .instance_size = sizeof(MiscState), 499 .class_init = apc_class_init, 500 }; 501 502 static void slavio_misc_register_types(void) 503 { 504 type_register_static(&slavio_misc_info); 505 type_register_static(&apc_info); 506 } 507 508 type_init(slavio_misc_register_types) 509