Re: [PATCH 6/8] spi-mem: Add dirmap API from Linux

2022-04-20 Thread Pratyush Yadav
On 14/04/22 07:23PM, Chin-Ting Kuo wrote:
> This adds the dirmap API originally introduced in Linux commit aa167f3
> ("spi: spi-mem: Add a new API to support direct mapping"). This also
> includes several follow-up patches and fixes.
> 
> Changes from Linux include:
> * Added Kconfig option
> * Changed struct device to struct udevice
> * Changed struct spi_mem to struct spi_slave
> 
> This patch is obtained from the following patch
> https://patchwork.ozlabs.org/project/uboot/patch/20210205043924.149504-3-sean...@gmail.com/
> 
> Signed-off-by: Chin-Ting Kuo 
> Signed-off-by: Sean Anderson 

Have not looked at it too closely, but the idea sounds good to me.

Acked-by: Pratyush Yadav 

-- 
Regards,
Pratyush Yadav
Texas Instruments Inc.


[PATCH 6/8] spi-mem: Add dirmap API from Linux

2022-04-14 Thread Chin-Ting Kuo
This adds the dirmap API originally introduced in Linux commit aa167f3
("spi: spi-mem: Add a new API to support direct mapping"). This also
includes several follow-up patches and fixes.

Changes from Linux include:
* Added Kconfig option
* Changed struct device to struct udevice
* Changed struct spi_mem to struct spi_slave

This patch is obtained from the following patch
https://patchwork.ozlabs.org/project/uboot/patch/20210205043924.149504-3-sean...@gmail.com/

Signed-off-by: Chin-Ting Kuo 
Signed-off-by: Sean Anderson 
---
 drivers/spi/Kconfig   |  10 ++
 drivers/spi/spi-mem.c | 270 ++
 include/spi-mem.h |  98 +++
 3 files changed, 378 insertions(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index dc05b3966f..cf0eaf1810 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -40,6 +40,16 @@ config SPI_MEM
  This extension is meant to simplify interaction with SPI memories
  by providing an high-level interface to send memory-like commands.
 
+config SPI_DIRMAP
+   bool "SPI direct mapping"
+   depends on SPI_MEM
+   help
+ Enable the SPI direct mapping API. Most modern SPI controllers can
+ directly map a SPI memory (or a portion of the SPI memory) in the CPU
+ address space. Most of the time this brings significant performance
+ improvements as it automates the whole process of sending SPI memory
+ operations every time a new region is accessed.
+
 if DM_SPI
 
 config ALTERA_SPI
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 9c1ede1b61..8e4f37fb50 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -21,6 +21,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #endif
 
 #ifndef __UBOOT__
@@ -491,6 +493,274 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, 
struct spi_mem_op *op)
 }
 EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
 
+#if CONFIG_IS_ENABLED(SPI_DIRMAP)
+static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+   struct spi_mem_op op = desc->info.op_tmpl;
+   int ret;
+
+   op.addr.val = desc->info.offset + offs;
+   op.data.buf.in = buf;
+   op.data.nbytes = len;
+   ret = spi_mem_adjust_op_size(desc->slave, );
+   if (ret)
+   return ret;
+
+   ret = spi_mem_exec_op(desc->slave, );
+   if (ret)
+   return ret;
+
+   return op.data.nbytes;
+}
+
+static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc,
+  u64 offs, size_t len, const void *buf)
+{
+   struct spi_mem_op op = desc->info.op_tmpl;
+   int ret;
+
+   op.addr.val = desc->info.offset + offs;
+   op.data.buf.out = buf;
+   op.data.nbytes = len;
+   ret = spi_mem_adjust_op_size(desc->slave, );
+   if (ret)
+   return ret;
+
+   ret = spi_mem_exec_op(desc->slave, );
+   if (ret)
+   return ret;
+
+   return op.data.nbytes;
+}
+
+/**
+ * spi_mem_dirmap_create() - Create a direct mapping descriptor
+ * @mem: SPI mem device this direct mapping should be created for
+ * @info: direct mapping information
+ *
+ * This function is creating a direct mapping descriptor which can then be used
+ * to access the memory using spi_mem_dirmap_read() or spi_mem_dirmap_write().
+ * If the SPI controller driver does not support direct mapping, this function
+ * falls back to an implementation using spi_mem_exec_op(), so that the caller
+ * doesn't have to bother implementing a fallback on his own.
+ *
+ * Return: a valid pointer in case of success, and ERR_PTR() otherwise.
+ */
+struct spi_mem_dirmap_desc *
+spi_mem_dirmap_create(struct spi_slave *slave,
+ const struct spi_mem_dirmap_info *info)
+{
+   struct udevice *bus = slave->dev->parent;
+   struct dm_spi_ops *ops = spi_get_ops(bus);
+   struct spi_mem_dirmap_desc *desc;
+   int ret = -EOPNOTSUPP;
+
+   /* Make sure the number of address cycles is between 1 and 8 bytes. */
+   if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8)
+   return ERR_PTR(-EINVAL);
+
+   /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */
+   if (info->op_tmpl.data.dir == SPI_MEM_NO_DATA)
+   return ERR_PTR(-EINVAL);
+
+   desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+   if (!desc)
+   return ERR_PTR(-ENOMEM);
+
+   desc->slave = slave;
+   desc->info = *info;
+   if (ops->mem_ops && ops->mem_ops->dirmap_create)
+   ret = ops->mem_ops->dirmap_create(desc);
+
+   if (ret) {
+   desc->nodirmap = true;
+   if (!spi_mem_supports_op(desc->slave, >info.op_tmpl))
+   ret = -EOPNOTSUPP;
+   else
+   ret = 0;
+   }
+
+   if (ret) {
+