diff options
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.patch | 179 |
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 + |