This adds support for the dirmap API to the spi-nor subsystem, as
introduced in Linux commit df5c21002cf4 ("mtd: spi-nor: use spi-mem dirmap
API").

Signed-off-by: Sean Anderson <sean...@gmail.com>
---

 drivers/mtd/spi/sf_probe.c     | 79 ++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/spi-nor-core.c | 45 +++++++++++++------
 include/linux/mtd/spi-nor.h    |  6 +++
 3 files changed, 116 insertions(+), 14 deletions(-)

diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 6c87434867..796a2fa6bc 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -14,9 +14,72 @@
 #include <malloc.h>
 #include <spi.h>
 #include <spi_flash.h>
+#include <spi-mem.h>
 
 #include "sf_internal.h"
 
+#if CONFIG_IS_ENABLED(SPI_DIRMAP)
+static int spi_nor_create_read_dirmap(struct spi_nor *nor)
+{
+       struct spi_mem_dirmap_info info = {
+               .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
+                                     SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
+                                     SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
+                                     SPI_MEM_OP_DATA_IN(0, NULL, 1)),
+               .offset = 0,
+               .length = nor->mtd.size,
+       };
+       struct spi_mem_op *op = &info.op_tmpl;
+
+       /* get transfer protocols. */
+       op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
+       op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
+       op->dummy.buswidth = op->addr.buswidth;
+       op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+
+       /* convert the dummy cycles to the number of bytes */
+       op->dummy.nbytes = (nor->read_dummy * op->dummy.buswidth) / 8;
+
+       nor->dirmap.rdesc = spi_mem_dirmap_create(nor->spi, &info);
+       return PTR_ERR_OR_ZERO(nor->dirmap.rdesc);
+}
+
+static int spi_nor_create_write_dirmap(struct spi_nor *nor)
+{
+       struct spi_mem_dirmap_info info = {
+               .op_tmpl = SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
+                                     SPI_MEM_OP_ADDR(nor->addr_width, 0, 1),
+                                     SPI_MEM_OP_NO_DUMMY,
+                                     SPI_MEM_OP_DATA_OUT(0, NULL, 1)),
+               .offset = 0,
+               .length = nor->mtd.size,
+       };
+       struct spi_mem_op *op = &info.op_tmpl;
+
+       /* get transfer protocols. */
+       op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
+       op->addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
+       op->dummy.buswidth = op->addr.buswidth;
+       op->data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
+
+       if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
+               op->addr.nbytes = 0;
+
+       nor->dirmap.wdesc = spi_mem_dirmap_create(nor->spi, &info);
+       return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
+}
+#else
+static int spi_nor_create_read_dirmap(struct spi_nor *nor)
+{
+       return 0;
+}
+
+static int spi_nor_create_write_dirmap(struct spi_nor *nor)
+{
+       return 0;
+}
+#endif /* CONFIG_SPI_DIRMAP */
+
 /**
  * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
  *
@@ -45,6 +108,14 @@ static int spi_flash_probe_slave(struct spi_flash *flash)
        if (ret)
                goto err_read_id;
 
+       ret = spi_nor_create_read_dirmap(flash);
+       if (ret)
+               return ret;
+
+       ret = spi_nor_create_write_dirmap(flash);
+       if (ret)
+               return ret;
+
        if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
                ret = spi_flash_mtd_register(flash);
 
@@ -83,6 +154,9 @@ struct spi_flash *spi_flash_probe(unsigned int busnum, 
unsigned int cs,
 
 void spi_flash_free(struct spi_flash *flash)
 {
+       spi_mem_dirmap_destroy(flash->dirmap.wdesc);
+       spi_mem_dirmap_destroy(flash->dirmap.rdesc);
+
        if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
                spi_flash_mtd_unregister();
 
@@ -143,6 +217,11 @@ int spi_flash_std_probe(struct udevice *dev)
 
 static int spi_flash_std_remove(struct udevice *dev)
 {
+       struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+       spi_mem_dirmap_destroy(flash->dirmap.wdesc);
+       spi_mem_dirmap_destroy(flash->dirmap.rdesc);
+
        if (CONFIG_IS_ENABLED(SPI_FLASH_MTD))
                spi_flash_mtd_unregister();
 
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index e16b0e1462..32c712a9f1 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -96,13 +96,23 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, 
loff_t from, size_t len,
 
        while (remaining) {
                op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
-               ret = spi_mem_adjust_op_size(nor->spi, &op);
-               if (ret)
-                       return ret;
 
-               ret = spi_mem_exec_op(nor->spi, &op);
-               if (ret)
-                       return ret;
+               if (CONFIG_IS_ENABLED(SPI_DIRMAP) && nor->dirmap.rdesc) {
+                       ret = spi_mem_dirmap_read(nor->dirmap.rdesc,
+                                                 op.addr.val, op.data.nbytes,
+                                                 op.data.buf.in);
+                       if (ret < 0)
+                               return ret;
+                       op.data.nbytes = ret;
+               } else {
+                       ret = spi_mem_adjust_op_size(nor->spi, &op);
+                       if (ret)
+                               return ret;
+
+                       ret = spi_mem_exec_op(nor->spi, &op);
+                       if (ret)
+                               return ret;
+               }
 
                op.addr.val += op.data.nbytes;
                remaining -= op.data.nbytes;
@@ -120,6 +130,7 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, 
loff_t to, size_t len,
                                   SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
                                   SPI_MEM_OP_NO_DUMMY,
                                   SPI_MEM_OP_DATA_OUT(len, buf, 1));
+       ssize_t nbytes;
        int ret;
 
        /* get transfer protocols. */
@@ -130,16 +141,22 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, 
loff_t to, size_t len,
        if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
                op.addr.nbytes = 0;
 
-       ret = spi_mem_adjust_op_size(nor->spi, &op);
-       if (ret)
-               return ret;
-       op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
+       if (CONFIG_IS_ENABLED(SPI_DIRMAP) && nor->dirmap.wdesc) {
+               nbytes = spi_mem_dirmap_write(nor->dirmap.wdesc, op.addr.val,
+                                             op.data.nbytes, op.data.buf.out);
+       } else {
+               ret = spi_mem_adjust_op_size(nor->spi, &op);
+               if (ret)
+                       return ret;
+               op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
 
-       ret = spi_mem_exec_op(nor->spi, &op);
-       if (ret)
-               return ret;
+               ret = spi_mem_exec_op(nor->spi, &op);
+               if (ret)
+                       return ret;
+               nbytes = op.data.nbytes;
+       }
 
-       return op.data.nbytes;
+       return nbytes;
 }
 
 /*
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 39ef872ebf..ffa4dd3e7d 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -304,6 +304,7 @@ struct spi_flash {
  * @flash_is_locked:   [FLASH-SPECIFIC] check if a region of the SPI NOR is
  *                     completely locked
  * @quad_enable:       [FLASH-SPECIFIC] enables SPI NOR quad mode
+ * @dirmap:             pointers to struct spi_mem_dirmap_desc for 
reads/writes.
  * @priv:              the private data
  */
 struct spi_nor {
@@ -346,6 +347,11 @@ struct spi_nor {
        int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
        int (*quad_enable)(struct spi_nor *nor);
 
+       struct {
+               struct spi_mem_dirmap_desc *rdesc;
+               struct spi_mem_dirmap_desc *wdesc;
+       } dirmap;
+
        void *priv;
 /* Compatibility for spi_flash, remove once sf layer is merged with mtd */
        const char *name;
-- 
2.29.2

Reply via email to