Statistics
| Branch: | Revision:

root / hw / pci / host / uninorth.c @ 49ab747f

History | View | Annotate | Download (14.7 kB)

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 "hw/hw.h"
25
#include "hw/ppc/mac.h"
26
#include "hw/pci/pci.h"
27
#include "hw/pci/pci_host.h"
28

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

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

    
39
static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
40

    
41
#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
42
#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
43
#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
44
#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
45

    
46
#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
47
    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
48
#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
49
    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
50
#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
51
    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
52
#define U3_AGP_HOST_BRIDGE(obj) \
53
    OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
54

    
55
typedef struct UNINState {
56
    PCIHostState parent_obj;
57

    
58
    MemoryRegion pci_mmio;
59
    MemoryRegion pci_hole;
60
} UNINState;
61

    
62
static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
63
{
64
    int retval;
65
    int devfn = pci_dev->devfn & 0x00FFFFFF;
66

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

    
69
    return retval;
70
}
71

    
72
static void pci_unin_set_irq(void *opaque, int irq_num, int level)
73
{
74
    qemu_irq *pic = opaque;
75

    
76
    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
77
                 unin_irq_line[irq_num], level);
78
    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
79
}
80

    
81
static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
82
{
83
    uint32_t retval;
84

    
85
    if (reg & (1u << 31)) {
86
        /* XXX OpenBIOS compatibility hack */
87
        retval = reg | (addr & 3);
88
    } else if (reg & 1) {
89
        /* CFA1 style */
90
        retval = (reg & ~7u) | (addr & 7);
91
    } else {
92
        uint32_t slot, func;
93

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

    
98
        /* ... and then convert them to x86 format */
99
        /* config pointer */
100
        retval = (reg & (0xff - 7)) | (addr & 7);
101
        /* slot */
102
        retval |= slot << 11;
103
        /* fn */
104
        retval |= func << 8;
105
    }
106

    
107

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

    
111
    return retval;
112
}
113

    
114
static void unin_data_write(void *opaque, hwaddr addr,
115
                            uint64_t val, unsigned len)
116
{
117
    UNINState *s = opaque;
118
    PCIHostState *phb = PCI_HOST_BRIDGE(s);
119
    UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
120
                 addr, len, val);
121
    pci_data_write(phb->bus,
122
                   unin_get_config_reg(phb->config_reg, addr),
123
                   val, len);
124
}
125

    
126
static uint64_t unin_data_read(void *opaque, hwaddr addr,
127
                               unsigned len)
128
{
129
    UNINState *s = opaque;
130
    PCIHostState *phb = PCI_HOST_BRIDGE(s);
131
    uint32_t val;
132

    
133
    val = pci_data_read(phb->bus,
134
                        unin_get_config_reg(phb->config_reg, addr),
135
                        len);
136
    UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
137
                 addr, len, val);
138
    return val;
139
}
140

    
141
static const MemoryRegionOps unin_data_ops = {
142
    .read = unin_data_read,
143
    .write = unin_data_write,
144
    .endianness = DEVICE_LITTLE_ENDIAN,
145
};
146

    
147
static int pci_unin_main_init_device(SysBusDevice *dev)
148
{
149
    PCIHostState *h;
150

    
151
    /* Use values found on a real PowerMac */
152
    /* Uninorth main bus */
153
    h = PCI_HOST_BRIDGE(dev);
154

    
155
    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
156
                          dev, "pci-conf-idx", 0x1000);
157
    memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
158
                          "pci-conf-data", 0x1000);
159
    sysbus_init_mmio(dev, &h->conf_mem);
160
    sysbus_init_mmio(dev, &h->data_mem);
161

    
162
    return 0;
163
}
164

    
165

    
166
static int pci_u3_agp_init_device(SysBusDevice *dev)
167
{
168
    PCIHostState *h;
169

    
170
    /* Uninorth U3 AGP bus */
171
    h = PCI_HOST_BRIDGE(dev);
172

    
173
    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
174
                          dev, "pci-conf-idx", 0x1000);
175
    memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
176
                          "pci-conf-data", 0x1000);
177
    sysbus_init_mmio(dev, &h->conf_mem);
178
    sysbus_init_mmio(dev, &h->data_mem);
179

    
180
    return 0;
181
}
182

    
183
static int pci_unin_agp_init_device(SysBusDevice *dev)
184
{
185
    PCIHostState *h;
186

    
187
    /* Uninorth AGP bus */
188
    h = PCI_HOST_BRIDGE(dev);
189

    
190
    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
191
                          dev, "pci-conf-idx", 0x1000);
192
    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
193
                          dev, "pci-conf-data", 0x1000);
194
    sysbus_init_mmio(dev, &h->conf_mem);
195
    sysbus_init_mmio(dev, &h->data_mem);
196
    return 0;
