qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

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"
     43 OBJECT_DECLARE_SIMPLE_TYPE(MiscState, SLAVIO_MISC)
     44 
     45 struct 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"
     66 typedef struct APCState APCState;
     67 DECLARE_INSTANCE_CHECKER(APCState, APC,
     68                          TYPE_APC)
     69 
     70 struct 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 
     92 static 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 
    105 static 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 
    113 static 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 
    126 static 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 
    136 static 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 
    147 static 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 
    157 static 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 
    166 static 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 
    177 static 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 
    187 static 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 
    196 static 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 
    207 static 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 
    217 static 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 
    234 static 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 
    245 static 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 
    255 static 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 
    271 static 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 
    282 static 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 
    292 static 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 
    301 static 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 
    310 static 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 
    320 static 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 
    337 static 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 
    355 static 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 
    365 static 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 
    382 static 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 
    397 static 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 
    407 static 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 
    423 static 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 
    436 static 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 
    486 static 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 
    494 static 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 
    502 static 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 
    509 static void slavio_misc_register_types(void)
    510 {
    511     type_register_static(&slavio_misc_info);
    512     type_register_static(&apc_info);
    513 }
    514 
    515 type_init(slavio_misc_register_types)