From 4e094634d1995e279f8bc5eb92463295cb894c76 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 8 Jan 2016 17:02:16 +0100 Subject: [PATCH 19/33] mtd: spi-nor: fix support of Macronix memories This patch fixes the support of Macronix memories. Especially we avoid updating the Status Register when not needed as the Quad Enable (QE) bit is a non-volatile bit. Also we add comments to explain why we use some Fast Read op codes rather than others. Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 81 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 889af12..1b1f5a6 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1107,6 +1107,11 @@ static int macronix_quad_enable(struct spi_nor *nor) val = read_sr(nor); if (val < 0) return val; + + if (likely(val & SR_QUAD_EN_MX)) + return 0; + dev_warn(nor->dev, "Macronix Quad mode disabled, enable it\n"); + write_enable(nor); write_sr(nor, val | SR_QUAD_EN_MX); @@ -1161,21 +1166,73 @@ static int spansion_quad_enable(struct spi_nor *nor) return 0; } +static int macronix_set_quad_mode(struct spi_nor *nor) +{ + int status; + + /* Check whether the QPI mode is enabled. */ + if (nor->read_proto == SNOR_PROTO_4_4_4) { + /* + * Since the QPI mode is enabled, the Quad Enabled (QE) + * non-volatile bit is already set. + * However in QPI mode, only the Fast Read 1-4-4 (0xeb) + * op code is supported. + * WARNING: we should take care about the performance + * enhance toggling bits P0-P7 written during the + * dummy/mode cycles to avoid entering the continuous + * read (performance enhance) mode by mistake! + */ + nor->read_opcode = SPINOR_OP_READ_1_4_4; + return 0; + } + + /* + * The QPI mode is disabled but we still need to set the QE bit: + * this disables the reset and write protect features and + * frees the associated pins so they can be used as the 3rd + * and 4th I/O lines required by Quad SPI commands. + * Also we'd rather use the Fast Read 1-1-4 (0x6b) op code than + * the Fast Read 1-4-4 (0xeb) op code so we don't care about + * entering the continuous read mode by mistake if some + * performance enhance toggling bits P0-P7 were written during + * dummy/mode cycles. + */ + status = macronix_quad_enable(nor); + if (status) { + dev_err(nor->dev, "Macronix quad-read not enabled\n"); + return status; + } + nor->read_proto = SNOR_PROTO_1_1_4; + nor->read_opcode = SPINOR_OP_READ_1_1_4; + return 0; +} + +/* + * For both Macronix Dual and Single modes, we don't care about the value of + * the Quad Enabled (QE) bit since the memory still replies to Dual or Single + * SPI commands. + */ + +static int macronix_set_dual_mode(struct spi_nor *nor) +{ + nor->read_proto = SNOR_PROTO_1_1_2; + nor->read_opcode = SPINOR_OP_READ_1_1_2; + return 0; +} + +static int macronix_set_single_mode(struct spi_nor *nor) +{ + nor->read_proto = SNOR_PROTO_1_1_1; + return 0; +} + static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) { int status; switch (JEDEC_MFR(info)) { case SNOR_MFR_MACRONIX: - status = macronix_quad_enable(nor); - if (status) { - dev_err(nor->dev, "Macronix quad-read not enabled\n"); - return -EINVAL; - } - /* Check whether Macronix QPI mode is enabled. */ - if (nor->read_proto != SNOR_PROTO_4_4_4) - nor->read_proto = SNOR_PROTO_1_1_4; - break; + return macronix_set_quad_mode(nor); case SNOR_MFR_MICRON: /* Check whether Micron Quad mode is enabled. */ @@ -1203,6 +1260,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info) { switch (JEDEC_MFR(info)) { + case SNOR_MFR_MACRONIX: + return macronix_set_dual_mode(nor); + case SNOR_MFR_MICRON: /* Check whether Micron Dual mode is enabled. */ if (nor->read_proto != SNOR_PROTO_2_2_2) @@ -1221,6 +1281,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info) static int set_single_mode(struct spi_nor *nor, const struct flash_info *info) { switch (JEDEC_MFR(info)) { + case SNOR_MFR_MACRONIX: + return macronix_set_single_mode(nor); + default: nor->read_proto = SNOR_PROTO_1_1_1; break; -- 2.8.1