aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2016-06-20 15:28:36 +0200
committerZoltan HERPAI <wigyori@uid0.hu>2016-06-20 15:28:36 +0200
commit870678baa7f8b9a65945237704d84d7724f42459 (patch)
tree29dba8a076d9e53752b02f768dcdbe15fa9271cd /target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
parent8864b97350bde1fffe614df3c0bfc0cb34fb40d4 (diff)
downloadmaster-187ad058-870678baa7f8b9a65945237704d84d7724f42459.tar.gz
master-187ad058-870678baa7f8b9a65945237704d84d7724f42459.tar.bz2
master-187ad058-870678baa7f8b9a65945237704d84d7724f42459.zip
target: socfpga: Add support for QSPI NOR boot
Add necessary kernel backports to support the Cadence QSPI controller present on the Altera SoCFPGA SoC. Signed-off-by: Marek Vasut <marex@denx.de>
Diffstat (limited to 'target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch')
-rw-r--r--target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch224
1 files changed, 224 insertions, 0 deletions
diff --git a/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch b/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
new file mode 100644
index 0000000000..83d79ab90d
--- /dev/null
+++ b/target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch
@@ -0,0 +1,224 @@
+From 0cd0df6b3583920ab9231035e533560b58e71a50 Mon Sep 17 00:00:00 2001
+From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+Date: Fri, 8 Jan 2016 17:02:18 +0100
+Subject: [PATCH 21/33] mtd: spi-nor: fix support of Micron memories
+
+This patch adds missing mode transitions. Indeed depending on both the
+current memory mode and the new protocol wanted by the user, we may need
+to perform a switch back to the Extended SPI mode.
+
+However when the current mode is the Quad mode and the user has asked for
+a Quad SPI protocol, we'd rather stay in Quad mode and use the Fast Read
+4-4-4 command than switch to the Extended SPI mode and use the Fast Read
+1-1-4 command.
+
+Also we'd rather stay in Dual mode than swith to the Extended SPI mode
+whenever the user has asked for Dual SPI protocol.
+
+Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+---
+ drivers/mtd/spi-nor/spi-nor.c | 154 +++++++++++++++++++++++++++++++++++++++---
+ include/linux/mtd/spi-nor.h | 1 +
+ 2 files changed, 147 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
+index aa7d26d..ae2cbac 100644
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1317,6 +1317,147 @@ static int winbond_set_single_mode(struct spi_nor *nor)
+ return 0;
+ }
+
++static int micron_set_protocol(struct spi_nor *nor, u8 mask, u8 val,
++ enum spi_nor_protocol proto)
++{
++ u8 evcr;
++ int ret;
++
++ /* Read the Enhanced Volatile Configuration Register (EVCR). */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while reading EVCR register\n");
++ return ret;
++ }
++
++ /* Check whether we need to update the protocol bits. */
++ if ((evcr & mask) == val)
++ return 0;
++
++ /* Set EVCR protocol bits. */
++ write_enable(nor);
++ evcr = (evcr & ~mask) | val;
++ ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, &evcr, 1);
++ if (ret < 0) {
++ dev_err(nor->dev, "error while writing EVCR register\n");
++ return ret;
++ }
++
++ /* Switch reg protocol now before accessing any other registers. */
++ nor->reg_proto = proto;
++
++ ret = spi_nor_wait_till_ready(nor);
++ if (ret)
++ return ret;
++
++ /* Read EVCR and check it. */
++ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
++ if (ret < 0 || (evcr & mask) != val) {
++ dev_err(nor->dev, "Micron EVCR protocol bits not updated\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int micron_set_extended_spi_protocol(struct spi_nor *nor)
++{
++ int ret;
++
++ /* Set Quad/Dual bits to 11 to select the Extended SPI mode */
++ ret = micron_set_protocol(nor,
++ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
++ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
++ SNOR_PROTO_1_1_1);
++ if (ret) {
++ dev_err(nor->dev, "Failed to set Micron Extended SPI mode\n");
++ return ret;
++ }
++
++ nor->write_proto = SNOR_PROTO_1_1_1;
++ nor->erase_proto = SNOR_PROTO_1_1_1;
++ return 0;
++}
++
++static int micron_set_quad_mode(struct spi_nor *nor)
++{
++ /* Check whether the Dual SPI mode is enabled. */
++ if (unlikely(nor->read_proto == SNOR_PROTO_2_2_2)) {
++ int ret;
++
++ /*
++ * Exit Micron Dual mode and switch to the Extended SPI mode:
++ * we can change the mode safely as we write into a volatile
++ * register.
++ * Also the Quad mode is not worth it for MTD usages: it
++ * should only be relevant for eXecution In Place (XIP) usages,
++ * which are out of the scope of the spi-nor framework.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Whatever the Quad mode is enabled or not, the
++ * Fast Read Quad Output 1-1-4 (0x6b) op code is supported.
++ */
++ if (nor->read_proto != SNOR_PROTO_4_4_4)
++ nor->read_proto = SNOR_PROTO_1_1_4;
++ nor->read_opcode = SPINOR_OP_READ_1_1_4;
++ return 0;
++}
++
++static int micron_set_dual_mode(struct spi_nor *nor)
++{
++ /* Check whether Quad mode is enabled. */
++ if (unlikely(nor->read_proto == SNOR_PROTO_4_4_4)) {
++ int ret;
++
++ /*
++ * Exit Micron Quad mode and switch to the Extended SPI mode:
++ * we can change the mode safely as we write into a volatile
++ * register.
++ * Also the Dual mode is not worth it for MTD usages: it
++ * should only be relevant for eXecution In Place (XIP) usages,
++ * which are out of the scope of the spi-nor framework.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * Whatever the Dual mode is enabled or not, the
++ * Fast Read Dual Output 1-1-2 (0x3b) op code is supported.
++ */
++ if (nor->read_proto != SNOR_PROTO_2_2_2)
++ nor->read_proto = SNOR_PROTO_1_1_2;
++ nor->read_opcode = SPINOR_OP_READ_1_1_2;
++ return 0;
++}
++
++static int micron_set_single_mode(struct spi_nor *nor)
++{
++ /* Check whether either the Dual or Quad mode is enabled. */
++ if (unlikely(nor->read_proto != SNOR_PROTO_1_1_1)) {
++ int ret;
++
++ /*
++ * Exit Micron Dual or Quad mode and switch to the Extended SPI
++ * mode: we can change the mode safely as we write into a
++ * volatile register.
++ */
++ ret = micron_set_extended_spi_protocol(nor);
++ if (ret)
++ return ret;
++
++ 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;
+@@ -1329,10 +1470,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+ 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)
+- nor->read_proto = SNOR_PROTO_1_1_4;
+- break;
++ return micron_set_quad_mode(nor);
+
+ case SNOR_MFR_SPANSION:
+ status = spansion_quad_enable(nor);
+@@ -1361,10 +1499,7 @@ static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info)
+ 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)
+- nor->read_proto = SNOR_PROTO_1_1_2;
+- break;
++ return micron_set_dual_mode(nor);
+
+ default:
+ nor->read_proto = SNOR_PROTO_1_1_2;
+@@ -1384,6 +1519,9 @@ static int set_single_mode(struct spi_nor *nor, const struct flash_info *info)
+ case SNOR_MFR_WINBOND:
+ return winbond_set_single_mode(nor);
+
++ case SNOR_MFR_MICRON:
++ return micron_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 46343f5..d0a6f34 100644
+--- a/include/linux/mtd/spi-nor.h
++++ b/include/linux/mtd/spi-nor.h
+@@ -102,6 +102,7 @@
+
+ /* Enhanced Volatile Configuration Register bits */
+ #define EVCR_QUAD_EN_MICRON BIT(7) /* Micron Quad I/O */
++#define EVCR_DUAL_EN_MICRON BIT(6) /* Micron Dual I/O */
+
+ /* Flag Status Register bits */
+ #define FSR_READY BIT(7)
+--
+2.8.1
+