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.h" 26 #include "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 qemu_irq irq; 43 qemu_irq fdc_tc; 44 uint32_t dummy; 45 uint8_t config; 46 uint8_t aux1, aux2; 47 uint8_t diag, mctrl; 48 uint8_t sysctrl; 49 uint16_t leds; 50 } MiscState; 51 52 typedef struct APCState { 53 SysBusDevice busdev; 54 MemoryRegion iomem; 55 qemu_irq cpu_halt; 56 } APCState; 57 58 #define MISC_SIZE 1 59 #define SYSCTRL_SIZE 4 60 61 #define AUX1_TC 0x02 62 63 #define AUX2_PWROFF 0x01 64 #define AUX2_PWRINTCLR 0x02 65 #define AUX2_PWRFAIL 0x20 66 67 #define CFG_PWRINTEN 0x08 68 69 #define SYS_RESET 0x01 70 #define SYS_RESETSTAT 0x02 71 72 static void slavio_misc_update_irq(void *opaque) 73 { 74 MiscState *s = opaque; 75 76 if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) { 77 trace_slavio_misc_update_irq_raise(); 78 qemu_irq_raise(s->irq); 79 } else { 80 trace_slavio_misc_update_irq_lower(); 81 qemu_irq_lower(s->irq); 82 } 83 } 84 85 static void slavio_misc_reset(DeviceState *d) 86 { 87 MiscState *s = container_of(d, MiscState, busdev.qdev); 88 89 // Diagnostic and system control registers not cleared in reset 90 s->config = s->aux1 = s->aux2 = s->mctrl = 0; 91 } 92 93 static void slavio_set_power_fail(void *opaque, int irq, int power_failing) 94 { 95 MiscState *s = opaque; 96 97 trace_slavio_set_power_fail(power_failing, s->config); 98 if (power_failing && (s->config & CFG_PWRINTEN)) { 99 s->aux2 |= AUX2_PWRFAIL; 100 } else { 101 s->aux2 &= ~AUX2_PWRFAIL; 102 } 103 slavio_misc_update_irq(s); 104 } 105 106 static void slavio_cfg_mem_writeb(void *opaque, target_phys_addr_t addr, 107 uint64_t val, unsigned size) 108 { 109 MiscState *s = opaque; 110 111 trace_slavio_cfg_mem_writeb(val & 0xff); 112 s->config = val & 0xff; 113 slavio_misc_update_irq(s); 114 } 115 116 static uint64_t slavio_cfg_mem_readb(void *opaque, target_phys_addr_t addr, 117 unsigned size) 118 { 119 MiscState *s = opaque; 120 uint32_t ret = 0; 121 122 ret = s->config; 123 trace_slavio_cfg_mem_readb(ret); 124 return ret; 125 } 126 127 static const MemoryRegionOps slavio_cfg_mem_ops = { 128 .read = slavio_cfg_mem_readb, 129 .write = slavio_cfg_mem_writeb, 130 .endianness = DEVICE_NATIVE_ENDIAN, 131 .valid = { 132 .min_access_size = 1, 133 .max_access_size = 1, 134 }, 135 }; 136 137 static void slavio_diag_mem_writeb(void *opaque, target_phys_addr_t addr, 138 uint64_t val, unsigned size) 139 { 140 MiscState *s = opaque; 141 142 trace_slavio_diag_mem_writeb(val & 0xff); 143 s->diag = val & 0xff; 144 } 145 146 static uint64_t slavio_diag_mem_readb(void *opaque, target_phys_addr_t addr, 147 unsigned size) 148 { 149 MiscState *s = opaque; 150 uint32_t ret = 0; 151 152 ret = s->diag; 153 trace_slavio_diag_mem_readb(ret); 154 return ret; 155 } 156 157 static const MemoryRegionOps slavio_diag_mem_ops = { 158 .read = slavio_diag_mem_readb, 159 .write = slavio_diag_mem_writeb, 160 .endianness = DEVICE_NATIVE_ENDIAN, 161 .valid = { 162 .min_access_size = 1, 163 .max_access_size = 1, 164 }, 165 }; 166 167 static void slavio_mdm_mem_writeb(void *opaque, target_phys_addr_t addr, 168 uint64_t val, unsigned size) 169 { 170 MiscState *s = opaque; 171 172 trace_slavio_mdm_mem_writeb(val & 0xff); 173 s->mctrl = val & 0xff; 174 } 175 176 static uint64_t slavio_mdm_mem_readb(void *opaque, target_phys_addr_t addr, 177 unsigned size) 178 { 179 MiscState *s = opaque; 180 uint32_t ret = 0; 181 182 ret = s->mctrl; 183 trace_slavio_mdm_mem_readb(ret); 184 return ret; 185 } 186 187 static const MemoryRegionOps slavio_mdm_mem_ops = { 188 .read = slavio_mdm_mem_readb, 189 .write = slavio_mdm_mem_writeb, 190 .endianness = DEVICE_NATIVE_ENDIAN, 191 .valid = { 192 .min_access_size = 1, 193 .max_access_size = 1, 194 }, 195 }; 196 197 static void slavio_aux1_mem_writeb(void *opaque, target_phys_addr_t addr, 198 uint32_t val) 199 { 200 MiscState *s = opaque; 201 202 trace_slavio_aux1_mem_writeb(val & 0xff); 203 if (val & AUX1_TC) { 204 // Send a pulse to floppy terminal count line 205 if (s->fdc_tc) { 206 qemu_irq_raise(s->fdc_tc); 207 qemu_irq_lower(s->fdc_tc); 208 } 209 val &= ~AUX1_TC; 210 } 211 s->aux1 = val & 0xff; 212 } 213 214 static uint32_t slavio_aux1_mem_readb(void *opaque, target_phys_addr_t addr) 215 { 216 MiscState *s = opaque; 217 uint32_t ret = 0; 218 219 ret = s->aux1; 220 trace_slavio_aux1_mem_readb(ret); 221 return ret; 222 } 223 224 static CPUReadMemoryFunc * const slavio_aux1_mem_read[3] = { 225 slavio_aux1_mem_readb, 226 NULL, 227 NULL, 228 }; 229 230 static CPUWriteMemoryFunc * const slavio_aux1_mem_write[3] = { 231 slavio_aux1_mem_writeb, 232 NULL, 233 NULL, 234 }; 235 236 static void slavio_aux2_mem_writeb(void *opaque, target_phys_addr_t addr, 237 uint32_t val) 238 { 239 MiscState *s = opaque; 240 241 val &= AUX2_PWRINTCLR | AUX2_PWROFF; 242 trace_slavio_aux2_mem_writeb(val & 0xff); 243 val |= s->aux2 & AUX2_PWRFAIL; 244 if (val & AUX2_PWRINTCLR) // Clear Power Fail int 245 val &= AUX2_PWROFF; 246 s->aux2 = val; 247 if (val & AUX2_PWROFF) 248 qemu_system_shutdown_request(); 249 slavio_misc_update_irq(s); 250 } 251 252 static uint32_t slavio_aux2_mem_readb(void *opaque, target_phys_addr_t addr) 253 { 254 MiscState *s = opaque; 255 uint32_t ret = 0; 256 257 ret = s->aux2; 258 trace_slavio_aux2_mem_readb(ret); 259 return ret; 260 } 261 262 static CPUReadMemoryFunc * const slavio_aux2_mem_read[3] = { 263 slavio_aux2_mem_readb, 264 NULL, 265 NULL, 266 }; 267 268 static CPUWriteMemoryFunc * const slavio_aux2_mem_write[3] = { 269 slavio_aux2_mem_writeb, 270 NULL, 271 NULL, 272 }; 273 274 static void apc_mem_writeb(void *opaque, target_phys_addr_t addr, 275 uint64_t val, unsigned size) 276 { 277 APCState *s = opaque; 278 279 trace_apc_mem_writeb(val & 0xff); 280 qemu_irq_raise(s->cpu_halt); 281 } 282 283 static uint64_t apc_mem_readb(void *opaque, target_phys_addr_t addr, 284 unsigned size) 285 { 286 uint32_t ret = 0; 287 288 trace_apc_mem_readb(ret); 289 return ret; 290 } 291 292 static const MemoryRegionOps apc_mem_ops = { 293 .read = apc_mem_readb, 294 .write = apc_mem_writeb, 295 .endianness = DEVICE_NATIVE_ENDIAN, 296 .valid = { 297 .min_access_size = 1, 298 .max_access_size = 1, 299 } 300 }; 301 302 static uint32_t slavio_sysctrl_mem_readl(void *opaque, target_phys_addr_t addr) 303 { 304 MiscState *s = opaque; 305 uint32_t ret = 0; 306 307 switch (addr) { 308 case 0: 309 ret = s->sysctrl; 310 break; 311 default: 312 break; 313 } 314 trace_slavio_sysctrl_mem_readl(ret); 315 return ret; 316 } 317 318 static void slavio_sysctrl_mem_writel(void *opaque, target_phys_addr_t addr, 319 uint32_t val) 320 { 321 MiscState *s = opaque; 322 323 trace_slavio_sysctrl_mem_writel(val); 324 switch (addr) { 325 case 0: 326 if (val & SYS_RESET) { 327 s->sysctrl = SYS_RESETSTAT; 328 qemu_system_reset_request(); 329 } 330 break; 331 default: 332 break; 333 } 334 } 335 336 static CPUReadMemoryFunc * const slavio_sysctrl_mem_read[3] = { 337 NULL, 338 NULL, 339 slavio_sysctrl_mem_readl, 340 }; 341 342 static CPUWriteMemoryFunc * const slavio_sysctrl_mem_write[3] = { 343 NULL, 344 NULL, 345 slavio_sysctrl_mem_writel, 346 }; 347 348 static uint32_t slavio_led_mem_readw(void *opaque, target_phys_addr_t addr) 349 { 350 MiscState *s = opaque; 351 uint32_t ret = 0; 352 353 switch (addr) { 354 case 0: 355 ret = s->leds; 356 break; 357 default: 358 break; 359 } 360 trace_slavio_led_mem_readw(ret); 361 return ret; 362 } 363 364 static void slavio_led_mem_writew(void *opaque, target_phys_addr_t addr, 365 uint32_t val) 366 { 367 MiscState *s = opaque; 368 369 trace_slavio_led_mem_readw(val & 0xffff); 370 switch (addr) { 371 case 0: 372 s->leds = val; 373 break; 374 default: 375 break; 376 } 377 } 378 379 static CPUReadMemoryFunc * const slavio_led_mem_read[3] = { 380 NULL, 381 slavio_led_mem_readw, 382 NULL, 383 }; 384 385 static CPUWriteMemoryFunc * const slavio_led_mem_write[3] = { 386 NULL, 387 slavio_led_mem_writew, 388 NULL, 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, &apc_mem_ops, s, 416 "apc", MISC_SIZE); 417 sysbus_init_mmio_region(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 int io; 425 426 sysbus_init_irq(dev, &s->irq); 427 sysbus_init_irq(dev, &s->fdc_tc); 428 429 /* 8 bit registers */ 430 /* Slavio control */ 431 memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s, 432 "configuration", MISC_SIZE); 433 sysbus_init_mmio_region(dev, &s->cfg_iomem); 434 435 /* Diagnostics */ 436 memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s, 437 "diagnostic", MISC_SIZE); 438 sysbus_init_mmio_region(dev, &s->diag_iomem); 439 440 /* Modem control */ 441 memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s, 442 "modem", MISC_SIZE); 443 sysbus_init_mmio_region(dev, &s->mdm_iomem); 444 445 /* 16 bit registers */ 446 /* ss600mp diag LEDs */ 447 io = cpu_register_io_memory(slavio_led_mem_read, 448 slavio_led_mem_write, s, 449 DEVICE_NATIVE_ENDIAN); 450 sysbus_init_mmio(dev, MISC_SIZE, io); 451 452 /* 32 bit registers */ 453 /* System control */ 454 io = cpu_register_io_memory(slavio_sysctrl_mem_read, 455 slavio_sysctrl_mem_write, s, 456 DEVICE_NATIVE_ENDIAN); 457 sysbus_init_mmio(dev, SYSCTRL_SIZE, io); 458 459 /* AUX 1 (Misc System Functions) */ 460 io = cpu_register_io_memory(slavio_aux1_mem_read, 461 slavio_aux1_mem_write, s, 462 DEVICE_NATIVE_ENDIAN); 463 sysbus_init_mmio(dev, MISC_SIZE, io); 464 465 /* AUX 2 (Software Powerdown Control) */ 466 io = cpu_register_io_memory(slavio_aux2_mem_read, 467 slavio_aux2_mem_write, s, 468 DEVICE_NATIVE_ENDIAN); 469 sysbus_init_mmio(dev, MISC_SIZE, io); 470 471 qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1); 472 473 return 0; 474 } 475 476 static SysBusDeviceInfo slavio_misc_info = { 477 .init = slavio_misc_init1, 478 .qdev.name = "slavio_misc", 479 .qdev.size = sizeof(MiscState), 480 .qdev.vmsd = &vmstate_misc, 481 .qdev.reset = slavio_misc_reset, 482 }; 483 484 static SysBusDeviceInfo apc_info = { 485 .init = apc_init1, 486 .qdev.name = "apc", 487 .qdev.size = sizeof(MiscState), 488 }; 489 490 static void slavio_misc_register_devices(void) 491 { 492 sysbus_register_withprop(&slavio_misc_info); 493 sysbus_register_withprop(&apc_info); 494 } 495 496 device_init(slavio_misc_register_devices) 497