[PATCH qemu v2 06/10] ast2400: handle SPI flash Command mode (read only)

Cédric Le Goater clg at kaod.org
Tue Jun 14 03:16:32 AEST 2016


To handle memory accesses when the SPI flash slave is configured in
Command mode, let's change the memory region of the SPI flash object
to a ROM memory region (like the pflash_cfi* object). The m25p80 flash
object creation is changed accordingly to use the new memory region as
a storage.

Only read only accesses are handled. Supporting write accesses would
demand using internal routines of the m25p80 flash model. This is not
required for the moment.

Signed-off-by: Cédric Le Goater <clg at kaod.org>
---
 hw/ssi/aspeed_smc.c         | 63 +++++++++++++++++++++++++++++++++++++++++----
 include/hw/ssi/aspeed_smc.h |  1 +
 2 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index ce59cb59be9f..8be00412b5b1 100644
--- a/hw/ssi/aspeed_smc.c
+++ b/hw/ssi/aspeed_smc.c
@@ -23,11 +23,13 @@
  */
 
 #include "qemu/osdep.h"
+#include "qapi/error.h"
 #include "hw/sysbus.h"
 #include "sysemu/sysemu.h"
 #include "qemu/log.h"
 #include "include/qemu/error-report.h"
 #include "exec/address-spaces.h"
+#include "hw/block/flash.h"
 
 #include "hw/ssi/aspeed_smc.h"
 
@@ -225,6 +227,12 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
      */
     s->regs[addr] = value;
     if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) {
+        int i;
+
+        for (i = 0; i < s->num_cs; ++i) {
+            memory_region_rom_device_set_romd(&s->flashes[i]->mmio,
+                                              !aspeed_smc_is_usermode(s, i));
+        }
         aspeed_smc_update_cs(s);
     }
 }
@@ -335,6 +343,35 @@ static void aspeed_smc_register_types(void)
 
 type_init(aspeed_smc_register_types)
 
+/* Sanity checks on the command mode and the SPI flash command being
+ * used */
+static inline bool aspeed_smc_check_mode(AspeedSMCState *s, int cs)
+{
+    uint8_t mode = aspeed_smc_flash_mode(s, cs);
+    uint8_t cmd = (s->regs[s->r_ctrl0 + cs] >> CTRL_CMD_SHIFT) && CTRL_CMD_MASK;
+    bool ret;
+
+    switch (mode) {
+    case CTRL_READMODE:
+        ret = (cmd == 0x3 || cmd == 0x0);
+        break;
+    case CTRL_FREADMODE:
+        ret = true;
+        break;
+    case CTRL_WRITEMODE:
+    default:
+        ret = false;
+        break;
+    }
+
+    if (!ret) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mode/command: %d/%d\n",
+                      __func__, cmd, mode);
+    }
+
+    return ret;
+}
+
 static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
 {
     AspeedSMCFlashState *fl = ASPEED_SMC_FLASH(opaque);
@@ -347,8 +384,11 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
             ret = (ret << 8) | ssi_transfer(s->spi, 0x0);
         }
     } else {
-        error_report("%s: flash not in usermode", __func__);
-        ret = -1;
+        if (aspeed_smc_check_mode(s, fl->id)) {
+            for (i = 0; i < size; i++) {
+                ret = (ret << 8) | fl->storage[addr + i];
+            }
+        }
     }
 
     return ret;
@@ -422,6 +462,7 @@ void aspeed_smc_init_flashes(AspeedSMCState *s, const char *flashtype,
 {
     int i ;
     char name[32];
+    Error *err = NULL;
 
     for (i = 0; i < s->num_cs; ++i) {
         Object *obj = object_new(TYPE_ASPEED_SMC_FLASH);
@@ -437,12 +478,24 @@ void aspeed_smc_init_flashes(AspeedSMCState *s, const char *flashtype,
         fl->size = s->ctrl->segments[i].size;
 
         /* backing region */
-        memory_region_init_io(&fl->mmio, obj, &aspeed_smc_flash_ops, fl, name,
-                              fl->size);
+        memory_region_init_rom_device(&fl->mmio, obj, &aspeed_smc_flash_ops,
+                                      fl, name, fl->size, &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        vmstate_register_ram(&fl->mmio, DEVICE(fl));
         sysbus_init_mmio(SYS_BUS_DEVICE(fl), &fl->mmio);
 
+        fl->storage = memory_region_get_ram_ptr(&fl->mmio);
+
         /* SPI Flash module */
-        fl->flash = ssi_create_slave(s->spi, flashtype);
+        fl->flash = m25p80_create_rom(s->spi, flashtype, &fl->mmio, &err);
+        if (err) {
+            vmstate_unregister_ram(&fl->mmio, DEVICE(fl));
+            error_propagate(errp, err);
+            return;
+        }
         cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
         sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
 
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index 2636c775c90f..069891b0bd5a 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -35,6 +35,7 @@ typedef struct AspeedSMCFlashState {
     MemoryRegion mmio;
     uint8_t id;
     size_t size;
+    uint8_t *storage;
     struct AspeedSMCState *controller;
     DeviceState *flash;
 } AspeedSMCFlashState;
-- 
2.1.4



More information about the openbmc mailing list