|
|
1.1 root 1: /*
2: * QEMU Uninorth PCI host (for all Mac99 and newer machines)
3: *
4: * Copyright (c) 2006 Fabrice Bellard
1.1.1.3 root 5: *
1.1 root 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: */
1.1.1.3 root 24: #include "hw.h"
25: #include "ppc_mac.h"
26: #include "pci.h"
1.1.1.7 root 27: #include "pci_host.h"
1.1.1.3 root 28:
1.1.1.4 root 29: /* debug UniNorth */
30: //#define DEBUG_UNIN
31:
32: #ifdef DEBUG_UNIN
1.1.1.5 root 33: #define UNIN_DPRINTF(fmt, ...) \
34: do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
1.1.1.4 root 35: #else
1.1.1.5 root 36: #define UNIN_DPRINTF(fmt, ...)
1.1.1.4 root 37: #endif
38:
1.1.1.8 root 39: static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
40:
1.1.1.7 root 41: typedef struct UNINState {
42: SysBusDevice busdev;
43: PCIHostState host_state;
1.1.1.11! root 44: MemoryRegion pci_mmio;
! 45: MemoryRegion pci_hole;
1.1.1.7 root 46: } UNINState;
1.1 root 47:
1.1.1.7 root 48: static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
1.1 root 49: {
1.1.1.8 root 50: int retval;
51: int devfn = pci_dev->devfn & 0x00FFFFFF;
52:
53: retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
54:
55: return retval;
1.1 root 56: }
57:
1.1.1.7 root 58: static void pci_unin_set_irq(void *opaque, int irq_num, int level)
1.1 root 59: {
1.1.1.7 root 60: qemu_irq *pic = opaque;
1.1 root 61:
1.1.1.8 root 62: UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
63: unin_irq_line[irq_num], level);
64: qemu_set_irq(pic[unin_irq_line[irq_num]], level);
1.1 root 65: }
66:
1.1.1.7 root 67: static void pci_unin_reset(void *opaque)
1.1 root 68: {
1.1.1.2 root 69: }
70:
1.1.1.8 root 71: static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
72: {
73: uint32_t retval;
74:
75: if (reg & (1u << 31)) {
76: /* XXX OpenBIOS compatibility hack */
77: retval = reg | (addr & 3);
78: } else if (reg & 1) {
79: /* CFA1 style */
80: retval = (reg & ~7u) | (addr & 7);
81: } else {
82: uint32_t slot, func;
83:
84: /* Grab CFA0 style values */
85: slot = ffs(reg & 0xfffff800) - 1;
86: func = (reg >> 8) & 7;
87:
88: /* ... and then convert them to x86 format */
89: /* config pointer */
90: retval = (reg & (0xff - 7)) | (addr & 7);
91: /* slot */
92: retval |= slot << 11;
93: /* fn */
94: retval |= func << 8;
95: }
96:
97:
98: UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
99: reg, addr, retval);
100:
101: return retval;
102: }
103:
1.1.1.11! root 104: static void unin_data_write(void *opaque, target_phys_addr_t addr,
! 105: uint64_t val, unsigned len)
1.1.1.8 root 106: {
1.1.1.11! root 107: UNINState *s = opaque;
! 108: UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
! 109: addr, len, val);
1.1.1.8 root 110: pci_data_write(s->host_state.bus,
111: unin_get_config_reg(s->host_state.config_reg, addr),
112: val, len);
113: }
114:
1.1.1.11! root 115: static uint64_t unin_data_read(void *opaque, target_phys_addr_t addr,
! 116: unsigned len)
1.1.1.8 root 117: {
1.1.1.11! root 118: UNINState *s = opaque;
1.1.1.8 root 119: uint32_t val;
120:
121: val = pci_data_read(s->host_state.bus,
122: unin_get_config_reg(s->host_state.config_reg, addr),
123: len);
1.1.1.11! root 124: UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
! 125: addr, len, val);
1.1.1.8 root 126: return val;
127: }
128:
1.1.1.11! root 129: static const MemoryRegionOps unin_data_ops = {
! 130: .read = unin_data_read,
! 131: .write = unin_data_write,
! 132: .endianness = DEVICE_LITTLE_ENDIAN,
! 133: };
! 134:
1.1.1.7 root 135: static int pci_unin_main_init_device(SysBusDevice *dev)
1.1.1.2 root 136: {
1.1.1.7 root 137: UNINState *s;
138:
139: /* Use values found on a real PowerMac */
140: /* Uninorth main bus */
141: s = FROM_SYSBUS(UNINState, dev);
142:
1.1.1.11! root 143: memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
! 144: &s->host_state, "pci-conf-idx", 0x1000);
! 145: memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
! 146: "pci-conf-data", 0x1000);
! 147: sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
! 148: sysbus_init_mmio_region(dev, &s->host_state.data_mem);
1.1.1.7 root 149:
150: qemu_register_reset(pci_unin_reset, &s->host_state);
151: return 0;
1.1 root 152: }
153:
1.1.1.11! root 154:
1.1.1.8 root 155: static int pci_u3_agp_init_device(SysBusDevice *dev)
1.1.1.4 root 156: {
1.1.1.7 root 157: UNINState *s;
1.1.1.4 root 158:
1.1.1.8 root 159: /* Uninorth U3 AGP bus */
1.1.1.7 root 160: s = FROM_SYSBUS(UNINState, dev);
161:
1.1.1.11! root 162: memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
! 163: &s->host_state, "pci-conf-idx", 0x1000);
! 164: memory_region_init_io(&s->host_state.data_mem, &unin_data_ops, s,
! 165: "pci-conf-data", 0x1000);
! 166: sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
! 167: sysbus_init_mmio_region(dev, &s->host_state.data_mem);
1.1.1.8 root 168:
169: qemu_register_reset(pci_unin_reset, &s->host_state);
170:
1.1.1.7 root 171: return 0;
1.1.1.4 root 172: }
173:
1.1.1.7 root 174: static int pci_unin_agp_init_device(SysBusDevice *dev)
1.1.1.4 root 175: {
1.1.1.7 root 176: UNINState *s;
1.1.1.4 root 177:
1.1.1.7 root 178: /* Uninorth AGP bus */
179: s = FROM_SYSBUS(UNINState, dev);
1.1.1.4 root 180:
1.1.1.11! root 181: memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
! 182: &s->host_state, "pci-conf-idx", 0x1000);
! 183: memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
! 184: &s->host_state, "pci-conf-data", 0x1000);
! 185: sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
! 186: sysbus_init_mmio_region(dev, &s->host_state.data_mem);
1.1.1.7 root 187: return 0;
1.1.1.4 root 188: }
189:
1.1.1.7 root 190: static int pci_unin_internal_init_device(SysBusDevice *dev)
1.1.1.4 root 191: {
1.1.1.7 root 192: UNINState *s;
193:
194: /* Uninorth internal bus */
195: s = FROM_SYSBUS(UNINState, dev);
196:
1.1.1.11! root 197: memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
! 198: &s->host_state, "pci-conf-idx", 0x1000);
! 199: memory_region_init_io(&s->host_state.data_mem, &pci_host_data_le_ops,
! 200: &s->host_state, "pci-conf-data", 0x1000);
! 201: sysbus_init_mmio_region(dev, &s->host_state.conf_mem);
! 202: sysbus_init_mmio_region(dev, &s->host_state.data_mem);
1.1.1.7 root 203: return 0;
1.1.1.4 root 204: }
205:
1.1.1.11! root 206: PCIBus *pci_pmac_init(qemu_irq *pic,
! 207: MemoryRegion *address_space_mem,
! 208: MemoryRegion *address_space_io)
1.1 root 209: {
1.1.1.7 root 210: DeviceState *dev;
211: SysBusDevice *s;
212: UNINState *d;
1.1 root 213:
214: /* Use values found on a real PowerMac */
215: /* Uninorth main bus */
1.1.1.7 root 216: dev = qdev_create(NULL, "uni-north");
217: qdev_init_nofail(dev);
218: s = sysbus_from_qdev(dev);
219: d = FROM_SYSBUS(UNINState, s);
1.1.1.11! root 220: memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
! 221: memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
! 222: 0x80000000ULL, 0x70000000ULL);
! 223: memory_region_add_subregion(address_space_mem, 0x80000000ULL,
! 224: &d->pci_hole);
! 225:
1.1.1.7 root 226: d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
227: pci_unin_set_irq, pci_unin_map_irq,
1.1.1.11! root 228: pic,
! 229: &d->pci_mmio,
! 230: address_space_io,
! 231: PCI_DEVFN(11, 0), 4);
1.1.1.7 root 232:
233: #if 0
1.1.1.8 root 234: pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north");
1.1.1.7 root 235: #endif
236:
237: sysbus_mmio_map(s, 0, 0xf2800000);
238: sysbus_mmio_map(s, 1, 0xf2c00000);
239:
240: /* DEC 21154 bridge */
241: #if 0
242: /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
1.1.1.8 root 243: pci_create_simple(d->host_state.bus, PCI_DEVFN(12, 0), "dec-21154");
1.1.1.7 root 244: #endif
245:
246: /* Uninorth AGP bus */
1.1.1.8 root 247: pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
1.1.1.7 root 248: dev = qdev_create(NULL, "uni-north-agp");
249: qdev_init_nofail(dev);
250: s = sysbus_from_qdev(dev);
251: sysbus_mmio_map(s, 0, 0xf0800000);
252: sysbus_mmio_map(s, 1, 0xf0c00000);
253:
254: /* Uninorth internal bus */
255: #if 0
256: /* XXX: not needed for now */
1.1.1.8 root 257: pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci");
1.1.1.7 root 258: dev = qdev_create(NULL, "uni-north-pci");
259: qdev_init_nofail(dev);
260: s = sysbus_from_qdev(dev);
261: sysbus_mmio_map(s, 0, 0xf4800000);
262: sysbus_mmio_map(s, 1, 0xf4c00000);
263: #endif
264:
265: return d->host_state.bus;
266: }
267:
1.1.1.11! root 268: PCIBus *pci_pmac_u3_init(qemu_irq *pic,
! 269: MemoryRegion *address_space_mem,
! 270: MemoryRegion *address_space_io)
1.1.1.8 root 271: {
272: DeviceState *dev;
273: SysBusDevice *s;
274: UNINState *d;
275:
276: /* Uninorth AGP bus */
277:
278: dev = qdev_create(NULL, "u3-agp");
279: qdev_init_nofail(dev);
280: s = sysbus_from_qdev(dev);
281: d = FROM_SYSBUS(UNINState, s);
282:
1.1.1.11! root 283: memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
! 284: memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
! 285: 0x80000000ULL, 0x70000000ULL);
! 286: memory_region_add_subregion(address_space_mem, 0x80000000ULL,
! 287: &d->pci_hole);
! 288:
1.1.1.8 root 289: d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
290: pci_unin_set_irq, pci_unin_map_irq,
1.1.1.11! root 291: pic,
! 292: &d->pci_mmio,
! 293: address_space_io,
! 294: PCI_DEVFN(11, 0), 4);
1.1.1.8 root 295:
296: sysbus_mmio_map(s, 0, 0xf0800000);
297: sysbus_mmio_map(s, 1, 0xf0c00000);
298:
299: pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp");
300:
301: return d->host_state.bus;
302: }
303:
1.1.1.7 root 304: static int unin_main_pci_host_init(PCIDevice *d)
305: {
1.1 root 306: d->config[0x0C] = 0x08; // cache_line_size
307: d->config[0x0D] = 0x10; // latency_timer
308: d->config[0x34] = 0x00; // capabilities_pointer
1.1.1.7 root 309: return 0;
310: }
1.1 root 311:
1.1.1.7 root 312: static int unin_agp_pci_host_init(PCIDevice *d)
313: {
1.1 root 314: d->config[0x0C] = 0x08; // cache_line_size
315: d->config[0x0D] = 0x10; // latency_timer
316: // d->config[0x34] = 0x80; // capabilities_pointer
1.1.1.7 root 317: return 0;
318: }
1.1 root 319:
1.1.1.8 root 320: static int u3_agp_pci_host_init(PCIDevice *d)
321: {
322: /* cache line size */
323: d->config[0x0C] = 0x08;
324: /* latency timer */
325: d->config[0x0D] = 0x10;
326: return 0;
327: }
328:
1.1.1.7 root 329: static int unin_internal_pci_host_init(PCIDevice *d)
330: {
1.1 root 331: d->config[0x0C] = 0x08; // cache_line_size
332: d->config[0x0D] = 0x10; // latency_timer
333: d->config[0x34] = 0x00; // capabilities_pointer
1.1.1.7 root 334: return 0;
335: }
336:
337: static PCIDeviceInfo unin_main_pci_host_info = {
338: .qdev.name = "uni-north",
339: .qdev.size = sizeof(PCIDevice),
340: .init = unin_main_pci_host_init,
1.1.1.10 root 341: .vendor_id = PCI_VENDOR_ID_APPLE,
342: .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
343: .revision = 0x00,
344: .class_id = PCI_CLASS_BRIDGE_HOST,
1.1.1.7 root 345: };
346:
1.1.1.8 root 347: static PCIDeviceInfo u3_agp_pci_host_info = {
348: .qdev.name = "u3-agp",
1.1.1.7 root 349: .qdev.size = sizeof(PCIDevice),
1.1.1.8 root 350: .init = u3_agp_pci_host_init,
1.1.1.10 root 351: .vendor_id = PCI_VENDOR_ID_APPLE,
352: .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
353: .revision = 0x00,
354: .class_id = PCI_CLASS_BRIDGE_HOST,
1.1.1.7 root 355: };
356:
357: static PCIDeviceInfo unin_agp_pci_host_info = {
358: .qdev.name = "uni-north-agp",
359: .qdev.size = sizeof(PCIDevice),
360: .init = unin_agp_pci_host_init,
1.1.1.10 root 361: .vendor_id = PCI_VENDOR_ID_APPLE,
362: .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
363: .revision = 0x00,
364: .class_id = PCI_CLASS_BRIDGE_HOST,
1.1.1.7 root 365: };
1.1.1.4 root 366:
1.1.1.7 root 367: static PCIDeviceInfo unin_internal_pci_host_info = {
368: .qdev.name = "uni-north-pci",
369: .qdev.size = sizeof(PCIDevice),
370: .init = unin_internal_pci_host_init,
1.1.1.10 root 371: .vendor_id = PCI_VENDOR_ID_APPLE,
372: .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
373: .revision = 0x00,
374: .class_id = PCI_CLASS_BRIDGE_HOST,
1.1.1.7 root 375: };
376:
377: static void unin_register_devices(void)
378: {
379: sysbus_register_dev("uni-north", sizeof(UNINState),
380: pci_unin_main_init_device);
381: pci_qdev_register(&unin_main_pci_host_info);
1.1.1.8 root 382: sysbus_register_dev("u3-agp", sizeof(UNINState),
383: pci_u3_agp_init_device);
384: pci_qdev_register(&u3_agp_pci_host_info);
1.1.1.7 root 385: sysbus_register_dev("uni-north-agp", sizeof(UNINState),
386: pci_unin_agp_init_device);
387: pci_qdev_register(&unin_agp_pci_host_info);
388: sysbus_register_dev("uni-north-pci", sizeof(UNINState),
389: pci_unin_internal_init_device);
390: pci_qdev_register(&unin_internal_pci_host_info);
1.1 root 391: }
1.1.1.7 root 392:
393: device_init(unin_register_devices)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.