unin_pci.c 11.9 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 27
#include "hw.h"
#include "ppc_mac.h"
#include "pci.h"

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

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

P
pbrook 已提交
38 39 40
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"

41 42 43 44
typedef struct UNINState {
    SysBusDevice busdev;
    PCIHostState host_state;
} UNINState;
P
pbrook 已提交
45 46 47 48 49 50

static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
                                         uint32_t val)
{
    UNINState *s = opaque;

51
    UNIN_DPRINTF("config_writel addr " TARGET_FMT_plx " val %x\n", addr, val);
P
pbrook 已提交
52 53 54 55
#ifdef TARGET_WORDS_BIGENDIAN
    val = bswap32(val);
#endif

56
    s->host_state.config_reg = val;
P
pbrook 已提交
57 58 59 60 61 62 63 64
}

static uint32_t pci_unin_main_config_readl (void *opaque,
                                            target_phys_addr_t addr)
{
    UNINState *s = opaque;
    uint32_t val;

65
    val = s->host_state.config_reg;
P
pbrook 已提交
66 67 68
#ifdef TARGET_WORDS_BIGENDIAN
    val = bswap32(val);
#endif
69
    UNIN_DPRINTF("config_readl addr " TARGET_FMT_plx " val %x\n", addr, val);
P
pbrook 已提交
70 71 72 73

    return val;
}

74
static CPUWriteMemoryFunc * const pci_unin_main_config_write[] = {
P
pbrook 已提交
75 76 77 78 79
    &pci_unin_main_config_writel,
    &pci_unin_main_config_writel,
    &pci_unin_main_config_writel,
};

80
static CPUReadMemoryFunc * const pci_unin_main_config_read[] = {
P
pbrook 已提交
81 82 83 84 85
    &pci_unin_main_config_readl,
    &pci_unin_main_config_readl,
    &pci_unin_main_config_readl,
};

86
static CPUWriteMemoryFunc * const pci_unin_main_write[] = {
P
pbrook 已提交
87 88 89 90 91
    &pci_host_data_writeb,
    &pci_host_data_writew,
    &pci_host_data_writel,
};

92
static CPUReadMemoryFunc * const pci_unin_main_read[] = {
P
pbrook 已提交
93 94 95 96 97 98 99 100 101 102
    &pci_host_data_readb,
    &pci_host_data_readw,
    &pci_host_data_readl,
};

static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
                                    uint32_t val)
{
    UNINState *s = opaque;

103
    s->host_state.config_reg = val;
P
pbrook 已提交
104 105 106 107 108 109 110
}

static uint32_t pci_unin_config_readl (void *opaque,
                                       target_phys_addr_t addr)
{
    UNINState *s = opaque;

111
    return s->host_state.config_reg;
P
pbrook 已提交
112 113
}

114
static CPUWriteMemoryFunc * const pci_unin_config_write[] = {
P
pbrook 已提交
115 116 117 118 119
    &pci_unin_config_writel,
    &pci_unin_config_writel,
    &pci_unin_config_writel,
};

120
static CPUReadMemoryFunc * const pci_unin_config_read[] = {
P
pbrook 已提交
121 122 123 124 125
    &pci_unin_config_readl,
    &pci_unin_config_readl,
    &pci_unin_config_readl,
};

126
static CPUWriteMemoryFunc * const pci_unin_write[] = {
127 128 129
    &pci_host_data_writeb,
    &pci_host_data_writew,
    &pci_host_data_writel,
P
pbrook 已提交
130 131
};

132
static CPUReadMemoryFunc * const pci_unin_read[] = {
133 134 135
    &pci_host_data_readb,
    &pci_host_data_readw,
    &pci_host_data_readl,
P
pbrook 已提交
136 137
};

138 139
/* Don't know if this matches real hardware, but it agrees with OHW.  */
static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
P
pbrook 已提交
140
{
141 142 143
    return (irq_num + (pci_dev->devfn >> 3)) & 3;
}

P
pbrook 已提交
144
static void pci_unin_set_irq(qemu_irq *pic, int irq_num, int level)
145
{
P
pbrook 已提交
146
    qemu_set_irq(pic[irq_num + 8], level);
P
pbrook 已提交
147 148
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
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)
{
}

170
static void pci_unin_main_init_device(SysBusDevice *dev)
P
pbrook 已提交
171 172 173 174 175 176
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

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

179
    pci_mem_config = cpu_register_io_memory(pci_unin_main_config_read,
P
pbrook 已提交
180
                                            pci_unin_main_config_write, s);
181
    pci_mem_data = cpu_register_io_memory(pci_unin_main_read,
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
                                          pci_unin_main_write, &s->host_state);

    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);
    pci_unin_reset(&s->host_state);
}

static void pci_dec_21154_init_device(SysBusDevice *dev)
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

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

    // XXX: s = &pci_bridge[2];
    pci_mem_config = cpu_register_io_memory(pci_unin_config_read,
                                            pci_unin_config_write, s);
    pci_mem_data = cpu_register_io_memory(pci_unin_main_read,
                                          pci_unin_main_write, &s->host_state);
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
}

static void pci_unin_agp_init_device(SysBusDevice *dev)
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

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

    pci_mem_config = cpu_register_io_memory(pci_unin_config_read,
                                            pci_unin_config_write, s);
    pci_mem_data = cpu_register_io_memory(pci_unin_main_read,
                                          pci_unin_main_write, &s->host_state);
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
}

