qemu/hw/grackle_pci.c
<<
>>
Prefs
   1/*
   2 * QEMU Grackle PCI host (heathrow OldWorld PowerMac)
   3 *
   4 * Copyright (c) 2006-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 "sysbus.h"
  27#include "ppc_mac.h"
  28#include "pci.h"
  29#include "pci_host.h"
  30
  31/* debug Grackle */
  32//#define DEBUG_GRACKLE
  33
  34#ifdef DEBUG_GRACKLE
  35#define GRACKLE_DPRINTF(fmt, ...)                               \
  36    do { printf("GRACKLE: " fmt , ## __VA_ARGS__); } while (0)
  37#else
  38#define GRACKLE_DPRINTF(fmt, ...)
  39#endif
  40
  41typedef struct GrackleState {
  42    SysBusDevice busdev;
  43    PCIHostState host_state;
  44} GrackleState;
  45
  46/* Don't know if this matches real hardware, but it agrees with OHW.  */
  47static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
  48{
  49    return (irq_num + (pci_dev->devfn >> 3)) & 3;
  50}
  51
  52static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
  53{
  54    qemu_irq *pic = opaque;
  55
  56    GRACKLE_DPRINTF("set_irq num %d level %d\n", irq_num, level);
  57    qemu_set_irq(pic[irq_num + 0x15], level);
  58}
  59
  60static void pci_grackle_save(QEMUFile* f, void *opaque)
  61{
  62    PCIDevice *d = opaque;
  63
  64    pci_device_save(d, f);
  65}
  66
  67static int pci_grackle_load(QEMUFile* f, void *opaque, int version_id)
  68{
  69    PCIDevice *d = opaque;
  70
  71    if (version_id != 1)
  72        return -EINVAL;
  73
  74    return pci_device_load(d, f);
  75}
  76
  77static void pci_grackle_reset(void *opaque)
  78{
  79}
  80
  81PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
  82{
  83    DeviceState *dev;
  84    SysBusDevice *s;
  85    GrackleState *d;
  86
  87    dev = qdev_create(NULL, "grackle");
  88    qdev_init_nofail(dev);
  89    s = sysbus_from_qdev(dev);
  90    d = FROM_SYSBUS(GrackleState, s);
  91    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
  92                                         pci_grackle_set_irq,
  93                                         pci_grackle_map_irq,
  94                                         pic, 0, 4);
  95
  96    pci_create_simple(d->host_state.bus, 0, "grackle");
  97
  98    sysbus_mmio_map(s, 0, base);
  99    sysbus_mmio_map(s, 1, base + 0x00200000);
 100
 101    return d->host_state.bus;
 102}
 103
 104static int pci_grackle_init_device(SysBusDevice *dev)
 105{
 106    GrackleState *s;
 107    int pci_mem_config, pci_mem_data;
 108
 109    s = FROM_SYSBUS(GrackleState, dev);
 110
 111    pci_mem_config = pci_host_conf_register_mmio(&s->host_state,
 112                                                 DEVICE_LITTLE_ENDIAN);
 113    pci_mem_data = pci_host_data_register_mmio(&s->host_state,
 114                                               DEVICE_LITTLE_ENDIAN);
 115    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
 116    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
 117
 118    register_savevm(&dev->qdev, "grackle", 0, 1, pci_grackle_save,
 119                    pci_grackle_load, &s->host_state);
 120    qemu_register_reset(pci_grackle_reset, &s->host_state);
 121    return 0;
 122}
 123
 124static int grackle_pci_host_init(PCIDevice *d)
 125{
 126    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
 127    pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_MPC106);
 128    d->config[0x08] = 0x00; // revision
 129    d->config[0x09] = 0x01;
 130    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
 131    return 0;
 132}
 133
 134static PCIDeviceInfo grackle_pci_host_info = {
 135    .qdev.name = "grackle",
 136    .qdev.size = sizeof(PCIDevice),
 137    .init      = grackle_pci_host_init,
 138};
 139
 140static void grackle_register_devices(void)
 141{
 142    sysbus_register_dev("grackle", sizeof(GrackleState),
 143                        pci_grackle_init_device);
 144    pci_qdev_register(&grackle_pci_host_info);
 145}
 146
 147device_init(grackle_register_devices)
 148