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