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
  26#include "qemu/osdep.h"
  27#include "qapi/error.h"
  28#include "qemu/module.h"
  29#include "hw/ppc/mac.h"
  30#include "hw/misc/macio/cuda.h"
  31#include "hw/pci/pci.h"
  32#include "hw/ppc/mac_dbdma.h"
  33#include "hw/qdev-properties.h"
  34#include "migration/vmstate.h"
  35#include "hw/char/escc.h"
  36#include "hw/misc/macio/macio.h"
  37#include "hw/intc/heathrow_pic.h"
  38#include "trace.h"
  39
  40/* Note: this code is strongly inspirated from the corresponding code
  41 * 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 */
  54static 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
  86static 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
  96static 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
 121static 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
 138static 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
 205static 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
 216static 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", 0x2000);
 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
 237static void timer_write(void *opaque, hwaddr addr, uint64_t value,
 238                       unsigned size)
 239{
 240    trace_macio_timer_write(addr, size, value);
 241}
 242
 243static 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
 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    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
 369static 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
 384static 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
 398static 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
 408static 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
 418static 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
 428static 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
 434static 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
 445static Property macio_properties[] = {
 446    DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
 447    DEFINE_PROP_END_OF_LIST()
 448};
 449
 450static 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
 461static const TypeInfo macio_bus_info = {
 462    .name = TYPE_MACIO_BUS,
 463    .parent = TYPE_SYSTEM_BUS,
 464    .instance_size = sizeof(MacIOBusState),
 465};
 466
 467static 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
 475static 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
 483static 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
 496static 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
 504type_init(macio_register_types)
 505