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 = ctz32(reg & 0xfffff800); 96 if (slot == 32) { 97 slot = -1; /* XXX: should this be 0? */ 98 } 99 func = (reg >> 8) & 7; 100 101 /* ... and then convert them to x86 format */ 102 /* config pointer */ 103 retval = (reg & (0xff - 7)) | (addr & 7); 104 /* slot */ 105 retval |= slot << 11; 106 /* fn */ 107 retval |= func << 8; 108 } 109 110 111 UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n", 112 reg, addr, retval); 113 114 return retval; 115 } 116 117 static void unin_data_write(void *opaque, hwaddr addr, 118 uint64_t val, unsigned len) 119 { 120 UNINState *s = opaque; 121 PCIHostState *phb = PCI_HOST_BRIDGE(s); 122 UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n", 123 addr, len, val); 124 pci_data_write(phb->bus, 125 unin_get_config_reg(phb->config_reg, addr), 126 val, len); 127 } 128 129 static uint64_t unin_data_read(void *opaque, hwaddr addr, 130 unsigned len) 131 { 132 UNINState *s = opaque; 133 PCIHostState *phb = PCI_HOST_BRIDGE(s); 134 uint32_t val; 135 136 val = pci_data_read(phb->bus, 137 unin_get_config_reg(phb->config_reg, addr), 138 len); 139 UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n", 140 addr, len, val); 141 return val; 142 } 143 144 static const MemoryRegionOps unin_data_ops = { 145 .read = unin_data_read, 146 .write = unin_data_write, 147 .endianness = DEVICE_LITTLE_ENDIAN, 148 }; 149 150 static int pci_unin_main_init_device(SysBusDevice *dev) 151 { 152 PCIHostState *h; 153 154 /* Use values found on a real PowerMac */ 155 /* Uninorth main bus */ 156 h = PCI_HOST_BRIDGE(dev); 157 158 memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, 159 dev, "pci-conf-idx", 0x1000); 160 memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev, 161 "pci-conf-data", 0x1000); 162 sysbus_init_mmio(dev, &h->conf_mem); 163 sysbus_init_mmio(dev, &h->data_mem); 164 165 return 0; 166 } 167 168 169 static int pci_u3_agp_init_device(SysBusDevice *dev) 170 { 171 PCIHostState *h; 172 173 /* Uninorth U3 AGP bus */ 174 h = PCI_HOST_BRIDGE(dev); 175 176 memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, 177 dev, "pci-conf-idx", 0x1000); 178 memory_region_init_io(&h->data_mem, OBJECT(h), &unin_data_ops, dev, 179 "pci-conf-data", 0x1000); 180 sysbus_init_mmio(dev, &h->conf_mem); 181 sysbus_init_mmio(dev, &h->data_mem); 182 183 return 0; 184 } 185 186 static int pci_unin_agp_init_device(SysBusDevice *dev) 187 { 188 PCIHostState *h; 189 190 /* Uninorth AGP bus */ 191 h = PCI_HOST_BRIDGE(dev); 192 193 memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, 194 dev, "pci-conf-idx", 0x1000); 195 memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, 196 dev, "pci-conf-data", 0x1000); 197 sysbus_init_mmio(dev, &h->conf_mem); 198 sysbus_init_mmio(dev, &h->data_mem); 199 return 0; 200 } 201 202 static int pci_unin_internal_init_device(SysBusDevice *dev) 203 { 204 PCIHostState *h; 205 206 /* Uninorth internal bus */ 207 h = PCI_HOST_BRIDGE(dev); 208 209 memory_region_init_io(&h->conf_mem, OBJECT(h), &pci_host_conf_le_ops, 210 dev, "pci-conf-idx", 0x1000); 211 memory_region_init_io(&h->data_mem, OBJECT(h), &pci_host_data_le_ops, 212 dev, "pci-conf-data", 0x1000); 213 sysbus_init_mmio(dev, &h->conf_mem); 214 sysbus_init_mmio(dev, &h->data_mem); 215 return 0; 216 } 217 218 PCIBus *pci_pmac_init(qemu_irq *pic, 219 MemoryRegion *address_space_mem, 220 MemoryRegion *address_space_io) 221 { 222 DeviceState *dev; 223 SysBusDevice *s; 224 PCIHostState *h; 225 UNINState *d; 226 227 /* Use values found on a real PowerMac */ 228 /* Uninorth main bus */ 229 dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE); 230 qdev_init_nofail(dev); 231 s = SYS_BUS_DEVICE(dev); 232 h = PCI_HOST_BRIDGE(s); 233 d = UNI_NORTH_PCI_HOST_BRIDGE(dev); 234 memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL); 235 memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio, 236 0x80000000ULL, 0x10000000ULL); 237 memory_region_add_subregion(address_space_mem, 0x80000000ULL, 238 &d->pci_hole); 239 240 h->bus = pci_register_bus(dev, NULL, 241 pci_unin_set_irq, pci_unin_map_irq, 242 pic, 243 &d->pci_mmio, 244 address_space_io, 245 PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS); 246 247 #if 0 248 pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north"); 249 #endif 250 251 sysbus_mmio_map(s, 0, 0xf2800000); 252 sysbus_mmio_map(s, 1, 0xf2c00000); 253 254 /* DEC 21154 bridge */ 255 #if 0 256 /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */ 257 pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154"); 258 #endif 259 260 /* Uninorth AGP bus */ 261 pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp"); 262 dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE); 263 qdev_init_nofail(dev); 264 s = SYS_BUS_DEVICE(dev); 265 sysbus_mmio_map(s, 0, 0xf0800000); 266 sysbus_mmio_map(s, 1, 0xf0c00000); 267 268 /* Uninorth internal bus */ 269 #if 0 270 /* XXX: not needed for now */ 271 pci_create_simple(h->bus, PCI_DEVFN(14, 0), 272 "uni-north-internal-pci"); 273 dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE); 274 qdev_init_nofail(dev); 275 s = SYS_BUS_DEVICE(dev); 276 sysbus_mmio_map(s, 0, 0xf4800000); 277 sysbus_mmio_map(s, 1, 0xf4c00000); 278 #endif 279 280 return h->bus; 281 } 282 283 PCIBus *pci_pmac_u3_init(qemu_irq *pic, 284 MemoryRegion *address_space_mem, 285 MemoryRegion *address_space_io) 286 { 287 DeviceState *dev; 288 SysBusDevice *s; 289 PCIHostState *h; 290 UNINState *d; 291 292 /* Uninorth AGP bus */ 293 294 dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE); 295 qdev_init_nofail(dev); 296 s = SYS_BUS_DEVICE(dev); 297 h = PCI_HOST_BRIDGE(dev); 298 d = U3_AGP_HOST_BRIDGE(dev); 299 300 memory_region_init(&d->pci_mmio, OBJECT(d), "pci-mmio", 0x100000000ULL); 301 memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio, 302 0x80000000ULL, 0x70000000ULL); 303 memory_region_add_subregion(address_space_mem, 0x80000000ULL, 304 &d->pci_hole); 305 306 h->bus = pci_register_bus(dev, NULL, 307 pci_unin_set_irq, pci_unin_map_irq, 308 pic, 309 &d->pci_mmio, 310 address_space_io, 311 PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS); 312 313 sysbus_mmio_map(s, 0, 0xf0800000); 314 sysbus_mmio_map(s, 1, 0xf0c00000); 315 316 pci_create_simple(h->bus, 11 << 3, "u3-agp"); 317 318 return h->bus; 319 } 320 321 static void unin_main_pci_host_realize(PCIDevice *d, Error **errp) 322 { 323 d->config[0x0C] = 0x08; // cache_line_size 324 d->config[0x0D] = 0x10; // latency_timer 325 d->config[0x34] = 0x00; // capabilities_pointer 326 } 327 328 static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp) 329 { 330 d->config[0x0C] = 0x08; // cache_line_size 331 d->config[0x0D] = 0x10; // latency_timer 332 // d->config[0x34] = 0x80; // capabilities_pointer 333 } 334 335 static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp) 336 { 337 /* cache line size */ 338 d->config[0x0C] = 0x08; 339 /* latency timer */ 340 d->config[0x0D] = 0x10; 341 } 342 343 static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp) 344 { 345 d->config[0x0C] = 0x08; // cache_line_size 346 d->config[0x0D] = 0x10; // latency_timer 347 d->config[0x34] = 0x00; // capabilities_pointer 348 } 349 350 static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) 351 { 352 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 353 DeviceClass *dc = DEVICE_CLASS(klass); 354 355 k->realize = unin_main_pci_host_realize; 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 * PCI-facing part of the host bridge, not usable without the 362 * host-facing part, which can't be device_add'ed, yet. 363 */ 364 dc->cannot_instantiate_with_device_add_yet = true; 365 } 366 367 static const TypeInfo unin_main_pci_host_info = { 368 .name = "uni-north-pci", 369 .parent = TYPE_PCI_DEVICE, 370 .instance_size = sizeof(PCIDevice), 371 .class_init = unin_main_pci_host_class_init, 372 }; 373 374 static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) 375 { 376 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 377 DeviceClass *dc = DEVICE_CLASS(klass); 378 379 k->realize = u3_agp_pci_host_realize; 380 k->vendor_id = PCI_VENDOR_ID_APPLE; 381 k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP; 382 k->revision = 0x00; 383 k->class_id = PCI_CLASS_BRIDGE_HOST; 384 /* 385 * PCI-facing part of the host bridge, not usable without the 386 * host-facing part, which can't be device_add'ed, yet. 387 */ 388 dc->cannot_instantiate_with_device_add_yet = true; 389 } 390 391 static const TypeInfo u3_agp_pci_host_info = { 392 .name = "u3-agp", 393 .parent = TYPE_PCI_DEVICE, 394 .instance_size = sizeof(PCIDevice), 395 .class_init = u3_agp_pci_host_class_init, 396 }; 397 398 static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) 399 { 400 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 401 DeviceClass *dc = DEVICE_CLASS(klass); 402 403 k->realize = unin_agp_pci_host_realize; 404 k->vendor_id = PCI_VENDOR_ID_APPLE; 405 k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP; 406 k->revision = 0x00; 407 k->class_id = PCI_CLASS_BRIDGE_HOST; 408 /* 409 * PCI-facing part of the host bridge, not usable without the 410 * host-facing part, which can't be device_add'ed, yet. 411 */ 412 dc->cannot_instantiate_with_device_add_yet = true; 413 } 414 415 static const TypeInfo unin_agp_pci_host_info = { 416 .name = "uni-north-agp", 417 .parent = TYPE_PCI_DEVICE, 418 .instance_size = sizeof(PCIDevice), 419 .class_init = unin_agp_pci_host_class_init, 420 }; 421 422 static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) 423 { 424 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 425 DeviceClass *dc = DEVICE_CLASS(klass); 426 427 k->realize = unin_internal_pci_host_realize; 428 k->vendor_id = PCI_VENDOR_ID_APPLE; 429 k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI; 430 k->revision = 0x00; 431 k->class_id = PCI_CLASS_BRIDGE_HOST; 432 /* 433 * PCI-facing part of the host bridge, not usable without the 434 * host-facing part, which can't be device_add'ed, yet. 435 */ 436 dc->cannot_instantiate_with_device_add_yet = true; 437 } 438 439 static const TypeInfo unin_internal_pci_host_info = { 440 .name = "uni-north-internal-pci", 441 .parent = TYPE_PCI_DEVICE, 442 .instance_size = sizeof(PCIDevice), 443 .class_init = unin_internal_pci_host_class_init, 444 }; 445 446 static void pci_unin_main_class_init(ObjectClass *klass, void *data) 447 { 448 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 449 450 sbc->init = pci_unin_main_init_device; 451 } 452 453 static const TypeInfo pci_unin_main_info = { 454 .name = TYPE_UNI_NORTH_PCI_HOST_BRIDGE, 455 .parent = TYPE_PCI_HOST_BRIDGE, 456 .instance_size = sizeof(UNINState), 457 .class_init = pci_unin_main_class_init, 458 }; 459 460 static void pci_u3_agp_class_init(ObjectClass *klass, void *data) 461 { 462 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 463 464 sbc->init = pci_u3_agp_init_device; 465 } 466 467 static const TypeInfo pci_u3_agp_info = { 468 .name = TYPE_U3_AGP_HOST_BRIDGE, 469 .parent = TYPE_PCI_HOST_BRIDGE, 470 .instance_size = sizeof(UNINState), 471 .class_init = pci_u3_agp_class_init, 472 }; 473 474 static void pci_unin_agp_class_init(ObjectClass *klass, void *data) 475 { 476 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 477 478 sbc->init = pci_unin_agp_init_device; 479 } 480 481 static const TypeInfo pci_unin_agp_info = { 482 .name = TYPE_UNI_NORTH_AGP_HOST_BRIDGE, 483 .parent = TYPE_PCI_HOST_BRIDGE, 484 .instance_size = sizeof(UNINState), 485 .class_init = pci_unin_agp_class_init, 486 }; 487 488 static void pci_unin_internal_class_init(ObjectClass *klass, void *data) 489 { 490 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 491 492 sbc->init = pci_unin_internal_init_device; 493 } 494 495 static const TypeInfo pci_unin_internal_info = { 496 .name = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE, 497 .parent = TYPE_PCI_HOST_BRIDGE, 498 .instance_size = sizeof(UNINState), 499 .class_init = pci_unin_internal_class_init, 500 }; 501 502 static void unin_register_types(void) 503 { 504 type_register_static(&unin_main_pci_host_info); 505 type_register_static(&u3_agp_pci_host_info); 506 type_register_static(&unin_agp_pci_host_info); 507 type_register_static(&unin_internal_pci_host_info); 508 509 type_register_static(&pci_unin_main_info); 510 type_register_static(&pci_u3_agp_info); 511 type_register_static(&pci_unin_agp_info); 512 type_register_static(&pci_unin_internal_info); 513 } 514 515 type_init(unin_register_types) 516