static void pci_unin_internal_init_device(SysBusDevice *dev)
{
    UNINState *s;
    int pci_mem_config, pci_mem_data;

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

    pci_mem_config = cpu_register_io_memory(pci_unin_config_read,
                                            pci_unin_config_write, s);
    pci_mem_data = cpu_register_io_memory(pci_unin_read,
                                          pci_unin_write, s);
    sysbus_init_mmio(dev, 0x1000, pci_mem_config);
    sysbus_init_mmio(dev, 0x1000, pci_mem_data);
}

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

    /* Use values found on a real PowerMac */
    /* Uninorth main bus */
    dev = qdev_create(NULL, "Uni-north main");
    qdev_init(dev);
    s = sysbus_from_qdev(dev);
    d = FROM_SYSBUS(UNINState, s);
    d->host_state.bus = pci_register_bus(NULL, "pci",
                                         pci_unin_set_irq, pci_unin_map_irq,
                                         pic, 11 << 3, 4);

    pci_create_simple(d->host_state.bus, 11 << 3, "Uni-north main");

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

    /* Uninorth AGP bus */
    pci_create_simple(d->host_state.bus, 13 << 3, "Uni-north AGP");

    /* Uninorth internal bus */
#if 0
    /* XXX: not needed for now */
    pci_create_simple(d->host_state.bus, 14 << 3, "Uni-north internal");
#endif

    return d->host_state.bus;
}

static void unin_main_pci_host_init(PCIDevice *d)
{
282
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
283
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_UNI_N_PCI);
P
pbrook 已提交
284
    d->config[0x08] = 0x00; // revision
285
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
P
pbrook 已提交
286 287
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x10; // latency_timer
I
Isaku Yamahata 已提交
288
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
P
pbrook 已提交
289
    d->config[0x34] = 0x00; // capabilities_pointer
290
}
P
pbrook 已提交
291

292 293
static void dec_21154_pci_host_init(PCIDevice *d)
{
P
pbrook 已提交
294
    /* pci-to-pci bridge */
295 296
    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_DEC);
    pci_config_set_device_id(d->config, PCI_DEVICE_ID_DEC_21154);
P
pbrook 已提交
297
    d->config[0x08] = 0x05; // revision
298
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
P
pbrook 已提交
299 300
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x20; // latency_timer
I
Isaku Yamahata 已提交
301
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_BRIDGE; // header_type
P
pbrook 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

    d->config[0x18] = 0x01; // primary_bus
    d->config[0x19] = 0x02; // secondary_bus
    d->config[0x1A] = 0x02; // subordinate_bus
    d->config[0x1B] = 0x20; // secondary_latency_timer
    d->config[0x1C] = 0x11; // io_base
    d->config[0x1D] = 0x01; // io_limit
    d->config[0x20] = 0x00; // memory_base
    d->config[0x21] = 0x80;
    d->config[0x22] = 0x00; // memory_limit
    d->config[0x23] = 0x80;
    d->config[0x24] = 0x01; // prefetchable_memory_base
    d->config[0x25] = 0x80;
    d->config[0x26] = 0xF1; // prefectchable_memory_limit
    d->config[0x27] = 0x7F;
    // d->config[0x34] = 0xdc // capabilities_pointer
318
}
P
pbrook 已提交
319

320 321
static void unin_agp_pci_host_init(PCIDevice *d)
{
322 323
    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 已提交
324
    d->config[0x08] = 0x00; // revision
325
    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
P
pbrook 已提交
326 327
    d->config[0x0C] = 0x08; // cache_line_size
    d->config[0x0D] = 0x10; // latency_timer
I
Isaku Yamahata 已提交
328
    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
P
pbrook 已提交
329
    //    d->config[0x34] = 0x80; // capabilities_pointer
330
}
P
pbrook 已提交
331

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

static PCIDeviceInfo unin_main_pci_host_info = {
    .qdev.name = "Uni-north main",
    .qdev.size = sizeof(PCIDevice),
    .init      = unin_main_pci_host_init,
};

static PCIDeviceInfo dec_21154_pci_host_info = {
    .qdev.name = "DEC 21154",
    .qdev.size = sizeof(PCIDevice),
    .init      = dec_21154_pci_host_init,
};
355

356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
static PCIDeviceInfo unin_agp_pci_host_info = {
    .qdev.name = "Uni-north AGP",
    .qdev.size = sizeof(PCIDevice),
    .init      = unin_agp_pci_host_init,
};

static PCIDeviceInfo unin_internal_pci_host_info = {
    .qdev.name = "Uni-north internal",
    .qdev.size = sizeof(PCIDevice),
    .init      = unin_internal_pci_host_init,
};

static void unin_register_devices(void)
{
    sysbus_register_dev("Uni-north main", sizeof(UNINState),
                        pci_unin_main_init_device);
    pci_qdev_register(&unin_main_pci_host_info);
    sysbus_register_dev("DEC 21154", sizeof(UNINState),
                        pci_dec_21154_init_device);
    pci_qdev_register(&dec_21154_pci_host_info);
    sysbus_register_dev("Uni-north AGP", sizeof(UNINState),
                        pci_unin_agp_init_device);
    pci_qdev_register(&unin_agp_pci_host_info);
    sysbus_register_dev("Uni-north internal", sizeof(UNINState),
                        pci_unin_internal_init_device);
    pci_qdev_register(&unin_internal_pci_host_info);
P
pbrook 已提交
382
}
383 384

device_init(unin_register_devices)