diff options
Diffstat (limited to 'hw/misc/stm32l4x5_exti.c')
-rw-r--r-- | hw/misc/stm32l4x5_exti.c | 43 |
1 files changed, 23 insertions, 20 deletions
diff --git a/hw/misc/stm32l4x5_exti.c b/hw/misc/stm32l4x5_exti.c index 495a000..9c00216 100644 --- a/hw/misc/stm32l4x5_exti.c +++ b/hw/misc/stm32l4x5_exti.c @@ -42,7 +42,6 @@ #define EXTI_SWIER2 0x30 #define EXTI_PR2 0x34 -#define EXTI_NUM_GPIO_EVENT_IN_LINES 16 #define EXTI_MAX_IRQ_PER_BANK 32 #define EXTI_IRQS_BANK0 32 #define EXTI_IRQS_BANK1 8 @@ -88,6 +87,7 @@ static void stm32l4x5_exti_reset_hold(Object *obj, ResetType type) s->ftsr[bank] = 0x00000000; s->swier[bank] = 0x00000000; s->pr[bank] = 0x00000000; + s->irq_levels[bank] = 0x00000000; } } @@ -102,27 +102,30 @@ static void stm32l4x5_exti_set_irq(void *opaque, int irq, int level) /* Shift the value to enable access in x2 registers. */ irq %= EXTI_MAX_IRQ_PER_BANK; + if (level == extract32(s->irq_levels[bank], irq, 1)) { + /* No change in IRQ line state: do nothing */ + return; + } + s->irq_levels[bank] = deposit32(s->irq_levels[bank], irq, 1, level); + /* If the interrupt is masked, pr won't be raised */ if (!extract32(s->imr[bank], irq, 1)) { return; } - if (((1 << irq) & s->rtsr[bank]) && level) { - /* Rising Edge */ - s->pr[bank] |= 1 << irq; - qemu_irq_pulse(s->irq[oirq]); - } else if (((1 << irq) & s->ftsr[bank]) && !level) { - /* Falling Edge */ + /* In case of a direct line interrupt */ + if (extract32(exti_romask[bank], irq, 1)) { + qemu_set_irq(s->irq[oirq], level); + return; + } + + /* In case of a configurable interrupt */ + if ((level && extract32(s->rtsr[bank], irq, 1)) || + (!level && extract32(s->ftsr[bank], irq, 1))) { + s->pr[bank] |= 1 << irq; qemu_irq_pulse(s->irq[oirq]); } - /* - * In the following situations : - * - falling edge but rising trigger selected - * - rising edge but falling trigger selected - * - no trigger selected - * No action is required - */ } static uint64_t stm32l4x5_exti_read(void *opaque, hwaddr addr, @@ -241,7 +244,7 @@ static void stm32l4x5_exti_init(Object *obj) { Stm32l4x5ExtiState *s = STM32L4X5_EXTI(obj); - for (size_t i = 0; i < EXTI_NUM_INTERRUPT_OUT_LINES; i++) { + for (size_t i = 0; i < EXTI_NUM_LINES; i++) { sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]); } @@ -249,14 +252,13 @@ static void stm32l4x5_exti_init(Object *obj) TYPE_STM32L4X5_EXTI, 0x400); sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); - qdev_init_gpio_in(DEVICE(obj), stm32l4x5_exti_set_irq, - EXTI_NUM_GPIO_EVENT_IN_LINES); + qdev_init_gpio_in(DEVICE(obj), stm32l4x5_exti_set_irq, EXTI_NUM_LINES); } static const VMStateDescription vmstate_stm32l4x5_exti = { .name = TYPE_STM32L4X5_EXTI, - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(imr, Stm32l4x5ExtiState, EXTI_NUM_REGISTER), VMSTATE_UINT32_ARRAY(emr, Stm32l4x5ExtiState, EXTI_NUM_REGISTER), @@ -264,11 +266,12 @@ static const VMStateDescription vmstate_stm32l4x5_exti = { VMSTATE_UINT32_ARRAY(ftsr, Stm32l4x5ExtiState, EXTI_NUM_REGISTER), VMSTATE_UINT32_ARRAY(swier, Stm32l4x5ExtiState, EXTI_NUM_REGISTER), VMSTATE_UINT32_ARRAY(pr, Stm32l4x5ExtiState, EXTI_NUM_REGISTER), + VMSTATE_UINT32_ARRAY(irq_levels, Stm32l4x5ExtiState, EXTI_NUM_REGISTER), VMSTATE_END_OF_LIST() } }; -static void stm32l4x5_exti_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_exti_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); |