qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] hw/arm/stm32f405: Add preliminary flash interface emulation supp


From: Stephanos Ioannidis
Subject: [PATCH] hw/arm/stm32f405: Add preliminary flash interface emulation support
Date: Sun, 1 Mar 2020 08:45:01 +0000

The flash interface (FLASHIF) peripheral provides a control interface
for the SoC embedded flash memory on the STM32F4xx series devices.

This commit adds preliminary support for the flash interface peripheral
emulation, in order to support proper emulation of the firmware images
that use the STM32Cube driver, which configures and validates the
FLASH_ACR register during system initialisation.

Signed-off-by: Stephanos Ioannidis <address@hidden>
---
 hw/arm/Kconfig                      |   1 +
 hw/arm/stm32f405_soc.c              |  15 +-
 hw/misc/Kconfig                     |   3 +
 hw/misc/Makefile.objs               |   1 +
 hw/misc/stm32f4xx_flashif.c         | 215 ++++++++++++++++++++++++++++
 hw/misc/trace-events                |   4 +
 include/hw/arm/stm32f405_soc.h      |   2 +
 include/hw/misc/stm32f4xx_flashif.h | 144 +++++++++++++++++++
 8 files changed, 384 insertions(+), 1 deletion(-)
 create mode 100644 hw/misc/stm32f4xx_flashif.c
 create mode 100644 include/hw/misc/stm32f4xx_flashif.h

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 3d86691ae0..179696ec91 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -314,6 +314,7 @@ config STM32F205_SOC
 config STM32F405_SOC
     bool
     select ARM_V7M
+    select STM32F4XX_FLASHIF
     select STM32F4XX_SYSCFG
     select STM32F4XX_EXTI
 
diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c
index 9bcad97853..72b16910c7 100644
--- a/hw/arm/stm32f405_soc.c
+++ b/hw/arm/stm32f405_soc.c
@@ -30,6 +30,7 @@
 #include "hw/arm/stm32f405_soc.h"
 #include "hw/misc/unimp.h"
 
+#define FLASHIF_ADDR                   0x40023C00
 #define SYSCFG_ADD                     0x40013800
 static const uint32_t usart_addr[] = { 0x40011000, 0x40004400, 0x40004800,
                                        0x40004C00, 0x40005000, 0x40011400,
@@ -59,6 +60,9 @@ static void stm32f405_soc_initfn(Object *obj)
     sysbus_init_child_obj(obj, "armv7m", &s->armv7m, sizeof(s->armv7m),
                           TYPE_ARMV7M);
 
+    sysbus_init_child_obj(obj, "flashif", &s->flashif, sizeof(s->flashif),
+                          TYPE_STM32F4XX_FLASHIF);
+
     sysbus_init_child_obj(obj, "syscfg", &s->syscfg, sizeof(s->syscfg),
                           TYPE_STM32F4XX_SYSCFG);
 
@@ -130,6 +134,16 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, 
Error **errp)
         return;
     }
 
+    /* Flash interface */
+    dev = DEVICE(&s->flashif);
+    object_property_set_bool(OBJECT(&s->flashif), true, "realized", &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
+    }
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, FLASHIF_ADDR);
+
     /* System configuration controller */
     dev = DEVICE(&s->syscfg);
     object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
@@ -261,7 +275,6 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, 
Error **errp)
     create_unimplemented_device("GPIOI",       0x40022000, 0x400);
     create_unimplemented_device("CRC",         0x40023000, 0x400);
     create_unimplemented_device("RCC",         0x40023800, 0x400);
-    create_unimplemented_device("Flash Int",   0x40023C00, 0x400);
     create_unimplemented_device("BKPSRAM",     0x40024000, 0x400);
     create_unimplemented_device("DMA1",        0x40026000, 0x400);
     create_unimplemented_device("DMA2",        0x40026400, 0x400);
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index bdd77d8020..e333a955b2 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -79,6 +79,9 @@ config IMX
     select SSI
     select USB_EHCI_SYSBUS
 
+config STM32F4XX_FLASHIF
+    bool
+
 config STM32F2XX_SYSCFG
     bool
 
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index da993f45b7..1aea0b9bb9 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -58,6 +58,7 @@ common-obj-$(CONFIG_RASPI) += bcm2835_thermal.o
 common-obj-$(CONFIG_SLAVIO) += slavio_misc.o
 common-obj-$(CONFIG_ZYNQ) += zynq_slcr.o
 common-obj-$(CONFIG_ZYNQ) += zynq-xadc.o
