2 * STM32L4x5 SYSCFG (System Configuration Controller)
4 * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5 * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
7 * SPDX-License-Identifier: GPL-2.0-or-later
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
12 * This work is based on the stm32f4xx_syscfg by Alistair Francis.
13 * Original code is licensed under the MIT License:
15 * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
19 * The reference used is the STMicroElectronics RM0351 Reference manual
20 * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
21 * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
24 #include "qemu/osdep.h"
28 #include "migration/vmstate.h"
30 #include "hw/qdev-clock.h"
31 #include "qapi/error.h"
32 #include "hw/misc/stm32l4x5_syscfg.h"
33 #include "hw/gpio/stm32l4x5_gpio.h"
35 #define SYSCFG_MEMRMP 0x00
36 #define SYSCFG_CFGR1 0x04
37 #define SYSCFG_EXTICR1 0x08
38 #define SYSCFG_EXTICR2 0x0C
39 #define SYSCFG_EXTICR3 0x10
40 #define SYSCFG_EXTICR4 0x14
41 #define SYSCFG_SCSR 0x18
42 #define SYSCFG_CFGR2 0x1C
43 #define SYSCFG_SWPR 0x20
44 #define SYSCFG_SKR 0x24
45 #define SYSCFG_SWPR2 0x28
47 /* 00000000_00000000_00000001_00000111 */
48 #define ACTIVABLE_BITS_MEMRP 0x00000107
50 /* 11111100_11111111_00000001_00000000 */
51 #define ACTIVABLE_BITS_CFGR1 0xFCFF0100
52 /* 00000000_00000000_00000000_00000001 */
53 #define FIREWALL_DISABLE_CFGR1 0x00000001
55 /* 00000000_00000000_11111111_11111111 */
56 #define ACTIVABLE_BITS_EXTICR 0x0000FFFF
58 /* 00000000_00000000_00000000_00000011 */
59 /* #define ACTIVABLE_BITS_SCSR 0x00000003 */
61 /* 00000000_00000000_00000000_00001111 */
62 #define ECC_LOCK_CFGR2 0x0000000F
63 /* 00000000_00000000_00000001_00000000 */
64 #define SRAM2_PARITY_ERROR_FLAG_CFGR2 0x00000100
66 /* 00000000_00000000_00000000_11111111 */
67 #define ACTIVABLE_BITS_SKR 0x000000FF
69 #define NUM_LINES_PER_EXTICR_REG 4
71 static void stm32l4x5_syscfg_hold_reset(Object
*obj
, ResetType type
)
73 Stm32l4x5SyscfgState
*s
= STM32L4X5_SYSCFG(obj
);
75 s
->memrmp
= 0x00000000;
76 s
->cfgr1
= 0x7C000001;
77 s
->exticr
[0] = 0x00000000;
78 s
->exticr
[1] = 0x00000000;
79 s
->exticr
[2] = 0x00000000;
80 s
->exticr
[3] = 0x00000000;
82 s
->cfgr2
= 0x00000000;
85 s
->swpr2
= 0x00000000;
88 static void stm32l4x5_syscfg_set_irq(void *opaque
, int irq
, int level
)
90 Stm32l4x5SyscfgState
*s
= opaque
;
91 const uint8_t gpio
= irq
/ GPIO_NUM_PINS
;
92 const int line
= irq
% GPIO_NUM_PINS
;
94 const int exticr_reg
= line
/ NUM_LINES_PER_EXTICR_REG
;
95 const int startbit
= (line
% NUM_LINES_PER_EXTICR_REG
) * 4;
97 g_assert(gpio
< NUM_GPIOS
);
98 trace_stm32l4x5_syscfg_set_irq(gpio
, line
, level
);
100 if (extract32(s
->exticr
[exticr_reg
], startbit
, 4) == gpio
) {
101 trace_stm32l4x5_syscfg_forward_exti(line
);
102 qemu_set_irq(s
->gpio_out
[line
], level
);
106 static uint64_t stm32l4x5_syscfg_read(void *opaque
, hwaddr addr
,
109 Stm32l4x5SyscfgState
*s
= opaque
;
111 trace_stm32l4x5_syscfg_read(addr
);
118 case SYSCFG_EXTICR1
...SYSCFG_EXTICR4
:
119 return s
->exticr
[(addr
- SYSCFG_EXTICR1
) / 4];
131 qemu_log_mask(LOG_GUEST_ERROR
,
132 "%s: Bad offset 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
136 static void stm32l4x5_syscfg_write(void *opaque
, hwaddr addr
,
137 uint64_t value
, unsigned int size
)
139 Stm32l4x5SyscfgState
*s
= opaque
;
141 trace_stm32l4x5_syscfg_write(addr
, value
);
145 qemu_log_mask(LOG_UNIMP
,
146 "%s: Changing the memory mapping isn't supported\n",
148 s
->memrmp
= value
& ACTIVABLE_BITS_MEMRP
;
151 qemu_log_mask(LOG_UNIMP
,
152 "%s: Functions in CFGRx aren't supported\n",
154 /* bit 0 (firewall dis.) is cleared by software, set only by reset. */
155 s
->cfgr1
= (s
->cfgr1
& value
& FIREWALL_DISABLE_CFGR1
) |
156 (value
& ACTIVABLE_BITS_CFGR1
);
158 case SYSCFG_EXTICR1
...SYSCFG_EXTICR4
:
159 s
->exticr
[(addr
- SYSCFG_EXTICR1
) / 4] =
160 (value
& ACTIVABLE_BITS_EXTICR
);
163 qemu_log_mask(LOG_UNIMP
,
164 "%s: Erasing SRAM2 isn't supported\n",
167 * only non reserved bits are :
168 * bit 0 (write-protected by a passkey), bit 1 (meant to be read)
169 * so it serves no purpose yet to add :
170 * s->scsr = value & 0x3;
174 qemu_log_mask(LOG_UNIMP
,
175 "%s: Functions in CFGRx aren't supported\n",
177 /* bit 8 (SRAM2 PEF) is cleared by software by writing a '1'.*/
178 /* bits[3:0] (ECC Lock) are set by software, cleared only by reset.*/
179 s
->cfgr2
= (s
->cfgr2
| (value
& ECC_LOCK_CFGR2
)) &
180 ~(value
& SRAM2_PARITY_ERROR_FLAG_CFGR2
);
183 qemu_log_mask(LOG_UNIMP
,
184 "%s: Write protecting SRAM2 isn't supported\n",
186 /* These bits are set by software and cleared only by reset.*/
190 qemu_log_mask(LOG_UNIMP
,
191 "%s: Erasing SRAM2 isn't supported\n",
193 s
->skr
= value
& ACTIVABLE_BITS_SKR
;
196 qemu_log_mask(LOG_UNIMP
,
197 "%s: Write protecting SRAM2 isn't supported\n",
199 /* These bits are set by software and cleared only by reset.*/
203 qemu_log_mask(LOG_GUEST_ERROR
,
204 "%s: Bad offset 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
208 static const MemoryRegionOps stm32l4x5_syscfg_ops
= {
209 .read
= stm32l4x5_syscfg_read
,
210 .write
= stm32l4x5_syscfg_write
,
211 .endianness
= DEVICE_NATIVE_ENDIAN
,
212 .impl
.min_access_size
= 4,
213 .impl
.max_access_size
= 4,
214 .impl
.unaligned
= false,
215 .valid
.min_access_size
= 4,
216 .valid
.max_access_size
= 4,
217 .valid
.unaligned
= false,
220 static void stm32l4x5_syscfg_init(Object
*obj
)
222 Stm32l4x5SyscfgState
*s
= STM32L4X5_SYSCFG(obj
);
224 memory_region_init_io(&s
->mmio
, obj
, &stm32l4x5_syscfg_ops
, s
,
225 TYPE_STM32L4X5_SYSCFG
, 0x400);
226 sysbus_init_mmio(SYS_BUS_DEVICE(obj
), &s
->mmio
);
228 qdev_init_gpio_in(DEVICE(obj
), stm32l4x5_syscfg_set_irq
,
229 GPIO_NUM_PINS
* NUM_GPIOS
);
230 qdev_init_gpio_out(DEVICE(obj
), s
->gpio_out
, GPIO_NUM_PINS
);
231 s
->clk
= qdev_init_clock_in(DEVICE(s
), "clk", NULL
, s
, 0);
234 static void stm32l4x5_syscfg_realize(DeviceState
*dev
, Error
**errp
)
236 Stm32l4x5SyscfgState
*s
= STM32L4X5_SYSCFG(dev
);
237 if (!clock_has_source(s
->clk
)) {
238 error_setg(errp
, "SYSCFG: clk input must be connected");
243 static const VMStateDescription vmstate_stm32l4x5_syscfg
= {
244 .name
= TYPE_STM32L4X5_SYSCFG
,
246 .minimum_version_id
= 2,
247 .fields
= (VMStateField
[]) {
248 VMSTATE_UINT32(memrmp
, Stm32l4x5SyscfgState
),
249 VMSTATE_UINT32(cfgr1
, Stm32l4x5SyscfgState
),
250 VMSTATE_UINT32_ARRAY(exticr
, Stm32l4x5SyscfgState
,
252 VMSTATE_UINT32(scsr
, Stm32l4x5SyscfgState
),
253 VMSTATE_UINT32(cfgr2
, Stm32l4x5SyscfgState
),
254 VMSTATE_UINT32(swpr
, Stm32l4x5SyscfgState
),
255 VMSTATE_UINT32(skr
, Stm32l4x5SyscfgState
),
256 VMSTATE_UINT32(swpr2
, Stm32l4x5SyscfgState
),
257 VMSTATE_CLOCK(clk
, Stm32l4x5SyscfgState
),
258 VMSTATE_END_OF_LIST()
262 static void stm32l4x5_syscfg_class_init(ObjectClass
*klass
, void *data
)
264 DeviceClass
*dc
= DEVICE_CLASS(klass
);
265 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
267 dc
->vmsd
= &vmstate_stm32l4x5_syscfg
;
268 dc
->realize
= stm32l4x5_syscfg_realize
;
269 rc
->phases
.hold
= stm32l4x5_syscfg_hold_reset
;
272 static const TypeInfo stm32l4x5_syscfg_info
[] = {
274 .name
= TYPE_STM32L4X5_SYSCFG
,
275 .parent
= TYPE_SYS_BUS_DEVICE
,
276 .instance_size
= sizeof(Stm32l4x5SyscfgState
),
277 .instance_init
= stm32l4x5_syscfg_init
,
278 .class_init
= stm32l4x5_syscfg_class_init
,
282 DEFINE_TYPES(stm32l4x5_syscfg_info
)