qemu

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

macio.c (17050B)


      1 /*
      2  * PowerMac MacIO device emulation
      3  *
      4  * Copyright (c) 2005-2007 Fabrice Bellard
      5  * Copyright (c) 2007 Jocelyn Mayer
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  */
     25 
     26 #include "qemu/osdep.h"
     27 #include "qapi/error.h"
     28 #include "qemu/module.h"
     29 #include "hw/misc/macio/cuda.h"
     30 #include "hw/pci/pci.h"
     31 #include "hw/ppc/mac_dbdma.h"
     32 #include "hw/qdev-properties.h"
     33 #include "migration/vmstate.h"
     34 #include "hw/char/escc.h"
     35 #include "hw/misc/macio/macio.h"
     36 #include "hw/intc/heathrow_pic.h"
     37 #include "trace.h"
     38 
     39 #define ESCC_CLOCK 3686400
     40 
     41 /* Note: this code is strongly inspired by the corresponding code in PearPC */
     42 
     43 /*
     44  * The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
     45  * while the other one is the normal, current ESCC interface.
     46  *
     47  * The magic below creates memory aliases to spawn the escc-legacy device
     48  * purely by rerouting the respective registers to our escc region. This
     49  * works because the only difference between the two memory regions is the
     50  * register layout, not their semantics.
     51  *
     52  * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
     53  */
     54 static void macio_escc_legacy_setup(MacIOState *s)
     55 {
     56     ESCCState *escc = ESCC(&s->escc);
     57     SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
     58     MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
     59     MemoryRegion *bar = &s->bar;
     60     int i;
     61     static const int maps[] = {
     62         0x00, 0x00, /* Command B */
     63         0x02, 0x20, /* Command A */
     64         0x04, 0x10, /* Data B */
     65         0x06, 0x30, /* Data A */
     66         0x08, 0x40, /* Enhancement B */
     67         0x0A, 0x50, /* Enhancement A */
     68         0x80, 0x80, /* Recovery count */
     69         0x90, 0x90, /* Start A */
     70         0xa0, 0xa0, /* Start B */
     71         0xb0, 0xb0, /* Detect AB */
     72     };
     73 
     74     memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256);
     75     for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
     76         MemoryRegion *port = g_new(MemoryRegion, 1);
     77         memory_region_init_alias(port, OBJECT(s), "escc-legacy-port",
     78                                  sysbus_mmio_get_region(sbd, 0),
     79                                  maps[i + 1], 0x2);
     80         memory_region_add_subregion(escc_legacy, maps[i], port);
     81     }
     82 
     83     memory_region_add_subregion(bar, 0x12000, escc_legacy);
     84 }
     85 
     86 static void macio_bar_setup(MacIOState *s)
     87 {
     88     ESCCState *escc = ESCC(&s->escc);
     89     SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
     90     MemoryRegion *bar = &s->bar;
     91 
     92     memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0));
     93     macio_escc_legacy_setup(s);
     94 }
     95 
     96 static void macio_common_realize(PCIDevice *d, Error **errp)
     97 {
     98     MacIOState *s = MACIO(d);
     99     SysBusDevice *sysbus_dev;
    100 
    101     if (!qdev_realize(DEVICE(&s->dbdma), BUS(&s->macio_bus), errp)) {
    102         return;
    103     }
    104     sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
    105     memory_region_add_subregion(&s->bar, 0x08000,
    106                                 sysbus_mmio_get_region(sysbus_dev, 0));
    107 
    108     qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
    109     qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
    110     qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
    111     qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial);
    112     qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial);
    113     if (!qdev_realize(DEVICE(&s->escc), BUS(&s->macio_bus), errp)) {
    114         return;
    115     }
    116 
    117     macio_bar_setup(s);
    118     pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
    119 }
    120 
    121 static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
    122                               qemu_irq irq0, qemu_irq irq1, int dmaid,
    123                               Error **errp)
    124 {
    125     SysBusDevice *sysbus_dev;
    126 
    127     sysbus_dev = SYS_BUS_DEVICE(ide);
    128     sysbus_connect_irq(sysbus_dev, 0, irq0);
    129     sysbus_connect_irq(sysbus_dev, 1, irq1);
    130     qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
    131     object_property_set_link(OBJECT(ide), "dbdma", OBJECT(&s->dbdma),
    132                              &error_abort);
    133     macio_ide_register_dma(ide);
    134 
    135     qdev_realize(DEVICE(ide), BUS(&s->macio_bus), errp);
    136 }
    137 
    138 static void macio_oldworld_realize(PCIDevice *d, Error **errp)
    139 {
    140     MacIOState *s = MACIO(d);
    141     OldWorldMacIOState *os = OLDWORLD_MACIO(d);
    142     DeviceState *pic_dev = DEVICE(&os->pic);
    143     Error *err = NULL;
    144     SysBusDevice *sysbus_dev;
    145 
    146     macio_common_realize(d, &err);
    147     if (err) {
    148         error_propagate(errp, err);
    149         return;
    150     }
    151 
    152     /* Heathrow PIC */
    153     if (!qdev_realize(DEVICE(&os->pic), BUS(&s->macio_bus), errp)) {
    154         return;
    155     }
    156     sysbus_dev = SYS_BUS_DEVICE(&os->pic);
    157     memory_region_add_subregion(&s->bar, 0x0,
    158                                 sysbus_mmio_get_region(sysbus_dev, 0));
    159 
    160     qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
    161                          s->frequency);
    162     if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), errp)) {
    163         return;
    164     }
    165     sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
    166     memory_region_add_subregion(&s->bar, 0x16000,
    167                                 sysbus_mmio_get_region(sysbus_dev, 0));
    168     sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
    169                                                        OLDWORLD_CUDA_IRQ));
    170 
    171     sysbus_dev = SYS_BUS_DEVICE(&s->escc);
    172     sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
    173                                                        OLDWORLD_ESCCB_IRQ));
    174     sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev,
    175                                                        OLDWORLD_ESCCA_IRQ));
    176 
    177     if (!qdev_realize(DEVICE(&os->nvram), BUS(&s->macio_bus), errp)) {
    178         return;
    179     }
    180     sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
    181     memory_region_add_subregion(&s->bar, 0x60000,
    182                                 sysbus_mmio_get_region(sysbus_dev, 0));
    183     pmac_format_nvram_partition(&os->nvram, os->nvram.size);
    184 
    185     /* IDE buses */
    186     macio_realize_ide(s, &os->ide[0],
    187                       qdev_get_gpio_in(pic_dev, OLDWORLD_IDE0_IRQ),
    188                       qdev_get_gpio_in(pic_dev, OLDWORLD_IDE0_DMA_IRQ),
    189                       0x16, &err);
    190     if (err) {
    191         error_propagate(errp, err);
    192         return;
    193     }
    194 
    195     macio_realize_ide(s, &os->ide[1],
    196                       qdev_get_gpio_in(pic_dev, OLDWORLD_IDE1_IRQ),
    197                       qdev_get_gpio_in(pic_dev, OLDWORLD_IDE1_DMA_IRQ),
    198                       0x1a, &err);
    199     if (err) {
    200         error_propagate(errp, err);
    201         return;
    202     }
    203 }
    204 
    205 static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, int index)
    206 {
    207     gchar *name = g_strdup_printf("ide[%i]", index);
    208     uint32_t addr = 0x1f000 + ((index + 1) * 0x1000);
    209 
    210     object_initialize_child(OBJECT(s), name, ide, TYPE_MACIO_IDE);
    211     qdev_prop_set_uint32(DEVICE(ide), "addr", addr);
    212     memory_region_add_subregion(&s->bar, addr, &ide->mem);
    213     g_free(name);
    214 }
    215 
    216 static void macio_oldworld_init(Object *obj)
    217 {
    218     MacIOState *s = MACIO(obj);
    219     OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
    220     DeviceState *dev;
    221     int i;
    222 
    223     object_initialize_child(OBJECT(s), "pic", &os->pic, TYPE_HEATHROW);
    224 
    225     object_initialize_child(OBJECT(s), "cuda", &s->cuda, TYPE_CUDA);
    226 
    227     object_initialize_child(OBJECT(s), "nvram", &os->nvram, TYPE_MACIO_NVRAM);
    228     dev = DEVICE(&os->nvram);
    229     qdev_prop_set_uint32(dev, "size", MACIO_NVRAM_SIZE);
    230     qdev_prop_set_uint32(dev, "it_shift", 4);
    231 
    232     for (i = 0; i < 2; i++) {
    233         macio_init_ide(s, &os->ide[i], i);
    234     }
    235 }
    236 
    237 static void timer_write(void *opaque, hwaddr addr, uint64_t value,
    238                        unsigned size)
    239 {
    240     trace_macio_timer_write(addr, size, value);
    241 }
    242 
    243 static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
    244 {
    245     uint32_t value = 0;
    246     uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
    247     uint64_t kltime;
    248 
    249     kltime = muldiv64(systime, 4194300, NANOSECONDS_PER_SECOND * 4);
    250     kltime = muldiv64(kltime, 18432000, 1048575);
    251 
    252     switch (addr) {
    253     case 0x38:
    254         value = kltime;
    255         break;
    256     case 0x3c:
    257         value = kltime >> 32;
    258         break;
    259     }
    260 
    261     trace_macio_timer_read(addr, size, value);
    262     return value;
    263 }
    264 
    265 static const MemoryRegionOps timer_ops = {
    266     .read = timer_read,
    267     .write = timer_write,
    268     .endianness = DEVICE_LITTLE_ENDIAN,
    269 };
    270 
    271 static void macio_newworld_realize(PCIDevice *d, Error **errp)
    272 {
    273     MacIOState *s = MACIO(d);
    274     NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
    275     DeviceState *pic_dev = DEVICE(&ns->pic);
    276     Error *err = NULL;
    277     SysBusDevice *sysbus_dev;
    278     MemoryRegion *timer_memory = NULL;
    279 
    280     macio_common_realize(d, &err);
    281     if (err) {
    282         error_propagate(errp, err);
    283         return;
    284     }
    285 
    286     /* OpenPIC */
    287     qdev_prop_set_uint32(pic_dev, "model", OPENPIC_MODEL_KEYLARGO);
    288     sysbus_dev = SYS_BUS_DEVICE(&ns->pic);
    289     sysbus_realize_and_unref(sysbus_dev, &error_fatal);
    290     memory_region_add_subregion(&s->bar, 0x40000,
    291                                 sysbus_mmio_get_region(sysbus_dev, 0));
    292 
    293     sysbus_dev = SYS_BUS_DEVICE(&s->escc);
    294     sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
    295                                                        NEWWORLD_ESCCB_IRQ));
    296     sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev,
    297                                                        NEWWORLD_ESCCA_IRQ));
    298 
    299     /* IDE buses */
    300     macio_realize_ide(s, &ns->ide[0],
    301                       qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_IRQ),
    302                       qdev_get_gpio_in(pic_dev, NEWWORLD_IDE0_DMA_IRQ),
    303                       0x16, &err);
    304     if (err) {
    305         error_propagate(errp, err);
    306         return;
    307     }
    308 
    309     macio_realize_ide(s, &ns->ide[1],
    310                       qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_IRQ),
    311                       qdev_get_gpio_in(pic_dev, NEWWORLD_IDE1_DMA_IRQ),
    312                       0x1a, &err);
    313     if (err) {
    314         error_propagate(errp, err);
    315         return;
    316     }
    317 
    318     /* Timer */
    319     timer_memory = g_new(MemoryRegion, 1);
    320     memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
    321                           0x1000);
    322     memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
    323 
    324     if (ns->has_pmu) {
    325         /* GPIOs */
    326         if (!qdev_realize(DEVICE(&ns->gpio), BUS(&s->macio_bus), errp)) {
    327             return;
    328         }
    329         sysbus_dev = SYS_BUS_DEVICE(&ns->gpio);
    330         sysbus_connect_irq(sysbus_dev, 1, qdev_get_gpio_in(pic_dev,
    331                            NEWWORLD_EXTING_GPIO1));
    332         sysbus_connect_irq(sysbus_dev, 9, qdev_get_gpio_in(pic_dev,
    333                            NEWWORLD_EXTING_GPIO9));
    334         memory_region_add_subregion(&s->bar, 0x50,
    335                                     sysbus_mmio_get_region(sysbus_dev, 0));
    336 
    337         /* PMU */
    338         object_initialize_child(OBJECT(s), "pmu", &s->pmu, TYPE_VIA_PMU);
    339         object_property_set_link(OBJECT(&s->pmu), "gpio", OBJECT(sysbus_dev),
    340                                  &error_abort);
    341         qdev_prop_set_bit(DEVICE(&s->pmu), "has-adb", ns->has_adb);
    342         if (!qdev_realize(DEVICE(&s->pmu), BUS(&s->macio_bus), errp)) {
    343             return;
    344         }
    345         sysbus_dev = SYS_BUS_DEVICE(&s->pmu);
    346         sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
    347                                                            NEWWORLD_PMU_IRQ));
    348         memory_region_add_subregion(&s->bar, 0x16000,
    349                                     sysbus_mmio_get_region(sysbus_dev, 0));
    350     } else {
    351         object_unparent(OBJECT(&ns->gpio));
    352 
    353         /* CUDA */
    354         object_initialize_child(OBJECT(s), "cuda", &s->cuda, TYPE_CUDA);
    355         qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
    356                              s->frequency);
    357 
    358         if (!qdev_realize(DEVICE(&s->cuda), BUS(&s->macio_bus), errp)) {
    359             return;
    360         }
    361         sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
    362         sysbus_connect_irq(sysbus_dev, 0, qdev_get_gpio_in(pic_dev,
    363                                                            NEWWORLD_CUDA_IRQ));
    364         memory_region_add_subregion(&s->bar, 0x16000,
    365                                     sysbus_mmio_get_region(sysbus_dev, 0));
    366     }
    367 }
    368 
    369 static void macio_newworld_init(Object *obj)
    370 {
    371     MacIOState *s = MACIO(obj);
    372     NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
    373     int i;
    374 
    375     object_initialize_child(OBJECT(s), "pic", &ns->pic, TYPE_OPENPIC);
    376 
    377     object_initialize_child(OBJECT(s), "gpio", &ns->gpio, TYPE_MACIO_GPIO);
    378 
    379     for (i = 0; i < 2; i++) {
    380         macio_init_ide(s, &ns->ide[i], i);
    381     }
    382 }
    383 
    384 static void macio_instance_init(Object *obj)
    385 {
    386     MacIOState *s = MACIO(obj);
    387 
    388     memory_region_init(&s->bar, obj, "macio", 0x80000);
    389 
    390     qbus_init(&s->macio_bus, sizeof(s->macio_bus), TYPE_MACIO_BUS,
    391               DEVICE(obj), "macio.0");
    392 
    393     object_initialize_child(OBJECT(s), "dbdma", &s->dbdma, TYPE_MAC_DBDMA);
    394 
    395     object_initialize_child(OBJECT(s), "escc", &s->escc, TYPE_ESCC);
    396 }
    397 
    398 static const VMStateDescription vmstate_macio_oldworld = {
    399     .name = "macio-oldworld",
    400     .version_id = 0,
    401     .minimum_version_id = 0,
    402     .fields = (VMStateField[]) {
    403         VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState),
    404         VMSTATE_END_OF_LIST()
    405     }
    406 };
    407 
    408 static void macio_oldworld_class_init(ObjectClass *oc, void *data)
    409 {
    410     PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
    411     DeviceClass *dc = DEVICE_CLASS(oc);
    412 
    413     pdc->realize = macio_oldworld_realize;
    414     pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
    415     dc->vmsd = &vmstate_macio_oldworld;
    416 }
    417 
    418 static const VMStateDescription vmstate_macio_newworld = {
    419     .name = "macio-newworld",
    420     .version_id = 0,
    421     .minimum_version_id = 0,
    422     .fields = (VMStateField[]) {
    423         VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState),
    424         VMSTATE_END_OF_LIST()
    425     }
    426 };
    427 
    428 static Property macio_newworld_properties[] = {
    429     DEFINE_PROP_BOOL("has-pmu", NewWorldMacIOState, has_pmu, false),
    430     DEFINE_PROP_BOOL("has-adb", NewWorldMacIOState, has_adb, false),
    431     DEFINE_PROP_END_OF_LIST()
    432 };
    433 
    434 static void macio_newworld_class_init(ObjectClass *oc, void *data)
    435 {
    436     PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
    437     DeviceClass *dc = DEVICE_CLASS(oc);
    438 
    439     pdc->realize = macio_newworld_realize;
    440     pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
    441     dc->vmsd = &vmstate_macio_newworld;
    442     device_class_set_props(dc, macio_newworld_properties);
    443 }
    444 
    445 static Property macio_properties[] = {
    446     DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
    447     DEFINE_PROP_END_OF_LIST()
    448 };
    449 
    450 static void macio_class_init(ObjectClass *klass, void *data)
    451 {
    452     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    453     DeviceClass *dc = DEVICE_CLASS(klass);
    454 
    455     k->vendor_id = PCI_VENDOR_ID_APPLE;
    456     k->class_id = PCI_CLASS_OTHERS << 8;
    457     device_class_set_props(dc, macio_properties);
    458     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    459 }
    460 
    461 static const TypeInfo macio_bus_info = {
    462     .name = TYPE_MACIO_BUS,
    463     .parent = TYPE_SYSTEM_BUS,
    464     .instance_size = sizeof(MacIOBusState),
    465 };
    466 
    467 static const TypeInfo macio_oldworld_type_info = {
    468     .name          = TYPE_OLDWORLD_MACIO,
    469     .parent        = TYPE_MACIO,
    470     .instance_size = sizeof(OldWorldMacIOState),
    471     .instance_init = macio_oldworld_init,
    472     .class_init    = macio_oldworld_class_init,
    473 };
    474 
    475 static const TypeInfo macio_newworld_type_info = {
    476     .name          = TYPE_NEWWORLD_MACIO,
    477     .parent        = TYPE_MACIO,
    478     .instance_size = sizeof(NewWorldMacIOState),
    479     .instance_init = macio_newworld_init,
    480     .class_init    = macio_newworld_class_init,
    481 };
    482 
    483 static const TypeInfo macio_type_info = {
    484     .name          = TYPE_MACIO,
    485     .parent        = TYPE_PCI_DEVICE,
    486     .instance_size = sizeof(MacIOState),
    487     .instance_init = macio_instance_init,
    488     .abstract      = true,
    489     .class_init    = macio_class_init,
    490     .interfaces = (InterfaceInfo[]) {
    491         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    492         { },
    493     },
    494 };
    495 
    496 static void macio_register_types(void)
    497 {
    498     type_register_static(&macio_bus_info);
    499     type_register_static(&macio_type_info);
    500     type_register_static(&macio_oldworld_type_info);
    501     type_register_static(&macio_newworld_type_info);
    502 }
    503 
    504 type_init(macio_register_types)