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