unin_pci.c 11.6 KB
Newer Older
P
pbrook 已提交
1 2 3 4
/*
 * QEMU Uninorth PCI host (for all Mac99 and newer machines)
 *
 * Copyright (c) 2006 Fabrice Bellard
5
 *
P
pbrook 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
pbrook 已提交
24 25 26
#include "hw.h"
#include "ppc_mac.h"
#include "pci.h"
27
#include "pci_host.h"
P
pbrook 已提交
28

29 30 31 32
/* debug UniNorth */
//#define DEBUG_UNIN

#ifdef DEBUG_UNIN
33 34
#define UNIN_DPRINTF(fmt, ...)                                  \
    do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
35
#else
36
#define UNIN_DPRINTF(fmt, ...)
37 38
#endif

A
Alexander Graf 已提交
39 40
static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };

41 42 43
typedef struct UNINState {
    SysBusDevice busdev;
    PCIHostState host_state;
44
    ReadWriteHandler data_handler;
45
} UNINState;
P
pbrook 已提交
46

47
static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
P
pbrook 已提交
48
{
A
Alexander Graf 已提交
49 50 51 52 53 54
    int retval;
    int devfn = pci_dev->devfn & 0x00FFFFFF;

    retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;

    return retval;
55 56
}

57
static void pci_unin_set_irq(void *opaque, int irq_num, int level)
58
{
59 60
    qemu_irq *pic = opaque;

A
Alexander Graf 已提交
61 62 63
    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
                 unin_irq_line[irq_num], level);
    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
P
pbrook 已提交
64 65
}

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
static void pci_unin_save(QEMUFile* f, void *opaque)
{
    PCIDevice *d = opaque;

    pci_device_save(d, f);
}

static int pci_unin_load(QEMUFile* f, void *opaque, int version_id)
{
    PCIDevice *d = opaque;

    if (version_id != 1)
        return -EINVAL;

    return pci_device_load(d, f);
}

static void pci_unin_reset(void *opaque)
{
}

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
{
    uint32_t retval;

    if (reg & (1u << 31)) {
        /* XXX OpenBIOS compatibility hack */
        retval = reg | (addr & 3);
    } else if (reg & 1) {
        /* CFA1 style */
        retval = (reg & ~7u) | (addr & 7);
    } else {
        uint32_t slot, func;

        /* Grab CFA0 style values */
        slot = ffs(reg & 0xfffff800) - 1;
        func = (reg >> 8) & 7;

        /* ... and then convert them to x86 format */
        /* config pointer */
        retval = (reg & (0xff - 7)) | (addr & 7);
        /* slot */
        retval |= slot << 11;
        /* fn */
        retval |= func << 8;
    }


    UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
                 reg, addr, retval);

    return retval;
}

static void unin_data_write(ReadWriteHandler *handler,
                            pcibus_t addr, uint32_t val, int len)
{
    UNINState *s = container_of(handler, UNINState, data_handler);
    val = qemu_bswap_len(val, len);
    UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
    pci_data_write(s->host_state.bus,
                   unin_get_config_reg(s->host_state.config_reg, addr),
                   val, len);
}

static uint32_t unin_data_read(ReadWriteHandler *handler,
                               pcibus_t addr, int len)
{
    UNINState *s = container_of(handler, UNINState, data_handler);
    uint32_t val;

    val = pci_data_read(s->host_state.bus,
                        unin_get_config_reg(s->host_state.config_reg, addr),
                        len);
    UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
    val = qemu_bswap_len(val, len);
    return val;
}

145
static int pci_unin_main_init_device(SysBusDevice *dev)
P
pbrook 已提交
146 147 148 149 150 151
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

    /* Use values found on a real PowerMac */
    /* Uninorth main bus */
152
    s = FROM_SYSBUS(UNINState, dev);
P
pbrook 已提交
153

B
Blue Swirl 已提交
154
    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
155 156 157
    s->data_handler.read = unin_data_read;
    s->data_handler.write = unin_data_write;
    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
158 159 160
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);

