qemu/hw/pci-host/uninorth.c
<<
>>
Prefs
   1/*
   2 * QEMU Uninorth PCI host (for all Mac99 and newer machines)
   3 *
   4 * Copyright (c) 2006 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#include "qemu/osdep.h"
  25#include "hw/hw.h"
  26#include "hw/ppc/mac.h"
  27#include "hw/pci/pci.h"
  28#include "hw/pci/pci_host.h"
  29
  30/* debug UniNorth */
  31//#define DEBUG_UNIN
  32
  33#ifdef DEBUG_UNIN
  34#define UNIN_DPRINTF(fmt, ...)                                  \
  35    do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
  36#else
  37#define UNIN_DPRINTF(fmt, ...)
  38#endif
  39
  40static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
  41
  42#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
  43#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
  44#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
  45#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
  46
  47#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
  48    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
  49#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
  50    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
  51#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
  52    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
  53#define U3_AGP_HOST_BRIDGE(obj) \
  54    OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
  55
  56typedef struct UNINState {
  57    PCIHostState parent_obj;
  58
  59    MemoryRegion pci_mmio;
  60    MemoryRegion pci_hole;
  61} UNINState;
  62
  63static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
  64{
  65    int devfn = pci_dev->devfn & 0x00FFFFFF;
  66
  67    return (((devfn >> 11) & 0x1F) + irq_num) & 3;
  68}
  69
  70static void pci_unin_set_irq(void *opaque, int irq_num, int level)
  71{
  72    qemu_irq *pic = opaque;
  73
  74    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
  75                 unin_irq_line[irq_num], level);
  76    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
  77}
  78
  79static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
  80{
  81    uint32_t retval;
  82
  83    if (reg & (1u << 31)) {
  84        /* XXX OpenBIOS compatibility hack */
  85        retval = reg | (addr & 3);
  86    } else if (reg & 1) {
  87        /* CFA1 style */
  88        retval = (reg & ~7u) | (addr & 7);
  89    } else {
  90        uint32_t slot, func;
  91
  92        /* Grab CFA0 style values */
  93        slot = ctz32(reg & 0xfffff800);
  94        if (slot == 32) {
  95            slot = -1; /* XXX: should this be 0? */
  96        }
  97        func = (reg >> 8) & 7;
  98
  99        /* ... and then convert them to x86 format */
 100        /* config pointer */
 101        retval = (reg & (0xff - 7)) | (addr & 7);
 102        /* slot */
 103        retval |= slot << 11;
 104        /* fn */
 105        retval |= func << 8;
 106    }
 107
 108
 109    UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
 110                 reg, addr, retval);
 111
 112    return retval;
 113}
 114
 115static void unin_data_write(void *opaque, hwaddr addr,
 116                            uint64_t val, unsigned len)
 117{
 118    UNINState *s = opaque;
 119    PCIHostState *phb = PCI_HOST_BRIDGE(s);
 120    UNIN_DPRINTF("write addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
 121                 addr, len, val);
 122    pci_data_write(phb->bus,
 123                   unin_get_config_reg(phb->config_reg, addr),
 124                   val, len);
 125}
 126
 127static uint64_t unin_data_read(void *opaque, hwaddr addr,
 128                               unsigned len)
 129{
 130    UNINState *s = opaque;
 131    PCIHostState *phb = PCI_HOST_BRIDGE(s);
 132    uint32_t val;
 133
 134    val = pci_data_read(phb->bus,
 135                        unin_get_config_reg(phb->config_reg, addr),
 136                        len);
 137    UNIN_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
 138                 addr, len, val);
 139    return val;
 140}
 141
 142static const MemoryRegionOps unin_data_ops = {
 143    .read = unin_data_read,
 144    .write = unin_data_write,
 145    .endianness = DEVICE_LITTLE_ENDIAN,
 146};
 147
 148static int pci_unin_main_init_device(SysBusDevice *dev)
 149{
 150    PCIHostState *h;
 151
 152    /* Use values found on a real PowerMac */
 153    /* Uninorth main bus */
 154    h = PCI_HOST_BRIDGE(dev);
 155
 156    memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
 157                          dev, "pci-conf-idx", 0x1000);
 158    memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev,
 159                          "pci-conf-data", 0x1000);
 160    sysbus_init_mmio(dev, &h->conf_mem);
 161    sysbus_init_mmio(dev, &h->data_mem);
 162
 163    return 0;
 164}
 165
 166
 167static int pci_u3_agp_init_device(SysBusDevice *dev)
 168{
 169    PCIHostState *h;
 170
 171    /* Uninorth U3 AGP bus */
 172    h = PCI_HOST_BRIDGE(dev);
 173
 174    memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
 175                          dev, "pci-conf-idx", 0x1000);
 176    memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev,
 177                          "pci-conf-data", 0x1000);
 178    sysbus_init_mmio(dev, &h->conf_mem);
 179    sysbus_init_mmio(dev, &h->data_mem);
 180
 181    return 0;
 182}
 183
 184static int pci_unin_agp_init_device(SysBusDevice *dev)
 185{
 186    PCIHostState *h;
 187
 188    /* Uninorth AGP bus */
 189    h = PCI_HOST_BRIDGE(dev);
 190
 191    memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
 192                          dev, "pci-conf-idx", 0x1000);
 193    memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops,
 194                          dev, "pci-conf-data", 0x1000);
 195    sysbus_init_mmio(dev, &h->conf_mem);
 196    sysbus_init_mmio(dev, &h->data_mem);
 197    return 0;
 198}
 199
 200static int pci_unin_internal_init_device(SysBusDevice *dev)
 201{
 202    PCIHostState *h;
 203
 204    /* Uninorth internal bus */
 205    h = PCI_HOST_BRIDGE(dev);
 206
 207    memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
 208                          dev, "pci-conf-idx", 0x1000);
 209    memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops,
 210                          dev, "pci-conf-data", 0x1000);
 211    sysbus_init_mmio(dev, &h->conf_mem);
 212    sysbus_init_mmio(dev, &h->data_mem);
 213    return 0;
 214}
 215
 216PCIBus *pci_pmac_init(qemu_irq *pic,
 217                      MemoryRegion *address_space_mem,
 218                      MemoryRegion *address_space_io)
 219{
 220    DeviceState *dev;
 221    SysBusDevice *s;
 222    PCIHostState *h;
 223    UNINState *d;
 224
 225    /* Use values found on a real PowerMac */
 226    /* Uninorth main bus */
 227    dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
 228    qdev_init_nofail(dev);
 229    s = SYS_BUS_DEVICE(dev);
 230    h = PCI_HOST_BRIDGE(s);
 231    d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
 232    memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
 233    memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
 234                             0x80000000ULL, 0x10000000ULL);
 235    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
 236                                &d->pci_hole);
 237
 238    h->bus = pci_register_bus(dev, NULL,
 239                              pci_unin_set_irq, pci_unin_map_irq,
 240                              pic,
 241                              &d->pci_mmio,
 242                              address_space_io,
 243                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
 244
 245#if 0
 246    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
 247#endif
 248
 249    sysbus_mmio_map(s, 0, 0xf2800000);
 250    sysbus_mmio_map(s, 1, 0xf2c00000);
 251
 252    /* DEC 21154 bridge */
 253#if 0
 254    /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
 255    pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
 256#endif
 257
 258    /* Uninorth AGP bus */
 259    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
 260    dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
 261    qdev_init_nofail(dev);
 262    s = SYS_BUS_DEVICE(dev);
 263    sysbus_mmio_map(s, 0, 0xf0800000);
 264    sysbus_mmio_map(s, 1, 0xf0c00000);
 265
 266    /* Uninorth internal bus */
 267#if 0
 268    /* XXX: not needed for now */
 269    pci_create_simple(h->bus, PCI_DEVFN(14, 0),
 270                      "uni-north-internal-pci");
 271    dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
 272    qdev_init_nofail(dev);
 273    s = SYS_BUS_DEVICE(dev);
 274    sysbus_mmio_map(s, 0, 0xf4800000);
 275    sysbus_mmio_map(s, 1, 0xf4c00000);
 276#endif
 277
 278    return h->bus;
 279}
 280
 281PCIBus *pci_pmac_u3_init(qemu_irq *pic,
 282                         MemoryRegion *address_space_mem,
 283                         MemoryRegion *address_space_io)
 284{
 285    DeviceState *dev;
 286    SysBusDevice *s;
 287    PCIHostState *h;
 288    UNINState *d;
 289
 290    /* Uninorth AGP bus */
 291
 292    dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
 293    qdev_init_nofail(dev);
 294    s = SYS_BUS_DEVICE(dev);
 295    h = PCI_HOST_BRIDGE(dev);
 296    d = U3_AGP_HOST_BRIDGE(dev);
 297
 298    memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
 299    memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
 300                             0x80000000ULL, 0x70000000ULL);
 301    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
 302                                &d->pci_hole);
 303
 304    h->bus = pci_register_bus(dev, NULL,
 305                              pci_unin_set_irq, pci_unin_map_irq,
 306                              pic,
 307                              &d->pci_mmio,
 308                              address_space_io,
 309                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
 310
 311    sysbus_mmio_map(s, 0, 0xf0800000);
 312    sysbus_mmio_map(s, 1, 0xf0c00000);
 313
 314    pci_create_simple(h->bus, 11 << 3, "u3-agp");
 315
 316    return h->bus;
 317}
 318
 319static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
 320{
 321    d->config[0x0C] = 0x08; // cache_line_size
 322    d->config[0x0D] = 0x10; // latency_timer
 323    d->config[0x34] = 0x00; // capabilities_pointer
 324}
 325
 326static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp)
 327{
 328    d->config[0x0C] = 0x08; // cache_line_size
 329    d->config[0x0D] = 0x10; // latency_timer
 330    //    d->config[0x34] = 0x80; // capabilities_pointer
 331    /*
 332     * Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI
 333     * memory space with base 0x80000000, size 0x10000000 for Apple's
 334     * AppleMacRiscPCI driver
 335     */
 336    d->config[0x48] = 0x0;
 337    d->config[0x49] = 0x0;
 338    d->config[0x4a] = 0x0;
 339    d->config[0x4b] = 0x1;
 340}
 341
 342static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp)
 343{
 344    /* cache line size */
 345    d->config[0x0C] = 0x08;
 346    /* latency timer */
 347    d->config[0x0D] = 0x10;
 348}
 349
 350static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp)
 351{
 352    d->config[0x0C] = 0x08; // cache_line_size
 353    d->config[0x0D] = 0x10; // latency_timer
 354    d->config[0x34] = 0x00; // capabilities_pointer
 355}
 356
 357static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
 358{
 359    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 360    DeviceClass *dc = DEVICE_CLASS(klass);
 361
 362    k->realize   = unin_main_pci_host_realize;
 363    k->vendor_id = PCI_VENDOR_ID_APPLE;
 364    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
 365    k->revision  = 0x00;
 366    k->class_id  = PCI_CLASS_BRIDGE_HOST;
 367    /*
 368     * PCI-facing part of the host bridge, not usable without the
 369     * host-facing part, which can't be device_add'ed, yet.
 370     */
 371    dc->cannot_instantiate_with_device_add_yet = true;
 372}
 373
 374static const TypeInfo unin_main_pci_host_info = {
 375    .name = "uni-north-pci",
 376    .parent = TYPE_PCI_DEVICE,
 377    .instance_size = sizeof(PCIDevice),
 378    .class_init = unin_main_pci_host_class_init,
 379};
 380
 381static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
 382{
 383    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 384    DeviceClass *dc = DEVICE_CLASS(klass);
 385
 386    k->realize   = u3_agp_pci_host_realize;
 387    k->vendor_id = PCI_VENDOR_ID_APPLE;
 388    k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
 389    k->revision  = 0x00;
 390    k->class_id  = PCI_CLASS_BRIDGE_HOST;
 391    /*
 392     * PCI-facing part of the host bridge, not usable without the
 393     * host-facing part, which can't be device_add'ed, yet.
 394     */
 395    dc->cannot_instantiate_with_device_add_yet = true;
 396}
 397
 398static const TypeInfo u3_agp_pci_host_info = {
 399    .name = "u3-agp",
 400    .parent = TYPE_PCI_DEVICE,
 401    .instance_size = sizeof(PCIDevice),
 402    .class_init = u3_agp_pci_host_class_init,
 403};
 404
 405static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
 406{
 407    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 408    DeviceClass *dc = DEVICE_CLASS(klass);
 409
 410    k->realize   = unin_agp_pci_host_realize;
 411    k->vendor_id = PCI_VENDOR_ID_APPLE;
 412    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
 413    k->revision  = 0x00;
 414    k->class_id  = PCI_CLASS_BRIDGE_HOST;
 415    /*
 416     * PCI-facing part of the host bridge, not usable without the
 417     * host-facing part, which can't be device_add'ed, yet.
 418     */
 419    dc->cannot_instantiate_with_device_add_yet = true;
 420}
 421
 422static const TypeInfo unin_agp_pci_host_info = {
 423    .name = "uni-north-agp",
 424    .parent = TYPE_PCI_DEVICE,
 425    .instance_size = sizeof(PCIDevice),
 426    .class_init = unin_agp_pci_host_class_init,
 427};
 428
 429static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
 430{
 431    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 432    DeviceClass *dc = DEVICE_CLASS(klass);
 433
 434    k->realize   = unin_internal_pci_host_realize;
 435    k->vendor_id = PCI_VENDOR_ID_APPLE;
 436    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
 437    k->revision  = 0x00;
 438    k->class_id  = PCI_CLASS_BRIDGE_HOST;
 439    /*
 440     * PCI-facing part of the host bridge, not usable without the
 441     * host-facing part, which can't be device_add'ed, yet.
 442     */
 443    dc->cannot_instantiate_with_device_add_yet = true;
 444}
 445
 446static const TypeInfo unin_internal_pci_host_info = {
 447    .name = "uni-north-internal-pci",
 448    .parent = TYPE_PCI_DEVICE,
 449    .instance_size = sizeof(PCIDevice),
 450    .class_init = unin_internal_pci_host_class_init,
 451};
 452
 453static void pci_unin_main_class_init(ObjectClass *klass, void *data)
 454{
 455    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
 456    DeviceClass *dc = DEVICE_CLASS(klass);
 457
 458    sbc->init = pci_unin_main_init_device;
 459    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 460}
 461
 462static const TypeInfo pci_unin_main_info = {
 463    .name          = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
 464    .parent        = TYPE_PCI_HOST_BRIDGE,
 465    .instance_size = sizeof(UNINState),
 466    .class_init    = pci_unin_main_class_init,
 467};
 468
 469static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
 470{
 471    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
 472    DeviceClass *dc = DEVICE_CLASS(klass);
 473
 474    sbc->init = pci_u3_agp_init_device;
 475    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 476}
 477
 478static const TypeInfo pci_u3_agp_info = {
 479    .name          = TYPE_U3_AGP_HOST_BRIDGE,
 480    .parent        = TYPE_PCI_HOST_BRIDGE,
 481    .instance_size = sizeof(UNINState),
 482    .class_init    = pci_u3_agp_class_init,
 483};
 484
 485static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
 486{
 487    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
 488    DeviceClass *dc = DEVICE_CLASS(klass);
 489
 490    sbc->init = pci_unin_agp_init_device;
 491    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 492}
 493
 494static const TypeInfo pci_unin_agp_info = {
 495    .name          = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
 496    .parent        = TYPE_PCI_HOST_BRIDGE,
 497    .instance_size = sizeof(UNINState),
 498    .class_init    = pci_unin_agp_class_init,
 499};
 500
 501static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
 502{
 503    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
 504    DeviceClass *dc = DEVICE_CLASS(klass);
 505
 506    sbc->init = pci_unin_internal_init_device;
 507    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 508}
 509
 510static const TypeInfo pci_unin_internal_info = {
 511    .name          = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
 512    .parent        = TYPE_PCI_HOST_BRIDGE,
 513    .instance_size = sizeof(UNINState),
 514    .class_init    = pci_unin_internal_class_init,
 515};
 516
 517static void unin_register_types(void)
 518{
 519    type_register_static(&unin_main_pci_host_info);
 520    type_register_static(&u3_agp_pci_host_info);
 521    type_register_static(&unin_agp_pci_host_info);
 522    type_register_static(&unin_internal_pci_host_info);
 523
 524    type_register_static(&pci_unin_main_info);
 525    type_register_static(&pci_u3_agp_info);
 526    type_register_static(&pci_unin_agp_info);
 527    type_register_static(&pci_unin_internal_info);
 528}
 529
 530type_init(unin_register_types)
 531