From: Takahiro Kuwano <takahiro.kuw...@infineon.com> Fixes mode clocks for SPINOR_OP_READ_FAST_4B and volatile QE bit in tiny. The volatile QE bit function, spansion_quad_enable_volatile() supports dual/quad die package parts, by taking 'die_size' parameter that is used to iterate register update for all dies in the device.
Signed-off-by: Takahiro Kuwano <takahiro.kuw...@infineon.com> --- drivers/mtd/spi/spi-nor-tiny.c | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 5cc2b7d996..66680df5a9 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -555,6 +555,85 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor) } #endif /* CONFIG_SPI_FLASH_SPANSION */ +#ifdef CONFIG_SPI_FLASH_SPANSION +/** + * spansion_quad_enable_volatile() - enable Quad I/O mode in volatile register. + * @nor: pointer to a 'struct spi_nor' + * @die_size: maximum number of bytes per die ('mtd.size' > 'die_size' in + * multi die package parts). + * @dummy: number of dummy cycles for register read + * + * It is recommended to update volatile registers in the field application due + * to a risk of the non-volatile registers corruption by power interrupt. This + * function sets Quad Enable bit in CFR1 volatile. + * + * Return: 0 on success, -errno otherwise. + */ +static int spansion_quad_enable_volatile(struct spi_nor *nor, u32 die_size, + u8 dummy) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(0, 1), + SPI_MEM_OP_ADDR(4, 0, 1), + SPI_MEM_OP_DUMMY(0, 1), + SPI_MEM_OP_DATA_IN(1, NULL, 1)); + u32 addr; + u8 cr; + int ret; + + /* Use 4-byte address for RDAR/WRAR */ + ret = spi_nor_write_reg(nor, SPINOR_OP_EN4B, NULL, 0); + if (ret < 0) { + dev_dbg(nor->dev, + "error while enabling 4-byte address\n"); + return ret; + } + + for (addr = 0; addr < nor->mtd.size; addr += die_size) { + op.addr.val = addr + SPINOR_REG_ADDR_CFR1V; + + /* Check current Quad Enable bit value. */ + op.cmd.opcode = SPINOR_OP_RDAR; + op.dummy.nbytes = dummy / 8; + op.data.dir = SPI_MEM_DATA_IN; + ret = spi_nor_read_write_reg(nor, &op, &cr); + if (ret < 0) { + dev_dbg(nor->dev, + "error while reading configuration register\n"); + return -EINVAL; + } + + if (cr & CR_QUAD_EN_SPAN) + return 0; + + /* Write new value. */ + cr |= CR_QUAD_EN_SPAN; + op.cmd.opcode = SPINOR_OP_WRAR; + op.dummy.nbytes = 0; + op.data.dir = SPI_MEM_DATA_OUT; + write_enable(nor); + ret = spi_nor_read_write_reg(nor, &op, &cr); + if (ret < 0) { + dev_dbg(nor->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* Read back and check it. */ + op.cmd.opcode = SPINOR_OP_RDAR; + op.dummy.nbytes = dummy / 8; + op.data.dir = SPI_MEM_DATA_IN; + ret = spi_nor_read_write_reg(nor, &op, &cr); + if (ret || !(cr & CR_QUAD_EN_SPAN)) { + dev_dbg(nor->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + } + + return 0; +} +#endif + static void spi_nor_set_read_settings(struct spi_nor_read_command *read, u8 num_mode_clocks, @@ -583,6 +662,11 @@ static int spi_nor_init_params(struct spi_nor *nor, spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_FAST], 0, 8, SPINOR_OP_READ_FAST, SNOR_PROTO_1_1_1); +#ifdef CONFIG_SPI_FLASH_SPANSION + if (JEDEC_MFR(info) == SNOR_MFR_CYPRESS && + (info->id[1] == 0x2a || info->id[1] == 0x2b)) + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; +#endif } if (info->flags & SPI_NOR_QUAD_READ) { @@ -659,6 +743,11 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info, case SNOR_MFR_MACRONIX: err = macronix_quad_enable(nor); break; +#endif +#ifdef CONFIG_SPI_FLASH_SPANSION + case SNOR_MFR_CYPRESS: + err = spansion_quad_enable_volatile(nor, SZ_128M, 0); + break; #endif case SNOR_MFR_ST: case SNOR_MFR_MICRON: -- 2.25.1