A
Alex Williamson 已提交
161 162
    register_savevm(&dev->qdev, "uninorth", 0, 1,
                    pci_unin_save, pci_unin_load, &s->host_state);
163
    qemu_register_reset(pci_unin_reset, &s->host_state);
164
    return 0;
165 166
}

A
Alexander Graf 已提交
167 168 169 170 171 172 173 174
static int pci_u3_agp_init_device(SysBusDevice *dev)
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

    /* Uninorth U3 AGP bus */
    s = FROM_SYSBUS(UNINState, dev);

B
Blue Swirl 已提交
175
    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
A
Alexander Graf 已提交
176 177 178 179 180 181
    s->data_handler.read = unin_data_read;
    s->data_handler.write = unin_data_write;
    pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);

A
Alex Williamson 已提交
182 183
    register_savevm(&dev->qdev, "uninorth", 0, 1,
                    pci_unin_save, pci_unin_load, &s->host_state);
A
Alexander Graf 已提交
184 185 186 187 188
    qemu_register_reset(pci_unin_reset, &s->host_state);

    return 0;
}

189
static int pci_unin_agp_init_device(SysBusDevice *dev)
190 191 192 193 194 195 196
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

    /* Uninorth AGP bus */
    s = FROM_SYSBUS(UNINState, dev);

B
Blue Swirl 已提交
197 198
    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 0);
    pci_mem_data = pci_host_data_register_mmio(&s->host_state, 1);
199 200
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
201
    return 0;
202 203
}

204
static int pci_unin_internal_init_device(SysBusDevice *dev)
205 206 207 208 209 210 211
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

    /* Uninorth internal bus */
    s = FROM_SYSBUS(UNINState, dev);

B
Blue Swirl 已提交
212 213
    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 0);
    pci_mem_data = pci_host_data_register_mmio(&s->host_state, 1);
214 215
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
216
    return 0;
217 218 219 220 221 222 223 224 225 226
}

PCIBus *pci_pmac_init(qemu_irq *pic)
{
    DeviceState *dev;
    SysBusDevice *s;
    UNINState *d;

    /* Use values found on a real PowerMac */
    /* Uninorth main bus */
227
    dev = qdev_create(NULL, "uni-north");
M
Markus Armbruster 已提交
228
    qdev_init_nofail(dev);
229 230
    s = sysbus_from_qdev(dev);
    d = FROM_SYSBUS(UNINState, s);
231
    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
232
                                         pci_unin_set_irq, pci_unin_map_irq,
233
                                         pic, PCI_DEVFN(11, 0), 4);
234

235
#if 0
236
    pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
237
#endif
238 239 240 241 242 243 244

    sysbus_mmio_map(s, 0, 0xf2800000);
    sysbus_mmio_map(s, 1, 0xf2c00000);

    /* DEC 21154 bridge */
#if 0
    /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
245
    pci_create_simple(d->host_state.bus, PCI_DEVFN(12, 0), "dec-21154");
246 247 248
#endif

    /* Uninorth AGP bus */
249
    pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
250
    dev = qdev_create(NULL, "uni-north-agp");
251 252 253 254
    qdev_init_nofail(dev);
    s = sysbus_from_qdev(dev);
    sysbus_mmio_map(s, 0, 0xf0800000);
    sysbus_mmio_map(s, 1, 0xf0c00000);
255 256 257 258

    /* Uninorth internal bus */
#if 0
    /* XXX: not needed for now */
259
    pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci");
260
    dev = qdev_create(NULL, "uni-north-pci");
261 262 263 264
    qdev_init_nofail(dev);
    s = sysbus_from_qdev(dev);
    sysbus_mmio_map(s, 0, 0xf4800000);
    sysbus_mmio_map(s, 1, 0xf4c00000);
265 266 267 268 269
#endif

    return d->host_state.bus;
}

