@@ -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 */
@@ -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
@@ -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 */