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

📄 onenand_base.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 4 页
字号:
	return 0;}#else#define onenand_verify(...)             (0)#define onenand_verify_oob(...)         (0)#endif#define NOTALIGNED(x)	((x & (this->subpagesize - 1)) != 0)/** * 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_nolock - [OneNAND Interface] write main and/or out-of-band * @param mtd           MTD device structure * @param to            offset to write to * @param ops           oob operation description structure * * Write main and/or oob with ECC */static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,		struct mtd_oob_ops *ops){	struct onenand_chip *this = mtd->priv;	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;	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ops_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Initialize retlen, in case of early exit */	ops->retlen = 0;	ops->oobretlen = 0;	/* Do not allow writes past end of device */	if (unlikely((to + len) > mtd->size)) {		printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n");		return -EINVAL;	}	/* Reject writes, which are not page aligned */	if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) {		printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n");		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);	/* Loop until all data write */	while (written < len) {		u_char *wbuf = (u_char *) buf;		thislen = min_t(int, mtd->writesize - column, len - written);		thisooblen = min_t(int, oobsize - oobcolumn, ooblen - oobwritten);		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen);		/* Partial page write */		subpage = thislen < mtd->writesize;		if (subpage) {			memset(this->page_buf, 0xff, mtd->writesize);			memcpy(this->page_buf + column, buf, thislen);			wbuf = this->page_buf;		}		this->write_bufferram(mtd, to, ONENAND_DATARAM, wbuf, 0, mtd->writesize);		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, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);		ret = this->wait(mtd, FL_WRITING);		/* In partial page write we don't update bufferram */		onenand_update_bufferram(mtd, to, !ret && !subpage);		if (ONENAND_IS_2PLANE(this)) {			ONENAND_SET_BUFFERRAM1(this);			onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);		}		if (ret) {			printk(KERN_ERR "onenand_write_ops_nolock: write filaed %d\n", ret);			break;		}		/* Only check verify write turn on */		ret = onenand_verify(mtd, buf, to, thislen);		if (ret) {			printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret);			break;		}		written += thislen;		if (written == len)			break;		column = 0;		to += thislen;		buf += thislen;	}	ops->retlen = written;	return ret;}/** * onenand_write_oob_nolock - [Internal] 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 * @param mode          operation mode * * OneNAND write out-of-band */static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,		struct mtd_oob_ops *ops){	struct onenand_chip *this = mtd->priv;	int column, ret = 0, oobsize;	int written = 0;	u_char *oobbuf;	size_t len = ops->ooblen;	const u_char *buf = ops->oobbuf;	mtd_oob_mode_t mode = ops->mode;	to += ops->ooboffs;	MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob_nolock: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Initialize retlen, in case of early exit */	ops->oobretlen = 0;	if (mode == MTD_OOB_AUTO)		oobsize = this->ecclayout->oobavail;	else		oobsize = mtd->oobsize;	column = to & (mtd->oobsize - 1);	if (unlikely(column >= oobsize)) {		printk(KERN_ERR "onenand_write_oob_nolock: Attempted to start write outside oob\n");		return -EINVAL;	}	/* For compatibility with NAND: Do not allow write past end of page */	if (unlikely(column + len > oobsize)) {		printk(KERN_ERR "onenand_write_oob_nolock: "				"Attempt to write past end of page\n");		return -EINVAL;	}	/* Do not allow reads past end of device */	if (unlikely(to >= mtd->size ||				column + len > ((mtd->size >> this->page_shift) -					(to >> this->page_shift)) * oobsize)) {		printk(KERN_ERR "onenand_write_oob_nolock: Attempted to write past end of device\n");		return -EINVAL;	}	oobbuf = this->oob_buf;	/* Loop until all data write */	while (written < len) {		int thislen = min_t(int, oobsize, len - written);		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);		/* We send data to spare ram with oobsize		 * to prevent byte access */		memset(oobbuf, 0xff, mtd->oobsize);		if (mode == MTD_OOB_AUTO)			onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen);		else			memcpy(oobbuf + column, buf, thislen);		this->write_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);		this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);		onenand_update_bufferram(mtd, to, 0);		if (ONENAND_IS_2PLANE(this)) {			ONENAND_SET_BUFFERRAM1(this);			onenand_update_bufferram(mtd, to + this->writesize, 0);		}		ret = this->wait(mtd, FL_WRITING);		if (ret) {			printk(KERN_ERR "onenand_write_oob_nolock: write failed %d\n", ret);			break;		}		ret = onenand_verify_oob(mtd, oobbuf, to);		if (ret) {			printk(KERN_ERR "onenand_write_oob_nolock: verify failed %d\n", ret);			break;		}		written += thislen;		if (written == len)			break;		to += mtd->writesize;		buf += thislen;		column = 0;	}	ops->oobretlen = 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 * * Write with ECC */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;	onenand_get_device(mtd, FL_WRITING);	ret = onenand_write_ops_nolock(mtd, to, &ops);	onenand_release_device(mtd);	*retlen = ops.retlen;	return ret;}/** * onenand_write_oob - [MTD Interface] OneNAND write out-of-band * @param mtd		MTD device structure * @param to		offset to write to * @param ops		oob operation description structure * * OneNAND write main and/or out-of-band */int onenand_write_oob(struct mtd_info *mtd, loff_t to,			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_WRITING);	if (ops->datbuf)		ret = onenand_write_ops_nolock(mtd, to, ops);	else		ret = onenand_write_oob_nolock(mtd, to, ops);	onenand_release_device(mtd);	return ret;}/** * 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 * * Erase one ore more blocks */int onenand_erase(struct mtd_info *mtd, struct erase_info *instr){	struct onenand_chip *this = mtd->priv;	unsigned int block_size;	loff_t addr;	int len;	int ret = 0;	MTDDEBUG (MTD_DEBUG_LEVEL3,		 "onenand_erase: start = 0x%08x, len = %i\n",		 (unsigned int)instr->addr, (unsigned int)instr->len);	block_size = (1 << this->erase_shift);	/* Start address must align on block boundary */	if (unlikely(instr->addr & (block_size - 1))) {		MTDDEBUG (MTD_DEBUG_LEVEL0,			 "onenand_erase: Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (unlikely(instr->len & (block_size - 1))) {		MTDDEBUG (MTD_DEBUG_LEVEL0,			 "onenand_erase: Length not block aligned\n");		return -EINVAL;	}	/* Do not allow erase past end of device */	if (unlikely((instr->len + instr->addr) > mtd->size)) {		MTDDEBUG (MTD_DEBUG_LEVEL0,			 "onenand_erase: Erase past end of device\n");		return -EINVAL;	}	instr->fail_addr = 0xffffffff;	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_ERASING);	/* Loop throught the pages */	len = instr->len;	addr = instr->addr;	instr->state = MTD_ERASING;	while (len) {		/* Check if we have a bad block, we do not erase bad blocks */		if (instr->priv == 0 && onenand_block_isbad_nolock(mtd, addr, 0)) {			printk(KERN_WARNING "onenand_erase: attempt to erase"				" a bad block at addr 0x%08x\n",				(unsigned int) addr);			instr->state = MTD_ERASE_FAILED;			goto erase_exit;		}		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) {			if (ret == -EPERM)				MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "					  "Device is write protected!!!\n");			else				MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "					  "Failed erase, block %d\n",					  (unsigned)(addr >> this->erase_shift));			if (ret == -EPERM)				printk("onenand_erase: "					  "Device is write protected!!!\n");			else				printk("onenand_erase: "					  "Failed erase, block %d\n",					  (unsigned)(addr >> this->erase_shift));			instr->state = MTD_ERASE_FAILED;			instr->fail_addr = addr;			goto erase_exit;		}		len -= block_size;		addr += block_size;	}	instr->state = MTD_ERASE_DONE;erase_exit:	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;	/* Do call back function */	if (!ret)		mtd_erase_callback(instr);	/* Deselect and wake up anyone waiting on the device */	onenand_release_device(mtd);	return ret;}/** * onenand_sync - [MTD Interface] sync * @param mtd		MTD device structure * * Sync is actually a wait for chip ready function */void onenand_sync(struct mtd_info *mtd){	MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_sync: called\n");	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_SYNCING);	/* Release it and go back */	onenand_release_device(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){	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_default_block_markbad - [DEFAULT] mark a block bad * @param mtd           MTD device structure * @param ofs           offset from device start * * This is the default implementation, which can be overridden by * a hardware specific driver. */static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs){	struct onenand_chip *this = mtd->priv;	struct bbm_info *bbm = this->bbm;	u_char buf[2] = {0, 0};	struct mtd_oob_ops ops = {		.mode = MTD_OOB_PLACE,		.ooblen = 2,		.oobbuf = buf,		.ooboffs = 0,	};	int block;	/* Get block number */	block = ((int) ofs) >> bbm->bbt_erase_shift;	if (bbm->bbt)		bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);	/* We write two bytes, so we dont have to mess with 16 bit access */	ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);	return onenand_write_oob_nolock(mtd, ofs, &ops);}/** * 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)

⌨️ 快捷键说明

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