diff options
-rw-r--r-- | common/cmd_nand.c | 5 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_ifc_nand.c | 79 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 14 | ||||
-rw-r--r-- | include/linux/mtd/nand.h | 2 | ||||
-rw-r--r-- | include/linux/mtd/nand_ecc.h | 25 |
6 files changed, 54 insertions, 73 deletions
diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 3e2edb8aaa..fa96a5201c 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -48,7 +48,7 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) last = off; - datbuf = malloc(nand->writesize + nand->oobsize); + datbuf = malloc(nand->writesize); oobbuf = malloc(nand->oobsize); if (!datbuf || !oobbuf) { puts("No memory for page buffer\n"); @@ -59,7 +59,7 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) struct mtd_oob_ops ops; memset(&ops, 0, sizeof(ops)); ops.datbuf = datbuf; - ops.oobbuf = oobbuf; /* must exist, but oob data will be appended to ops.datbuf */ + ops.oobbuf = oobbuf; ops.len = nand->writesize; ops.ooblen = nand->oobsize; ops.mode = MTD_OOB_RAW; @@ -85,6 +85,7 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) } puts("OOB:\n"); i = nand->oobsize >> 3; + p = oobbuf; while (i--) { printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 998fc73497..1d1b628651 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -39,7 +39,7 @@ COBJS-y += nand_bbt.o COBJS-y += nand_ids.o COBJS-y += nand_util.o endif -COBJS-$(CONFIG_MTD_ECC_SOFT) += nand_ecc.o +COBJS-y += nand_ecc.o COBJS-y += nand_base.o COBJS-$(CONFIG_NAND_ECC_BCH) += nand_bch.o diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index b3f3c3c05a..5cac78b296 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -1,6 +1,6 @@ /* Integrated Flash Controller NAND Machine Driver * - * Copyright (c) 2011 Freescale Semiconductor, Inc + * Copyright (c) 2012 Freescale Semiconductor, Inc * * Authors: Dipen Dudhat <Dipen.Dudhat@freescale.com> * @@ -221,24 +221,11 @@ static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, u32 *eccstat, unsigned int bufnum) { u32 reg = eccstat[bufnum / 4]; - int errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; - - if (errors == 15) { /* uncorrectable */ - /* Blank pages fail hw ECC checks */ - if (is_blank(mtd, ctrl, bufnum)) - return 1; - - /* - * We disable ECCER reporting in hardware due to - * erratum IFC-A002770 -- so report it now if we - * see an uncorrectable error in ECCSTAT. - */ - ctrl->status |= IFC_NAND_EVTER_STAT_ECCER; - } else if (errors > 0) { - mtd->ecc_stats.corrected += errors; - } + int errors; - return 0; + errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; + + return errors; } /* @@ -279,16 +266,33 @@ static int fsl_ifc_run_command(struct mtd_info *mtd) printf("%s: Write Protect Error\n", __func__); if (ctrl->eccread) { - int bufperpage = mtd->writesize / 512; - int bufnum = (ctrl->page & priv->bufnum_mask) * bufperpage; - int bufnum_end = bufnum + bufperpage - 1; + int errors; + int bufnum = ctrl->page & priv->bufnum_mask; + int sector = bufnum * chip->ecc.steps; + int sector_end = sector + chip->ecc.steps - 1; - for (i = bufnum / 4; i <= bufnum_end / 4; i++) + for (i = sector / 4; i <= sector_end / 4; i++) eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]); - for (i = bufnum; i <= bufnum_end; i++) { - if (check_read_ecc(mtd, ctrl, eccstat, i)) + for (i = sector; i <= sector_end; i++) { + errors = check_read_ecc(mtd, ctrl, eccstat, i); + + if (errors == 15) { + /* + * Uncorrectable error. + * OK only if the whole page is blank. + * + * We disable ECCER reporting due to erratum + * IFC-A002770 -- so report it now if we + * see an uncorrectable error in ECCSTAT. + */ + if (!is_blank(mtd, ctrl, bufnum)) + ctrl->status |= + IFC_NAND_EVTER_STAT_ECCER; break; + } + + mtd->ecc_stats.corrected += errors; } ctrl->eccread = 0; @@ -448,21 +452,19 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, out_be32(&ifc->ifc_nand.nand_fir1, (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT)); - if (column >= mtd->writesize) { - /* OOB area --> READOOB */ - column -= mtd->writesize; - nand_fcr0 |= NAND_CMD_READOOB << - IFC_NAND_FCR0_CMD0_SHIFT; - ctrl->oob = 1; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - nand_fcr0 |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; - } else { - /* Second 256 bytes --> READ1 */ - nand_fcr0 |= NAND_CMD_READ1 << FCR_CMD0_SHIFT; - } + if (column >= mtd->writesize) + nand_fcr0 |= + NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT; + else + nand_fcr0 |= + NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT; } + if (column >= mtd->writesize) { + /* OOB area --> READOOB */ + column -= mtd->writesize; + ctrl->oob = 1; + } out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0); set_addr(mtd, column, page_addr, ctrl->oob); return; @@ -471,7 +473,8 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: if (ctrl->oob) - out_be32(&ifc->ifc_nand.nand_fbcr, ctrl->index); + out_be32(&ifc->ifc_nand.nand_fbcr, + ctrl->index - ctrl->column); else out_be32(&ifc->ifc_nand.nand_fbcr, 0); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 12b960fdb9..44f7b91457 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -479,6 +479,11 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, { struct nand_chip *chip = mtd->priv; + if (!(chip->options & NAND_BBT_SCANNED)) { + chip->options |= NAND_BBT_SCANNED; + chip->scan_bbt(mtd); + } + if (!chip->bbt) return chip->block_bad(mtd, ofs, getchip); @@ -3028,10 +3033,6 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: - if (!mtd_nand_has_ecc_soft()) { - printk(KERN_WARNING "CONFIG_MTD_ECC_SOFT not enabled\n"); - return -EINVAL; - } chip->ecc.calculate = nand_calculate_ecc; chip->ecc.correct = nand_correct_data; chip->ecc.read_page = nand_read_page_swecc; @@ -3170,10 +3171,9 @@ int nand_scan_tail(struct mtd_info *mtd) /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) - return 0; + chip->options |= NAND_BBT_SCANNED; - /* Build bad block table */ - return chip->scan_bbt(mtd); + return 0; } /** diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 99668d552e..da6fa184c3 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -232,6 +232,8 @@ typedef enum { #define NAND_CREATE_EMPTY_BBT 0x01000000 /* Options set by nand scan */ +/* bbt has already been read */ +#define NAND_BBT_SCANNED 0x40000000 /* Nand scan has allocated controller struct */ #define NAND_CONTROLLER_ALLOC 0x80000000 diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h index 9715a53d86..090da50542 100644 --- a/include/linux/mtd/nand_ecc.h +++ b/include/linux/mtd/nand_ecc.h @@ -15,10 +15,6 @@ struct mtd_info; -#if defined(CONFIG_MTD_ECC_SOFT) - -static inline int mtd_nand_has_ecc_soft(void) { return 1; } - /* * Calculate 3 byte ECC code for 256 byte block */ @@ -29,25 +25,4 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code */ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -#else - -static inline int mtd_nand_has_ecc_soft(void) { return 0; } - -static inline int -nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) -{ - return -1; -} - -static inline int -nand_correct_data(struct mtd_info *mtd, - u_char *dat, - u_char *read_ecc, - u_char *calc_ecc) -{ - return -1; -} - -#endif - #endif /* __MTD_NAND_ECC_H__ */ |