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 #include "hw/misc/macio/macio.h" 34 #include "hw/intc/heathrow_pic.h" 35 36 /* 37 * The mac-io has two interfaces to the ESCC. One is called "escc-legacy", 38 * while the other one is the normal, current ESCC interface. 39 * 40 * The magic below creates memory aliases to spawn the escc-legacy device 41 * purely by rerouting the respective registers to our escc region. This 42 * works because the only difference between the two memory regions is the 43 * register layout, not their semantics. 44 * 45 * Reference: ftp://ftp.software.ibm.com/rs6000/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf 46 */ 47 static void macio_escc_legacy_setup(MacIOState *s) 48 { 49 ESCCState *escc = ESCC(&s->escc); 50 SysBusDevice *sbd = SYS_BUS_DEVICE(escc); 51 MemoryRegion *escc_legacy = g_new(MemoryRegion, 1); 52 MemoryRegion *bar = &s->bar; 53 int i; 54 static const int maps[] = { 55 0x00, 0x00, /* Command B */ 56 0x02, 0x20, /* Command A */ 57 0x04, 0x10, /* Data B */ 58 0x06, 0x30, /* Data A */ 59 0x08, 0x40, /* Enhancement B */ 60 0x0A, 0x50, /* Enhancement A */ 61 0x80, 0x80, /* Recovery count */ 62 0x90, 0x90, /* Start A */ 63 0xa0, 0xa0, /* Start B */ 64 0xb0, 0xb0, /* Detect AB */ 65 }; 66 67 memory_region_init(escc_legacy, OBJECT(s), "escc-legacy", 256); 68 for (i = 0; i < ARRAY_SIZE(maps); i += 2) { 69 MemoryRegion *port = g_new(MemoryRegion, 1); 70 memory_region_init_alias(port, OBJECT(s), "escc-legacy-port", 71 sysbus_mmio_get_region(sbd, 0), 72 maps[i + 1], 0x2); 73 memory_region_add_subregion(escc_legacy, maps[i], port); 74 } 75 76 memory_region_add_subregion(bar, 0x12000, escc_legacy); 77 } 78 79 static void macio_bar_setup(MacIOState *s) 80 { 81 ESCCState *escc = ESCC(&s->escc); 82 SysBusDevice *sbd = SYS_BUS_DEVICE(escc); 83 MemoryRegion *bar = &s->bar; 84 85 memory_region_add_subregion(bar, 0x13000, sysbus_mmio_get_region(sbd, 0)); 86 macio_escc_legacy_setup(s); 87 } 88 89 static void macio_common_realize(PCIDevice *d, Error **errp) 90 { 91 MacIOState *s = MACIO(d); 92 SysBusDevice *sysbus_dev; 93 Error *err = NULL; 94 95 object_property_set_bool(OBJECT(&s->dbdma), true, "realized", &err); 96 if (err) { 97 error_propagate(errp, err); 98 return; 99 } 100 sysbus_dev = SYS_BUS_DEVICE(&s->dbdma); 101 memory_region_add_subregion(&s->bar, 0x08000, 102 sysbus_mmio_get_region(sysbus_dev, 0)); 103 104 qdev_prop_set_uint64(DEVICE(&s->cuda), "timebase-frequency", 105 s->frequency); 106 object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); 107 if (err) { 108 error_propagate(errp, err); 109 return; 110 } 111 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 112 memory_region_add_subregion(&s->bar, 0x16000, 113 sysbus_mmio_get_region(sysbus_dev, 0)); 114 115 object_property_set_bool(OBJECT(&s->escc), true, "realized", &err); 116 if (err) { 117 error_propagate(errp, err); 118 return; 119 } 120 121 macio_bar_setup(s); 122 pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); 123 } 124 125 static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, 126 qemu_irq irq0, qemu_irq irq1, int dmaid, 127 Error **errp) 128 { 129 SysBusDevice *sysbus_dev; 130 131 sysbus_dev = SYS_BUS_DEVICE(ide); 132 sysbus_connect_irq(sysbus_dev, 0, irq0); 133 sysbus_connect_irq(sysbus_dev, 1, irq1); 134 qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); 135 object_property_set_link(OBJECT(ide), OBJECT(&s->dbdma), "dbdma", errp); 136 macio_ide_register_dma(ide); 137 138 object_property_set_bool(OBJECT(ide), true, "realized", errp); 139 } 140 141 static void macio_oldworld_realize(PCIDevice *d, Error **errp) 142 { 143 MacIOState *s = MACIO(d); 144 OldWorldMacIOState *os = OLDWORLD_MACIO(d); 145 Error *err = NULL; 146 SysBusDevice *sysbus_dev; 147 int i; 148 int cur_irq = 0; 149 150 macio_common_realize(d, &err); 151 if (err) { 152 error_propagate(errp, err); 153 return; 154 } 155 156 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 157 sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]); 158 159 sysbus_dev = SYS_BUS_DEVICE(&s->escc); 160 sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]); 161 sysbus_connect_irq(sysbus_dev, 1, os->irqs[cur_irq++]); 162 163 object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err); 164 if (err) { 165 error_propagate(errp, err); 166 return; 167 } 168 sysbus_dev = SYS_BUS_DEVICE(&os->nvram); 169 memory_region_add_subregion(&s->bar, 0x60000, 170 sysbus_mmio_get_region(sysbus_dev, 0)); 171 pmac_format_nvram_partition(&os->nvram, os->nvram.size); 172 173 /* Heathrow PIC */ 174 sysbus_dev = SYS_BUS_DEVICE(os->pic); 175 memory_region_add_subregion(&s->bar, 0x0, 176 sysbus_mmio_get_region(sysbus_dev, 0)); 177 178 /* IDE buses */ 179 for (i = 0; i < ARRAY_SIZE(os->ide); i++) { 180 qemu_irq irq0 = os->irqs[cur_irq++]; 181 qemu_irq irq1 = os->irqs[cur_irq++]; 182 183 macio_realize_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4), &err); 184 if (err) { 185 error_propagate(errp, err); 186 return; 187 } 188 } 189 } 190 191 static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size, 192 int index) 193 { 194 gchar *name; 195 196 object_initialize(ide, ide_size, TYPE_MACIO_IDE); 197 qdev_set_parent_bus(DEVICE(ide), sysbus_get_default()); 198 memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000), 199 &ide->mem); 200 name = g_strdup_printf("ide[%i]", index); 201 object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL); 202 g_free(name); 203 } 204 205 static void macio_oldworld_init(Object *obj) 206 { 207 MacIOState *s = MACIO(obj); 208 OldWorldMacIOState *os = OLDWORLD_MACIO(obj); 209 DeviceState *dev; 210 int i; 211 212 qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); 213 214 object_property_add_link(obj, "pic", TYPE_HEATHROW, 215 (Object **) &os->pic, 216 qdev_prop_allow_set_link_before_realize, 217 0, NULL); 218 219 object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM); 220 dev = DEVICE(&os->nvram); 221 qdev_prop_set_uint32(dev, "size", 0x2000); 222 qdev_prop_set_uint32(dev, "it_shift", 4); 223 224 for (i = 0; i < 2; i++) { 225 macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i); 226 } 227 } 228 229 static void timer_write(void *opaque, hwaddr addr, uint64_t value, 230 unsigned size) 231 { 232 } 233 234 static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) 235 { 236 uint32_t value = 0; 237 uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 238 uint64_t kltime; 239 240 kltime = muldiv64(systime, 4194300, NANOSECONDS_PER_SECOND * 4); 241 kltime = muldiv64(kltime, 18432000, 1048575); 242 243 switch (addr) { 244 case 0x38: 245 value = kltime; 246 break; 247 case 0x3c: 248 value = kltime >> 32; 249 break; 250 } 251 252 return value; 253 } 254 255 static const MemoryRegionOps timer_ops = { 256 .read = timer_read, 257 .write = timer_write, 258 .endianness = DEVICE_LITTLE_ENDIAN, 259 }; 260 261 static void macio_newworld_realize(PCIDevice *d, Error **errp) 262 { 263 MacIOState *s = MACIO(d); 264 NewWorldMacIOState *ns = NEWWORLD_MACIO(d); 265 Error *err = NULL; 266 SysBusDevice *sysbus_dev; 267 MemoryRegion *timer_memory = NULL; 268 int i; 269 int cur_irq = 0; 270 271 macio_common_realize(d, &err); 272 if (err) { 273 error_propagate(errp, err); 274 return; 275 } 276 277 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 278 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); 279 280 sysbus_dev = SYS_BUS_DEVICE(&s->escc); 281 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); 282 sysbus_connect_irq(sysbus_dev, 1, ns->irqs[cur_irq++]); 283 284 /* OpenPIC */ 285 sysbus_dev = SYS_BUS_DEVICE(ns->pic); 286 memory_region_add_subregion(&s->bar, 0x40000, 287 sysbus_mmio_get_region(sysbus_dev, 0)); 288 289 /* IDE buses */ 290 for (i = 0; i < ARRAY_SIZE(ns->ide); i++) { 291 qemu_irq irq0 = ns->irqs[cur_irq++]; 292 qemu_irq irq1 = ns->irqs[cur_irq++]; 293 294 macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err); 295 if (err) { 296 error_propagate(errp, err); 297 return; 298 } 299 } 300 301 /* Timer */ 302 timer_memory = g_new(MemoryRegion, 1); 303 memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer", 304 0x1000); 305 memory_region_add_subregion(&s->bar, 0x15000, timer_memory); 306 } 307 308 static void macio_newworld_init(Object *obj) 309 { 310 MacIOState *s = MACIO(obj); 311 NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); 312 int i; 313 314 qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); 315 316 object_property_add_link(obj, "pic", TYPE_OPENPIC, 317 (Object **) &ns->pic, 318 qdev_prop_allow_set_link_before_realize, 319 0, NULL); 320 321 for (i = 0; i < 2; i++) { 322 macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i); 323 } 324 } 325 326 static void macio_instance_init(Object *obj) 327 { 328 MacIOState *s = MACIO(obj); 329 330 memory_region_init(&s->bar, obj, "macio", 0x80000); 331 332 object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA); 333 qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); 334 object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); 335 336 object_initialize(&s->dbdma, sizeof(s->dbdma), TYPE_MAC_DBDMA); 337 qdev_set_parent_bus(DEVICE(&s->dbdma), sysbus_get_default()); 338 object_property_add_child(obj, "dbdma", OBJECT(&s->dbdma), NULL); 339 340 object_initialize(&s->escc, sizeof(s->escc), TYPE_ESCC); 341 qdev_prop_set_uint32(DEVICE(&s->escc), "disabled", 0); 342 qdev_prop_set_uint32(DEVICE(&s->escc), "frequency", ESCC_CLOCK); 343 qdev_prop_set_uint32(DEVICE(&s->escc), "it_shift", 4); 344 qdev_prop_set_chr(DEVICE(&s->escc), "chrA", serial_hds[0]); 345 qdev_prop_set_chr(DEVICE(&s->escc), "chrB", serial_hds[1]); 346 qdev_prop_set_uint32(DEVICE(&s->escc), "chnBtype", escc_serial); 347 qdev_prop_set_uint32(DEVICE(&s->escc), "chnAtype", escc_serial); 348 qdev_set_parent_bus(DEVICE(&s->escc), sysbus_get_default()); 349 object_property_add_child(obj, "escc", OBJECT(&s->escc), NULL); 350 } 351 352 static const VMStateDescription vmstate_macio_oldworld = { 353 .name = "macio-oldworld", 354 .version_id = 0, 355 .minimum_version_id = 0, 356 .fields = (VMStateField[]) { 357 VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState), 358 VMSTATE_END_OF_LIST() 359 } 360 }; 361 362 static void macio_oldworld_class_init(ObjectClass *oc, void *data) 363 { 364 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 365 DeviceClass *dc = DEVICE_CLASS(oc); 366 367 pdc->realize = macio_oldworld_realize; 368 pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201; 369 dc->vmsd = &vmstate_macio_oldworld; 370 } 371 372 static const VMStateDescription vmstate_macio_newworld = { 373 .name = "macio-newworld", 374 .version_id = 0, 375 .minimum_version_id = 0, 376 .fields = (VMStateField[]) { 377 VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState), 378 VMSTATE_END_OF_LIST() 379 } 380 }; 381 382 static void macio_newworld_class_init(ObjectClass *oc, void *data) 383 { 384 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 385 DeviceClass *dc = DEVICE_CLASS(oc); 386 387 pdc->realize = macio_newworld_realize; 388 pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; 389 dc->vmsd = &vmstate_macio_newworld; 390 } 391 392 static Property macio_properties[] = { 393 DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0), 394 DEFINE_PROP_END_OF_LIST() 395 }; 396 397 static void macio_class_init(ObjectClass *klass, void *data) 398 { 399 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 400 DeviceClass *dc = DEVICE_CLASS(klass); 401 402 k->vendor_id = PCI_VENDOR_ID_APPLE; 403 k->class_id = PCI_CLASS_OTHERS << 8; 404 dc->props = macio_properties; 405 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); 406 } 407 408 static const TypeInfo macio_oldworld_type_info = { 409 .name = TYPE_OLDWORLD_MACIO, 410 .parent = TYPE_MACIO, 411 .instance_size = sizeof(OldWorldMacIOState), 412 .instance_init = macio_oldworld_init, 413 .class_init = macio_oldworld_class_init, 414 }; 415 416 static const TypeInfo macio_newworld_type_info = { 417 .name = TYPE_NEWWORLD_MACIO, 418 .parent = TYPE_MACIO, 419 .instance_size = sizeof(NewWorldMacIOState), 420 .instance_init = macio_newworld_init, 421 .class_init = macio_newworld_class_init, 422 }; 423 424 static const TypeInfo macio_type_info = { 425 .name = TYPE_MACIO, 426 .parent = TYPE_PCI_DEVICE, 427 .instance_size = sizeof(MacIOState), 428 .instance_init = macio_instance_init, 429 .abstract = true, 430 .class_init = macio_class_init, 431 .interfaces = (InterfaceInfo[]) { 432 { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 433 { }, 434 }, 435 }; 436 437 static void macio_register_types(void) 438 { 439 type_register_static(&macio_type_info); 440 type_register_static(&macio_oldworld_type_info); 441 type_register_static(&macio_newworld_type_info); 442 } 443 444 type_init(macio_register_types) 445 446 void macio_init(PCIDevice *d, 447 MemoryRegion *pic_mem) 448 { 449 /* Note: this code is strongly inspirated from the corresponding code 450 in PearPC */ 451 qdev_init_nofail(DEVICE(d)); 452 } 453