2 * STM32L4x5 EXTI (Extended interrupts and events controller)
4 * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5 * Copyright (c) 2023 Samuel Tardieu <samuel.tardieu@telecom-paris.fr>
6 * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
8 * SPDX-License-Identifier: GPL-2.0-or-later
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
13 * This work is based on the stm32f4xx_exti by Alistair Francis.
14 * Original code is licensed under the MIT License:
16 * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
20 * The reference used is the STMicroElectronics RM0351 Reference manual
21 * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
22 * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
25 #include "qemu/osdep.h"
29 #include "migration/vmstate.h"
30 #include "hw/misc/stm32l4x5_exti.h"
32 #define EXTI_IMR1 0x00
33 #define EXTI_EMR1 0x04
34 #define EXTI_RTSR1 0x08
35 #define EXTI_FTSR1 0x0C
36 #define EXTI_SWIER1 0x10
38 #define EXTI_IMR2 0x20
39 #define EXTI_EMR2 0x24
40 #define EXTI_RTSR2 0x28
41 #define EXTI_FTSR2 0x2C
42 #define EXTI_SWIER2 0x30
45 #define EXTI_MAX_IRQ_PER_BANK 32
46 #define EXTI_IRQS_BANK0 32
47 #define EXTI_IRQS_BANK1 8
49 static const unsigned irqs_per_bank
[EXTI_NUM_REGISTER
] = {
54 static const uint32_t exti_romask
[EXTI_NUM_REGISTER
] = {
55 0xff820000, /* 0b11111111_10000010_00000000_00000000 */
56 0x00000087, /* 0b00000000_00000000_00000000_10000111 */
59 static unsigned regbank_index_by_irq(unsigned irq
)
61 return irq
>= EXTI_MAX_IRQ_PER_BANK
? 1 : 0;
64 static unsigned regbank_index_by_addr(hwaddr addr
)
66 return addr
>= EXTI_IMR2
? 1 : 0;
69 static unsigned valid_mask(unsigned bank
)
71 return MAKE_64BIT_MASK(0, irqs_per_bank
[bank
]);
74 static unsigned configurable_mask(unsigned bank
)
76 return valid_mask(bank
) & ~exti_romask
[bank
];
79 static void stm32l4x5_exti_reset_hold(Object
*obj
, ResetType type
)
81 Stm32l4x5ExtiState
*s
= STM32L4X5_EXTI(obj
);
83 for (unsigned bank
= 0; bank
< EXTI_NUM_REGISTER
; bank
++) {
84 s
->imr
[bank
] = exti_romask
[bank
];
85 s
->emr
[bank
] = 0x00000000;
86 s
->rtsr
[bank
] = 0x00000000;
87 s
->ftsr
[bank
] = 0x00000000;
88 s
->swier
[bank
] = 0x00000000;
89 s
->pr
[bank
] = 0x00000000;
90 s
->irq_levels
[bank
] = 0x00000000;
94 static void stm32l4x5_exti_set_irq(void *opaque
, int irq
, int level
)
96 Stm32l4x5ExtiState
*s
= opaque
;
97 const unsigned bank
= regbank_index_by_irq(irq
);
100 trace_stm32l4x5_exti_set_irq(irq
, level
);
102 /* Shift the value to enable access in x2 registers. */
103 irq
%= EXTI_MAX_IRQ_PER_BANK
;
105 if (level
== extract32(s
->irq_levels
[bank
], irq
, 1)) {
106 /* No change in IRQ line state: do nothing */
109 s
->irq_levels
[bank
] = deposit32(s
->irq_levels
[bank
], irq
, 1, level
);
111 /* If the interrupt is masked, pr won't be raised */
112 if (!extract32(s
->imr
[bank
], irq
, 1)) {
116 /* In case of a direct line interrupt */
117 if (extract32(exti_romask
[bank
], irq
, 1)) {
118 qemu_set_irq(s
->irq
[oirq
], level
);
122 /* In case of a configurable interrupt */
123 if ((level
&& extract32(s
->rtsr
[bank
], irq
, 1)) ||
124 (!level
&& extract32(s
->ftsr
[bank
], irq
, 1))) {
126 s
->pr
[bank
] |= 1 << irq
;
127 qemu_irq_pulse(s
->irq
[oirq
]);
131 static uint64_t stm32l4x5_exti_read(void *opaque
, hwaddr addr
,
134 Stm32l4x5ExtiState
*s
= opaque
;
136 const unsigned bank
= regbank_index_by_addr(addr
);
165 qemu_log_mask(LOG_GUEST_ERROR
,
166 "STM32L4X5_exti_read: Bad offset 0x%" HWADDR_PRIx
"\n",
171 trace_stm32l4x5_exti_read(addr
, r
);
176 static void stm32l4x5_exti_write(void *opaque
, hwaddr addr
,
177 uint64_t val64
, unsigned int size
)
179 Stm32l4x5ExtiState
*s
= opaque
;
180 const unsigned bank
= regbank_index_by_addr(addr
);
182 trace_stm32l4x5_exti_write(addr
, val64
);
187 s
->imr
[bank
] = val64
& valid_mask(bank
);
191 s
->emr
[bank
] = val64
& valid_mask(bank
);
195 s
->rtsr
[bank
] = val64
& configurable_mask(bank
);
199 s
->ftsr
[bank
] = val64
& configurable_mask(bank
);
203 const uint32_t set
= val64
& configurable_mask(bank
);
204 const uint32_t pend
= set
& ~s
->swier
[bank
] & s
->imr
[bank
] &
206 s
->swier
[bank
] = set
;
208 for (unsigned i
= 0; i
< irqs_per_bank
[bank
]; i
++) {
209 if (extract32(pend
, i
, 1)) {
210 qemu_irq_pulse(s
->irq
[i
+ 32 * bank
]);
217 const uint32_t cleared
= s
->pr
[bank
] & val64
& configurable_mask(bank
);
218 /* This bit is cleared by writing a 1 to it */
219 s
->pr
[bank
] &= ~cleared
;
220 /* Software triggered interrupts are cleared as well */
221 s
->swier
[bank
] &= ~cleared
;
225 qemu_log_mask(LOG_GUEST_ERROR
,
226 "STM32L4X5_exti_write: Bad offset 0x%" HWADDR_PRIx
"\n",
231 static const MemoryRegionOps stm32l4x5_exti_ops
= {
232 .read
= stm32l4x5_exti_read
,
233 .write
= stm32l4x5_exti_write
,
234 .endianness
= DEVICE_NATIVE_ENDIAN
,
235 .impl
.min_access_size
= 4,
236 .impl
.max_access_size
= 4,
237 .impl
.unaligned
= false,
238 .valid
.min_access_size
= 4,
239 .valid
.max_access_size
= 4,
240 .valid
.unaligned
= false,
243 static void stm32l4x5_exti_init(Object
*obj
)
245 Stm32l4x5ExtiState
*s
= STM32L4X5_EXTI(obj
);
247 for (size_t i
= 0; i
< EXTI_NUM_LINES
; i
++) {
248 sysbus_init_irq(SYS_BUS_DEVICE(obj
), &s
->irq
[i
]);
251 memory_region_init_io(&s
->mmio
, obj
, &stm32l4x5_exti_ops
, s
,
252 TYPE_STM32L4X5_EXTI
, 0x400);
253 sysbus_init_mmio(SYS_BUS_DEVICE(obj
), &s
->mmio
);
255 qdev_init_gpio_in(DEVICE(obj
), stm32l4x5_exti_set_irq
, EXTI_NUM_LINES
);
258 static const VMStateDescription vmstate_stm32l4x5_exti
= {
259 .name
= TYPE_STM32L4X5_EXTI
,
261 .minimum_version_id
= 2,
262 .fields
= (VMStateField
[]) {
263 VMSTATE_UINT32_ARRAY(imr
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
264 VMSTATE_UINT32_ARRAY(emr
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
265 VMSTATE_UINT32_ARRAY(rtsr
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
266 VMSTATE_UINT32_ARRAY(ftsr
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
267 VMSTATE_UINT32_ARRAY(swier
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
268 VMSTATE_UINT32_ARRAY(pr
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
269 VMSTATE_UINT32_ARRAY(irq_levels
, Stm32l4x5ExtiState
, EXTI_NUM_REGISTER
),
270 VMSTATE_END_OF_LIST()
274 static void stm32l4x5_exti_class_init(ObjectClass
*klass
, void *data
)
276 DeviceClass
*dc
= DEVICE_CLASS(klass
);
277 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
279 dc
->vmsd
= &vmstate_stm32l4x5_exti
;
280 rc
->phases
.hold
= stm32l4x5_exti_reset_hold
;
283 static const TypeInfo stm32l4x5_exti_types
[] = {
285 .name
= TYPE_STM32L4X5_EXTI
,
286 .parent
= TYPE_SYS_BUS_DEVICE
,
287 .instance_size
= sizeof(Stm32l4x5ExtiState
),
288 .instance_init
= stm32l4x5_exti_init
,
289 .class_init
= stm32l4x5_exti_class_init
,
293 DEFINE_TYPES(stm32l4x5_exti_types
)