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 "qemu/bitops.h"
34 #include "qemu/module.h"
37 #define AVIC_NEW_BASE_OFFSET 0x80
39 #define AVIC_L_MASK 0xFFFFFFFFU
40 #define AVIC_H_MASK 0x0007FFFFU
41 #define AVIC_EVENT_W_MASK (0x78000ULL << 32)
43 static void aspeed_vic_update(AspeedVICState
*s
)
45 uint64_t new = (s
->raw
& s
->enable
);
48 flags
= new & s
->select
;
49 trace_aspeed_vic_update_fiq(!!flags
);
50 qemu_set_irq(s
->fiq
, !!flags
);
52 flags
= new & ~s
->select
;
53 trace_aspeed_vic_update_irq(!!flags
);
54 qemu_set_irq(s
->irq
, !!flags
);
57 static void aspeed_vic_set_irq(void *opaque
, int irq
, int level
)
61 AspeedVICState
*s
= (AspeedVICState
*)opaque
;
63 if (irq
> ASPEED_VIC_NR_IRQS
) {
64 qemu_log_mask(LOG_GUEST_ERROR
, "%s: Invalid interrupt number: %d\n",
69 trace_aspeed_vic_set_irq(irq
, level
);
72 if (s
->sense
& irq_mask
) {
74 if (s
->event
& irq_mask
) {
81 s
->raw
= deposit64(s
->raw
, irq
, 1, raise
);
83 uint64_t old_level
= s
->level
& irq_mask
;
86 if (s
->dual_edge
& irq_mask
) {
87 raise
= (!!old_level
) != (!!level
);
89 if (s
->event
& irq_mask
) {
90 /* rising-sensitive */
91 raise
= !old_level
&& level
;
93 /* falling-sensitive */
94 raise
= old_level
&& !level
;
98 s
->raw
= deposit64(s
->raw
, irq
, 1, raise
);
101 s
->level
= deposit64(s
->level
, irq
, 1, level
);
102 aspeed_vic_update(s
);
105 static uint64_t aspeed_vic_read(void *opaque
, hwaddr offset
, unsigned size
)
107 AspeedVICState
*s
= (AspeedVICState
*)opaque
;
112 if (offset
< AVIC_NEW_BASE_OFFSET
) {
116 high
= !!(offset
& 0x4);
117 n_offset
= (offset
& ~0x4);
121 case 0x80: /* IRQ Status */
123 val
= s
->raw
& ~s
->select
& s
->enable
;
125 case 0x88: /* FIQ Status */
127 val
= s
->raw
& s
->select
& s
->enable
;
129 case 0x90: /* Raw Interrupt Status */
133 case 0x98: /* Interrupt Selection */
137 case 0xa0: /* Interrupt Enable */
141 case 0xb0: /* Software Interrupt */
145 case 0xc0: /* Interrupt Sensitivity */
149 case 0xc8: /* Interrupt Both Edge Trigger Control */
153 case 0xd0: /* Interrupt Event */
157 case 0xe0: /* Edge Triggered Interrupt Status */
158 val
= s
->raw
& ~s
->sense
;
161 case 0xa8: /* Interrupt Enable Clear */
162 case 0xb8: /* Software Interrupt Clear */
163 case 0xd8: /* Edge Triggered Interrupt Clear */
164 qemu_log_mask(LOG_GUEST_ERROR
,
165 "%s: Read of write-only register with offset 0x%"
166 HWADDR_PRIx
"\n", __func__
, offset
);
170 qemu_log_mask(LOG_GUEST_ERROR
,
171 "%s: Bad register at offset 0x%" HWADDR_PRIx
"\n",
177 val
= extract64(val
, 32, 19);
179 val
= extract64(val
, 0, 32);
181 trace_aspeed_vic_read(offset
, size
, val
);
185 static void aspeed_vic_write(void *opaque
, hwaddr offset
, uint64_t data
,
188 AspeedVICState
*s
= (AspeedVICState
*)opaque
;
192 if (offset
< AVIC_NEW_BASE_OFFSET
) {
196 high
= !!(offset
& 0x4);
197 n_offset
= (offset
& ~0x4);
200 trace_aspeed_vic_write(offset
, size
, data
);
202 /* Given we have members using separate enable/clear registers, deposit64()
203 * isn't quite the tool for the job. Instead, relocate the incoming bits to
204 * the required bit offset based on the provided access address
214 case 0x98: /* Interrupt Selection */
216 /* Register has deposit64() semantics - overwrite requested 32 bits */
218 s
->select
&= AVIC_L_MASK
;
220 s
->select
&= ((uint64_t) AVIC_H_MASK
) << 32;
224 case 0xa0: /* Interrupt Enable */
228 case 0xa8: /* Interrupt Enable Clear */
232 case 0xb0: /* Software Interrupt */
234 qemu_log_mask(LOG_UNIMP
, "%s: Software interrupts unavailable. "
235 "IRQs requested: 0x%016" PRIx64
"\n", __func__
, data
);
237 case 0xb8: /* Software Interrupt Clear */
239 qemu_log_mask(LOG_UNIMP
, "%s: Software interrupts unavailable. "
240 "IRQs to be cleared: 0x%016" PRIx64
"\n", __func__
, data
);
242 case 0xd0: /* Interrupt Event */
243 /* Register has deposit64() semantics - overwrite the top four valid
244 * IRQ bits, as only the top four IRQs (GPIOs) can change their event
247 s
->event
&= ~AVIC_EVENT_W_MASK
;
248 s
->event
|= (data
& AVIC_EVENT_W_MASK
);
250 qemu_log_mask(LOG_GUEST_ERROR
,
251 "Ignoring invalid write to interrupt event register");
254 case 0xd8: /* Edge Triggered Interrupt Clear */
256 s
->raw
&= ~(data
& ~s
->sense
);
258 case 0x80: /* IRQ Status */
260 case 0x88: /* FIQ Status */
262 case 0x90: /* Raw Interrupt Status */
264 case 0xc0: /* Interrupt Sensitivity */
266 case 0xc8: /* Interrupt Both Edge Trigger Control */
268 case 0xe0: /* Edge Triggered Interrupt Status */
269 qemu_log_mask(LOG_GUEST_ERROR
,
270 "%s: Write of read-only register with offset 0x%"
271 HWADDR_PRIx
"\n", __func__
, offset
);
275 qemu_log_mask(LOG_GUEST_ERROR
,
276 "%s: Bad register at offset 0x%" HWADDR_PRIx
"\n",
280 aspeed_vic_update(s
);
283 static const MemoryRegionOps aspeed_vic_ops
= {
284 .read
= aspeed_vic_read
,
285 .write
= aspeed_vic_write
,
286 .endianness
= DEVICE_LITTLE_ENDIAN
,
287 .valid
.min_access_size
= 4,
288 .valid
.max_access_size
= 4,
289 .valid
.unaligned
= false,
292 static void aspeed_vic_reset(DeviceState
*dev
)
294 AspeedVICState
*s
= ASPEED_VIC(dev
);
301 s
->sense
= 0x1F07FFF8FFFFULL
;
302 s
->dual_edge
= 0xF800070000ULL
;
303 s
->event
= 0x5F07FFF8FFFFULL
;
306 #define AVIC_IO_REGION_SIZE 0x20000
308 static void aspeed_vic_realize(DeviceState
*dev
, Error
**errp
)
310 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
311 AspeedVICState
*s
= ASPEED_VIC(dev
);
313 memory_region_init_io(&s
->iomem
, OBJECT(s
), &aspeed_vic_ops
, s
,
314 TYPE_ASPEED_VIC
, AVIC_IO_REGION_SIZE
);
316 sysbus_init_mmio(sbd
, &s
->iomem
);
318 qdev_init_gpio_in(dev
, aspeed_vic_set_irq
, ASPEED_VIC_NR_IRQS
);
319 sysbus_init_irq(sbd
, &s
->irq
);
320 sysbus_init_irq(sbd
, &s
->fiq
);
323 static const VMStateDescription vmstate_aspeed_vic
= {
324 .name
= "aspeed.new-vic",
326 .minimum_version_id
= 1,
327 .fields
= (VMStateField
[]) {
328 VMSTATE_UINT64(level
, AspeedVICState
),
329 VMSTATE_UINT64(raw
, AspeedVICState
),
330 VMSTATE_UINT64(select
, AspeedVICState
),
331 VMSTATE_UINT64(enable
, AspeedVICState
),
332 VMSTATE_UINT64(trigger
, AspeedVICState
),
333 VMSTATE_UINT64(sense
, AspeedVICState
),
334 VMSTATE_UINT64(dual_edge
, AspeedVICState
),
335 VMSTATE_UINT64(event
, AspeedVICState
),
336 VMSTATE_END_OF_LIST()
340 static void aspeed_vic_class_init(ObjectClass
*klass
, void *data
)
342 DeviceClass
*dc
= DEVICE_CLASS(klass
);
343 dc
->realize
= aspeed_vic_realize
;
344 dc
->reset
= aspeed_vic_reset
;
345 dc
->desc
= "ASPEED Interrupt Controller (New)";
346 dc
->vmsd
= &vmstate_aspeed_vic
;
349 static const TypeInfo aspeed_vic_info
= {
350 .name
= TYPE_ASPEED_VIC
,
351 .parent
= TYPE_SYS_BUS_DEVICE
,
352 .instance_size
= sizeof(AspeedVICState
),
353 .class_init
= aspeed_vic_class_init
,
356 static void aspeed_vic_register_types(void)
358 type_register_static(&aspeed_vic_info
);
361 type_init(aspeed_vic_register_types
);