[RFC PATCH 03/13] mtd: spi-nor: use spi-mem dirmap API
Sean Anderson
seanga2 at gmail.com
Fri Feb 5 05:39:13 CET 2021
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 <seanga2 at 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
More information about the U-Boot
mailing list