182 lines
6.5 KiB
Diff
182 lines
6.5 KiB
Diff
|
From 924f021c0344554a4b61746e5c4dcfc91d618ce2 Mon Sep 17 00:00:00 2001
|
||
|
From: Yunhui Cui <yunhui.cui@nxp.com>
|
||
|
Date: Thu, 18 Feb 2016 16:41:53 +0800
|
||
|
Subject: [PATCH 105/113] mtd: spi-nor: add DDR quad read support
|
||
|
|
||
|
This patch adds the DDR quad read support by the following:
|
||
|
|
||
|
[1] add SPI_NOR_DDR_QUAD read mode.
|
||
|
|
||
|
[2] add DDR Quad read opcodes:
|
||
|
SPINOR_OP_READ_1_4_4_D / SPINOR_OP_READ4_1_4_4_D
|
||
|
|
||
|
[3] add set_ddr_quad_mode() to initialize for the DDR quad read.
|
||
|
Currently it only works for Spansion NOR.
|
||
|
|
||
|
[4] set dummy with 6 for Spansion family
|
||
|
Test this patch for Spansion s25fl128s NOR flash.
|
||
|
|
||
|
Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
|
||
|
---
|
||
|
drivers/mtd/spi-nor/spi-nor.c | 53 ++++++++++++++++++++++++++++++++++++-----
|
||
|
include/linux/mtd/spi-nor.h | 8 +++++--
|
||
|
2 files changed, 53 insertions(+), 8 deletions(-)
|
||
|
|
||
|
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||
|
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||
|
@@ -73,7 +73,8 @@ struct flash_info {
|
||
|
#define SECT_4K_PMC 0x10 /* SPINOR_OP_BE_4K_PMC works uniformly */
|
||
|
#define SPI_NOR_DUAL_READ 0x20 /* Flash supports Dual Read */
|
||
|
#define SPI_NOR_QUAD_READ 0x40 /* Flash supports Quad Read */
|
||
|
-#define USE_FSR 0x80 /* use flag status register */
|
||
|
+#define SPI_NOR_DDR_QUAD_READ 0x80 /* Flash supports DDR Quad Read */
|
||
|
+#define USE_FSR 0x100 /* use flag status register */
|
||
|
};
|
||
|
|
||
|
#define JEDEC_MFR(info) ((info)->id[0])
|
||
|
@@ -144,13 +145,17 @@ static int read_cr(struct spi_nor *nor)
|
||
|
* It can be used to support more commands with
|
||
|
* different dummy cycle requirements.
|
||
|
*/
|
||
|
-static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
|
||
|
+static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor,
|
||
|
+ const struct flash_info *info)
|
||
|
{
|
||
|
switch (nor->flash_read) {
|
||
|
case SPI_NOR_FAST:
|
||
|
case SPI_NOR_DUAL:
|
||
|
case SPI_NOR_QUAD:
|
||
|
return 8;
|
||
|
+ case SPI_NOR_DDR_QUAD:
|
||
|
+ if (JEDEC_MFR(info) == SNOR_MFR_SPANSION)
|
||
|
+ return 6;
|
||
|
case SPI_NOR_NORMAL:
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -797,7 +802,8 @@ static const struct flash_info spi_nor_i
|
||
|
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
|
||
|
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
|
||
|
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
|
||
|
- { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) },
|
||
|
+ { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ
|
||
|
+ | SPI_NOR_DDR_QUAD_READ) },
|
||
|
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||
|
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||
|
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
|
||
|
@@ -1186,6 +1192,23 @@ static int spansion_quad_enable(struct s
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
|
||
|
+{
|
||
|
+ int status;
|
||
|
+
|
||
|
+ switch (JEDEC_MFR(info)) {
|
||
|
+ case SNOR_MFR_SPANSION:
|
||
|
+ status = spansion_quad_enable(nor);
|
||
|
+ if (status) {
|
||
|
+ dev_err(nor->dev, "Spansion DDR quad-read not enabled\n");
|
||
|
+ return status;
|
||
|
+ }
|
||
|
+ return status;
|
||
|
+ default:
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
|
||
|
{
|
||
|
int status;
|
||
|
@@ -1375,8 +1398,15 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||
|
if (info->flags & SPI_NOR_NO_FR)
|
||
|
nor->flash_read = SPI_NOR_NORMAL;
|
||
|
|
||
|
- /* Quad/Dual-read mode takes precedence over fast/normal */
|
||
|
- if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
|
||
|
+ /* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */
|
||
|
+ if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) {
|
||
|
+ ret = set_ddr_quad_mode(nor, info);
|
||
|
+ if (ret) {
|
||
|
+ dev_err(dev, "DDR quad mode not supported\n");
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+ nor->flash_read = SPI_NOR_DDR_QUAD;
|
||
|
+ } else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) {
|
||
|
ret = set_quad_mode(nor, info);
|
||
|
if (ret) {
|
||
|
dev_err(dev, "quad mode not supported\n");
|
||
|
@@ -1389,6 +1419,14 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||
|
|
||
|
/* Default commands */
|
||
|
switch (nor->flash_read) {
|
||
|
+ case SPI_NOR_DDR_QUAD:
|
||
|
+ if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { /* Spansion */
|
||
|
+ nor->read_opcode = SPINOR_OP_READ_1_4_4_D;
|
||
|
+ } else {
|
||
|
+ dev_err(dev, "DDR Quad Read is not supported.\n");
|
||
|
+ return -EINVAL;
|
||
|
+ }
|
||
|
+ break;
|
||
|
case SPI_NOR_QUAD:
|
||
|
nor->read_opcode = SPINOR_OP_READ_1_1_4;
|
||
|
break;
|
||
|
@@ -1416,6 +1454,9 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||
|
if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) {
|
||
|
/* Dedicated 4-byte command set */
|
||
|
switch (nor->flash_read) {
|
||
|
+ case SPI_NOR_DDR_QUAD:
|
||
|
+ nor->read_opcode = SPINOR_OP_READ4_1_4_4_D;
|
||
|
+ break;
|
||
|
case SPI_NOR_QUAD:
|
||
|
nor->read_opcode = SPINOR_OP_READ4_1_1_4;
|
||
|
break;
|
||
|
@@ -1445,7 +1486,7 @@ int spi_nor_scan(struct spi_nor *nor, co
|
||
|
return -EINVAL;
|
||
|
}
|
||
|
|
||
|
- nor->read_dummy = spi_nor_read_dummy_cycles(nor);
|
||
|
+ nor->read_dummy = spi_nor_read_dummy_cycles(nor, info);
|
||
|
|
||
|
dev_info(dev, "%s (%lld Kbytes)\n", info->name,
|
||
|
(long long)mtd->size >> 10);
|
||
|
--- a/include/linux/mtd/spi-nor.h
|
||
|
+++ b/include/linux/mtd/spi-nor.h
|
||
|
@@ -30,10 +30,11 @@
|
||
|
|
||
|
/*
|
||
|
* Note on opcode nomenclature: some opcodes have a format like
|
||
|
- * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number
|
||
|
+ * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y,and z stand for the number
|
||
|
* of I/O lines used for the opcode, address, and data (respectively). The
|
||
|
* FUNCTION has an optional suffix of '4', to represent an opcode which
|
||
|
- * requires a 4-byte (32-bit) address.
|
||
|
+ * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the
|
||
|
+ * DDR mode.
|
||
|
*/
|
||
|
|
||
|
/* Flash opcodes. */
|
||
|
@@ -44,6 +45,7 @@
|
||
|
#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
|
||
|
#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
|
||
|
#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
|
||
|
+#define SPINOR_OP_READ_1_4_4_D 0xed /* Read data bytes (DDR Quad SPI) */
|
||
|
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
|
||
|
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
|
||
|
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
|
||
|
@@ -59,6 +61,7 @@
|
||
|
#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */
|
||
|
#define SPINOR_OP_READ4_1_1_2 0x3c /* Read data bytes (Dual SPI) */
|
||
|
#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */
|
||
|
+#define SPINOR_OP_READ4_1_4_4_D 0xee /* Read data bytes (DDR Quad SPI) */
|
||
|
#define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */
|
||
|
#define SPINOR_OP_SE_4B 0xdc /* Sector erase (usually 64KiB) */
|
||
|
|
||
|
@@ -107,6 +110,7 @@ enum read_mode {
|
||
|
SPI_NOR_FAST,
|
||
|
SPI_NOR_DUAL,
|
||
|
SPI_NOR_QUAD,
|
||
|
+ SPI_NOR_DDR_QUAD,
|
||
|
};
|
||
|
|
||
|
#define SPI_NOR_MAX_CMD_SIZE 8
|