xref: /qemu/hw/pci-host/uninorth.c (revision a16a7907)
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 "qemu/osdep.h"
25 #include "hw/hw.h"
26 #include "hw/ppc/mac.h"
27 #include "hw/pci/pci.h"
28 #include "hw/pci/pci_host.h"
29 
30 /* debug UniNorth */
31 //#define DEBUG_UNIN
32 
33 #ifdef DEBUG_UNIN
34 #define UNIN_DPRINTF(fmt, ...)                                  \
35     do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
36 #else
37 #define UNIN_DPRINTF(fmt, ...)
38 #endif
39 
40 static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
41 
42 #define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
43 #define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
44 #define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
45 #define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
46 
47 #define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
48     OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
49 #define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
50     OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
51 #define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
52     OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
53 #define U3_AGP_HOST_BRIDGE(obj) \
54     OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
55 
56 typedef struct UNINState {
57     PCIHostState parent_obj;
58 
59     MemoryRegion pci_mmio;
60     MemoryRegion pci_hole;
61 } UNINState;
62 
63 static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
64 {
65     return (irq_num + (pci_dev->devfn >> 3)) & 3;
66 }
67 
68 static void pci_unin_set_irq(void *opaque, int irq_num, int level)
69 {
70     qemu_irq *pic = opaque;
71 
72     UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
73                  unin_irq_line[irq_num], level);
74     qemu_set_irq(pic[unin_irq_line[irq_num]], level);
75 }
76 
77 static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
78 {
79     uint32_t retval;
80 
81     if (reg & (1u << 31)) {
82         /* XXX OpenBIOS compatibility hack */
83         retval = reg | (addr & 3);
84     } else if (reg & 1) {
85         /* CFA1 style */
86         retval = (reg & ~7u) | (addr & 7);
87     } else {
88         uint32_t slot, func;
89 
90         /* Grab CFA0 style values */
91         slot = ctz32(reg & 0xfffff800);
92         if (slot == 32) {
93             slot = -1; /* XXX: should this be 0? */
94         }
95         func = (reg >> 8) & 7;
96 
97         /* ... and then convert them to x86 format */
98         /* config pointer */
99         retval = (reg & (0xff - 7)) | (addr & 7);
100         /* slot */
101         retval |= slot << 11;
102         /* fn */
103         retval |= func << 8;
104     }
105 
106 
107     UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
108                  reg, addr, retval);
109 
110     return retval;
111 }
112 
113 static void unin_data_write(void *opaque, hwaddr addr,
114                             uint64_t val, unsigned len)
115 {
116     UNINState *s = opaque;
117     PCIHostState *phb = PCI_HOST_BRIDGE(s);
118     UNIN_DPRINTF("write addr " TARGET_FMT_plx " len %d val %"PRIx64"\n",
119                  addr, len, val);
120     pci_data_write(phb->bus,
121                    unin_get_config_reg(phb->config_reg, addr),
122                    val, len);
123 }
124 
125 static uint64_t unin_data_read(void *opaque, hwaddr addr,
126                                unsigned len)
127 {
128     UNINState *s = opaque;
129     PCIHostState *phb = PCI_HOST_BRIDGE(s);
130     uint32_t val;
131 
132     val = pci_data_read(phb->bus,
133                         unin_get_config_reg(phb->config_reg, addr),
134                         len);
135     UNIN_DPRINTF("read addr " TARGET_FMT_plx " len %d val %x\n",
136                  addr, len, val);
137     return val;
138 }
139 
140 static const MemoryRegionOps unin_data_ops = {
141     .read = unin_data_read,
142     .write = unin_data_write,
143     .endianness = DEVICE_LITTLE_ENDIAN,
144 };
145 
146 static int pci_unin_main_init_device(SysBusDevice *dev)
147 {
148     PCIHostState *h;
149 
150     /* Use values found on a real PowerMac */
151     /* Uninorth main bus */
152     h = PCI_HOST_BRIDGE(dev);
153 
154     memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
155                           dev, "pci-conf-idx", 0x1000);
156     memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev,
157                           "pci-conf-data", 0x1000);
158     sysbus_init_mmio(dev, &h->conf_mem);
159     sysbus_init_mmio(dev, &h->data_mem);
160 
161     return 0;
162 }
163 
164 
165 static int pci_u3_agp_init_device(SysBusDevice *dev)
166 {
167     PCIHostState *h;
168 
169     /* Uninorth U3 AGP bus */
170     h = PCI_HOST_BRIDGE(dev);
171 
172     memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
173                           dev, "pci-conf-idx", 0x1000);
174     memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev,
175                           "pci-conf-data", 0x1000);
176     sysbus_init_mmio(dev, &h->conf_mem);
177     sysbus_init_mmio(dev, &h->data_mem);
178 
179     return 0;
180 }
181 
182 static int pci_unin_agp_init_device(SysBusDevice *dev)
183 {
184     PCIHostState *h;
185 
186     /* Uninorth AGP bus */
187     h = PCI_HOST_BRIDGE(dev);
188 
189     memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
190                           dev, "pci-conf-idx", 0x1000);
191     memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops,
192                           dev, "pci-conf-data", 0x1000);
193     sysbus_init_mmio(dev, &h->conf_mem);
194     sysbus_init_mmio(dev, &h->data_mem);
195     return 0;
196 }
197 
198 static int pci_unin_internal_init_device(SysBusDevice *dev)
199 {
200     PCIHostState *h;
201 
202     /* Uninorth internal bus */
203     h = PCI_HOST_BRIDGE(dev);
204 
205     memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops,
206                           dev, "pci-conf-idx", 0x1000);
207     memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops,
208                           dev, "pci-conf-data", 0x1000);
209     sysbus_init_mmio(dev, &h->conf_mem);
210     sysbus_init_mmio(dev, &h->data_mem);
211     return 0;
212 }
213 
214 PCIBus *pci_pmac_init(qemu_irq *pic,
215                       MemoryRegion *address_space_mem,
216                       MemoryRegion *address_space_io)
217 {
218     DeviceState *dev;
219     SysBusDevice *s;
220     PCIHostState *h;
221     UNINState *d;
222 
223     /* Use values found on a real PowerMac */
224     /* Uninorth main bus */
225     dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
226     qdev_init_nofail(dev);
227     s = SYS_BUS_DEVICE(dev);
228     h = PCI_HOST_BRIDGE(s);
229     d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
230     memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
231     memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
232                              0x80000000ULL, 0x10000000ULL);
233     memory_region_add_subregion(address_space_mem, 0x80000000ULL,
234                                 &d->pci_hole);
235 
236     h->bus = pci_register_root_bus(dev, NULL,
237                                    pci_unin_set_irq, pci_unin_map_irq,
238                                    pic,
239                                    &d->pci_mmio,
240                                    address_space_io,
241                                    PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
242 
243 #if 0
244     pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
245 #endif
246 
247     sysbus_mmio_map(s, 0, 0xf2800000);
248     sysbus_mmio_map(s, 1, 0xf2c00000);
249 
250     /* DEC 21154 bridge */
251 #if 0
252     /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
253     pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
254 #endif
255 
256     /* Uninorth AGP bus */
257     pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
258     dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
259     qdev_init_nofail(dev);
260     s = SYS_BUS_DEVICE(dev);
261     sysbus_mmio_map(s, 0, 0xf0800000);
262     sysbus_mmio_map(s, 1, 0xf0c00000);
263 
264     /* Uninorth internal bus */
265 #if 0
266     /* XXX: not needed for now */
267     pci_create_simple(h->bus, PCI_DEVFN(14, 0),
268                       "uni-north-internal-pci");
269     dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
270     qdev_init_nofail(dev);
271     s = SYS_BUS_DEVICE(dev);
272     sysbus_mmio_map(s, 0, 0xf4800000);
273     sysbus_mmio_map(s, 1, 0xf4c00000);
274 #endif
275 
276     return h->bus;
277 }
278 
279 PCIBus *pci_pmac_u3_init(qemu_irq *pic,
280                          MemoryRegion *address_space_mem,
281                          MemoryRegion *address_space_io)
282 {
283     DeviceState *dev;
284     SysBusDevice *s;
285     PCIHostState *h;
286     UNINState *d;
287 
288     /* Uninorth AGP bus */
289 
290     dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
291     qdev_init_nofail(dev);
292     s = SYS_BUS_DEVICE(dev);
293     h = PCI_HOST_BRIDGE(dev);
294     d = U3_AGP_HOST_BRIDGE(dev);
295 
296     memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL);
297     memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio,
298                              0x80000000ULL, 0x70000000ULL);
299     memory_region_add_subregion(address_space_mem, 0x80000000ULL,
300                                 &d->pci_hole);
301 
302     h->bus = pci_register_root_bus(dev, NULL,
303                                    pci_unin_set_irq, pci_unin_map_irq,
304                                    pic,
305                                    &d->pci_mmio,
306                                    address_space_io,
307                                    PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
308 
309     sysbus_mmio_map(s, 0, 0xf0800000);
310     sysbus_mmio_map(s, 1, 0xf0c00000);
311 
312     pci_create_simple(h->bus, 11 << 3, "u3-agp");
313 
314     return h->bus;
315 }
316 
317 static void unin_main_pci_host_realize(PCIDevice *d, Error **errp)
318 {
319     d->config[0x0C] = 0x08; // cache_line_size
320     d->config[0x0D] = 0x10; // latency_timer
321     d->config[0x34] = 0x00; // capabilities_pointer
322 }
323 
324 static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp)
325 {
326     d->config[0x0C] = 0x08; // cache_line_size
327     d->config[0x0D] = 0x10; // latency_timer
328     //    d->config[0x34] = 0x80; // capabilities_pointer
329     /*
330      * Set kMacRISCPCIAddressSelect (0x48) register to indicate PCI
331      * memory space with base 0x80000000, size 0x10000000 for Apple's
332      * AppleMacRiscPCI driver
333      */
334     d->config[0x48] = 0x0;
335     d->config[0x49] = 0x0;
336     d->config[0x4a] = 0x0;
337     d->config[0x4b] = 0x1;
338 }
339 
340 static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp)
341 {
342     /* cache line size */
343     d->config[0x0C] = 0x08;
344     /* latency timer */
345     d->config[0x0D] = 0x10;
346 }
347 
348 static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp)
349 {
350     d->config[0x0C] = 0x08; // cache_line_size
351     d->config[0x0D] = 0x10; // latency_timer
352     d->config[0x34] = 0x00; // capabilities_pointer
353 }
354 
355 static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
356 {
357     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
358     DeviceClass *dc = DEVICE_CLASS(klass);
359 
360     k->realize   = unin_main_pci_host_realize;
361     k->vendor_id = PCI_VENDOR_ID_APPLE;
362     k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
363     k->revision  = 0x00;
364     k->class_id  = PCI_CLASS_BRIDGE_HOST;
365     /*
366      * PCI-facing part of the host bridge, not usable without the
367      * host-facing part, which can't be device_add'ed, yet.
368      */
369     dc->user_creatable = false;
370 }
371 
372 static const TypeInfo unin_main_pci_host_info = {
373     .name = "uni-north-pci",
374     .parent = TYPE_PCI_DEVICE,
375     .instance_size = sizeof(PCIDevice),
376     .class_init = unin_main_pci_host_class_init,
377     .interfaces = (InterfaceInfo[]) {
378         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
379         { },
380     },
381 };
382 
383 static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
384 {
385     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
386     DeviceClass *dc = DEVICE_CLASS(klass);
387 
388     k->realize   = u3_agp_pci_host_realize;
389     k->vendor_id = PCI_VENDOR_ID_APPLE;
390     k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
391     k->revision  = 0x00;
392     k->class_id  = PCI_CLASS_BRIDGE_HOST;
393     /*
394      * PCI-facing part of the host bridge, not usable without the
395      * host-facing part, which can't be device_add'ed, yet.
396      */
397     dc->user_creatable = false;
398 }
399 
400 static const TypeInfo u3_agp_pci_host_info = {
401     .name = "u3-agp",
402     .parent = TYPE_PCI_DEVICE,
403     .instance_size = sizeof(PCIDevice),
404     .class_init = u3_agp_pci_host_class_init,
405     .interfaces = (InterfaceInfo[]) {
406         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
407         { },
408     },
409 };
410 
411 static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
412 {
413     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
414     DeviceClass *dc = DEVICE_CLASS(klass);
415 
416     k->realize   = unin_agp_pci_host_realize;
417     k->vendor_id = PCI_VENDOR_ID_APPLE;
418     k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
419     k->revision  = 0x00;
420     k->class_id  = PCI_CLASS_BRIDGE_HOST;
421     /*
422      * PCI-facing part of the host bridge, not usable without the
423      * host-facing part, which can't be device_add'ed, yet.
424      */
425     dc->user_creatable = false;
426 }
427 
428 static const TypeInfo unin_agp_pci_host_info = {
429     .name = "uni-north-agp",
430     .parent = TYPE_PCI_DEVICE,
431     .instance_size = sizeof(PCIDevice),
432     .class_init = unin_agp_pci_host_class_init,
433     .interfaces = (InterfaceInfo[]) {
434         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
435         { },
436     },
437 };
438 
439 static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
440 {
441     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
442     DeviceClass *dc = DEVICE_CLASS(klass);
443 
444     k->realize   = unin_internal_pci_host_realize;
445     k->vendor_id = PCI_VENDOR_ID_APPLE;
446     k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
447     k->revision  = 0x00;
448     k->class_id  = PCI_CLASS_BRIDGE_HOST;
449     /*
450      * PCI-facing part of the host bridge, not usable without the
451      * host-facing part, which can't be device_add'ed, yet.
452      */
453     dc->user_creatable = false;
454 }
455 
456 static const TypeInfo unin_internal_pci_host_info = {
457     .name = "uni-north-internal-pci",
458     .parent = TYPE_PCI_DEVICE,
459     .instance_size = sizeof(PCIDevice),
460     .class_init = unin_internal_pci_host_class_init,
461     .interfaces = (InterfaceInfo[]) {
462         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
463         { },
464     },
465 };
466 
467 static void pci_unin_main_class_init(ObjectClass *klass, void *data)
468 {
469     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
470     DeviceClass *dc = DEVICE_CLASS(klass);
471 
472     sbc->init = pci_unin_main_init_device;
473     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
474 }
475 
476 static const TypeInfo pci_unin_main_info = {
477     .name          = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
478     .parent        = TYPE_PCI_HOST_BRIDGE,
479     .instance_size = sizeof(UNINState),
480     .class_init    = pci_unin_main_class_init,
481 };
482 
483 static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
484 {
485     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
486     DeviceClass *dc = DEVICE_CLASS(klass);
487 
488     sbc->init = pci_u3_agp_init_device;
489     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
490 }
491 
492 static const TypeInfo pci_u3_agp_info = {
493     .name          = TYPE_U3_AGP_HOST_BRIDGE,
494     .parent        = TYPE_PCI_HOST_BRIDGE,
495     .instance_size = sizeof(UNINState),
496     .class_init    = pci_u3_agp_class_init,
497 };
498 
499 static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
500 {
501     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
502     DeviceClass *dc = DEVICE_CLASS(klass);
503 
504     sbc->init = pci_unin_agp_init_device;
505     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
506 }
507 
508 static const TypeInfo pci_unin_agp_info = {
509     .name          = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
510     .parent        = TYPE_PCI_HOST_BRIDGE,
511     .instance_size = sizeof(UNINState),
512     .class_init    = pci_unin_agp_class_init,
513 };
514 
515 static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
516 {
517     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
518     DeviceClass *dc = DEVICE_CLASS(klass);
519 
520     sbc->init = pci_unin_internal_init_device;
521     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
522 }
523 
524 static const TypeInfo pci_unin_internal_info = {
525     .name          = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
526     .parent        = TYPE_PCI_HOST_BRIDGE,
527     .instance_size = sizeof(UNINState),
528     .class_init    = pci_unin_internal_class_init,
529 };
530 
531 static void unin_register_types(void)
532 {
533     type_register_static(&unin_main_pci_host_info);
534     type_register_static(&u3_agp_pci_host_info);
535     type_register_static(&unin_agp_pci_host_info);
536     type_register_static(&unin_internal_pci_host_info);
537 
538     type_register_static(&pci_unin_main_info);
539     type_register_static(&pci_u3_agp_info);
540     type_register_static(&pci_unin_agp_info);
541     type_register_static(&pci_unin_internal_info);
542 }
543 
544 type_init(unin_register_types)
545