[PATCH 1/3] mtd: spi nor: add support for dual and quad bit transfers

Pratyush Yadav p.yadav at ti.com
Mon Nov 30 13:37:43 CET 2020


Hi Jean,

On 29/11/20 11:39AM, Jean Pihet wrote:
> Use the flags field of the SPI slave struct to pass the dual and quad
> read properties, from the SPI NOR layer to the low level driver.
> Tested with TI QSPI in 1, 2 and 4 bits modes.
> 
> Signed-off-by: Jean Pihet <jean.pihet at newoldbits.com>
> ---
>  drivers/mtd/spi/spi-nor-core.c | 34 +++++++++++++++++++++++++++++++---
>  drivers/spi/spi-mem.c          |  8 +++++++-
>  include/spi.h                  |  2 ++
>  3 files changed, 40 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index e16b0e1462..54569b3cba 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -94,22 +94,50 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
>  	/* convert the dummy cycles to the number of bytes */
>  	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
>  
> +	/* Check for dual and quad I/O read */
> +	switch (op.cmd.opcode) {
> +	case SPINOR_OP_READ_1_1_2:
> +	case SPINOR_OP_READ_1_2_2:
> +	case SPINOR_OP_READ_1_1_2_4B:
> +	case SPINOR_OP_READ_1_2_2_4B:
> +	case SPINOR_OP_READ_1_2_2_DTR:
> +	case SPINOR_OP_READ_1_2_2_DTR_4B:
> +		nor->spi->flags |= SPI_XFER_DUAL_READ;
> +		break;
> +	case SPINOR_OP_READ_1_1_4:
> +	case SPINOR_OP_READ_1_4_4:
> +	case SPINOR_OP_READ_1_1_4_4B:
> +	case SPINOR_OP_READ_1_4_4_4B:
> +	case SPINOR_OP_READ_1_4_4_DTR:
> +	case SPINOR_OP_READ_1_4_4_DTR_4B:
> +		nor->spi->flags |= SPI_XFER_QUAD_READ;
> +		break;
> +	default:
> +		break;
> +	}
> +

NACK. What if a flash uses some other opcode for dual or quad reads?

Why not use op->data.buswidth in ti_qspi_exec_mem_op() to enable dual or 
quad mode? In fact, ti_qspi_setup_mmap_read() already checks this and 
enables dual or quad mode. What problem does this patch solve then?

>  	while (remaining) {
>  		op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
>  		ret = spi_mem_adjust_op_size(nor->spi, &op);
>  		if (ret)
> -			return ret;
> +			goto out;
>  
>  		ret = spi_mem_exec_op(nor->spi, &op);
>  		if (ret)
> -			return ret;
> +			goto out;
>  
>  		op.addr.val += op.data.nbytes;
>  		remaining -= op.data.nbytes;
>  		op.data.buf.in += op.data.nbytes;
>  	}
>  
> -	return len;
> +	ret = len;
> +
> +out:
> +	/* Reset dual and quad I/O read flags for upcoming transactions */
> +	nor->spi->flags &= ~(SPI_XFER_DUAL_READ | SPI_XFER_QUAD_READ);
> +
> +	return ret;
>  }
>  
>  static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
> diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
> index c095ae9505..24e38ea95e 100644
> --- a/drivers/spi/spi-mem.c
> +++ b/drivers/spi/spi-mem.c
> @@ -387,9 +387,15 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
>  		return ret;
>  
>  	/* 2nd transfer: rx or tx data path */
> +	flag = SPI_XFER_END;
> +	/* Check for dual and quad I/O reads */
> +	if (slave->flags & SPI_XFER_DUAL_READ)
> +		flag |= SPI_XFER_DUAL_READ;
> +	if (slave->flags & SPI_XFER_QUAD_READ)
> +		flag |= SPI_XFER_QUAD_READ;

Ah, so you are targeting the "legacy" path. Seeing that ti_qspi does 
support the SPI MEM path, this would be executed when the read exceeds 
priv->mmap_size, correct?

In any case, I don't see why you need slave->flags. Why can't you set 
these flags by checking op->data.buswidth and op->data.dir? This would 
make your fix transparent to SPI NOR, which IMO is a much better idea.

>  	if (tx_buf || rx_buf) {
>  		ret = spi_xfer(slave, op->data.nbytes * 8, tx_buf,
> -			       rx_buf, SPI_XFER_END);
> +			       rx_buf, flag);
>  		if (ret)
>  			return ret;
>  	}
> diff --git a/include/spi.h b/include/spi.h
> index ef8c1f6692..cf5f05e526 100644
> --- a/include/spi.h
> +++ b/include/spi.h
> @@ -146,6 +146,8 @@ struct spi_slave {
>  #define SPI_XFER_BEGIN		BIT(0)	/* Assert CS before transfer */
>  #define SPI_XFER_END		BIT(1)	/* Deassert CS after transfer */
>  #define SPI_XFER_ONCE		(SPI_XFER_BEGIN | SPI_XFER_END)
> +#define SPI_XFER_DUAL_READ	BIT(2)  /* Dual I/O read */
> +#define SPI_XFER_QUAD_READ	BIT(3)  /* Quad I/O read */
>  };
>  
>  /**
> -- 
> 2.26.2
> 

-- 
Regards,
Pratyush Yadav
Texas Instruments India


More information about the U-Boot mailing list