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