diff options
author | Marek Vasut <marex@denx.de> | 2016-06-20 15:28:36 +0200 |
---|---|---|
committer | Zoltan HERPAI <wigyori@uid0.hu> | 2016-06-20 15:28:36 +0200 |
commit | 870678baa7f8b9a65945237704d84d7724f42459 (patch) | |
tree | 29dba8a076d9e53752b02f768dcdbe15fa9271cd /target/linux/socfpga/patches-4.4/0021-mtd-spi-nor-fix-support-of-Micron-memories.patch | |
parent | 8864b97350bde1fffe614df3c0bfc0cb34fb40d4 (diff) | |
download | master-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.patch | 224 |
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 + |