[PATCH v2] mtd-nand: davinci: correct 4-bit error correction

Sudhakar Rajashekhara sudhakar.raj at ti.com
Thu Jul 15 01:10:41 EDT 2010


On TI's DA830/OMAP-L137, DA850/OMAP-L138 and DM365, after setting the
4BITECC_ADD_CALC_START bit in the NAND Flash control register to 1 and
before waiting for the NAND Flash status register to be equal to 1, 2 or
3, we have to wait till the ECC HW goes to correction state.  Without this
wait, ECC correction calculations will not be proper.

This has been tested on DA830/OMAP-L137, DA850/OMAP-L138, DM355 and DM365
EVMs.

Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj at ti.com>
Acked-by: Sneha Narnakaje <nsnehaprabha at ti.com>
Cc: David Woodhouse <dwmw2 at infradead.org>
Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
---
Since v1:
a. Timeout has been changed from 100 msec to 100 usec.
b. Comment above the do, while loop was not matching the code.
   This has been corrected.
c. Initialization of 'timeo' variable has been moved down.
d. It was observed that, while calculating the time in the loop,
   if there is a context switch between setting the 4BITECC_ADD_CALC_START
   bit and reading of ECC_STATE field, then the loop will not come out
   until the timeout happens. To prevent the context switch, spin_lock_irqsave
   and spin_unlock_irqrestore are used.

 drivers/mtd/nand/davinci_nand.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c
index 9c9d893..1e2657c 100644
--- a/drivers/mtd/nand/davinci_nand.c
+++ b/drivers/mtd/nand/davinci_nand.c
@@ -311,7 +311,11 @@ static int nand_davinci_correct_4bit(struct mtd_info *mtd,
 	unsigned short ecc10[8];
 	unsigned short *ecc16;
 	u32 syndrome[4];
+	u32 ecc_state;
 	unsigned num_errors, corrected;
+	unsigned long timeo;
+	DEFINE_SPINLOCK(ecc_spin_lock);
+	unsigned long flags;
 
 	/* All bytes 0xff?  It's an erased page; ignore its ECC. */
 	for (i = 0; i < 10; i++) {
@@ -355,12 +359,30 @@ compare:
 	 */
 	davinci_nand_readl(info, NAND_ERR_ADD1_OFFSET);
 
+	spin_lock_irqsave(&ecc_spin_lock, flags);
 	/* Start address calculation, and wait for it to complete.
 	 * We _could_ start reading more data while this is working,
 	 * to speed up the overall page read.
 	 */
 	davinci_nand_writel(info, NANDFCR_OFFSET,
 			davinci_nand_readl(info, NANDFCR_OFFSET) | BIT(13));
+
+	/*
+	 * ECC_STATE field reads 0x3 (Error correction complete) immediately
+	 * after setting the 4BITECC_ADD_CALC_START bit. So if you immediately
+	 * begin trying to poll for the state, you may fall right out of your
+	 * loop without any of the correction calculations having taken place.
+	 * The recommendation from the hardware team is to wait till ECC_STATE
+	 * reads >= 4, which means ECC HW has entered correction state.
+	 */
+	timeo = jiffies + usecs_to_jiffies(100);
+	do {
+		ecc_state = (davinci_nand_readl(info,
+				NANDFSR_OFFSET) >> 8) & 0x0f;
+		cpu_relax();
+	} while ((ecc_state < 4) && time_before(jiffies, timeo));
+	spin_unlock_irqrestore(&ecc_spin_lock, flags);
+
 	for (;;) {
 		u32	fsr = davinci_nand_readl(info, NANDFSR_OFFSET);
 
-- 
1.5.6




More information about the linux-mtd mailing list