1 /* 2 * PowerMac MacIO device emulation 3 * 4 * Copyright (c) 2005-2007 Fabrice Bellard 5 * Copyright (c) 2007 Jocelyn Mayer 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25 #include "qemu/osdep.h" 26 #include "qapi/error.h" 27 #include "hw/hw.h" 28 #include "hw/ppc/mac.h" 29 #include "hw/misc/macio/cuda.h" 30 #include "hw/pci/pci.h" 31 #include "hw/ppc/mac_dbdma.h" 32 #include "hw/char/escc.h" 33 34 #define TYPE_MACIO "macio" 35 #define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) 36 37 typedef struct MacIOState 38 { 39 /*< private >*/ 40 PCIDevice parent; 41 /*< public >*/ 42 43 MemoryRegion bar; 44 CUDAState cuda; 45 DBDMAState *dbdma; 46 MemoryRegion *pic_mem; 47 MemoryRegion *escc_mem; 48 uint64_t frequency; 49 } MacIOState; 50 51 #define OLDWORLD_MACIO(obj) \ 52 OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO) 53 54 typedef struct OldWorldMacIOState { 55 /*< private >*/ 56 MacIOState parent_obj; 57 /*< public >*/ 58 59 qemu_irq irqs[5]; 60 61 MacIONVRAMState nvram; 62 MACIOIDEState ide[2]; 63 } OldWorldMacIOState; 64 65 #define NEWWORLD_MACIO(obj) \ 66 OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO) 67 68 typedef struct NewWorldMacIOState { 69 /*< private >*/ 70 MacIOState parent_obj; 71 /*< public >*/ 72 qemu_irq irqs[5]; 73 MACIOIDEState ide[2]; 74 } NewWorldMacIOState; 75 76 /* 77 * The mac-io has two interfaces to the ESCC. One is called "escc-legacy", 78 * while the other one is the normal, current ESCC interface. 79 * 80 * The magic below creates memory aliases to spawn the escc-legacy device 81 * purely by rerouting the respective registers to our escc region. This 82 * works because the only difference between the two memory regions is the 83 * register layout, not their semantics. 84 * 85 * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf 86 */ 87 static void macio_escc_legacy_setup(MacIOState *macio_state) 88 { 89 MemoryRegion *escc_legacy = g_new(MemoryRegion, 1); 90 MemoryRegion *bar = &macio_state->bar; 91 int i; 92 static const int maps[] = { 93 0x00, 0x00, /* Command B */ 94 0x02, 0x20, /* Command A */ 95 0x04, 0x10, /* Data B */ 96 0x06, 0x30, /* Data A */ 97 0x08, 0x40, /* Enhancement B */ 98 0x0A, 0x50, /* Enhancement A */ 99 0x80, 0x80, /* Recovery count */ 100 0x90, 0x90, /* Start A */ 101 0xa0, 0xa0, /* Start B */ 102 0xb0, 0xb0, /* Detect AB */ 103 }; 104 105 memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256); 106 for (i = 0; i < ARRAY_SIZE(maps); i += 2) { 107 MemoryRegion *port = g_new(MemoryRegion, 1); 108 memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port", 109 macio_state->escc_mem, maps[i+1], 0x2); 110 memory_region_add_subregion(escc_legacy, maps[i], port); 111 } 112 113 memory_region_add_subregion(bar, 0x12000, escc_legacy); 114 } 115 116 static void macio_bar_setup(MacIOState *macio_state) 117 { 118 MemoryRegion *bar = &macio_state->bar; 119 120 if (macio_state->escc_mem) { 121 memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); 122 macio_escc_legacy_setup(macio_state); 123 } 124 } 125 126 static void macio_common_realize(PCIDevice *d, Error **errp) 127 { 128 MacIOState *s = MACIO(d); 129 SysBusDevice *sysbus_dev; 130 Error *err = NULL; 131 132 object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err); 133 if (err) { 134 error_propagate(errp, err); 135 return; 136 } 137 sysbus_dev = SYS_BUS_DEVICE(s->dbdma); 138 memory_region_add_subregion(&s->bar, 0x08000, 139 sysbus_mmio_get_region(sysbus_dev, 0)); 140 141 object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); 142 if (err) { 143 error_propagate(errp, err); 144 return; 145 } 146 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 147 memory_region_add_subregion(&s->bar, 0x16000, 148 sysbus_mmio_get_region(sysbus_dev, 0)); 149 150 macio_bar_setup(s); 151 pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); 152 } 153 154 static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, 155 qemu_irq irq0, qemu_irq irq1, int dmaid, 156 Error **errp) 157 { 158 SysBusDevice *sysbus_dev; 159 160 sysbus_dev = SYS_BUS_DEVICE(ide); 161 sysbus_connect_irq(sysbus_dev, 0, irq0); 162 sysbus_connect_irq(sysbus_dev, 1, irq1); 163 qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); 164 object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp); 165 macio_ide_register_dma(ide); 166 167 object_property_set_bool(OBJECT(ide), true, "realized", errp); 168 } 169 170 static void macio_oldworld_realize(PCIDevice *d, Error **errp) 171 { 172 MacIOState *s = MACIO(d); 173 OldWorldMacIOState *os = OLDWORLD_MACIO(d); 174 Error *err = NULL; 175 SysBusDevice *sysbus_dev; 176 int i; 177 int cur_irq = 0; 178 179 macio_common_realize(d, &err); 180 if (err) { 181 error_propagate(errp, err); 182 return; 183 } 184 185 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 186 sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]); 187 188 object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err); 189 if (err) { 190 error_propagate(errp, err); 191 return; 192 } 193 sysbus_dev = SYS_BUS_DEVICE(&os->nvram); 194 memory_region_add_subregion(&s->bar, 0x60000, 195 sysbus_mmio_get_region(sysbus_dev, 0)); 196 pmac_format_nvram_partition(&os->nvram, os->nvram.size); 197 198 if (s->pic_mem) { 199 /* Heathrow PIC */ 200 memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); 201 } 202 203 /* IDE buses */ 204 for (i = 0; i < ARRAY_SIZE(os->ide); i++) { 205 qemu_irq irq0 = os->irqs[cur_irq++]; 206 qemu_irq irq1 = os->irqs[cur_irq++]; 207 208 macio_realize_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4), &err); 209 if (err) { 210 error_propagate(errp, err); 211 return; 212 } 213 } 214 } 215 216 static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size, 217 int index) 218 { 219 gchar *name; 220 221 object_initialize(ide, ide_size, TYPE_MACIO_IDE); 222 qdev_set_parent_bus(DEVICE(ide), sysbus_get_default()); 223 memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000), 224 &ide->mem); 225 name = g_strdup_printf("ide[%i]", index); 226 object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL); 227 g_free(name); 228 } 229 230 static void macio_oldworld_init(Object *obj) 231 { 232 MacIOState *s = MACIO(obj); 233 OldWorldMacIOState *os = OLDWORLD_MACIO(obj); 234 DeviceState *dev; 235 int i; 236 237 qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); 238 239 object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM); 240 dev = DEVICE(&os->nvram); 241 qdev_prop_set_uint32(dev, "size", 0x2000); 242 qdev_prop_set_uint32(dev, "it_shift", 4); 243 244 for (i = 0; i < 2; i++) { 245 macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i); 246 } 247 } 248 249 static void timer_write(void *opaque, hwaddr addr, uint64_t value, 250 unsigned size) 251 { 252 } 253 254 static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) 255 { 256 uint32_t value = 0; 257 uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 258 uint64_t kltime; 259 260 kltime = muldiv64(systime, 4194300, NANOSECONDS_PER_SECOND * 4); 261 kltime = muldiv64(kltime, 18432000, 1048575); 262 263 switch (addr) { 264 case 0x38: 265 value = kltime; 266 break; 267 case 0x3c: 268 value = kltime >> 32; 269 break; 270 } 271 272 return value; 273 } 274 275 static const MemoryRegionOps timer_ops = { 276 .read = timer_read, 277 .write = timer_write, 278 .endianness = DEVICE_LITTLE_ENDIAN, 279 }; 280 281 static void macio_newworld_realize(PCIDevice *d, Error **errp) 282 { 283 MacIOState *s = MACIO(d); 284 NewWorldMacIOState *ns = NEWWORLD_MACIO(d); 285 Error *err = NULL; 286 SysBusDevice *sysbus_dev; 287 MemoryRegion *timer_memory = NULL; 288 int i; 289 int cur_irq = 0; 290 291 macio_common_realize(d, &err); 292 if (err) { 293 error_propagate(errp, err); 294 return; 295 } 296 297 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 298 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); 299 300 if (s->pic_mem) { 301 /* OpenPIC */ 302 memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); 303 } 304 305 /* IDE buses */ 306 for (i = 0; i < ARRAY_SIZE(ns->ide); i++) { 307 qemu_irq irq0 = ns->irqs[cur_irq++]; 308 qemu_irq irq1 = ns->irqs[cur_irq++]; 309 310 macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err); 311 if (err) { 312 error_propagate(errp, err); 313 return; 314 } 315 } 316 317 /* Timer */ 318 timer_memory = g_new(MemoryRegion, 1); 319 memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer", 320 0x1000); 321 memory_region_add_subregion(&s->bar, 0x15000, timer_memory); 322 } 323 324 static void macio_newworld_init(Object *obj) 325 { 326 MacIOState *s = MACIO(obj); 327 NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); 328 int i; 329 330 qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); 331 332 for (i = 0; i < 2; i++) { 333 macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i); 334 } 335 } 336 337 static void macio_instance_init(Object *obj) 338 { 339 MacIOState *s = MACIO(obj); 340 341 memory_region_init(&s->bar, obj, "macio", 0x80000); 342 343 object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA); 344 qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); 345 object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); 346 347 s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA)); 348 object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL); 349 } 350 351 static const VMStateDescription vmstate_macio_oldworld = { 352 .name = "macio-oldworld", 353 .version_id = 0, 354 .minimum_version_id = 0, 355 .fields = (VMStateField[]) { 356 VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState), 357 VMSTATE_END_OF_LIST() 358 } 359 }; 360 361 static void macio_oldworld_class_init(ObjectClass *oc, void *data) 362 { 363 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 364 DeviceClass *dc = DEVICE_CLASS(oc); 365 366 pdc->realize = macio_oldworld_realize; 367 pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201; 368 dc->vmsd = &vmstate_macio_oldworld; 369 } 370 371 static const VMStateDescription vmstate_macio_newworld = { 372 .name = "macio-newworld", 373 .version_id = 0, 374 .minimum_version_id = 0, 375 .fields = (VMStateField[]) { 376 VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState), 377 VMSTATE_END_OF_LIST() 378 } 379 }; 380 381 static void macio_newworld_class_init(ObjectClass *oc, void *data) 382 { 383 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 384 DeviceClass *dc = DEVICE_CLASS(oc); 385 386 pdc->realize = macio_newworld_realize; 387 pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; 388 dc->vmsd = &vmstate_macio_newworld; 389 } 390 391 static Property macio_properties[] = { 392 DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0), 393 DEFINE_PROP_END_OF_LIST() 394 }; 395 396 static void macio_class_init(ObjectClass *klass, void *data) 397 { 398 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 399 DeviceClass *dc = DEVICE_CLASS(klass); 400 401 k->vendor_id = PCI_VENDOR_ID_APPLE; 402 k->class_id = PCI_CLASS_OTHERS << 8; 403 dc->props = macio_properties; 404 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 405 } 406 407 static const TypeInfo macio_oldworld_type_info = { 408 .name = TYPE_OLDWORLD_MACIO, 409 .parent = TYPE_MACIO, 410 .instance_size = sizeof(OldWorldMacIOState), 411 .instance_init = macio_oldworld_init, 412 .class_init = macio_oldworld_class_init, 413 }; 414 415 static const TypeInfo macio_newworld_type_info = { 416 .name = TYPE_NEWWORLD_MACIO, 417 .parent = TYPE_MACIO, 418 .instance_size = sizeof(NewWorldMacIOState), 419 .instance_init = macio_newworld_init, 420 .class_init = macio_newworld_class_init, 421 }; 422 423 static const TypeInfo macio_type_info = { 424 .name = TYPE_MACIO, 425 .parent = TYPE_PCI_DEVICE, 426 .instance_size = sizeof(MacIOState), 427 .instance_init = macio_instance_init, 428 .abstract = true, 429 .class_init = macio_class_init, 430 .interfaces = (InterfaceInfo[]) { 431 { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 432 { }, 433 }, 434 }; 435 436 static void macio_register_types(void) 437 { 438 type_register_static(&macio_type_info); 439 type_register_static(&macio_oldworld_type_info); 440 type_register_static(&macio_newworld_type_info); 441 } 442 443 type_init(macio_register_types) 444 445 void macio_init(PCIDevice *d, 446 MemoryRegion *pic_mem, 447 MemoryRegion *escc_mem) 448 { 449 MacIOState *macio_state = MACIO(d); 450 451 macio_state->pic_mem = pic_mem; 452 macio_state->escc_mem = escc_mem; 453 /* Note: this code is strongly inspirated from the corresponding code 454 in PearPC */ 455 qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "timebase-frequency", 456 macio_state->frequency); 457 458 qdev_init_nofail(DEVICE(d)); 459 } 460