qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] Add device STM32L4x5 SYSCFG
@ 2023-12-29 16:47 Inès Varhol
  2023-12-29 16:47 ` [PATCH v3 1/3] hw/misc: Implement " Inès Varhol
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Inès Varhol @ 2023-12-29 16:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, Inès Varhol,
	Paolo Bonzini, Alistair Francis, Arnaud Minier, qemu-arm,
	Peter Maydell, Thomas Huth

Changes from v2 to v3:
- updating the B-L475E-IOT01A machine's documentation file
- using `GPIO_NUM_PINS` instead of 16 in `stm32l4x5_syscfg_init`
- correcting the formatting of multiline indents
- renaming a trace function (`trace_stm32l4x5_syscfg_forward_exti`
instead of `trace_stm32l4x5_syscfg_pulse_exti`)

Changes from v1 to v2:
- explain in 3rd commit why SYSCFG input GPIOs aren't connected and add
a TODO comment in stm32l4x5_soc.c
- use macros `NUM_GPIOS` and `GPIO_NUM_PINS` in
`stm32l4x5_syscfg_set_irq`
- rename STM32L4XX to STM32L4X5, Stm32l4xx to Stm32l4x5
(the SYSCFG implementation is only valid for STM32L4x5 and STM32L4x6
but not for STM32L41xx/42xx/43xx/44xx)
- refactor `STM32L4x5SyscfgState` to `Stm32l4x5SyscfgState` to be
consistent with other peripherals

Based-on: <20231228161944.303768-1-ines.varhol@telecom-paris.fr>
([PATCH v5 0/3] Add device STM32L4x5 EXTI)

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>

Inès Varhol (3):
  hw/misc: Implement STM32L4x5 SYSCFG
  tests/qtest: Add STM32L4x5 SYSCFG QTest testcase
  hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC

 docs/system/arm/b-l475e-iot01a.rst  |   2 +-
 hw/arm/Kconfig                      |   1 +
 hw/arm/stm32l4x5_soc.c              |  23 +-
 hw/misc/Kconfig                     |   3 +
 hw/misc/meson.build                 |   1 +
 hw/misc/stm32l4x5_syscfg.c          | 265 ++++++++++++++++++
 hw/misc/trace-events                |   6 +
 include/hw/arm/stm32l4x5_soc.h      |   2 +
 include/hw/misc/stm32l4x5_syscfg.h  |  54 ++++
 tests/qtest/meson.build             |   3 +-
 tests/qtest/stm32l4x5_syscfg-test.c | 408 ++++++++++++++++++++++++++++
 11 files changed, 765 insertions(+), 3 deletions(-)
 create mode 100644 hw/misc/stm32l4x5_syscfg.c
 create mode 100644 include/hw/misc/stm32l4x5_syscfg.h
 create mode 100644 tests/qtest/stm32l4x5_syscfg-test.c

-- 
2.43.0



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/3] hw/misc: Implement STM32L4x5 SYSCFG
  2023-12-29 16:47 [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Inès Varhol
@ 2023-12-29 16:47 ` Inès Varhol
  2024-01-05  5:12   ` Alistair Francis
  2023-12-29 16:47 ` [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase Inès Varhol
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Inès Varhol @ 2023-12-29 16:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, Inès Varhol,
	Paolo Bonzini, Alistair Francis, Arnaud Minier, qemu-arm,
	Peter Maydell, Thomas Huth

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
---
 docs/system/arm/b-l475e-iot01a.rst |   2 +-
 hw/misc/Kconfig                    |   3 +
 hw/misc/meson.build                |   1 +
 hw/misc/stm32l4x5_syscfg.c         | 265 +++++++++++++++++++++++++++++
 hw/misc/trace-events               |   6 +
 include/hw/misc/stm32l4x5_syscfg.h |  54 ++++++
 6 files changed, 330 insertions(+), 1 deletion(-)
 create mode 100644 hw/misc/stm32l4x5_syscfg.c
 create mode 100644 include/hw/misc/stm32l4x5_syscfg.h

diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-iot01a.rst
index 72f256ace7..1a021b306a 100644
--- a/docs/system/arm/b-l475e-iot01a.rst
+++ b/docs/system/arm/b-l475e-iot01a.rst
@@ -16,6 +16,7 @@ Currently B-L475E-IOT01A machine's only supports the following devices:
 
 - Cortex-M4F based STM32L4x5 SoC
 - STM32L4x5 EXTI (Extended interrupts and events controller)
+- STM32L4x5 SYSCFG (System configuration controller)
 
 Missing devices
 """""""""""""""
@@ -24,7 +25,6 @@ The B-L475E-IOT01A does *not* support the following devices:
 
 - Reset and clock control (RCC)
 - Serial ports (UART)
-- System configuration controller (SYSCFG)
 - General-purpose I/Os (GPIO)
 - Analog to Digital Converter (ADC)
 - SPI controller
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 3efe3dc2cc..4fc6b29b43 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -90,6 +90,9 @@ config STM32F4XX_EXTI
 config STM32L4X5_EXTI
     bool
 
+config STM32L4X5_SYSCFG
+    bool
+
 config MIPS_ITU
     bool
 
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index 16db6e228d..2ca2ce4b62 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -111,6 +111,7 @@ system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.
 system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
 system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
 system_ss.add(when: 'CONFIG_STM32L4X5_EXTI', if_true: files('stm32l4x5_exti.c'))
+system_ss.add(when: 'CONFIG_STM32L4X5_SYSCFG', if_true: files('stm32l4x5_syscfg.c'))
 system_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c'))
 system_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c'))
 
diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
new file mode 100644
index 0000000000..36ac8956f9
--- /dev/null
+++ b/hw/misc/stm32l4x5_syscfg.c
@@ -0,0 +1,265 @@
+/*
+ * STM32L4x5 SYSCFG (System Configuration Controller)
+ *
+ * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This work is based on the stm32f4xx_syscfg by Alistair Francis.
+ * Original code is licensed under the MIT License:
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ */
+
+/*
+ * The reference used is the STMicroElectronics RM0351 Reference manual
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
+ * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32l4x5_syscfg.h"
+
+#define SYSCFG_MEMRMP 0x00
+#define SYSCFG_CFGR1 0x04
+#define SYSCFG_EXTICR1 0x08
+#define SYSCFG_EXTICR2 0x0C
+#define SYSCFG_EXTICR3 0x10
+#define SYSCFG_EXTICR4 0x14
+#define SYSCFG_SCSR 0x18
+#define SYSCFG_CFGR2 0x1C
+#define SYSCFG_SWPR 0x20
+#define SYSCFG_SKR 0x24
+#define SYSCFG_SWPR2 0x28
+
+/* 00000000_00000000_00000001_00000111 */
+#define ACTIVABLE_BITS_MEMRP 0x00000107
+
+/* 11111100_11111111_00000001_00000000 */
+#define ACTIVABLE_BITS_CFGR1 0xFCFF0100
+/* 00000000_00000000_00000000_00000001 */
+#define FIREWALL_DISABLE_CFGR1 0x00000001
+
+/* 00000000_00000000_11111111_11111111 */
+#define ACTIVABLE_BITS_EXTICR 0x0000FFFF
+
+/* 00000000_00000000_00000000_00000011 */
+/* #define ACTIVABLE_BITS_SCSR 0x00000003 */
+
+/* 00000000_00000000_00000000_00001111 */
+#define ECC_LOCK_CFGR2 0x0000000F
+/* 00000000_00000000_00000001_00000000 */
+#define SRAM2_PARITY_ERROR_FLAG_CFGR2 0x00000100
+
+/* 00000000_00000000_00000000_11111111 */
+#define ACTIVABLE_BITS_SKR 0x000000FF
+
+static void stm32l4x5_syscfg_hold_reset(Object *obj)
+{
+    Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
+
+    s->memrmp = 0x00000000;
+    s->cfgr1 = 0x7C000001;
+    s->exticr[0] = 0x00000000;
+    s->exticr[1] = 0x00000000;
+    s->exticr[2] = 0x00000000;
+    s->exticr[3] = 0x00000000;
+    s->scsr = 0x00000000;
+    s->cfgr2 = 0x00000000;
+    s->swpr = 0x00000000;
+    s->skr = 0x00000000;
+    s->swpr2 = 0x00000000;
+}
+
+static void stm32l4x5_syscfg_set_irq(void *opaque, int irq, int level)
+{
+    Stm32l4x5SyscfgState *s = opaque;
+    uint8_t gpio = irq / GPIO_NUM_PINS;
+    g_assert(gpio < NUM_GPIOS);
+
+    int line = irq % GPIO_NUM_PINS;
+    int exticr_reg = line / 4;
+    int startbit = (irq % 4) * 4;
+
+    trace_stm32l4x5_syscfg_set_irq(gpio, line, level);
+
+    if (extract32(s->exticr[exticr_reg], startbit, 4) == gpio) {
+        trace_stm32l4x5_syscfg_forward_exti(line);
+        qemu_set_irq(s->gpio_out[line], level);
+   }
+}
+
+static uint64_t stm32l4x5_syscfg_read(void *opaque, hwaddr addr,
+                                      unsigned int size)
+{
+    Stm32l4x5SyscfgState *s = opaque;
+
+    trace_stm32l4x5_syscfg_read(addr);
+
+    switch (addr) {
+    case SYSCFG_MEMRMP:
+        return s->memrmp;
+    case SYSCFG_CFGR1:
+        return s->cfgr1;
+    case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
+        return s->exticr[(addr - SYSCFG_EXTICR1) / 4];
+    case SYSCFG_SCSR:
+        return s->scsr;
+    case SYSCFG_CFGR2:
+        return s->cfgr2;
+    case SYSCFG_SWPR:
+        return s->swpr;
+    case SYSCFG_SKR:
+        return s->skr;
+    case SYSCFG_SWPR2:
+        return s->swpr2;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        return 0;
+    }
+}
+static void stm32l4x5_syscfg_write(void *opaque, hwaddr addr,
+                                   uint64_t val64, unsigned int size)
+{
+    Stm32l4x5SyscfgState *s = opaque;
+    uint32_t value = val64;
+
+    trace_stm32l4x5_syscfg_write(addr, value);
+
+    switch (addr) {
+    case SYSCFG_MEMRMP:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Changing the memory mapping isn't supported\n",
+                      __func__);
+        s->memrmp = value & ACTIVABLE_BITS_MEMRP;
+        return;
+    case SYSCFG_CFGR1:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Functions in CFGRx aren't supported\n",
+                      __func__);
+        /* bit 0 (firewall dis.) is cleared by software, set only by reset. */
+        s->cfgr1 = (s->cfgr1 & value & FIREWALL_DISABLE_CFGR1) |
+                   (value & ACTIVABLE_BITS_CFGR1);
+        return;
+    case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
+        s->exticr[(addr - SYSCFG_EXTICR1) / 4] =
+                (value & ACTIVABLE_BITS_EXTICR);
+        return;
+    case SYSCFG_SCSR:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Erasing SRAM2 isn't supported\n",
+                      __func__);
+        /*
+         * only non reserved bits are :
+         * bit 0 (write-protected by a passkey), bit 1 (meant to be read)
+         * so it serves no purpose yet to add :
+         * s->scsr = value & 0x3;
+         */
+        return;
+    case SYSCFG_CFGR2:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Functions in CFGRx aren't supported\n",
+                      __func__);
+        /* bit 8 (SRAM2 PEF) is cleared by software by writing a '1'.*/
+        /* bits[3:0] (ECC Lock) are set by software, cleared only by reset.*/
+        s->cfgr2 = (s->cfgr2 | (value & ECC_LOCK_CFGR2)) &
+                   ~(value & SRAM2_PARITY_ERROR_FLAG_CFGR2);
+        return;
+    case SYSCFG_SWPR:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Write protecting SRAM2 isn't supported\n",
+                      __func__);
+        /* These bits are set by software and cleared only by reset.*/
+        s->swpr |= value;
+        return;
+    case SYSCFG_SKR:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Erasing SRAM2 isn't supported\n",
+                      __func__);
+        s->skr = value & ACTIVABLE_BITS_SKR;
+        return;
+    case SYSCFG_SWPR2:
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: Write protecting SRAM2 isn't supported\n",
+                      __func__);
+        /* These bits are set by software and cleared only by reset.*/
+        s->swpr2 |= value;
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps stm32l4x5_syscfg_ops = {
+    .read = stm32l4x5_syscfg_read,
+    .write = stm32l4x5_syscfg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+    .impl.unaligned = false,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .valid.unaligned = false,
+};
+
+static void stm32l4x5_syscfg_init(Object *obj)
+{
+    Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
+
+    memory_region_init_io(&s->mmio, obj, &stm32l4x5_syscfg_ops, s,
+                          TYPE_STM32L4X5_SYSCFG, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+    qdev_init_gpio_in(DEVICE(obj), stm32l4x5_syscfg_set_irq,
+                      GPIO_NUM_PINS * NUM_GPIOS);
+    qdev_init_gpio_out(DEVICE(obj), s->gpio_out, GPIO_NUM_PINS);
+}
+
+static const VMStateDescription vmstate_stm32l4x5_syscfg = {
+    .name = TYPE_STM32L4X5_SYSCFG,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(memrmp, Stm32l4x5SyscfgState),
+        VMSTATE_UINT32(cfgr1, Stm32l4x5SyscfgState),
+        VMSTATE_UINT32_ARRAY(exticr, Stm32l4x5SyscfgState,
+                             SYSCFG_NUM_EXTICR),
+        VMSTATE_UINT32(scsr, Stm32l4x5SyscfgState),
+        VMSTATE_UINT32(cfgr2, Stm32l4x5SyscfgState),
+        VMSTATE_UINT32(swpr, Stm32l4x5SyscfgState),
+        VMSTATE_UINT32(skr, Stm32l4x5SyscfgState),
+        VMSTATE_UINT32(swpr2, Stm32l4x5SyscfgState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void stm32l4x5_syscfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+    dc->vmsd = &vmstate_stm32l4x5_syscfg;
+    rc->phases.hold = stm32l4x5_syscfg_hold_reset;
+}
+
+static const TypeInfo stm32l4x5_syscfg_info[] = {
+    {
+        .name          = TYPE_STM32L4X5_SYSCFG,
+        .parent        = TYPE_SYS_BUS_DEVICE,
+        .instance_size = sizeof(Stm32l4x5SyscfgState),
+        .instance_init = stm32l4x5_syscfg_init,
+        .class_init    = stm32l4x5_syscfg_class_init,
+    }
+};
+
+DEFINE_TYPES(stm32l4x5_syscfg_info)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 2f01c62c0e..60d0a14e74 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -163,6 +163,12 @@ stm32f4xx_exti_set_irq(int irq, int level) "Set EXTI: %d to %d"
 stm32f4xx_exti_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
 stm32f4xx_exti_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
 
+# stm32l4x5_syscfg.c
+stm32l4x5_syscfg_set_irq(int gpio, int line, int level) "irq from GPIO: %d, line: %d, level: %d"
+stm32l4x5_syscfg_forward_exti(int irq) "irq %d forwarded to EXTI"
+stm32l4x5_syscfg_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
+stm32l4x5_syscfg_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
+
 # stm32l4x5_exti.c
 stm32l4x5_exti_set_irq(int irq, int level) "Set EXTI: %d to %d"
 stm32l4x5_exti_read(uint64_t addr, uint64_t data) "reg read: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
diff --git a/include/hw/misc/stm32l4x5_syscfg.h b/include/hw/misc/stm32l4x5_syscfg.h
new file mode 100644
index 0000000000..76bdcf5189
--- /dev/null
+++ b/include/hw/misc/stm32l4x5_syscfg.h
@@ -0,0 +1,54 @@
+/*
+ * STM32L4x5 SYSCFG (System Configuration Controller)
+ *
+ * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This work is based on the stm32f4xx_syscfg by Alistair Francis.
+ * Original code is licensed under the MIT License:
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ */
+
+/*
+ * The reference used is the STMicroElectronics RM0351 Reference manual
+ * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
+ * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
+ */
+
+#ifndef HW_STM32L4X5_SYSCFG_H
+#define HW_STM32L4X5_SYSCFG_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_STM32L4X5_SYSCFG "stm32l4x5-syscfg"
+OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5SyscfgState, STM32L4X5_SYSCFG)
+
+#define NUM_GPIOS 8
+#define GPIO_NUM_PINS 16
+#define SYSCFG_NUM_EXTICR 4
+
+struct Stm32l4x5SyscfgState {
+    SysBusDevice parent_obj;
+
+    MemoryRegion mmio;
+
+    uint32_t memrmp;
+    uint32_t cfgr1;
+    uint32_t exticr[SYSCFG_NUM_EXTICR];
+    uint32_t scsr;
+    uint32_t cfgr2;
+    uint32_t swpr;
+    uint32_t skr;
+    uint32_t swpr2;
+
+    qemu_irq gpio_out[16];
+};
+
+#endif
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase
  2023-12-29 16:47 [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Inès Varhol
  2023-12-29 16:47 ` [PATCH v3 1/3] hw/misc: Implement " Inès Varhol
@ 2023-12-29 16:47 ` Inès Varhol
  2024-01-04 13:23   ` Philippe Mathieu-Daudé
  2024-01-04 13:37   ` Philippe Mathieu-Daudé
  2023-12-29 16:47 ` [PATCH v3 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC Inès Varhol
  2024-01-04 13:47 ` [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Philippe Mathieu-Daudé
  3 siblings, 2 replies; 9+ messages in thread
From: Inès Varhol @ 2023-12-29 16:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, Inès Varhol,
	Paolo Bonzini, Alistair Francis, Arnaud Minier, qemu-arm,
	Peter Maydell, Thomas Huth

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
---
 tests/qtest/meson.build             |   3 +-
 tests/qtest/stm32l4x5_syscfg-test.c | 408 ++++++++++++++++++++++++++++
 2 files changed, 410 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/stm32l4x5_syscfg-test.c

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index d5126f4d86..a2213d60b3 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -196,7 +196,8 @@ qtests_aspeed = \
    'aspeed_gpio-test']
 
 qtests_stm32l4x5 = \
-  ['stm32l4x5_exti-test']
+  ['stm32l4x5_exti-test',
+   'stm32l4x5_syscfg-test']
 
 qtests_arm = \
   (config_all_devices.has_key('CONFIG_MPS2') ? ['sse-timer-test'] : []) + \
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c b/tests/qtest/stm32l4x5_syscfg-test.c
new file mode 100644
index 0000000000..3edd13b222
--- /dev/null
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -0,0 +1,408 @@
+/*
+ * QTest testcase for STM32L4x5_SYSCFG
+ *
+ * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
+ * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest-single.h"
+
+#define SYSCFG_BASE_ADDR 0x40010000
+#define SYSCFG_MEMRMP 0x00
+#define SYSCFG_CFGR1 0x04
+#define SYSCFG_EXTICR1 0x08
+#define SYSCFG_EXTICR2 0x0C
+#define SYSCFG_EXTICR3 0x10
+#define SYSCFG_EXTICR4 0x14
+#define SYSCFG_SCSR 0x18
+#define SYSCFG_CFGR2 0x1C
+#define SYSCFG_SWPR 0x20
+#define SYSCFG_SKR 0x24
+#define SYSCFG_SWPR2 0x28
+#define INVALID_ADDR 0x2C
+
+#define EXTI_BASE_ADDR 0x40010400
+#define EXTI_IMR1 0x00
+#define EXTI_RTSR1 0x08
+#define EXTI_FTSR1 0x0C
+
+static void syscfg_writel(unsigned int offset, uint32_t value)
+{
+    writel(SYSCFG_BASE_ADDR + offset, value);
+}
+
+static uint32_t syscfg_readl(unsigned int offset)
+{
+    return readl(SYSCFG_BASE_ADDR + offset);
+}
+
+static void exti_writel(unsigned int offset, uint32_t value)
+{
+    writel(EXTI_BASE_ADDR + offset, value);
+}
+
+static void system_reset(void)
+{
+    QDict *response;
+    response = qtest_qmp(global_qtest, "{'execute': 'system_reset'}");
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+}
+
+static void test_reset(void)
+{
+    /*
+     * Test that registers are initialized at the correct values
+     */
+    const uint32_t memrmp = syscfg_readl(SYSCFG_MEMRMP);
+    g_assert_cmpuint(memrmp, ==, 0x00000000);
+
+    const uint32_t cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+    g_assert_cmpuint(cfgr1, ==, 0x7C000001);
+
+    const uint32_t exticr1 = syscfg_readl(SYSCFG_EXTICR1);
+    g_assert_cmpuint(exticr1, ==, 0x00000000);
+
+    const uint32_t exticr2 = syscfg_readl(SYSCFG_EXTICR2);
+    g_assert_cmpuint(exticr2, ==, 0x00000000);
+
+    const uint32_t exticr3 = syscfg_readl(SYSCFG_EXTICR3);
+    g_assert_cmpuint(exticr3, ==, 0x00000000);
+
+    const uint32_t exticr4 = syscfg_readl(SYSCFG_EXTICR4);
+    g_assert_cmpuint(exticr4, ==, 0x00000000);
+
+    const uint32_t scsr = syscfg_readl(SYSCFG_SCSR);
+    g_assert_cmpuint(scsr, ==, 0x00000000);
+
+    const uint32_t cfgr2 = syscfg_readl(SYSCFG_CFGR2);
+    g_assert_cmpuint(cfgr2, ==, 0x00000000);
+
+    const uint32_t swpr = syscfg_readl(SYSCFG_SWPR);
+    g_assert_cmpuint(swpr, ==, 0x00000000);
+
+    const uint32_t skr = syscfg_readl(SYSCFG_SKR);
+    g_assert_cmpuint(skr, ==, 0x00000000);
+
+    const uint32_t swpr2 = syscfg_readl(SYSCFG_SWPR2);
+    g_assert_cmpuint(swpr2, ==, 0x00000000);
+}
+
+static void test_reserved_bits(void)
+{
+    /*
+     * Test that reserved bits stay at reset value
+     * (which is 0 for all of them) by writing '1'
+     * in all reserved bits (keeping reset value for
+     * other bits) and checking that the
+     * register is still at reset value
+     */
+    syscfg_writel(SYSCFG_MEMRMP, 0xFFFFFEF8);
+    const uint32_t memrmp = syscfg_readl(SYSCFG_MEMRMP);
+    g_assert_cmpuint(memrmp, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_CFGR1, 0x7F00FEFF);
+    const uint32_t cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+    g_assert_cmpuint(cfgr1, ==, 0x7C000001);
+
+    syscfg_writel(SYSCFG_EXTICR1, 0xFFFF0000);
+    const uint32_t exticr1 = syscfg_readl(SYSCFG_EXTICR1);
+    g_assert_cmpuint(exticr1, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_EXTICR2, 0xFFFF0000);
+    const uint32_t exticr2 = syscfg_readl(SYSCFG_EXTICR2);
+    g_assert_cmpuint(exticr2, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_EXTICR3, 0xFFFF0000);
+    const uint32_t exticr3 = syscfg_readl(SYSCFG_EXTICR3);
+    g_assert_cmpuint(exticr3, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_EXTICR4, 0xFFFF0000);
+    const uint32_t exticr4 = syscfg_readl(SYSCFG_EXTICR4);
+    g_assert_cmpuint(exticr4, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_SKR, 0xFFFFFF00);
+    const uint32_t skr = syscfg_readl(SYSCFG_SKR);
+    g_assert_cmpuint(skr, ==, 0x00000000);
+}
+
+static void test_set_and_clear(void)
+{
+    /*
+     * Test that regular bits can be set and cleared
+     */
+    syscfg_writel(SYSCFG_MEMRMP, 0x00000107);
+    uint32_t memrmp = syscfg_readl(SYSCFG_MEMRMP);
+    g_assert_cmpuint(memrmp, ==, 0x00000107);
+    syscfg_writel(SYSCFG_MEMRMP, 0x00000000);
+    memrmp = syscfg_readl(SYSCFG_MEMRMP);
+    g_assert_cmpuint(memrmp, ==, 0x00000000);
+
+    /* cfgr1 bit 0 is clear only so we keep it set */
+    syscfg_writel(SYSCFG_CFGR1, 0xFCFF0101);
+    uint32_t cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+    g_assert_cmpuint(cfgr1, ==, 0xFCFF0101);
+    syscfg_writel(SYSCFG_CFGR1, 0x00000001);
+    cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+    g_assert_cmpuint(cfgr1, ==, 0x00000001);
+
+    syscfg_writel(SYSCFG_EXTICR1, 0x0000FFFF);
+    uint32_t exticr1 = syscfg_readl(SYSCFG_EXTICR1);
+    g_assert_cmpuint(exticr1, ==, 0x0000FFFF);
+    syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
+    exticr1 = syscfg_readl(SYSCFG_EXTICR1);
+    g_assert_cmpuint(exticr1, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_EXTICR2, 0x0000FFFF);
+    uint32_t exticr2 = syscfg_readl(SYSCFG_EXTICR2);
+    g_assert_cmpuint(exticr2, ==, 0x0000FFFF);
+    syscfg_writel(SYSCFG_EXTICR2, 0x00000000);
+    exticr2 = syscfg_readl(SYSCFG_EXTICR2);
+    g_assert_cmpuint(exticr2, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_EXTICR3, 0x0000FFFF);
+    uint32_t exticr3 = syscfg_readl(SYSCFG_EXTICR3);
+    g_assert_cmpuint(exticr3, ==, 0x0000FFFF);
+    syscfg_writel(SYSCFG_EXTICR3, 0x00000000);
+    exticr3 = syscfg_readl(SYSCFG_EXTICR3);
+    g_assert_cmpuint(exticr3, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_EXTICR4, 0x0000FFFF);
+    uint32_t exticr4 = syscfg_readl(SYSCFG_EXTICR4);
+    g_assert_cmpuint(exticr4, ==, 0x0000FFFF);
+    syscfg_writel(SYSCFG_EXTICR4, 0x00000000);
+    exticr4 = syscfg_readl(SYSCFG_EXTICR4);
+    g_assert_cmpuint(exticr4, ==, 0x00000000);
+
+    syscfg_writel(SYSCFG_SKR, 0x000000FF);
+    uint32_t skr = syscfg_readl(SYSCFG_SKR);
+    g_assert_cmpuint(skr, ==, 0x000000FF);
+    syscfg_writel(SYSCFG_SKR, 0x00000000);
+    skr = syscfg_readl(SYSCFG_SKR);
+    g_assert_cmpuint(skr, ==, 0x00000000);
+}
+
+static void test_clear_by_writing_1(void)
+{
+    /*
+     * Test that writing '1' doesn't set the bit
+     */
+    syscfg_writel(SYSCFG_CFGR2, 0x00000100);
+    const uint32_t cfgr2 = syscfg_readl(SYSCFG_CFGR2);
+    g_assert_cmpuint(cfgr2, ==, 0x00000000);
+}
+
+static void test_set_only_bits(void)
+{
+    /*
+     * Test that set only bits stay can't be cleared
+     */
+    syscfg_writel(SYSCFG_CFGR2, 0x0000000F);
+    syscfg_writel(SYSCFG_CFGR2, 0x00000000);
+    const uint32_t exticr3 = syscfg_readl(SYSCFG_CFGR2);
+    g_assert_cmpuint(exticr3, ==, 0x0000000F);
+
+    syscfg_writel(SYSCFG_SWPR, 0xFFFFFFFF);
+    syscfg_writel(SYSCFG_SWPR, 0x00000000);
+    const uint32_t swpr = syscfg_readl(SYSCFG_SWPR);
+    g_assert_cmpuint(swpr, ==, 0xFFFFFFFF);
+
+    syscfg_writel(SYSCFG_SWPR2, 0xFFFFFFFF);
+    syscfg_writel(SYSCFG_SWPR2, 0x00000000);
+    const uint32_t swpr2 = syscfg_readl(SYSCFG_SWPR2);
+    g_assert_cmpuint(swpr2, ==, 0xFFFFFFFF);
+
+    system_reset();
+}
+
+static void test_clear_only_bits(void)
+{
+    /*
+     * Test that clear only bits stay can't be set
+     */
+    syscfg_writel(SYSCFG_CFGR1, 0x00000000);
+    syscfg_writel(SYSCFG_CFGR1, 0x00000001);
+    const uint32_t cfgr1 = syscfg_readl(SYSCFG_CFGR1);
+    g_assert_cmpuint(cfgr1, ==, 0x00000000);
+
+    system_reset();
+}
+
+static void test_interrupt(void)
+{
+    /*
+     * Test that GPIO rising lines result in an irq
+     * with the right configuration
+     */
+    qtest_irq_intercept_in(global_qtest, "/machine/unattached/device[0]/exti");
+    /* Enable interrupt on rising edge of GPIO PA[0] */
+    exti_writel(EXTI_IMR1, 0x00000001);
+    exti_writel(EXTI_RTSR1, 0x00000001);
+
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 1);
+
+    g_assert_true(get_irq(0));
+
+    /* Enable interrupt on rising edge of GPIO PA[15] */
+    exti_writel(EXTI_IMR1, 0x00008000);
+    exti_writel(EXTI_RTSR1, 0x00008000);
+
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 15, 1);
+
+    g_assert_true(get_irq(15));
+
+    /* Enable interrupt on rising edge of GPIO PB[1] */
+    syscfg_writel(SYSCFG_EXTICR1, 0x00000010);
+    exti_writel(EXTI_IMR1, 0x00000002);
+    exti_writel(EXTI_RTSR1, 0x00000002);
+
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 17, 1);
+
+    g_assert_true(get_irq(1));
+
+    /* Clean the test */
+    syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 0);
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 15, 0);
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 17, 0);
+}
+
+static void test_irq_pin_multiplexer(void)
+{
+    /*
+     * Test that syscfg irq sets the right exti irq
+     */
+
+    qtest_irq_intercept_in(global_qtest, "/machine/unattached/device[0]/exti");
+
+    /* Enable interrupt on rising edge of GPIO PA[0] */
+    exti_writel(EXTI_IMR1, 0x00000001);
+    exti_writel(EXTI_RTSR1, 0x00000001);
+
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 1);
+
+    /* Check that irq 0 was set and irq 15 wasn't */
+    g_assert_true(get_irq(0));
+    g_assert_false(get_irq(15));
+
+    /* Clean the test */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 0);
+
+    /* Enable interrupt on rising edge of GPIO PA[15] */
+    exti_writel(EXTI_IMR1, 0x00008000);
+    exti_writel(EXTI_RTSR1, 0x00008000);
+
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 15, 1);
+
+    /* Check that irq 15 was set and irq 0 wasn't */
+    g_assert_true(get_irq(15));
+    g_assert_false(get_irq(0));
+
+    /* Clean the test */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 15, 0);
+}
+
+static void test_irq_gpio_multiplexer(void)
+{
+    /*
+     * Test that an irq is generated only by the right GPIO
+     */
+
+    qtest_irq_intercept_in(global_qtest, "/machine/unattached/device[0]/exti");
+
+    /* Enable interrupt on rising edge of GPIO PA[0] */
+    exti_writel(EXTI_IMR1, 0x00000001);
+    exti_writel(EXTI_RTSR1, 0x00000001);
+
+    /* Check that setting rising pin GPIOA[0] generates an irq */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 1);
+
+    g_assert_true(get_irq(0));
+
+    /* Clean the test */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 0);
+
+    /* Check that setting rising pin GPIOB[0] doesn't generate an irq */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 16, 1);
+
+    g_assert_false(get_irq(0));
+
+    /* Clean the test */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 16, 0);
+
+    /* Enable interrupt on rising edge of GPIO PB[0] */
+    exti_writel(EXTI_IMR1, 0x00000001);
+    exti_writel(EXTI_RTSR1, 0x00000001);
+    syscfg_writel(SYSCFG_EXTICR1, 0x00000001);
+
+    /* Check that setting rising pin GPIOA[0] doesn't generate an irq */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 1);
+
+    g_assert_false(get_irq(0));
+
+    /* Clean the test */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 0, 0);
+
+    /* Check that setting rising pin GPIOB[0] generates an irq */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 16, 1);
+
+    g_assert_true(get_irq(0));
+
+    /* Clean the test */
+    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
+                     NULL, 16, 0);
+    syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    g_test_set_nonfatal_assertions();
+
+    qtest_add_func("stm32l4x5/syscfg/test_reset", test_reset);
+    qtest_add_func("stm32l4x5/syscfg/test_reserved_bits",
+                   test_reserved_bits);
+    qtest_add_func("stm32l4x5/syscfg/test_set_and_clear",
+                   test_set_and_clear);
+    qtest_add_func("stm32l4x5/syscfg/test_clear_by_writing_1",
+                   test_clear_by_writing_1);
+    qtest_add_func("stm32l4x5/syscfg/test_set_only_bits",
+                   test_set_only_bits);
+    qtest_add_func("stm32l4x5/syscfg/test_clear_only_bits",
+                   test_clear_only_bits);
+    qtest_add_func("stm32l4x5/syscfg/test_interrupt",
+                   test_interrupt);
+    qtest_add_func("stm32l4x5/syscfg/test_irq_pin_multiplexer",
+                   test_irq_pin_multiplexer);
+    qtest_add_func("stm32l4x5/syscfg/test_irq_gpio_multiplexer",
+                   test_irq_gpio_multiplexer);
+
+    qtest_start("-machine b-l475e-iot01a");
+    ret = g_test_run();
+    qtest_end();
+
+    return ret;
+}
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC
  2023-12-29 16:47 [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Inès Varhol
  2023-12-29 16:47 ` [PATCH v3 1/3] hw/misc: Implement " Inès Varhol
  2023-12-29 16:47 ` [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase Inès Varhol
@ 2023-12-29 16:47 ` Inès Varhol
  2024-01-04 13:20   ` Philippe Mathieu-Daudé
  2024-01-04 13:47 ` [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Philippe Mathieu-Daudé
  3 siblings, 1 reply; 9+ messages in thread
From: Inès Varhol @ 2023-12-29 16:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Laurent Vivier, Philippe Mathieu-Daudé, Inès Varhol,
	Paolo Bonzini, Alistair Francis, Arnaud Minier, qemu-arm,
	Peter Maydell, Thomas Huth

The SYSCFG input GPIOs aren't connected yet. When the STM32L4x5 GPIO
device will be implemented, its output GPIOs will be connected to the
SYSCFG input GPIOs.

Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
---
 hw/arm/Kconfig                 |  1 +
 hw/arm/stm32l4x5_soc.c         | 23 ++++++++++++++++++++++-
 include/hw/arm/stm32l4x5_soc.h |  2 ++
 3 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 9c9d5bb541..e7c9470d59 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -458,6 +458,7 @@ config STM32L4X5_SOC
     bool
     select ARM_V7M
     select OR_IRQ
+    select STM32L4X5_SYSCFG
     select STM32L4X5_EXTI
 
 config XLNX_ZYNQMP_ARM
diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
index 08b8a4c2ed..0581f4ce30 100644
--- a/hw/arm/stm32l4x5_soc.c
+++ b/hw/arm/stm32l4x5_soc.c
@@ -37,6 +37,7 @@
 #define SRAM2_SIZE (32 * KiB)
 
 #define EXTI_ADDR 0x40010400
+#define SYSCFG_ADDR 0x40010000
 
 #define NUM_EXTI_IRQ 40
 /* Match exti line connections with their CPU IRQ number */
@@ -81,6 +82,8 @@ static void stm32l4x5_soc_initfn(Object *obj)
 
     object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI);
 
+    object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
+
     s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
     s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
 }
@@ -158,6 +161,20 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
         return;
     }
 
+    /* System configuration controller */
+    dev = DEVICE(&s->syscfg);
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) {
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, SYSCFG_ADDR);
+    /*
+     * TODO: when the GPIO device is implemented, connect it
+     * to SYCFG using `qdev_connect_gpio_out`, NUM_GPIOS and
+     * GPIO_NUM_PINS.
+     */
+
+    /* EXTI device */
     dev = DEVICE(&s->exti);
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), errp)) {
         return;
@@ -168,6 +185,11 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
         sysbus_connect_irq(busdev, i, qdev_get_gpio_in(armv7m, exti_irq[i]));
     }
 
+    for (i = 0; i < 16; i++) {
+        qdev_connect_gpio_out(DEVICE(&s->syscfg), i,
+                              qdev_get_gpio_in(dev, i));
+    }
+
     /* APB1 BUS */
     create_unimplemented_device("TIM2",      0x40000000, 0x400);
     create_unimplemented_device("TIM3",      0x40000400, 0x400);
@@ -205,7 +227,6 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
     /* RESERVED:    0x40009800, 0x6800 */
 
     /* APB2 BUS */
-    create_unimplemented_device("SYSCFG",    0x40010000, 0x30);
     create_unimplemented_device("VREFBUF",   0x40010030, 0x1D0);
     create_unimplemented_device("COMP",      0x40010200, 0x200);
     /* RESERVED:    0x40010800, 0x1400 */
diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h
index 6cba566a31..04b1151eed 100644
--- a/include/hw/arm/stm32l4x5_soc.h
+++ b/include/hw/arm/stm32l4x5_soc.h
@@ -28,6 +28,7 @@
 #include "qemu/units.h"
 #include "hw/qdev-core.h"
 #include "hw/arm/armv7m.h"
+#include "hw/misc/stm32l4x5_syscfg.h"
 #include "hw/misc/stm32l4x5_exti.h"
 #include "qom/object.h"
 
@@ -43,6 +44,7 @@ struct Stm32l4x5SocState {
     ARMv7MState armv7m;
 
     Stm32l4x5ExtiState exti;
+    Stm32l4x5SyscfgState syscfg;
 
     MemoryRegion sram1;
     MemoryRegion sram2;
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC
  2023-12-29 16:47 ` [PATCH v3 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC Inès Varhol
@ 2024-01-04 13:20   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-01-04 13:20 UTC (permalink / raw)
  To: Inès Varhol, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Alistair Francis, Arnaud Minier,
	qemu-arm, Peter Maydell, Thomas Huth

On 29/12/23 17:47, Inès Varhol wrote:
> The SYSCFG input GPIOs aren't connected yet. When the STM32L4x5 GPIO
> device will be implemented, its output GPIOs will be connected to the
> SYSCFG input GPIOs.
> 
> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
> ---
>   hw/arm/Kconfig                 |  1 +
>   hw/arm/stm32l4x5_soc.c         | 23 ++++++++++++++++++++++-
>   include/hw/arm/stm32l4x5_soc.h |  2 ++
>   3 files changed, 25 insertions(+), 1 deletion(-)


> diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c
> index 08b8a4c2ed..0581f4ce30 100644
> --- a/hw/arm/stm32l4x5_soc.c
> +++ b/hw/arm/stm32l4x5_soc.c
> @@ -37,6 +37,7 @@
>   #define SRAM2_SIZE (32 * KiB)
>   
>   #define EXTI_ADDR 0x40010400
> +#define SYSCFG_ADDR 0x40010000
>   
>   #define NUM_EXTI_IRQ 40
>   /* Match exti line connections with their CPU IRQ number */
> @@ -81,6 +82,8 @@ static void stm32l4x5_soc_initfn(Object *obj)
>   
>       object_initialize_child(obj, "exti", &s->exti, TYPE_STM32L4X5_EXTI);
>   
> +    object_initialize_child(obj, "syscfg", &s->syscfg, TYPE_STM32L4X5_SYSCFG);
> +
>       s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
>       s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
>   }
> @@ -158,6 +161,20 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
>           return;
>       }
>   
> +    /* System configuration controller */
> +    dev = DEVICE(&s->syscfg);

No need for 'dev', use 'busdev' directly.

> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->syscfg), errp)) {
> +        return;
> +    }
> +    busdev = SYS_BUS_DEVICE(dev);
> +    sysbus_mmio_map(busdev, 0, SYSCFG_ADDR);
> +    /*
> +     * TODO: when the GPIO device is implemented, connect it
> +     * to SYCFG using `qdev_connect_gpio_out`, NUM_GPIOS and
> +     * GPIO_NUM_PINS.
> +     */
> +
> +    /* EXTI device */
>       dev = DEVICE(&s->exti);
>       if (!sysbus_realize(SYS_BUS_DEVICE(&s->exti), errp)) {
>           return;
> @@ -168,6 +185,11 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp)
>           sysbus_connect_irq(busdev, i, qdev_get_gpio_in(armv7m, exti_irq[i]));
>       }
>   
> +    for (i = 0; i < 16; i++) {

You can reduce 'i' scope.

> +        qdev_connect_gpio_out(DEVICE(&s->syscfg), i,
> +                              qdev_get_gpio_in(dev, i));
> +    }

Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Preferably using 'busdev':
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase
  2023-12-29 16:47 ` [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase Inès Varhol
@ 2024-01-04 13:23   ` Philippe Mathieu-Daudé
  2024-01-04 13:37   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-01-04 13:23 UTC (permalink / raw)
  To: Inès Varhol, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Alistair Francis, Arnaud Minier,
	qemu-arm, Peter Maydell, Thomas Huth

On 29/12/23 17:47, Inès Varhol wrote:
> Acked-by: Alistair Francis <alistair.francis@wdc.com>
> 
> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
> ---
>   tests/qtest/meson.build             |   3 +-
>   tests/qtest/stm32l4x5_syscfg-test.c | 408 ++++++++++++++++++++++++++++
>   2 files changed, 410 insertions(+), 1 deletion(-)
>   create mode 100644 tests/qtest/stm32l4x5_syscfg-test.c

Sitting on this commit, the test fails (because the tested
device is added in the following patch):

▶ 19/36 /arm/stm32l4x5/syscfg/test_reset 
   FAIL
▶ 19/36 /arm/stm32l4x5/syscfg/test_reserved_bits 
   FAIL
▶ 19/36 /arm/stm32l4x5/syscfg/test_set_and_clear 
   FAIL
▶ 19/36 /arm/stm32l4x5/syscfg/test_set_only_bits 
   FAIL
▶ 19/36 /arm/stm32l4x5/syscfg/test_interrupt 
   FAIL
▶ 19/36 /arm/stm32l4x5/syscfg/test_irq_pin_multiplexer 
   FAIL
▶ 19/36 /arm/stm32l4x5/syscfg/test_irq_gpio_multiplexer 
   FAIL
Listing only the last 100 lines from a long log.
**
ERROR:../../tests/qtest/stm32l4x5_syscfg-test.c:140:test_set_and_clear: 
code should not be reached
**
ERROR:../../tests/qtest/stm32l4x5_syscfg-test.c:148:test_set_and_clear: 
assertion failed (cfgr1 == 0xFCFF0101): (0 == 4244570369)
**
ERROR:../../tests/qtest/stm32l4x5_syscfg-test.c:148:test_set_and_clear: 
code should not be reached
**
ERROR:../../tests/qtest/stm32l4x5_syscfg-test.c:151:test_set_and_clear: 
assertion failed (cfgr1 == 0x00000001): (0 == 1)
**
ERROR:../../tests/qtest/stm32l4x5_syscfg-test.c:151:test_set_and_clear: 
code should not be reached
**
ERROR:../../tests/qtest/stm32l4x5_syscfg-test.c:155:test_set_and_clear: 
assertion failed (exticr1 == 0x0000FFFF): (0 == 65535)
**
...

To avoid breaking automatic bisections, first add the device, then the
test (invert patches 2 <-> 3).

Regards,

Phil.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase
  2023-12-29 16:47 ` [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase Inès Varhol
  2024-01-04 13:23   ` Philippe Mathieu-Daudé
@ 2024-01-04 13:37   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-01-04 13:37 UTC (permalink / raw)
  To: Inès Varhol, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Alistair Francis, Arnaud Minier,
	qemu-arm, Peter Maydell, Thomas Huth

On 29/12/23 17:47, Inès Varhol wrote:
> Acked-by: Alistair Francis <alistair.francis@wdc.com>
> 
> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
> ---
>   tests/qtest/meson.build             |   3 +-
>   tests/qtest/stm32l4x5_syscfg-test.c | 408 ++++++++++++++++++++++++++++
>   2 files changed, 410 insertions(+), 1 deletion(-)
>   create mode 100644 tests/qtest/stm32l4x5_syscfg-test.c

Helper suggestion to ease readability:

static void syscfg_set_irq(int num, int level)
{
    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg",
                     NULL, num, level);
}

When the SoC is parented to the machine, this patch needs:

-- >8 --
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c 
b/tests/qtest/stm32l4x5_syscfg-test.c
index 3edd13b222..272ba91055 100644
--- a/tests/qtest/stm32l4x5_syscfg-test.c
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -240,3 +240,3 @@ static void test_interrupt(void)
       */
-    qtest_irq_intercept_in(global_qtest, 
"/machine/unattached/device[0]/exti");
+    qtest_irq_intercept_in(global_qtest, "/machine/soc/exti");
      /* Enable interrupt on rising edge of GPIO PA[0] */
@@ -245,4 +245,3 @@ static void test_interrupt(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 1);

@@ -254,4 +253,3 @@ static void test_interrupt(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 15, 1);

@@ -264,4 +262,3 @@ static void test_interrupt(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 17, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 17, 1);

@@ -271,8 +268,5 @@ static void test_interrupt(void)
      syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 0);
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 17, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 15, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 17, 0);
  }
@@ -285,3 +279,3 @@ static void test_irq_pin_multiplexer(void)

-    qtest_irq_intercept_in(global_qtest, 
"/machine/unattached/device[0]/exti");
+    qtest_irq_intercept_in(global_qtest, "/machine/soc/exti");

@@ -291,4 +285,3 @@ static void test_irq_pin_multiplexer(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 1);

@@ -299,4 +292,3 @@ static void test_irq_pin_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 0);

@@ -306,4 +298,3 @@ static void test_irq_pin_multiplexer(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 15, 1);

@@ -314,4 +305,3 @@ static void test_irq_pin_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 15, 0);
  }
@@ -324,3 +314,3 @@ static void test_irq_gpio_multiplexer(void)

-    qtest_irq_intercept_in(global_qtest, 
"/machine/unattached/device[0]/exti");
+    qtest_irq_intercept_in(global_qtest, "/machine/soc/exti");

@@ -331,4 +321,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Check that setting rising pin GPIOA[0] generates an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 1);

@@ -337,8 +326,6 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 0);

      /* Check that setting rising pin GPIOB[0] doesn't generate an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 16, 1);

@@ -347,4 +334,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 16, 0);

@@ -356,4 +342,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Check that setting rising pin GPIOA[0] doesn't generate an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 1);

@@ -362,8 +347,6 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 0, 0);

      /* Check that setting rising pin GPIOB[0] generates an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 1);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 16, 1);

@@ -372,4 +355,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 0);
+    qtest_set_irq_in(global_qtest, "/machine/soc/syscfg", NULL, 16, 0);
      syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
---

With the helper included (since I tested it):

-- >8 --
diff --git a/tests/qtest/stm32l4x5_syscfg-test.c 
b/tests/qtest/stm32l4x5_syscfg-test.c
index 3edd13b222..19a5f83ebe 100644
--- a/tests/qtest/stm32l4x5_syscfg-test.c
+++ b/tests/qtest/stm32l4x5_syscfg-test.c
@@ -47,2 +47,8 @@ static void exti_writel(unsigned int offset, uint32_t 
value)

+static void syscfg_set_irq(int num, int level)
+{
+   qtest_set_irq_in(global_qtest, "/machine/soc/syscfg",
+                    NULL, num, level);
+}
+
  static void system_reset(void)
@@ -240,3 +246,3 @@ static void test_interrupt(void)
       */
-    qtest_irq_intercept_in(global_qtest, 
"/machine/unattached/device[0]/exti");
+    qtest_irq_intercept_in(global_qtest, "/machine/soc/exti");
      /* Enable interrupt on rising edge of GPIO PA[0] */
@@ -245,4 +251,3 @@ static void test_interrupt(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    syscfg_set_irq(0, 1);

@@ -254,4 +259,3 @@ static void test_interrupt(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 1);
+    syscfg_set_irq(15, 1);

@@ -264,4 +268,3 @@ static void test_interrupt(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 17, 1);
+    syscfg_set_irq(17, 1);

@@ -271,8 +274,5 @@ static void test_interrupt(void)
      syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 0);
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 17, 0);
+    syscfg_set_irq(0, 0);
+    syscfg_set_irq(15, 0);
+    syscfg_set_irq(17, 0);
  }
@@ -285,3 +285,3 @@ static void test_irq_pin_multiplexer(void)

-    qtest_irq_intercept_in(global_qtest, 
"/machine/unattached/device[0]/exti");
+    qtest_irq_intercept_in(global_qtest, "/machine/soc/exti");

@@ -291,4 +291,3 @@ static void test_irq_pin_multiplexer(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    syscfg_set_irq(0, 1);

@@ -299,4 +298,3 @@ static void test_irq_pin_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
+    syscfg_set_irq(0, 0);

@@ -306,4 +304,3 @@ static void test_irq_pin_multiplexer(void)

-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 1);
+    syscfg_set_irq(15, 1);

@@ -314,4 +311,3 @@ static void test_irq_pin_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 15, 0);
+    syscfg_set_irq(15, 0);
  }
@@ -324,3 +320,3 @@ static void test_irq_gpio_multiplexer(void)

-    qtest_irq_intercept_in(global_qtest, 
"/machine/unattached/device[0]/exti");
+    qtest_irq_intercept_in(global_qtest, "/machine/soc/exti");

@@ -331,4 +327,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Check that setting rising pin GPIOA[0] generates an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    syscfg_set_irq(0, 1);

@@ -337,8 +332,6 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
+    syscfg_set_irq(0, 0);

      /* Check that setting rising pin GPIOB[0] doesn't generate an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 1);
+    syscfg_set_irq(16, 1);

@@ -347,4 +340,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 0);
+    syscfg_set_irq(16, 0);

@@ -356,4 +348,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Check that setting rising pin GPIOA[0] doesn't generate an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 1);
+    syscfg_set_irq(0, 1);

@@ -362,8 +353,6 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 0, 0);
+    syscfg_set_irq(0, 0);

      /* Check that setting rising pin GPIOB[0] generates an irq */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 1);
+    syscfg_set_irq(16, 1);

@@ -372,4 +361,3 @@ static void test_irq_gpio_multiplexer(void)
      /* Clean the test */
-    qtest_set_irq_in(global_qtest, "/machine/unattached/device[0]/syscfg",
-                     NULL, 16, 0);
+    syscfg_set_irq(16, 0);
      syscfg_writel(SYSCFG_EXTICR1, 0x00000000);
---

Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Regards,

Phil.


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/3] Add device STM32L4x5 SYSCFG
  2023-12-29 16:47 [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Inès Varhol
                   ` (2 preceding siblings ...)
  2023-12-29 16:47 ` [PATCH v3 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC Inès Varhol
@ 2024-01-04 13:47 ` Philippe Mathieu-Daudé
  3 siblings, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2024-01-04 13:47 UTC (permalink / raw)
  To: Inès Varhol, qemu-devel
  Cc: Laurent Vivier, Paolo Bonzini, Alistair Francis, Arnaud Minier,
	qemu-arm, Peter Maydell, Thomas Huth, Samuel Tardieu

Hi Inès,

On 29/12/23 17:47, Inès Varhol wrote:

> Based-on: <20231228161944.303768-1-ines.varhol@telecom-paris.fr>
> ([PATCH v5 0/3] Add device STM32L4x5 EXTI)
> 
> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>
> 
> Inès Varhol (3):
>    hw/misc: Implement STM32L4x5 SYSCFG
>    tests/qtest: Add STM32L4x5 SYSCFG QTest testcase
>    hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC

Very good work!

In case that helps, I pushed my reviewed branch of your
series here:
https://gitlab.com/philmd/qemu/-/commits/review/stm32l4x5-v5/

Regards,

Phil.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/3] hw/misc: Implement STM32L4x5 SYSCFG
  2023-12-29 16:47 ` [PATCH v3 1/3] hw/misc: Implement " Inès Varhol
@ 2024-01-05  5:12   ` Alistair Francis
  0 siblings, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2024-01-05  5:12 UTC (permalink / raw)
  To: Inès Varhol
  Cc: qemu-devel, Laurent Vivier, Philippe Mathieu-Daudé,
	Paolo Bonzini, Alistair Francis, Arnaud Minier, qemu-arm,
	Peter Maydell, Thomas Huth

On Sat, Dec 30, 2023 at 2:50 AM Inès Varhol
<ines.varhol@telecom-paris.fr> wrote:
>
> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr>
> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  docs/system/arm/b-l475e-iot01a.rst |   2 +-
>  hw/misc/Kconfig                    |   3 +
>  hw/misc/meson.build                |   1 +
>  hw/misc/stm32l4x5_syscfg.c         | 265 +++++++++++++++++++++++++++++
>  hw/misc/trace-events               |   6 +
>  include/hw/misc/stm32l4x5_syscfg.h |  54 ++++++
>  6 files changed, 330 insertions(+), 1 deletion(-)
>  create mode 100644 hw/misc/stm32l4x5_syscfg.c
>  create mode 100644 include/hw/misc/stm32l4x5_syscfg.h
>
> diff --git a/docs/system/arm/b-l475e-iot01a.rst b/docs/system/arm/b-l475e-iot01a.rst
> index 72f256ace7..1a021b306a 100644
> --- a/docs/system/arm/b-l475e-iot01a.rst
> +++ b/docs/system/arm/b-l475e-iot01a.rst
> @@ -16,6 +16,7 @@ Currently B-L475E-IOT01A machine's only supports the following devices:
>
>  - Cortex-M4F based STM32L4x5 SoC
>  - STM32L4x5 EXTI (Extended interrupts and events controller)
> +- STM32L4x5 SYSCFG (System configuration controller)
>
>  Missing devices
>  """""""""""""""
> @@ -24,7 +25,6 @@ The B-L475E-IOT01A does *not* support the following devices:
>
>  - Reset and clock control (RCC)
>  - Serial ports (UART)
> -- System configuration controller (SYSCFG)
>  - General-purpose I/Os (GPIO)
>  - Analog to Digital Converter (ADC)
>  - SPI controller
> diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
> index 3efe3dc2cc..4fc6b29b43 100644
> --- a/hw/misc/Kconfig
> +++ b/hw/misc/Kconfig
> @@ -90,6 +90,9 @@ config STM32F4XX_EXTI
>  config STM32L4X5_EXTI
>      bool
>
> +config STM32L4X5_SYSCFG
> +    bool
> +
>  config MIPS_ITU
>      bool
>
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 16db6e228d..2ca2ce4b62 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -111,6 +111,7 @@ system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.
>  system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c'))
>  system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c'))
>  system_ss.add(when: 'CONFIG_STM32L4X5_EXTI', if_true: files('stm32l4x5_exti.c'))
> +system_ss.add(when: 'CONFIG_STM32L4X5_SYSCFG', if_true: files('stm32l4x5_syscfg.c'))
>  system_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c'))
>  system_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c'))
>
> diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c
> new file mode 100644
> index 0000000000..36ac8956f9
> --- /dev/null
> +++ b/hw/misc/stm32l4x5_syscfg.c
> @@ -0,0 +1,265 @@
> +/*
> + * STM32L4x5 SYSCFG (System Configuration Controller)
> + *
> + * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
> + * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + * This work is based on the stm32f4xx_syscfg by Alistair Francis.
> + * Original code is licensed under the MIT License:
> + *
> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
> + */
> +
> +/*
> + * The reference used is the STMicroElectronics RM0351 Reference manual
> + * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
> + * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "trace.h"
> +#include "hw/irq.h"
> +#include "migration/vmstate.h"
> +#include "hw/misc/stm32l4x5_syscfg.h"
> +
> +#define SYSCFG_MEMRMP 0x00
> +#define SYSCFG_CFGR1 0x04
> +#define SYSCFG_EXTICR1 0x08
> +#define SYSCFG_EXTICR2 0x0C
> +#define SYSCFG_EXTICR3 0x10
> +#define SYSCFG_EXTICR4 0x14
> +#define SYSCFG_SCSR 0x18
> +#define SYSCFG_CFGR2 0x1C
> +#define SYSCFG_SWPR 0x20
> +#define SYSCFG_SKR 0x24
> +#define SYSCFG_SWPR2 0x28
> +
> +/* 00000000_00000000_00000001_00000111 */
> +#define ACTIVABLE_BITS_MEMRP 0x00000107
> +
> +/* 11111100_11111111_00000001_00000000 */
> +#define ACTIVABLE_BITS_CFGR1 0xFCFF0100
> +/* 00000000_00000000_00000000_00000001 */
> +#define FIREWALL_DISABLE_CFGR1 0x00000001
> +
> +/* 00000000_00000000_11111111_11111111 */
> +#define ACTIVABLE_BITS_EXTICR 0x0000FFFF
> +
> +/* 00000000_00000000_00000000_00000011 */
> +/* #define ACTIVABLE_BITS_SCSR 0x00000003 */
> +
> +/* 00000000_00000000_00000000_00001111 */
> +#define ECC_LOCK_CFGR2 0x0000000F
> +/* 00000000_00000000_00000001_00000000 */
> +#define SRAM2_PARITY_ERROR_FLAG_CFGR2 0x00000100
> +
> +/* 00000000_00000000_00000000_11111111 */
> +#define ACTIVABLE_BITS_SKR 0x000000FF
> +
> +static void stm32l4x5_syscfg_hold_reset(Object *obj)
> +{
> +    Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
> +
> +    s->memrmp = 0x00000000;
> +    s->cfgr1 = 0x7C000001;
> +    s->exticr[0] = 0x00000000;
> +    s->exticr[1] = 0x00000000;
> +    s->exticr[2] = 0x00000000;
> +    s->exticr[3] = 0x00000000;
> +    s->scsr = 0x00000000;
> +    s->cfgr2 = 0x00000000;
> +    s->swpr = 0x00000000;
> +    s->skr = 0x00000000;
> +    s->swpr2 = 0x00000000;
> +}
> +
> +static void stm32l4x5_syscfg_set_irq(void *opaque, int irq, int level)
> +{
> +    Stm32l4x5SyscfgState *s = opaque;
> +    uint8_t gpio = irq / GPIO_NUM_PINS;
> +    g_assert(gpio < NUM_GPIOS);
> +
> +    int line = irq % GPIO_NUM_PINS;
> +    int exticr_reg = line / 4;
> +    int startbit = (irq % 4) * 4;
> +
> +    trace_stm32l4x5_syscfg_set_irq(gpio, line, level);
> +
> +    if (extract32(s->exticr[exticr_reg], startbit, 4) == gpio) {
> +        trace_stm32l4x5_syscfg_forward_exti(line);
> +        qemu_set_irq(s->gpio_out[line], level);
> +   }
> +}
> +
> +static uint64_t stm32l4x5_syscfg_read(void *opaque, hwaddr addr,
> +                                      unsigned int size)
> +{
> +    Stm32l4x5SyscfgState *s = opaque;
> +
> +    trace_stm32l4x5_syscfg_read(addr);
> +
> +    switch (addr) {
> +    case SYSCFG_MEMRMP:
> +        return s->memrmp;
> +    case SYSCFG_CFGR1:
> +        return s->cfgr1;
> +    case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
> +        return s->exticr[(addr - SYSCFG_EXTICR1) / 4];
> +    case SYSCFG_SCSR:
> +        return s->scsr;
> +    case SYSCFG_CFGR2:
> +        return s->cfgr2;
> +    case SYSCFG_SWPR:
> +        return s->swpr;
> +    case SYSCFG_SKR:
> +        return s->skr;
> +    case SYSCFG_SWPR2:
> +        return s->swpr2;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +        return 0;
> +    }
> +}
> +static void stm32l4x5_syscfg_write(void *opaque, hwaddr addr,
> +                                   uint64_t val64, unsigned int size)
> +{
> +    Stm32l4x5SyscfgState *s = opaque;
> +    uint32_t value = val64;
> +
> +    trace_stm32l4x5_syscfg_write(addr, value);
> +
> +    switch (addr) {
> +    case SYSCFG_MEMRMP:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Changing the memory mapping isn't supported\n",
> +                      __func__);
> +        s->memrmp = value & ACTIVABLE_BITS_MEMRP;
> +        return;
> +    case SYSCFG_CFGR1:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Functions in CFGRx aren't supported\n",
> +                      __func__);
> +        /* bit 0 (firewall dis.) is cleared by software, set only by reset. */
> +        s->cfgr1 = (s->cfgr1 & value & FIREWALL_DISABLE_CFGR1) |
> +                   (value & ACTIVABLE_BITS_CFGR1);
> +        return;
> +    case SYSCFG_EXTICR1...SYSCFG_EXTICR4:
> +        s->exticr[(addr - SYSCFG_EXTICR1) / 4] =
> +                (value & ACTIVABLE_BITS_EXTICR);
> +        return;
> +    case SYSCFG_SCSR:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Erasing SRAM2 isn't supported\n",
> +                      __func__);
> +        /*
> +         * only non reserved bits are :
> +         * bit 0 (write-protected by a passkey), bit 1 (meant to be read)
> +         * so it serves no purpose yet to add :
> +         * s->scsr = value & 0x3;
> +         */
> +        return;
> +    case SYSCFG_CFGR2:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Functions in CFGRx aren't supported\n",
> +                      __func__);
> +        /* bit 8 (SRAM2 PEF) is cleared by software by writing a '1'.*/
> +        /* bits[3:0] (ECC Lock) are set by software, cleared only by reset.*/
> +        s->cfgr2 = (s->cfgr2 | (value & ECC_LOCK_CFGR2)) &
> +                   ~(value & SRAM2_PARITY_ERROR_FLAG_CFGR2);
> +        return;
> +    case SYSCFG_SWPR:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Write protecting SRAM2 isn't supported\n",
> +                      __func__);
> +        /* These bits are set by software and cleared only by reset.*/
> +        s->swpr |= value;
> +        return;
> +    case SYSCFG_SKR:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Erasing SRAM2 isn't supported\n",
> +                      __func__);
> +        s->skr = value & ACTIVABLE_BITS_SKR;
> +        return;
> +    case SYSCFG_SWPR2:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "%s: Write protecting SRAM2 isn't supported\n",
> +                      __func__);
> +        /* These bits are set by software and cleared only by reset.*/
> +        s->swpr2 |= value;
> +        return;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
> +    }
> +}
> +
> +static const MemoryRegionOps stm32l4x5_syscfg_ops = {
> +    .read = stm32l4x5_syscfg_read,
> +    .write = stm32l4x5_syscfg_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .impl.unaligned = false,
> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 4,
> +    .valid.unaligned = false,
> +};
> +
> +static void stm32l4x5_syscfg_init(Object *obj)
> +{
> +    Stm32l4x5SyscfgState *s = STM32L4X5_SYSCFG(obj);
> +
> +    memory_region_init_io(&s->mmio, obj, &stm32l4x5_syscfg_ops, s,
> +                          TYPE_STM32L4X5_SYSCFG, 0x400);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
> +
> +    qdev_init_gpio_in(DEVICE(obj), stm32l4x5_syscfg_set_irq,
> +                      GPIO_NUM_PINS * NUM_GPIOS);
> +    qdev_init_gpio_out(DEVICE(obj), s->gpio_out, GPIO_NUM_PINS);
> +}
> +
> +static const VMStateDescription vmstate_stm32l4x5_syscfg = {
> +    .name = TYPE_STM32L4X5_SYSCFG,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(memrmp, Stm32l4x5SyscfgState),
> +        VMSTATE_UINT32(cfgr1, Stm32l4x5SyscfgState),
> +        VMSTATE_UINT32_ARRAY(exticr, Stm32l4x5SyscfgState,
> +                             SYSCFG_NUM_EXTICR),
> +        VMSTATE_UINT32(scsr, Stm32l4x5SyscfgState),
> +        VMSTATE_UINT32(cfgr2, Stm32l4x5SyscfgState),
> +        VMSTATE_UINT32(swpr, Stm32l4x5SyscfgState),
> +        VMSTATE_UINT32(skr, Stm32l4x5SyscfgState),
> +        VMSTATE_UINT32(swpr2, Stm32l4x5SyscfgState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void stm32l4x5_syscfg_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    ResettableClass *rc = RESETTABLE_CLASS(klass);
> +
> +    dc->vmsd = &vmstate_stm32l4x5_syscfg;
> +    rc->phases.hold = stm32l4x5_syscfg_hold_reset;
> +}
> +
> +static const TypeInfo stm32l4x5_syscfg_info[] = {
> +    {
> +        .name          = TYPE_STM32L4X5_SYSCFG,
> +        .parent        = TYPE_SYS_BUS_DEVICE,
> +        .instance_size = sizeof(Stm32l4x5SyscfgState),
> +        .instance_init = stm32l4x5_syscfg_init,
> +        .class_init    = stm32l4x5_syscfg_class_init,
> +    }
> +};
> +
> +DEFINE_TYPES(stm32l4x5_syscfg_info)
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index 2f01c62c0e..60d0a14e74 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -163,6 +163,12 @@ stm32f4xx_exti_set_irq(int irq, int level) "Set EXTI: %d to %d"
>  stm32f4xx_exti_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
>  stm32f4xx_exti_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
>
> +# stm32l4x5_syscfg.c
> +stm32l4x5_syscfg_set_irq(int gpio, int line, int level) "irq from GPIO: %d, line: %d, level: %d"
> +stm32l4x5_syscfg_forward_exti(int irq) "irq %d forwarded to EXTI"
> +stm32l4x5_syscfg_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
> +stm32l4x5_syscfg_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
> +
>  # stm32l4x5_exti.c
>  stm32l4x5_exti_set_irq(int irq, int level) "Set EXTI: %d to %d"
>  stm32l4x5_exti_read(uint64_t addr, uint64_t data) "reg read: addr: 0x%" PRIx64 " val: 0x%" PRIx64 ""
> diff --git a/include/hw/misc/stm32l4x5_syscfg.h b/include/hw/misc/stm32l4x5_syscfg.h
> new file mode 100644
> index 0000000000..76bdcf5189
> --- /dev/null
> +++ b/include/hw/misc/stm32l4x5_syscfg.h
> @@ -0,0 +1,54 @@
> +/*
> + * STM32L4x5 SYSCFG (System Configuration Controller)
> + *
> + * Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
> + * Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + * This work is based on the stm32f4xx_syscfg by Alistair Francis.
> + * Original code is licensed under the MIT License:
> + *
> + * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
> + */
> +
> +/*
> + * The reference used is the STMicroElectronics RM0351 Reference manual
> + * for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
> + * https://www.st.com/en/microcontrollers-microprocessors/stm32l4x5/documentation.html
> + */
> +
> +#ifndef HW_STM32L4X5_SYSCFG_H
> +#define HW_STM32L4X5_SYSCFG_H
> +
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_STM32L4X5_SYSCFG "stm32l4x5-syscfg"
> +OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5SyscfgState, STM32L4X5_SYSCFG)
> +
> +#define NUM_GPIOS 8
> +#define GPIO_NUM_PINS 16
> +#define SYSCFG_NUM_EXTICR 4
> +
> +struct Stm32l4x5SyscfgState {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion mmio;
> +
> +    uint32_t memrmp;
> +    uint32_t cfgr1;
> +    uint32_t exticr[SYSCFG_NUM_EXTICR];
> +    uint32_t scsr;
> +    uint32_t cfgr2;
> +    uint32_t swpr;
> +    uint32_t skr;
> +    uint32_t swpr2;
> +
> +    qemu_irq gpio_out[16];
> +};
> +
> +#endif
> --
> 2.43.0
>
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2024-01-05  5:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-29 16:47 [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Inès Varhol
2023-12-29 16:47 ` [PATCH v3 1/3] hw/misc: Implement " Inès Varhol
2024-01-05  5:12   ` Alistair Francis
2023-12-29 16:47 ` [PATCH v3 2/3] tests/qtest: Add STM32L4x5 SYSCFG QTest testcase Inès Varhol
2024-01-04 13:23   ` Philippe Mathieu-Daudé
2024-01-04 13:37   ` Philippe Mathieu-Daudé
2023-12-29 16:47 ` [PATCH v3 3/3] hw/arm: Connect STM32L4x5 SYSCFG to STM32L4x5 SoC Inès Varhol
2024-01-04 13:20   ` Philippe Mathieu-Daudé
2024-01-04 13:47 ` [PATCH v3 0/3] Add device STM32L4x5 SYSCFG Philippe Mathieu-Daudé

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).