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

📄 yynf_nand.c

📁 nand flash驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* check, if we have a fs-supplied oob-buffer */	if (oob_buf) {		for (i = 0; i < mtd->oobsize; i++) {			if (oob_data[i] != readb (this->IO_ADDR_R)) {				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);				return -EIO;			}		}	} else {		if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) {			int ecc_bytes = 0;			switch (this->eccmode) {			case NAND_ECC_SOFT:			case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;			case NAND_ECC_HW3_512: ecc_bytes = 3; break;			case NAND_ECC_HW6_512: ecc_bytes = 6; break;			}			for (i = 0; i < mtd->oobsize; i++)				oob_data[i] = readb (this->IO_ADDR_R);			for (i = 0; i < ecc_bytes; i++) {				if (oob_data[oob_config[i]] != ecc_code[i]) {					DEBUG (MTD_DEBUG_LEVEL0,					       "%s: Failed ECC write "				       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);				return -EIO;				}			}		}	}#endif	return 0;}/**	Use NAND read ECC*/static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){	return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, 0));}			   /* * NAND read with ECC */static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,			  size_t * retlen, u_char * buf, u_char * oob_buf, int oobsel){	int j, col, page, end, ecc;	int erase_state = 0;	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;	struct nand_chip *this = mtd->priv;	u_char *data_poi, *oob_data = oob_buf;	u_char ecc_calc[6];	u_char ecc_code[6];	int	eccmode = oobsel ? this->eccmode : NAND_ECC_NONE;	int *oob_config = oobconfigs[oobsel];		DEBUG (MTD_DEBUG_LEVEL3, "nand_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, "nand_read_ecc: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, mtd ,FL_READING, &erase_state);	/* Select the NAND device */	nand_select ();	/* First we calculate the starting page */	page = from >> this->page_shift;	/* Get raw starting column */	col = from & (mtd->oobblock - 1);	end = mtd->oobblock;	ecc = mtd->eccsize;	/* Send the read command */	this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);		/* Loop until all data read */	while (read < len) {				/* If we have consequent page reads, apply delay or wait for ready/busy pin */		if (read) {			if (!this->dev_ready) 				udelay (this->chip_delay);			else				while (!this->dev_ready());			}		/* 		 * If the read is not page aligned, we have to read into data buffer		 * due to ecc, else we read into return buffer direct		 */		if (!col && (len - read) >= end)  			data_poi = &buf[read];		else 			data_poi = this->data_buf;		/* get oob area, if we have no oob buffer from fs-driver */		if (!oob_buf) {			oob_data = &this->data_buf[end];			oob = 0;		} 						j = 0;		switch (eccmode) {		case NAND_ECC_NONE:	/* No ECC, Read in a page */					while (j < end)				data_poi[j++] = readb (this->IO_ADDR_R);			break;					case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */			while (j < end)				data_poi[j++] = readb (this->IO_ADDR_R);			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);			if (mtd->oobblock == 512)				this->calculate_ecc (&data_poi[256], &ecc_calc[3]);			break;						case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */			this->enable_hwecc (NAND_ECC_READ);				while (j < ecc)				data_poi[j++] = readb (this->IO_ADDR_R);			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */						if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */				this->enable_hwecc (NAND_ECC_READ);					while (j < end)					data_poi[j++] = readb (this->IO_ADDR_R);				this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */			}								break;												case NAND_ECC_HW3_512:			case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page  */			this->enable_hwecc (NAND_ECC_READ);				while (j < end)				data_poi[j++] = readb (this->IO_ADDR_R);			this->calculate_ecc (&data_poi[0], &ecc_calc[0]);	/* read from hardware */			break;		default:			printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);			BUG();			}		/* read oobdata */		for (j = 0; j <  mtd->oobsize; j++) 			oob_data[oob + j] = readb (this->IO_ADDR_R);				/* Skip ECC, if not active */		if (eccmode == NAND_ECC_NONE)			goto readdata;					/* Pick the ECC bytes out of the oob data */		for (j = 0; j < 6; j++)			ecc_code[j] = oob_data[oob + oob_config[j]];		/* correct data, if neccecary */		ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);		/* check, if we have a fs supplied oob-buffer */		if (oob_buf) { 			oob += mtd->oobsize;			*((int *)&oob_data[oob]) = ecc_status;			oob += sizeof(int);		}		if (ecc_status == -1) {				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);			ecc_failed++;		}				if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {			ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);			if (oob_buf) {				*((int *)&oob_data[oob]) = ecc_status;				oob += sizeof(int);			}			if (ecc_status == -1) {				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);				ecc_failed++;			}		}readdata:		if (col || (len - read) < end) { 			for (j = col; j < end && read < len; j++)				buf[read++] = data_poi[j];		} else					read += mtd->oobblock;		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		page++;	}	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	/*	 * Return success, if no ECC failures, else -EIO	 * fs driver will take care of that, because	 * retlen == desired len and result == -EIO	 */	*retlen = read;	return ecc_failed ? -EIO : 0;}/* * NAND read out-of-band */static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){	int i, col, page;	int erase_state = 0;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Shift to get page */	page = ((int) from) >> this->page_shift;	/* Mask to get column */	col = from & 0x0f;	/* Initialize return length value */	*retlen = 0;	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, mtd , FL_READING, &erase_state);	/* Select the NAND device */	nand_select ();	/* Send the read command */	this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);	/* 	 * Read the data, if we read more than one page	 * oob data, let the device transfer the data !	 */	for (i = 0; i < len; i++) {		buf[i] = readb (this->IO_ADDR_R);		if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))			udelay (this->chip_delay);	}	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	/* Return happy */	*retlen = len;	return 0;}/**	Use NAND write ECC*/static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){	return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, 0));}			   /* * NAND write with ECC */static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,			   size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel){	int i, page, col, cnt, ret = 0, oob = 0, written = 0;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Do not allow write past end of device */	if ((to + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");		return -EINVAL;	}	/* Shift to get page */	page = ((int) to) >> this->page_shift;	/* Get the starting column */	col = to & (mtd->oobblock - 1);	/* Grab the lock and see if the device is available */	nand_get_chip (this, mtd, FL_WRITING, NULL);	/* Select the NAND device */	nand_select ();	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	if (!(readb (this->IO_ADDR_R) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");		ret = -EIO;		goto out;	}	/* Loop until all data is written */	while (written < len) {		/* 		 * Check, if we have a full page write, then we can		 * use the given buffer, else we have to copy		 */		if (!col && (len - written) >= mtd->oobblock) {   			this->data_poi = (u_char*) &buf[written];			cnt = mtd->oobblock;		} else {			cnt = 0;			for (i = col; i < len && i < mtd->oobblock; i++) {				this->data_buf[i] = buf[written + i];				cnt++;			}			this->data_poi = this->data_buf;				}		/* We use the same function for write and writev !) */		if (eccbuf) {			ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel);			oob += mtd->oobsize;		} else 			ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel);					if (ret)			goto out;		/* Update written bytes count */		written += cnt;		/* Next write is aligned */		col = 0;		/* Increment page address */		page++;	}out:	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	*retlen = written;	return ret;}/* * NAND write out-of-band */static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){	int i, column, page, status, ret = 0;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Shift to get page */	page = ((int) to) >> this->page_shift;	/* Mask to get column */	column = to & 0x1f;	/* Initialize return length value */	*retlen = 0;	/* Do not allow write past end of page */	if ((column + len) > mtd->oobsize) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, mtd, FL_WRITING, NULL);	/* Select the NAND device */	nand_select ();	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	if (!(readb (this->IO_ADDR_R) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");		ret = -EIO;		goto out;	}	/* Write out desired data */	this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);	/* prepad 0xff for partial programming */	for (i = 0; i < column; i++)		writeb (0xff, this->IO_ADDR_W);	/* write data */	for (i = 0; i < len; i++)		writeb (buf[i], this->IO_ADDR_W);		/* postpad 0xff for partial programming */	for (i = len + column; i < mtd->oobsize; i++)		writeb (0xff, this->IO_ADDR_W);	/* Send command to program the OOB data */	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);	status = this->waitfunc (mtd, this, FL_WRITING);	/* See if device thinks it succeeded */	if (status & 0x01) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);		ret = -EIO;		goto out;	}	/* Return happy */	*retlen = len;#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	/* Send command to read back the data */	this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);	/* Loop through and verify the data */	for (i = 0; i < len; i++) {		if (buf[i] != readb (this->IO_ADDR_R)) {			DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);			ret = -EIO;			goto out;		}	}#endifout:	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	return ret;}/* * NAND write with iovec */static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 		loff_t to, size_t * retlen){	return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0));	}static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, 		loff_t to, size_t * retlen, u_char *eccbuf, int oobsel){	int i, page, col, cnt, len, total_len, ret = 0, written = 0;	struct nand_chip *this = mtd->priv;	/* Calculate total length of data */	total_len = 0;	for (i = 0; i < count; i++)		total_len += (int) vecs[i].iov_len;	DEBUG (MTD_DEBUG_LEVEL3,	       "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);	/* Do not allow write past end of page */	if ((to + total_len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");		return -EINVAL;	}	/* Shift to get page */	page = ((int) to) >> this->page_shift;	/* Get the starting column */	col = to & (mtd->oobblock - 1);

⌨️ 快捷键说明

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