]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
mtd: nand: denali: support hardware-assisted erased page detection
authorMasahiro Yamada <yamada.masahiro@socionext.com>
Tue, 13 Jun 2017 13:45:46 +0000 (22:45 +0900)
committerBoris Brezillon <boris.brezillon@free-electrons.com>
Tue, 20 Jun 2017 07:14:48 +0000 (09:14 +0200)
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@socionext.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h

index ed0044c560e54ffdc388bea3c223d37ef17e92d8..e8d8e6c6f45e59a48480d6bd03851166c5d6ff7d 100644 (file)
@@ -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,
index f5da52f09e34bfce20f9162ad75aec6bb94b69e3..657a794af695ed7e7a8aed9fd8c26697a399753e 100644 (file)
 
 #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)
 #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)