1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
36typedef struct MacIOState
37{
38
39 PCIDevice parent;
40
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
53typedef struct OldWorldMacIOState {
54
55 MacIOState parent_obj;
56
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
67typedef struct NewWorldMacIOState {
68
69 MacIOState parent_obj;
70
71 qemu_irq irqs[5];
72 MACIOIDEState ide[2];
73} NewWorldMacIOState;
74
75
76
77
78
79
80
81
82
83
84
85
86static 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,
93 0x02, 0x20,
94 0x04, 0x10,
95 0x06, 0x30,
96 0x08, 0x40,
97 0x0A, 0x50,
98 0x80, 0x80,
99 0x90, 0x90,
100 0xa0, 0xa0,
101 0xb0, 0xb0,
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
115static 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
125static 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
153static 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 object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp);
164 macio_ide_register_dma(ide);
165
166 object_property_set_bool(OBJECT(ide), true, "realized", errp);
167}
168
169static void macio_oldworld_realize(PCIDevice *d, Error **errp)
170{
171 MacIOState *s = MACIO(d);
172 OldWorldMacIOState *os = OLDWORLD_MACIO(d);
173 Error *err = NULL;
174 SysBusDevice *sysbus_dev;
175 int i;
176 int cur_irq = 0;
177
178 macio_common_realize(d, &err);
179 if (err) {
180 error_propagate(errp, err);
181 return;
182 }
183
184 sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
185 sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]);
186
187 object_property_set_bool(OBJECT(&os->nvram), true, "realized", &err);
188 if (err) {
189 error_propagate(errp, err);
190 return;
191 }
192 sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
193 memory_region_add_subregion(&s->bar, 0x60000,
194 sysbus_mmio_get_region(sysbus_dev, 0));
195 pmac_format_nvram_partition(&os->nvram, os->nvram.size);
196
197 if (s->pic_mem) {
198
199 memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
200 }
201
202
203 for (i = 0; i < ARRAY_SIZE(os->ide); i++) {
204 qemu_irq irq0 = os->irqs[cur_irq++];
205 qemu_irq irq1 = os->irqs[cur_irq++];
206
207 macio_realize_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
208 if (err) {
209 error_propagate(errp, err);
210 return;
211 }
212 }
213}
214
215static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
216 int index)
217{
218 gchar *name;
219
220 object_initialize(ide, ide_size, TYPE_MACIO_IDE);
221 qdev_set_parent_bus(DEVICE(ide), sysbus_get_default());
222 memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000),
223 &ide->mem);
224 name = g_strdup_printf("ide[%i]", index);
225 object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL);
226 g_free(name);
227}
228
229static void macio_oldworld_init(Object *obj)
230{
231 MacIOState *s = MACIO(obj);
232 OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
233 DeviceState *dev;
234 int i;
235
236 qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
237
238 object_initialize(&os->nvram, sizeof(os->nvram), TYPE_MACIO_NVRAM);
239 dev = DEVICE(&os->nvram);
240 qdev_prop_set_uint32(dev, "size", 0x2000);
241 qdev_prop_set_uint32(dev, "it_shift", 4);
242
243 for (i = 0; i < 2; i++) {
244 macio_init_ide(s, &os->ide[i], sizeof(os->ide[i]), i);
245 }
246}
247
248static void timer_write(void *opaque, hwaddr addr, uint64_t value,
249 unsigned size)
250{
251}
252
253static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
254{
255 uint32_t value = 0;
256 uint64_t systime = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
257 uint64_t kltime;
258
259 kltime = muldiv64(systime, 4194300, NANOSECONDS_PER_SECOND * 4);
260 kltime = muldiv64(kltime, 18432000, 1048575);
261
262 switch (addr) {
263 case 0x38:
264 value = kltime;
265 break;
266 case 0x3c:
267 value = kltime >> 32;
268 break;
269 }
270
271 return value;
272}
273
274static const MemoryRegionOps timer_ops = {
275 .read = timer_read,
276 .write = timer_write,
277 .endianness = DEVICE_LITTLE_ENDIAN,
278};
279
280static void macio_newworld_realize(PCIDevice *d, Error **errp)
281{
282 MacIOState *s = MACIO(d);
283 NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
284 Error *err = NULL;
285 SysBusDevice *sysbus_dev;
286 MemoryRegion *timer_memory = NULL;
287 int i;
288 int cur_irq = 0;
289
290 macio_common_realize(d, &err);
291 if (err) {
292 error_propagate(errp, err);
293 return;
294 }
295
296 sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
297 sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]);
298
299 if (s->pic_mem) {
300
301 memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
302 }
303
304
305 for (i = 0; i < ARRAY_SIZE(ns->ide); i++) {
306 qemu_irq irq0 = ns->irqs[cur_irq++];
307 qemu_irq irq1 = ns->irqs[cur_irq++];
308
309 macio_realize_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4), &err);
310 if (err) {
311 error_propagate(errp, err);
312 return;
313 }
314 }
315
316
317 timer_memory = g_new(MemoryRegion, 1);
318 memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer",
319 0x1000);
320 memory_region_add_subregion(&s->bar, 0x15000, timer_memory);
321}
322
323static void macio_newworld_init(Object *obj)
324{
325 MacIOState *s = MACIO(obj);
326 NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
327 int i;
328
329 qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
330
331 for (i = 0; i < 2; i++) {
332 macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
333 }
334}
335
336static void macio_instance_init(Object *obj)
337{
338 MacIOState *s = MACIO(obj);
339
340 memory_region_init(&s->bar, obj, "macio", 0x80000);
341
342 object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
343 qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
344 object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
345
346 s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA));
347 object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL);
348}
349
350static const VMStateDescription vmstate_macio_oldworld = {
351 .name = "macio-oldworld",
352 .version_id = 0,
353 .minimum_version_id = 0,
354 .fields = (VMStateField[]) {
355 VMSTATE_PCI_DEVICE(parent_obj.parent, OldWorldMacIOState),
356 VMSTATE_END_OF_LIST()
357 }
358};
359
360static void macio_oldworld_class_init(ObjectClass *oc, void *data)
361{
362 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
363 DeviceClass *dc = DEVICE_CLASS(oc);
364
365 pdc->realize = macio_oldworld_realize;
366 pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
367 dc->vmsd = &vmstate_macio_oldworld;
368}
369
370static const VMStateDescription vmstate_macio_newworld = {
371 .name = "macio-newworld",
372 .version_id = 0,
373 .minimum_version_id = 0,
374 .fields = (VMStateField[]) {
375 VMSTATE_PCI_DEVICE(parent_obj.parent, NewWorldMacIOState),
376 VMSTATE_END_OF_LIST()
377 }
378};
379
380static void macio_newworld_class_init(ObjectClass *oc, void *data)
381{
382 PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
383 DeviceClass *dc = DEVICE_CLASS(oc);
384
385 pdc->realize = macio_newworld_realize;
386 pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
387 dc->vmsd = &vmstate_macio_newworld;
388}
389
390static Property macio_properties[] = {
391 DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0),
392 DEFINE_PROP_END_OF_LIST()
393};
394
395static void macio_class_init(ObjectClass *klass, void *data)
396{
397 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
398 DeviceClass *dc = DEVICE_CLASS(klass);
399
400 k->vendor_id = PCI_VENDOR_ID_APPLE;
401 k->class_id = PCI_CLASS_OTHERS << 8;
402 dc->props = macio_properties;
403 set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
404}
405
406static const TypeInfo macio_oldworld_type_info = {
407 .name = TYPE_OLDWORLD_MACIO,
408 .parent = TYPE_MACIO,
409 .instance_size = sizeof(OldWorldMacIOState),
410 .instance_init = macio_oldworld_init,
411 .class_init = macio_oldworld_class_init,
412};
413
414static const TypeInfo macio_newworld_type_info = {
415 .name = TYPE_NEWWORLD_MACIO,
416 .parent = TYPE_MACIO,
417 .instance_size = sizeof(NewWorldMacIOState),
418 .instance_init = macio_newworld_init,
419 .class_init = macio_newworld_class_init,
420};
421
422static const TypeInfo macio_type_info = {
423 .name = TYPE_MACIO,
424 .parent = TYPE_PCI_DEVICE,
425 .instance_size = sizeof(MacIOState),
426 .instance_init = macio_instance_init,
427 .abstract = true,
428 .class_init = macio_class_init,
429 .interfaces = (InterfaceInfo[]) {
430 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
431 { },
432 },
433};
434
435static void macio_register_types(void)
436{
437 type_register_static(&macio_type_info);
438 type_register_static(&macio_oldworld_type_info);
439 type_register_static(&macio_newworld_type_info);
440}
441
442type_init(macio_register_types)
443
444void macio_init(PCIDevice *d,
445 MemoryRegion *pic_mem,
446 MemoryRegion *escc_mem)
447{
448 MacIOState *macio_state = MACIO(d);
449
450 macio_state->pic_mem = pic_mem;
451 macio_state->escc_mem = escc_mem;
452
453
454 qdev_prop_set_uint64(DEVICE(&macio_state->cuda), "frequency",
455 macio_state->frequency);
456
457 qdev_init_nofail(DEVICE(d));
458}
459