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

📄 onenand_base.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
		unsigned short word;		/* Align with word(16-bit) size */		count--;		/* Read word and save byte */		word = this->read_word(bufferram + offset + count);		buffer[count] = (word & 0xff);	}	memcpy(buffer, bufferram + offset, count);	return 0;}/** * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode * @param mtd		MTD data structure * @param area		BufferRAM area * @param buffer	the databuffer to put/get data * @param offset	offset to read from or write to * @param count		number of bytes to read/write * * Read the BufferRAM area with Sync. Burst Mode */static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,		unsigned char *buffer, int offset, size_t count){	struct onenand_chip *this = mtd->priv;	void __iomem *bufferram;	bufferram = this->base + area;	bufferram += onenand_bufferram_offset(mtd, area);	this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);	if (ONENAND_CHECK_BYTE_ACCESS(count)) {		unsigned short word;		/* Align with word(16-bit) size */		count--;		/* Read word and save byte */		word = this->read_word(bufferram + offset + count);		buffer[count] = (word & 0xff);	}	memcpy(buffer, bufferram + offset, count);	this->mmcontrol(mtd, 0);	return 0;}/** * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area * @param mtd		MTD data structure * @param area		BufferRAM area * @param buffer	the databuffer to put/get data * @param offset	offset to read from or write to * @param count		number of bytes to read/write * * Write the BufferRAM area */static int onenand_write_bufferram(struct mtd_info *mtd, int area,		const unsigned char *buffer, int offset, size_t count){	struct onenand_chip *this = mtd->priv;	void __iomem *bufferram;	bufferram = this->base + area;	bufferram += onenand_bufferram_offset(mtd, area);	if (ONENAND_CHECK_BYTE_ACCESS(count)) {		unsigned short word;		int byte_offset;		/* Align with word(16-bit) size */		count--;		/* Calculate byte access offset */		byte_offset = offset + count;		/* Read word and save byte */		word = this->read_word(bufferram + byte_offset);		word = (word & ~0xff) | buffer[count];		this->write_word(word, bufferram + byte_offset);	}	memcpy(bufferram + offset, buffer, count);	return 0;}/** * onenand_get_2x_blockpage - [GENERIC] Get blockpage at 2x program mode * @param mtd		MTD data structure * @param addr		address to check * @return		blockpage address * * Get blockpage address at 2x program mode */static int onenand_get_2x_blockpage(struct mtd_info *mtd, loff_t addr){	struct onenand_chip *this = mtd->priv;	int blockpage, block, page;	/* Calculate the even block number */	block = (int) (addr >> this->erase_shift) & ~1;	/* Is it the odd plane? */	if (addr & this->writesize)		block++;	page = (int) (addr >> (this->page_shift + 1)) & this->page_mask;	blockpage = (block << 7) | page;	return blockpage;}/** * onenand_check_bufferram - [GENERIC] Check BufferRAM information * @param mtd		MTD data structure * @param addr		address to check * @return		1 if there are valid data, otherwise 0 * * Check bufferram if there is data we required */static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr){	struct onenand_chip *this = mtd->priv;	int blockpage, found = 0;	unsigned int i;	if (ONENAND_IS_2PLANE(this))		blockpage = onenand_get_2x_blockpage(mtd, addr);	else		blockpage = (int) (addr >> this->page_shift);	/* Is there valid data? */	i = ONENAND_CURRENT_BUFFERRAM(this);	if (this->bufferram[i].blockpage == blockpage)		found = 1;	else {		/* Check another BufferRAM */		i = ONENAND_NEXT_BUFFERRAM(this);		if (this->bufferram[i].blockpage == blockpage) {			ONENAND_SET_NEXT_BUFFERRAM(this);			found = 1;		}	}	if (found && ONENAND_IS_DDP(this)) {		/* Select DataRAM for DDP */		int block = (int) (addr >> this->erase_shift);		int value = onenand_bufferram_address(this, block);		this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);	}	return found;}/** * 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 void onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,		int valid){	struct onenand_chip *this = mtd->priv;	int blockpage;	unsigned int i;	if (ONENAND_IS_2PLANE(this))		blockpage = onenand_get_2x_blockpage(mtd, addr);	else		blockpage = (int) (addr >> this->page_shift);	/* Invalidate another BufferRAM */	i = ONENAND_NEXT_BUFFERRAM(this);	if (this->bufferram[i].blockpage == blockpage)		this->bufferram[i].blockpage = -1;	/* Update BufferRAM */	i = ONENAND_CURRENT_BUFFERRAM(this);	if (valid)		this->bufferram[i].blockpage = blockpage;	else		this->bufferram[i].blockpage = -1;}/** * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information * @param mtd		MTD data structure * @param addr		start address to invalidate * @param len		length to invalidate * * Invalidate BufferRAM information */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 int onenand_get_device(struct mtd_info *mtd, int new_state){	struct onenand_chip *this = mtd->priv;	DECLARE_WAITQUEUE(wait, current);	/*	 * Grab the lock and see if the device is available	 */	while (1) {		spin_lock(&this->chip_lock);		if (this->state == FL_READY) {			this->state = new_state;			spin_unlock(&this->chip_lock);			break;		}		if (new_state == FL_PM_SUSPENDED) {			spin_unlock(&this->chip_lock);			return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;		}		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&this->wq, &wait);		spin_unlock(&this->chip_lock);		schedule();		remove_wait_queue(&this->wq, &wait);	}	return 0;}/** * 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){	struct onenand_chip *this = mtd->priv;	/* Release the chip */	spin_lock(&this->chip_lock);	this->state = FL_READY;	wake_up(&this->wq);	spin_unlock(&this->chip_lock);}/** * 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_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;	DEBUG(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->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->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, 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) 			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; 		cond_resched(); 		/* 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;	DEBUG(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) {		cond_resched();		thislen = 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);		if (ret && ret != -EBADMSG) {			printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);

⌨️ 快捷键说明

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