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, NULL, &pci_host_conf_le_ops, 156 dev, "pci-conf-idx", 0x1000); 157 memory_region_init_io(&h->data_mem, NULL, &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, NULL, &pci_host_conf_le_ops, 174 dev, "pci-conf-idx", 0x1000); 175 memory_region_init_io(&h->data_mem, NULL, &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, NULL, &pci_host_conf_le_ops, 191 dev, "pci-conf-idx", 0x1000); 192 memory_region_init_io(&h->data_mem, NULL, &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, NULL, &pci_host_conf_le_ops, 207 dev, "pci-conf-idx", 0x1000); 208 memory_region_init_io(&h->data_mem, NULL, &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, NULL, "pci-mmio", 0x100000000ULL); 232 memory_region_init_alias(&d->pci_hole, NULL, "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, NULL, "pci-mmio", 0x100000000ULL); 298 memory_region_init_alias(&d->pci_hole, NULL, "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) 493