SF: Bulk Erase command support for spansion

Change-Id: Ida70d167cafc6af823f31c660d108cc25be6edff
Signed-off-by: Antony Arun T <antothom@codeaurora.org>
diff --git a/common/cmd_sf.c b/common/cmd_sf.c
index 7815bdc..69345db 100644
--- a/common/cmd_sf.c
+++ b/common/cmd_sf.c
@@ -347,6 +347,22 @@
 	return ret == 0 ? 0 : 1;
 }
 
+static int do_spi_flash_berase(int argc, char * const argv[])
+{
+	switch (spi_flash_berase(flash)) {
+	case 0:
+		return 0;
+	case -ENOTSUPP:
+		printf("SPI flash %s not supported\n", argv[0]);
+		return 1;
+	default:
+		printf("SPI flash %s failed\n", argv[0]);
+		return 1;
+	}
+
+	return 1;
+}
+
 static int do_spi_protect(int argc, char * const argv[])
 {
 	int ret = 0;
@@ -576,6 +592,8 @@
 	else if (!strcmp(cmd, "test"))
 		ret = do_spi_flash_test(argc, argv);
 #endif
+	else if (strcmp(cmd, "bulkerase") == 0)
+		ret = do_spi_flash_berase(argc, argv);
 	else
 		ret = -1;
 
@@ -613,5 +631,7 @@
 	"					  or to start of mtd `partition'\n"
 	"sf protect lock/unlock sector len	- protect/unprotect 'len' bytes starting\n"
 	"					  at address 'sector'\n"
+	"sf bulkerase				- Erase entire flash chip\n"
+	"						(Not supported on all devices)\n"
 	SF_TEST_HELP
 );
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index d58d841..ecc2b57 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -12,6 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/compiler.h>
+#include <linux/compat.h>
 
 /* Dual SPI flash memories - see SPI_COMM_DUAL_... */
 enum spi_dual_flash {
@@ -115,6 +116,7 @@
 #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)
 #define SPI_FLASH_PAGE_ERASE_TIMEOUT	(5 * CONFIG_SYS_HZ)
 #define SPI_FLASH_SECTOR_ERASE_TIMEOUT	(10 * CONFIG_SYS_HZ)
+#define SPI_FLASH_BERASE_TIMEOUT(f)	((f)->berase_timeout * CONFIG_SYS_HZ)
 
 /* SST specific */
 #ifdef CONFIG_SPI_FLASH_SST
@@ -147,6 +149,7 @@
 	u32 nr_sectors;
 	u8 e_rd_cmd;
 	u16 flags;
+	u16 bulkerase_timeout;		/* in seconds */
 };
 
 extern const struct spi_flash_params spi_flash_params_table[];
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index 3f141e2..7739f4a 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -72,9 +72,9 @@
 	{"S25FL032P",	   0x010215, 0x4d00,    64 * 1024,    64, RD_FULL,		     WR_QPP},
 	{"S25FL064P",	   0x010216, 0x4d00,    64 * 1024,   128, RD_FULL,		     WR_QPP},
 	{"S25FL128S_256K", 0x012018, 0x4d00,   256 * 1024,    64, RD_FULL,		     WR_QPP},
-	{"S25FL128S_64K",  0x012018, 0x4d01,    64 * 1024,   256, RD_FULL,		     WR_QPP},
+	{"S25FL128S_64K",  0x012018, 0x4d01,    64 * 1024,   256, RD_FULL,		     WR_QPP,	180},
 	{"S25FL256S_256K", 0x010219, 0x4d00,   256 * 1024,   128, RD_FULL,		     WR_QPP},
-	{"S25FL256S_64K",  0x010219, 0x4d01,	64 * 1024,   512, RD_FULL,		     WR_QPP},
+	{"S25FL256S_64K",  0x010219, 0x4d01,	64 * 1024,   512, RD_FULL,		     WR_QPP,	360},
 	{"S25FL512S_256K", 0x010220, 0x4d00,   256 * 1024,   256, RD_FULL,		     WR_QPP},
 	{"S25FL512S_64K",  0x010220, 0x4d01,    64 * 1024,  1024, RD_FULL,		     WR_QPP},
 	{"S25FL512S_512K", 0x010220, 0x4f00,   256 * 1024,   256, RD_FULL,		     WR_QPP},
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 2b9217f..73c44fe 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -19,6 +19,10 @@
 
 #include "sf_internal.h"
 
+#if defined CONFIG_SPI_FLASH_SPANSION
+#define CMD_S25FSXX_BE	0x60
+#endif
+
 DECLARE_GLOBAL_DATA_PTR;
 
 static void spi_flash_addr(struct spi_flash *flash, u32 addr, u8 *cmd)
@@ -266,6 +270,37 @@
 	return -ETIMEDOUT;
 }
 
+#if defined CONFIG_SPI_FLASH_SPANSION
+int spi_flash_cmd_berase(struct spi_flash *flash, u8 erase_cmd)
+{
+	int ret;
+
+	ret = spi_claim_bus(flash->spi);
+	if (ret) {
+		debug("SF: Unable to claim SPI bus\n");
+		return ret;
+	}
+
+	ret = spi_flash_cmd_write_enable(flash);
+	if (ret)
+		goto out;
+
+	ret = spi_flash_cmd_write(flash->spi, &erase_cmd, 1, NULL, 0);
+	if (ret)
+		goto out;
+
+	ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_BERASE_TIMEOUT(flash));
+out:
+	spi_release_bus(flash->spi);
+	return ret;
+}
+
+static int bulk_erase(struct spi_flash *flash)
+{
+	return spi_flash_cmd_berase(flash, CMD_S25FSXX_BE);
+}
+#endif
+
 int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 		size_t cmd_len, const void *buf, size_t buf_len)
 {
@@ -1161,5 +1196,12 @@
 	}
 #endif
 
+#if defined CONFIG_SPI_FLASH_SPANSION
+	if (params->bulkerase_timeout) {
+		flash->berase = bulk_erase;
+		flash->berase_timeout = params->bulkerase_timeout;
+	}
+#endif
+
 	return ret;
 }
diff --git a/include/spi_flash.h b/include/spi_flash.h
index 995d123..1e05be2 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -114,6 +114,9 @@
 			const void *buf);
 	int (*erase)(struct spi_flash *flash, u32 offset, size_t len);
 #endif
+
+	u16 berase_timeout;				/* Bulk erase timeout */
+	int (*berase)(struct spi_flash *flash);		/* Bulk Erase */
 };
 
 struct dm_spi_flash_ops {
@@ -249,6 +252,14 @@
 		return flash->flash_unlock(flash, ofs, len);
 }
 
+static inline int spi_flash_berase(struct spi_flash *flash)
+{
+	if (!flash->berase)
+		return -ENOTSUPP;
+
+	return flash->berase(flash);
+}
+
 void spi_boot(void) __noreturn;
 void spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);