197
}
198

    
199
static int pci_unin_internal_init_device(SysBusDevice *dev)
200
{
201
    PCIHostState *h;
202

    
203
    /* Uninorth internal bus */
204
    h = PCI_HOST_BRIDGE(dev);
205

    
206
    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
207
                          dev, "pci-conf-idx", 0x1000);
208
    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
209
                          dev, "pci-conf-data", 0x1000);
210
    sysbus_init_mmio(dev, &h->conf_mem);
211
    sysbus_init_mmio(dev, &h->data_mem);
212
    return 0;
213
}
214

    
215
PCIBus *pci_pmac_init(qemu_irq *pic,
216
                      MemoryRegion *address_space_mem,
217
                      MemoryRegion *address_space_io)
218
{
219
    DeviceState *dev;
220
    SysBusDevice *s;
221
    PCIHostState *h;
222
    UNINState *d;
223

    
224
    /* Use values found on a real PowerMac */
225
    /* Uninorth main bus */
226
    dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
227
    qdev_init_nofail(dev);
228
    s = SYS_BUS_DEVICE(dev);
229
    h = PCI_HOST_BRIDGE(s);
230
    d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
231
    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
232
    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
233
                             0x80000000ULL, 0x70000000ULL);
234
    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
235
                                &d->pci_hole);
236

    
237
    h->bus = pci_register_bus(dev, "pci",
238
                              pci_unin_set_irq, pci_unin_map_irq,
239
                              pic,
240
                              &d->pci_mmio,
241
                              address_space_io,
242
                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
243

    
244
#if 0
245
    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
246
#endif
247

    
248
    sysbus_mmio_map(s, 0, 0xf2800000);
249
    sysbus_mmio_map(s, 1, 0xf2c00000);
250

    
251
    /* DEC 21154 bridge */
252
#if 0
253
    /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
254
    pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
255
#endif
256

    
257
    /* Uninorth AGP bus */
258
    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
259
    dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
260
    qdev_init_nofail(dev);
261
    s = SYS_BUS_DEVICE(dev);
262
    sysbus_mmio_map(s, 0, 0xf0800000);
263
    sysbus_mmio_map(s, 1, 0xf0c00000);
264

    
265
    /* Uninorth internal bus */
266
#if 0
267
    /* XXX: not needed for now */
268
    pci_create_simple(h->bus, PCI_DEVFN(14, 0),
269
                      "uni-north-internal-pci");
270
    dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
271
    qdev_init_nofail(dev);
272
    s = SYS_BUS_DEVICE(dev);
273
    sysbus_mmio_map(s, 0, 0xf4800000);
274
    sysbus_mmio_map(s, 1, 0xf4c00000);
275
#endif
276

    
277
    return h->bus;
278
}
279

    
280
PCIBus *pci_pmac_u3_init(qemu_irq *pic,
281
                         MemoryRegion *address_space_mem,
282
                         MemoryRegion *address_space_io)
283
{
284
    DeviceState *dev;
285
    SysBusDevice *s;
286
    PCIHostState *h;
287
    UNINState *d;
288

    
289
    /* Uninorth AGP bus */
290

    
291
    dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
292
    qdev_init_nofail(dev);
293
    s = SYS_BUS_DEVICE(dev);
294
    h = PCI_HOST_BRIDGE(dev);
295
    d = U3_AGP_HOST_BRIDGE(dev);
296

    
297
    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
298
    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
299
                             0x80000000ULL, 0x70000000ULL);
300
    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
301
                                &d->pci_hole);
