X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/371a775dc18ece3ff7d77328d1ee28cb2d473706..d2164ad35c411d97abd2aa5c6f160283d215e214:/hw/intc/xilinx_intc.c diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index 5df7008e2f..9d8139bc6d 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/hw.h" @@ -37,9 +38,13 @@ #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; @@ -49,18 +54,27 @@ struct xlx_pic /* 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; @@ -108,6 +122,14 @@ pic_write(void *opaque, hwaddr addr, 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; @@ -130,31 +152,26 @@ static void irq_handler(void *opaque, int irq, int level) { 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[] = { @@ -165,16 +182,15 @@ 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, };