mtd: nand: denali: support hardware-assisted erased page detection

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Thu Jul 13 10:59:22 PDT 2017


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=57a4d8b5f6482718f17c08f2cdfea085b1d3c12a
Commit:     57a4d8b5f6482718f17c08f2cdfea085b1d3c12a
Parent:     26d266e10e5eb59cfbcc47922655dc3149e1bd59
Author:     Masahiro Yamada <yamada.masahiro at socionext.com>
AuthorDate: Tue Jun 13 22:45:46 2017 +0900
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Tue Jun 20 09:14:48 2017 +0200

    mtd: nand: denali: support hardware-assisted erased page detection
    
    Recent versions of this IP support automatic erased page detection.
    If an erased page is detected on reads, the controller does not set
    INTR__ECC_UNCOR_ERR, but INTR__ERASED_PAGE.
    
    The detection of erased pages is based on the number of zeros in a
    page; if the number of zeros is less than the value in the field
    ERASED_THRESHOLD, the page is assumed as erased.
    
    Please note ERASED_THRESHOLD specifies the number of zeros in a _page_
    instead of an ECC chunk.  Moreover, the controller does not provide a
    way to know the actual number of bitflips.
    
    Actually, an erased page (all 0xff) is not an ECC correctable pattern
    on the Denali ECC engine.  In other words, there may be overlap between
    the following two:
    
    [1] a bit pattern reachable from a valid payload + ECC pattern within
        ecc.strength bitflips
    [2] a bit pattern reachable from an erased state (all 0xff) within
        ecc.strength bitflips
    
    So, this feature may intercept ECC correctable patterns, then replace
    [1] with [2].
    
    After all, this feature can work safely only when ECC_THRESHOLD == 1,
    i.e. detect erased pages without any bitflips.  This should be the
    case most of the time.  If there is a bitflip or more, the driver will
    fallback to the software method by using nand_check_erased_ecc_chunk().
    
    Strangely enough, the driver still has to fill the buffer with 0xff
    in case of INTR__ERASED_PAGE because the ECC correction engine has
    already manipulated the data in the buffer before it judges erased
    pages.
    
    Signed-off-by: Masahiro Yamada <yamada.masahiro at socionext.com>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/nand/denali.c | 9 ++++++++-
 drivers/mtd/nand/denali.h | 5 +++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index ed0044c..e8d8e6c 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -560,6 +560,9 @@ static int denali_pio_read(struct denali_nand_info *denali, void *buf,
 	if (!(irq_status & INTR__PAGE_XFER_INC))
 		return -EIO;
 
+	if (irq_status & INTR__ERASED_PAGE)
+		memset(buf, 0xff, size);
+
 	return irq_status & ecc_err_mask ? -EBADMSG : 0;
 }
 
@@ -635,6 +638,9 @@ static int denali_dma_xfer(struct denali_nand_info *denali, void *buf,
 	denali_enable_dma(denali, false);
 	dma_sync_single_for_cpu(denali->dev, dma_addr, size, dir);
 
+	if (irq_status & INTR__ERASED_PAGE)
+		memset(buf, 0xff, size);
+
 	return ret;
 }
 
@@ -1406,7 +1412,8 @@ int denali_init(struct denali_nand_info *denali)
 		"chosen ECC settings: step=%d, strength=%d, bytes=%d\n",
 		chip->ecc.size, chip->ecc.strength, chip->ecc.bytes);
 
-	iowrite32(chip->ecc.strength, denali->flash_reg + ECC_CORRECTION);
+	iowrite32(MAKE_ECC_CORRECTION(chip->ecc.strength, 1),
+		  denali->flash_reg + ECC_CORRECTION);
 	iowrite32(mtd->erasesize / mtd->writesize,
 		  denali->flash_reg + PAGES_PER_BLOCK);
 	iowrite32(chip->options & NAND_BUSWIDTH_16 ? 1 : 0,
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index f5da52f..657a794 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -110,6 +110,10 @@
 
 #define ECC_CORRECTION				0x1b0
 #define     ECC_CORRECTION__VALUE			GENMASK(4, 0)
+#define     ECC_CORRECTION__ERASE_THRESHOLD		GENMASK(31, 16)
+#define     MAKE_ECC_CORRECTION(val, thresh)		\
+			(((val) & (ECC_CORRECTION__VALUE)) | \
+			(((thresh) << 16) & (ECC_CORRECTION__ERASE_THRESHOLD)))
 
 #define READ_MODE				0x1c0
 #define     READ_MODE__VALUE				GENMASK(3, 0)
@@ -233,6 +237,7 @@
 #define     INTR__RST_COMP				BIT(13)
 #define     INTR__PIPE_CMD_ERR				BIT(14)
 #define     INTR__PAGE_XFER_INC				BIT(15)
+#define     INTR__ERASED_PAGE				BIT(16)
 
 #define PAGE_CNT(bank)				(0x430 + (bank) * 0x50)
 #define ERR_PAGE_ADDR(bank)			(0x440 + (bank) * 0x50)



More information about the linux-mtd-cvs mailing list