Missing support for ECC_SOFT_BCH in fsl-elbc-nand
Scott Wood
scottwood at freescale.com
Mon Apr 13 12:12:33 PDT 2015
On Mon, 2015-04-13 at 00:30 +0200, Tomas Hlavacek wrote:
> 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.
Yes, the hardware ECC on eLBC is only suitable if 1 bit per 512 bytes
meets the NAND chip's specifications.
> 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
You shouldn't be setting BR_DECC if you don't want to use HW ECC, so
this ifdef doesn't accomplish anything.
Also, while a compile-time hack may be suitable for your own use, to get
a mergable patch it should be a runtime decision. You should be able to
read at runtime the level of ECC that the flash requires.
> } 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)));
Instead change U-Boot to never set that bit in the first place.
> 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.
>From this I assume you're booting from NAND, but even so U-Boot will
overwrite that register with its own desired value.
> 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.
There is no default write_subpage function for swecc.
> 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.
I think you should just set index = column. The OOB has already been
read if we previously read a full page -- and RNDOUT is also used in
other contexts such as ONFI identification.
-Scott
More information about the linux-mtd
mailing list