
On 14/04/22 07:23PM, Chin-Ting Kuo wrote:
This adds support for the dirmap API to the spi-nor subsystem, as introduced in Linux commit df5c210 ("mtd: spi-nor: use spi-mem dirmap API").
This patch is synchronize from the following patch https://patchwork.ozlabs.org/project/uboot/patch/20210205043924.149504-4-sea...
Signed-off-by: Chin-Ting Kuo chin-ting_kuo@aspeedtech.com Signed-off-by: Sean Anderson seanga2@gmail.com
drivers/mtd/spi/sf_probe.c | 82 ++++++++++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-core.c | 55 ++++++++++++++++------- include/linux/mtd/spi-nor.h | 18 ++++++++ 3 files changed, 139 insertions(+), 16 deletions(-)
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index f461082e03..a3b38b6a29 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -10,13 +10,81 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <linux/mtd/spi-nor.h> #include <log.h> #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, 0),
SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
SPI_MEM_OP_DUMMY(nor->read_dummy, 0),
SPI_MEM_OP_DATA_IN(0, NULL, 0)),
.offset = 0,
.length = nor->mtd.size,
- };
- struct spi_mem_op *op = &info.op_tmpl;
- /* get transfer protocols. */
- spi_nor_setup_op(nor, op, nor->read_proto);
- 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;
- if (spi_nor_protocol_is_dtr(nor->read_proto))
op->dummy.nbytes *= 2;
- nor->dirmap.rdesc = spi_mem_dirmap_create(nor->spi, &info);
- if (IS_ERR(nor->dirmap.rdesc))
return PTR_ERR(nor->dirmap.rdesc);
- return 0;
+}
+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, 0),
SPI_MEM_OP_ADDR(nor->addr_width, 0, 0),
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_OUT(0, NULL, 0)),
.offset = 0,
.length = nor->mtd.size,
- };
- struct spi_mem_op *op = &info.op_tmpl;
- /* get transfer protocols. */
- spi_nor_setup_op(nor, op, nor->write_proto);
- 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);
- if (IS_ERR(nor->dirmap.wdesc))
return PTR_ERR(nor->dirmap.wdesc);
- return 0;
+} +#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 */
Instead of wrapping these in #ifdefs...
/**
- spi_flash_probe_slave() - Probe for a SPI flash device on a bus
@@ -45,6 +113,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;
... wrap these in a
if (CONFIG_IS_ENABLED(SPI_DIRMAP)) { // Create read and write dirmap }
Then at compile time if the config is not enabled, this is a dead branch and the compiler should not look at spi_nor_create_{read,write}_dirmap() at all.
if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) ret = spi_flash_mtd_register(flash);
@@ -83,6 +159,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(flash);
@@ -153,6 +232,9 @@ static int spi_flash_std_remove(struct udevice *dev) struct spi_flash *flash = dev_get_uclass_priv(dev); int ret;
- spi_mem_dirmap_destroy(flash->dirmap.wdesc);
- spi_mem_dirmap_destroy(flash->dirmap.rdesc);
- ret = spi_nor_remove(flash); if (ret) return ret;
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 3b7c817c02..0c6262b7fd 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -239,9 +239,9 @@ static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor,
need to be initialized.
- @proto: the protocol from which the properties need to be set.
*/ -static void spi_nor_setup_op(const struct spi_nor *nor,
struct spi_mem_op *op,
const enum spi_nor_protocol proto)
+void spi_nor_setup_op(const struct spi_nor *nor,
struct spi_mem_op *op,
const enum spi_nor_protocol proto)
{ u8 ext;
@@ -362,13 +362,29 @@ 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) {
/*
* Record current operation information which may be used
* when the address or data length exceeds address mapping.
*/
memcpy(&nor->dirmap.rdesc->info.op_tmpl, &op,
sizeof(struct spi_mem_op));
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;
@@ -393,14 +409,21 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
spi_nor_setup_op(nor, &op, nor->write_proto);
- 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) {
memcpy(&nor->dirmap.wdesc->info.op_tmpl, &op,
sizeof(struct spi_mem_op));
op.data.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;
}
return op.data.nbytes;
} diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4ceeae623d..2a5ad09625 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -11,6 +11,7 @@ #include <linux/bitops.h> #include <linux/mtd/cfi.h> #include <linux/mtd/mtd.h> +#include <spi-mem.h>
/*
- Manufacturer IDs
@@ -511,6 +512,7 @@ struct spi_flash {
- @quad_enable: [FLASH-SPECIFIC] enables SPI NOR quad mode
- @octal_dtr_enable: [FLASH-SPECIFIC] enables SPI NOR octal DTR mode.
- @ready: [FLASH-SPECIFIC] check if the flash is ready
*/
- @dirmap: pointers to struct spi_mem_dirmap_desc for reads/writes.
- @priv: the private data
struct spi_nor { @@ -561,6 +563,11 @@ struct spi_nor { int (*octal_dtr_enable)(struct spi_nor *nor); int (*ready)(struct spi_nor *nor);
- struct {
struct spi_mem_dirmap_desc *rdesc;
struct spi_mem_dirmap_desc *wdesc;
- } dirmap;
- void *priv; char mtd_name[MTD_NAME_SIZE(MTD_DEV_TYPE_NOR)];
/* Compatibility for spi_flash, remove once sf layer is merged with mtd */ @@ -584,6 +591,17 @@ device_node *spi_nor_get_flash_node(struct spi_nor *nor) } #endif /* __UBOOT__ */
+/**
- spi_nor_setup_op() - Set up common properties of a spi-mem op.
- @nor: pointer to a 'struct spi_nor'
- @op: pointer to the 'struct spi_mem_op' whose properties
need to be initialized.
- @proto: the protocol from which the properties need to be set.
- */
+void spi_nor_setup_op(const struct spi_nor *nor,
struct spi_mem_op *op,
const enum spi_nor_protocol proto);
/**
- spi_nor_scan() - scan the SPI NOR
- @nor: the spi_nor structure
-- 2.25.1