diff options
Diffstat (limited to 'drivers/mtd/nand/omap2.c')
-rw-r--r-- | drivers/mtd/nand/omap2.c | 512 |
1 files changed, 218 insertions, 294 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index bf642ceef681..1ff49b80bdaf 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -118,14 +118,9 @@ #define OMAP24XX_DMA_GPMC 4 -#define BCH8_MAX_ERROR 8 /* upto 8 bit correctable */ -#define BCH4_MAX_ERROR 4 /* upto 4 bit correctable */ - #define SECTOR_BYTES 512 /* 4 bit padding to make byte aligned, 56 = 52 + 4 */ #define BCH4_BIT_PAD 4 -#define BCH8_ECC_MAX ((SECTOR_BYTES + BCH8_ECC_OOB_BYTES) * 8) -#define BCH4_ECC_MAX ((SECTOR_BYTES + BCH4_ECC_OOB_BYTES) * 8) /* GPMC ecc engine settings for read */ #define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */ @@ -159,7 +154,7 @@ struct omap_nand_info { int gpmc_cs; unsigned long phys_base; - unsigned long mem_size; + enum omap_ecc ecc_opt; struct completion comp; struct dma_chan *dma; int gpmc_irq_fifo; @@ -172,7 +167,6 @@ struct omap_nand_info { int buf_len; struct gpmc_nand_regs reg; /* fields specific for BCHx_HW ECC scheme */ - bool is_elm_used; struct device *elm_dev; struct device_node *of_node; }; @@ -1043,9 +1037,8 @@ static int omap_dev_ready(struct mtd_info *mtd) } } -#if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH) /** - * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction + * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation * @mtd: MTD device structure * @mode: Read/Write mode * @@ -1056,50 +1049,73 @@ static int omap_dev_ready(struct mtd_info *mtd) * eccsize0 = 0 (no additional protected byte in spare area) * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area) */ -static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) +static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode) { - int nerrors; + unsigned int bch_type; unsigned int dev_width, nsectors; struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); + enum omap_ecc ecc_opt = info->ecc_opt; struct nand_chip *chip = mtd->priv; u32 val, wr_mode; unsigned int ecc_size1, ecc_size0; - /* Using wrapping mode 6 for writing */ - wr_mode = BCH_WRAPMODE_6; - - /* - * ECC engine enabled for valid ecc_size0 nibbles - * and disabled for ecc_size1 nibbles. - */ - ecc_size0 = BCH_ECC_SIZE0; - ecc_size1 = BCH_ECC_SIZE1; - - /* Perform ecc calculation on 512-byte sector */ - nsectors = 1; - - /* Update number of error correction */ - nerrors = info->nand.ecc.strength; - - /* Multi sector reading/writing for NAND flash with page size < 4096 */ - if (info->is_elm_used && (mtd->writesize <= 4096)) { + /* GPMC configurations for calculating ECC */ + switch (ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + bch_type = 0; + nsectors = 1; + if (mode == NAND_ECC_READ) { + wr_mode = BCH_WRAPMODE_6; + ecc_size0 = BCH_ECC_SIZE0; + ecc_size1 = BCH_ECC_SIZE1; + } else { + wr_mode = BCH_WRAPMODE_6; + ecc_size0 = BCH_ECC_SIZE0; + ecc_size1 = BCH_ECC_SIZE1; + } + break; + case OMAP_ECC_BCH4_CODE_HW: + bch_type = 0; + nsectors = chip->ecc.steps; if (mode == NAND_ECC_READ) { - /* Using wrapping mode 1 for reading */ - wr_mode = BCH_WRAPMODE_1; - - /* - * ECC engine enabled for ecc_size0 nibbles - * and disabled for ecc_size1 nibbles. - */ - ecc_size0 = (nerrors == 8) ? - BCH8R_ECC_SIZE0 : BCH4R_ECC_SIZE0; - ecc_size1 = (nerrors == 8) ? - BCH8R_ECC_SIZE1 : BCH4R_ECC_SIZE1; + wr_mode = BCH_WRAPMODE_1; + ecc_size0 = BCH4R_ECC_SIZE0; + ecc_size1 = BCH4R_ECC_SIZE1; + } else { + wr_mode = BCH_WRAPMODE_6; + ecc_size0 = BCH_ECC_SIZE0; + ecc_size1 = BCH_ECC_SIZE1; } - - /* Perform ecc calculation for one page (< 4096) */ - nsectors = info->nand.ecc.steps; + break; + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + bch_type = 1; + nsectors = 1; + if (mode == NAND_ECC_READ) { + wr_mode = BCH_WRAPMODE_6; + ecc_size0 = BCH_ECC_SIZE0; + ecc_size1 = BCH_ECC_SIZE1; + } else { + wr_mode = BCH_WRAPMODE_6; + ecc_size0 = BCH_ECC_SIZE0; + ecc_size1 = BCH_ECC_SIZE1; + } + break; + case OMAP_ECC_BCH8_CODE_HW: + bch_type = 1; + nsectors = chip->ecc.steps; + if (mode == NAND_ECC_READ) { + wr_mode = BCH_WRAPMODE_1; + ecc_size0 = BCH8R_ECC_SIZE0; + ecc_size1 = BCH8R_ECC_SIZE1; + } else { + wr_mode = BCH_WRAPMODE_6; + ecc_size0 = BCH_ECC_SIZE0; + ecc_size1 = BCH_ECC_SIZE1; + } + break; + default: + return; } writel(ECC1, info->reg.gpmc_ecc_control); @@ -1112,7 +1128,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) /* BCH configuration */ val = ((1 << 16) | /* enable BCH */ - (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */ + (bch_type << 12) | /* BCH4/BCH8/BCH16 */ (wr_mode << 8) | /* wrap mode */ (dev_width << 7) | /* bus width */ (((nsectors-1) & 0x7) << 4) | /* number of sectors */ @@ -1124,132 +1140,40 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) /* Clear ecc and enable bits */ writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); } -#endif - -#ifdef CONFIG_MTD_NAND_ECC_BCH -/** - * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes - * @mtd: MTD device structure - * @dat: The pointer to data on which ecc is computed - * @ecc_code: The ecc_code buffer - */ -static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - unsigned long nsectors, val1, val2; - int i; - - nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; - - for (i = 0; i < nsectors; i++) { - /* Read hw-computed remainder */ - val1 = readl(info->reg.gpmc_bch_result0[i]); - val2 = readl(info->reg.gpmc_bch_result1[i]); - - /* - * Add constant polynomial to remainder, in order to get an ecc - * sequence of 0xFFs for a buffer filled with 0xFFs; and - * left-justify the resulting polynomial. - */ - *ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF); - *ecc_code++ = 0x13 ^ ((val2 >> 4) & 0xFF); - *ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF)); - *ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF); - *ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF); - *ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF); - *ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4); - } - - return 0; -} +static u8 bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f}; +static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2, + 0x97, 0x79, 0xe5, 0x24, 0xb5}; /** - * omap3_calculate_ecc_bch8 - Generate 13 bytes of ECC bytes - * @mtd: MTD device structure - * @dat: The pointer to data on which ecc is computed - * @ecc_code: The ecc_code buffer - */ -static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, - mtd); - unsigned long nsectors, val1, val2, val3, val4; - int i; - - nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; - - for (i = 0; i < nsectors; i++) { - - /* Read hw-computed remainder */ - val1 = readl(info->reg.gpmc_bch_result0[i]); - val2 = readl(info->reg.gpmc_bch_result1[i]); - val3 = readl(info->reg.gpmc_bch_result2[i]); - val4 = readl(info->reg.gpmc_bch_result3[i]); - - /* - * Add constant polynomial to remainder, in order to get an ecc - * sequence of 0xFFs for a buffer filled with 0xFFs. - */ - *ecc_code++ = 0xef ^ (val4 & 0xFF); - *ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF); - *ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF); - *ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF); - *ecc_code++ = 0xed ^ (val3 & 0xFF); - *ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF); - *ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF); - *ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF); - *ecc_code++ = 0x97 ^ (val2 & 0xFF); - *ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF); - *ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF); - *ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF); - *ecc_code++ = 0xb5 ^ (val1 & 0xFF); - } - - return 0; -} -#endif /* CONFIG_MTD_NAND_ECC_BCH */ - -#ifdef CONFIG_MTD_NAND_OMAP_BCH -/** - * omap3_calculate_ecc_bch - Generate bytes of ECC bytes + * omap_calculate_ecc_bch - Generate bytes of ECC bytes * @mtd: MTD device structure * @dat: The pointer to data on which ecc is computed * @ecc_code: The ecc_code buffer * * Support calculating of BCH4/8 ecc vectors for the page */ -static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) +static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd, + const u_char *dat, u_char *ecc_calc) { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); + int eccbytes = info->nand.ecc.bytes; + struct gpmc_nand_regs *gpmc_regs = &info->reg; + u8 *ecc_code; unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4; - int i, eccbchtsel; + int i; nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1; - /* - * find BCH scheme used - * 0 -> BCH4 - * 1 -> BCH8 - */ - eccbchtsel = ((readl(info->reg.gpmc_ecc_config) >> 12) & 0x3); - for (i = 0; i < nsectors; i++) { - - /* Read hw-computed remainder */ - bch_val1 = readl(info->reg.gpmc_bch_result0[i]); - bch_val2 = readl(info->reg.gpmc_bch_result1[i]); - if (eccbchtsel) { - bch_val3 = readl(info->reg.gpmc_bch_result2[i]); - bch_val4 = readl(info->reg.gpmc_bch_result3[i]); - } - - if (eccbchtsel) { - /* BCH8 ecc scheme */ + ecc_code = ecc_calc; + switch (info->ecc_opt) { + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH8_CODE_HW: + bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); + bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); + bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]); + bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]); *ecc_code++ = (bch_val4 & 0xFF); *ecc_code++ = ((bch_val3 >> 24) & 0xFF); *ecc_code++ = ((bch_val3 >> 16) & 0xFF); @@ -1263,14 +1187,11 @@ static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, *ecc_code++ = ((bch_val1 >> 16) & 0xFF); *ecc_code++ = ((bch_val1 >> 8) & 0xFF); *ecc_code++ = (bch_val1 & 0xFF); - /* - * Setting 14th byte to zero to handle - * erased page & maintain compatibility - * with RBL - */ - *ecc_code++ = 0x0; - } else { - /* BCH4 ecc scheme */ + break; + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + case OMAP_ECC_BCH4_CODE_HW: + bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]); + bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]); *ecc_code++ = ((bch_val2 >> 12) & 0xFF); *ecc_code++ = ((bch_val2 >> 4) & 0xFF); *ecc_code++ = ((bch_val2 & 0xF) << 4) | @@ -1279,12 +1200,38 @@ static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat, *ecc_code++ = ((bch_val1 >> 12) & 0xFF); *ecc_code++ = ((bch_val1 >> 4) & 0xFF); *ecc_code++ = ((bch_val1 & 0xF) << 4); - /* - * Setting 8th byte to zero to handle - * erased page - */ - *ecc_code++ = 0x0; + break; + default: + return -EINVAL; } + + /* ECC scheme specific syndrome customizations */ + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: + /* Add constant polynomial to remainder, so that + * ECC of blank pages results in 0x0 on reading back */ + for (i = 0; i < eccbytes; i++) + ecc_calc[i] ^= bch4_polynomial[i]; + break; + case OMAP_ECC_BCH4_CODE_HW: + /* Set 8th ECC byte as 0x0 for ROM compatibility */ + ecc_calc[eccbytes - 1] = 0x0; + break; + case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: + /* Add constant polynomial to remainder, so that + * ECC of blank pages results in 0x0 on reading back */ + for (i = 0; i < eccbytes; i++) + ecc_calc[i] ^= bch8_polynomial[i]; + break; + case OMAP_ECC_BCH8_CODE_HW: + /* Set 14th ECC byte as 0x0 for ROM compatibility */ + ecc_calc[eccbytes - 1] = 0x0; + break; + default: + return -EINVAL; + } + + ecc_calc += eccbytes; } return 0; @@ -1329,6 +1276,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, return flip_bits; } +#ifdef CONFIG_MTD_NAND_OMAP_BCH /** * omap_elm_correct_data - corrects page data area in case error reported * @mtd: MTD device structure @@ -1337,55 +1285,46 @@ static int erased_sector_bitflips(u_char *data, u_char *oob, * @calc_ecc: ecc read from HW ECC registers * * Calculated ecc vector reported as zero in case of non-error pages. - * In case of error/erased pages non-zero error vector is reported. - * In case of non-zero ecc vector, check read_ecc at fixed offset - * (x = 13/7 in case of BCH8/4 == 0) to find page programmed or not. - * To handle bit flips in this data, count the number of 0's in - * read_ecc[x] and check if it greater than 4. If it is less, it is - * programmed page, else erased page. - * - * 1. If page is erased, check with standard ecc vector (ecc vector - * for erased page to find any bit flip). If check fails, bit flip - * is present in erased page. Count the bit flips in erased page and - * if it falls under correctable level, report page with 0xFF and - * update the correctable bit information. - * 2. If error is reported on programmed page, update elm error - * vector and correct the page with ELM error correction routine. - * + * In case of non-zero ecc vector, first filter out erased-pages, and + * then process data via ELM to detect bit-flips. */ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, u_char *read_ecc, u_char *calc_ecc) { struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); + struct nand_ecc_ctrl *ecc = &info->nand.ecc; int eccsteps = info->nand.ecc.steps; int i , j, stat = 0; - int eccsize, eccflag, ecc_vector_size; + int eccflag, actual_eccbytes; struct elm_errorvec err_vec[ERROR_VECTOR_MAX]; u_char *ecc_vec = calc_ecc; u_char *spare_ecc = read_ecc; u_char *erased_ecc_vec; - enum bch_ecc type; + u_char *buf; + int bitflip_count; bool is_error_reported = false; + u32 bit_pos, byte_pos, error_max, pos; + int err; - /* Initialize elm error vector to zero */ - memset(err_vec, 0, sizeof(err_vec)); - - if (info->nand.ecc.strength == BCH8_MAX_ERROR) { - type = BCH8_ECC; - erased_ecc_vec = bch8_vector; - } else { - type = BCH4_ECC; + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW: + /* omit 7th ECC byte reserved for ROM code compatibility */ + actual_eccbytes = ecc->bytes - 1; erased_ecc_vec = bch4_vector; + break; + case OMAP_ECC_BCH8_CODE_HW: + /* omit 14th ECC byte reserved for ROM code compatibility */ + actual_eccbytes = ecc->bytes - 1; + erased_ecc_vec = bch8_vector; + break; + default: + pr_err("invalid driver configuration\n"); + return -EINVAL; } - ecc_vector_size = info->nand.ecc.bytes; - - /* - * Remove extra byte padding for BCH8 RBL - * compatibility and erased page handling - */ - eccsize = ecc_vector_size - 1; + /* Initialize elm error vector to zero */ + memset(err_vec, 0, sizeof(err_vec)); for (i = 0; i < eccsteps ; i++) { eccflag = 0; /* initialize eccflag */ @@ -1394,8 +1333,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, * Check any error reported, * In case of error, non zero ecc reported. */ - - for (j = 0; (j < eccsize); j++) { + for (j = 0; j < actual_eccbytes; j++) { if (calc_ecc[j] != 0) { eccflag = 1; /* non zero ecc, error present */ break; @@ -1403,50 +1341,43 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, } if (eccflag == 1) { - /* - * Set threshold to minimum of 4, half of ecc.strength/2 - * to allow max bit flip in byte to 4 - */ - unsigned int threshold = min_t(unsigned int, 4, - info->nand.ecc.strength / 2); - - /* - * Check data area is programmed by counting - * number of 0's at fixed offset in spare area. - * Checking count of 0's against threshold. - * In case programmed page expects at least threshold - * zeros in byte. - * If zeros are less than threshold for programmed page/ - * zeros are more than threshold erased page, either - * case page reported as uncorrectable. - */ - if (hweight8(~read_ecc[eccsize]) >= threshold) { + if (memcmp(calc_ecc, erased_ecc_vec, + actual_eccbytes) == 0) { /* - * Update elm error vector as - * data area is programmed + * calc_ecc[] matches pattern for ECC(all 0xff) + * so this is definitely an erased-page */ - err_vec[i].error_reported = true; - is_error_reported = true; } else { - /* Error reported in erased page */ - int bitflip_count; - u_char *buf = &data[info->nand.ecc.size * i]; - - if (memcmp(calc_ecc, erased_ecc_vec, eccsize)) { - bitflip_count = erased_sector_bitflips( - buf, read_ecc, info); - - if (bitflip_count) - stat += bitflip_count; - else - return -EINVAL; + buf = &data[info->nand.ecc.size * i]; + /* + * count number of 0-bits in read_buf. + * This check can be removed once a similar + * check is introduced in generic NAND driver + */ + bitflip_count = erased_sector_bitflips( + buf, read_ecc, info); + if (bitflip_count) { + /* + * number of 0-bits within ECC limits + * So this may be an erased-page + */ + stat += bitflip_count; + } else { + /* + * Too many 0-bits. It may be a + * - programmed-page, OR + * - erased-page with many bit-flips + * So this page requires check by ELM + */ + err_vec[i].error_reported = true; + is_error_reported = true; } } } /* Update the ecc vector */ - calc_ecc += ecc_vector_size; - read_ecc += ecc_vector_size; + calc_ecc += ecc->bytes; + read_ecc += ecc->bytes; } /* Check if any error reported */ @@ -1456,23 +1387,26 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, /* Decode BCH error using ELM module */ elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec); + err = 0; for (i = 0; i < eccsteps; i++) { - if (err_vec[i].error_reported) { + if (err_vec[i].error_uncorrectable) { + pr_err("nand: uncorrectable bit-flips found\n"); + err = -EBADMSG; + } else if (err_vec[i].error_reported) { for (j = 0; j < err_vec[i].error_count; j++) { - u32 bit_pos, byte_pos, error_max, pos; - - if (type == BCH8_ECC) - error_max = BCH8_ECC_MAX; - else - error_max = BCH4_ECC_MAX; - - if (info->nand.ecc.strength == BCH8_MAX_ERROR) - pos = err_vec[i].error_loc[j]; - else - /* Add 4 to take care 4 bit padding */ + switch (info->ecc_opt) { + case OMAP_ECC_BCH4_CODE_HW: + /* Add 4 bits to take care of padding */ pos = err_vec[i].error_loc[j] + BCH4_BIT_PAD; - + break; + case OMAP_ECC_BCH8_CODE_HW: + pos = err_vec[i].error_loc[j]; + break; + default: + return -EINVAL; + } + error_max = (ecc->size + actual_eccbytes) * 8; /* Calculate bit position of error */ bit_pos = pos % 8; @@ -1480,13 +1414,22 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, byte_pos = (error_max - pos - 1) / 8; if (pos < error_max) { - if (byte_pos < 512) + if (byte_pos < 512) { + pr_debug("bitflip@dat[%d]=%x\n", + byte_pos, data[byte_pos]); data[byte_pos] ^= 1 << bit_pos; - else + } else { + pr_debug("bitflip@oob[%d]=%x\n", + (byte_pos - 512), + spare_ecc[byte_pos - 512]); spare_ecc[byte_pos - 512] ^= 1 << bit_pos; + } + } else { + pr_err("invalid bit-flip @ %d:%d\n", + byte_pos, bit_pos); + err = -EBADMSG; } - /* else, not interested to correct ecc */ } } @@ -1494,16 +1437,11 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, stat += err_vec[i].error_count; /* Update page data with sector size */ - data += info->nand.ecc.size; - spare_ecc += ecc_vector_size; + data += ecc->size; + spare_ecc += ecc->bytes; } - for (i = 0; i < eccsteps; i++) - /* Return error if uncorrectable error present */ - if (err_vec[i].error_uncorrectable) - return -EINVAL; - - return stat; + return (err) ? err : stat; } /** @@ -1601,7 +1539,8 @@ static int is_elm_present(struct omap_nand_info *info, struct device_node *elm_node, enum bch_ecc bch_type) { struct platform_device *pdev; - info->is_elm_used = false; + struct nand_ecc_ctrl *ecc = &info->nand.ecc; + int err; /* check whether elm-id is passed via DT */ if (!elm_node) { pr_err("nand: error: ELM DT node not found\n"); @@ -1615,10 +1554,10 @@ static int is_elm_present(struct omap_nand_info *info, } /* ELM module available, now configure it */ info->elm_dev = &pdev->dev; - if (elm_config(info->elm_dev, bch_type)) - return -ENODEV; - info->is_elm_used = true; - return 0; + err = elm_config(info->elm_dev, bch_type, + (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes); + + return err; } #endif /* CONFIG_MTD_NAND_ECC_BCH */ @@ -1657,6 +1596,7 @@ static int omap_nand_probe(struct platform_device *pdev) info->gpmc_cs = pdata->cs; info->reg = pdata->reg; info->of_node = pdata->of_node; + info->ecc_opt = pdata->ecc_opt; mtd = &info->mtd; mtd->priv = &info->nand; mtd->name = dev_name(&pdev->dev); @@ -1666,27 +1606,11 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->options |= NAND_SKIP_BBTSCAN; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - err = -EINVAL; - dev_err(&pdev->dev, "error getting memory resource\n"); - goto return_error; - } + nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nand_chip->IO_ADDR_R)) + return PTR_ERR(nand_chip->IO_ADDR_R); info->phys_base = res->start; - info->mem_size = resource_size(res); - - if (!devm_request_mem_region(&pdev->dev, info->phys_base, - info->mem_size, pdev->dev.driver->name)) { - err = -EBUSY; - goto return_error; - } - - nand_chip->IO_ADDR_R = devm_ioremap(&pdev->dev, info->phys_base, - info->mem_size); - if (!nand_chip->IO_ADDR_R) { - err = -ENOMEM; - goto return_error; - } nand_chip->controller = &info->controller; @@ -1812,7 +1736,7 @@ static int omap_nand_probe(struct platform_device *pdev) /* populate MTD interface based on ECC scheme */ nand_chip->ecc.layout = &omap_oobinfo; ecclayout = &omap_oobinfo; - switch (pdata->ecc_opt) { + switch (info->ecc_opt) { case OMAP_ECC_HAM1_CODE_HW: pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); nand_chip->ecc.mode = NAND_ECC_HW; @@ -1844,9 +1768,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.size = 512; nand_chip->ecc.bytes = 7; nand_chip->ecc.strength = 4; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; + nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = nand_bch_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch4; + nand_chip->ecc.calculate = omap_calculate_ecc_bch; /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1884,9 +1808,9 @@ static int omap_nand_probe(struct platform_device *pdev) /* 14th bit is kept reserved for ROM-code compatibility */ nand_chip->ecc.bytes = 7 + 1; nand_chip->ecc.strength = 4; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; + nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch; + nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; /* define ECC layout */ @@ -1919,9 +1843,9 @@ static int omap_nand_probe(struct platform_device *pdev) nand_chip->ecc.size = 512; nand_chip->ecc.bytes = 13; nand_chip->ecc.strength = 8; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; + nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = nand_bch_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch8; + nand_chip->ecc.calculate = omap_calculate_ecc_bch; /* define ECC layout */ ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / @@ -1960,9 +1884,9 @@ static int omap_nand_probe(struct platform_device *pdev) /* 14th bit is kept reserved for ROM-code compatibility */ nand_chip->ecc.bytes = 13 + 1; nand_chip->ecc.strength = 8; - nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; + nand_chip->ecc.hwctl = omap_enable_hwecc_bch; nand_chip->ecc.correct = omap_elm_correct_data; - nand_chip->ecc.calculate = omap3_calculate_ecc_bch; + nand_chip->ecc.calculate = omap_calculate_ecc_bch; nand_chip->ecc.read_page = omap_read_page_bch; nand_chip->ecc.write_page = omap_write_page_bch; /* This ECC scheme requires ELM H/W block */ |