mtd: spi-nor-core: Add octal mode support
authorVignesh Raghavendra <vigneshr@ti.com>
Thu, 5 Dec 2019 10:16:05 +0000 (15:46 +0530)
committerJagan Teki <jagan@amarulasolutions.com>
Mon, 27 Jan 2020 16:57:22 +0000 (22:27 +0530)
Add support for Octal flash devices. Octal flash devices use 8 IO lines
for data transfer. Currently only 1-1-8 Octal Read mode is supported.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
Reviewed-by: Jagan Teki <jagan@amarulasolutions.com>
drivers/mtd/spi/sf_internal.h
drivers/mtd/spi/spi-nor-core.c
drivers/spi/spi-mem.c
drivers/spi/spi-uclass.c
include/linux/mtd/spi-nor.h
include/spi.h

index 5c643034c691ae101bddb561584920e5ce896f6c..940b2e4c9e0043816ed95975c780cf3034148e90 100644 (file)
@@ -37,7 +37,7 @@ struct flash_info {
        u16             page_size;
        u16             addr_width;
 
-       u16             flags;
+       u32             flags;
 #define SECT_4K                        BIT(0)  /* SPINOR_OP_BE_4K works uniformly */
 #define SPI_NOR_NO_ERASE       BIT(1)  /* No erase command needed */
 #define SST_WRITE              BIT(2)  /* use SST byte programming */
@@ -66,6 +66,7 @@ struct flash_info {
 #define SPI_NOR_SKIP_SFDP      BIT(13) /* Skip parsing of SFDP tables */
 #define USE_CLSR               BIT(14) /* use CLSR command */
 #define SPI_NOR_HAS_SST26LOCK  BIT(15) /* Flash supports lock/unlock via BPR */
+#define SPI_NOR_OCTAL_READ      BIT(16) /* Flash supports Octal Read */
 };
 
 extern const struct flash_info spi_nor_ids[];
index 6e7fc2311e194747b81e6b73fa9a7fcdd66a151b..d7020c190bad29d4508b25c53e34dd79a054b20f 100644 (file)
@@ -251,6 +251,8 @@ static u8 spi_nor_convert_3to4_read(u8 opcode)
                { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B },
                { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B },
                { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B },
+               { SPINOR_OP_READ_1_1_8, SPINOR_OP_READ_1_1_8_4B },
+               { SPINOR_OP_READ_1_8_8, SPINOR_OP_READ_1_8_8_4B },
 
                { SPINOR_OP_READ_1_1_1_DTR,     SPINOR_OP_READ_1_1_1_DTR_4B },
                { SPINOR_OP_READ_1_2_2_DTR,     SPINOR_OP_READ_1_2_2_DTR_4B },
@@ -267,6 +269,8 @@ static u8 spi_nor_convert_3to4_program(u8 opcode)
                { SPINOR_OP_PP,         SPINOR_OP_PP_4B },
                { SPINOR_OP_PP_1_1_4,   SPINOR_OP_PP_1_1_4_4B },
                { SPINOR_OP_PP_1_4_4,   SPINOR_OP_PP_1_4_4_4B },
+               { SPINOR_OP_PP_1_1_8,   SPINOR_OP_PP_1_1_8_4B },
+               { SPINOR_OP_PP_1_8_8,   SPINOR_OP_PP_1_8_8_4B },
        };
 
        return spi_nor_convert_opcode(opcode, spi_nor_3to4_program,
@@ -2169,6 +2173,13 @@ static int spi_nor_init_params(struct spi_nor *nor,
                                          SNOR_PROTO_1_1_4);
        }
 
+       if (info->flags & SPI_NOR_OCTAL_READ) {
+               params->hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
+               spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_1_1_8],
+                                         0, 8, SPINOR_OP_READ_1_1_8,
+                                         SNOR_PROTO_1_1_8);
+       }
+
        /* Page Program settings. */
        params->hwcaps.mask |= SNOR_HWCAPS_PP;
        spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
@@ -2476,7 +2487,14 @@ int spi_nor_scan(struct spi_nor *nor)
        nor->read_reg = spi_nor_read_reg;
        nor->write_reg = spi_nor_write_reg;
 
