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