xref: /openbmc/qemu/hw/misc/stm32f4xx_exti.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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