📄 onenand_base.c
字号:
}/** * onenand_update_bufferram - [GENERIC] Update BufferRAM information * @param mtd MTD data structure * @param addr address to update * @param valid valid flag * * Update BufferRAM information */static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr, int valid){ struct onenand_chip *this = mtd->priv; int block, page; int i; block = (int)(addr >> this->erase_shift); page = (int)(addr >> this->page_shift); page &= this->page_mask; /* Invalidate BufferRAM */ for (i = 0; i < MAX_BUFFERRAM; i++) { if (this->bufferram[i].block == block && this->bufferram[i].page == page) this->bufferram[i].valid = 0; } /* Update BufferRAM */ i = ONENAND_CURRENT_BUFFERRAM(this); this->bufferram[i].block = block; this->bufferram[i].page = page; this->bufferram[i].valid = valid; return 0;}/** * onenand_get_device - [GENERIC] Get chip for selected access * @param mtd MTD device structure * @param new_state the state which is requested * * Get the device and lock it for exclusive access */static void onenand_get_device(struct mtd_info *mtd, int new_state){ /* Do nothing */}/** * onenand_release_device - [GENERIC] release chip * @param mtd MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device */static void onenand_release_device(struct mtd_info *mtd){ /* Do nothing */}/** * onenand_read_ecc - [MTD Interface] Read data with ECC * @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 oob_buf filesystem supplied oob data buffer * @param oobsel oob selection structure * * OneNAND read with ECC */static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel){ struct onenand_chip *this = mtd->priv; int read = 0, column; int thislen; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_READING); while (read < len) { thislen = min_t(int, mtd->oobblock, len - read); column = from & (mtd->oobblock - 1); if (column + thislen > mtd->oobblock) thislen = mtd->oobblock - column; if (!onenand_check_bufferram(mtd, from)) { this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ onenand_update_bufferram(mtd, from, 1); } this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); read += thislen; if (read == len) break; if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret); break; } from += thislen; buf += thislen; } /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG * fs driver will take care of that, because * retlen == desired len and result == -EBADMSG */ *retlen = read; return ret;}/** * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc * @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 * * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL*/int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){ return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);}/** * onenand_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 * * OneNAND read out-of-band data from the spare area */int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){ struct onenand_chip *this = mtd->priv; int read = 0, thislen, column; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len); /* Initialize return length value */ *retlen = 0; /* Do not allow reads past end of device */ if (unlikely((from + len) > mtd->size)) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_READING); column = from & (mtd->oobsize - 1); while (read < len) { thislen = mtd->oobsize - column; thislen = min_t(int, thislen, len); this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize); onenand_update_bufferram(mtd, from, 0); ret = this->wait(mtd, FL_READING); /* First copy data and check return value for ECC handling */ this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); read += thislen; if (read == len) break; if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret); break; } buf += thislen; /* Read more? */ if (read < len) { /* Page size */ from += mtd->oobblock; column = 0; } } /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); *retlen = read; return ret;}#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE/** * onenand_verify_page - [GENERIC] verify the chip contents after a write * @param mtd MTD device structure * @param buf the databuffer to verify * @param block block address * @param page page address * * Check DataRAM area directly */static int onenand_verify_page(struct mtd_info *mtd, u_char * buf, loff_t addr, int block, int page){ struct onenand_chip *this = mtd->priv; void __iomem *dataram0, *dataram1; int ret = 0; this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); ret = this->wait(mtd, FL_READING); if (ret) return ret; onenand_update_bufferram(mtd, addr, 1); /* Check, if the two dataram areas are same */ dataram0 = this->base + ONENAND_DATARAM; dataram1 = dataram0 + mtd->oobblock; if (memcmp(dataram0, dataram1, mtd->oobblock)) return -EBADMSG; return 0;}#else#define onenand_verify_page(...) (0)#endif#define NOTALIGNED(x) ((x & (mtd->oobblock - 1)) != 0)/** * onenand_write_ecc - [MTD Interface] OneNAND write with ECC * @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 eccbuf filesystem supplied oob data buffer * @param oobsel oob selection structure * * OneNAND write with ECC */static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel){ struct onenand_chip *this = mtd->priv; int written = 0; int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n"); return -EINVAL; } /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); /* Loop until all data write */ while (written < len) { int thislen = min_t(int, mtd->oobblock, len - written); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); 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); onenand_update_bufferram(mtd, to, 1); ret = this->wait(mtd, FL_WRITING); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret); break; } written += thislen; /* Only check verify write turn on */ ret = onenand_verify_page(mtd, (u_char *) buf, to, block, page); if (ret) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret); break; } if (written == len) break; to += thislen; buf += thislen; } /* Deselect and wake up anyone waiting on the device */ onenand_release_device(mtd); *retlen = written; return ret;}/** * onenand_write - [MTD Interface] compability function for onenand_write_ecc * @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 * * This function simply calls onenand_write_ecc * with oob buffer and oobsel = NULL */int onenand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){ return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);}/** * onenand_write_oob - [MTD Interface] OneNAND write 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 * * OneNAND write out-of-band */int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){ struct onenand_chip *this = mtd->priv; int column, status; int written = 0; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; /* Do not allow writes past end of device */ if (unlikely((to + len) > mtd->size)) { DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n"); return -EINVAL; } /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); /* Loop until all data write */ while (written < len) { int thislen = min_t(int, mtd->oobsize, len - written); column = to & (mtd->oobsize - 1); this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize); this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); status = this->wait(mtd, FL_WRITING); if (status) break; written += thislen; if (written == len)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -