[RFC] spi-nor: Use different timeout values for write and erase operations

Andrey Smirnov andrew.smirnov at gmail.com
Sat Feb 6 12:23:00 PST 2016


Some chips take longer than 40 seconds to perform certain
operations. One concrete example would be M25P128 that, according to
its spec, can take up to 250 seconds to perform a chip erase.

This commit:

     - Adds 'wait_time` parameter to spi_nor_wait_till_ready() so that
       each individual caller of would be able to use custom timeout

     - Adds timings information to flash_info and nor_spi structures
       to specify sector and chip erase timeouts

     - Modifies the code of spi_nor_erase() to make use of previously
       mentioned changes

Signed-off-by: Andrey Smirnov <andrew.smirnov at gmail.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 329 ++++++++++++++++++++++--------------------
 include/linux/mtd/spi-nor.h   |  13 ++
 2 files changed, 188 insertions(+), 154 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 27f4abc..c9cd76c 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -43,6 +43,8 @@ struct flash_info {
 	u16		page_size;
 	u16		addr_width;
 
+	struct spi_nor_timings timings;
+
 	u16		flags;
 #define	SECT_4K			0x01	/* SPINOR_OP_BE_4K works uniformly */
 #define	SPI_NOR_NO_ERASE	0x02	/* No erase command needed */
@@ -228,14 +230,14 @@ static int spi_nor_ready(struct spi_nor *nor)
  * Service routine to read status register until ready, or timeout occurs.
  * Returns non-zero if error.
  */
-static int spi_nor_wait_till_ready(struct spi_nor *nor)
+static int spi_nor_wait_till_ready(struct spi_nor *nor, uint64_t wait_time)
 {
 	uint64_t start = get_time_ns();
 	int timeout = 0;
 	int ret;
 
 	while (!timeout) {
-		if (is_timeout(start, 40 * SECOND))
+		if (is_timeout(start, wait_time))
 			timeout = 1;
 
 		ret = spi_nor_ready(nor);
@@ -308,7 +310,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 	len = instr->len;
 
 	/* Assure previous operations are completed */
-	ret = spi_nor_wait_till_ready(nor);
+	ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 	if (ret)
 		goto erase_err;
 
@@ -325,7 +327,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 			goto erase_err;
 		}
 
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor,
+					      nor->timings.chip_erase);
 		if (ret)
 			goto erase_err;
 
@@ -347,7 +350,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
 			addr += mtd->erasesize;
 			len -= mtd->erasesize;
 
-			ret = spi_nor_wait_till_ready(nor);
+			ret = spi_nor_wait_till_ready(nor,
+						      nor->timings.sector_erase);
 			if (ret)
 				goto erase_err;
 		}
@@ -395,7 +399,8 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 }
 
 /* Used when the "_ext_id" is two bytes at most */
-#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors,		\
+	     _sector_erase_time, _chip_erase_time, _flags)		\
 	((unsigned long)&(struct flash_info) {				\
 		.id = {							\
 			((_jedec_id) >> 16) & 0xff,			\
@@ -408,10 +413,15 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 		.sector_size = (_sector_size),				\
 		.n_sectors = (_n_sectors),				\
 		.page_size = 256,					\
+		.timings = {						\
+			.sector_erase	= _sector_erase_time,		\
+			.chip_erase	= _chip_erase_time,		\
+		},							\
 		.flags = (_flags),					\
 	})
 
-#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
+#define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors,		\
+	     _sector_erase_time, _chip_erase_time, _flags)		\
 	((unsigned long)&(struct flash_info) {				\
 		.id = {							\
 			((_jedec_id) >> 16) & 0xff,			\
@@ -425,15 +435,24 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 		.sector_size = (_sector_size),				\
 		.n_sectors = (_n_sectors),				\
 		.page_size = 256,					\
+		.timings = {						\
+			.sector_erase	= _sector_erase_time,		\
+			.chip_erase	= _chip_erase_time,		\
+		},							\
 		.flags = (_flags),					\
 	})
 
-#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)	\
+#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width,	\
+	     _sector_erase_time, _chip_erase_time, _flags)		\
 	((unsigned long)&(struct flash_info) {				\
 		.sector_size = (_sector_size),				\
 		.n_sectors = (_n_sectors),				\
 		.page_size = (_page_size),				\
 		.addr_width = (_addr_width),				\
+		.timings = {						\
+			.sector_erase	= _sector_erase_time,		\
+			.chip_erase	= _chip_erase_time,		\
+		},							\
 		.flags = (_flags),					\
 	})
 
