This patch provides an alternative to support memory >16MiB (>128Mib).
Indeed using the Base Address Register changes the internal state of
the SPI flash memory. However some early boot loaders expect to access
the first memory bank of the SPI flash. Then when another bank has been
selected, those boot loader will fail to read the right data.

Using 4byte address opcodes doesn't change the internal state of the SPI
flash memory but sill allows to access data above 16MiB.

Signed-off-by: Cyrille Pitchen <cyrille.pitc...@atmel.com>
---
 drivers/mtd/spi/Kconfig       | 18 ++++++++-
 drivers/mtd/spi/sf_internal.h | 17 +++++++-
 drivers/mtd/spi/spi_flash.c   | 93 +++++++++++++++++++++++++++++++++++++------
 include/spi_flash.h           |  2 +
 4 files changed, 114 insertions(+), 16 deletions(-)

diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 3f7433cbc214..999c3176adee 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -34,14 +34,30 @@ config SPI_FLASH
 
          If unsure, say N
 
+config SPI_FLASH_ABOVE_16MB
+       bool "Support of >16MB memories"
+       depends on SPI_FLASH
+       default n
+
+choice
+       prompt "Select >16MB method"
+       depends on SPI_FLASH_ABOVE_16MB
+
 config SPI_FLASH_BAR
        bool "SPI flash Bank/Extended address register support"
-       depends on SPI_FLASH
        help
          Enable the SPI flash Bank/Extended address register support.
          Bank/Extended address registers are used to access the flash
          which has size > 16MiB in 3-byte addressing.
 
+config SPI_FLASH_4B_OPCODES
+       bool "4-byte address op codes support"
+       help
+         Replace regular 3-byte address op codes by thier 4-byte address
+         version when the size of the memory if greater than 16MB.
+
+endchoice
+
 if SPI_FLASH
 
 config SPI_FLASH_ATMEL
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 86a0276f8518..a98c011218ce 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -62,8 +62,8 @@ enum spi_nor_option_flags {
        SNOR_F_USE_FSR          = BIT(2),
 };
 
-#define SPI_FLASH_3B_ADDR_LEN          3
-#define SPI_FLASH_CMD_LEN              (1 + SPI_FLASH_3B_ADDR_LEN)
+#define SPI_FLASH_4B_ADDR_LEN          4
+#define SPI_FLASH_CMD_LEN              (1 + SPI_FLASH_4B_ADDR_LEN)
 #define SPI_FLASH_16MB_BOUN            0x1000000
 
 /* CFI Manufacture ID's */
