[PATCH 0/3] mtd: spi-nor-core: Add support for mx66lm1g45g

Add support for mx66lm1g45g: - Introduce SPI_NOR_SOFT_RESET flash_info flag -> the flash does not define the SFDP tables and can't determine its reset sequence on its own. - Fix the opcode extension for the software reset sequence -> it was hardcoded.
Tudor Ambarus (3): mtd: spi-nor-core: Introduce SPI_NOR_SOFT_RESET flash_info flag mtd: spi-nor-core: macronix: Add support for mx66lm1g45g mtd: spi-nor-core: Fix the opcode extension for the software reset sequence
drivers/mtd/spi/Kconfig | 8 +++ drivers/mtd/spi/sf_internal.h | 5 ++ drivers/mtd/spi/spi-nor-core.c | 89 ++++++++++++++++++++++++++++++---- drivers/mtd/spi/spi-nor-ids.c | 6 +++ include/linux/mtd/spi-nor.h | 8 +++ 5 files changed, 107 insertions(+), 9 deletions(-)

Some flashes can determine if Soft Reset is supported by parsing BFPT_DWORD(16). There are however flashes that do not define any of the SFDP tables, so they can't discover this capability at SFDP parsing time. For such cases introduce the SPI_NOR_SOFT_RESET flash_info flag to be able to specify statically this support. This flag must be used together with the SPI_NOR_SKIP_SFDP flag. For flashes that support Soft Reset and define BFPT, but have the BFPT_DWORD(16) missing or with a wrong value, a post_sfdp() fixup hook should be used instead, where SNOR_F_SOFT_RESET should be set.
Signed-off-by: Tudor Ambarus tudor.ambarus@microchip.com --- drivers/mtd/spi/sf_internal.h | 5 +++++ drivers/mtd/spi/spi-nor-core.c | 3 +++ 2 files changed, 8 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index d3ef69ec74..9a16e07bc4 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -69,6 +69,11 @@ struct flash_info { #define SPI_NOR_HAS_SST26LOCK BIT(15) /* Flash supports lock/unlock via BPR */ #define SPI_NOR_OCTAL_READ BIT(16) /* Flash supports Octal Read */ #define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */ +#define SPI_NOR_SOFT_RESET BIT(18) /* + * Used by flashes that do not define + * any SFDP tables, i.e. in conjunction + * with SPI_NOR_SKIP_SFDP. + */ };
extern const struct flash_info spi_nor_ids[]; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 4388a08a90..ce1ecae899 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3813,6 +3813,9 @@ int spi_nor_scan(struct spi_nor *nor) if (info->flags & SPI_NOR_NO_ERASE) mtd->flags |= MTD_NO_ERASE;
+ if (info->flags & SPI_NOR_SOFT_RESET) + nor->flags |= SNOR_F_SOFT_RESET; + nor->page_size = params.page_size; mtd->writebufsize = nor->page_size;

mx66lm1g45g supports just 1-1-1, 8-8-8 and 8d-8d-8d modes. Tested in 1-1-1 and 8d-8d-8d modes using microchip's Octal SPI IP.
Signed-off-by: Tudor Ambarus tudor.ambarus@microchip.com --- drivers/mtd/spi/Kconfig | 8 ++++ drivers/mtd/spi/spi-nor-core.c | 74 ++++++++++++++++++++++++++++++++++ drivers/mtd/spi/spi-nor-ids.c | 6 +++ include/linux/mtd/spi-nor.h | 8 ++++ 4 files changed, 96 insertions(+)
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 408a53f861..2d2b71c52d 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -160,6 +160,14 @@ config SPI_FLASH_MACRONIX help Add support for various Macronix SPI flash chips (MX25Lxxx)
+config SPI_FLASH_MX66LM1G45G + bool "Macronix MX66LM1G45G chip support" + depends on SPI_FLASH_MACRONIX + help + Add support for the Macronix mx66lm1g45g chip. This is a separate + config because the fixup hooks for this flash add extra size overhead. + Boards that don't use the flash can disable this to save space. + config SPI_FLASH_SPANSION bool "Spansion SPI flash support" help diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index ce1ecae899..df66a73495 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3526,6 +3526,75 @@ static struct spi_nor_fixups mt35xu512aba_fixups = { }; #endif /* CONFIG_SPI_FLASH_MT35XU */
+#ifdef CONFIG_SPI_FLASH_MX66LM1G45G +static int spi_nor_macronix_octal_dtr_enable(struct spi_nor *nor) +{ + struct spi_mem_op op; + u8 buf; + int ret; + + /* Use 20 dummy cycles for memory array reads. */ + buf = SPINOR_REG_CR2_DUMMY_20; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRITE_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_CR2_DUMMY_ADDR, + 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = write_enable(nor); + if (ret) + return ret; + + ret = spi_mem_exec_op(nor->spi, &op); + if (ret) + return ret; + + ret = spi_nor_wait_till_ready(nor); + if (ret) + return ret; + + buf = SPINOR_REG_CR2_DTR_OPI_ENABLE; + op = (struct spi_mem_op) + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRITE_CR2, 1), + SPI_MEM_OP_ADDR(4, SPINOR_REG_CR2_MODE_ADDR, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, &buf, 1)); + + ret = write_enable(nor); + if (ret) + return ret; + + return spi_mem_exec_op(nor->spi, &op); +} + +static void mx66lm1g45g_default_init(struct spi_nor *nor) +{ + nor->octal_dtr_enable = spi_nor_macronix_octal_dtr_enable; +} + +static void mx66lm1g45g_post_sfdp(struct spi_nor *nor, + struct spi_nor_flash_parameter *params) +{ + /* Set the Fast Read settings. */ + params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; + spi_nor_set_read_settings(¶ms->reads[SNOR_CMD_READ_8_8_8_DTR], + 0, 20, SPINOR_OP_MX_DTR_RD, + SNOR_PROTO_8_8_8_DTR); + + params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR; + + nor->cmd_ext_type = SPI_NOR_EXT_INVERT; + params->rdsr_dummy = 4; + params->rdsr_addr_nbytes = 4; +} + +static struct spi_nor_fixups mx66lm1g45g_fixups = { + .default_init = mx66lm1g45g_default_init, + .post_sfdp = mx66lm1g45g_post_sfdp, +}; +#endif /* CONFIG_SPI_FLASH_MX66LM1G45G */ + /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed * @nor: pointer to a 'struct spi_nor' * @@ -3696,6 +3765,11 @@ void spi_nor_set_fixups(struct spi_nor *nor) if (!strcmp(nor->info->name, "mt35xu512aba")) nor->fixups = &mt35xu512aba_fixups; #endif + +#ifdef CONFIG_SPI_FLASH_MX66LM1G45G + if (!strcmp(nor->info->name, "mx66lm1g45g")) + nor->fixups = &mx66lm1g45g_fixups; +#endif }
int spi_nor_scan(struct spi_nor *nor) diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 3ae7bb1ed7..d5bc106e68 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -179,6 +179,12 @@ const struct flash_info spi_nor_ids[] = { { INFO("mx25l1633e", 0xc22415, 0, 64 * 1024, 32, SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SECT_4K) }, { INFO("mx25r6435f", 0xc22817, 0, 64 * 1024, 128, SECT_4K) }, { INFO("mx66uw2g345g", 0xc2943c, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_OCTAL_READ | SPI_NOR_4B_OPCODES) }, +#ifdef CONFIG_SPI_FLASH_MX66LM1G45G + { INFO("mx66lm1g45g", 0xc2853b, 0, 64 * 1024, 2048, + SPI_NOR_SKIP_SFDP | SPI_NOR_SOFT_RESET | + SECT_4K | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_4B_OPCODES) + }, +#endif #endif
#ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4ceeae623d..c8b8a242ba 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -119,6 +119,14 @@ /* Used for Macronix and Winbond flashes. */ #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */ #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */ +#define SPINOR_OP_READ_CR2 0x71 +#define SPINOR_OP_WRITE_CR2 0x72 +#define SPINOR_OP_MX_DTR_RD 0xee +#define SPINOR_REG_CR2_MODE_ADDR 0 +#define SPINOR_REG_CR2_DTR_OPI_ENABLE BIT(1) +#define SPINOR_REG_CR2_SPI 0 +#define SPINOR_REG_CR2_DUMMY_ADDR 0x300 +#define SPINOR_REG_CR2_DUMMY_20 0
/* Used for Spansion flashes only. */ #define SPINOR_OP_BRWR 0x17 /* Bank register write */

It was always hardcoded to SPI_NOR_EXT_REPEAT, while there are flashes that may use an SPI_NOR_EXT_INVERT opcode extension (mx66lm1g45g). Remove the hardcoded value and let flashes use their per flash opcode extension type.
Signed-off-by: Tudor Ambarus tudor.ambarus@microchip.com --- drivers/mtd/spi/spi-nor-core.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index df66a73495..35327307a7 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -3685,10 +3685,6 @@ static int spi_nor_soft_reset(struct spi_nor *nor) { struct spi_mem_op op; int ret; - enum spi_nor_cmd_ext ext; - - ext = nor->cmd_ext_type; - nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 0), SPI_MEM_OP_NO_DUMMY, @@ -3698,7 +3694,7 @@ static int spi_nor_soft_reset(struct spi_nor *nor) ret = spi_mem_exec_op(nor->spi, &op); if (ret) { dev_warn(nor->dev, "Software reset enable failed: %d\n", ret); - goto out; + return ret; }
op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 0), @@ -3709,7 +3705,7 @@ static int spi_nor_soft_reset(struct spi_nor *nor) ret = spi_mem_exec_op(nor->spi, &op); if (ret) { dev_warn(nor->dev, "Software reset failed: %d\n", ret); - goto out; + return ret; }
/* @@ -3719,9 +3715,7 @@ static int spi_nor_soft_reset(struct spi_nor *nor) */ udelay(SPI_NOR_SRST_SLEEP_LEN);
-out: - nor->cmd_ext_type = ext; - return ret; + return 0; } #endif /* CONFIG_SPI_FLASH_SOFT_RESET */
participants (1)
-
Tudor Ambarus