[PATCH v2 3/7] mtd: spinand: simulate behavior of linux's function spinand_wait()
Mikhail Kshevetskiy
mikhail.kshevetskiy at iopsys.eu
Fri Jul 5 16:24:56 CEST 2024
also call schedule() to allow periodic actions
Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
---
drivers/mtd/nand/spi/core.c | 35 ++++++++++++++++++++++++++++-------
include/linux/mtd/spinand.h | 22 ++++++++++++++++++++++
2 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index f10a3dbfdff..8664e882753 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -32,6 +32,7 @@
#include <linux/bug.h>
#include <linux/mtd/spinand.h>
#include <linux/printk.h>
+#include <linux/delay.h>
#endif
/* SPI NAND index visible in MTD names */
@@ -358,21 +359,29 @@ static int spinand_erase_op(struct spinand_device *spinand,
return spi_mem_exec_op(spinand->slave, &op);
}
-static int spinand_wait(struct spinand_device *spinand, u8 *s)
+static int spinand_wait(struct spinand_device *spinand,
+ unsigned long initial_delay_us,
+ unsigned long poll_delay_us,
+ u8 *s)
{
unsigned long start, stop;
u8 status;
int ret;
+ udelay(initial_delay_us);
start = get_timer(0);
- stop = 400;
+ stop = SPINAND_WAITRDY_TIMEOUT_MS;
do {
+ schedule();
+
ret = spinand_read_status(spinand, &status);
if (ret)
return ret;
if (!(status & STATUS_BUSY))
goto out;
+
+ udelay(poll_delay_us);
} while (get_timer(start) < stop);
/*
@@ -414,7 +423,10 @@ static int spinand_reset_op(struct spinand_device *spinand)
if (ret)
return ret;
- return spinand_wait(spinand, NULL);
+ return spinand_wait(spinand,
+ SPINAND_RESET_INITIAL_DELAY_US,
+ SPINAND_RESET_POLL_DELAY_US,
+ NULL);
}
static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
@@ -462,7 +474,10 @@ static int spinand_read_page(struct spinand_device *spinand,
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_READ_INITIAL_DELAY_US,
+ SPINAND_READ_POLL_DELAY_US,
+ &status);
if (ret < 0)
return ret;
@@ -494,9 +509,12 @@ static int spinand_write_page(struct spinand_device *spinand,
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_WRITE_INITIAL_DELAY_US,
+ SPINAND_WRITE_POLL_DELAY_US,
+ &status);
if (!ret && (status & STATUS_PROG_FAILED))
- ret = -EIO;
+ return -EIO;
return ret;
}
@@ -698,7 +716,10 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
if (ret)
return ret;
- ret = spinand_wait(spinand, &status);
+ ret = spinand_wait(spinand,
+ SPINAND_ERASE_INITIAL_DELAY_US,
+ SPINAND_ERASE_POLL_DELAY_US,
+ &status);
if (!ret && (status & STATUS_ERASE_FAILED))
ret = -EIO;
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 5934b7604cc..b701d25f73d 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -176,6 +176,28 @@ struct spinand_op;
struct spinand_device;
#define SPINAND_MAX_ID_LEN 4
+/*
+ * For erase, write and read operation, we got the following timings :
+ * tBERS (erase) 1ms to 4ms
+ * tPROG 300us to 400us
+ * tREAD 25us to 100us
+ * In order to minimize latency, the min value is divided by 4 for the
+ * initial delay, and dividing by 20 for the poll delay.
+ * For reset, 5us/10us/500us if the device is respectively
+ * reading/programming/erasing when the RESET occurs. Since we always
+ * issue a RESET when the device is IDLE, 5us is selected for both initial
+ * and poll delay.
+ */
+#define SPINAND_READ_INITIAL_DELAY_US 6
+#define SPINAND_READ_POLL_DELAY_US 5
+#define SPINAND_RESET_INITIAL_DELAY_US 5
+#define SPINAND_RESET_POLL_DELAY_US 5
+#define SPINAND_WRITE_INITIAL_DELAY_US 75
+#define SPINAND_WRITE_POLL_DELAY_US 15
+#define SPINAND_ERASE_INITIAL_DELAY_US 250
+#define SPINAND_ERASE_POLL_DELAY_US 50
+
+#define SPINAND_WAITRDY_TIMEOUT_MS 400
/**
* struct spinand_id - SPI NAND id structure
--
2.39.2
More information about the U-Boot
mailing list