A
Alexander Graf 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
PCIBus *pci_pmac_u3_init(qemu_irq *pic)
{
    DeviceState *dev;
    SysBusDevice *s;
    UNINState *d;

    /* Uninorth AGP bus */

    dev = qdev_create(NULL, "u3-agp");
    qdev_init_nofail(dev);
    s = sysbus_from_qdev(dev);
    d = FROM_SYSBUS(UNINState, s);

    d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
                                         pci_unin_set_irq, pci_unin_map_irq,
285
                                         pic, PCI_DEVFN(11, 0), 4);
A
Alexander Graf 已提交
286 287 288 289 290 291 292 293 294

    sysbus_mmio_map(s, 0, 0xf0800000);
    sysbus_mmio_map(s, 1, 0xf0c00000);

    pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");

    return d->host_state.bus;
}

295
static int unin_main_pci_host_init(PCIDevice *d)
296
{
297
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
298
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_PCI);
P
pbrook 已提交
299
    d->config[0x08] = 0x00; // revision
300
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
P
pbrook 已提交
301 302 303
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x10; // latency_timer
    d->config[0x34] = 0x00; // capabilities_pointer
304
    return 0;
305
}
P
pbrook 已提交
306

307
static int unin_agp_pci_host_init(PCIDevice *d)
308
{
309 310
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_AGP);
P
pbrook 已提交
311
    d->config[0x08] = 0x00; // revision
312
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
P
pbrook 已提交
313 314 315
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x10; // latency_timer
    //    d->config[0x34] = 0x80; // capabilities_pointer
316
    return 0;
317
}
P
pbrook 已提交
318

A
Alexander Graf 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332
static int u3_agp_pci_host_init(PCIDevice *d)
{
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP);
    /* revision */
    d->config[0x08] = 0x00;
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
    /* cache line size */
    d->config[0x0C] = 0x08;
    /* latency timer */
    d->config[0x0D] = 0x10;
    return 0;
}

333
static int unin_internal_pci_host_init(PCIDevice *d)
334
{
335
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
336
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_I_PCI);
P
pbrook 已提交
337
    d->config[0x08] = 0x00; // revision
338
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
P
pbrook 已提交
339 340 341
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x10; // latency_timer
    d->config[0x34] = 0x00; // capabilities_pointer
342
    return 0;
343 344 345
}

static PCIDeviceInfo unin_main_pci_host_info = {
346
    .qdev.name = "uni-north",
347 348 349 350
    .qdev.size = sizeof(PCIDevice),
    .init      = unin_main_pci_host_init,
};

A
Alexander Graf 已提交
351 352 353 354 355 356
static PCIDeviceInfo u3_agp_pci_host_info = {
    .qdev.name = "u3-agp",
    .qdev.size = sizeof(PCIDevice),
    .init      = u3_agp_pci_host_init,
};

357
static PCIDeviceInfo unin_agp_pci_host_info = {
358
    .qdev.name = "uni-north-agp",
359 360 361 362 363
    .qdev.size = sizeof(PCIDevice),
    .init      = unin_agp_pci_host_init,
};

static PCIDeviceInfo unin_internal_pci_host_info = {
364
    .qdev.name = "uni-north-pci",
365 366 367 368 369 370
    .qdev.size = sizeof(PCIDevice),
    .init      = unin_internal_pci_host_init,
};

static void unin_register_devices(void)
{
371
    sysbus_register_dev("uni-north", sizeof(UNINState),
372 373
                        pci_unin_main_init_device);
    pci_qdev_register(&unin_main_pci_host_info);
A
Alexander Graf 已提交
374 375 376
    sysbus_register_dev("u3-agp", sizeof(UNINState),
                        pci_u3_agp_init_device);
    pci_qdev_register(&u3_agp_pci_host_info);
377
    sysbus_register_dev("uni-north-agp", sizeof(UNINState),
378 379
                        pci_unin_agp_init_device);
    pci_qdev_register(&unin_agp_pci_host_info);
380
    sysbus_register_dev("uni-north-pci", sizeof(UNINState),
381 382
                        pci_unin_internal_init_device);
    pci_qdev_register(&unin_internal_pci_host_info);
P
pbrook 已提交
383
}
384 385

device_init(unin_register_devices)