diff options
| author | Bean Huo 霍斌斌 (beanhuo) <beanhuo@micron.com> | 2014-12-17 02:35:45 -0500 |
|---|---|---|
| committer | Brian Norris <computersforpeace@gmail.com> | 2015-01-07 14:33:22 -0500 |
| commit | 548cd3ab54da10f896daa7ca422236847a915734 (patch) | |
| tree | b639d9d85db919c3ddfbf4be097cd25ab08f7e87 /drivers/mtd | |
| parent | ed0215cc3b5292fc0f4af70e29dc61fa2d0aa76c (diff) | |
mtd: spi-nor: Add quad I/O support for Micron SPI NOR
This patch adds code which enables Quad I/O mode on Micron SPI NOR flashes.
For Micron SPI NOR flash, enabling or disabling quad I/O protocol can be
done By two methods, which are to use EVCR (Enhanced Volatile
Configuration Register) and the ENTER QUAD I/O MODE command. There is no
difference between these two methods. Unfortunately, for some Micron SPI
NOR flashes, there no ENTER Quad I/O command (35h), such as n25q064. But
for all current Micron SPI NOR, if it support quad I/O mode, using EVCR
definitely be supported. It is a recommended method to enable Quad I/O
mode by EVCR, Quad I/O protocol bit 7. When EVCR bit 7 is reset to 0,
the SPI NOR flash will operate in quad I/O mode.
This patch has been tested on N25Q512A and MT25TL256BAA1ESF. Micron SPI
NOR of spi_nor_ids[] table all support this method.
Signed-off-by: Bean Huo <beanhuo@micron.com>
Acked-by: Marek Vasut <marex@denx.de>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
| -rw-r--r-- | drivers/mtd/spi-nor/spi-nor.c | 62 |
1 files changed, 54 insertions, 8 deletions
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 0f8ec3c2d015..ea196c18dec9 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c | |||
| @@ -560,14 +560,14 @@ static const struct spi_device_id spi_nor_ids[] = { | |||
| 560 | { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, | 560 | { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, |
| 561 | 561 | ||
| 562 | /* Micron */ | 562 | /* Micron */ |
| 563 | { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) }, | 563 | { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, |
| 564 | { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, | 564 | { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) }, |
| 565 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) }, | 565 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, |
| 566 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) }, | 566 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, |
| 567 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) }, | 567 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, |
| 568 | { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) }, | 568 | { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
| 569 | { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) }, | 569 | { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
| 570 | { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) }, | 570 | { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, |
| 571 | 571 | ||
| 572 | /* PMC */ | 572 | /* PMC */ |
| 573 | { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, | 573 | { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, |
| @@ -891,6 +891,45 @@ static int spansion_quad_enable(struct spi_nor *nor) | |||
| 891 | return 0; | 891 | return 0; |
| 892 | } | 892 | } |
| 893 | 893 | ||
| 894 | static int micron_quad_enable(struct spi_nor *nor) | ||
| 895 | { | ||
| 896 | int ret; | ||
| 897 | u8 val; | ||
| 898 | |||
| 899 | ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); | ||
| 900 | if (ret < 0) { | ||
| 901 | dev_err(nor->dev, "error %d reading EVCR\n", ret); | ||
| 902 | return ret; | ||
| 903 | } | ||
| 904 | |||
| 905 | write_enable(nor); | ||
| 906 | |||
| 907 | /* set EVCR, enable quad I/O */ | ||
| 908 | nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON; | ||
| 909 | ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0); | ||
| 910 | if (ret < 0) { | ||
| 911 | dev_err(nor->dev, "error while writing EVCR register\n"); | ||
| 912 | return ret; | ||
| 913 | } | ||
| 914 | |||
| 915 | ret = spi_nor_wait_till_ready(nor); | ||
| 916 | if (ret) | ||
| 917 | return ret; | ||
| 918 | |||
| 919 | /* read EVCR and check it */ | ||
| 920 | ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1); | ||
| 921 | if (ret < 0) { | ||
| 922 | dev_err(nor->dev, "error %d reading EVCR\n", ret); | ||
| 923 | return ret; | ||
| 924 | } | ||
| 925 | if (val & EVCR_QUAD_EN_MICRON) { | ||
| 926 | dev_err(nor->dev, "Micron EVCR Quad bit not clear\n"); | ||
| 927 | return -EINVAL; | ||
| 928 | } | ||
| 929 | |||
| 930 | return 0; | ||
| 931 | } | ||
| 932 | |||
| 894 | static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) | 933 | static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) |
| 895 | { | 934 | { |
| 896 | int status; | 935 | int status; |
| @@ -903,6 +942,13 @@ static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) | |||
| 903 | return -EINVAL; | 942 | return -EINVAL; |
| 904 | } | 943 | } |
| 905 | return status; | 944 | return status; |
| 945 | case CFI_MFR_ST: | ||
| 946 | status = micron_quad_enable(nor); | ||
| 947 | if (status) { | ||
| 948 | dev_err(nor->dev, "Micron quad-read not enabled\n"); | ||
| 949 | return -EINVAL; | ||
| 950 | } | ||
| 951 | return status; | ||
| 906 | default: | 952 | default: |
| 907 | status = spansion_quad_enable(nor); | 953 | status = spansion_quad_enable(nor); |
| 908 | if (status) { | 954 | if (status) { |
