From: Ian Roberts <ian.robe...@timesys.com> ISSI IS25*x series SPIflash chips are capable of Octal IO and DDR. Add spi-nor support to enable and operate in these modes.
Co-developed-by: Nathan Barrett-Morrison <nathan.morri...@timesys.com> Signed-off-by: Nathan Barrett-Morrison <nathan.morri...@timesys.com> Signed-off-by: Greg Malysa <greg.mal...@timesys.com> Signed-off-by: Ian Roberts <ian.robe...@timesys.com> --- drivers/mtd/spi/spi-nor-core.c | 78 ++++++++++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-ids.c | 6 ++- include/linux/mtd/spi-nor.h | 6 +++ 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index f164c3cf73..ce86e53860 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3968,6 +3968,76 @@ static struct spi_nor_fixups macronix_octal_fixups = { }; #endif /* CONFIG_SPI_FLASH_MACRONIX */ +#ifdef CONFIG_SPI_FLASH_ISSI +/** + * spi_nor_issi_octal_dtr_enable() - Enable octal DTR on ISSI flashes. + * @nor: pointer to a 'struct spi_nor' + * + * Return: 0 on success, -errno otherwise. + */ +static int spi_nor_issi_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + int ret; + u8 regval; + + nor->read_dummy = ISSI_MAX_DC; + + ret = write_enable(nor); + if (ret) + return ret; + + regval = SPINOR_REG_ISSI_VCR_ODDR_EN; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_ISSI_WR_VCR, 1), + SPI_MEM_OP_ADDR(3, SPINOR_REG_ISSI_VCR_IOMODE, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, ®val, 1)); + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) { + dev_err(nor->dev, "Failed to enable octal DTR mode\n"); + return ret; + } + + nor->reg_proto = SNOR_PROTO_8_8_8_DTR; + + return 0; +} + +static void issi_octal_default_init(struct spi_nor *nor) +{ + nor->octal_dtr_enable = spi_nor_issi_octal_dtr_enable; +} + +static void issi_octal_post_sfdp_fixup(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* + * Adding SNOR_HWCAPS_PP_8_8_8_DTR in hwcaps.mask when + * SPI_NOR_OCTAL_DTR_READ flag exists. + */ + if (params->hwcaps.mask & SNOR_HWCAPS_READ_8_8_8_DTR) + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + nor->cmd_ext_type = SPI_NOR_EXT_INVERT; + + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, 16, 0x0c, SNOR_PROTO_8_8_8_DTR); + spi_nor_set_pp_settings(¶ms->page_programs[SNOR_CMD_PP_8_8_8_DTR], + 0x12, SNOR_PROTO_8_8_8_DTR); + + params->rdsr_dummy = 8; + + nor->flags |= SNOR_F_IO_MODE_EN_VOLATILE; + nor->flags |= SNOR_F_SOFT_RESET; +} + +static struct spi_nor_fixups issi_octal_dtr_fixups = { + .default_init = issi_octal_default_init, + .post_sfdp = issi_octal_post_sfdp_fixup, +}; +#endif /* CONFIG_SPI_FLASH_ISSI */ + /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed * @nor: pointer to a 'struct spi_nor' * @@ -4161,6 +4231,14 @@ void spi_nor_set_fixups(struct spi_nor *nor) nor->fixups = &mt35xu512aba_fixups; #endif +#if CONFIG_IS_ENABLED(SPI_FLASH_ISSI) + if (JEDEC_MFR(nor->info) == SNOR_MFR_ISSI) { + if ((nor->info->id[1] == 0x5a || nor->info->id[1] == 0x5b) && + (nor->info->id[2] == 0x19 || nor->info->id[2] == 0x18)) + nor->fixups = &issi_octal_dtr_fixups; + } +#endif + #if CONFIG_IS_ENABLED(SPI_FLASH_MACRONIX) nor->fixups = ¯onix_octal_fixups; #endif /* SPI_FLASH_MACRONIX */ diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 4e83b8c94c..e3e37cd79b 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -238,8 +238,12 @@ const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("is25wp01g", 0x9d701b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("is25lx256", 0x9d5a19, 0, 128 * 1024, 256, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ + | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, { INFO("is25wx256", 0x9d5b19, 0, 128 * 1024, 256, - SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, + SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ + | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) }, { INFO("is25lx512", 0x9d5a1a, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_TB) }, #endif diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 2eddb52392..bd364e74a7 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -131,6 +131,12 @@ #define SPINOR_REG_MXIC_DC_20 0x0 /* Setting dummy cycles to 20 */ #define MXIC_MAX_DC 20 /* Maximum value of dummy cycles */ +/* Used for ISSI flashes. */ +#define SPINOR_OP_ISSI_WR_VCR 0x81 +#define SPINOR_REG_ISSI_VCR_IOMODE 0x0 +#define SPINOR_REG_ISSI_VCR_ODDR_EN 0xe7 +#define ISSI_MAX_DC 16 + /* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */ #define SPINOR_OP_BRRD 0x16 /* Bank register read */ -- 2.43.2