Loading drivers/mtd/onenand/onenand_base.c +233 −116 Original line number Diff line number Diff line Loading @@ -763,31 +763,83 @@ static void onenand_release_device(struct mtd_info *mtd) } /** * onenand_read - [MTD Interface] Read data from flash * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from * @param thislen oob length to read */ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int readcol = column; int readend = column + thislen; int lastgap = 0; unsigned int i; uint8_t *oob_buf = this->oob_buf; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (readcol >= lastgap) readcol += free->offset - lastgap; if (readend >= lastgap) readend += free->offset - lastgap; lastgap = free->offset + free->length; } this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < readend && free_end > readcol) { int st = max_t(int,free->offset,readcol); int ed = min_t(int,free_end,readend); int n = ed - st; memcpy(buf, oob_buf + st, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_read_ops - [OneNAND Interface] OneNAND read main and/or out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * @param ops: oob operation description structure * * Read with ecc * OneNAND read main and/or out-of-band data */ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) static int onenand_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; struct mtd_ecc_stats stats; int read = 0, column; int thislen; size_t len = ops->len; size_t ooblen = ops->ooblen; u_char *buf = ops->datbuf; u_char *oobbuf = ops->oobbuf; int read = 0, column, thislen; int oobread = 0, oobcolumn, thisooblen, oobsize; int ret = 0, boundary = 0; int writesize = this->writesize; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; oobcolumn = from & (mtd->oobsize - 1); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n"); *retlen = 0; printk(KERN_ERR "onenand_read_ops: Attempt read beyond end of device\n"); ops->retlen = 0; ops->oobretlen = 0; return -EINVAL; } Loading Loading @@ -832,6 +884,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /* While load is going, read from last bufferRAM */ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); /* Read oob area if needed */ if (oobbuf) { thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); if (ops->mode == MTD_OOB_AUTO) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); oobread += thisooblen; oobbuf += thisooblen; oobcolumn = 0; } /* See if we are done */ read += thislen; if (read == len) Loading @@ -857,7 +924,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, * fs driver will take care of that, because * retlen == desired len and result == -EBADMSG */ *retlen = read; ops->retlen = read; ops->oobretlen = oobread; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; Loading @@ -868,56 +936,11 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from * @param thislen oob length to read */ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int readcol = column; int readend = column + thislen; int lastgap = 0; unsigned int i; uint8_t *oob_buf = this->oob_buf; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (readcol >= lastgap) readcol += free->offset - lastgap; if (readend >= lastgap) readend += free->offset - lastgap; lastgap = free->offset + free->length; } this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < readend && free_end > readcol) { int st = max_t(int,free->offset,readcol); int ed = min_t(int,free_end,readend); int n = ed - st; memcpy(buf, oob_buf + st, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * @param mode operation mode * @param ops: oob operation description structure * * OneNAND read out-of-band data from the spare area */ Loading Loading @@ -1007,10 +1030,39 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, } /** * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band * onenand_read - [MTD Interface] Read data from flash * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * * Read with ecc */ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_oob_ops ops = { .len = len, .ooblen = 0, .datbuf = buf, .oobbuf = NULL, }; int ret; ret = onenand_read_ops(mtd, from, &ops); *retlen = ops.retlen; return ret; } /** * onenand_read_oob - [MTD Interface] Read main and/or out-of-band * @param mtd: MTD device structure * @param from: offset to read from * @param ops: oob operation description structure * Read main and/or out-of-band */ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) Loading @@ -1024,6 +1076,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, default: return -EINVAL; } if (ops->datbuf) return onenand_read_ops(mtd, from, ops); return onenand_do_read_oob(mtd, from, ops); } Loading Loading @@ -1148,7 +1204,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, * @param mtd MTD device structure * @param buf the databuffer to verify * @param to offset to read from * */ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) { Loading Loading @@ -1176,7 +1231,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to * @param buf the databuffer to verify * @param addr offset to read from * @param len number of bytes to read and compare * */ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) { Loading Loading @@ -1222,27 +1276,72 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** * onenand_write - [MTD Interface] write buffer to FLASH * onenand_fill_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address * @param column oob offset to write to * @param thislen oob length to write */ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, const u_char *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int writecol = column; int writeend = column + thislen; int lastgap = 0; unsigned int i; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (writecol >= lastgap) writecol += free->offset - lastgap; if (writeend >= lastgap) writeend += free->offset - lastgap; lastgap = free->offset + free->length; } free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < writeend && free_end > writecol) { int st = max_t(int,free->offset,writecol); int ed = min_t(int,free_end,writeend); int n = ed - st; memcpy(oob_buf + st, buf, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_write_ops - [OneNAND Interface] write main and/or out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * @param ops oob operation description structure * * Write with ECC * Write main and/or oob with ECC */ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) static int onenand_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; int written = 0; int written = 0, column, thislen, subpage; int oobwritten = 0, oobcolumn, thisooblen, oobsize; size_t len = ops->len; size_t ooblen = ops->ooblen; const u_char *buf = ops->datbuf; const u_char *oob = ops->oobbuf; u_char *oobbuf; int ret = 0; int column, subpage; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ *retlen = 0; ops->retlen = 0; ops->oobretlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { Loading @@ -1256,6 +1355,13 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; oobcolumn = to & (mtd->oobsize - 1); column = to & (mtd->writesize - 1); /* Grab the lock and see if the device is available */ Loading @@ -1263,9 +1369,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Loop until all data write */ while (written < len) { int thislen = min_t(int, mtd->writesize - column, len - written); u_char *wbuf = (u_char *) buf; thislen = min_t(int, mtd->writesize - column, len - written); thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); cond_resched(); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); Loading @@ -1279,7 +1387,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, } this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); if (oob) { oobbuf = this->oob_buf; /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); if (ops->mode == MTD_OOB_AUTO) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); else memcpy(oobbuf + oobcolumn, oob, thisooblen); oobwritten += thisooblen; oob += thisooblen; oobcolumn = 0; } else oobbuf = (u_char *) ffchars; this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); Loading Loading @@ -1317,51 +1443,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); *retlen = written; ops->retlen = written; return ret; } /** * onenand_fill_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address * @param column oob offset to write to * @param thislen oob length to write */ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, const u_char *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int writecol = column; int writeend = column + thislen; int lastgap = 0; unsigned int i; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (writecol >= lastgap) writecol += free->offset - lastgap; if (writeend >= lastgap) writeend += free->offset - lastgap; lastgap = free->offset + free->length; } free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < writeend && free_end > writecol) { int st = max_t(int,free->offset,writecol); int ed = min_t(int,free_end,writeend); int n = ed - st; memcpy(oob_buf + st, buf, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_do_write_oob - [Internal] OneNAND write out-of-band Loading Loading @@ -1478,6 +1564,33 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, return ret; } /** * onenand_write - [MTD Interface] write buffer to FLASH * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * * Write with ECC */ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct mtd_oob_ops ops = { .len = len, .ooblen = 0, .datbuf = (u_char *) buf, .oobbuf = NULL, }; int ret; ret = onenand_write_ops(mtd, to, &ops); *retlen = ops.retlen; return ret; } /** * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @param mtd: MTD device structure Loading @@ -1496,6 +1609,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, default: return -EINVAL; } if (ops->datbuf) return onenand_write_ops(mtd, to, ops); return onenand_do_write_oob(mtd, to, ops); } Loading Loading
drivers/mtd/onenand/onenand_base.c +233 −116 Original line number Diff line number Diff line Loading @@ -763,31 +763,83 @@ static void onenand_release_device(struct mtd_info *mtd) } /** * onenand_read - [MTD Interface] Read data from flash * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from * @param thislen oob length to read */ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int readcol = column; int readend = column + thislen; int lastgap = 0; unsigned int i; uint8_t *oob_buf = this->oob_buf; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (readcol >= lastgap) readcol += free->offset - lastgap; if (readend >= lastgap) readend += free->offset - lastgap; lastgap = free->offset + free->length; } this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < readend && free_end > readcol) { int st = max_t(int,free->offset,readcol); int ed = min_t(int,free_end,readend); int n = ed - st; memcpy(buf, oob_buf + st, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_read_ops - [OneNAND Interface] OneNAND read main and/or out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * @param ops: oob operation description structure * * Read with ecc * OneNAND read main and/or out-of-band data */ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) static int onenand_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; struct mtd_ecc_stats stats; int read = 0, column; int thislen; size_t len = ops->len; size_t ooblen = ops->ooblen; u_char *buf = ops->datbuf; u_char *oobbuf = ops->oobbuf; int read = 0, column, thislen; int oobread = 0, oobcolumn, thisooblen, oobsize; int ret = 0, boundary = 0; int writesize = this->writesize; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; oobcolumn = from & (mtd->oobsize - 1); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { printk(KERN_ERR "onenand_read: Attempt read beyond end of device\n"); *retlen = 0; printk(KERN_ERR "onenand_read_ops: Attempt read beyond end of device\n"); ops->retlen = 0; ops->oobretlen = 0; return -EINVAL; } Loading Loading @@ -832,6 +884,21 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, } /* While load is going, read from last bufferRAM */ this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); /* Read oob area if needed */ if (oobbuf) { thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); if (ops->mode == MTD_OOB_AUTO) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); oobread += thisooblen; oobbuf += thisooblen; oobcolumn = 0; } /* See if we are done */ read += thislen; if (read == len) Loading @@ -857,7 +924,8 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, * fs driver will take care of that, because * retlen == desired len and result == -EBADMSG */ *retlen = read; ops->retlen = read; ops->oobretlen = oobread; if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; Loading @@ -868,56 +936,11 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from * @param thislen oob length to read */ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int readcol = column; int readend = column + thislen; int lastgap = 0; unsigned int i; uint8_t *oob_buf = this->oob_buf; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (readcol >= lastgap) readcol += free->offset - lastgap; if (readend >= lastgap) readend += free->offset - lastgap; lastgap = free->offset + free->length; } this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < readend && free_end > readcol) { int st = max_t(int,free->offset,readcol); int ed = min_t(int,free_end,readend); int n = ed - st; memcpy(buf, oob_buf + st, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_do_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * @param mode operation mode * @param ops: oob operation description structure * * OneNAND read out-of-band data from the spare area */ Loading Loading @@ -1007,10 +1030,39 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, } /** * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band * onenand_read - [MTD Interface] Read data from flash * @param mtd MTD device structure * @param from offset to read from * @param len number of bytes to read * @param retlen pointer to variable to store the number of read bytes * @param buf the databuffer to put data * * Read with ecc */ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_oob_ops ops = { .len = len, .ooblen = 0, .datbuf = buf, .oobbuf = NULL, }; int ret; ret = onenand_read_ops(mtd, from, &ops); *retlen = ops.retlen; return ret; } /** * onenand_read_oob - [MTD Interface] Read main and/or out-of-band * @param mtd: MTD device structure * @param from: offset to read from * @param ops: oob operation description structure * Read main and/or out-of-band */ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) Loading @@ -1024,6 +1076,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, default: return -EINVAL; } if (ops->datbuf) return onenand_read_ops(mtd, from, ops); return onenand_do_read_oob(mtd, from, ops); } Loading Loading @@ -1148,7 +1204,6 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, * @param mtd MTD device structure * @param buf the databuffer to verify * @param to offset to read from * */ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) { Loading Loading @@ -1176,7 +1231,6 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to * @param buf the databuffer to verify * @param addr offset to read from * @param len number of bytes to read and compare * */ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, size_t len) { Loading Loading @@ -1222,27 +1276,72 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** * onenand_write - [MTD Interface] write buffer to FLASH * onenand_fill_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address * @param column oob offset to write to * @param thislen oob length to write */ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, const u_char *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int writecol = column; int writeend = column + thislen; int lastgap = 0; unsigned int i; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (writecol >= lastgap) writecol += free->offset - lastgap; if (writeend >= lastgap) writeend += free->offset - lastgap; lastgap = free->offset + free->length; } free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < writeend && free_end > writecol) { int st = max_t(int,free->offset,writecol); int ed = min_t(int,free_end,writeend); int n = ed - st; memcpy(oob_buf + st, buf, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_write_ops - [OneNAND Interface] write main and/or out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * @param ops oob operation description structure * * Write with ECC * Write main and/or oob with ECC */ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) static int onenand_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct onenand_chip *this = mtd->priv; int written = 0; int written = 0, column, thislen, subpage; int oobwritten = 0, oobcolumn, thisooblen, oobsize; size_t len = ops->len; size_t ooblen = ops->ooblen; const u_char *buf = ops->datbuf; const u_char *oob = ops->oobbuf; u_char *oobbuf; int ret = 0; int column, subpage; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Initialize retlen, in case of early exit */ *retlen = 0; ops->retlen = 0; ops->oobretlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { Loading @@ -1256,6 +1355,13 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } if (ops->mode == MTD_OOB_AUTO) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; oobcolumn = to & (mtd->oobsize - 1); column = to & (mtd->writesize - 1); /* Grab the lock and see if the device is available */ Loading @@ -1263,9 +1369,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Loop until all data write */ while (written < len) { int thislen = min_t(int, mtd->writesize - column, len - written); u_char *wbuf = (u_char *) buf; thislen = min_t(int, mtd->writesize - column, len - written); thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten); cond_resched(); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); Loading @@ -1279,7 +1387,25 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, } this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); if (oob) { oobbuf = this->oob_buf; /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); if (ops->mode == MTD_OOB_AUTO) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); else memcpy(oobbuf + oobcolumn, oob, thisooblen); oobwritten += thisooblen; oob += thisooblen; oobcolumn = 0; } else oobbuf = (u_char *) ffchars; this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); Loading Loading @@ -1317,51 +1443,11 @@ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); *retlen = written; ops->retlen = written; return ret; } /** * onenand_fill_auto_oob - [Internal] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address * @param column oob offset to write to * @param thislen oob length to write */ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, const u_char *buf, int column, int thislen) { struct onenand_chip *this = mtd->priv; struct nand_oobfree *free; int writecol = column; int writeend = column + thislen; int lastgap = 0; unsigned int i; free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { if (writecol >= lastgap) writecol += free->offset - lastgap; if (writeend >= lastgap) writeend += free->offset - lastgap; lastgap = free->offset + free->length; } free = this->ecclayout->oobfree; for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { int free_end = free->offset + free->length; if (free->offset < writeend && free_end > writecol) { int st = max_t(int,free->offset,writecol); int ed = min_t(int,free_end,writeend); int n = ed - st; memcpy(oob_buf + st, buf, n); buf += n; } else if (column == 0) break; } return 0; } /** * onenand_do_write_oob - [Internal] OneNAND write out-of-band Loading Loading @@ -1478,6 +1564,33 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, return ret; } /** * onenand_write - [MTD Interface] write buffer to FLASH * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write * @param retlen pointer to variable to store the number of written bytes * @param buf the data to write * * Write with ECC */ static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct mtd_oob_ops ops = { .len = len, .ooblen = 0, .datbuf = (u_char *) buf, .oobbuf = NULL, }; int ret; ret = onenand_write_ops(mtd, to, &ops); *retlen = ops.retlen; return ret; } /** * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @param mtd: MTD device structure Loading @@ -1496,6 +1609,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, default: return -EINVAL; } if (ops->datbuf) return onenand_write_ops(mtd, to, ops); return onenand_do_write_oob(mtd, to, ops); } Loading