|
@@ -331,7 +331,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;
|
|
|
}
|
|
@@ -481,6 +481,30 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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
|
|
@@ -541,15 +565,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);
|
|
@@ -664,7 +688,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;
|
|
|
}
|
|
|
}
|
|
@@ -691,7 +715,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)
|
|
@@ -701,9 +725,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;
|
|
@@ -712,7 +736,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
|
|
@@ -760,15 +784,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);
|
|
|
|
|
@@ -892,6 +916,25 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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
|
|
@@ -950,6 +993,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) {
|
|
@@ -1005,30 +1050,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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1184,10 +1244,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);
|
|
@@ -1212,16 +1270,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 */
|
|
|
|
|
@@ -1240,11 +1298,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;
|