diff options
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
-rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 131 |
1 files changed, 94 insertions, 37 deletions
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7c9438b..8f12fa2 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -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 @@ -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); @@ -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 @@ -757,15 +781,15 @@ 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); @@ -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 @@ -947,6 +990,8 @@ 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) { @@ -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; |