]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
sf: Turn SPI flash chip into 3-Byte address mode
authorSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Fri, 14 Aug 2015 09:11:14 +0000 (14:41 +0530)
committerMichal Simek <michal.simek@xilinx.com>
Fri, 14 Aug 2015 12:14:16 +0000 (14:14 +0200)
For more than 16MiB SPI flash chips, there are 3-Byte and 4-Byte address
mode, and only the 3-Byte address mode is supported in U-Boot so far.
So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI
flash work correctly, because it may has been set to 4-Byte address mode
after warm boot.

Signed-off-by: Hou Zhiqiang <B48286@freescale.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/mtd/spi/sf_internal.h
drivers/mtd/spi/sf_ops.c
drivers/mtd/spi/sf_probe.c

index dc192e20a0aceb76610981bdff3693fcc56ccb01..44f0e07db02da167424a033aebec4765547302bf 100644 (file)
@@ -76,6 +76,9 @@ enum {
 #define CMD_WRITE_ENABLE               0x06
 #define CMD_READ_CONFIG                        0x35
 #define CMD_FLAG_STATUS                        0x70
+/* Used for Micron, Macronix and Winbond flashes */
+#define CMD_ENTER_4B_ADDR              0xB7
+#define CMD_EXIT_4B_ADDR               0xE9
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW            0x03
@@ -221,6 +224,9 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
 int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
                size_t len, void *data);
 
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash,
+               int enable, u8 idcode0);
+
 #ifdef CONFIG_SPI_FLASH_MTD
 int spi_flash_mtd_register(struct spi_flash *flash);
 void spi_flash_mtd_unregister(void);
index d1bb41bcfe5c0d75acf7a63b8564906d771928c9..87818196d2efb7867d32dea73895f07a6774d4cd 100644 (file)
@@ -126,6 +126,46 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc)
 }
 #endif
 
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash,
+                               int enable, u8 idcode0)
+{
+       int ret;
+       u8 cmd, bar;
+       bool need_wren = false;
+
+       ret = spi_claim_bus(flash->spi);
+       if (ret) {
+               debug("SF: unable to claim SPI bus\n");
+               return ret;
+       }
+
+       switch (idcode0) {
+       case SPI_FLASH_CFI_MFR_STMICRO:
+               /* Some Micron need WREN command; all will accept it */
+               need_wren = true;
+       case SPI_FLASH_CFI_MFR_MACRONIX:
+       case SPI_FLASH_CFI_MFR_WINBOND:
+               if (need_wren)
+                       spi_flash_cmd_write_enable(flash);
+
+               cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR;
+               ret = spi_flash_cmd(flash->spi, cmd, NULL, 0);
+               if (need_wren)
+                       spi_flash_cmd_write_disable(flash);
+
+               break;
+       default:
+               /* Spansion style */
+               bar = enable << 7;
+               cmd = CMD_BANKADDR_BRWR;
+               ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &bar, 1);
+       }
+
+       spi_release_bus(flash->spi);
+
+       return ret;
+}
+
 #ifdef CONFIG_SPI_FLASH_BAR
 static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel)
 {
index 5377c2f623dfcaa8b3e816d27b6b3e1217086aad..bbb51ef9bd53e6e05bd3905772496d66a538c552 100644 (file)
@@ -207,6 +207,17 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
        flash->page_size <<= flash->shift;
        flash->sector_size = params->sector_size << flash->shift;
        flash->size = flash->sector_size * params->nr_sectors;
+
+       /*
+        * So far, the 4-byte address mode haven't been supported in U-Boot,
+        * and make sure the chip (> 16MiB) in default 3-byte address mode,
+        * in case of warm bootup, the chip was set to 4-byte mode in kernel.
+        */
+       if (flash->size > SPI_FLASH_16MB_BOUN) {
+               if (spi_flash_cmd_4B_addr_switch(flash, false, idcode[0]) < 0)
+                       debug("SF: enter 3B address mode failed\n");
+       }
+
 #ifdef CONFIG_SF_DUAL_FLASH
        if (flash->dual_flash & SF_DUAL_STACKED_FLASH)
                flash->size <<= 1;