Hi Inès,
On 22/1/24 10:18, Inès Varhol wrote:
Features supported :
- the 8 STM32L4x5 GPIOs are initialized with their reset values
(except IDR, see below)
- input mode : setting a pin in input mode "externally" (using input
irqs) results in an out irq (transmitted to SYSCFG)
- output mode : setting a bit in ODR sets the corresponding out irq
(if this line is configured in output mode)
- pull-up, pull-down
- push-pull, open-drain
Difference with the real GPIOs :
- Alternate Function and Analog mode aren't implemented :
pins in AF/Analog behave like pins in input mode
- floating pins stay at their last value
- register IDR reset values differ from the real one :
values are coherent with the other registers reset values
and the fact that AF/Analog modes aren't implemented
- setting I/O output speed isn't supported
- locking port bits isn't supported
- ADC function isn't supported
- GPIOH has 16 pins instead of 2 pins
- writing to registers LCKR, AFRL, AFRH and ASCR is ineffective
Signed-off-by: Arnaud Minier <[email protected]>
Signed-off-by: Inès Varhol <[email protected]>
---
MAINTAINERS | 1 +
docs/system/arm/b-l475e-iot01a.rst | 2 +-
hw/gpio/Kconfig | 3 +
hw/gpio/meson.build | 1 +
hw/gpio/stm32l4x5_gpio.c | 537 +++++++++++++++++++++++++++++
hw/gpio/trace-events | 6 +
include/hw/gpio/stm32l4x5_gpio.h | 80 +++++
7 files changed, 629 insertions(+), 1 deletion(-)
create mode 100644 hw/gpio/stm32l4x5_gpio.c
create mode 100644 include/hw/gpio/stm32l4x5_gpio.h
+#define GPIO_MODER 0x00
+#define GPIO_OTYPER 0x04
+#define GPIO_OSPEEDR 0x08
+#define GPIO_PUPDR 0x0C
+#define GPIO_IDR 0x10
+#define GPIO_ODR 0x14
+#define GPIO_BSRR 0x18
+#define GPIO_LCKR 0x1C
+#define GPIO_AFRL 0x20
+#define GPIO_AFRH 0x24
+#define GPIO_BRR 0x28
+#define GPIO_ASCR 0x2C
+/*
+ * DISCONNECTED_PINS isn't actually a GPIO register.
+ * It exists to ensure that :
+ * - push-pull output pins can't be set externally
+ * - open-drain output pins can only be externally set to 0
+ *
+ * This field is accessed for test purposes.
+ */
+#define GPIO_DISCONNECTED_PINS 0x30
[*]
+static void stm32l4x5_gpio_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ Stm32l4x5GpioState *s = opaque;
+
+ uint32_t value = val64;
+ trace_stm32l4x5_gpio_write(addr, val64);
+
+ switch (addr) {
+ /* a tweak to enable the qtest checking disconnected pins */
+ case GPIO_DISCONNECTED_PINS:
+ disconnect_gpio_pins(s, value);
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ }
+}
+
+static uint64_t stm32l4x5_gpio_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ Stm32l4x5GpioState *s = opaque;
+
+ trace_stm32l4x5_gpio_read(addr);
+
+ switch (addr) {
+ /* a tweak to enable the qtest checking disconnected pins */
+ case GPIO_DISCONNECTED_PINS:
+ return s->disconnected_pins;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, addr);
+ return 0;
+ }
+}
+static void stm32l4x5_gpio_init(Object *obj)
+{
+ Stm32l4x5GpioState *s = STM32L4X5_GPIO(obj);
+
+ memory_region_init_io(&s->mmio, obj, &stm32l4x5_gpio_ops, s,
+ TYPE_STM32L4X5_GPIO, 0x400);
This "testing purpose" [*] register is accessible by the guest, so
this isn't a faithful emulation of the device, and could possibly
lead to unexpected guest behavior.
You can store testing fields in the device state, but don't expose
the as register. Expose them as QOM/QDev properties and access them
with the QOM QTest helpers.
Regards,
Phil.
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ qdev_init_gpio_out(DEVICE(obj), s->pin, GPIO_NUM_PINS);
+ qdev_init_gpio_in(DEVICE(obj), stm32l4x5_gpio_set, GPIO_NUM_PINS);
+
+ s->clk = qdev_init_clock_in(DEVICE(s), "clk", NULL, s, 0);
+}