MLK-11941: mtd: spi-nor: add DDR quad read support
authorHan Xu <b45815@freescale.com>
Tue, 3 Nov 2015 22:52:25 +0000 (16:52 -0600)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:49:21 +0000 (14:49 -0500)
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.

[3] about the dummy cycles.
    We set the dummy with 8 for DDR quad read by default.
    The m25p80.c can not support the DDR quad read, but the SPI NOR controller
    can set the dummy value in its child DT node, and the SPI NOR framework
    can parse it out.

Signed-off-by: Han Xu <b45815@freescale.com>
drivers/mtd/spi-nor/spi-nor.c
include/linux/mtd/spi-nor.h

index 21dde52..d26a0a1 100644 (file)
@@ -75,6 +75,7 @@ struct flash_info {
                                         * bit. Must be used with
                                         * SPI_NOR_HAS_LOCK.
                                         */
+#define        SPI_NOR_DDR_QUAD_READ   BIT(10)  /* Flash supports DDR Quad Read */
 };
 
 #define JEDEC_MFR(info)        ((info)->id[0])
@@ -146,6 +147,21 @@ static int read_cr(struct spi_nor *nor)
 static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor)
 {
        switch (nor->flash_read) {
+       case SPI_NOR_DDR_QUAD:
+       {
+               struct device_node *np = spi_nor_get_flash_node(nor);
+               u32 dummy;
+
+               /*
+               * The m25p80.c can not support the DDR quad read.
+               * We set the dummy cycles to 8 by default. The SPI NOR
+               * controller driver can set it in its child DT node.
+               * We parse it out here.
+               */
+               if (of_property_read_u32(np,"spi-nor,ddr-quad-read-dummy",
+                                        &dummy))
+                       return dummy;
+       }
        case SPI_NOR_FAST:
        case SPI_NOR_DUAL:
        case SPI_NOR_QUAD:
@@ -1272,6 +1288,24 @@ static int spansion_quad_enable(struct spi_nor *nor)
        return 0;
 }
 
+static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+{
+       int status;
+
+       switch (JEDEC_MFR(info)) {
+       case CFI_MFR_AMD: /* Spansion, actually */
+               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;
@@ -1440,8 +1474,15 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
        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");
@@ -1454,6 +1495,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
 
        /* Default commands */
        switch (nor->flash_read) {
+       case SPI_NOR_DDR_QUAD:
+               if (JEDEC_MFR(info) == CFI_MFR_AMD) { /* 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;
@@ -1481,6 +1530,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
                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;
index c425c7b..1d0b9fb 100644 (file)
 
 /*
  * 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. */
@@ -45,6 +46,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 0xeb    /* 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 */
@@ -60,6 +62,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) */
 
@@ -105,6 +108,7 @@ enum read_mode {
        SPI_NOR_FAST,
        SPI_NOR_DUAL,
        SPI_NOR_QUAD,
+       SPI_NOR_DDR_QUAD,
 };
 
 #define SPI_NOR_MAX_CMD_SIZE   8