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 "hw/hw.h" 26 #include "hw/ppc/mac.h" 27 #include "hw/pci/pci.h" 28 #include "hw/ppc/mac_dbdma.h" 29 #include "hw/char/escc.h" 30 31 #define TYPE_MACIO "macio" 32 #define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) 33 34 typedef struct MacIOState 35 { 36 /*< private >*/ 37 PCIDevice parent; 38 /*< public >*/ 39 40 MemoryRegion bar; 41 CUDAState cuda; 42 void *dbdma; 43 MemoryRegion *pic_mem; 44 MemoryRegion *escc_mem; 45 } MacIOState; 46 47 #define OLDWORLD_MACIO(obj) \ 48 OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO) 49 50 typedef struct OldWorldMacIOState { 51 /*< private >*/ 52 MacIOState parent_obj; 53 /*< public >*/ 54 55 qemu_irq irqs[3]; 56 57 MacIONVRAMState nvram; 58 MACIOIDEState ide; 59 } OldWorldMacIOState; 60 61 #define NEWWORLD_MACIO(obj) \ 62 OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO) 63 64 typedef struct NewWorldMacIOState { 65 /*< private >*/ 66 MacIOState parent_obj; 67 /*< public >*/ 68 qemu_irq irqs[5]; 69 MACIOIDEState ide[2]; 70 } NewWorldMacIOState; 71 72 static void macio_bar_setup(MacIOState *macio_state) 73 { 74 MemoryRegion *bar = &macio_state->bar; 75 76 if (macio_state->escc_mem) { 77 memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); 78 } 79 } 80 81 static int macio_common_initfn(PCIDevice *d) 82 { 83 MacIOState *s = MACIO(d); 84 SysBusDevice *sysbus_dev; 85 int ret; 86 87 d->config[0x3d] = 0x01; // interrupt on pin 1 88 89 ret = qdev_init(DEVICE(&s->cuda)); 90 if (ret < 0) { 91 return ret; 92 } 93 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 94 memory_region_add_subregion(&s->bar, 0x16000, 95 sysbus_mmio_get_region(sysbus_dev, 0)); 96 97 macio_bar_setup(s); 98 pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); 99 100 return 0; 101 } 102 103 static int macio_oldworld_initfn(PCIDevice *d) 104 { 105 MacIOState *s = MACIO(d); 106 OldWorldMacIOState *os = OLDWORLD_MACIO(d); 107 SysBusDevice *sysbus_dev; 108 int ret = macio_common_initfn(d); 109 if (ret < 0) { 110 return ret; 111 } 112 113 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 114 sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]); 115 116 ret = qdev_init(DEVICE(&os->nvram)); 117 if (ret < 0) { 118 return ret; 119 } 120 sysbus_dev = SYS_BUS_DEVICE(&os->nvram); 121 memory_region_add_subregion(&s->bar, 0x60000, 122 sysbus_mmio_get_region(sysbus_dev, 0)); 123 pmac_format_nvram_partition(&os->nvram, os->nvram.size); 124 125 if (s->pic_mem) { 126 /* Heathrow PIC */ 127 memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); 128 } 129 130 sysbus_dev = SYS_BUS_DEVICE(&os->ide); 131 sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]); 132 sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]); 133 macio_ide_register_dma(&os->ide, s->dbdma, 0x16); 134 ret = qdev_init(DEVICE(&os->ide)); 135 if (ret < 0) { 136 return ret; 137 } 138 139 return 0; 140 } 141 142 static void macio_oldworld_init(Object *obj) 143 { 144 MacIOState *s = MACIO(obj); 145 OldWorldMacIOState *os = OLDWORLD_MACIO(obj); 146 DeviceState *dev; 147 148 qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); 149 150 object_initialize(&os->nvram, TYPE_MACIO_NVRAM); 151 dev = DEVICE(&os->nvram); 152 qdev_prop_set_uint32(dev, "size", 0x2000); 153 qdev_prop_set_uint32(dev, "it_shift", 4); 154 155 object_initialize(&os->ide, TYPE_MACIO_IDE); 156 qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default()); 157 memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem); 158 object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL); 159 } 160 161 static int macio_newworld_initfn(PCIDevice *d) 162 { 163 MacIOState *s = MACIO(d); 164 NewWorldMacIOState *ns = NEWWORLD_MACIO(d); 165 SysBusDevice *sysbus_dev; 166 int ret = macio_common_initfn(d); 167 if (ret < 0) { 168 return ret; 169 } 170 171 sysbus_dev = SYS_BUS_DEVICE(&s->cuda); 172 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]); 173 174 if (s->pic_mem) { 175 /* OpenPIC */ 176 memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); 177 } 178 179 sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]); 180 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]); 181 sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]); 182 macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16); 183 ret = qdev_init(DEVICE(&ns->ide[0])); 184 if (ret < 0) { 185 return ret; 186 } 187 188 sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]); 189 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]); 190 sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]); 191 macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a); 192 ret = qdev_init(DEVICE(&ns->ide[1])); 193 if (ret < 0) { 194 return ret; 195 } 196 197 return 0; 198 } 199 200 static void macio_newworld_init(Object *obj) 201 { 202 MacIOState *s = MACIO(obj); 203 NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); 204 int i; 205 gchar *name; 206 207 qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); 208 209 for (i = 0; i < 2; i++) { 210 object_initialize(&ns->ide[i], TYPE_MACIO_IDE); 211 qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default()); 212 memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000), 213 &ns->ide[i].mem); 214 name = g_strdup_printf("ide[%i]", i); 215 object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL); 216 g_free(name); 217 } 218 } 219 220 static void macio_instance_init(Object *obj) 221 { 222 MacIOState *s = MACIO(obj); 223 MemoryRegion *dbdma_mem; 224 225 memory_region_init(&s->bar, "macio", 0x80000); 226 227 object_initialize(&s->cuda, TYPE_CUDA); 228 qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); 229 object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); 230 231 s->dbdma = DBDMA_init(&dbdma_mem); 232 memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem); 233 } 234 235 static void macio_oldworld_class_init(ObjectClass *oc, void *data) 236 { 237 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 238 239 pdc->init = macio_oldworld_initfn; 240 pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201; 241 } 242 243 static void macio_newworld_class_init(ObjectClass *oc, void *data) 244 { 245 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); 246 247 pdc->init = macio_newworld_initfn; 248 pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; 249 } 250 251 static void macio_class_init(ObjectClass *klass, void *data) 252 { 253 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 254 255 k->vendor_id = PCI_VENDOR_ID_APPLE; 256 k->class_id = PCI_CLASS_OTHERS << 8; 257 } 258 259 static const TypeInfo macio_oldworld_type_info = { 260 .name = TYPE_OLDWORLD_MACIO, 261 .parent = TYPE_MACIO, 262 .instance_size = sizeof(OldWorldMacIOState), 263 .instance_init = macio_oldworld_init, 264 .class_init = macio_oldworld_class_init, 265 }; 266 267 static const TypeInfo macio_newworld_type_info = { 268 .name = TYPE_NEWWORLD_MACIO, 269 .parent = TYPE_MACIO, 270 .instance_size = sizeof(NewWorldMacIOState), 271 .instance_init = macio_newworld_init, 272 .class_init = macio_newworld_class_init, 273 }; 274 275 static const TypeInfo macio_type_info = { 276 .name = TYPE_MACIO, 277 .parent = TYPE_PCI_DEVICE, 278 .instance_size = sizeof(MacIOState), 279 .instance_init = macio_instance_init, 280 .abstract = true, 281 .class_init = macio_class_init, 282 }; 283 284 static void macio_register_types(void) 285 { 286 type_register_static(&macio_type_info); 287 type_register_static(&macio_oldworld_type_info); 288 type_register_static(&macio_newworld_type_info); 289 } 290 291 type_init(macio_register_types) 292 293 void macio_init(PCIDevice *d, 294 MemoryRegion *pic_mem, 295 MemoryRegion *escc_mem) 296 { 297 MacIOState *macio_state = MACIO(d); 298 299 macio_state->pic_mem = pic_mem; 300 macio_state->escc_mem = escc_mem; 301 /* Note: this code is strongly inspirated from the corresponding code 302 in PearPC */ 303 304 qdev_init_nofail(DEVICE(d)); 305 } 306