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
26#include "qemu/osdep.h"
27#include "hw/qdev-properties.h"
28#include "migration/vmstate.h"
29#include "hw/misc/macio/macio.h"
30#include "hw/misc/macio/gpio.h"
31#include "hw/nmi.h"
32#include "qemu/log.h"
33#include "qemu/module.h"
34#include "trace.h"
35
36
37void macio_set_gpio(MacIOGPIOState *s, uint32_t gpio, bool state)
38{
39 uint8_t new_reg;
40
41 trace_macio_set_gpio(gpio, state);
42
43 if (s->gpio_regs[gpio] & 4) {
44 qemu_log_mask(LOG_GUEST_ERROR,
45 "GPIO: Setting GPIO %d while it's an output\n", gpio);
46 }
47
48 new_reg = s->gpio_regs[gpio] & ~2;
49 if (state) {
50 new_reg |= 2;
51 }
52
53 if (new_reg == s->gpio_regs[gpio]) {
54 return;
55 }
56
57 s->gpio_regs[gpio] = new_reg;
58
59
60
61
62
63
64
65
66 switch (gpio) {
67 case 1:
68
69 if (!state) {
70 trace_macio_gpio_irq_assert(gpio);
71 qemu_irq_raise(s->gpio_extirqs[gpio]);
72 } else {
73 trace_macio_gpio_irq_deassert(gpio);
74 qemu_irq_lower(s->gpio_extirqs[gpio]);
75 }
76 break;
77
78 case 9:
79
80 if (state) {
81 trace_macio_gpio_irq_assert(gpio);
82 qemu_irq_raise(s->gpio_extirqs[gpio]);
83 } else {
84 trace_macio_gpio_irq_deassert(gpio);
85 qemu_irq_lower(s->gpio_extirqs[gpio]);
86 }
87 break;
88
89 default:
90 qemu_log_mask(LOG_UNIMP, "GPIO: setting unimplemented GPIO %d", gpio);
91 }
92}
93
94static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
95 unsigned size)
96{
97 MacIOGPIOState *s = opaque;
98 uint8_t ibit;
99
100 trace_macio_gpio_write(addr, value);
101
102
103 if (addr < 8) {
104 return;
105 }
106
107 addr -= 8;
108 if (addr < 36) {
109 value &= ~2;
110
111 if (value & 4) {
112 ibit = (value & 1) << 1;
113 } else {
114 ibit = s->gpio_regs[addr] & 2;
115 }
116
117 s->gpio_regs[addr] = value | ibit;
118 }
119}
120
121static uint64_t macio_gpio_read(void *opaque, hwaddr addr, unsigned size)
122{
123 MacIOGPIOState *s = opaque;
124 uint64_t val = 0;
125
126
127 if (addr < 8) {
128 val = s->gpio_levels[addr];
129 } else {
130 addr -= 8;
131
132 if (addr < 36) {
133 val = s->gpio_regs[addr];
134 }
135 }
136
137 trace_macio_gpio_write(addr, val);
138 return val;
139}
140
141static const MemoryRegionOps macio_gpio_ops = {
142 .read = macio_gpio_read,
143 .write = macio_gpio_write,
144 .endianness = DEVICE_LITTLE_ENDIAN,
145 .impl = {
146 .min_access_size = 1,
147 .max_access_size = 1,
148 },
149};
150
151static void macio_gpio_init(Object *obj)
152{
153 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
154 MacIOGPIOState *s = MACIO_GPIO(obj);
155 int i;
156
157 for (i = 0; i < 10; i++) {
158 sysbus_init_irq(sbd, &s->gpio_extirqs[i]);
159 }
160
161 memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj,
162 "gpio", 0x30);
163 sysbus_init_mmio(sbd, &s->gpiomem);
164}
165
166static const VMStateDescription vmstate_macio_gpio = {
167 .name = "macio_gpio",
168 .version_id = 0,
169 .minimum_version_id = 0,
170 .fields = (VMStateField[]) {
171 VMSTATE_UINT8_ARRAY(gpio_levels, MacIOGPIOState, 8),
172 VMSTATE_UINT8_ARRAY(gpio_regs, MacIOGPIOState, 36),
173 VMSTATE_END_OF_LIST()
174 }
175};
176
177static void macio_gpio_reset(DeviceState *dev)
178{
179 MacIOGPIOState *s = MACIO_GPIO(dev);
180
181
182 macio_set_gpio(s, 1, true);
183}
184
185static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp)
186{
187 macio_set_gpio(MACIO_GPIO(n), 9, true);
188 macio_set_gpio(MACIO_GPIO(n), 9, false);
189}
190
191static void macio_gpio_class_init(ObjectClass *oc, void *data)
192{
193 DeviceClass *dc = DEVICE_CLASS(oc);
194 NMIClass *nc = NMI_CLASS(oc);
195
196 dc->reset = macio_gpio_reset;
197 dc->vmsd = &vmstate_macio_gpio;
198 nc->nmi_monitor_handler = macio_gpio_nmi;
199}
200
201static const TypeInfo macio_gpio_init_info = {
202 .name = TYPE_MACIO_GPIO,
203 .parent = TYPE_SYS_BUS_DEVICE,
204 .instance_size = sizeof(MacIOGPIOState),
205 .instance_init = macio_gpio_init,
206 .class_init = macio_gpio_class_init,
207 .interfaces = (InterfaceInfo[]) {
208 { TYPE_NMI },
209 { }
210 },
211};
212
213static void macio_gpio_register_types(void)
214{
215 type_register_static(&macio_gpio_init_info);
216}
217
218type_init(macio_gpio_register_types)
219