1870c034dSAlistair Francis /* 2870c034dSAlistair Francis * STM32F4xx SYSCFG 3870c034dSAlistair Francis * 4870c034dSAlistair Francis * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me> 5870c034dSAlistair Francis * 6870c034dSAlistair Francis * Permission is hereby granted, free of charge, to any person obtaining a copy 7870c034dSAlistair Francis * of this software and associated documentation files (the "Software"), to deal 8870c034dSAlistair Francis * in the Software without restriction, including without limitation the rights 9870c034dSAlistair Francis * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10870c034dSAlistair Francis * copies of the Software, and to permit persons to whom the Software is 11870c034dSAlistair Francis * furnished to do so, subject to the following conditions: 12870c034dSAlistair Francis * 13870c034dSAlistair Francis * The above copyright notice and this permission notice shall be included in 14870c034dSAlistair Francis * all copies or substantial portions of the Software. 15870c034dSAlistair Francis * 16870c034dSAlistair Francis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17870c034dSAlistair Francis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18870c034dSAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19870c034dSAlistair Francis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20870c034dSAlistair Francis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21870c034dSAlistair Francis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22870c034dSAlistair Francis * THE SOFTWARE. 23870c034dSAlistair Francis */ 24870c034dSAlistair Francis 25870c034dSAlistair Francis #include "qemu/osdep.h" 26870c034dSAlistair Francis #include "qemu/log.h" 27870c034dSAlistair Francis #include "trace.h" 28870c034dSAlistair Francis #include "hw/irq.h" 29870c034dSAlistair Francis #include "migration/vmstate.h" 30870c034dSAlistair Francis #include "hw/misc/stm32f4xx_syscfg.h" 31870c034dSAlistair Francis 32870c034dSAlistair Francis static void stm32f4xx_syscfg_reset(DeviceState *dev) 33870c034dSAlistair Francis { 34870c034dSAlistair Francis STM32F4xxSyscfgState *s = STM32F4XX_SYSCFG(dev); 35870c034dSAlistair Francis 36870c034dSAlistair Francis s->syscfg_memrmp = 0x00000000; 37870c034dSAlistair Francis s->syscfg_pmc = 0x00000000; 38870c034dSAlistair Francis s->syscfg_exticr[0] = 0x00000000; 39870c034dSAlistair Francis s->syscfg_exticr[1] = 0x00000000; 40870c034dSAlistair Francis s->syscfg_exticr[2] = 0x00000000; 41870c034dSAlistair Francis s->syscfg_exticr[3] = 0x00000000; 42870c034dSAlistair Francis s->syscfg_cmpcr = 0x00000000; 43870c034dSAlistair Francis } 44870c034dSAlistair Francis 45870c034dSAlistair Francis static void stm32f4xx_syscfg_set_irq(void *opaque, int irq, int level) 46870c034dSAlistair Francis { 47870c034dSAlistair Francis STM32F4xxSyscfgState *s = opaque; 48870c034dSAlistair Francis int icrreg = irq / 4; 49870c034dSAlistair Francis int startbit = (irq & 3) * 4; 50a4abb6f2SPhilippe Mathieu-Daudé uint8_t config = irq / 16; 51870c034dSAlistair Francis 52870c034dSAlistair Francis trace_stm32f4xx_syscfg_set_irq(irq / 16, irq % 16, level); 53870c034dSAlistair Francis 54870c034dSAlistair Francis g_assert(icrreg < SYSCFG_NUM_EXTICR); 55870c034dSAlistair Francis 56870c034dSAlistair Francis if (extract32(s->syscfg_exticr[icrreg], startbit, 4) == config) { 57870c034dSAlistair Francis qemu_set_irq(s->gpio_out[irq], level); 58870c034dSAlistair Francis trace_stm32f4xx_pulse_exti(irq); 59870c034dSAlistair Francis } 60870c034dSAlistair Francis } 61870c034dSAlistair Francis 62870c034dSAlistair Francis static uint64_t stm32f4xx_syscfg_read(void *opaque, hwaddr addr, 63870c034dSAlistair Francis unsigned int size) 64870c034dSAlistair Francis { 65870c034dSAlistair Francis STM32F4xxSyscfgState *s = opaque; 66870c034dSAlistair Francis 67870c034dSAlistair Francis trace_stm32f4xx_syscfg_read(addr); 68870c034dSAlistair Francis 69870c034dSAlistair Francis switch (addr) { 70870c034dSAlistair Francis case SYSCFG_MEMRMP: 71870c034dSAlistair Francis return s->syscfg_memrmp; 72870c034dSAlistair Francis case SYSCFG_PMC: 73870c034dSAlistair Francis return s->syscfg_pmc; 74870c034dSAlistair Francis case SYSCFG_EXTICR1...SYSCFG_EXTICR4: 75870c034dSAlistair Francis return s->syscfg_exticr[addr / 4 - SYSCFG_EXTICR1 / 4]; 76870c034dSAlistair Francis case SYSCFG_CMPCR: 77870c034dSAlistair Francis return s->syscfg_cmpcr; 78870c034dSAlistair Francis default: 79870c034dSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 80870c034dSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 81870c034dSAlistair Francis return 0; 82870c034dSAlistair Francis } 83870c034dSAlistair Francis } 84870c034dSAlistair Francis 85870c034dSAlistair Francis static void stm32f4xx_syscfg_write(void *opaque, hwaddr addr, 86870c034dSAlistair Francis uint64_t val64, unsigned int size) 87870c034dSAlistair Francis { 88870c034dSAlistair Francis STM32F4xxSyscfgState *s = opaque; 89870c034dSAlistair Francis uint32_t value = val64; 90870c034dSAlistair Francis 91870c034dSAlistair Francis trace_stm32f4xx_syscfg_write(value, addr); 92870c034dSAlistair Francis 93870c034dSAlistair Francis switch (addr) { 94870c034dSAlistair Francis case SYSCFG_MEMRMP: 95870c034dSAlistair Francis qemu_log_mask(LOG_UNIMP, 96870c034dSAlistair Francis "%s: Changing the memory mapping isn't supported " \ 97870c034dSAlistair Francis "in QEMU\n", __func__); 98870c034dSAlistair Francis return; 99870c034dSAlistair Francis case SYSCFG_PMC: 100870c034dSAlistair Francis qemu_log_mask(LOG_UNIMP, 101870c034dSAlistair Francis "%s: Changing the memory mapping isn't supported " \ 102870c034dSAlistair Francis "in QEMU\n", __func__); 103870c034dSAlistair Francis return; 104870c034dSAlistair Francis case SYSCFG_EXTICR1...SYSCFG_EXTICR4: 105870c034dSAlistair Francis s->syscfg_exticr[addr / 4 - SYSCFG_EXTICR1 / 4] = (value & 0xFFFF); 106870c034dSAlistair Francis return; 107870c034dSAlistair Francis case SYSCFG_CMPCR: 108870c034dSAlistair Francis s->syscfg_cmpcr = value; 109870c034dSAlistair Francis return; 110870c034dSAlistair Francis default: 111870c034dSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 112870c034dSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 113870c034dSAlistair Francis } 114870c034dSAlistair Francis } 115870c034dSAlistair Francis 116870c034dSAlistair Francis static const MemoryRegionOps stm32f4xx_syscfg_ops = { 117870c034dSAlistair Francis .read = stm32f4xx_syscfg_read, 118870c034dSAlistair Francis .write = stm32f4xx_syscfg_write, 119870c034dSAlistair Francis .endianness = DEVICE_NATIVE_ENDIAN, 120870c034dSAlistair Francis }; 121870c034dSAlistair Francis 122870c034dSAlistair Francis static void stm32f4xx_syscfg_init(Object *obj) 123870c034dSAlistair Francis { 124870c034dSAlistair Francis STM32F4xxSyscfgState *s = STM32F4XX_SYSCFG(obj); 125870c034dSAlistair Francis 126870c034dSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 127870c034dSAlistair Francis 128870c034dSAlistair Francis memory_region_init_io(&s->mmio, obj, &stm32f4xx_syscfg_ops, s, 129870c034dSAlistair Francis TYPE_STM32F4XX_SYSCFG, 0x400); 130870c034dSAlistair Francis sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 131870c034dSAlistair Francis 132870c034dSAlistair Francis qdev_init_gpio_in(DEVICE(obj), stm32f4xx_syscfg_set_irq, 16 * 9); 133870c034dSAlistair Francis qdev_init_gpio_out(DEVICE(obj), s->gpio_out, 16); 134870c034dSAlistair Francis } 135870c034dSAlistair Francis 136870c034dSAlistair Francis static const VMStateDescription vmstate_stm32f4xx_syscfg = { 137870c034dSAlistair Francis .name = TYPE_STM32F4XX_SYSCFG, 138870c034dSAlistair Francis .version_id = 1, 139870c034dSAlistair Francis .minimum_version_id = 1, 140e4ea952fSRichard Henderson .fields = (const VMStateField[]) { 141870c034dSAlistair Francis VMSTATE_UINT32(syscfg_memrmp, STM32F4xxSyscfgState), 142870c034dSAlistair Francis VMSTATE_UINT32(syscfg_pmc, STM32F4xxSyscfgState), 143870c034dSAlistair Francis VMSTATE_UINT32_ARRAY(syscfg_exticr, STM32F4xxSyscfgState, 144870c034dSAlistair Francis SYSCFG_NUM_EXTICR), 145870c034dSAlistair Francis VMSTATE_UINT32(syscfg_cmpcr, STM32F4xxSyscfgState), 146870c034dSAlistair Francis VMSTATE_END_OF_LIST() 147870c034dSAlistair Francis } 148870c034dSAlistair Francis }; 149870c034dSAlistair Francis 150870c034dSAlistair Francis static void stm32f4xx_syscfg_class_init(ObjectClass *klass, void *data) 151870c034dSAlistair Francis { 152870c034dSAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 153870c034dSAlistair Francis 154*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, stm32f4xx_syscfg_reset); 155870c034dSAlistair Francis dc->vmsd = &vmstate_stm32f4xx_syscfg; 156870c034dSAlistair Francis } 157870c034dSAlistair Francis 158870c034dSAlistair Francis static const TypeInfo stm32f4xx_syscfg_info = { 159870c034dSAlistair Francis .name = TYPE_STM32F4XX_SYSCFG, 160870c034dSAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 161870c034dSAlistair Francis .instance_size = sizeof(STM32F4xxSyscfgState), 162870c034dSAlistair Francis .instance_init = stm32f4xx_syscfg_init, 163870c034dSAlistair Francis .class_init = stm32f4xx_syscfg_class_init, 164870c034dSAlistair Francis }; 165870c034dSAlistair Francis 166870c034dSAlistair Francis static void stm32f4xx_syscfg_register_types(void) 167870c034dSAlistair Francis { 168870c034dSAlistair Francis type_register_static(&stm32f4xx_syscfg_info); 169870c034dSAlistair Francis } 170870c034dSAlistair Francis 171870c034dSAlistair Francis type_init(stm32f4xx_syscfg_register_types) 172