123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- From 96b232d03a0c4462eacf879ed80b0cfd235e65c4 Mon Sep 17 00:00:00 2001
- From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
- Date: Fri, 8 Jan 2016 17:02:17 +0100
- Subject: [PATCH 20/33] mtd: spi-nor: fix support of Winbond memories
- This patch fixes the support of Winbond memories. Indeed, before
- performing any Quad SPI command, the Quad Enable (QE) non-volatile bit
- MUST be set in the Status Register 2.
- According to the w25q16fw datasheet from Winbond:
- "When QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3."
- Quad SPI instructions requires the bidirectional IO2 and IO3 pins.
- Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
- ---
- drivers/mtd/spi-nor/spi-nor.c | 100 ++++++++++++++++++++++++++++++++++++++++++
- include/linux/mtd/spi-nor.h | 6 +++
- 2 files changed, 106 insertions(+)
- diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
- index 1b1f5a6..aa7d26d 100644
- --- a/drivers/mtd/spi-nor/spi-nor.c
- +++ b/drivers/mtd/spi-nor/spi-nor.c
- @@ -1166,6 +1166,40 @@ static int spansion_quad_enable(struct spi_nor *nor)
- return 0;
- }
-
- +static int winbond_quad_enable(struct spi_nor *nor)
- +{
- + int ret;
- + u8 sr2;
- +
- + ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
- + if (ret < 0)
- + return ret;
- +
- + if (likely(sr2 & SR2_QUAD_EN_WINB))
- + return 0;
- + dev_warn(nor->dev, "Winbond Quad mode disabled, enable it\n");
- +
- + write_enable(nor);
- +
- + sr2 |= SR2_QUAD_EN_WINB;
- + ret = nor->write_reg(nor, SPINOR_OP_WRSR2_WINB, &sr2, 1);
- + if (ret < 0)
- + return ret;
- +
- + if (spi_nor_wait_till_ready(nor))
- + return -EIO;
- +
- + ret = nor->read_reg(nor, SPINOR_OP_RDSR2_WINB, &sr2, 1);
- + if (ret < 0)
- + return ret;
- + if (!(sr2 & SR2_QUAD_EN_WINB)) {
- + dev_err(nor->dev, "Winbond Quad bit not set\n");
- + return -EINVAL;
- + }
- +
- + return 0;
- +}
- +
- static int macronix_set_quad_mode(struct spi_nor *nor)
- {
- int status;
- @@ -1226,6 +1260,63 @@ static int macronix_set_single_mode(struct spi_nor *nor)
- return 0;
- }
-
- +static int winbond_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.
- + * If the Fast Read 1-4-4 (0xeb) were used, we should
- + * take care about the value M7-M0 written during
- + * dummy/mode cycles to avoid entering the continuous
- + * read mode by mistake.
- + * Also the Fast Read 1-1-4 (0x6b) op code is not
- + * supported in QPI mode.
- + * Hence the Fast Read 1-1-1 (0x0b) op code is chosen.
- + */
- + nor->read_opcode = SPINOR_OP_READ_FAST;
- + return 0;
- + }
- +
- + /*
- + * The QPI mode is disabled but we still need to set the QE bit:
- + * when QE=1, the /WP pin becomes IO2 and /HOLD pin becomes IO3.
- + * If the Fast Read 1-4-4 (0xeb) were used, we should take care
- + * about the value M7-M0 written during dummy/mode cycles to
- + * avoid entering the continuous read mode by mistake.
- + * Hence the Fast Read 1-1-4 (0x6b) op code is preferred.
- + */
- + status = winbond_quad_enable(nor);
- + if (status) {
- + dev_err(nor->dev, "Winbond quad-read nor 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 Winbond 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 winbond_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 winbond_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;
- @@ -1234,6 +1325,9 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
- case SNOR_MFR_MACRONIX:
- return macronix_set_quad_mode(nor);
-
- + case SNOR_MFR_WINBOND:
- + return winbond_set_quad_mode(nor);
- +
- case SNOR_MFR_MICRON:
- /* Check whether Micron Quad mode is enabled. */
- if (nor->read_proto != SNOR_PROTO_4_4_4)
- @@ -1263,6 +1357,9 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
- case SNOR_MFR_MACRONIX:
- return macronix_set_dual_mode(nor);
-
- + case SNOR_MFR_WINBOND:
- + return winbond_set_dual_mode(nor);
- +
- case SNOR_MFR_MICRON:
- /* Check whether Micron Dual mode is enabled. */
- if (nor->read_proto != SNOR_PROTO_2_2_2)
- @@ -1284,6 +1381,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
- case SNOR_MFR_MACRONIX:
- return macronix_set_single_mode(nor);
-
- + case SNOR_MFR_WINBOND:
- + return winbond_set_single_mode(nor);
- +
- default:
- nor->read_proto = SNOR_PROTO_1_1_1;
- break;
- diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
- index 89e3228..46343f5 100644
- --- a/include/linux/mtd/spi-nor.h
- +++ b/include/linux/mtd/spi-nor.h
- @@ -75,6 +75,12 @@
- #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
- #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
-
- +/* Used for Winbond flashes only. */
- +#define SPINOR_OP_RDSR2_WINB 0x35 /* Read status register 2 */
- +#define SPINOR_OP_WRSR2_WINB 0x31 /* Write status register 2 */
- +
- +#define SR2_QUAD_EN_WINB BIT(1) /* Quad Enable bit */
- +
- /* Used for Spansion flashes only. */
- #define SPINOR_OP_BRWR 0x17 /* Bank register write */
-
- --
- 2.8.1
|