|
@@ -16,6 +16,7 @@
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/mutex.h>
|
|
|
#include <linux/math64.h>
|
|
|
+#include <linux/sizes.h>
|
|
|
|
|
|
#include <linux/mtd/cfi.h>
|
|
|
#include <linux/mtd/mtd.h>
|
|
@@ -24,7 +25,18 @@
|
|
|
#include <linux/mtd/spi-nor.h>
|
|
|
|
|
|
/* Define max times to check status register before we give up. */
|
|
|
-#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
|
|
|
+
|
|
|
+/*
|
|
|
+ * For everything but full-chip erase; probably could be much smaller, but kept
|
|
|
+ * around for safety for now
|
|
|
+ */
|
|
|
+#define DEFAULT_READY_WAIT_JIFFIES (40UL * HZ)
|
|
|
+
|
|
|
+/*
|
|
|
+ * For full-chip erase, calibrated to a 2MB flash (M25P16); should be scaled up
|
|
|
+ * for larger flash
|
|
|
+ */
|
|
|
+#define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ)
|
|
|
|
|
|
#define SPI_NOR_MAX_ID_LEN 6
|
|
|
|
|
@@ -233,12 +245,13 @@ 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_with_timeout(struct spi_nor *nor,
|
|
|
+ unsigned long timeout_jiffies)
|
|
|
{
|
|
|
unsigned long deadline;
|
|
|
int timeout = 0, ret;
|
|
|
|
|
|
- deadline = jiffies + MAX_READY_WAIT_JIFFIES;
|
|
|
+ deadline = jiffies + timeout_jiffies;
|
|
|
|
|
|
while (!timeout) {
|
|
|
if (time_after_eq(jiffies, deadline))
|
|
@@ -258,6 +271,12 @@ static int spi_nor_wait_till_ready(struct spi_nor *nor)
|
|
|
return -ETIMEDOUT;
|
|
|
}
|
|
|
|
|
|
+static int spi_nor_wait_till_ready(struct spi_nor *nor)
|
|
|
+{
|
|
|
+ return spi_nor_wait_till_ready_with_timeout(nor,
|
|
|
+ DEFAULT_READY_WAIT_JIFFIES);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Erase the whole flash memory
|
|
|
*
|
|
@@ -321,6 +340,8 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|
|
|
|
|
/* whole-chip erase? */
|
|
|
if (len == mtd->size) {
|
|
|
+ unsigned long timeout;
|
|
|
+
|
|
|
write_enable(nor);
|
|
|
|
|
|
if (erase_chip(nor)) {
|
|
@@ -328,7 +349,16 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)
|
|
|
goto erase_err;
|
|
|
}
|
|
|
|
|
|
- ret = spi_nor_wait_till_ready(nor);
|
|
|
+ /*
|
|
|
+ * Scale the timeout linearly with the size of the flash, with
|
|
|
+ * a minimum calibrated to an old 2MB flash. We could try to
|
|
|
+ * pull these from CFI/SFDP, but these values should be good
|
|
|
+ * enough for now.
|
|
|
+ */
|
|
|
+ timeout = max(CHIP_ERASE_2MB_READY_WAIT_JIFFIES,
|
|
|
+ CHIP_ERASE_2MB_READY_WAIT_JIFFIES *
|
|
|
+ (unsigned long)(mtd->size / SZ_2M));
|
|
|
+ ret = spi_nor_wait_till_ready_with_timeout(nor, timeout);
|
|
|
if (ret)
|
|
|
goto erase_err;
|
|
|
|