⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 onenand_base.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 4 页
字号:
 */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].blockpage << this->page_shift;		if (buf_addr >= addr && buf_addr < end_addr)			this->bufferram[i].blockpage = -1;	}}/** * 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_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, 0, 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_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band * @param mtd		MTD device structure * @param from		offset to read from * @param ops		oob operation description structure * * OneNAND read main and/or out-of-band data */static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,		struct mtd_oob_ops *ops){	struct onenand_chip *this = mtd->priv;	struct mtd_ecc_stats stats;	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;	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: 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_ops_nolock: Attempt read beyond end of device\n");		ops->retlen = 0;		ops->oobretlen = 0;		return -EINVAL;	}	stats = mtd->ecc_stats;	/* Read-while-load method */	/* Do first load to bufferRAM */	if (read < len) {		if (!onenand_check_bufferram(mtd, from)) {			this->main_buf = buf;			this->command(mtd, ONENAND_CMD_READ, from, writesize);			ret = this->wait(mtd, FL_READING);			onenand_update_bufferram(mtd, from, !ret);			if (ret == -EBADMSG)				ret = 0;		}	}	thislen = min_t(int, writesize, len - read);	column = from & (writesize - 1);	if (column + thislen > writesize)		thislen = writesize - column;	while (!ret) {		/* If there is more to load then start next load */		from += thislen;		if (read + thislen < len) {			this->main_buf = buf + thislen;			this->command(mtd, ONENAND_CMD_READ, from, writesize);			/*			 * Chip boundary handling in DDP			 * Now we issued chip 1 read and pointed chip 1			 * bufferam so we have to point chip 0 bufferam.			 */			if (ONENAND_IS_DDP(this) &&					unlikely(from == (this->chipsize >> 1))) {				this->write_word(ONENAND_DDP_CHIP0, this->base + ONENAND_REG_START_ADDRESS2);				boundary = 1;			} else				boundary = 0;			ONENAND_SET_PREV_BUFFERRAM(this);		}		/* While load is going, read from last bufferRAM */		this->read_bufferram(mtd, from - thislen, 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, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen);			oobread += thisooblen;			oobbuf += thisooblen;			oobcolumn = 0;		}		/* See if we are done */		read += thislen;		if (read == len)			break;		/* Set up for next read from bufferRAM */		if (unlikely(boundary))			this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);		ONENAND_SET_NEXT_BUFFERRAM(this);		buf += thislen;		thislen = min_t(int, writesize, len - read);		column = 0;		/* Now wait for load */		ret = this->wait(mtd, FL_READING);		onenand_update_bufferram(mtd, from, !ret);		if (ret == -EBADMSG)			ret = 0;	}	/*	 * Return success, if no ECC failures, else -EBADMSG	 * fs driver will take care of that, because	 * retlen == desired len and result == -EBADMSG	 */	ops->retlen = read;	ops->oobretlen = oobread;	if (ret)		return ret;	if (mtd->ecc_stats.failed - stats.failed)		return -EBADMSG;	return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;}/** * onenand_read_oob_nolock - [MTD Interface] OneNAND read out-of-band * @param mtd		MTD device structure * @param from		offset to read from * @param ops		oob operation description structure * * OneNAND read out-of-band data from the spare area */static int onenand_read_oob_nolock(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, thislen, column, oobsize;	size_t len = ops->ooblen;	mtd_oob_mode_t mode = ops->mode;	u_char *buf = ops->oobbuf;	int ret = 0;	from += ops->ooboffs;	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Initialize return length value */	ops->oobretlen = 0;	if (mode == MTD_OOB_AUTO)		oobsize = this->ecclayout->oobavail;	else		oobsize = mtd->oobsize;	column = from & (mtd->oobsize - 1);	if (unlikely(column >= oobsize)) {		printk(KERN_ERR "onenand_read_oob_nolock: Attempted to start read outside oob\n");		return -EINVAL;	}	/* Do not allow reads past end of device */	if (unlikely(from >= mtd->size ||		column + len > ((mtd->size >> this->page_shift) -				(from >> this->page_shift)) * oobsize)) {		printk(KERN_ERR "onenand_read_oob_nolock: Attempted to read beyond end of device\n");		return -EINVAL;	}	stats = mtd->ecc_stats;	while (read < len) {		thislen = oobsize - column;		thislen = min_t(int, thislen, len);		this->spare_buf = buf;		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);		onenand_update_bufferram(mtd, from, 0);		ret = this->wait(mtd, FL_READING);		if (ret && ret != -EBADMSG) {			printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);			break;		}		if (mode == MTD_OOB_AUTO)			onenand_transfer_auto_oob(mtd, buf, column, thislen);		else			this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);		read += thislen;		if (read == len)			break;		buf += thislen;		/* Read more? */		if (read < len) {			/* Page size */			from += mtd->writesize;			column = 0;		}	}	ops->oobretlen = read;	if (ret)		return ret;	if (mtd->ecc_stats.failed - stats.failed)		return -EBADMSG;	return 0;}/** * 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){	struct mtd_oob_ops ops = {		.len    = len,		.ooblen = 0,		.datbuf = buf,		.oobbuf = NULL,	};	int ret;	onenand_get_device(mtd, FL_READING);	ret = onenand_read_ops_nolock(mtd, from, &ops);	onenand_release_device(mtd);	*retlen = ops.retlen;	return ret;}/** * onenand_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd		MTD device structure * @param from		offset to read from * @param ops		oob operations description structure * * OneNAND main and/or out-of-band */int onenand_read_oob(struct mtd_info *mtd, loff_t from,			struct mtd_oob_ops *ops){	int ret;	switch (ops->mode) {	case MTD_OOB_PLACE:	case MTD_OOB_AUTO:		break;	case MTD_OOB_RAW:		/* Not implemented yet */	default:		return -EINVAL;	}	onenand_get_device(mtd, FL_READING);	if (ops->datbuf)		ret = onenand_read_ops_nolock(mtd, from, ops);	else		ret = onenand_read_oob_nolock(mtd, from, ops);	onenand_release_device(mtd);	return ret;}/** * onenand_bbt_wait - [DEFAULT] wait until the command is done * @param mtd		MTD device structure * @param state		state to select the max. timeout value * * Wait for command done. */static int onenand_bbt_wait(struct mtd_info *mtd, int state){	struct onenand_chip *this = mtd->priv;	unsigned int flags = ONENAND_INT_MASTER;	unsigned int interrupt;	unsigned int ctrl;	while (1) {		interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);		if (interrupt & flags)			break;	}	/* To get correct interrupt status in timeout case */	interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);	ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);	if (interrupt & ONENAND_INT_READ) {		int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);		if (ecc & ONENAND_ECC_2BIT_ALL)			return ONENAND_BBT_READ_ERROR;	} else {		printk(KERN_ERR "onenand_bbt_wait: read timeout!"				"ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);		return ONENAND_BBT_READ_FATAL_ERROR;	}	/* Initial bad block case: 0x2400 or 0x0400 */	if (ctrl & ONENAND_CTRL_ERROR) {		printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);		return ONENAND_BBT_READ_ERROR;	}	return 0;}/** * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan * @param mtd		MTD device structure * @param from		offset to read from * @param ops		oob operation description structure * * OneNAND read out-of-band data from the spare area for bbt scan */int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,		struct mtd_oob_ops *ops){	struct onenand_chip *this = mtd->priv;	int read = 0, thislen, column;	int ret = 0;	size_t len = ops->ooblen;	u_char *buf = ops->oobbuf;	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_bbt_read_oob: from = 0x%08x, len = %zi\n", (unsigned int) from, len);	/* Initialize return value */	ops->oobretlen = 0;	/* Do not allow reads past end of device */	if (unlikely((from + len) > mtd->size)) {		printk(KERN_ERR "onenand_bbt_read_oob: Attempt read beyond end of device\n");		return ONENAND_BBT_READ_FATAL_ERROR;	}	/* 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->spare_buf = buf;		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);		onenand_update_bufferram(mtd, from, 0);		ret = this->bbt_wait(mtd, FL_READING);		if (ret)			break;		this->read_spareram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen);		read += thislen;		if (read == len)			break;		buf += thislen;		/* Read more? */		if (read < len) {			/* Update Page size */			from += this->writesize;			column = 0;		}	}	/* Deselect and wake up anyone waiting on the device */	onenand_release_device(mtd);	ops->oobretlen = read;	return ret;}#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE/** * onenand_verify_oob - [GENERIC] verify the oob contents after a write * @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){	struct onenand_chip *this = mtd->priv;	u_char *oob_buf = this->oob_buf;	int status, i;	this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);	onenand_update_bufferram(mtd, to, 0);	status = this->wait(mtd, FL_READING);	if (status)		return status;	this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize);	for (i = 0; i < mtd->oobsize; i++)		if (buf[i] != 0xFF && buf[i] != oob_buf[i])			return -EBADMSG;	return 0;}/** * onenand_verify - [GENERIC] verify the chip contents after a write * @param mtd          MTD device structure * @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){	struct onenand_chip *this = mtd->priv;	void __iomem *dataram;	int ret = 0;	int thislen, column;	while (len != 0) {		thislen = min_t(int, this->writesize, len);		column = addr & (this->writesize - 1);		if (column + thislen > this->writesize)			thislen = this->writesize - column;		this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);		onenand_update_bufferram(mtd, addr, 0);		ret = this->wait(mtd, FL_READING);		if (ret)			return ret;		onenand_update_bufferram(mtd, addr, 1);		dataram = this->base + ONENAND_DATARAM;		dataram += onenand_bufferram_offset(mtd, ONENAND_DATARAM);		if (memcmp(buf, dataram + column, thislen))			return -EBADMSG;		len -= thislen;		buf += thislen;		addr += thislen;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -