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

📄 onenand_base.c

📁 项目源码察看工具---- MTD工具
💻 C
📖 第 1 页 / 共 4 页
字号:
out:	/* Deselect and wake up anyone waiting on the device */	onenand_release_device(mtd);	*retlen = written;	return ret;}/** * onenand_writev_ecc - [MTD Interface] write with iovec with ecc * @param mtd		MTD device structure * @param vecs		the iovectors to write * @param count		number of vectors * @param to		offset to write to * @param retlen	pointer to variable to store the number of written bytes * @param eccbuf	filesystem supplied oob data buffer * @param oobsel	oob selection structure * * OneNAND write with iovec with ecc */static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,	unsigned long count, loff_t to, size_t *retlen,	u_char *eccbuf, struct nand_oobinfo *oobsel){	struct onenand_chip *this = mtd->priv;	unsigned char *pbuf;	size_t total_len, len;	int i, written = 0;	int ret = 0;	/* Preset written len for early exit */	*retlen = 0;	/* Calculate total length of data */	total_len = 0;	for (i = 0; i < count; i++)		total_len += vecs[i].iov_len;	DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);	/* Do not allow write past end of the device */	if (unlikely((to + total_len) > mtd->size)) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n");		return -EINVAL;	}	/* Reject writes, which are not page aligned */        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) {                DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_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);	/* TODO handling oob */	/* Loop until all keve's data has been written */	len = 0;	while (count) {		pbuf = this->page_buf;		/*		 * If the given tuple is >= pagesize then		 * write it out from the iov		 */		if ((vecs->iov_len - len) >= mtd->oobblock) {			pbuf = vecs->iov_base + len;			len += mtd->oobblock;			/* Check, if we have to switch to the next tuple */			if (len >= (int) vecs->iov_len) {				vecs++;				len = 0;				count--;			}		} else {			int cnt = 0, thislen;			while (cnt < mtd->oobblock) {				thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len);				memcpy(this->page_buf + cnt, vecs->iov_base + len, thislen);				cnt += thislen;				len += thislen;				/* Check, if we have to switch to the next tuple */				if (len >= (int) vecs->iov_len) {					vecs++;					len = 0;					count--;				}			}		}		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);		this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock);		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_writev_ecc: write failed %d\n", ret);			goto out;		}		/* Only check verify write turn on */		ret = onenand_verify_page(mtd, (u_char *) pbuf, to);		if (ret) {			DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret);			goto out;		}		written += mtd->oobblock;		to += mtd->oobblock;	}out:	/* Deselect and wakt up anyone waiting on the device */	onenand_release_device(mtd);	*retlen = written;	return 0;}/** * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc * @param mtd		MTD device structure * @param vecs		the iovectors to write * @param count		number of vectors * @param to		offset to write to * @param retlen	pointer to variable to store the number of written bytes * * OneNAND write with kvec. This just calls the ecc function */static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs,	unsigned long count, loff_t to, size_t *retlen){	return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);}/** * onenand_block_checkbad - [GENERIC] Check if a block is marked bad * @param mtd		MTD device structure * @param ofs		offset from device start * @param getchip	0, if the chip is already selected * @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_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, 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 */static 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;	DEBUG(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))) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (unlikely(instr->len & (block_size - 1))) {		DEBUG(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)) {		DEBUG(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 (onenand_block_checkbad(mtd, addr, 0, 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);		ret = this->wait(mtd, FL_ERASING);		/* Check, if it is write protected */		if (ret) {			if (ret == -EPERM)				DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n");			else				DEBUG(MTD_DEBUG_LEVEL0, "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 */static void onenand_sync(struct mtd_info *mtd){	DEBUG(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 */static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs){	/* Check for invalid offset */	if (ofs > mtd->size)		return -EINVAL;	return onenand_block_checkbad(mtd, ofs, 1, 0);}/** * 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};	size_t retlen;	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 mtd->write_oob(mtd, ofs , 2, &retlen, buf);}/** * 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 */static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs){	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;	}	return this->block_markbad(mtd, ofs);}/** * onenand_unlock - [MTD Interface] Unlock block(s) * @param mtd		MTD device structure * @param ofs		offset relative to mtd start * @param len		number of bytes to unlock * * Unlock one or more blocks */static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len){	struct onenand_chip *this = mtd->priv;	int start, end, block, value, status;	start = ofs >> this->erase_shift;	end = len >> this->erase_shift;	/* Continuous lock scheme */	if (this->options & ONENAND_CONT_LOCK) {		/* Set start block address */		this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);		/* Set end block address */		this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);		/* Write unlock command */		this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);		/* There's no return value */		this->wait(mtd, FL_UNLOCKING);		/* Sanity check */		while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)		    & ONENAND_CTRL_ONGO)			continue;		/* Check lock status */		status = this->read_word(this->base + ONENAND_REG_WP_STATUS);		if (!(status & ONENAND_WP_US))			printk(KERN_ERR "wp status = 0x%x\n", status);		return 0;	}	/* Block lock scheme */	for (block = start; block < end; block++) {		/* Set block address */		value = onenand_block_address(this, block);		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);		/* Select DataRAM for DDP */		value = onenand_bufferram_address(this, block);		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);		/* Set start block address */		this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);		/* Write unlock command */		this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);		/* There's no return value */		this->wait(mtd, FL_UNLOCKING);		/* Sanity check */		while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)		    & ONENAND_CTRL_ONGO)			continue;		/* Check lock status */		status = this->read_word(this->base + ONENAND_REG_WP_STATUS);		if (!(status & ONENAND_WP_US))			printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);	}	return 0;}#ifdef CONFIG_MTD_ONENAND_OTP/* Interal OTP operation */typedef int (*otp_op_t)(struct mtd_info *mtd, loff_t form, size_t len,		size_t *retlen, u_char *buf);/** * do_otp_read - [DEFAULT] Read OTP block area * @param mtd		MTD device structure * @param from		The offset to read * @param len		number of bytes to read * @param retlen	pointer to variable to store the number of readbytes * @param buf		the databuffer to put/get data * * Read OTP block area. */static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len,		size_t *retlen, u_char *buf){	struct onenand_chip *this = mtd->priv;	int ret;	/* Enter OTP access mode */	this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);	this->wait(mtd, FL_OTPING);	ret = mtd->read(mtd, from, len, retlen, buf);	/* Exit OTP access mode */	this->command(mtd, ONENAND_CMD_RESET, 0, 0);	this->wait(mtd, FL_RESETING);	return ret;}/** * do_otp_write - [DEFAULT] Write OTP block area * @param mtd		MTD device structure * @param from		The offset to write * @param len		number of bytes to write * @param retlen	pointer to variable to store the number of write bytes * @param buf		the databuffer to put/get data * * Write OTP block area. */static int do_otp_write(struct mtd_info *mtd, loff_t from, size_t len,		size_t *retlen, u_char *buf){	struct onenand_chip *this = mtd->priv;	unsigned char *pbuf = buf;	int ret;	/* Force buffer page aligned */	if (len < mtd->oobblock) {		memcpy(this->page_buf, buf, len);		memset(this->page_buf + len, 0xff, mtd->oobblock - len);		pbuf = this->page_buf;		len = mtd->oobblock;	}	/* Enter OTP access mode */	this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);	this->wait(mtd, FL_OTPING);	ret = mtd->write(mtd, from, len, retlen, pbuf);	/* Exit OTP access mode */	this->command(mtd, ONENAND_CMD_RESET, 0, 0);	this->wait(mtd, FL_RESETING);	return ret;}/** * do_otp_lock - [DEFAULT] Lock OTP block area * @param mtd		MTD device structure * @param from		The offset to lock * @param len		number of bytes to lock * @param retlen	pointer to variable to store the number of lock bytes * @param buf		the databuffer to put/get data * * Lock OTP block area. */static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,		size_t *retlen, u_char *buf){	struct onenand_chip *this = mtd->priv;	int ret;	/* Enter OTP access mode */	this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0);	this->wait(mtd, FL_OTPING);	ret = mtd->write_oob(mtd, from, len, retlen, buf);

⌨️ 快捷键说明

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