@@ -79,6 +79,9 @@ enum spi_nor_option_flags {
 #define CMD_ERASE_32K                  0x52
 #define CMD_ERASE_CHIP                 0xc7
 #define CMD_ERASE_64K                  0xd8
+#define CMD_ERASE_4K_4B                        0x21
+#define CMD_ERASE_32K_4B               0x5c
+#define CMD_ERASE_64K_4B               0xdc
 
 /* Write commands */
 #define CMD_WRITE_STATUS               0x01
@@ -86,6 +89,10 @@ enum spi_nor_option_flags {
 #define CMD_WRITE_DISABLE              0x04
 #define CMD_WRITE_ENABLE               0x06
 #define CMD_QUAD_PAGE_PROGRAM          0x32
+#define CMD_QUAD_PAGE_PROGRAM_MXIC     0x38
+#define CMD_PAGE_PROGRAM_4B            0x12
+#define CMD_QUAD_PAGE_PROGRAM_4B       0x34
+#define CMD_QUAD_PAGE_PROGRAM_MXIC_4B  0x3e
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW            0x03
@@ -94,6 +101,12 @@ enum spi_nor_option_flags {
 #define CMD_READ_DUAL_IO_FAST          0xbb
 #define CMD_READ_QUAD_OUTPUT_FAST      0x6b
 #define CMD_READ_QUAD_IO_FAST          0xeb
+#define CMD_READ_ARRAY_SLOW_4B         0x13
+#define CMD_READ_ARRAY_FAST_4B         0x0c
+#define CMD_READ_DUAL_OUTPUT_FAST_4B   0x3c
+#define CMD_READ_DUAL_IO_FAST_4B       0xbc
+#define CMD_READ_QUAD_OUTPUT_FAST_4B   0x6c
+#define CMD_READ_QUAD_IO_FAST_4B       0xec
 #define CMD_READ_ID                    0x9f
 #define CMD_READ_STATUS                        0x05
 #define CMD_READ_STATUS1               0x35
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 01a073d81eb9..b4a44e25f190 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -22,12 +22,15 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static void spi_flash_addr(u32 addr, u8 *cmd)
+static void spi_flash_addr(const struct spi_flash *flash, u32 addr, u8 *cmd)
 {
+       u8 shift = flash->addr_width * 8;
+
        /* cmd[0] is actual command */
-       cmd[1] = addr >> 16;
-       cmd[2] = addr >> 8;
-       cmd[3] = addr >> 0;
+       cmd[1] = addr >> (shift -  8);
+       cmd[2] = addr >> (shift - 16);
+       cmd[3] = addr >> (shift - 24);
+       cmd[4] = addr >> (shift - 32);
 }
 
 static int read_sr(struct spi_flash *flash, u8 *rs)
@@ -154,6 +157,62 @@ bar_end:
 }
 #endif
 
+#ifdef CONFIG_SPI_FLASH_4B_OPCODES
+struct address_entry {
+       u8      src_opcode;
+       u8      dst_opcode;
+};
+
+static u8 spi_flash_convert_opcode(u8 opcode,
+                                  const struct address_entry *entries,
+                                  size_t num_entries)
+{
+       int b, e;
+
+       b = 0;
+       e = num_entries - 1;
+       while (b <= e) {
+               int m = (b + e) >> 1;
+               const struct address_entry *entry = &entries[m];
+
+               if (opcode == entry->src_opcode)
+                       return entry->dst_opcode;
+
+               if (opcode < entry->src_opcode)
+                       e = m - 1;
+               else
+                       b = m + 1;
+       }
+
+       /* No convertion found */
+       return opcode;
+}
+
+static u8 spi_flash_3to4_opcode(u8 opcode)
+{
+       /* MUST be sorted by 3byte opcode */
+#define ENTRY_3TO4(_opcode)    { _opcode, _opcode##_4B }
+       static const struct address_entry spi_flash_3to4_table[] = {
+               ENTRY_3TO4(CMD_READ_ARRAY_SLOW),        /* 0x03 */
+               ENTRY_3TO4(CMD_READ_ARRAY_FAST),        /* 0x0b */
+               ENTRY_3TO4(CMD_ERASE_4K),               /* 0x20 */
+               ENTRY_3TO4(CMD_QUAD_PAGE_PROGRAM),      /* 0x32 */
+               ENTRY_3TO4(CMD_QUAD_PAGE_PROGRAM_MXIC), /* 0x38 */
+               ENTRY_3TO4(CMD_READ_DUAL_OUTPUT_FAST),  /* 0x3b */
+               ENTRY_3TO4(CMD_ERASE_32K),              /* 0x52 */
+               ENTRY_3TO4(CMD_READ_QUAD_OUTPUT_FAST),  /* 0x6b */
+               ENTRY_3TO4(CMD_READ_DUAL_IO_FAST),      /* 0xbb */
+               ENTRY_3TO4(CMD_ERASE_64K),              /* 0xd8 */
+               ENTRY_3TO4(CMD_READ_QUAD_IO_FAST),      /* 0xeb */
+       };
+#undef ENTRY_3TO4
+
+       return spi_flash_convert_opcode(opcode,
+                                       spi_flash_3to4_table,
+                                       ARRAY_SIZE(spi_flash_3to4_table));
+}
+#endif /* CONFIG_SPI_FLASH_4B_OPCODES */
+
 #ifdef CONFIG_SF_DUAL_FLASH
 static void spi_flash_dual(struct spi_flash *flash, u32 *addr)
 {
@@ -353,10 +412,11 @@ static int spi_flash_erase_impl(struct spi_flash *flash, 
u32 offset)
 {
        struct spi_slave *spi = flash->spi;
        u8 cmd[SPI_FLASH_CMD_LEN];
+       size_t cmdsz = 1 + flash->addr_width;
 
        cmd[0] = flash->erase_cmd;
-       spi_flash_addr(offset, cmd);
-       return spi_flash_cmd_write(spi, cmd, sizeof(cmd), NULL, 0);
+       spi_flash_addr(flash, offset, cmd);
+       return spi_flash_cmd_write(spi, cmd, cmdsz, NULL, 0);
 }
 
 int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
@@ -461,10 +521,10 @@ static int spi_flash_write_impl(struct spi_flash *flash, 
u32 offset,
 {
        struct spi_slave *spi = flash->spi;
        u8 cmd[SPI_FLASH_CMD_LEN];
-       size_t cmdsz = sizeof(cmd);
+       size_t cmdsz = 1 + flash->addr_width;
 
        cmd[0] = flash->write_cmd;
-       spi_flash_addr(offset, cmd);
+       spi_flash_addr(flash, offset, cmd);
 #ifdef CONFIG_SPI_FLASH_SST
        if (flash->flags & SNOR_F_SST_WR_2ND)
                cmdsz = 1;
@@ -567,7 +627,7 @@ static int spi_flash_read_impl(struct spi_flash *flash, u32 
offset,
        size_t cmdsz;
        int ret;
 
-       cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte;
+       cmdsz = 1 + flash->addr_width + flash->dummy_byte;
        cmd = calloc(1, cmdsz);
        if (!cmd) {
                debug("SF: Failed to allocate cmd\n");
@@ -575,7 +635,7 @@ static int spi_flash_read_impl(struct spi_flash *flash, u32 
offset,
        }
 
        cmd[0] = flash->read_cmd;
-       spi_flash_addr(offset, cmd);
+       spi_flash_addr(flash, offset, cmd);
        ret = spi_flash_cmd_read(spi, cmd, cmdsz, buf, len);
        free(cmd);
        return ret;
@@ -1255,15 +1315,22 @@ int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
        puts("\n");
 #endif
 
-#ifndef CONFIG_SPI_FLASH_BAR
+       /* Set number of bytes for address and convert opcodes if needed */
+       flash->addr_width = 3;
        if (((flash->dual_flash == SF_SINGLE_FLASH) &&
             (flash->size > SPI_FLASH_16MB_BOUN)) ||
             ((flash->dual_flash > SF_SINGLE_FLASH) &&
             (flash->size > SPI_FLASH_16MB_BOUN << 1))) {
+#if defined(CONFIG_SPI_FLASH_4B_OPCODES)
+               flash->addr_width = 4;
+               flash->read_cmd  = spi_flash_3to4_opcode(flash->read_cmd);
+               flash->write_cmd = spi_flash_3to4_opcode(flash->write_cmd);
+               flash->erase_cmd = spi_flash_3to4_opcode(flash->erase_cmd);
+#elif !defined(CONFIG_SPI_FLASH_BAR)
                puts("SF: Warning - Only lower 16MiB accessible,");
-               puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
-       }
+               puts(" Full access #define CONFIG_SPI_FLASH_ABOVE_16MB\n");
 #endif
+       }
 
        return ret;
 }
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 945cc07ee8b2..5db06e5133f3 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -88,6 +88,7 @@ enum spi_flash_protocol {
  * @read_proto         SPI protocol to be used by &read ops
  * @write_proto                SPI protocol to be used by &write ops
  * @erase_proto                SPI protocol to be used by &erase ops
+ * @addr_width         Number of address bytes (typically 3 or 4)
  * @memory_map:                Address of read-only SPI flash access
  * @flash_lock:                lock a region of the SPI Flash
  * @flash_unlock:      unlock a region of the SPI Flash
@@ -117,6 +118,7 @@ struct spi_flash {
        u32 page_size;
        u32 sector_size;
        u32 erase_size;
+       u32 addr_width;
 #ifdef CONFIG_SPI_FLASH_BAR
        u8 bank_read_cmd;
        u8 bank_write_cmd;
-- 
1.8.2.2

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to