Missing support for ECC_SOFT_BCH in fsl-elbc-nand
Tomas Hlavacek
tomas.hlavacek at nic.cz
Sun Apr 12 15:30:12 PDT 2015
Hi!
On Friday, March 27, 2015 3:13:09 PM CEST, Martin Strbačka wrote:
> in our product we have Freescale P2020 SoC together with Micron
> MT29F2G08ABAEAWP NAND. Lately we discovered that the internal driver
> (fsl-elbc-nand) supports only 1-bit HW ECC.
Actually we use the NAND pretty intensively with JFFS2 and we have seen
some uncorrectable multiple bitflips with the current HW ECC mode (it means
more than one bit flip in 512B subpage, if I got that right). So we would
like to change to software BCH ECC since we have powerful enough CPU.
I would like to discuss two major questions before I submit a patch for
this:
1) How to disable HW ECC?
What I have done is this:
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c
b/drivers/mtd/nand/fsl_elbc_nand.c
index 04b22fd..e5818ba 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -676,6 +691,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info
*mtd)
} else if (mtd->writesize == 2048) {
priv->page_size = 1;
setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
+#ifndef ELBC_ECC_SW_BCH
/* adjust ecc setup if needed */
if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
BR_DECC_CHK_GEN) {
@@ -684,6 +700,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info
*mtd)
&fsl_elbc_oob_lp_eccm1 :
&fsl_elbc_oob_lp_eccm0;
}
+#endif
} else {
dev_err(priv->dev,
"fsl_elbc_init: page size %d is not supported\n",
@@ -774,11 +791,18 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd
*priv)
chip->ecc.read_page = fsl_elbc_read_page;
chip->ecc.write_page = fsl_elbc_write_page;
- chip->ecc.write_subpage = fsl_elbc_write_subpage;
+#ifdef ELBC_ECC_SW_BCH
+
out_be32(&lbc->bank[priv->bank].br,(in_be32(&lbc->bank[priv->bank].br) &
(~BR_DECC)));
+ chip->ecc.mode = NAND_ECC_SOFT_BCH;
+ chip->ecc.size = 512;
+ chip->ecc.bytes = 13;
+ chip->ecc.strength = 8;
+#else
/* If CS Base Register selects full hardware ECC then use it */
if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
BR_DECC_CHK_GEN) {
+ chip->ecc.write_subpage = fsl_elbc_write_subpage;
chip->ecc.mode = NAND_ECC_HW;
/* put in small page settings and adjust later if needed */
chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
@@ -790,6 +814,7 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd
*priv)
/* otherwise fall back to default software ECC */
chip->ecc.mode = NAND_ECC_SOFT;
}
+#endif
return 0;
}
It works but I am particularly not sure of line
out_be32(&lbc->bank[priv->bank].br,(in_be32(&lbc->bank[priv->bank].br) &
(~BR_DECC)));
Does it make sense? I have been told that on our board there is some
unconnected pin that causes that (in_be32(&lbc->bank[priv->bank].br) &
BR_DECC) == BR_DECC_CHK_GEN is true but I still have to disable HW ECC.
Does it make sense to add Kconf switch "force SW ECC" which would define
my ELBC_ECC_SW_BCH?
I would like to point out that the shuffling chip->ecc.write_subpage =
fsl_elbc_write_subpage; line is needed for subpages to work properly with
SW ECC because the write_subpage pointer in elbc_fcm_ctrl is left intact
when SW ECC is being initialized and then the ECC does not work for
subpages. Not setting it causes that default write_subpage function is
used.
2) We need to implement RNDOUT operation for SW ECC / ECC_BCH. My attempt
follows:
@@ -335,6 +335,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd,
unsigned int command,
fsl_elbc_run_command(mtd);
return;
+ /* !!! Experimental */
+ case NAND_CMD_RNDOUT:
+ dev_vdbg(priv->dev,
+ "fsl_elbc_cmdfunc: NAND_CMD_RNDOUT, "
+ "column: 0x%x.\n", column);
+
+ if ((column < 512) || (priv->page_size && (column < 2048)))
{
+ elbc_fcm_ctrl->index = column;
+ return;
+ } else {
+ column -= priv->page_size ? 2048 : 512;
+ page_addr = elbc_fcm_ctrl->page;
+ /* and fall-through to READOOB */
+ }
+
/* READOOB reads only the OOB because no ECC is performed. */
case NAND_CMD_READOOB:
dev_vdbg(priv->dev,
Maybe it is too complicated (?) and it would be sufficient to set
elbc_fcm_ctrl->index = column both for IB and OOB data? It seems that both
ways work for me.
Cheers,
Tomas
More information about the linux-mtd
mailing list