Re: [PATCH v14 12/15] mtd: spi-nor: core: perform a Soft Reset on shutdown

From: Tudor.Ambarus
Date: Thu Oct 01 2020 - 04:23:53 EST


On 9/30/20 9:57 PM, Pratyush Yadav wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> Perform a Soft Reset on shutdown on flashes that support it so that the
> flash can be reset to its initial state and any configurations made by
> spi-nor (given that they're only done in volatile registers) will be
> reset. This will hand back the flash in pristine state for any further
> operations on it.
>
> Signed-off-by: Pratyush Yadav <p.yadav@xxxxxx>

Reviewed-by: Tudor Ambarus <tudor.ambarus@xxxxxxxxxxxxx>

> ---
> drivers/mtd/spi-nor/core.c | 45 +++++++++++++++++++++++++++++++++++++
> include/linux/mtd/spi-nor.h | 2 ++
> 2 files changed, 47 insertions(+)
>
> diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
> index b42d59ab2724..9de811b33125 100644
> --- a/drivers/mtd/spi-nor/core.c
> +++ b/drivers/mtd/spi-nor/core.c
> @@ -40,6 +40,9 @@
>
> #define SPI_NOR_MAX_ADDR_WIDTH 4
>
> +#define SPI_NOR_SRST_SLEEP_MIN 200
> +#define SPI_NOR_SRST_SLEEP_MAX 400
> +
> /**
> * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
> * extension type.
> @@ -3175,6 +3178,45 @@ static int spi_nor_init(struct spi_nor *nor)
> return 0;
> }
>
> +static void spi_nor_soft_reset(struct spi_nor *nor)
> +{
> + struct spi_mem_op op;
> + int ret;
> +
> + op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0),
> + SPI_MEM_OP_NO_DUMMY,
> + SPI_MEM_OP_NO_ADDR,
> + SPI_MEM_OP_NO_DATA);
> +
> + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
> +
> + ret = spi_mem_exec_op(nor->spimem, &op);
> + if (ret) {
> + dev_warn(nor->dev, "Software reset failed: %d\n", ret);
> + return;
> + }
> +
> + op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 0),
> + SPI_MEM_OP_NO_DUMMY,
> + SPI_MEM_OP_NO_ADDR,
> + SPI_MEM_OP_NO_DATA);
> +
> + spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
> +
> + ret = spi_mem_exec_op(nor->spimem, &op);
> + if (ret) {
> + dev_warn(nor->dev, "Software reset failed: %d\n", ret);
> + return;
> + }
> +
> + /*
> + * Software Reset is not instant, and the delay varies from flash to
> + * flash. Looking at a few flashes, most range somewhere below 100
> + * microseconds. So, sleep for a range of 200-400 us.
> + */
> + usleep_range(SPI_NOR_SRST_SLEEP_MIN, SPI_NOR_SRST_SLEEP_MAX);
> +}
> +
> /* mtd resume handler */
> static void spi_nor_resume(struct mtd_info *mtd)
> {
> @@ -3194,6 +3236,9 @@ void spi_nor_restore(struct spi_nor *nor)
> if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
> nor->flags & SNOR_F_BROKEN_RESET)
> nor->params->set_4byte_addr_mode(nor, false);
> +
> + if (nor->flags & SNOR_F_SOFT_RESET)
> + spi_nor_soft_reset(nor);
> }
> EXPORT_SYMBOL_GPL(spi_nor_restore);
>
> diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
> index cd549042c53d..299685d15dc2 100644
> --- a/include/linux/mtd/spi-nor.h
> +++ b/include/linux/mtd/spi-nor.h
> @@ -51,6 +51,8 @@
> #define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
> #define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */
> #define SPINOR_OP_WREAR 0xc5 /* Write Extended Address Register */
> +#define SPINOR_OP_SRSTEN 0x66 /* Software Reset Enable */
> +#define SPINOR_OP_SRST 0x99 /* Software Reset */
>
> /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
> #define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */
> --
> 2.28.0
>