diff mbox

[5/7] ast2400: handle SPI flash Command mode (read only)

Message ID 1467634738-28642-6-git-send-email-clg@kaod.org
State New
Headers show

Commit Message

Cédric Le Goater July 4, 2016, 12:18 p.m. UTC
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@kaod.org>
---
 hw/arm/palmetto-bmc.c       |  2 ++
 hw/ssi/aspeed_smc.c         | 60 +++++++++++++++++++++++++++++++++++++++++----
 include/hw/ssi/aspeed_smc.h |  1 +
 3 files changed, 58 insertions(+), 5 deletions(-)
diff mbox

Patch

diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c
index c0bb922f6406..b00757dcbc69 100644
--- a/hw/arm/palmetto-bmc.c
+++ b/hw/arm/palmetto-bmc.c
@@ -20,6 +20,7 @@ 
 #include "qemu/log.h"
 #include "sysemu/block-backend.h"
 #include "sysemu/blockdev.h"
+#include "hw/block/flash.h"
 
 static struct arm_boot_info palmetto_bmc_binfo = {
     .loader_start = AST2400_SDRAM_BASE,
@@ -51,6 +52,7 @@  static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype,
             qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
                                 errp);
         }
+        m25p80_set_rom_storage(fl->flash, &fl->mmio);
         qdev_init_nofail(fl->flash);
 
         cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
index cb0b23750bcf..f88edf953dee 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"
 
@@ -198,6 +200,37 @@  static inline bool aspeed_smc_is_writable(const AspeedSMCState *s, int cs)
     return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + cs));
 }
 
+/*
+ * Sanity checks on the command mode and the SPI flash command being
+ * used
+ */
+static inline bool aspeed_smc_check_mode(const 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)
 {
     AspeedSMCFlash *fl = opaque;
@@ -210,9 +243,11 @@  static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
             ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
         }
     } else {
-        qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
-                      __func__);
-        ret = -1;
+        if (aspeed_smc_check_mode(s, fl->id)) {
+            for (i = 0; i < size; i++) {
+                ret = fl->storage[addr + i] << (8 * i);
+            }
+        }
     }
 
     return ret;
@@ -336,6 +371,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);
     }
 }
@@ -355,6 +396,7 @@  static void aspeed_smc_realize(DeviceState *dev, Error **errp)
     int i;
     char name[32];
     hwaddr offset = 0;
+    Error *err = NULL;
 
     s->ctrl = mc->ctrl;
 
@@ -409,8 +451,16 @@  static void aspeed_smc_realize(DeviceState *dev, Error **errp)
         fl->id = i;
         fl->controller = s;
         fl->size = s->ctrl->segments[i].size;
-        memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops,
-                              fl, name, fl->size);
+        memory_region_init_rom_device(&fl->mmio, OBJECT(s),
+                                      &aspeed_smc_flash_ops,
+                                      fl, name, fl->size, &err);
+        if (err) {
+            error_propagate(errp, err);
+            return;
+        }
+        vmstate_register_ram(&fl->mmio, DEVICE(s));
+        fl->storage = memory_region_get_ram_ptr(&fl->mmio);
+
         memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio);
         offset += fl->size;
     }
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
index def3b4507e75..4796b4ca0138 100644
--- a/include/hw/ssi/aspeed_smc.h
+++ b/include/hw/ssi/aspeed_smc.h
@@ -47,6 +47,7 @@  typedef struct AspeedSMCController {
 
 typedef struct AspeedSMCFlash {
     const struct AspeedSMCState *controller;
+    uint8_t *storage;
 
     uint8_t id;
     uint32_t size;