diff options
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/fsl_elbc_nand.c | 98 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 12 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 185 | ||||
-rw-r--r-- | drivers/mtd/onenand/onenand_bbt.c | 4 |
4 files changed, 178 insertions, 121 deletions
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 0bd1bdb..674c542 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -141,14 +141,14 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) if (priv->page_size) { out_be32(&lbc->fbar, page_addr >> 6); out_be32(&lbc->fpar, - ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | - (oob ? FPAR_LP_MS : 0) | column); + ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | + (oob ? FPAR_LP_MS : 0) | column); buf_num = (page_addr & 1) << 2; } else { out_be32(&lbc->fbar, page_addr >> 5); out_be32(&lbc->fpar, - ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | - (oob ? FPAR_SP_MS : 0) | column); + ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | + (oob ? FPAR_SP_MS : 0) | column); buf_num = page_addr & 7; } @@ -227,24 +227,24 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob) if (priv->page_size) { out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_CW1 << FIR_OP3_SHIFT) | - (FIR_OP_RBW << FIR_OP4_SHIFT)); + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_CW1 << FIR_OP3_SHIFT) | + (FIR_OP_RBW << FIR_OP4_SHIFT)); out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | - (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); + (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); } else { out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_RBW << FIR_OP3_SHIFT)); + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_RBW << FIR_OP3_SHIFT)); if (oob) out_be32(&lbc->fcr, - NAND_CMD_READOOB << FCR_CMD0_SHIFT); + NAND_CMD_READOOB << FCR_CMD0_SHIFT); else out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); } @@ -252,7 +252,7 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob) /* cmdfunc send commands to the FCM */ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) + int column, int page_addr) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; @@ -306,8 +306,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, vdbg("fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_UA << FIR_OP1_SHIFT) | - (FIR_OP_RBW << FIR_OP2_SHIFT)); + (FIR_OP_UA << FIR_OP1_SHIFT) | + (FIR_OP_RBW << FIR_OP2_SHIFT)); out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); /* 5 bytes for manuf, device and exts */ out_be32(&lbc->fbcr, 5); @@ -331,13 +331,13 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, vdbg("fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_PA << FIR_OP1_SHIFT) | - (FIR_OP_CM1 << FIR_OP2_SHIFT)); + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_PA << FIR_OP1_SHIFT) | + (FIR_OP_CM1 << FIR_OP2_SHIFT)); out_be32(&lbc->fcr, - (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT)); + (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) | + (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT)); out_be32(&lbc->fbcr, 0); ctrl->read_bytes = 0; @@ -360,22 +360,22 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT); out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CA << FIR_OP1_SHIFT) | - (FIR_OP_PA << FIR_OP2_SHIFT) | - (FIR_OP_WB << FIR_OP3_SHIFT) | - (FIR_OP_CW1 << FIR_OP4_SHIFT)); + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CA << FIR_OP1_SHIFT) | + (FIR_OP_PA << FIR_OP2_SHIFT) | + (FIR_OP_WB << FIR_OP3_SHIFT) | + (FIR_OP_CW1 << FIR_OP4_SHIFT)); } else { fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_CM2 << FIR_OP1_SHIFT) | - (FIR_OP_CA << FIR_OP2_SHIFT) | - (FIR_OP_PA << FIR_OP3_SHIFT) | - (FIR_OP_WB << FIR_OP4_SHIFT) | - (FIR_OP_CW1 << FIR_OP5_SHIFT)); + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_CM2 << FIR_OP1_SHIFT) | + (FIR_OP_CA << FIR_OP2_SHIFT) | + (FIR_OP_PA << FIR_OP3_SHIFT) | + (FIR_OP_WB << FIR_OP4_SHIFT) | + (FIR_OP_CW1 << FIR_OP5_SHIFT)); if (column >= mtd->writesize) { /* OOB area --> READOOB */ @@ -430,7 +430,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, fsl_elbc_run_command(mtd); memcpy_fromio(ctrl->oob_poi + 6, - &ctrl->addr[ctrl->index], 3); + &ctrl->addr[ctrl->index], 3); ctrl->index += 3; } @@ -442,8 +442,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* Note - it does not wait for the ready line */ case NAND_CMD_STATUS: out_be32(&lbc->fir, - (FIR_OP_CM0 << FIR_OP0_SHIFT) | - (FIR_OP_RBW << FIR_OP1_SHIFT)); + (FIR_OP_CM0 << FIR_OP0_SHIFT) | + (FIR_OP_RBW << FIR_OP1_SHIFT)); out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); out_be32(&lbc->fbcr, 1); set_addr(mtd, 0, 0, 0); @@ -467,7 +467,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, default: printf("fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", - command); + command); } } @@ -559,7 +559,7 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) * Verify buffer against the FCM Controller Data Buffer */ static int fsl_elbc_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) + const u_char *buf, int len) { struct nand_chip *chip = mtd->priv; struct fsl_elbc_mtd *priv = chip->priv; @@ -603,8 +603,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) /* Use READ_STATUS command, but wait for the device to be ready */ ctrl->use_mdr = 0; out_be32(&lbc->fir, - (FIR_OP_CW0 << FIR_OP0_SHIFT) | - (FIR_OP_RBW << FIR_OP1_SHIFT)); + (FIR_OP_CW0 << FIR_OP0_SHIFT) | + (FIR_OP_RBW << FIR_OP1_SHIFT)); out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); out_be32(&lbc->fbcr, 1); set_addr(mtd, 0, 0, 0); @@ -623,8 +623,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) } static int fsl_elbc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf) + struct nand_chip *chip, + uint8_t *buf) { fsl_elbc_read_buf(mtd, buf, mtd->writesize); fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -639,8 +639,8 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, * waitfunc. */ static void fsl_elbc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf) + struct nand_chip *chip, + const uint8_t *buf) { struct fsl_elbc_mtd *priv = chip->priv; struct fsl_elbc_ctrl *ctrl = priv->ctrl; @@ -737,8 +737,8 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_HW; nand->ecc.layout = (priv->fmr & FMR_ECCM) ? - &fsl_elbc_oob_sp_eccm1 : - &fsl_elbc_oob_sp_eccm0; + &fsl_elbc_oob_sp_eccm1 : + &fsl_elbc_oob_sp_eccm0; nand->ecc.size = 512; nand->ecc.bytes = 3; @@ -758,8 +758,8 @@ int board_nand_init(struct nand_chip *nand) if ((br & BR_DECC) == BR_DECC_CHK_GEN) { nand->ecc.steps = 4; nand->ecc.layout = (priv->fmr & FMR_ECCM) ? - &fsl_elbc_oob_lp_eccm1 : - &fsl_elbc_oob_lp_eccm0; + &fsl_elbc_oob_lp_eccm1 : + &fsl_elbc_oob_lp_eccm0; } } diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 22820d5..52b3d21 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -435,7 +435,7 @@ int nand_unlock(nand_info_t *meminfo, ulong start, ulong length) * @return image length including bad blocks */ static size_t get_len_incl_bad (nand_info_t *nand, size_t offset, - const size_t length) + const size_t length) { size_t len_incl_bad = 0; size_t len_excl_bad = 0; @@ -472,7 +472,7 @@ static size_t get_len_incl_bad (nand_info_t *nand, size_t offset, * @return 0 in case of success */ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, - u_char *buffer) + u_char *buffer) { int rval; size_t left_to_write = *length; @@ -497,7 +497,7 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, rval = nand_write (nand, offset, length, buffer); if (rval != 0) { printf ("NAND write to offset %x failed %d\n", - offset, rval); + offset, rval); return rval; } } @@ -521,7 +521,7 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, rval = nand_write (nand, offset, &write_size, p_buffer); if (rval != 0) { printf ("NAND write to offset %x failed %d\n", - offset, rval); + offset, rval); *length -= left_to_write; return rval; } @@ -567,7 +567,7 @@ int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length, rval = nand_read (nand, offset, length, buffer); if (rval != 0) { printf ("NAND read from offset %x failed %d\n", - offset, rval); + offset, rval); return rval; } } @@ -591,7 +591,7 @@ int nand_read_skip_bad(nand_info_t *nand, size_t offset, size_t *length, rval = nand_read (nand, offset, &read_length, p_buffer); if (rval != 0) { printf ("NAND read from offset %x failed %d\n", - offset, rval); + offset, rval); *length -= left_to_read; return rval; } diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7c9438b..9ce68e1 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -292,13 +292,13 @@ static int onenand_wait(struct mtd_info *mtd, int state) if (ctrl & ONENAND_CTRL_ERROR) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_wait: controller error = 0x%04x\n", ctrl); + "onenand_wait: controller error = 0x%04x\n", ctrl); return -EAGAIN; } if (ctrl & ONENAND_CTRL_LOCK) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_wait: it's locked error = 0x%04x\n", ctrl); + "onenand_wait: it's locked error = 0x%04x\n", ctrl); return -EIO; } @@ -306,7 +306,7 @@ static int onenand_wait(struct mtd_info *mtd, int state) ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS); if (ecc & ONENAND_ECC_2BIT_ALL) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_wait: ECC error = 0x%04x\n", ecc); + "onenand_wait: ECC error = 0x%04x\n", ecc); return -EBADMSG; } } @@ -328,7 +328,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area) if (ONENAND_CURRENT_BUFFERRAM(this)) { if (area == ONENAND_DATARAM) - return mtd->oobblock; + return mtd->writesize; if (area == ONENAND_SPARERAM) return mtd->oobsize; } @@ -479,6 +479,30 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, } /** + * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information + * @param mtd MTD data structure + * @param addr start address to invalidate + * @param len length to invalidate + * + * Invalidate BufferRAM information + */ +static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr, + unsigned int len) +{ + struct onenand_chip *this = mtd->priv; + int i; + loff_t end_addr = addr + len; + + /* Invalidate BufferRAM */ + for (i = 0; i < MAX_BUFFERRAM; i++) { + loff_t buf_addr = this->bufferram[i].block << this->erase_shift; + + if (buf_addr >= addr && buf_addr < end_addr) + this->bufferram[i].valid = 0; + } +} + +/** * onenand_get_device - [GENERIC] Get chip for selected access * @param mtd MTD device structure * @param new_state the state which is requested @@ -523,13 +547,13 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, int ret = 0; MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_read_ecc: " - "from = 0x%08x, len = %i\n", - (unsigned int)from, (int)len); + "from = 0x%08x, len = %i\n", + (unsigned int)from, (int)len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_read_ecc: " - "Attempt read beyond end of device\n"); + "Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } @@ -538,15 +562,15 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, onenand_get_device(mtd, FL_READING); while (read < len) { - thislen = min_t(int, mtd->oobblock, len - read); + thislen = min_t(int, mtd->writesize, len - read); - column = from & (mtd->oobblock - 1); - if (column + thislen > mtd->oobblock) - thislen = mtd->oobblock - column; + column = from & (mtd->writesize - 1); + if (column + thislen > mtd->writesize) + thislen = mtd->writesize - column; if (!onenand_check_bufferram(mtd, from)) { this->command(mtd, ONENAND_CMD_READ, from, - mtd->oobblock); + mtd->writesize); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ onenand_update_bufferram(mtd, from, 1); @@ -561,7 +585,7 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, if (ret) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_read_ecc: read failed = %d\n", ret); + "onenand_read_ecc: read failed = %d\n", ret); break; } @@ -615,8 +639,8 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, int ret = 0; MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_read_oob: " - "from = 0x%08x, len = %i\n", - (unsigned int)from, (int)len); + "from = 0x%08x, len = %i\n", + (unsigned int)from, (int)len); /* Initialize return length value */ *retlen = 0; @@ -624,7 +648,7 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, /* Do not allow reads past end of device */ if (unlikely((from + len) > mtd->size)) { MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_read_oob: " - "Attempt read beyond end of device\n"); + "Attempt read beyond end of device\n"); return -EINVAL; } @@ -653,7 +677,7 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, if (ret) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_read_oob: read failed = %d\n", ret); + "onenand_read_oob: read failed = %d\n", ret); break; } @@ -661,7 +685,7 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, /* Read more? */ if (read < len) { /* Page size */ - from += mtd->oobblock; + from += mtd->writesize; column = 0; } } @@ -688,7 +712,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, void __iomem *dataram0, *dataram1; int ret = 0; - this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); + this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize); ret = this->wait(mtd, FL_READING); if (ret) @@ -698,9 +722,9 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, /* Check, if the two dataram areas are same */ dataram0 = this->base + ONENAND_DATARAM; - dataram1 = dataram0 + mtd->oobblock; + dataram1 = dataram0 + mtd->writesize; - if (memcmp(dataram0, dataram1, mtd->oobblock)) + if (memcmp(dataram0, dataram1, mtd->writesize)) return -EBADMSG; return 0; @@ -709,7 +733,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, #define onenand_verify_page(...) (0) #endif -#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0) +#define NOTALIGNED(x) ((x & (mtd->writesize - 1)) != 0) /** * onenand_write_ecc - [MTD Interface] OneNAND write with ECC @@ -732,8 +756,8 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, int ret = 0; MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_write_ecc: " - "to = 0x%08x, len = %i\n", - (unsigned int)to, (int)len); + "to = 0x%08x, len = %i\n", + (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; @@ -741,14 +765,14 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_ecc: " - "Attempt write to past end of device\n"); + "Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_ecc: " - "Attempt to write not page aligned data\n"); + "Attempt to write not page aligned data\n"); return -EINVAL; } @@ -757,22 +781,22 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, /* Loop until all data write */ while (written < len) { - int thislen = min_t(int, mtd->oobblock, len - written); + int thislen = min_t(int, mtd->writesize, len - written); - this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize); this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); - this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); + this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); onenand_update_bufferram(mtd, to, 1); ret = this->wait(mtd, FL_WRITING); if (ret) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_write_ecc: write filaed %d\n", ret); + "onenand_write_ecc: write filaed %d\n", ret); break; } @@ -782,7 +806,7 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ret = onenand_verify_page(mtd, (u_char *) buf, to); if (ret) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_write_ecc: verify failed %d\n", ret); + "onenand_write_ecc: verify failed %d\n", ret); break; } @@ -836,8 +860,8 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, int written = 0; MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_write_oob: " - "to = 0x%08x, len = %i\n", - (unsigned int)to, (int)len); + "to = 0x%08x, len = %i\n", + (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; @@ -845,7 +869,7 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_write_oob: " - "Attempt write to past end of device\n"); + "Attempt write to past end of device\n"); return -EINVAL; } @@ -890,6 +914,25 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, } /** + * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad + * @param mtd MTD device structure + * @param ofs offset from device start + * @param allowbbt 1, if its allowed to access the bbt area + * + * Check, if the block is bad, Either by reading the bad block table or + * calling of the scan function. + */ +static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt) +{ + struct onenand_chip *this = mtd->priv; + struct bbm_info *bbm = this->bbm; + + /* Return info from the table */ + return bbm->isbad_bbt(mtd, ofs, allowbbt); +} + + +/** * onenand_erase - [MTD Interface] erase block(s) * @param mtd MTD device structure * @param instr erase instruction @@ -905,28 +948,28 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) int ret = 0; MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", - (unsigned int)instr->addr, (unsigned int)instr->len); + (unsigned int)instr->addr, (unsigned int)instr->len); block_size = (1 << this->erase_shift); /* Start address must align on block boundary */ if (unlikely(instr->addr & (block_size - 1))) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_erase: Unaligned address\n"); + "onenand_erase: Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (unlikely(instr->len & (block_size - 1))) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_erase: Length not block aligned\n"); + "onenand_erase: Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if (unlikely((instr->len + instr->addr) > mtd->size)) { MTDDEBUG (MTD_DEBUG_LEVEL0, - "onenand_erase: Erase past end of device\n"); + "onenand_erase: Erase past end of device\n"); return -EINVAL; } @@ -947,16 +990,18 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); + onenand_invalidate_bufferram(mtd, addr, block_size); + ret = this->wait(mtd, FL_ERASING); /* Check, if it is write protected */ if (ret) { if (ret == -EPERM) MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: " - "Device is write protected!!!\n"); + "Device is write protected!!!\n"); else MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: " - "Failed erase, block %d\n", - (unsigned)(addr >> this->erase_shift)); + "Failed erase, block %d\n", + (unsigned)(addr >> this->erase_shift)); instr->state = MTD_ERASE_FAILED; instr->fail_addr = addr; goto erase_exit; @@ -1002,30 +1047,45 @@ void onenand_sync(struct mtd_info *mtd) * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad * @param mtd MTD device structure * @param ofs offset relative to mtd start + * + * Check whether the block is bad */ int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs) { - /* - * TODO - * 1. Bad block table (BBT) - * -> using NAND BBT to support JFFS2 - * 2. Bad block management (BBM) - * -> bad block replace scheme - * - * Currently we do nothing - */ - return 0; + int ret; + + /* Check for invalid offset */ + if (ofs > mtd->size) + return -EINVAL; + + onenand_get_device(mtd, FL_READING); + ret = onenand_block_isbad_nolock(mtd,ofs, 0); + onenand_release_device(mtd); + return ret; } /** * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad * @param mtd MTD device structure * @param ofs offset relative to mtd start + * + * Mark the block as bad */ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) { - /* see above */ - return 0; + struct onenand_chip *this = mtd->priv; + int ret; + + ret = onenand_block_isbad(mtd, ofs); + if (ret) { + /* If it was bad already, return success and do nothing */ + if (ret > 0) + return 0; + return ret; + } + + ret = this->block_markbad(mtd, ofs); + return ret; } /** @@ -1181,10 +1241,8 @@ static int onenand_probe(struct mtd_info *mtd) /* Reset OneNAND to read default register values */ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); - { - int i; - for (i = 0; i < 10000; i++) ; - } + /* Wait reset */ + this->wait(mtd, FL_RESETING); /* Read manufacturer and device IDs from Register */ maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); @@ -1209,16 +1267,16 @@ static int onenand_probe(struct mtd_info *mtd) /* OneNAND page size & block size */ /* The data buffer size is equal to page size */ - mtd->oobblock = + mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); - mtd->oobsize = mtd->oobblock >> 5; + mtd->oobsize = mtd->writesize >> 5; /* Pagers per block is always 64 in OneNAND */ - mtd->erasesize = mtd->oobblock << 6; + mtd->erasesize = mtd->writesize << 6; this->erase_shift = ffs(mtd->erasesize) - 1; - this->page_shift = ffs(mtd->oobblock) - 1; + this->page_shift = ffs(mtd->writesize) - 1; this->ppb_shift = (this->erase_shift - this->page_shift); - this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; + this->page_mask = (mtd->erasesize / mtd->writesize) - 1; /* REVIST: Multichip handling */ @@ -1237,11 +1295,10 @@ static int onenand_probe(struct mtd_info *mtd) this->options |= ONENAND_CONT_LOCK; } + mtd->flags = MTD_CAP_NANDFLASH; mtd->erase = onenand_erase; mtd->read = onenand_read; mtd->write = onenand_write; - mtd->read_ecc = onenand_read_ecc; - mtd->write_ecc = onenand_write_ecc; mtd->read_oob = onenand_read_oob; mtd->write_oob = onenand_write_oob; mtd->sync = onenand_sync; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 0abaa1a..d13d277 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -94,7 +94,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf, /* No need to read pages fully, * just read required OOB bytes */ ret = onenand_read_oob(mtd, - from + j * mtd->oobblock + + from + j * mtd->writesize + bd->offs, readlen, &retlen, &buf[0]); @@ -104,7 +104,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf, } if (check_short_pattern - (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { + (&buf[j * scanlen], scanlen, mtd->writesize, bd)) { bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, |