aboutsummaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/denali.h
diff options
context:
space:
mode:
authorMasahiro Yamada2017-03-30 15:45:52 +0900
committerBoris Brezillon2017-04-25 14:18:34 +0200
commit24715c749b2ff5545f0316e7ad8b65026f9e9612 (patch)
tree911df863e0e9eed6782d75c56032758379390fa9 /drivers/mtd/nand/denali.h
parentd29109be2e8d4a102d8304d7b8bb0d6dfe5e1d27 (diff)
mtd: nand: denali: support HW_ECC_FIXUP capability
Some old versions of the Denali IP (perhaps used only for Intel?) detects ECC errors and provides correct data via a register, but does not touch the transferred data. So, the software must fixup the data in the buffer according to the provided ECC correction information. Newer versions perform ECC correction before transferring the data. No more software intervention is needed. The ECC_ERROR_ADDRESS and ECC_CORRECTION_INFO registers were deprecated. Instead, the number of corrected bit-flips are reported via the ECC_COR_INFO register. When an uncorrectable ECC error happens, a status flag is set to the INTR_STATUS and ECC_COR_INFO registers. As is often the case with this IP, the register view of INTR_STATUS had broken compatibility. For older versions (SW ECC fixup): bit 0: ECC_TRANSACTION_DONE bit 1: ECC_ERR For newer versions (HW ECC fixup): bit 0: ECC_UNCOR_ERR bit 1: Reserved Due to this difference, the irq_mask must be fixed too. The existing handle_ecc() has been renamed to denali_sw_ecc_fixup() for clarification. What is unfortunate with this feature is we can not know the total number of corrected/uncorrected errors in a page. The register ECC_COR_INFO reports the maximum of per-sector bitflips. This is useful for ->read_page return value, but ecc_stats.{corrected,failed} increments may not be precise. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com> Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Diffstat (limited to 'drivers/mtd/nand/denali.h')
-rw-r--r--drivers/mtd/nand/denali.h14
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h
index 483c0e988f33..e532956b7177 100644
--- a/drivers/mtd/nand/denali.h
+++ b/drivers/mtd/nand/denali.h
@@ -20,6 +20,7 @@
#ifndef __DENALI_H__
#define __DENALI_H__
+#include <linux/bitops.h>
#include <linux/mtd/nand.h>
#define DEVICE_RESET 0x0
@@ -218,8 +219,10 @@
#define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50))
#define INTR_EN(__bank) (0x420 + ((__bank) * 0x50))
-#define INTR__ECC_TRANSACTION_DONE 0x0001
-#define INTR__ECC_ERR 0x0002
+/* bit[1:0] is used differently depending on IP version */
+#define INTR__ECC_UNCOR_ERR 0x0001 /* new IP */
+#define INTR__ECC_TRANSACTION_DONE 0x0001 /* old IP */
+#define INTR__ECC_ERR 0x0002 /* old IP */
#define INTR__DMA_CMD_COMP 0x0004
#define INTR__TIME_OUT 0x0008
#define INTR__PROGRAM_FAIL 0x0010
@@ -259,6 +262,11 @@
#define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000
#define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000
+#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10)
+#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8)
+#define ECC_COR_INFO__MAX_ERRORS 0x007f
+#define ECC_COR_INFO__UNCOR_ERR 0x0080
+
#define DMA_ENABLE 0x700
#define DMA_ENABLE__FLAG 0x0001
@@ -338,6 +346,8 @@ struct denali_nand_info {
unsigned int caps;
};
+#define DENALI_CAP_HW_ECC_FIXUP BIT(0)
+
extern int denali_init(struct denali_nand_info *denali);
extern void denali_remove(struct denali_nand_info *denali);