unin_pci.c 11.7 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 161 162
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);

    register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, &s->host_state);
    qemu_register_reset(pci_unin_reset, &s->host_state);
163
    return 0;
164 165
}

A
Alexander Graf 已提交
166 167 168 169 170 171 172 173
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 已提交
174
    pci_mem_config = pci_host_conf_register_mmio(&s->host_state, 1);
A
Alexander Graf 已提交
175 176 177 178 179 180 181 182 183 184 185 186
    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);

    register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, &s->host_state);
    qemu_register_reset(pci_unin_reset, &s->host_state);

    return 0;
}

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

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

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

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

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

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

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

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

233
#if 0
234
    pci_create_simple(d->host_state.bus, 11 << 3, "uni-north");
235
#endif
236 237 238 239 240 241 242

    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 */
243
    pci_create_simple(d->host_state.bus, 12 << 3, "dec-21154");
244 245 246
#endif

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

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

    return d->host_state.bus;
}

A
Alexander Graf 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
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,
                                         pic, 11 << 3, 4);

    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;
}

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

306
static int unin_agp_pci_host_init(PCIDevice *d)
307
{
308 309
    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 已提交
310
    d->config[0x08] = 0x00; // revision
311
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
P
pbrook 已提交
312 313
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x10; // latency_timer
I
Isaku Yamahata 已提交
314
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
P
pbrook 已提交
315
    //    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 333
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;
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
    return 0;
}

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

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

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

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

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

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

device_init(unin_register_devices)