302

    
303
    h->bus = pci_register_bus(dev, "pci",
304
                              pci_unin_set_irq, pci_unin_map_irq,
305
                              pic,
306
                              &d->pci_mmio,
307
                              address_space_io,
308
                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
309

    
310
    sysbus_mmio_map(s, 0, 0xf0800000);
311
    sysbus_mmio_map(s, 1, 0xf0c00000);
312

    
313
    pci_create_simple(h->bus, 11 << 3, "u3-agp");
314

    
315
    return h->bus;
316
}
317

    
318
static int unin_main_pci_host_init(PCIDevice *d)
319
{
320
    d->config[0x0C] = 0x08; // cache_line_size
321
    d->config[0x0D] = 0x10; // latency_timer
322
    d->config[0x34] = 0x00; // capabilities_pointer
323
    return 0;
324
}
325

    
326
static int unin_agp_pci_host_init(PCIDevice *d)
327
{
328
    d->config[0x0C] = 0x08; // cache_line_size
329
    d->config[0x0D] = 0x10; // latency_timer
330
    //    d->config[0x34] = 0x80; // capabilities_pointer
331
    return 0;
332
}
333

    
334
static int u3_agp_pci_host_init(PCIDevice *d)
335
{
336
    /* cache line size */
337
    d->config[0x0C] = 0x08;
338
    /* latency timer */
339
    d->config[0x0D] = 0x10;
340
    return 0;
341
}
342

    
343
static int unin_internal_pci_host_init(PCIDevice *d)
344
{
345
    d->config[0x0C] = 0x08; // cache_line_size
346
    d->config[0x0D] = 0x10; // latency_timer
347
    d->config[0x34] = 0x00; // capabilities_pointer
348
    return 0;
349
}
350

    
351
static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
352
{
353
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
354

    
355
    k->init      = unin_main_pci_host_init;
356
    k->vendor_id = PCI_VENDOR_ID_APPLE;
357
    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
358
    k->revision  = 0x00;
359
    k->class_id  = PCI_CLASS_BRIDGE_HOST;
360
}
361

    
362
static const TypeInfo unin_main_pci_host_info = {
363
    .name = "uni-north-pci",
364
    .parent = TYPE_PCI_DEVICE,
365
    .instance_size = sizeof(PCIDevice),
366
    .class_init = unin_main_pci_host_class_init,
367
};
368

    
369
static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
370
{
371
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
372

    
373
    k->init      = u3_agp_pci_host_init;
374
    k->vendor_id = PCI_VENDOR_ID_APPLE;
375
    k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
376
    k->revision  = 0x00;
377
    k->class_id  = PCI_CLASS_BRIDGE_HOST;
378
}
379

    
380
static const TypeInfo u3_agp_pci_host_info = {
381
    .name = "u3-agp",
382
    .parent = TYPE_PCI_DEVICE,
383
    .instance_size = sizeof(PCIDevice),
384
    .class_init = u3_agp_pci_host_class_init,
385
};
386

    
387
static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
388
{
389
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
390

    
391
    k->init      = unin_agp_pci_host_init;
392
    k->vendor_id = PCI_VENDOR_ID_APPLE;
393
    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
394
    k->revision  = 0x00;
395
    k->class_id  = PCI_CLASS_BRIDGE_HOST;
396
}
397

    
398
static const TypeInfo unin_agp_pci_host_info = {
399
    .name = "uni-north-agp",
400
    .parent = TYPE_PCI_DEVICE,
401
    .instance_size = sizeof(PCIDevice),
402
    .class_init = unin_agp_pci_host_class_init,
403
};
404

    
405
static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
406
{
407
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
408

    
409
    k->init      = unin_internal_pci_host_init;
410
    k->vendor_id = PCI_VENDOR_ID_APPLE;
411
    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
412
    k->revision  = 0x00;
413
    k->class_id  = PCI_CLASS_BRIDGE_HOST;
414
}
415

    
416
static const TypeInfo unin_internal_pci_host_info = {
417
    .name = "uni-north-internal-pci",
418
    .parent = TYPE_PCI_DEVICE,
419
    .instance_size = sizeof(PCIDevice),
420
    .class_init = unin_internal_pci_host_class_init,
421
};
422

    
423
static void pci_unin_main_class_init(ObjectClass *klass, void *data)
424
{
425
    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
426

    
427
    sbc->init = pci_unin_main_init_device;
428
}
429

    
430
static const TypeInfo pci_unin_main_info = {
431
    .name          = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
432
    .parent        = TYPE_PCI_HOST_BRIDGE,
433
    .instance_size = sizeof(UNINState),
434
    .class_init    = pci_unin_main_class_init,
435
};
436

    
437
static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
438
{
439
    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
440

    
441
    sbc->init = pci_u3_agp_init_device;
442
}
443

    
444
static const TypeInfo pci_u3_agp_info = {
445
    .name          = TYPE_U3_AGP_HOST_BRIDGE,
446
    .parent        = TYPE_PCI_HOST_BRIDGE,
447
    .instance_size = sizeof(UNINState),
448
    .class_init    = pci_u3_agp_class_init,
449
};
450

    
451
static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
452
{
453
    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
454

    
455
    sbc->init = pci_unin_agp_init_device;
456
}
457

    
458
static const TypeInfo pci_unin_agp_info = {
459
    .name          = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
460
    .parent        = TYPE_PCI_HOST_BRIDGE,
461
    .instance_size = sizeof(UNINState),
462
    .class_init    = pci_unin_agp_class_init,
463
};
464

    
465
static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
466
{
467
    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
468

    
469
    sbc->init = pci_unin_internal_init_device;
470
}
471

    
472
static const TypeInfo pci_unin_internal_info = {
473
    .name          = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
474
    .parent        = TYPE_PCI_HOST_BRIDGE,
475
    .instance_size = sizeof(UNINState),
476
    .class_init    = pci_unin_internal_class_init,
477
};
478

    
479
static void unin_register_types(void)
480
{
481
    type_register_static(&unin_main_pci_host_info);
482
    type_register_static(&u3_agp_pci_host_info);
483
    type_register_static(&unin_agp_pci_host_info);
484
    type_register_static(&unin_internal_pci_host_info);
485

    
486
    type_register_static(&pci_unin_main_info);
487
    type_register_static(&pci_u3_agp_info);
488
    type_register_static(&pci_unin_agp_info);
489
    type_register_static(&pci_unin_internal_info);
490
}
491

    
492
type_init(unin_register_types)