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, OBJECT(h), &pci_host_conf_le_ops, 156 dev, "pci-conf-idx", 0x1000); 157 memory_region_init_io(&h->data_mem, OBJECT(h), &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, OBJECT(h), &pci_host_conf_le_ops, 174 dev, "pci-conf-idx", 0x1000); 175 memory_region_init_io(&h->data_mem, OBJECT(h), &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, OBJECT(h), &pci_host_conf_le_ops, 191 dev, "pci-conf-idx", 0x1000); 192 memory_region_init_io(&h->data_mem, OBJECT(h), &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, OBJECT(h), &pci_host_conf_le_ops, 207 dev, "pci-conf-idx", 0x1000); 208 memory_region_init_io(&h->data_mem, OBJECT(h), &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, OBJECT(d), "pci-mmio", 0x100000000ULL); 232 memory_region_init_alias(&d->pci_hole, OBJECT(d), "pci-hole", &d->pci_mmio, 233 0x80000000ULL, 0x10000000ULL); 234 memory_region_add_subregion(address_space_mem, 0x80000000ULL, 235 &d->pci_hole); 236 237 h->bus = pci_register_bus(dev, NULL, 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, OBJECT(d), "pci-mmio", 0x100000000ULL); 298 memory_region_init_alias(&d->pci_hole, OBJECT(d), "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, NULL, 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 void unin_main_pci_host_realize(PCIDevice *d, Error **errp) 319 { 320 d->config[0x0C] = 0x08; // cache_line_size 321 d->config[0x0D] = 0x10; // latency_timer 322 d->config[0x34] = 0x00; // capabilities_pointer 323 } 324 325 static void unin_agp_pci_host_realize(PCIDevice *d, Error **errp) 326 { 327 d->config[0x0C] = 0x08; // cache_line_size 328 d->config[0x0D] = 0x10; // latency_timer 329 // d->config[0x34] = 0x80; // capabilities_pointer 330 } 331 332 static void u3_agp_pci_host_realize(PCIDevice *d, Error **errp) 333 { 334 /* cache line size */ 335 d->config[0x0C] = 0x08; 336 /* latency timer */ 337 d->config[0x0D] = 0x10; 338 } 339 340 static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp) 341 { 342 d->config[0x0C] = 0x08; // cache_line_size 343 d->config[0x0D] = 0x10; // latency_timer 344 d->config[0x34] = 0x00; // capabilities_pointer 345 } 346 347 static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) 348 { 349 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 350 DeviceClass *dc = DEVICE_CLASS(klass); 351 352 k->realize = unin_main_pci_host_realize; 353 k->vendor_id = PCI_VENDOR_ID_APPLE; 354 k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI; 355 k->revision = 0x00; 356 k->class_id = PCI_CLASS_BRIDGE_HOST; 357 /* 358 * PCI-facing part of the host bridge, not usable without the 359 * host-facing part, which can't be device_add'ed, yet. 360 */ 361 dc->cannot_instantiate_with_device_add_yet = true; 362 } 363 364 static const TypeInfo unin_main_pci_host_info = { 365 .name = "uni-north-pci", 366 .parent = TYPE_PCI_DEVICE, 367 .instance_size = sizeof(PCIDevice), 368 .class_init = unin_main_pci_host_class_init, 369 }; 370 371 static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) 372 { 373 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 374 DeviceClass *dc = DEVICE_CLASS(klass); 375 376 k->realize = u3_agp_pci_host_realize; 377 k->vendor_id = PCI_VENDOR_ID_APPLE; 378 k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP; 379 k->revision = 0x00; 380 k->class_id = PCI_CLASS_BRIDGE_HOST; 381 /* 382 * PCI-facing part of the host bridge, not usable without the 383 * host-facing part, which can't be device_add'ed, yet. 384 */ 385 dc->cannot_instantiate_with_device_add_yet = true; 386 } 387 388 static const TypeInfo u3_agp_pci_host_info = { 389 .name = "u3-agp", 390 .parent = TYPE_PCI_DEVICE, 391 .instance_size = sizeof(PCIDevice), 392 .class_init = u3_agp_pci_host_class_init, 393 }; 394 395 static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) 396 { 397 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 398 DeviceClass *dc = DEVICE_CLASS(klass); 399 400 k->realize = unin_agp_pci_host_realize; 401 k->vendor_id = PCI_VENDOR_ID_APPLE; 402 k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP; 403 k->revision = 0x00; 404 k->class_id = PCI_CLASS_BRIDGE_HOST; 405 /* 406 * PCI-facing part of the host bridge, not usable without the 407 * host-facing part, which can't be device_add'ed, yet. 408 */ 409 dc->cannot_instantiate_with_device_add_yet = true; 410 } 411 412 static const TypeInfo unin_agp_pci_host_info = { 413 .name = "uni-north-agp", 414 .parent = TYPE_PCI_DEVICE, 415 .instance_size = sizeof(PCIDevice), 416 .class_init = unin_agp_pci_host_class_init, 417 }; 418 419 static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) 420 { 421 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 422 DeviceClass *dc = DEVICE_CLASS(klass); 423 424 k->realize = unin_internal_pci_host_realize; 425 k->vendor_id = PCI_VENDOR_ID_APPLE; 426 k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI; 427 k->revision = 0x00; 428 k->class_id = PCI_CLASS_BRIDGE_HOST; 429 /* 430 * PCI-facing part of the host bridge, not usable without the 431 * host-facing part, which can't be device_add'ed, yet. 432 */ 433 dc->cannot_instantiate_with_device_add_yet = true; 434 } 435 436 static const TypeInfo unin_internal_pci_host_info = { 437 .name = "uni-north-internal-pci", 438 .parent = TYPE_PCI_DEVICE, 439 .instance_size = sizeof(PCIDevice), 440 .class_init = unin_internal_pci_host_class_init, 441 }; 442 443 static void pci_unin_main_class_init(ObjectClass *klass, void *data) 444 { 445 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 446 447 sbc->init = pci_unin_main_init_device; 448 } 449 450 static const TypeInfo pci_unin_main_info = { 451 .name = TYPE_UNI_NORTH_PCI_HOST_BRIDGE, 452 .parent = TYPE_PCI_HOST_BRIDGE, 453 .instance_size = sizeof(UNINState), 454 .class_init = pci_unin_main_class_init, 455 }; 456 457 static void pci_u3_agp_class_init(ObjectClass *klass, void *data) 458 { 459 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 460 461 sbc->init = pci_u3_agp_init_device; 462 } 463 464 static const TypeInfo pci_u3_agp_info = { 465 .name = TYPE_U3_AGP_HOST_BRIDGE, 466 .parent = TYPE_PCI_HOST_BRIDGE, 467 .instance_size = sizeof(UNINState), 468 .class_init = pci_u3_agp_class_init, 469 }; 470 471 static void pci_unin_agp_class_init(ObjectClass *klass, void *data) 472 { 473 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 474 475 sbc->init = pci_unin_agp_init_device; 476 } 477 478 static const TypeInfo pci_unin_agp_info = { 479 .name = TYPE_UNI_NORTH_AGP_HOST_BRIDGE, 480 .parent = TYPE_PCI_HOST_BRIDGE, 481 .instance_size = sizeof(UNINState), 482 .class_init = pci_unin_agp_class_init, 483 }; 484 485 static void pci_unin_internal_class_init(ObjectClass *klass, void *data) 486 { 487 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); 488 489 sbc->init = pci_unin_internal_init_device; 490 } 491 492 static const TypeInfo pci_unin_internal_info = { 493 .name = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE, 494 .parent = TYPE_PCI_HOST_BRIDGE, 495 .instance_size = sizeof(UNINState), 496 .class_init = pci_unin_internal_class_init, 497 }; 498 499 static void unin_register_types(void) 500 { 501 type_register_static(&unin_main_pci_host_info); 502 type_register_static(&u3_agp_pci_host_info); 503 type_register_static(&unin_agp_pci_host_info); 504 type_register_static(&unin_internal_pci_host_info); 505 506 type_register_static(&pci_unin_main_info); 507 type_register_static(&pci_u3_agp_info); 508 type_register_static(&pci_unin_agp_info); 509 type_register_static(&pci_unin_internal_info); 510 } 511 512 type_init(unin_register_types) 513