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