* THE SOFTWARE.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/hw.h"
#define R_MER 7
#define R_MAX 8
+#define TYPE_XILINX_INTC "xlnx.xps-intc"
+#define XILINX_INTC(obj) OBJECT_CHECK(struct xlx_pic, (obj), TYPE_XILINX_INTC)
+
struct xlx_pic
{
- SysBusDevice busdev;
+ SysBusDevice parent_obj;
+
MemoryRegion mmio;
qemu_irq parent_irq;
/* Runtime control registers. */
uint32_t regs[R_MAX];
+ /* state of the interrupt input pins */
+ uint32_t irq_pin_state;
};
static void update_irq(struct xlx_pic *p)
{
uint32_t i;
+
+ /* level triggered interrupt */
+ if (p->regs[R_MER] & 2) {
+ p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
+ }
+
/* Update the pending register. */
p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
/* Update the vector register. */
for (i = 0; i < 32; i++) {
- if (p->regs[R_IPR] & (1 << i))
+ if (p->regs[R_IPR] & (1U << i)) {
break;
+ }
}
if (i == 32)
i = ~0;
p->regs[R_IVR] = i;
- if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
- qemu_irq_raise(p->parent_irq);
- } else {
- qemu_irq_lower(p->parent_irq);
- }
+ qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
}
static uint64_t
case R_CIE:
p->regs[R_IER] &= ~value; /* Atomic clear ie. */
break;
+ case R_MER:
+ p->regs[R_MER] = value & 0x3;
+ break;
+ case R_ISR:
+ if ((p->regs[R_MER] & 2)) {
+ break;
+ }
+ /* fallthrough */
default:
if (addr < ARRAY_SIZE(p->regs))
p->regs[addr] = value;
{
struct xlx_pic *p = opaque;
- if (!(p->regs[R_MER] & 2)) {
- qemu_irq_lower(p->parent_irq);
- return;
- }
-
- /* Update source flops. Don't clear unless level triggered.
- Edge triggered interrupts only go away when explicitely acked to
- the interrupt controller. */
- if (!(p->c_kind_of_intr & (1 << irq)) || level) {
- p->regs[R_ISR] &= ~(1 << irq);
+ /* edge triggered interrupt */
+ if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
p->regs[R_ISR] |= (level << irq);
}
+
+ p->irq_pin_state &= ~(1 << irq);
+ p->irq_pin_state |= level << irq;
update_irq(p);
}
-static int xilinx_intc_init(SysBusDevice *dev)
+static void xilinx_intc_init(Object *obj)
{
- struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
+ struct xlx_pic *p = XILINX_INTC(obj);
- qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
- sysbus_init_irq(dev, &p->parent_irq);
+ qdev_init_gpio_in(DEVICE(obj), irq_handler, 32);
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &p->parent_irq);
- memory_region_init_io(&p->mmio, &pic_ops, p, "xlnx.xps-intc", R_MAX * 4);
- sysbus_init_mmio(dev, &p->mmio);
- return 0;
+ memory_region_init_io(&p->mmio, obj, &pic_ops, p, "xlnx.xps-intc",
+ R_MAX * 4);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &p->mmio);
}
static Property xilinx_intc_properties[] = {
static void xilinx_intc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
- k->init = xilinx_intc_init;
dc->props = xilinx_intc_properties;
}
static const TypeInfo xilinx_intc_info = {
- .name = "xlnx.xps-intc",
+ .name = TYPE_XILINX_INTC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct xlx_pic),
+ .instance_init = xilinx_intc_init,
.class_init = xilinx_intc_class_init,
};