qemu/hw/misc/macio/macio.c
<<
>>
Prefs
   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#include "qemu/osdep.h"
  26#include "qapi/error.h"
  27#include "hw/hw.h"
  28#include "hw/ppc/mac.h"
  29#include "hw/misc/macio/cuda.h"
  30#include "hw/pci/pci.h"
  31#include "hw/ppc/mac_dbdma.h"
  32#include "hw/char/escc.h"
  33#include "hw/misc/macio/macio.h"
  34#include "hw/intc/heathrow_pic.h"
  35
  36/* Note: this code is strongly inspirated from the corresponding code
  37 * in PearPC */
  38
  39/*
  40 * The mac-io has two interfaces to the ESCC. One is called "escc-legacy",
  41 * while the other one is the normal, current ESCC interface.
  42 *
  43 * The magic below creates memory aliases to spawn the escc-legacy device
  44 * purely by rerouting the respective registers to our escc region. This
  45 * works because the only difference between the two memory regions is the
  46 * register layout, not their semantics.
  47 *
  48 * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
  49 */
  50static void macio_escc_legacy_setup(MacIOState *s)
  51{
  52    ESCCState *escc = ESCC(&s->escc);
  53    SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
  54    MemoryRegion *escc_legacy = g_new(MemoryRegion, 1);
  55    MemoryRegion *bar = &s->bar;
  56    int i;
  57    static const int maps[] = {
  58        0x00, 0x00, /* Command B */
  59        0x02, 0x20, /* Command A */
  60        0x04, 0x10, /* Data B */
  61        0x06, 0x30, /* Data A */
  62        0x08, 0x40, /* Enhancement B */
  63        0x0A, 0x50, /* Enhancement A */
  64        0x80, 0x80, /* Recovery count */
  65        0x90, 0x90, /* Start A */
  66        0xa0, 0xa0, /* Start B */
  67        0xb0, 0xb0, /* Detect AB */
  68    };
  69
  70    memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256);
  71    for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
  72        MemoryRegion *port = g_new(MemoryRegion, 1);
  73        memory_region_init_alias(port, OBJECT(s), "escc-legacy-port",
  74                                 sysbus_mmio_get_region(sbd, 0),
  75                                 maps[i + 1], 0x2);
  76        memory_region_add_subregion(escc_legacy, maps[i], port);
  77    }
  78
  79    memory_region_add_subregion(bar, 0x12000, escc_legacy);
  80}
  81
  82static void macio_bar_setup(MacIOState *s)
  83{
  84    ESCCState *escc = ESCC(&s->escc);
  85    SysBusDevice *sbd = SYS_BUS_DEVICE(escc);
  86    MemoryRegion *bar = &s->bar;
  87
  88    memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0));
  89    macio_escc_legacy_setup(s);
  90}
  91
  92static void macio_common_realize(PCIDevice *d, Error **errp)
  93{
  94    MacIOState *s = MACIO(d);
  95    SysBusDevice *sysbus_dev;
  96    Error *err = NULL;
  97
  98    object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err);
  99    if (err) {
 100        error_propagate(errp, err);
 101        return;
 102    }
 103    sysbus_dev = SYS_BUS_DEVICE(&s->dbdma);
 104    memory_region_add_subregion(&s->bar, 0x08000,
 105                                sysbus_mmio_get_region(sysbus_dev, 0));
 106
 107    qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency",
 108                         s->frequency);
 109    object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
 110    if (err) {
 111        error_propagate(errp, err);
 112        return;
 113    }
 114    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
 115    memory_region_add_subregion(&s->bar, 0x16000,
 116                                sysbus_mmio_get_region(sysbus_dev, 0));
 117
 118    qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0);
 119    qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK);
 120    qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4);
 121    qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hds[0]);
 122    qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hds[1]);
 123    qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial);
 124    qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial);
 125    object_property_set_bool(OBJECT(&s->escc), true, "realized", &err);
 126    if (err) {
 127        error_propagate(errp, err);
 128        return;
 129    }
 130
 131    macio_bar_setup(s);
 132    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
 133}
 134
 135static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide,
 136                              qemu_irq irq0, qemu_irq irq1, int dmaid,
 137                              Error **errp)
 138{
 139    SysBusDevice *sysbus_dev;
 140
 141    sysbus_dev = SYS_BUS_DEVICE(ide);
 142    sysbus_connect_irq(sysbus_dev, 0, irq0);
 143    sysbus_connect_irq(sysbus_dev, 1, irq1);
 144    qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid);
 145    object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp);
 146    macio_ide_register_dma(ide);
 147
 148    object_property_set_bool(OBJECT(ide), true, "realized", errp);
 149}
 150
 151static void macio_oldworld_realize(PCIDevice *d, Error **errp)
 152{
 153    MacIOState *s = MACIO(d);
 154    OldWorldMacIOState *os = OLDWORLD_MACIO(d);
 155    Error *err = NULL;
 156    SysBusDevice *sysbus_dev;
 157    int i;
 158    int cur_irq = 0;
 159
 160    macio_common_realize(d, &err);
 161    if (err) {
 162        error_propagate(errp, err);
 163        return;
 164    }
 165
 166    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
 167    sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
 168
 169    sysbus_dev = SYS_BUS_DEVICE(&s->escc);
 170    sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
 171    sysbus_connect_irq(sysbus_dev, 1, os->irqs[cur_irq++]);
 172
 173    object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
 174    if (err) {
 175        error_propagate(errp, err);
 176        return;
 177    }
 178    sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
 179    memory_region_add_subregion(&s->bar, 0x60000,
 180                                sysbus_mmio_get_region(sysbus_dev, 0));
 181    pmac_format_nvram_partition(&os->nvram, os->nvram.size);
 182
 183    /* Heathrow PIC */
 184    sysbus_dev = SYS_BUS_DEVICE(os->pic);
 185    memory_region_add_subregion(&s->bar, 0x0,
 186                                sysbus_mmio_get_region(sysbus_dev, 0));
 187
 188    /* IDE buses */
 189    for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
 190        qemu_irq irq0 = os->irqs[cur_irq++];
 191        qemu_irq irq1 = os->irqs[cur_irq++];
 192
 193        macio_realize_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
 194        if (err) {
 195            error_propagate(errp, err);
 196            return;
 197        }
 198    }
 199}
 200
 201static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
 202                           int index)
 203{
 204    gchar *name;
 205
 206    object_initialize(ide, ide_size, TYPE_MACIO_IDE);
 207    qdev_set_parent_bus(DEVICE(ide), sysbus_get_default());
 208    memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000),
 209                                &ide->mem);
 210    name = g_strdup_printf("ide[%i]", index);
 211    object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL);
 212    g_free(name);
 213}
 214
 215static void macio_oldworld_init(Object *obj)
 216{
 217    MacIOState *s = MACIO(obj);
 218    OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
 219    DeviceState *dev;
 220    int i;
 221
 222    qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
 223
 224    object_property_add_link(obj, "pic", TYPE_HEATHROW,
 225                             (Object **) &os->pic,
 226                             qdev_prop_allow_set_link_before_realize,
 227                             0, NULL);
 228
 229    object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
 230    dev = DEVICE(&os->nvram);
 231    qdev_prop_set_uint32(dev, "size", 0x2000);
 232    qdev_prop_set_uint32(dev, "it_shift", 4);
 233
 234    for (i = 0; i < 2; i++) {
 235        macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i);
 236    }
 237}
 238
 239static void timer_write(void *opaque, hwaddr addr, uint64_t value,
 240                       unsigned size)
 241{
 242}
 243
 244static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
 245{
 246    uint32_t value = 0;
 247    uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
 248    uint64_t kltime;
 249
 250    kltime = muldiv64(systime, 4194300, NANOSECONDS_PER_SECOND * 4);
 251    kltime = muldiv64(kltime, 18432000, 1048575);
 252
 253    switch (addr) {
 254    case 0x38:
 255        value = kltime;
 256        break;
 257    case 0x3c:
 258        value = kltime >> 32;
 259        break;
 260    }
 261
 262    return value;
 263}
 264
 265static const MemoryRegionOps timer_ops = {
 266    .read = timer_read,
 267    .write = timer_write,
 268    .endianness = DEVICE_LITTLE_ENDIAN,
 269};
 270
 271static void macio_newworld_realize(PCIDevice *d, Error **errp)
 272{
 273    MacIOState *s = MACIO(d);
 274    NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
 275    Error *err = NULL;
 276    SysBusDevice *sysbus_dev;
 277    MemoryRegion *timer_memory = NULL;
 278    int i;
 279    int cur_irq = 0;
 280
 281    macio_common_realize(d, &err);
 282    if (err) {
 283        error_propagate(errp, err);
 284        return;
 285    }
 286
 287    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
 288    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
 289
 290    sysbus_dev = SYS_BUS_DEVICE(&s->escc);
 291    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
 292    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]);
 293
 294    /* OpenPIC */
 295    sysbus_dev = SYS_BUS_DEVICE(ns->pic);
 296    memory_region_add_subregion(&s->bar, 0x40000,
 297                                sysbus_mmio_get_region(sysbus_dev, 0));
 298
 299    /* IDE buses */
 300    for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
 301        qemu_irq irq0 = ns->irqs[cur_irq++];
 302        qemu_irq irq1 = ns->irqs[cur_irq++];
 303
 304        macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
 305        if (err) {
 306            error_propagate(errp, err);
 307            return;
 308        }
 309    }
 310
 311    /* Timer */
 312    timer_memory = g_new(MemoryRegion, 1);
 313    memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
 314                          0x1000);
 315    memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
 316}
 317
 318static void macio_newworld_init(Object *obj)
 319{
 320    MacIOState *s = MACIO(obj);
 321    NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
 322    int i;
 323
 324    qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
 325
 326    object_property_add_link(obj, "pic", TYPE_OPENPIC,
 327                             (Object **) &ns->pic,
 328                             qdev_prop_allow_set_link_before_realize,
 329                             0, NULL);
 330
 331    for (i = 0; i < 2; i++) {
 332        macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
 333    }
 334}
 335
 336static void macio_instance_init(Object *obj)
 337{
 338    MacIOState *s = MACIO(obj);
 339
 340    memory_region_init(&s->bar, obj, "macio", 0x80000);
 341
 342    object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
 343    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
 344    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
 345
 346    object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA);
 347    qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default());
 348    object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL);
 349
 350    object_initialize(&s->escc, sizeof(s->escc), TYPE_ESCC);
 351    qdev_set_parent_bus(DEVICE(&s->escc), sysbus_get_default());
 352    object_property_add_child(obj, "escc", OBJECT(&s->escc), NULL);
 353}
 354
 355static const VMStateDescription vmstate_macio_oldworld = {
 356    .name = "macio-oldworld",
 357    .version_id = 0,
 358    .minimum_version_id = 0,
 359    .fields = (VMStateField[]) {
 360        VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState),
 361        VMSTATE_END_OF_LIST()
 362    }
 363};
 364
 365static void macio_oldworld_class_init(ObjectClass *oc, void *data)
 366{
 367    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
 368    DeviceClass *dc = DEVICE_CLASS(oc);
 369
 370    pdc->realize = macio_oldworld_realize;
 371    pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
 372    dc->vmsd = &vmstate_macio_oldworld;
 373}
 374
 375static const VMStateDescription vmstate_macio_newworld = {
 376    .name = "macio-newworld",
 377    .version_id = 0,
 378    .minimum_version_id = 0,
 379    .fields = (VMStateField[]) {
 380        VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState),
 381        VMSTATE_END_OF_LIST()
 382    }
 383};
 384
 385static void macio_newworld_class_init(ObjectClass *oc, void *data)
 386{
 387    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
 388    DeviceClass *dc = DEVICE_CLASS(oc);
 389
 390    pdc->realize = macio_newworld_realize;
 391    pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
 392    dc->vmsd = &vmstate_macio_newworld;
 393}
 394
 395static Property macio_properties[] = {
 396    DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
 397    DEFINE_PROP_END_OF_LIST()
 398};
 399
 400static void macio_class_init(ObjectClass *klass, void *data)
 401{
 402    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 403    DeviceClass *dc = DEVICE_CLASS(klass);
 404
 405    k->vendor_id = PCI_VENDOR_ID_APPLE;
 406    k->class_id = PCI_CLASS_OTHERS << 8;
 407    dc->props = macio_properties;
 408    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 409    /* Reason: Uses serial_hds in macio_instance_init */
 410    dc->user_creatable = false;
 411}
 412
 413static const TypeInfo macio_oldworld_type_info = {
 414    .name          = TYPE_OLDWORLD_MACIO,
 415    .parent        = TYPE_MACIO,
 416    .instance_size = sizeof(OldWorldMacIOState),
 417    .instance_init = macio_oldworld_init,
 418    .class_init    = macio_oldworld_class_init,
 419};
 420
 421static const TypeInfo macio_newworld_type_info = {
 422    .name          = TYPE_NEWWORLD_MACIO,
 423    .parent        = TYPE_MACIO,
 424    .instance_size = sizeof(NewWorldMacIOState),
 425    .instance_init = macio_newworld_init,
 426    .class_init    = macio_newworld_class_init,
 427};
 428
 429static const TypeInfo macio_type_info = {
 430    .name          = TYPE_MACIO,
 431    .parent        = TYPE_PCI_DEVICE,
 432    .instance_size = sizeof(MacIOState),
 433    .instance_init = macio_instance_init,
 434    .abstract      = true,
 435    .class_init    = macio_class_init,
 436    .interfaces = (InterfaceInfo[]) {
 437        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
 438        { },
 439    },
 440};
 441
 442static void macio_register_types(void)
 443{
 444    type_register_static(&macio_type_info);
 445    type_register_static(&macio_oldworld_type_info);
 446    type_register_static(&macio_newworld_type_info);
 447}
 448
 449type_init(macio_register_types)
 450