Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-migration-20210726a...
[qemu/armbru.git] / hw / intc / aspeed_vic.c
blob5ba06c52628e2731d1bf9ec10406dd2449dcdedb
1 /*
2 * ASPEED Interrupt Controller (New)
4 * Andrew Jeffery <andrew@aj.id.au>
6 * Copyright 2015, 2016 IBM Corp.
8 * This code is licensed under the GPL version 2 or later. See
9 * the COPYING file in the top-level directory.
12 /* The hardware exposes two register sets, a legacy set and a 'new' set. The
13 * model implements the 'new' register set, and logs warnings on accesses to
14 * the legacy IO space.
16 * The hardware uses 32bit registers to manage 51 IRQs, with low and high
17 * registers for each conceptual register. The device model's implementation
18 * uses 64bit data types to store both low and high register values (in the one
19 * member), but must cope with access offset values in multiples of 4 passed to
20 * the callbacks. As such the read() and write() implementations process the
21 * provided offset to understand whether the access is requesting the lower or
22 * upper 32 bits of the 64bit member.
24 * Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt"
25 * fields have separate "enable"/"status" and "clear" registers, where set bits
26 * are written to one or the other to change state (avoiding a
27 * read-modify-write sequence).
30 #include "qemu/osdep.h"
31 #include "hw/intc/aspeed_vic.h"
32 #include "hw/irq.h"
33 #include "migration/vmstate.h"
34 #include "qemu/bitops.h"
35 #include "qemu/log.h"
36 #include "qemu/module.h"
37 #include "trace.h"
39 #define AVIC_NEW_BASE_OFFSET 0x80
41 #define AVIC_L_MASK 0xFFFFFFFFU
42 #define AVIC_H_MASK 0x0007FFFFU
43 #define AVIC_EVENT_W_MASK (0x78000ULL << 32)
45 static void aspeed_vic_update(AspeedVICState *s)
47 uint64_t new = (s->raw & s->enable);
48 uint64_t flags;
50 flags = new & s->select;
51 trace_aspeed_vic_update_fiq(!!flags);
52 qemu_set_irq(s->fiq, !!flags);
54 flags = new & ~s->select;
55 trace_aspeed_vic_update_irq(!!flags);
56 qemu_set_irq(s->irq, !!flags);
59 static void aspeed_vic_set_irq(void *opaque, int irq, int level)
61 uint64_t irq_mask;
62 bool raise;
63 AspeedVICState *s = (AspeedVICState *)opaque;
65 if (irq > ASPEED_VIC_NR_IRQS) {
66 qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
67 __func__, irq);
68 return;
71 trace_aspeed_vic_set_irq(irq, level);
73 irq_mask = BIT(irq);
74 if (s->sense & irq_mask) {
75 /* level-triggered */
76 if (s->event & irq_mask) {
77 /* high-sensitive */
78 raise = level;
79 } else {
80 /* low-sensitive */
81 raise = !level;
83 s->raw = deposit64(s->raw, irq, 1, raise);
84 } else {
85 uint64_t old_level = s->level & irq_mask;
87 /* edge-triggered */
88 if (s->dual_edge & irq_mask) {
89 raise = (!!old_level) != (!!level);
90 } else {
91 if (s->event & irq_mask) {
92 /* rising-sensitive */
93 raise = !old_level && level;
94 } else {
95 /* falling-sensitive */
96 raise = old_level && !level;
99 if (raise) {
100 s->raw = deposit64(s->raw, irq, 1, raise);
103 s->level = deposit64(s->level, irq, 1, level);
104 aspeed_vic_update(s);
107 static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
109 AspeedVICState *s = (AspeedVICState *)opaque;
110 hwaddr n_offset;
111 uint64_t val;
112 bool high;
114 if (offset < AVIC_NEW_BASE_OFFSET) {
115 high = false;
116 n_offset = offset;
117 } else {
118 high = !!(offset & 0x4);
119 n_offset = (offset & ~0x4);
122 switch (n_offset) {
123 case 0x80: /* IRQ Status */
124 case 0x00:
125 val = s->raw & ~s->select & s->enable;
126 break;
127 case 0x88: /* FIQ Status */
128 case 0x04:
129 val = s->raw & s->select & s->enable;
130 break;
131 case 0x90: /* Raw Interrupt Status */
132 case 0x08:
133 val = s->raw;
134 break;
135 case 0x98: /* Interrupt Selection */
136 case 0x0c:
137 val = s->select;
138 break;
139 case 0xa0: /* Interrupt Enable */
140 case 0x10:
141 val = s->enable;
142 break;
143 case 0xb0: /* Software Interrupt */
144 case 0x18:
145 val = s->trigger;
146 break;
147 case 0xc0: /* Interrupt Sensitivity */
148 case 0x24:
149 val = s->sense;
150 break;
151 case 0xc8: /* Interrupt Both Edge Trigger Control */
152 case 0x28:
153 val = s->dual_edge;
154 break;
155 case 0xd0: /* Interrupt Event */
156 case 0x2c:
157 val = s->event;
158 break;
159 case 0xe0: /* Edge Triggered Interrupt Status */
160 val = s->raw & ~s->sense;
161 break;
162 /* Illegal */
163 case 0xa8: /* Interrupt Enable Clear */
164 case 0xb8: /* Software Interrupt Clear */
165 case 0xd8: /* Edge Triggered Interrupt Clear */
166 qemu_log_mask(LOG_GUEST_ERROR,
167 "%s: Read of write-only register with offset 0x%"
168 HWADDR_PRIx "\n", __func__, offset);
169 val = 0;
170 break;
171 default:
172 qemu_log_mask(LOG_GUEST_ERROR,
173 "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
174 __func__, offset);
175 val = 0;
176 break;
178 if (high) {
179 val = extract64(val, 32, 19);
180 } else {
181 val = extract64(val, 0, 32);
183 trace_aspeed_vic_read(offset, size, val);
184 return val;
187 static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
188 unsigned size)
190 AspeedVICState *s = (AspeedVICState *)opaque;
191 hwaddr n_offset;
192 bool high;
194 if (offset < AVIC_NEW_BASE_OFFSET) {
195 high = false;
196 n_offset = offset;
197 } else {
198 high = !!(offset & 0x4);
199 n_offset = (offset & ~0x4);
202 trace_aspeed_vic_write(offset, size, data);
204 /* Given we have members using separate enable/clear registers, deposit64()
205 * isn't quite the tool for the job. Instead, relocate the incoming bits to
206 * the required bit offset based on the provided access address
208 if (high) {
209 data &= AVIC_H_MASK;
210 data <<= 32;
211 } else {
212 data &= AVIC_L_MASK;
215 switch (n_offset) {
216 case 0x98: /* Interrupt Selection */
217 case 0x0c:
218 /* Register has deposit64() semantics - overwrite requested 32 bits */
219 if (high) {
220 s->select &= AVIC_L_MASK;
221 } else {
222 s->select &= ((uint64_t) AVIC_H_MASK) << 32;
224 s->select |= data;
225 break;
226 case 0xa0: /* Interrupt Enable */
227 case 0x10:
228 s->enable |= data;
229 break;
230 case 0xa8: /* Interrupt Enable Clear */
231 case 0x14:
232 s->enable &= ~data;
233 break;
234 case 0xb0: /* Software Interrupt */
235 case 0x18:
236 qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
237 "IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
238 break;
239 case 0xb8: /* Software Interrupt Clear */
240 case 0x1c:
241 qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
242 "IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
243 break;
244 case 0xd0: /* Interrupt Event */
245 /* Register has deposit64() semantics - overwrite the top four valid
246 * IRQ bits, as only the top four IRQs (GPIOs) can change their event
247 * type */
248 if (high) {
249 s->event &= ~AVIC_EVENT_W_MASK;
250 s->event |= (data & AVIC_EVENT_W_MASK);
251 } else {
252 qemu_log_mask(LOG_GUEST_ERROR,
253 "Ignoring invalid write to interrupt event register");
255 break;
256 case 0xd8: /* Edge Triggered Interrupt Clear */
257 case 0x38:
258 s->raw &= ~(data & ~s->sense);
259 break;
260 case 0x80: /* IRQ Status */
261 case 0x00:
262 case 0x88: /* FIQ Status */
263 case 0x04:
264 case 0x90: /* Raw Interrupt Status */
265 case 0x08:
266 case 0xc0: /* Interrupt Sensitivity */
267 case 0x24:
268 case 0xc8: /* Interrupt Both Edge Trigger Control */
269 case 0x28:
270 case 0xe0: /* Edge Triggered Interrupt Status */
271 qemu_log_mask(LOG_GUEST_ERROR,
272 "%s: Write of read-only register with offset 0x%"
273 HWADDR_PRIx "\n", __func__, offset);
274 break;
276 default:
277 qemu_log_mask(LOG_GUEST_ERROR,
278 "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
279 __func__, offset);
280 break;
282 aspeed_vic_update(s);
285 static const MemoryRegionOps aspeed_vic_ops = {
286 .read = aspeed_vic_read,
287 .write = aspeed_vic_write,
288 .endianness = DEVICE_LITTLE_ENDIAN,
289 .valid.min_access_size = 4,
290 .valid.max_access_size = 4,
291 .valid.unaligned = false,
294 static void aspeed_vic_reset(DeviceState *dev)
296 AspeedVICState *s = ASPEED_VIC(dev);
298 s->level = 0;
299 s->raw = 0;
300 s->select = 0;
301 s->enable = 0;
302 s->trigger = 0;
303 s->sense = 0x1F07FFF8FFFFULL;
304 s->dual_edge = 0xF800070000ULL;
305 s->event = 0x5F07FFF8FFFFULL;
308 #define AVIC_IO_REGION_SIZE 0x20000
310 static void aspeed_vic_realize(DeviceState *dev, Error **errp)
312 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
313 AspeedVICState *s = ASPEED_VIC(dev);
315 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s,
316 TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE);
318 sysbus_init_mmio(sbd, &s->iomem);
320 qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS);
321 sysbus_init_irq(sbd, &s->irq);
322 sysbus_init_irq(sbd, &s->fiq);
325 static const VMStateDescription vmstate_aspeed_vic = {
326 .name = "aspeed.new-vic",
327 .version_id = 1,
328 .minimum_version_id = 1,
329 .fields = (VMStateField[]) {
330 VMSTATE_UINT64(level, AspeedVICState),
331 VMSTATE_UINT64(raw, AspeedVICState),
332 VMSTATE_UINT64(select, AspeedVICState),
333 VMSTATE_UINT64(enable, AspeedVICState),
334 VMSTATE_UINT64(trigger, AspeedVICState),
335 VMSTATE_UINT64(sense, AspeedVICState),
336 VMSTATE_UINT64(dual_edge, AspeedVICState),
337 VMSTATE_UINT64(event, AspeedVICState),
338 VMSTATE_END_OF_LIST()
342 static void aspeed_vic_class_init(ObjectClass *klass, void *data)
344 DeviceClass *dc = DEVICE_CLASS(klass);
345 dc->realize = aspeed_vic_realize;
346 dc->reset = aspeed_vic_reset;
347 dc->desc = "ASPEED Interrupt Controller (New)";
348 dc->vmsd = &vmstate_aspeed_vic;
351 static const TypeInfo aspeed_vic_info = {
352 .name = TYPE_ASPEED_VIC,
353 .parent = TYPE_SYS_BUS_DEVICE,
354 .instance_size = sizeof(AspeedVICState),
355 .class_init = aspeed_vic_class_init,
358 static void aspeed_vic_register_types(void)
360 type_register_static(&aspeed_vic_info);
363 type_init(aspeed_vic_register_types);