summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/fsl_nfc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/fsl_nfc.c')
-rw-r--r--drivers/mtd/nand/fsl_nfc.c72
1 files changed, 49 insertions, 23 deletions
diff --git a/drivers/mtd/nand/fsl_nfc.c b/drivers/mtd/nand/fsl_nfc.c
index 8def52a718e0..5f95b46b1a30 100644
--- a/drivers/mtd/nand/fsl_nfc.c
+++ b/drivers/mtd/nand/fsl_nfc.c
@@ -424,19 +424,8 @@ fsl_nfc_command(struct mtd_info *mtd, unsigned command,
CONFIG_ECC_MODE_MASK,
CONFIG_ECC_MODE_SHIFT, ECC_BYPASS);
- if (!(page%0x40)) {
- nfc_set_field(mtd, NFC_FLASH_CONFIG,
- CONFIG_ECC_MODE_MASK,
- CONFIG_ECC_MODE_SHIFT, ECC_BYPASS);
- }
-
switch (command) {
case NAND_CMD_PAGEPROG:
- if (!(prv->page%0x40))
- nfc_set_field(mtd, NFC_FLASH_CONFIG,
- CONFIG_ECC_MODE_MASK,
- CONFIG_ECC_MODE_SHIFT, ECC_BYPASS);
-
fsl_nfc_send_cmd(mtd,
PROGRAM_PAGE_CMD_BYTE1,
PROGRAM_PAGE_CMD_BYTE2,
@@ -664,25 +653,55 @@ fsl_nfc_read_word(struct mtd_info *mtd)
return tmp;
}
-#if 0
-static void fsl_nfc_check_ecc_status(struct mtd_info *mtd)
+static int nfc_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
+ u_char *ecc_code)
+{
+ return 0;
+}
+
+/* Count the number of 0's in buff upto max_bits */
+static int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+ int k, written_bits = 0;
+
+ for (k = 0; k < size; k++) {
+ written_bits += hweight8(~buff[k]);
+ if (written_bits > max_bits)
+ break;
+ }
+
+ return written_bits;
+}
+
+static int fsl_nfc_check_ecc_status(struct mtd_info *mtd, u_char *dat)
{
struct nand_chip *chip = mtd->priv;
struct fsl_nfc_prv *prv = chip->priv;
- u8 ecc_status, ecc_count;
+ u32 ecc_status;
+ u8 ecc_count;
+ int flip;
- ecc_status = *(u8 *)(prv->regs + ECC_SRAM_ADDR * 8 + 7);
+ /*
+ * ECC status is stored at NFC_CFG[ECCADD] +4 for
+ * little-endian and +7 for big-endian SOC. Access as 32 bits
+ * and use low byte.
+ */
+ ecc_status = __raw_readl(prv->regs + ECC_SRAM_ADDR * 8 + 4);
ecc_count = ecc_status & ECC_ERR_COUNT;
- if (ecc_status & ECC_STATUS_MASK) {
- /*mtd->ecc_stats.failed++;*/
- printk("ECC failed to correct all errors!\n");
- } else if (ecc_count) {
- /*mtd->ecc_stats.corrected += ecc_count;*/
- printk(KERN_INFO"ECC corrected %d errors\n", ecc_count);
+ if (!(ecc_status & ECC_STATUS_MASK))
+ return ecc_count;
+
+ /* If 'ecc_count' zero or less then buffer is all 0xff or erased. */
+ flip = count_written_bits(dat, chip->ecc.size, ecc_count);
+
+
+ if (flip > ecc_count) {
+ printk("ECC failed to correct all errors (%08x)\n", ecc_status);
+ return -1;
}
+ return 0;
}
-#endif
static void
copy_from_to_spare(struct mtd_info *mtd, void *pbuf, int len, int wr)
@@ -749,12 +768,19 @@ static int fsl_nfc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
static int fsl_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int page)
{
+ int stat;
struct fsl_nfc_prv *prv = chip->priv;
- /*fsl_nfc_check_ecc_status(mtd);*/
memcpy_fromio((void *)buf, prv->regs + NFC_MAIN_AREA(0),
mtd->writesize);
copy_from_to_spare(mtd, chip->oob_poi, mtd->oobsize, 0);
+
+ stat = fsl_nfc_check_ecc_status(mtd, buf);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+
return 0;
}