diff options
Diffstat (limited to 'drivers/mtd/nand/atmel_nand.c')
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 28 |
1 files changed, 17 insertions, 11 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 92623ac2015a..90bdca61c797 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
@@ -331,13 +331,13 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | |||
331 | * 12-bits 20-bytes 21-bytes | 331 | * 12-bits 20-bytes 21-bytes |
332 | * 24-bits 39-bytes 42-bytes | 332 | * 24-bits 39-bytes 42-bytes |
333 | */ | 333 | */ |
334 | static int __devinit pmecc_get_ecc_bytes(int cap, int sector_size) | 334 | static int pmecc_get_ecc_bytes(int cap, int sector_size) |
335 | { | 335 | { |
336 | int m = 12 + sector_size / 512; | 336 | int m = 12 + sector_size / 512; |
337 | return (m * cap + 7) / 8; | 337 | return (m * cap + 7) / 8; |
338 | } | 338 | } |
339 | 339 | ||
340 | static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, | 340 | static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, |
341 | int oobsize, int ecc_len) | 341 | int oobsize, int ecc_len) |
342 | { | 342 | { |
343 | int i; | 343 | int i; |
@@ -353,7 +353,7 @@ static void __devinit pmecc_config_ecc_layout(struct nand_ecclayout *layout, | |||
353 | oobsize - ecc_len - layout->oobfree[0].offset; | 353 | oobsize - ecc_len - layout->oobfree[0].offset; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) | 356 | static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host) |
357 | { | 357 | { |
358 | int table_size; | 358 | int table_size; |
359 | 359 | ||
@@ -375,7 +375,7 @@ static void pmecc_data_free(struct atmel_nand_host *host) | |||
375 | kfree(host->pmecc_delta); | 375 | kfree(host->pmecc_delta); |
376 | } | 376 | } |
377 | 377 | ||
378 | static int __devinit pmecc_data_alloc(struct atmel_nand_host *host) | 378 | static int pmecc_data_alloc(struct atmel_nand_host *host) |
379 | { | 379 | { |
380 | const int cap = host->pmecc_corr_cap; | 380 | const int cap = host->pmecc_corr_cap; |
381 | 381 | ||
@@ -724,6 +724,7 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf, | |||
724 | struct atmel_nand_host *host = nand_chip->priv; | 724 | struct atmel_nand_host *host = nand_chip->priv; |
725 | int i, err_nbr, eccbytes; | 725 | int i, err_nbr, eccbytes; |
726 | uint8_t *buf_pos; | 726 | uint8_t *buf_pos; |
727 | int total_err = 0; | ||
727 | 728 | ||
728 | eccbytes = nand_chip->ecc.bytes; | 729 | eccbytes = nand_chip->ecc.bytes; |
729 | for (i = 0; i < eccbytes; i++) | 730 | for (i = 0; i < eccbytes; i++) |
@@ -751,12 +752,13 @@ normal_check: | |||
751 | pmecc_correct_data(mtd, buf_pos, ecc, i, | 752 | pmecc_correct_data(mtd, buf_pos, ecc, i, |
752 | host->pmecc_bytes_per_sector, err_nbr); | 753 | host->pmecc_bytes_per_sector, err_nbr); |
753 | mtd->ecc_stats.corrected += err_nbr; | 754 | mtd->ecc_stats.corrected += err_nbr; |
755 | total_err += err_nbr; | ||
754 | } | 756 | } |
755 | } | 757 | } |
756 | pmecc_stat >>= 1; | 758 | pmecc_stat >>= 1; |
757 | } | 759 | } |
758 | 760 | ||
759 | return 0; | 761 | return total_err; |
760 | } | 762 | } |
761 | 763 | ||
762 | static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | 764 | static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, |
@@ -768,6 +770,7 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | |||
768 | uint32_t *eccpos = chip->ecc.layout->eccpos; | 770 | uint32_t *eccpos = chip->ecc.layout->eccpos; |
769 | uint32_t stat; | 771 | uint32_t stat; |
770 | unsigned long end_time; | 772 | unsigned long end_time; |
773 | int bitflips = 0; | ||
771 | 774 | ||
772 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); | 775 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST); |
773 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); | 776 | pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE); |
@@ -790,11 +793,14 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, | |||
790 | } | 793 | } |
791 | 794 | ||
792 | stat = pmecc_readl_relaxed(host->ecc, ISR); | 795 | stat = pmecc_readl_relaxed(host->ecc, ISR); |
793 | if (stat != 0) | 796 | if (stat != 0) { |
794 | if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0) | 797 | bitflips = pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]); |
795 | return -EIO; | 798 | if (bitflips < 0) |
799 | /* uncorrectable errors */ | ||
800 | return 0; | ||
801 | } | ||
796 | 802 | ||
797 | return 0; | 803 | return bitflips; |
798 | } | 804 | } |
799 | 805 | ||
800 | static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, | 806 | static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, |
@@ -1206,7 +1212,7 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) | |||
1206 | } | 1212 | } |
1207 | 1213 | ||
1208 | #if defined(CONFIG_OF) | 1214 | #if defined(CONFIG_OF) |
1209 | static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | 1215 | static int atmel_of_init_port(struct atmel_nand_host *host, |
1210 | struct device_node *np) | 1216 | struct device_node *np) |
1211 | { | 1217 | { |
1212 | u32 val, table_offset; | 1218 | u32 val, table_offset; |
@@ -1293,7 +1299,7 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | |||
1293 | return 0; | 1299 | return 0; |
1294 | } | 1300 | } |
1295 | #else | 1301 | #else |
1296 | static int __devinit atmel_of_init_port(struct atmel_nand_host *host, | 1302 | static int atmel_of_init_port(struct atmel_nand_host *host, |
1297 | struct device_node *np) | 1303 | struct device_node *np) |
1298 | { | 1304 | { |
1299 | return -EINVAL; | 1305 | return -EINVAL; |