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

📄 nand.c

📁 ARM的著名的启动代码 vivi s3c2440部分已测试通过
💻 C
📖 第 1 页 / 共 2 页
字号:
			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 */	this->select_chip(mtd, -1);	/* Wake up anyone waiting on the device */	this->state = FL_READY;	/*	 * 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;	}	/* Select the NAND device */	this->select_chip(mtd, 0);	/* 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 !	 */	i = 0;	while (i < len) {		int thislen = (mtd->oobsize - col) & (mtd->oobsize - 1);		if (!thislen)			thislen = mtd->oobsize;		if(len<thislen)			thislen=(int)len;		this->read_buf(mtd, &buf[i], thislen);		i += thislen;		col += thislen;		/* Delay between pages */		udelay (this->chip_delay);	}	/* De-select the NAND device */	this->select_chip(mtd, -1);	/* Return happy */	*retlen = len;	return 0;}#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 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, NULL));}			   /* * 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, struct nand_oobinfo *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_ecc: Attempt to write past end of page\n");		return -EINVAL;	}	/* reject writes, which are not page aligned */	//	if (NOTALIGNED (to) || NOTALIGNED(len)) {//		printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");//		return -EINVAL;//	}	// if oobsel is NULL, use chip defaults	if (oobsel == NULL) 		oobsel = &mtd->oobinfo;			/* Shift to get page */	page = ((int) to) >> this->page_shift;	/* Get the starting column */	col = to & (mtd->oobblock - 1);	/* Select the NAND device */	this->select_chip(mtd, 0);	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	while(!this->dev_ready(mtd)) 		udelay (this->chip_delay);		if (!(this->read_byte(mtd) & 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;		col = 0;		/* Increment page address */		page++;	}out:	/* De-select the NAND device */	this->select_chip(mtd, -1);	*retlen = written;	return ret;}static u_char ffchars[] = {	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};/* * 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 column, page, status, ret = 0;	struct nand_chip *this = mtd->priv;#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	int i;#endif	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;	}	/* Select the NAND device */	this->select_chip(mtd, 0);	/* Reset the chip. Some chips (like the Toshiba TC5832DC found	   in one of my DiskOnChip 2000 test units) will clear the whole	   data page too if we don't do this. I have no clue why, but	   I seem to have 'fixed' it in the doc2000 driver in	   August 1999.  dwmw2. */	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	while(!this->dev_ready(mtd)) 		udelay (this->chip_delay);		if (!(this->read_byte(mtd) & 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);	this->hwcontrol(mtd,NAND_CTL_DAT_OUT);	/* prepad 0xff for partial programming */	this->write_buf(mtd, ffchars, column);	/* write data */	this->write_buf(mtd, buf, len);	/* postpad 0xff for partial programming */	this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));	this->hwcontrol(mtd,NAND_CTL_DAT_IN);	/* Send command to program the OOB data */	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);	while(!this->dev_ready(mtd)) 		udelay (this->chip_delay);	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] != this->read_byte(mtd)) {			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 */	this->select_chip(mtd, -1);	return ret;}/* * NAND erase a block */static int nand_erase (struct mtd_info *mtd, struct erase_info *instr){	int i,page, len, status, pages_per_block;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3,	       "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);	/* Start address must align on block boundary */	if (instr->addr & (mtd->erasesize - 1)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (instr->len & (mtd->erasesize - 1)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");		return -EINVAL;	}	/* Do not allow erase past end of device */	if ((instr->len + instr->addr) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");		return -EINVAL;	}	/* Shift to get first page */	page = (int) (instr->addr >> this->page_shift);	/* Calculate pages in each block */	pages_per_block = mtd->erasesize / mtd->oobblock;	/* Select the NAND device */	this->select_chip(mtd, 0);	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	while(!this->dev_ready(mtd)) 		udelay (this->chip_delay);		if (!(this->read_byte(mtd) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");		this->select_chip(mtd, -1);		return -EIO;	}	/* Loop through the pages */	len = instr->len;	instr->state = MTD_ERASING;	while (len) {		/* Send commands to erase a page */		this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);		this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);		while(!this->dev_ready(mtd))			udelay(this->chip_delay);	//		spin_unlock_bh (&this->chip_lock);		status = this->waitfunc (mtd, this, FL_ERASING);				for(i=0;i<32;i++){			udelay(125);						this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);							while(!this->dev_ready(mtd))				udelay(this->chip_delay);							status=this->read_byte(mtd);			if(status & 0x40)				break;		}		/* See if block erase succeeded */		if (status & 0x01) {			DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);//			instr->state = MTD_ERASE_FAILED;			return -EIO;		}					/* Increment page address and decrement length */		len -= mtd->erasesize;		page += pages_per_block;	}	/* De-select the NAND device */	this->select_chip(mtd, -1);	/* Return more or less happy */	return 0;}/* * Scan for the NAND device */int nand_scan (struct mtd_info *mtd, int maxchips){	int i, nand_maf_id, nand_dev_id;	struct nand_chip *this = mtd->priv;	/* check for proper chip_delay setup, set 20us if not */	if (!this->chip_delay)		this->chip_delay = 20;	/* check, if a user supplied command function given */	if (this->cmdfunc == NULL)		this->cmdfunc = nand_command;	if (this->waitfunc == NULL)		this->waitfunc = nand_wait;	if (!this->block_bad)		this->block_bad = nand_block_bad;	if (!this->select_chip)		this->select_chip = nand_select_chip;//	if (!this->write_byte)//		this->write_byte = nand_write_byte;//	if (!this->read_byte)//		this->read_byte = nand_read_byte;	if (!this->write_buf)		this->write_buf = nand_write_buf;	if (!this->read_buf)		this->read_buf = nand_read_buf;	if (!this->verify_buf)		this->verify_buf = nand_verify_buf;	/* Select the device */	this->select_chip(mtd, 0);//	this->hwcontrol(mtd,NAND_CTL_CLRRnB); 	while(!this->dev_ready(mtd)) 		udelay (this->chip_delay);		/* Send the command for reading device ID */	this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);	for (i = 0; i < 100;i++);		/* Read manufacturer and device IDs */	nand_maf_id = this->read_byte(mtd);//	nand_maf_id = (u_char)NFDATA;	nand_dev_id = this->read_byte(mtd);//	nand_dev_id = (u_char)NFDATA;	/* Print and store flash device information */	for (i = 0; nand_flash_ids[i].name != NULL; i++) {		if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {			mtd->name = nand_flash_ids[i].name;			mtd->erasesize = nand_flash_ids[i].erasesize;			mtd->eccsize = 256;			this->chipshift = nand_flash_ids[i].chipshift;			if (nand_flash_ids[i].page256) {				mtd->oobblock = 256;				mtd->oobsize = 8;				this->page_shift = 8;			} else {				mtd->oobblock = 512;				mtd->oobsize = 16;				this->page_shift = 9;			}			/* Try to identify manufacturer */			for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {				if (nand_manuf_ids[i].id == nand_maf_id)					break;			}				printk("NAND device: Manufacturer ID:"				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 				nand_manuf_ids[i].name , mtd->name);			break;		}	}	if (!mtd->name) {		printk ("No NAND device found!!!\n");		return 1;	}	for (i=1; i < maxchips; i++) {		this->select_chip(mtd, i);		/* Send the command for reading device ID */		this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);		/* Read manufacturer and device IDs */		if (nand_maf_id != this->read_byte(mtd) ||nand_dev_id != this->read_byte(mtd))//		if (nand_maf_id !=(u_char)NFDATA||nand_dev_id !=(u_char)NFDATA)			break;	}		if (i > 1)		printk("%d NAND chips detected\n", i);	mtd->size = (1 << this->chipshift) /* * i when we fix the rest of the code */;	/* 	 * check ECC mode, default to software	 * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize	 * fallback to software ECC 	*/	this->eccsize = 256;	/* set default eccsize */		switch (this->eccmode) {	case NAND_ECC_HW3_512: 	case NAND_ECC_HW6_512: 		if (mtd->oobblock == 256) {			printk ("512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");			this->eccmode = NAND_ECC_SOFT;			this->calculate_ecc = nand_calculate_ecc;			this->correct_data = nand_correct_data;			break;				} else 			this->eccsize = 512; /* set eccsize to 512 and fall through for function check */	case NAND_ECC_HW3_256:		if (this->calculate_ecc && this->correct_data && this->enable_hwecc)			break;		printk ("No ECC functions supplied, Hardware ECC not possible\n");		return -1;		case NAND_ECC_NONE: 		printk ("NAND_ECC_NONE selected by board driver. This is not recommended !!\n");		this->eccmode = NAND_ECC_NONE;		break;	case NAND_ECC_SOFT:			this->calculate_ecc = nand_calculate_ecc;		this->correct_data = nand_correct_data;		break;	default:		printk ("Invalid NAND_ECC_MODE %d\n", this->eccmode);		return -1;		}			/* Initialize state, waitqueue and spinlock */	this->state = FL_READY;	/* De-select the device */	this->select_chip(mtd, -1);	/* Fill in remaining MTD driver data */	mtd->type = MTD_NANDFLASH;	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;	mtd->ecctype = MTD_ECC_SW;	mtd->erase = nand_erase;	mtd->point = NULL;	mtd->unpoint = NULL;	mtd->read = nand_read;	mtd->write = nand_write;	mtd->read_ecc = nand_read_ecc;	mtd->write_ecc = nand_write_ecc;	mtd->read_oob = nand_read_oob;	mtd->write_oob = nand_write_oob;//	mtd->readv = NULL;//	mtd->writev = nand_writev;//	mtd->writev_ecc = nand_writev_ecc;//	mtd->sync = nand_sync;	mtd->lock = NULL;	mtd->unlock = NULL;	/* Return happy */	return 0;}

⌨️ 快捷键说明

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