@@ -443,178 +462,178 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
  */
 static const struct spi_device_id spi_nor_ids[] = {
 	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
-	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
-	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
+	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
-	{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
-	{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
-	{ "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
+	{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
-	{ "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) },
-	{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
-	{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
-	{ "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
+	{ "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
-	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
+	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
 	/* EON -- en25xxx */
-	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
-	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
-	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
-	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
-	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
-	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 0) },
-	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
-	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, 0) },
+	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "en25qh128",  INFO(0x1c7018, 0, 64 * 1024,  256, 40 * SECOND, 40 * SECOND, 0) },
+	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 40 * SECOND, 40 * SECOND, 0) },
+	{ "en25s64",	INFO(0x1c3817, 0, 64 * 1024,  128, 40 * SECOND, 40 * SECOND, 0) },
 
 	/* ESMT */
-	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
+	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
 	/* Everspin */
-	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
-	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 
 	/* Fujitsu */
-	{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
+	{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE) },
 
 	/* GigaDevice */
-	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
+	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
 	/* Intel/Numonyx -- xxxs33b */
-	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
-	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
-	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 40 * SECOND, 40 * SECOND, 0) },
+	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
 
 	/* Macronix */
-	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
-	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
-	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
-	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
-	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
-	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
-	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
-	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
-	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
-	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
-	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
-	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) },
-	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
+	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 40 * SECOND, 40 * SECOND, 0) },
+	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
+	{ "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
 
 	/* Micron */
-	{ "n25q032",	 INFO(0x20ba16, 0, 64 * 1024,   64, SPI_NOR_QUAD_READ) },
-	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, SPI_NOR_QUAD_READ) },
-	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
-	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, SPI_NOR_QUAD_READ) },
-	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K | SPI_NOR_QUAD_READ) },
-	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
-	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
-	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+	{ "n25q032",	 INFO(0x20ba16, 0, 64 * 1024,   64, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
+	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
+	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
+	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
+	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, 40 * SECOND, 40 * SECOND, SECT_4K | SPI_NOR_QUAD_READ) },
+	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, 40 * SECOND, 40 * SECOND, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024, 40 * SECOND, 40 * SECOND, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048, 40 * SECOND, 40 * SECOND, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
 
 	/* PMC */
