2 * STM32L4x5 GPIO (General Purpose Input/Ouput)
4 * Copyright (c) 2024 Arnaud Minier <arnaud.minier@telecom-paris.fr>
5 * Copyright (c) 2024 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.
14 * The reference used is the STMicroElectronics RM0351 Reference manual
15 * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
16 * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
19 #include "qemu/osdep.h"
21 #include "hw/gpio/stm32l4x5_gpio.h"
24 #include "hw/qdev-clock.h"
25 #include "hw/qdev-properties.h"
26 #include "qapi/visitor.h"
27 #include "qapi/error.h"
28 #include "migration/vmstate.h"
31 #define GPIO_MODER 0x00
32 #define GPIO_OTYPER 0x04
33 #define GPIO_OSPEEDR 0x08
34 #define GPIO_PUPDR 0x0C
37 #define GPIO_BSRR 0x18
38 #define GPIO_LCKR 0x1C
39 #define GPIO_AFRL 0x20
40 #define GPIO_AFRH 0x24
42 #define GPIO_ASCR 0x2C
44 /* 0b11111111_11111111_00000000_00000000 */
45 #define RESERVED_BITS_MASK 0xFFFF0000
47 static void update_gpio_idr(Stm32l4x5GpioState
*s
);
49 static bool is_pull_up(Stm32l4x5GpioState
*s
, unsigned pin
)
51 return extract32(s
->pupdr
, 2 * pin
, 2) == 1;
54 static bool is_pull_down(Stm32l4x5GpioState
*s
, unsigned pin
)
56 return extract32(s
->pupdr
, 2 * pin
, 2) == 2;
59 static bool is_output(Stm32l4x5GpioState
*s
, unsigned pin
)
61 return extract32(s
->moder
, 2 * pin
, 2) == 1;
64 static bool is_open_drain(Stm32l4x5GpioState
*s
, unsigned pin
)
66 return extract32(s
->otyper
, pin
, 1) == 1;
69 static bool is_push_pull(Stm32l4x5GpioState
*s
, unsigned pin
)
71 return extract32(s
->otyper
, pin
, 1) == 0;
74 static void stm32l4x5_gpio_reset_hold(Object
*obj
, ResetType type
)
76 Stm32l4x5GpioState
*s
= STM32L4X5_GPIO(obj
);
78 s
->moder
= s
->moder_reset
;
79 s
->otyper
= 0x00000000;
80 s
->ospeedr
= s
->ospeedr_reset
;
81 s
->pupdr
= s
->pupdr_reset
;
89 s
->disconnected_pins
= 0xFFFF;
90 s
->pins_connected_high
= 0x0000;
94 static void stm32l4x5_gpio_set(void *opaque
, int line
, int level
)
96 Stm32l4x5GpioState
*s
= opaque
;
98 * The pin isn't set if line is configured in output mode
99 * except if level is 0 and the output is open-drain.
100 * This way there will be no short-circuit prone situations.
102 if (is_output(s
, line
) && !(is_open_drain(s
, line
) && (level
== 0))) {
103 qemu_log_mask(LOG_GUEST_ERROR
, "Line %d can't be driven externally\n",
108 s
->disconnected_pins
&= ~(1 << line
);
110 s
->pins_connected_high
|= (1 << line
);
112 s
->pins_connected_high
&= ~(1 << line
);
114 trace_stm32l4x5_gpio_pins(s
->name
, s
->disconnected_pins
,
115 s
->pins_connected_high
);
120 static void update_gpio_idr(Stm32l4x5GpioState
*s
)
122 uint32_t new_idr_mask
= 0;
123 uint32_t new_idr
= s
->odr
;
124 uint32_t old_idr
= s
->idr
;
125 int new_pin_state
, old_pin_state
;
127 for (int i
= 0; i
< GPIO_NUM_PINS
; i
++) {
128 if (is_output(s
, i
)) {
129 if (is_push_pull(s
, i
)) {
130 new_idr_mask
|= (1 << i
);
131 } else if (!(s
->odr
& (1 << i
))) {
132 /* open-drain ODR 0 */
133 new_idr_mask
|= (1 << i
);
134 /* open-drain ODR 1 */
135 } else if (!(s
->disconnected_pins
& (1 << i
)) &&
136 !(s
->pins_connected_high
& (1 << i
))) {
137 /* open-drain ODR 1 with pin connected low */
138 new_idr_mask
|= (1 << i
);
139 new_idr
&= ~(1 << i
);
140 /* open-drain ODR 1 with unactive pin */
141 } else if (is_pull_up(s
, i
)) {
142 new_idr_mask
|= (1 << i
);
143 } else if (is_pull_down(s
, i
)) {
144 new_idr_mask
|= (1 << i
);
145 new_idr
&= ~(1 << i
);
148 * The only case left is for open-drain ODR 1
149 * with unactive pin without pull-up or pull-down :
150 * the value is floating.
152 /* input or analog mode with connected pin */
153 } else if (!(s
->disconnected_pins
& (1 << i
))) {
154 if (s
->pins_connected_high
& (1 << i
)) {
156 new_idr_mask
|= (1 << i
);
160 new_idr_mask
|= (1 << i
);
161 new_idr
&= ~(1 << i
);
163 /* input or analog mode with disconnected pin */
165 if (is_pull_up(s
, i
)) {
167 new_idr_mask
|= (1 << i
);
169 } else if (is_pull_down(s
, i
)) {
171 new_idr_mask
|= (1 << i
);
172 new_idr
&= ~(1 << i
);
175 * The only case left is for a disconnected pin
176 * without pull-up or pull-down :
177 * the value is floating.
182 s
->idr
= (old_idr
& ~new_idr_mask
) | (new_idr
& new_idr_mask
);
183 trace_stm32l4x5_gpio_update_idr(s
->name
, old_idr
, s
->idr
);
185 for (int i
= 0; i
< GPIO_NUM_PINS
; i
++) {
186 if (new_idr_mask
& (1 << i
)) {
187 new_pin_state
= (new_idr
& (1 << i
)) > 0;
188 old_pin_state
= (old_idr
& (1 << i
)) > 0;
189 if (new_pin_state
> old_pin_state
) {
190 qemu_irq_raise(s
->pin
[i
]);
191 } else if (new_pin_state
< old_pin_state
) {
192 qemu_irq_lower(s
->pin
[i
]);
199 * Return mask of pins that are both configured in output
200 * mode and externally driven (except pins in open-drain
201 * mode externally set to 0).
203 static uint32_t get_gpio_pinmask_to_disconnect(Stm32l4x5GpioState
*s
)
205 uint32_t pins_to_disconnect
= 0;
206 for (int i
= 0; i
< GPIO_NUM_PINS
; i
++) {
207 /* for each connected pin in output mode */
208 if (!(s
->disconnected_pins
& (1 << i
)) && is_output(s
, i
)) {
209 /* if either push-pull or high level */
210 if (is_push_pull(s
, i
) || s
->pins_connected_high
& (1 << i
)) {
211 pins_to_disconnect
|= (1 << i
);
212 qemu_log_mask(LOG_GUEST_ERROR
,
213 "Line %d can't be driven externally\n",
218 return pins_to_disconnect
;
222 * Set field `disconnected_pins` and call `update_gpio_idr()`
224 static void disconnect_gpio_pins(Stm32l4x5GpioState
*s
, uint16_t lines
)
226 s
->disconnected_pins
|= lines
;
227 trace_stm32l4x5_gpio_pins(s
->name
, s
->disconnected_pins
,
228 s
->pins_connected_high
);
232 static void disconnected_pins_set(Object
*obj
, Visitor
*v
,
233 const char *name
, void *opaque
, Error
**errp
)
235 Stm32l4x5GpioState
*s
= STM32L4X5_GPIO(obj
);
237 if (!visit_type_uint16(v
, name
, &value
, errp
)) {
240 disconnect_gpio_pins(s
, value
);
243 static void disconnected_pins_get(Object
*obj
, Visitor
*v
,
244 const char *name
, void *opaque
, Error
**errp
)
246 visit_type_uint16(v
, name
, (uint16_t *)opaque
, errp
);
249 static void clock_freq_get(Object
*obj
, Visitor
*v
,
250 const char *name
, void *opaque
, Error
**errp
)
252 Stm32l4x5GpioState
*s
= STM32L4X5_GPIO(obj
);
253 uint32_t clock_freq_hz
= clock_get_hz(s
->clk
);
254 visit_type_uint32(v
, name
, &clock_freq_hz
, errp
);
257 static void stm32l4x5_gpio_write(void *opaque
, hwaddr addr
,
258 uint64_t val64
, unsigned int size
)
260 Stm32l4x5GpioState
*s
= opaque
;
262 uint32_t value
= val64
;
263 trace_stm32l4x5_gpio_write(s
->name
, addr
, val64
);
268 disconnect_gpio_pins(s
, get_gpio_pinmask_to_disconnect(s
));
269 qemu_log_mask(LOG_UNIMP
,
270 "%s: Analog and AF modes aren't supported\n\
271 Analog and AF mode behave like input mode\n",
275 s
->otyper
= value
& ~RESERVED_BITS_MASK
;
276 disconnect_gpio_pins(s
, get_gpio_pinmask_to_disconnect(s
));
279 qemu_log_mask(LOG_UNIMP
,
280 "%s: Changing I/O output speed isn't supported\n\
281 I/O speed is already maximal\n",
290 qemu_log_mask(LOG_UNIMP
,
291 "%s: GPIO->IDR is read-only\n",
295 s
->odr
= value
& ~RESERVED_BITS_MASK
;
299 uint32_t bits_to_reset
= (value
& RESERVED_BITS_MASK
) >> GPIO_NUM_PINS
;
300 uint32_t bits_to_set
= value
& ~RESERVED_BITS_MASK
;
301 /* If both BSx and BRx are set, BSx has priority.*/
302 s
->odr
&= ~bits_to_reset
;
303 s
->odr
|= bits_to_set
;
308 qemu_log_mask(LOG_UNIMP
,
309 "%s: Locking port bits configuration isn't supported\n",
311 s
->lckr
= value
& ~RESERVED_BITS_MASK
;
314 qemu_log_mask(LOG_UNIMP
,
315 "%s: Alternate functions aren't supported\n",
320 qemu_log_mask(LOG_UNIMP
,
321 "%s: Alternate functions aren't supported\n",
326 uint32_t bits_to_reset
= value
& ~RESERVED_BITS_MASK
;
327 s
->odr
&= ~bits_to_reset
;
332 qemu_log_mask(LOG_UNIMP
,
333 "%s: ADC function isn't supported\n",
335 s
->ascr
= value
& ~RESERVED_BITS_MASK
;
338 qemu_log_mask(LOG_GUEST_ERROR
,
339 "%s: Bad offset 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
343 static uint64_t stm32l4x5_gpio_read(void *opaque
, hwaddr addr
,
346 Stm32l4x5GpioState
*s
= opaque
;
348 trace_stm32l4x5_gpio_read(s
->name
, addr
);
376 qemu_log_mask(LOG_GUEST_ERROR
,
377 "%s: Bad offset 0x%" HWADDR_PRIx
"\n", __func__
, addr
);
382 static const MemoryRegionOps stm32l4x5_gpio_ops
= {
383 .read
= stm32l4x5_gpio_read
,
384 .write
= stm32l4x5_gpio_write
,
385 .endianness
= DEVICE_NATIVE_ENDIAN
,
387 .min_access_size
= 4,
388 .max_access_size
= 4,
392 .min_access_size
= 4,
393 .max_access_size
= 4,
398 static void stm32l4x5_gpio_init(Object
*obj
)
400 Stm32l4x5GpioState
*s
= STM32L4X5_GPIO(obj
);
402 memory_region_init_io(&s
->mmio
, obj
, &stm32l4x5_gpio_ops
, s
,
403 TYPE_STM32L4X5_GPIO
, 0x400);
405 sysbus_init_mmio(SYS_BUS_DEVICE(obj
), &s
->mmio
);
407 qdev_init_gpio_out(DEVICE(obj
), s
->pin
, GPIO_NUM_PINS
);
408 qdev_init_gpio_in(DEVICE(obj
), stm32l4x5_gpio_set
, GPIO_NUM_PINS
);
410 s
->clk
= qdev_init_clock_in(DEVICE(s
), "clk", NULL
, s
, 0);
412 object_property_add(obj
, "disconnected-pins", "uint16",
413 disconnected_pins_get
, disconnected_pins_set
,
414 NULL
, &s
->disconnected_pins
);
415 object_property_add(obj
, "clock-freq-hz", "uint32",
416 clock_freq_get
, NULL
, NULL
, NULL
);
419 static void stm32l4x5_gpio_realize(DeviceState
*dev
, Error
**errp
)
421 Stm32l4x5GpioState
*s
= STM32L4X5_GPIO(dev
);
422 if (!clock_has_source(s
->clk
)) {
423 error_setg(errp
, "GPIO: clk input must be connected");
428 static const VMStateDescription vmstate_stm32l4x5_gpio
= {
429 .name
= TYPE_STM32L4X5_GPIO
,
431 .minimum_version_id
= 2,
432 .fields
= (VMStateField
[]){
433 VMSTATE_UINT32(moder
, Stm32l4x5GpioState
),
434 VMSTATE_UINT32(otyper
, Stm32l4x5GpioState
),
435 VMSTATE_UINT32(ospeedr
, Stm32l4x5GpioState
),
436 VMSTATE_UINT32(pupdr
, Stm32l4x5GpioState
),
437 VMSTATE_UINT32(idr
, Stm32l4x5GpioState
),
438 VMSTATE_UINT32(odr
, Stm32l4x5GpioState
),
439 VMSTATE_UINT32(lckr
, Stm32l4x5GpioState
),
440 VMSTATE_UINT32(afrl
, Stm32l4x5GpioState
),
441 VMSTATE_UINT32(afrh
, Stm32l4x5GpioState
),
442 VMSTATE_UINT32(ascr
, Stm32l4x5GpioState
),
443 VMSTATE_UINT16(disconnected_pins
, Stm32l4x5GpioState
),
444 VMSTATE_UINT16(pins_connected_high
, Stm32l4x5GpioState
),
445 VMSTATE_CLOCK(clk
, Stm32l4x5GpioState
),
446 VMSTATE_END_OF_LIST()
450 static Property stm32l4x5_gpio_properties
[] = {
451 DEFINE_PROP_STRING("name", Stm32l4x5GpioState
, name
),
452 DEFINE_PROP_UINT32("mode-reset", Stm32l4x5GpioState
, moder_reset
, 0),
453 DEFINE_PROP_UINT32("ospeed-reset", Stm32l4x5GpioState
, ospeedr_reset
, 0),
454 DEFINE_PROP_UINT32("pupd-reset", Stm32l4x5GpioState
, pupdr_reset
, 0),
455 DEFINE_PROP_END_OF_LIST(),
458 static void stm32l4x5_gpio_class_init(ObjectClass
*klass
, void *data
)
460 DeviceClass
*dc
= DEVICE_CLASS(klass
);
461 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
463 device_class_set_props(dc
, stm32l4x5_gpio_properties
);
464 dc
->vmsd
= &vmstate_stm32l4x5_gpio
;
465 dc
->realize
= stm32l4x5_gpio_realize
;
466 rc
->phases
.hold
= stm32l4x5_gpio_reset_hold
;
469 static const TypeInfo stm32l4x5_gpio_types
[] = {
471 .name
= TYPE_STM32L4X5_GPIO
,
472 .parent
= TYPE_SYS_BUS_DEVICE
,
473 .instance_size
= sizeof(Stm32l4x5GpioState
),
474 .instance_init
= stm32l4x5_gpio_init
,
475 .class_init
= stm32l4x5_gpio_class_init
,
479 DEFINE_TYPES(stm32l4x5_gpio_types
)