Lately we have working on Flash interface unit (FIU) SPI driver that
using spi-mem interface, Our FIU HW module support direct Flash Rd//Wr.
In our SOC (32 bit dual core ARM) we have 3 FIU's that using memory mapping as follow:
FIU0 - have 2 chip select and each one have 128MB memory mapping (total 256MB memory mapping)
FIU1 - have 4 chip select and each one have 128MB memory mapping (total 512MB memory mapping)
FIU2 - have 4 chip select and each one have 16MB memory mapping (total 32MB memory mapping)
Totally 800MB memory mapping.
When the FIU driver probe it don't know the size of each Flash that
connected to the FIU, so the entire memory mapping is allocated for each FIU
according the FIU device tree memory map parameters.
It means, if we enable all three FIU's the drivers will try to allocate totally 800MB.
In 32bit system it is problematic because the kernel have only 1GB
of memory allocation so the vmalloc cannot take 800MB.
When implementing the FIU driver in the mtd/spi-nor we allocating memory address only
for detected Flash with exact size (usually we are not using 128MB Flash), and in that case usually we allocating much less memory.
To solve this issue we needed to overcome two things:
1. Get argument from the upper layer (spi-mem layer)
2. Calling the get argument function after SPI_NOR_SCAN function. (the MTD Flash size filled in SPI_NOR_SCAN function)
The attach patch set solving the describe issue by:
1. Add spi-mem callback function and value to the SPI device
for passing an argument from the spi-mem layer to the spi layer
2. Add spi-mem setup function to the spi-memory operation that running
after the spi-mem probe finished.
3. Implement function callback in the m25p80 driver that execute
get Flash size.
The patch set tested on NPCM750 EVB with FIU driver (implemented with SPI-MEM interface).
Thanks for your attention.
Tomer
Tomer Maimon (3):
spi: spi-mem: add spi-mem setup function
spi: spi-mem: add callback function to spi-mem device
mtd: m25p80: add get Flash size callback support
drivers/mtd/devices/m25p80.c | 12 ++++++++++++
drivers/spi/spi-mem.c | 27 ++++++++++++++++++++++++++-
include/linux/spi/spi-mem.h | 11 +++++++++++
3 files changed, 49 insertions(+), 1 deletion(-)
--
2.18.0
Add get Flash size function support for
passing Flash size through callback use
to the spi layer.
Add get Flash size function support
Signed-off-by: Tomer Maimon <[email protected]>
---
drivers/mtd/devices/m25p80.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index c50888670250..fd14c8c6d8d8 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -151,6 +151,15 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
return len;
}
+/* Sending Flash size thourgh callback function to spi layer */
+size_t m25p80_get_flash_size(void *param)
+{
+ struct spi_mem *spimem = param;
+ struct m25p *flash = spi_mem_get_drvdata(spimem);
+
+ return (u32)(flash->spi_nor.mtd.size >> 10) * 1024;
+}
+
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -188,6 +197,9 @@ static int m25p_probe(struct spi_mem *spimem)
spi_nor_set_flash_node(nor, spi->dev.of_node);
nor->priv = flash;
+ spimem->callback = m25p80_get_flash_size;
+ spimem->callback_param = spimem;
+
spi_mem_set_drvdata(spimem, flash);
flash->spimem = spimem;
--
2.18.0
Add callback function support to the spi-mem device
for passing an argument from the spi-mem layer
to the spi layer.
Signed-off-by: Tomer Maimon <[email protected]>
---
include/linux/spi/spi-mem.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 5f7d20bd2b09..b9841a9030be 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -13,6 +13,8 @@
#include <linux/spi/spi.h>
+typedef size_t (*spi_mem_callback)(void *spi_mem_param);
+
#define SPI_MEM_OP_CMD(__opcode, __buswidth) \
{ \
.buswidth = __buswidth, \
@@ -172,6 +174,9 @@ struct spi_mem_dirmap_desc {
* @spi: the underlying SPI device
* @drvpriv: spi_mem_driver private data
* @name: name of the SPI memory device
+ * @callback: routine for passing an argument from the
+ * spi-mem layer to the spi layer.
+ * @callback_param: general parameter to pass to the callback routine
*
* Extra information that describe the SPI memory device and may be needed by
* the controller to properly handle this device should be placed here.
@@ -183,6 +188,8 @@ struct spi_mem {
struct spi_device *spi;
void *drvpriv;
const char *name;
+ spi_mem_callback callback;
+ void *callback_param;
};
/**
--
2.18.0
Hi Tomer,
On Mon, 29 Jul 2019 17:25:01 +0300
Tomer Maimon <[email protected]> wrote:
> Lately we have working on Flash interface unit (FIU) SPI driver that
> using spi-mem interface, Our FIU HW module support direct Flash Rd//Wr.
>
> In our SOC (32 bit dual core ARM) we have 3 FIU's that using memory mapping as follow:
>
> FIU0 - have 2 chip select and each one have 128MB memory mapping (total 256MB memory mapping)
> FIU1 - have 4 chip select and each one have 128MB memory mapping (total 512MB memory mapping)
> FIU2 - have 4 chip select and each one have 16MB memory mapping (total 32MB memory mapping)
>
> Totally 800MB memory mapping.
>
> When the FIU driver probe it don't know the size of each Flash that
> connected to the FIU, so the entire memory mapping is allocated for each FIU
> according the FIU device tree memory map parameters.
Do you need those mappings to be active to support simple reg accesses?
> It means, if we enable all three FIU's the drivers will try to allocate totally 800MB.
>
> In 32bit system it is problematic because the kernel have only 1GB
> of memory allocation so the vmalloc cannot take 800MB.
>
> When implementing the FIU driver in the mtd/spi-nor we allocating memory address only
> for detected Flash with exact size (usually we are not using 128MB Flash), and in that case usually we allocating much less memory.
>
> To solve this issue we needed to overcome two things:
>
> 1. Get argument from the upper layer (spi-mem layer)
> 2. Calling the get argument function after SPI_NOR_SCAN function. (the MTD Flash size filled in SPI_NOR_SCAN function)
That's clearly breaking the layering we've tried to restore with the
spi-nor/spi-mem split, and I don't see why this is needed since we now
have a way to create direct mappings dynamically (with the dirmap API).
Have you tried implementing the dirmap hooks in your driver?
Regards,
Boris
Add spi-mem setup function support SPI memory
operations the spi-mem setup function running
after the spi-mem probe function if the spi-mem
setup function implemented.
Signed-off-by: Tomer Maimon <[email protected]>
---
drivers/spi/spi-mem.c | 27 ++++++++++++++++++++++++++-
include/linux/spi/spi-mem.h | 4 ++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index 9f0fa9f3116d..21fe3a75d636 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -398,6 +398,26 @@ const char *spi_mem_get_name(struct spi_mem *mem)
}
EXPORT_SYMBOL_GPL(spi_mem_get_name);
+/**
+ * spi_mem_setup() - Execute spi memory setup
+ * @mem: the SPI memory
+ *
+ * This function allows SPI mem users to execute spi memory
+ * setup after the probe finished.
+ *
+ * Return: 0 in case of success, a negative error code otherwise.
+ */
+int spi_mem_setup(struct spi_mem *mem)
+{
+ struct spi_controller *ctlr = mem->spi->controller;
+
+ if (ctlr->mem_ops && ctlr->mem_ops->setup)
+ return ctlr->mem_ops->setup(mem);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_mem_setup);
+
/**
* spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to
* match controller limitations
@@ -723,6 +743,7 @@ static int spi_mem_probe(struct spi_device *spi)
struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
struct spi_controller *ctlr = spi->controller;
struct spi_mem *mem;
+ int ret;
mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL);
if (!mem)
@@ -740,7 +761,11 @@ static int spi_mem_probe(struct spi_device *spi)
spi_set_drvdata(spi, mem);
- return memdrv->probe(mem);
+ ret = memdrv->probe(mem);
+ if (ret)
+ return ret;
+
+ return spi_mem_setup(mem);
}
static int spi_mem_remove(struct spi_device *spi)
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index af9ff2f0f1b2..5f7d20bd2b09 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -222,6 +222,7 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
* Note that if the implementation of this function allocates memory
* dynamically, then it should do so with devm_xxx(), as we don't
* have a ->free_name() function.
+ * @setup: execute a SPI memory setup
* @dirmap_create: create a direct mapping descriptor that can later be used to
* access the memory device. This method is optional
* @dirmap_destroy: destroy a memory descriptor previous created by
@@ -256,6 +257,7 @@ struct spi_controller_mem_ops {
int (*exec_op)(struct spi_mem *mem,
const struct spi_mem_op *op);
const char *(*get_name)(struct spi_mem *mem);
+ int (*setup)(struct spi_mem *mem);
int (*dirmap_create)(struct spi_mem_dirmap_desc *desc);
void (*dirmap_destroy)(struct spi_mem_dirmap_desc *desc);
ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *desc,
@@ -334,6 +336,8 @@ int spi_mem_exec_op(struct spi_mem *mem,
const char *spi_mem_get_name(struct spi_mem *mem);
+int spi_mem_setup(struct spi_mem *mem);
+
struct spi_mem_dirmap_desc *
spi_mem_dirmap_create(struct spi_mem *mem,
const struct spi_mem_dirmap_info *info);
--
2.18.0