From 47cbeb2e67288dcff95a47261b58306c107b4bd6 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Tue, 7 Jun 2022 19:30:59 +0100 Subject: x1000: add support for simple on-die ECC with NAND flash Many SPI NAND flash chips have on-die ECC engines that report ECC status via the status feature register. This code handles the common case where ECC status is reported with 2 bits: one bit to indicate if flips were detected & corrected, and another bit to indicate an uncorrectable error. Change-Id: I5d587cd960ca9d090d2629e890724a6bc411e70c --- firmware/target/mips/ingenic_x1000/nand-x1000.c | 20 ++++++++++++++++++++ firmware/target/mips/ingenic_x1000/nand-x1000.h | 3 +++ 2 files changed, 23 insertions(+) (limited to 'firmware/target/mips') diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index 2b62e8fb42..286dc3c64b 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c @@ -22,6 +22,7 @@ #include "nand-x1000.h" #include "sfc-x1000.h" #include "system.h" +#include "logf.h" #include const struct nand_chip supported_nand_chips[] = { @@ -151,6 +152,11 @@ static void setup_chip_registers(struct nand_drv* drv) en ? FREG_CFG_QUAD_ENABLE : 0); } + if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) { + /* Enable on-die ECC */ + nand_upd_reg(drv, FREG_CFG, FREG_CFG_ECC_ENABLE, FREG_CFG_ECC_ENABLE); + } + /* Clear OTP bit to access the main data array */ nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, 0); @@ -249,6 +255,20 @@ int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer) sfc_exec(drv->cmd_page_read, page, NULL, 0); nand_wait_busy(drv); sfc_exec(drv->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ); + + if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) { + uint8_t status = nand_get_reg(drv, FREG_STATUS); + + if(status & FREG_STATUS_ECC_UNCOR_ERR) { + logf("ecc uncorrectable error on page %08lx", (unsigned long)page); + return NAND_ERR_ECC_FAIL; + } + + if(status & FREG_STATUS_ECC_HAS_FLIPS) { + logf("ecc corrected bitflips on page %08lx", (unsigned long)page); + } + } + return NAND_SUCCESS; } diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h index 0a22a4ff3c..61e0bbebc9 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.h +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h @@ -32,6 +32,7 @@ #define NAND_ERR_PROGRAM_FAIL (-2) #define NAND_ERR_ERASE_FAIL (-3) #define NAND_ERR_UNALIGNED (-4) +#define NAND_ERR_ECC_FAIL (-5) /* keep max page size in sync with the NAND chip table in the .c file */ #define NAND_DRV_SCRATCHSIZE 32 @@ -43,6 +44,8 @@ #define NAND_CHIPFLAG_HAS_QE_BIT 0x0002 /* Chip has 2nd device ID byte */ #define NAND_CHIPFLAG_HAS_DEVID2 0x0004 +/* True if the chip has on-die ECC */ +#define NAND_CHIPFLAG_ON_DIE_ECC 0x0008 /* cmd mode a d phase format has data */ #define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) -- cgit v1.2.3