+common-obj-$(CONFIG_STM32F4XX_FLASHIF) += stm32f4xx_flashif.o
 common-obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
 common-obj-$(CONFIG_STM32F4XX_SYSCFG) += stm32f4xx_syscfg.o
 common-obj-$(CONFIG_STM32F4XX_EXTI) += stm32f4xx_exti.o
diff --git a/hw/misc/stm32f4xx_flashif.c b/hw/misc/stm32f4xx_flashif.c
new file mode 100644
index 0000000000..d280fc5b2c
--- /dev/null
+++ b/hw/misc/stm32f4xx_flashif.c
@@ -0,0 +1,215 @@
+/*
+ * STM32F4xx FLASHIF
+ *
+ * Copyright (c) 2020 Stephanos Ioannidis <address@hidden>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "hw/misc/stm32f4xx_flashif.h"
+
+static void stm32f4xx_flashif_reset(DeviceState *dev)
+{
+    STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(dev);
+
+    /* Initialise states */
+    s->cr_key_index = 0;
+    s->optcr_key_index = 0;
+
+    /* Initialise register values */
+    s->flash_acr.reg = 0x00000000;
+    s->flash_keyr.reg = 0x00000000;
+    s->flash_optkeyr.reg = 0x00000000;
+    s->flash_sr.reg = 0x00000000;
+    s->flash_cr.reg = 0x80000000;
+    s->flash_optcr.reg = 0x0FFFAAED;
+}
+
+static uint64_t stm32f4xx_flashif_read(void * opaque, hwaddr addr,
+                                       unsigned int size)
+{
+    STM32F4xxFlashIfState *s = opaque;
+
+    trace_stm32f4xx_flashif_read(addr);
+
+    switch (addr) {
+    case FLASH_ACR:
+        return s->flash_acr.reg;
+    case FLASH_SR:
+        return s->flash_sr.reg;
+    case FLASH_CR:
+        return s->flash_cr.reg;
+    case FLASH_OPTCR:
+        return s->flash_optcr.reg;
+    default:
+        qemu_log_mask(
+            LOG_GUEST_ERROR,
+            "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void flash_acr_write(STM32F4xxFlashIfState *s, FlashAcrType val)
+{
+    /* Set latency */
+    s->flash_acr.latency = val.latency;
+    /* Set prefetch status */
+    s->flash_acr.prften = val.prften;
+    /* Set instruction cache status */
+    s->flash_acr.icen = val.icen;
+    /* Set data cache status */
+    s->flash_acr.dcen = val.dcen;
+}
+
+static void flash_cr_write(STM32F4xxFlashIfState *s, FlashCrType val)
+{
+    /* Lock FLASH_CR if lock bit is set */
+    if (val.lock) {
+        s->flash_cr.lock = 1;
+        s->cr_key_index = 0;
+        return;
+    }
+}
+
+static void flash_optcr_write(STM32F4xxFlashIfState *s, FlashOptcrType val)
+{
+    /* Lock FLASH_OPTCR if lock bit is set */
+    if (val.optlock) {
+        s->flash_optcr.optlock = 1;
+        s->optcr_key_index = 0;
+        return;
+    }
+}
+
+static void stm32f4xx_flashif_write(void *opaque, hwaddr addr,
+                                    uint64_t val64, unsigned int size)
+{
+    STM32F4xxFlashIfState *s = opaque;
+    uint32_t value = val64;
+
+    trace_stm32f4xx_flashif_write(value, addr);
+
+    switch (addr) {
+    case FLASH_ACR:
+        flash_acr_write(s, (FlashAcrType)value);
+        return;
+    case FLASH_KEYR:
+        if (s->cr_key_index == 0 && value == 0x45670123) {
+            s->cr_key_index = 1;
+        } else if (s->cr_key_index == 1 && value == 0xCDEF89AB) {
+            /* Valid key; unlock FLASH_CR */
+            s->flash_cr.lock = 0;
+            s->cr_key_index = 0;
+        } else {
+            /* Invalid key; permanently lock FLASH_CR until reset */
+            s->flash_cr.lock = 1;
+            s->cr_key_index = -1;
+        }
+        return;
+    case FLASH_OPTKEYR:
+        if (s->optcr_key_index == 0 && value == 0x08192A3B) {
+            s->optcr_key_index = 1;
+        } else if (s->optcr_key_index == 1 && value == 0x4C5D6E7F) {
+            /* Valid key; unlock FLASH_OPTCR */
+            s->flash_optcr.optlock = 0;
+            s->optcr_key_index = 0;
+        } else {
+            /* Invalid key; lock FLASH_OPTCR until reset */
+            s->flash_optcr.optlock = 1;
+            s->optcr_key_index = -1;
+        }
+        return;
+    case FLASH_SR:
+        if (s->flash_sr.eop)        s->flash_sr.eop = 0;
+        if (s->flash_sr.operr)      s->flash_sr.operr = 0;
+        if (s->flash_sr.wrperr)     s->flash_sr.wrperr = 0;
+        if (s->flash_sr.pgaerr)     s->flash_sr.pgaerr = 0;
+        if (s->flash_sr.pgperr)     s->flash_sr.pgperr = 0;
+        if (s->flash_sr.pgserr)     s->flash_sr.pgserr = 0;
+        return;
+    case FLASH_CR:
+        flash_cr_write(s, (FlashCrType)value);
+        return;
+    case FLASH_OPTCR:
+        flash_optcr_write(s, (FlashOptcrType)value);
+        return;
+    default:
+        qemu_log_mask(
+            LOG_GUEST_ERROR,
+            "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps stm32f4xx_flashif_ops = {
+    .read = stm32f4xx_flashif_read,
+    .write = stm32f4xx_flashif_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static void stm32f4xx_flashif_init(Object *obj)
+{
+    STM32F4xxFlashIfState *s = STM32F4XX_FLASHIF(obj);
+
+    memory_region_init_io(&s->mmio, obj, &stm32f4xx_flashif_ops, s,
+                          TYPE_STM32F4XX_FLASHIF, 0x400);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static const VMStateDescription vmstate_stm32f4xx_flashif = {
+    .name = TYPE_STM32F4XX_FLASHIF,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(flash_acr.reg, STM32F4xxFlashIfState),
+        VMSTATE_UINT32(flash_keyr.reg, STM32F4xxFlashIfState),
+        VMSTATE_UINT32(flash_optkeyr.reg, STM32F4xxFlashIfState),
+        VMSTATE_UINT32(flash_sr.reg, STM32F4xxFlashIfState),
+        VMSTATE_UINT32(flash_cr.reg, STM32F4xxFlashIfState),
+        VMSTATE_UINT32(flash_optcr.reg, STM32F4xxFlashIfState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void stm32f4xx_flashif_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = stm32f4xx_flashif_reset;
+    dc->vmsd = &vmstate_stm32f4xx_flashif;
+}
+
+static const TypeInfo stm32f4xx_flashif_info = {
+    .name          = TYPE_STM32F4XX_FLASHIF,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(STM32F4xxFlashIfState),
+    .instance_init = stm32f4xx_flashif_init,
+    .class_init    = stm32f4xx_flashif_class_init
+};
+
+static void stm32f4xx_flashif_register_types(void)
+{
+    type_register_static(&stm32f4xx_flashif_info);
+}
+
+type_init(stm32f4xx_flashif_register_types)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 7f0f5dff3a..bd9a5dd483 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -84,6 +84,10 @@ mos6522_set_sr_int(void) "set sr_int"
 mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64
 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x"
 
+# stm32f4xx_flashif
+stm32f4xx_flashif_read(uint64_t addr) "reg read: addr: 0x%" PRIx64 " "
+stm32f4xx_flashif_write(uint64_t addr, uint64_t data) "reg write: addr: 0x%" 
PRIx64 " val: 0x%" PRIx64 ""
+
 # stm32f4xx_syscfg
 stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, 
Line: %d; Level: %d"
 stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
diff --git a/include/hw/arm/stm32f405_soc.h b/include/hw/arm/stm32f405_soc.h
index 1fe97f8c3a..a94c3c51ac 100644
--- a/include/hw/arm/stm32f405_soc.h
+++ b/include/hw/arm/stm32f405_soc.h
@@ -25,6 +25,7 @@
 #ifndef HW_ARM_STM32F405_SOC_H
 #define HW_ARM_STM32F405_SOC_H
 
+#include "hw/misc/stm32f4xx_flashif.h"
 #include "hw/misc/stm32f4xx_syscfg.h"
 #include "hw/timer/stm32f2xx_timer.h"
 #include "hw/char/stm32f2xx_usart.h"
@@ -57,6 +58,7 @@ typedef struct STM32F405State {
 
     ARMv7MState armv7m;
 
+    STM32F4xxFlashIfState flashif;
     STM32F4xxSyscfgState syscfg;
     STM32F4xxExtiState exti;
     STM32F2XXUsartState usart[STM_NUM_USARTS];
diff --git a/include/hw/misc/stm32f4xx_flashif.h 
b/include/hw/misc/stm32f4xx_flashif.h
new file mode 100644
index 0000000000..e364ca39c7
--- /dev/null
+++ b/include/hw/misc/stm32f4xx_flashif.h
@@ -0,0 +1,144 @@
+/*
+ * STM32F4xx FLASHIF
+ *
+ * Copyright (c) 2020 Stephanos Ioannidis <address@hidden>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HW_STM_FLASHIF_H
+#define HW_STM_FLASHIF_H
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+
+#define TYPE_STM32F4XX_FLASHIF "stm32f4xx-flashif"
+#define STM32F4XX_FLASHIF(obj) \
+    OBJECT_CHECK(STM32F4xxFlashIfState, (obj), TYPE_STM32F4XX_FLASHIF)
+
+#define FLASH_ACR       0x00
+#define FLASH_KEYR      0x04
+#define FLASH_OPTKEYR   0x08
+#define FLASH_SR        0x0C
+#define FLASH_CR        0x10
+#define FLASH_OPTCR     0x14
+
+typedef union {
+    struct {
+        uint32_t latency : 3;
+        uint32_t reserved0 : 5;
+        uint32_t prften : 1;
+        uint32_t icen : 1;
+        uint32_t dcen : 1;
+        uint32_t icrst : 1;
+        uint32_t dcrst : 1;
+        uint32_t reserved1 : 19;
+    };
+    uint32_t reg;
+} FlashAcrType;
+
+typedef union {
+    struct {
+        uint32_t key : 32;
+    };
+    uint32_t reg;
+} FlashKeyrType;
+
+typedef union {
+    struct {
+        uint32_t optkey : 32;
+    };
+    uint32_t reg;
+} FlashOptkeyrType;
+
+typedef union {
+    struct {
+        uint32_t eop : 1;
+        uint32_t operr : 1;
+        uint32_t reserved0 : 2;
+        uint32_t wrperr : 1;
+        uint32_t pgaerr : 1;
+        uint32_t pgperr : 1;
+        uint32_t pgserr : 1;
+        uint32_t reserved1 : 8;
+        uint32_t bsy : 1;
+        uint32_t reserved2 : 15;
+    };
+    uint32_t reg;
+} FlashSrType;
+
+typedef union {
+    struct {
+        uint32_t pg : 1;
+        uint32_t ser : 1;
+        uint32_t mer : 1;
+        uint32_t snb : 4;
+        uint32_t reserved0 : 1;
+        uint32_t psize : 2;
+        uint32_t reserved1 : 6;
+        uint32_t strt : 1;
+        uint32_t reserved2 : 7;
+        uint32_t eopie : 1;
+        uint32_t reserved3 : 6;
+        uint32_t lock : 1;
+    };
+    uint32_t reg;
+} FlashCrType;
+
+typedef union {
+    struct {
+        uint32_t optlock : 1;
+        uint32_t optstrt : 1;
+        uint32_t bor_lev : 2;
+        uint32_t reserved0 : 1;
+        uint32_t wdg_sw : 1;
+        uint32_t nrst_stop : 1;
+        uint32_t nrst_stdby : 1;
+        uint32_t rdp : 8;
+        uint32_t nwrp : 12;
+        uint32_t reserved1 : 4;
+    };
+    uint32_t reg;
+} FlashOptcrType;
+
+typedef struct {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /* <public> */
+    MemoryRegion mmio;
+
+    int32_t cr_key_index;
+    int32_t optcr_key_index;
+
+    /* Access control register (FLASH_ACR) */
+    FlashAcrType flash_acr;
+    /* Key register (FLASH_KEYR) */
+    FlashKeyrType flash_keyr;
+    /* Option key register (FLASH_OPTKEYR) */
+    FlashOptkeyrType flash_optkeyr;
+    /* Status register (FLASH_SR) */
+    FlashSrType flash_sr;
+    /* Control register (FLASH_CR) */
+    FlashCrType flash_cr;
+    /* Option control register (FLASH_OPTCR) */
+    FlashOptcrType flash_optcr;
+} STM32F4xxFlashIfState;
+
+#endif
-- 
2.17.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]