aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch')
-rw-r--r--target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch179
1 files changed, 179 insertions, 0 deletions
diff --git a/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch b/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
new file mode 100644
index 0000000000..e41fd3fff7
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0020-mtd-spi-nor-fix-support-of-Winbond-memories.patch
@@ -0,0 +1,179 @@
+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
+