diff mbox series

[7/8] mtd: spi-nor: use spi-mem dirmap API

Message ID 20220414112350.3994901-8-chin-ting_kuo@aspeedtech.com
State Changes Requested
Delegated to: Jagannadha Sutradharudu Teki
Headers show
Series Add ASPEED SPI controller driver | expand

Commit Message

Chin-Ting Kuo April 14, 2022, 11:23 a.m. UTC
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-seanga2@gmail.com/

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(-)

Comments

Pratyush Yadav April 20, 2022, 8:21 a.m. UTC | #1
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-seanga2@gmail.com/
> 
> 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
>
Chin-Ting Kuo April 20, 2022, 9:38 a.m. UTC | #2
Hi Pratyush,

Thanks for your review.

> -----Original Message-----
> From: Pratyush Yadav <p.yadav@ti.com>
> Sent: Wednesday, April 20, 2022 4:21 PM
> To: Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>
> Subject: Re: [PATCH 7/8] mtd: spi-nor: use spi-mem dirmap API
> 
> 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-seanga2@gmail.com/
> >
> > 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.

Okay, this will be updated in the next version.


Best Wishes,
Chin-Ting

> 
> >  	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
> >
> 
> --
> Regards,
> Pratyush Yadav
> Texas Instruments Inc.
diff mbox series

Patch

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 */
+
 /**
  * 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;
+
 	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