1e64d8c83SAlistair Francis /*
2e64d8c83SAlistair Francis * STM32F4XX EXTI
3e64d8c83SAlistair Francis *
4e64d8c83SAlistair Francis * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
5e64d8c83SAlistair Francis *
6e64d8c83SAlistair Francis * Permission is hereby granted, free of charge, to any person obtaining a copy
7e64d8c83SAlistair Francis * of this software and associated documentation files (the "Software"), to deal
8e64d8c83SAlistair Francis * in the Software without restriction, including without limitation the rights
9e64d8c83SAlistair Francis * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10e64d8c83SAlistair Francis * copies of the Software, and to permit persons to whom the Software is
11e64d8c83SAlistair Francis * furnished to do so, subject to the following conditions:
12e64d8c83SAlistair Francis *
13e64d8c83SAlistair Francis * The above copyright notice and this permission notice shall be included in
14e64d8c83SAlistair Francis * all copies or substantial portions of the Software.
15e64d8c83SAlistair Francis *
16e64d8c83SAlistair Francis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e64d8c83SAlistair Francis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e64d8c83SAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19e64d8c83SAlistair Francis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e64d8c83SAlistair Francis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21e64d8c83SAlistair Francis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22e64d8c83SAlistair Francis * THE SOFTWARE.
23e64d8c83SAlistair Francis */
24e64d8c83SAlistair Francis
25e64d8c83SAlistair Francis #include "qemu/osdep.h"
26e64d8c83SAlistair Francis #include "qemu/log.h"
27e64d8c83SAlistair Francis #include "trace.h"
28e64d8c83SAlistair Francis #include "hw/irq.h"
29e64d8c83SAlistair Francis #include "migration/vmstate.h"
30e64d8c83SAlistair Francis #include "hw/misc/stm32f4xx_exti.h"
31e64d8c83SAlistair Francis
stm32f4xx_exti_reset(DeviceState * dev)32e64d8c83SAlistair Francis static void stm32f4xx_exti_reset(DeviceState *dev)
33e64d8c83SAlistair Francis {
34e64d8c83SAlistair Francis STM32F4xxExtiState *s = STM32F4XX_EXTI(dev);
35e64d8c83SAlistair Francis
36e64d8c83SAlistair Francis s->exti_imr = 0x00000000;
37e64d8c83SAlistair Francis s->exti_emr = 0x00000000;
38e64d8c83SAlistair Francis s->exti_rtsr = 0x00000000;
39e64d8c83SAlistair Francis s->exti_ftsr = 0x00000000;
40e64d8c83SAlistair Francis s->exti_swier = 0x00000000;
41e64d8c83SAlistair Francis s->exti_pr = 0x00000000;
42e64d8c83SAlistair Francis }
43e64d8c83SAlistair Francis
stm32f4xx_exti_set_irq(void * opaque,int irq,int level)44e64d8c83SAlistair Francis static void stm32f4xx_exti_set_irq(void *opaque, int irq, int level)
45e64d8c83SAlistair Francis {
46e64d8c83SAlistair Francis STM32F4xxExtiState *s = opaque;
47e64d8c83SAlistair Francis
48e64d8c83SAlistair Francis trace_stm32f4xx_exti_set_irq(irq, level);
49e64d8c83SAlistair Francis
50e64d8c83SAlistair Francis if (((1 << irq) & s->exti_rtsr) && level) {
51e64d8c83SAlistair Francis /* Rising Edge */
52e64d8c83SAlistair Francis s->exti_pr |= 1 << irq;
53e64d8c83SAlistair Francis }
54e64d8c83SAlistair Francis
55e64d8c83SAlistair Francis if (((1 << irq) & s->exti_ftsr) && !level) {
56e64d8c83SAlistair Francis /* Falling Edge */
57e64d8c83SAlistair Francis s->exti_pr |= 1 << irq;
58e64d8c83SAlistair Francis }
59e64d8c83SAlistair Francis
60e64d8c83SAlistair Francis if (!((1 << irq) & s->exti_imr)) {
61e64d8c83SAlistair Francis /* Interrupt is masked */
62e64d8c83SAlistair Francis return;
63e64d8c83SAlistair Francis }
64e64d8c83SAlistair Francis qemu_irq_pulse(s->irq[irq]);
65e64d8c83SAlistair Francis }
66e64d8c83SAlistair Francis
stm32f4xx_exti_read(void * opaque,hwaddr addr,unsigned int size)67e64d8c83SAlistair Francis static uint64_t stm32f4xx_exti_read(void *opaque, hwaddr addr,
68e64d8c83SAlistair Francis unsigned int size)
69e64d8c83SAlistair Francis {
70e64d8c83SAlistair Francis STM32F4xxExtiState *s = opaque;
71e64d8c83SAlistair Francis
72e64d8c83SAlistair Francis trace_stm32f4xx_exti_read(addr);
73e64d8c83SAlistair Francis
74e64d8c83SAlistair Francis switch (addr) {
75e64d8c83SAlistair Francis case EXTI_IMR:
76e64d8c83SAlistair Francis return s->exti_imr;
77e64d8c83SAlistair Francis case EXTI_EMR:
78e64d8c83SAlistair Francis return s->exti_emr;
79e64d8c83SAlistair Francis case EXTI_RTSR:
80e64d8c83SAlistair Francis return s->exti_rtsr;
81e64d8c83SAlistair Francis case EXTI_FTSR:
82e64d8c83SAlistair Francis return s->exti_ftsr;
83e64d8c83SAlistair Francis case EXTI_SWIER:
84e64d8c83SAlistair Francis return s->exti_swier;
85e64d8c83SAlistair Francis case EXTI_PR:
86e64d8c83SAlistair Francis return s->exti_pr;
87e64d8c83SAlistair Francis default:
88e64d8c83SAlistair Francis qemu_log_mask(LOG_GUEST_ERROR,
89e64d8c83SAlistair Francis "STM32F4XX_exti_read: Bad offset %x\n", (int)addr);
90e64d8c83SAlistair Francis return 0;
91e64d8c83SAlistair Francis }
92e64d8c83SAlistair Francis return 0;
93e64d8c83SAlistair Francis }
94e64d8c83SAlistair Francis
stm32f4xx_exti_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)95e64d8c83SAlistair Francis static void stm32f4xx_exti_write(void *opaque, hwaddr addr,
96e64d8c83SAlistair Francis uint64_t val64, unsigned int size)
97e64d8c83SAlistair Francis {
98e64d8c83SAlistair Francis STM32F4xxExtiState *s = opaque;
99e64d8c83SAlistair Francis uint32_t value = (uint32_t) val64;
100e64d8c83SAlistair Francis
101e64d8c83SAlistair Francis trace_stm32f4xx_exti_write(addr, value);
102e64d8c83SAlistair Francis
103e64d8c83SAlistair Francis switch (addr) {
104e64d8c83SAlistair Francis case EXTI_IMR:
105e64d8c83SAlistair Francis s->exti_imr = value;
106e64d8c83SAlistair Francis return;
107e64d8c83SAlistair Francis case EXTI_EMR:
108e64d8c83SAlistair Francis s->exti_emr = value;
109e64d8c83SAlistair Francis return;
110e64d8c83SAlistair Francis case EXTI_RTSR:
111e64d8c83SAlistair Francis s->exti_rtsr = value;
112e64d8c83SAlistair Francis return;
113e64d8c83SAlistair Francis case EXTI_FTSR:
114e64d8c83SAlistair Francis s->exti_ftsr = value;
115e64d8c83SAlistair Francis return;
116e64d8c83SAlistair Francis case EXTI_SWIER:
117e64d8c83SAlistair Francis s->exti_swier = value;
118e64d8c83SAlistair Francis return;
119e64d8c83SAlistair Francis case EXTI_PR:
120e64d8c83SAlistair Francis /* This bit is cleared by writing a 1 to it */
121e64d8c83SAlistair Francis s->exti_pr &= ~value;
122e64d8c83SAlistair Francis return;
123e64d8c83SAlistair Francis default:
124e64d8c83SAlistair Francis qemu_log_mask(LOG_GUEST_ERROR,
125e64d8c83SAlistair Francis "STM32F4XX_exti_write: Bad offset %x\n", (int)addr);
126e64d8c83SAlistair Francis }
127e64d8c83SAlistair Francis }
128e64d8c83SAlistair Francis
129e64d8c83SAlistair Francis static const MemoryRegionOps stm32f4xx_exti_ops = {
130e64d8c83SAlistair Francis .read = stm32f4xx_exti_read,
131e64d8c83SAlistair Francis .write = stm32f4xx_exti_write,
132e64d8c83SAlistair Francis .endianness = DEVICE_NATIVE_ENDIAN,
133e64d8c83SAlistair Francis };
134e64d8c83SAlistair Francis
stm32f4xx_exti_init(Object * obj)135e64d8c83SAlistair Francis static void stm32f4xx_exti_init(Object *obj)
136e64d8c83SAlistair Francis {
137e64d8c83SAlistair Francis STM32F4xxExtiState *s = STM32F4XX_EXTI(obj);
138e64d8c83SAlistair Francis int i;
139e64d8c83SAlistair Francis
140e64d8c83SAlistair Francis for (i = 0; i < NUM_INTERRUPT_OUT_LINES; i++) {
141e64d8c83SAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq[i]);
142e64d8c83SAlistair Francis }
143e64d8c83SAlistair Francis
144e64d8c83SAlistair Francis memory_region_init_io(&s->mmio, obj, &stm32f4xx_exti_ops, s,
145e64d8c83SAlistair Francis TYPE_STM32F4XX_EXTI, 0x400);
146e64d8c83SAlistair Francis sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
147e64d8c83SAlistair Francis
148e64d8c83SAlistair Francis qdev_init_gpio_in(DEVICE(obj), stm32f4xx_exti_set_irq,
149e64d8c83SAlistair Francis NUM_GPIO_EVENT_IN_LINES);
150e64d8c83SAlistair Francis }
151e64d8c83SAlistair Francis
152e64d8c83SAlistair Francis static const VMStateDescription vmstate_stm32f4xx_exti = {
153e64d8c83SAlistair Francis .name = TYPE_STM32F4XX_EXTI,
154e64d8c83SAlistair Francis .version_id = 1,
155e64d8c83SAlistair Francis .minimum_version_id = 1,
156e4ea952fSRichard Henderson .fields = (const VMStateField[]) {
157e64d8c83SAlistair Francis VMSTATE_UINT32(exti_imr, STM32F4xxExtiState),
158e64d8c83SAlistair Francis VMSTATE_UINT32(exti_emr, STM32F4xxExtiState),
159e64d8c83SAlistair Francis VMSTATE_UINT32(exti_rtsr, STM32F4xxExtiState),
160e64d8c83SAlistair Francis VMSTATE_UINT32(exti_ftsr, STM32F4xxExtiState),
161e64d8c83SAlistair Francis VMSTATE_UINT32(exti_swier, STM32F4xxExtiState),
162e64d8c83SAlistair Francis VMSTATE_UINT32(exti_pr, STM32F4xxExtiState),
163e64d8c83SAlistair Francis VMSTATE_END_OF_LIST()
164e64d8c83SAlistair Francis }
165e64d8c83SAlistair Francis };
166e64d8c83SAlistair Francis
stm32f4xx_exti_class_init(ObjectClass * klass,void * data)167e64d8c83SAlistair Francis static void stm32f4xx_exti_class_init(ObjectClass *klass, void *data)
168e64d8c83SAlistair Francis {
169e64d8c83SAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass);
170e64d8c83SAlistair Francis
171*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, stm32f4xx_exti_reset);
172e64d8c83SAlistair Francis dc->vmsd = &vmstate_stm32f4xx_exti;
173e64d8c83SAlistair Francis }
174e64d8c83SAlistair Francis
175e64d8c83SAlistair Francis static const TypeInfo stm32f4xx_exti_info = {
176e64d8c83SAlistair Francis .name = TYPE_STM32F4XX_EXTI,
177e64d8c83SAlistair Francis .parent = TYPE_SYS_BUS_DEVICE,
178e64d8c83SAlistair Francis .instance_size = sizeof(STM32F4xxExtiState),
179e64d8c83SAlistair Francis .instance_init = stm32f4xx_exti_init,
180e64d8c83SAlistair Francis .class_init = stm32f4xx_exti_class_init,
181e64d8c83SAlistair Francis };
182e64d8c83SAlistair Francis
stm32f4xx_exti_register_types(void)183e64d8c83SAlistair Francis static void stm32f4xx_exti_register_types(void)
184e64d8c83SAlistair Francis {
185e64d8c83SAlistair Francis type_register_static(&stm32f4xx_exti_info);
186e64d8c83SAlistair Francis }
187e64d8c83SAlistair Francis
188e64d8c83SAlistair Francis type_init(stm32f4xx_exti_register_types)
189