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