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