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