-       if (spi->mode & SPI_RX_QUAD) {
+       if (spi->mode & SPI_RX_OCTAL) {
+               hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
+
+               if (spi->mode & SPI_TX_OCTAL)
+                       hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
+                                       SNOR_HWCAPS_PP_1_1_8 |
+                                       SNOR_HWCAPS_PP_1_8_8);
+       } else if (spi->mode & SPI_RX_QUAD) {
                hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
 
                if (spi->mode & SPI_TX_QUAD)
index 7788ab995344332a1280b196c52de652dd55de5a..cc358bd4f7ce836a2fbeaf0834e1084c0359d2f4 100644 (file)
@@ -123,6 +123,12 @@ static int spi_check_buswidth_req(struct spi_slave *slave, u8 buswidth, bool tx)
                        return 0;
 
                break;
+       case 8:
+               if ((tx && (mode & SPI_TX_OCTAL)) ||
+                   (!tx && (mode & SPI_RX_OCTAL)))
+                       return 0;
+
+               break;
 
        default:
                break;
index 9208b16db4fdd545e6b05426a94777e09811243f..4a02d95a34a9b388443f02bc4a88f977705eef61 100644 (file)
@@ -461,6 +461,9 @@ int spi_slave_ofdata_to_platdata(struct udevice *dev,
        case 4:
                mode |= SPI_TX_QUAD;
                break;
+       case 8:
+               mode |= SPI_TX_OCTAL;
+               break;
        default:
                warn_non_spl("spi-tx-bus-width %d not supported\n", value);
                break;
@@ -476,6 +479,9 @@ int spi_slave_ofdata_to_platdata(struct udevice *dev,
        case 4:
                mode |= SPI_RX_QUAD;
                break;
+       case 8:
+               mode |= SPI_RX_OCTAL;
+               break;
        default:
                warn_non_spl("spi-rx-bus-width %d not supported\n", value);
                break;
index 1d911772917d919cb13cb196438efc2afafa71f4..ec144a08d8f822752556b484489a07b08771e0d4 100644 (file)
 #define SPINOR_OP_READ_1_2_2   0xbb    /* Read data bytes (Dual I/O SPI) */
 #define SPINOR_OP_READ_1_1_4   0x6b    /* Read data bytes (Quad Output SPI) */
 #define SPINOR_OP_READ_1_4_4   0xeb    /* Read data bytes (Quad I/O SPI) */
+#define SPINOR_OP_READ_1_1_8   0x8b    /* Read data bytes (Octal Output SPI) */
+#define SPINOR_OP_READ_1_8_8   0xcb    /* Read data bytes (Octal I/O SPI) */
 #define SPINOR_OP_PP           0x02    /* Page program (up to 256 bytes) */
 #define SPINOR_OP_PP_1_1_4     0x32    /* Quad page program */
 #define SPINOR_OP_PP_1_4_4     0x38    /* Quad page program */
+#define SPINOR_OP_PP_1_1_8     0x82    /* Octal page program */
+#define SPINOR_OP_PP_1_8_8     0xc2    /* Octal page program */
 #define SPINOR_OP_BE_4K                0x20    /* Erase 4KiB block */
 #define SPINOR_OP_BE_4K_PMC    0xd7    /* Erase 4KiB block on PMC chips */
 #define SPINOR_OP_BE_32K       0x52    /* Erase 32KiB block */
 #define SPINOR_OP_READ_1_2_2_4B        0xbc    /* Read data bytes (Dual I/O SPI) */
 #define SPINOR_OP_READ_1_1_4_4B        0x6c    /* Read data bytes (Quad Output SPI) */
 #define SPINOR_OP_READ_1_4_4_4B        0xec    /* Read data bytes (Quad I/O SPI) */
+#define SPINOR_OP_READ_1_1_8_4B        0x7c    /* Read data bytes (Octal Output SPI) */
+#define SPINOR_OP_READ_1_8_8_4B        0xcc    /* Read data bytes (Octal I/O SPI) */
 #define SPINOR_OP_PP_4B                0x12    /* Page program (up to 256 bytes) */
 #define SPINOR_OP_PP_1_1_4_4B  0x34    /* Quad page program */
 #define SPINOR_OP_PP_1_4_4_4B  0x3e    /* Quad page program */
+#define SPINOR_OP_PP_1_1_8_4B  0x84    /* Octal page program */
+#define SPINOR_OP_PP_1_8_8_4B  0x8e    /* Octal page program */
 #define SPINOR_OP_BE_4K_4B     0x21    /* Erase 4KiB block */
 #define SPINOR_OP_BE_32K_4B    0x5c    /* Erase 32KiB block */
 #define SPINOR_OP_SE_4B                0xdc    /* Sector erase (usually 64KiB) */
index 18a0312f9f87052b52fedc54e7d081e81eff7009..852f570eaa8d997c4fedd2c5b5dd8f5d7811746f 100644 (file)
@@ -30,6 +30,8 @@
 #define SPI_RX_SLOW    BIT(11)                 /* receive with 1 wire slow */
 #define SPI_RX_DUAL    BIT(12)                 /* receive with 2 wires */
 #define SPI_RX_QUAD    BIT(13)                 /* receive with 4 wires */
+#define SPI_TX_OCTAL   BIT(14)                 /* transmit with 8 wires */
+#define SPI_RX_OCTAL   BIT(15)                 /* receive with 8 wires */
 
 /* Header byte that marks the start of the message */
 #define SPI_PREAMBLE_END_BYTE  0xec