spi: Add support for memory-mapped flash
authorSimon Glass <sjg@chromium.org>
Mon, 21 Oct 2019 03:31:47 +0000 (21:31 -0600)
committerBin Meng <bmeng.cn@gmail.com>
Sat, 2 Nov 2019 23:20:26 +0000 (07:20 +0800)
On x86 platforms the SPI flash can be mapped into memory so that the
contents can be read with normal memory accesses.

Add a new SPI method to find the location of the SPI flash in memory. This
differs from the existing device-tree "memory-map" mechanism in that the
location can be discovered at run-time.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
drivers/spi/sandbox_spi.c
drivers/spi/spi-uclass.c
include/spi.h
test/dm/sf.c

index 16473ec..6b610ff 100644 (file)
@@ -122,11 +122,22 @@ static int sandbox_cs_info(struct udevice *bus, uint cs,
        return 0;
 }
 
+static int sandbox_spi_get_mmap(struct udevice *dev, ulong *map_basep,
+                               uint *map_sizep, uint *offsetp)
+{
+       *map_basep = 0x1000;
+       *map_sizep = 0x2000;
+       *offsetp = 0x100;
+
+       return 0;
+}
+
 static const struct dm_spi_ops sandbox_spi_ops = {
        .xfer           = sandbox_spi_xfer,
        .set_speed      = sandbox_spi_set_speed,
        .set_mode       = sandbox_spi_set_mode,
        .cs_info        = sandbox_cs_info,
+       .get_mmap       = sandbox_spi_get_mmap,
 };
 
 static const struct udevice_id sandbox_spi_ids[] = {
index 9475160..665611f 100644 (file)
@@ -92,6 +92,20 @@ int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
        return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
+int dm_spi_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep,
+                   uint *offsetp)
+{
+       struct udevice *bus = dev->parent;
+       struct dm_spi_ops *ops = spi_get_ops(bus);
+
+       if (bus->uclass->uc_drv->id != UCLASS_SPI)
+               return -EOPNOTSUPP;
+       if (!ops->get_mmap)
+               return -ENOSYS;
+
+       return ops->get_mmap(dev, map_basep, map_sizep, offsetp);
+}
+
 int spi_claim_bus(struct spi_slave *slave)
 {
        return log_ret(dm_spi_claim_bus(slave->dev));
index 3f79168..6fbb433 100644 (file)
@@ -462,6 +462,19 @@ struct dm_spi_ops {
         *         is invalid, other -ve value on error
         */
        int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
+
+       /**
+        * get_mmap() - Get memory-mapped SPI
+        *
+        * @dev:        The SPI flash slave device
+        * @map_basep:  Returns base memory address for mapped SPI
+        * @map_sizep:  Returns size of mapped SPI
+        * @offsetp:    Returns start offset of SPI flash where the map works
+        *      correctly (offsets before this are not visible)
+        * @return 0 if OK, -EFAULT if memory mapping is not available
+        */
+       int (*get_mmap)(struct udevice *dev, ulong *map_basep,
+                       uint *map_sizep, uint *offsetp);
 };
 
 struct dm_spi_emul_ops {
@@ -650,6 +663,20 @@ void dm_spi_release_bus(struct udevice *dev);
 int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
                const void *dout, void *din, unsigned long flags);
 
+/**
+ * spi_get_mmap() - Get memory-mapped SPI
+ *
+ * @dev:       SPI slave device to check
+ * @map_basep: Returns base memory address for mapped SPI
+ * @map_sizep: Returns size of mapped SPI
+ * @offsetp:   Returns start offset of SPI flash where the map works
+ *     correctly (offsets before this are not visible)
+ * @return 0 if OK, -ENOSYS if no operation, -EFAULT if memory mapping is not
+ *     available
+ */
+int dm_spi_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep,
+                   uint *offsetp);
+
 /* Access the operations for a SPI device */
 #define spi_get_ops(dev)       ((struct dm_spi_ops *)(dev)->driver->ops)
 #define spi_emul_get_ops(dev)  ((struct dm_spi_emul_ops *)(dev)->driver->ops)
index 3788d59..65aab4f 100644 (file)
@@ -23,6 +23,9 @@ static int dm_test_spi_flash(struct unit_test_state *uts)
        int full_size = 0x200000;
        int size = 0x10000;
        u8 *src, *dst;
+       uint map_size;
+       ulong map_base;
+       uint offset;
        int i;
 
        src = map_sysmem(0x20000, full_size);
@@ -54,6 +57,12 @@ static int dm_test_spi_flash(struct unit_test_state *uts)
        sandbox_sf_set_block_protect(emul, 0);
        ut_asserteq(0, spl_flash_get_sw_write_prot(dev));
 
+       /* Check mapping */
+       ut_assertok(dm_spi_get_mmap(dev, &map_base, &map_size, &offset));
+       ut_asserteq(0x1000, map_base);
+       ut_asserteq(0x2000, map_size);
+       ut_asserteq(0x100, offset);
+
        /*
         * Since we are about to destroy all devices, we must tell sandbox
         * to forget the emulation device