qemu/hw/misc/slavio_misc.c
<<
>>
Prefs
   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)
 516