-	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
-	{ "pm25lv010",   INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
-	{ "pm25lq032",   INFO(0x7f9d46, 0, 64 * 1024,   64, SECT_4K) },
+	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, 40 * SECOND, 40 * SECOND, SECT_4K_PMC) },
+	{ "pm25lv010",   INFO(0,        0, 32 * 1024,    4, 40 * SECOND, 40 * SECOND, SECT_4K_PMC) },
+	{ "pm25lq032",   INFO(0x7f9d46, 0, 64 * 1024,   64, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
 	/* Spansion -- single (large) sector size only, at least
 	 * for the chips listed here (without boot sectors).
 	 */
-	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
-	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
-	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
-	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
-	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
-	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
-	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
-	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
-	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
-	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
-	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
-	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
-	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
-	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
-	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
-	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
-	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
-	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, 0) },
-	{ "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, SECT_4K) },
+	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, 40 * SECOND, 40 * SECOND, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, 40 * SECOND, 40 * SECOND, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, 40 * SECOND, 40 * SECOND, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25fl128s",	INFO6(0x012018, 0x4d0180, 64 * 1024, 256, 40 * SECOND, 40 * SECOND, SPI_NOR_QUAD_READ) },
+	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
-	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
-	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
-	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
-	{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
-	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
-	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
-	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
-	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-	{ "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
+	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
+	{ "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16, 40 * SECOND, 40 * SECOND, SECT_4K | SST_WRITE) },
 
 	/* ST Microelectronics -- newer production may have feature updates */
-	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
-	{ "m25p10",  INFO(0x202011,  0,  32 * 1024,   4, 0) },
-	{ "m25p20",  INFO(0x202012,  0,  64 * 1024,   4, 0) },
-	{ "m25p40",  INFO(0x202013,  0,  64 * 1024,   8, 0) },
-	{ "m25p80",  INFO(0x202014,  0,  64 * 1024,  16, 0) },
-	{ "m25p16",  INFO(0x202015,  0,  64 * 1024,  32, 0) },
-	{ "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 0) },
-	{ "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
-	{ "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
-
-	{ "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
-	{ "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
-	{ "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4, 0) },
-	{ "m25p40-nonjedec",  INFO(0, 0,  64 * 1024,   8, 0) },
-	{ "m25p80-nonjedec",  INFO(0, 0,  64 * 1024,  16, 0) },
-	{ "m25p16-nonjedec",  INFO(0, 0,  64 * 1024,  32, 0) },
-	{ "m25p32-nonjedec",  INFO(0, 0,  64 * 1024,  64, 0) },
-	{ "m25p64-nonjedec",  INFO(0, 0,  64 * 1024, 128, 0) },
-	{ "m25p128-nonjedec", INFO(0, 0, 256 * 1024,  64, 0) },
-
-	{ "m45pe10", INFO(0x204011,  0, 64 * 1024,    2, 0) },
-	{ "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 0) },
-	{ "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 0) },
-
-	{ "m25pe20", INFO(0x208012,  0, 64 * 1024,  4,       0) },
-	{ "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
-	{ "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
-
-	{ "m25px16",    INFO(0x207115,  0, 64 * 1024, 32, SECT_4K) },
-	{ "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, SECT_4K) },
-	{ "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, SECT_4K) },
-	{ "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, SECT_4K) },
-	{ "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
-	{ "m25px80",    INFO(0x207114,  0, 64 * 1024, 16, 0) },
+	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p10",  INFO(0x202011,  0,  32 * 1024,   4, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p20",  INFO(0x202012,  0,  64 * 1024,   4, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p40",  INFO(0x202013,  0,  64 * 1024,   8, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p80",  INFO(0x202014,  0,  64 * 1024,  16, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p16",  INFO(0x202015,  0,  64 * 1024,  32, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 3 * SECOND, 250 * SECOND, 0) },
+
+	{ "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p40-nonjedec",  INFO(0, 0,  64 * 1024,   8, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p80-nonjedec",  INFO(0, 0,  64 * 1024,  16, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p16-nonjedec",  INFO(0, 0,  64 * 1024,  32, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p32-nonjedec",  INFO(0, 0,  64 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p64-nonjedec",  INFO(0, 0,  64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25p128-nonjedec", INFO(0, 0, 256 * 1024,  64, 40 * SECOND, 40 * SECOND, 0) },
+
+	{ "m45pe10", INFO(0x204011,  0, 64 * 1024,    2, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 40 * SECOND, 40 * SECOND, 0) },
+
+	{ "m25pe20", INFO(0x208012,  0, 64 * 1024,  4, 40 * SECOND, 40 * SECOND,       0) },
+	{ "m25pe80", INFO(0x208014,  0, 64 * 1024, 16, 40 * SECOND, 40 * SECOND,       0) },
+	{ "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, 40 * SECOND, 40 * SECOND, SECT_4K) },
+
+	{ "m25px16",    INFO(0x207115,  0, 64 * 1024, 32, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, 0) },
+	{ "m25px80",    INFO(0x207114,  0, 64 * 1024, 16, 40 * SECOND, 40 * SECOND, 0) },
 
 	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
-	{ "w25x05", INFO(0xef3010, 0, 64 * 1024,  1,  SECT_4K) },
-	{ "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
-	{ "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
-	{ "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
-	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
-	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
-	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
-	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
-	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
-	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
+	{ "w25x05", INFO(0xef3010, 0, 64 * 1024,  1,  40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, 40 * SECOND, 40 * SECOND, SECT_4K) },
+	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, 40 * SECOND, 40 * SECOND, SECT_4K) },
 
 	/* Catalyst / On Semiconductor -- non-JEDEC */
-	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
-	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
-	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
-	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
-	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
+	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, 40 * SECOND, 40 * SECOND, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
 	{ },
 };
 
@@ -684,7 +703,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 		/* write one byte. */
 		nor->write(nor, to, 1, retlen, buf);
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 		if (ret)
 			goto time_out;
 	}
@@ -696,7 +715,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 		/* write two bytes. */
 		nor->write(nor, to, 2, retlen, buf + actual);
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 		if (ret)
 			goto time_out;
 		to += 2;
@@ -705,7 +724,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 	nor->sst_write_second = false;
 
 	write_disable(nor);
-	ret = spi_nor_wait_till_ready(nor);
+	ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 	if (ret)
 		goto time_out;
 
@@ -716,7 +735,7 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
 		nor->program_opcode = SPINOR_OP_BP;
 		nor->write(nor, to, 1, retlen, buf + actual);
 
-		ret = spi_nor_wait_till_ready(nor);
+		ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 		if (ret)
 			goto time_out;
 		write_disable(nor);
@@ -762,7 +781,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 			if (page_size > nor->page_size)
 				page_size = nor->page_size;
 
-			ret = spi_nor_wait_till_ready(nor);
+			ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 			if (ret)
 				goto write_err;
 
@@ -772,7 +791,7 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
 		}
 	}
 
-	ret = spi_nor_wait_till_ready(nor);
+	ret = spi_nor_wait_till_ready(nor, 40 * SECOND);
 write_err:
 	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
 	return ret;
@@ -788,7 +807,7 @@ static int macronix_quad_enable(struct spi_nor *nor)
 	nor->cmd_buf[0] = val | SR_QUAD_EN_MX;
 	nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 1, 0);
 
-	if (spi_nor_wait_till_ready(nor))
+	if (spi_nor_wait_till_ready(nor, 40 * SECOND))
 		return 1;
 
 	ret = read_sr(nor);
@@ -980,6 +999,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode,
 	nor->page_size = info->page_size;
 	mtd->writebufsize = nor->page_size;
 
+	memcpy(&nor->timings, &info->timings, sizeof(nor->timings));
+
 	if (np) {
 		/* If we were instantiated by DT, use it */
 		if (of_property_read_bool(np, "m25p,fast-read"))
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index de9ac08..9b2cae4 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -123,6 +123,18 @@ enum spi_nor_option_flags {
 };
 
 /**
+ * struct spi_nor_timings - Structure containing maximum timing values
+ * for various write/erase operations (per chip's specification)
+ *
+ * @sector_erase:	maximum amount of time it takes to erase a sector
+ * @chip_erase:		maximum amount of time it takes to erase whole chip
+ */
+struct spi_nor_timings {
+	uint64_t sector_erase;
+	uint64_t chip_erase;
+};
+
+/**
  * struct spi_nor - Structure for defining a the SPI NOR layer
  * @mtd:		point to a mtd_info structure
  * @lock:		the lock for the read/write/erase/lock/unlock operations
@@ -164,6 +176,7 @@ struct spi_nor {
 	u8			program_opcode;
 	enum read_mode		flash_read;
 	bool			sst_write_second;
+	struct spi_nor_timings  timings;
 	u32			flags;
 	struct spi_nor_xfer_cfg	cfg;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
-- 
2.5.0




More information about the barebox mailing list