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
stm32f4xx_syscfg_reset(DeviceState * dev)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
stm32f4xx_syscfg_set_irq(void * opaque,int irq,int level)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
stm32f4xx_syscfg_read(void * opaque,hwaddr addr,unsigned int size)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
stm32f4xx_syscfg_write(void * opaque,hwaddr addr,uint64_t val64,unsigned int size)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
stm32f4xx_syscfg_init(Object * obj)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
stm32f4xx_syscfg_class_init(ObjectClass * klass,void * data)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
stm32f4xx_syscfg_register_types(void)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