1 /*
2 * QEMU Macintosh Nubus Virtio MMIO card
3 *
4 * Copyright (c) 2024 Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
11 #include "hw/nubus/nubus-virtio-mmio.h"
12
13
14 #define NUBUS_VIRTIO_MMIO_PIC_OFFSET 0
15 #define NUBUS_VIRTIO_MMIO_DEV_OFFSET 0x200
16
17
nubus_virtio_mmio_set_input_irq(void * opaque,int n,int level)18 static void nubus_virtio_mmio_set_input_irq(void *opaque, int n, int level)
19 {
20 NubusDevice *nd = NUBUS_DEVICE(opaque);
21
22 nubus_set_irq(nd, level);
23 }
24
nubus_virtio_mmio_realize(DeviceState * dev,Error ** errp)25 static void nubus_virtio_mmio_realize(DeviceState *dev, Error **errp)
26 {
27 ERRP_GUARD();
28 NubusVirtioMMIODeviceClass *nvmdc = NUBUS_VIRTIO_MMIO_GET_CLASS(dev);
29 NubusVirtioMMIO *s = NUBUS_VIRTIO_MMIO(dev);
30 NubusDevice *nd = NUBUS_DEVICE(dev);
31 SysBusDevice *sbd;
32 int i, offset;
33
34 nvmdc->parent_realize(dev, errp);
35 if (*errp) {
36 return;
37 }
38
39 /* Goldfish PIC */
40 sbd = SYS_BUS_DEVICE(&s->pic);
41 if (!sysbus_realize(sbd, errp)) {
42 return;
43 }
44 memory_region_add_subregion(&nd->slot_mem, NUBUS_VIRTIO_MMIO_PIC_OFFSET,
45 sysbus_mmio_get_region(sbd, 0));
46 sysbus_connect_irq(sbd, 0,
47 qdev_get_gpio_in_named(dev, "pic-input-irq", 0));
48
49 /* virtio-mmio devices */
50 offset = NUBUS_VIRTIO_MMIO_DEV_OFFSET;
51 for (i = 0; i < NUBUS_VIRTIO_MMIO_NUM_DEVICES; i++) {
52 sbd = SYS_BUS_DEVICE(&s->virtio_mmio[i]);
53 qdev_prop_set_bit(DEVICE(sbd), "force-legacy", false);
54 if (!sysbus_realize_and_unref(sbd, errp)) {
55 return;
56 }
57
58 memory_region_add_subregion(&nd->slot_mem, offset,
59 sysbus_mmio_get_region(sbd, 0));
60 offset += 0x200;
61
62 sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(DEVICE(&s->pic), i));
63 }
64 }
65
nubus_virtio_mmio_init(Object * obj)66 static void nubus_virtio_mmio_init(Object *obj)
67 {
68 NubusVirtioMMIO *s = NUBUS_VIRTIO_MMIO(obj);
69 int i;
70
71 object_initialize_child(obj, "pic", &s->pic, TYPE_GOLDFISH_PIC);
72 for (i = 0; i < NUBUS_VIRTIO_MMIO_NUM_DEVICES; i++) {
73 char *name = g_strdup_printf("virtio-mmio[%d]", i);
74 object_initialize_child(obj, name, &s->virtio_mmio[i],
75 TYPE_VIRTIO_MMIO);
76 g_free(name);
77 }
78
79 /* Input from goldfish PIC */
80 qdev_init_gpio_in_named(DEVICE(obj), nubus_virtio_mmio_set_input_irq,
81 "pic-input-irq", 1);
82 }
83
nubus_virtio_mmio_class_init(ObjectClass * oc,void * data)84 static void nubus_virtio_mmio_class_init(ObjectClass *oc, void *data)
85 {
86 DeviceClass *dc = DEVICE_CLASS(oc);
87 NubusVirtioMMIODeviceClass *nvmdc = NUBUS_VIRTIO_MMIO_CLASS(oc);
88
89 device_class_set_parent_realize(dc, nubus_virtio_mmio_realize,
90 &nvmdc->parent_realize);
91 }
92
93 static const TypeInfo nubus_virtio_mmio_types[] = {
94 {
95 .name = TYPE_NUBUS_VIRTIO_MMIO,
96 .parent = TYPE_NUBUS_DEVICE,
97 .instance_init = nubus_virtio_mmio_init,
98 .instance_size = sizeof(NubusVirtioMMIO),
99 .class_init = nubus_virtio_mmio_class_init,
100 .class_size = sizeof(NubusVirtioMMIODeviceClass),
101 },
102 };
103
104 DEFINE_TYPES(nubus_virtio_mmio_types)
105