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

📄 nand.c

📁 ARM的著名的启动代码 vivi s3c2440部分已测试通过
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * vivi/drivers/mtd/nand/nand.c:  * * Based on linux/drivers/mtd/nand/nand.c * * $Id: smc_core.c,v 1.3 2002/08/10 07:47:08 nandy Exp $ * * * 棱淬: *   恐 this->oobblock捞扼绊 沁阑鳖? thsi->oobblcok_ofs捞扼绊 窍搁 *   粱歹 疙犬窍瘤 臼阑鳖? */#include "config.h"#include "mtd/mtd.h"#include "machine.h"#include "mtd/nand.h"#include "mtd/nand_ids.h"#include "mtd/nand_ecc.h"#include "time.h"#include "printk.h"#include "heap.h"#include "io.h"#include <types.h>#include <errno.h>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, struct nand_oobinfo *oobsel);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);static void nand_select_chip(struct mtd_info *mtd, int chip){	struct nand_chip *this = mtd->priv;	switch(chip) {	case -1:		this->hwcontrol(mtd, NAND_CTL_CLRNCE);			break;	case 0:		this->hwcontrol(mtd, NAND_CTL_SETNCE);		break;	default:		;	}}static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len){	int i;	struct nand_chip *this = mtd->priv;	for (i=0; i<len; i++)		this->write_byte(mtd,buf[i]);}static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len){	int i;	struct nand_chip *this = mtd->priv;	for (i=0; i<len; i++)		buf[i] = this->read_byte(mtd);}static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len){	int i;	struct nand_chip *this = mtd->priv;	for (i=0; i<len; i++)		if (buf[i] != this->read_byte(mtd))			return i;	return 0;}/* Appropriate chip should already be selected */static int nand_block_bad(struct mtd_info *mtd, unsigned long page){	struct nand_chip *this = mtd->priv;		this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);	if (this->read_byte(mtd) != 0xff)		return 1;	return 0;}/* * Send command to NAND device */static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr){	register struct nand_chip *this = mtd->priv;	/* Begin command latch cycle */	this->hwcontrol(mtd, NAND_CTL_SETCLE);	this->hwcontrol(mtd,NAND_CTL_DAT_OUT);	/*	 * Write out the command to the device.	 */	if (command == NAND_CMD_SEQIN) {		int readcmd;		if (column >= mtd->oobblock) {			/* OOB area */			column -= mtd->oobblock;			readcmd = NAND_CMD_READOOB;		} else if (column < 256) {			/* First 256 bytes --> READ0 */			readcmd = NAND_CMD_READ0;		} else {			column -= 256;			readcmd = NAND_CMD_READ1;		}//		this->write_byte(mtd, readcmd);		this->write_cmd(mtd, readcmd);	}//	this->write_byte(mtd, command);	this->write_cmd(mtd, command);	/* Set ALE and clear CLE to start address cycle */	this->hwcontrol(mtd, NAND_CTL_CLRCLE);	if (column != -1 || page_addr != -1) {		this->hwcontrol(mtd, NAND_CTL_SETALE);		/* Serially input address */		if (column != -1)//			this->write_byte(mtd, column);			this->write_addr(mtd, column);		if (page_addr != -1) {//			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));			this->write_addr(mtd, (unsigned char) (page_addr & 0xff));//			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));			this->write_addr(mtd, (unsigned char) ((page_addr >> 8) & 0xff));			/* One more address cycle for higher density devices */			if (mtd->size & 0x0c000000) //				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));				this->write_addr(mtd, (unsigned char) ((page_addr >> 16) & 0xff));		}		/* Latch in address */		this->hwcontrol(mtd, NAND_CTL_CLRALE);		this->hwcontrol(mtd,NAND_CTL_DAT_IN);	}		/* 	 * program and erase have their own busy handlers 	 * status and sequential in needs no delay	*/	switch (command) {				case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:		return;	case NAND_CMD_RESET:		if (this->dev_ready)				break;		udelay(this->chip_delay);		this->hwcontrol(mtd, NAND_CTL_SETCLE);//		this->write_byte(mtd, NAND_CMD_STATUS);		this->write_cmd(mtd, NAND_CMD_STATUS);		this->hwcontrol(mtd, NAND_CTL_CLRCLE);		while ( !(this->read_byte(mtd) & 0x40));		return;	/* This applies to read commands */		default:		/* 		 * If we don't have access to the busy pin, we apply the given		 * command delay		*/		while (!this->dev_ready(mtd)){			udelay (this->chip_delay);			return;		}		}		/* wait until command is processed */	while (!this->dev_ready(mtd))		udelay (this->chip_delay);}static int nand_wait(struct mtd_info *mtd,struct nand_chip *this,int state){	int i;	int status;	for(i=0;i<32;i++){		udelay(125);		this->cmdfunc(mtd,NAND_CMD_STATUS,-1,-1);			if(this->dev_ready){			if(this->dev_ready(mtd))				break;		}		if(this->read_byte(mtd)&0x40)			break;	}	status=(int)this->read_byte(mtd);		return status;	}/* *	Nand_page_program function is used for write and writev ! *	This function will always program a full page of data *	If you call it with a non page aligned buffer, you're lost :) */static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this,			    int page, int col, int last, u_char *oob_buf, struct nand_oobinfo *oobsel){	int 	i,status;	u_char	ecc_code[6], *oob_data;	int	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;	int  	*oob_config = oobsel->eccpos;		/* pad oob area, if we have no oob buffer from fs-driver */	if (!oob_buf) {		oob_data = &this->data_buf[mtd->oobblock];		for (i = 0; i < mtd->oobsize; i++)			oob_data[i] = 0xff;	} else 		oob_data = oob_buf;	/* software ecc 3 Bytes ECC / 256 Byte Data ? */	if (eccmode == NAND_ECC_SOFT) {		/* Read back previous written data, if col > 0 */		if (col) {			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);			this->read_buf(mtd,&this->data_poi[0],col);		}		if ((col < this->eccsize) && (last >= this->eccsize)) {			this->calculate_ecc (mtd,&this->data_poi[0], &(ecc_code[0]));			for (i = 0; i < 3; i++)				oob_data[oob_config[i]] = ecc_code[i];		}		/* Calculate and write the second ECC if we have enough data */		if ((mtd->oobblock == 512) && (last == 512)) {			this->calculate_ecc (mtd,&this->data_poi[256], &(ecc_code[3]));			for (i = 3; i < 6; i++)				oob_data[oob_config[i]] = ecc_code[i];		} 	} else {		/* For hardware ECC skip ECC, if we have no full page write */		if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock))			eccmode = NAND_ECC_NONE;	}				/* Prepad for partial page programming !!! */	for (i = 0; i < col; i++)		this->data_poi[i] = 0xff;	/* Postpad for partial page programming !!! oob is already padded */	for (i = last; i < mtd->oobblock; i++)		this->data_poi[i] = 0xff;		/* Send command to begin auto page programming */	this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);	/* Write out complete page of data, take care of eccmode */	switch (eccmode) {	/* No ecc and software ecc 3/256, write all */	case NAND_ECC_NONE://		printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");//		this->write_buf(mtd, this->data_poi, mtd->oobblock);//		break;	case NAND_ECC_SOFT://		this->calculate_ecc(mtd, &this->data_poi[0], &(ecc_code[0]));//		for (i = 0; i < 3; i++)//			oob_data[oob_config[i]] = ecc_code[i];		/* Calculate and write the second ECC for 512 Byte page size *///		if (mtd->oobblock == 512) {//			this->calculate_ecc(mtd, &this->data_poi[256], &(ecc_code[3]));//			for (i = 3; i < 6; i++)//				oob_data[oob_config[i]] = ecc_code[i];//		} 		this->write_buf(mtd, this->data_poi, mtd->oobblock);		break;			/* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */		case NAND_ECC_HW3_256:				this->enable_hwecc(mtd, NAND_ECC_WRITE);	/* enable hardware ecc logic for write */		this->write_buf(mtd, this->data_poi, mtd->eccsize);				this->calculate_ecc(mtd, NULL, &(ecc_code[0]));		for (i = 0; i < 3; i++)			oob_data[oob_config[i]] = ecc_code[i];					if (mtd->oobblock == 512) {			this->enable_hwecc(mtd, NAND_ECC_WRITE);	/* enable hardware ecc logic for write*/			this->write_buf(mtd, &this->data_poi[mtd->eccsize], mtd->oobblock - mtd->eccsize);			this->calculate_ecc(mtd, NULL, &(ecc_code[3]));			for (i = 3; i < 6; i++)				oob_data[oob_config[i]] = ecc_code[i];		}		break;					/* Hardware ecc 3 byte / 512 byte data, write full page */		case NAND_ECC_HW3_512:			this->enable_hwecc(mtd, NAND_ECC_WRITE);	/* enable hardware ecc logic */		this->write_buf(mtd, this->data_poi, mtd->oobblock);		this->calculate_ecc(mtd, NULL, &(ecc_code[0]));		for (i = 0; i < 3; i++)			oob_data[oob_config[i]] = ecc_code[i];		break;	/* Hardware ecc 6 byte / 512 byte data, write full page */		case NAND_ECC_HW6_512:			this->enable_hwecc(mtd, NAND_ECC_WRITE);	/* enable hardware ecc logic */		this->write_buf(mtd, this->data_poi, mtd->oobblock);		this->calculate_ecc(mtd, NULL, &(ecc_code[0]));		for (i = 0; i < 6; i++)			oob_data[oob_config[i]] = ecc_code[i];		break;		default:		printk ("Invalid NAND_ECC_MODE %d\n", this->eccmode);		return -1;	}		/* Write out OOB data */	this->write_buf(mtd, oob_data, mtd->oobsize);	/* Send command to actually program the data */	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);	/* Send command to actually program the data */	status=this->waitfunc (mtd, this,FL_WRITING);		if(status & 0x01){//		DEBUG(MTD_DEBUG_LEVEL0,"%S:" "Failed write,page 0x%08x,"__FUNCTION__,page);		printk("%S:" "Failed write,page 0x%08x,"__FUNCTION__,page);		return -EIO;	}	#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	/*	 * The NAND device assumes that it is always writing to	 * a cleanly erased page. Hence, it performs its internal	 * write verification only on bits that transitioned from	 * 1 to 0. The device does NOT verify the whole page on a	 * byte by byte basis. It is possible that the page was	 * not completely erased or the page is becoming unusable	 * due to wear. The read with ECC would catch the error	 * later when the ECC page check fails, but we would rather	 * catch it early in the page write stage. Better to write	 * no data than invalid data.	 */	/* Send command to read back the page */	this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);	/* Loop through and verify the data */	if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) {//		DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);		printk("%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);		return -EIO;	}	/* check, if we have a fs-supplied oob-buffer */	if (oob_buf) {		if (this->verify_buf(mtd, oob_data, mtd->oobsize)) {//			DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);			printk("%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);			return -EIO;		}	} else {		if (eccmode != NAND_ECC_NONE) {			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;			}			this->read_buf(mtd, oob_data, mtd->oobsize);			for (i = 0; i < ecc_bytes; i++) {				if (oob_data[oob_config[i]] != ecc_code[i]) {//					DEBUG (MTD_DEBUG_LEVEL0,					printk(									       "%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, NULL);}			   /* * 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, struct nand_oobinfo *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;	int	*oob_config;	// use chip default if zero	if (oobsel == NULL)		oobsel = &mtd->oobinfo;			eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;	oob_config = oobsel->eccpos;	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");		printk("nand_read_ecc: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Select the NAND device */	this->select_chip(mtd, 0);	/* 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->chip_delay) 				udelay (this->chip_delay);			else				while (!this->dev_ready(mtd));			}		/* 		 * 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 */			printk ( "Reading data from NAND FLASH without ECC is not recommended\n");						this->read_buf(mtd, data_poi, end);			break;							case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */			this->read_buf(mtd, data_poi, end);			this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]);			if (mtd->oobblock == 512)				this->calculate_ecc(mtd, &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(mtd, NAND_ECC_READ);				this->read_buf(mtd, data_poi, ecc);			this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]);	/* read from hardware */						if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */				this->enable_hwecc(mtd, NAND_ECC_READ);					this->read_buf(mtd, &data_poi[ecc], end-ecc);				this->calculate_ecc(mtd, &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(mtd, NAND_ECC_READ);				this->read_buf(mtd, data_poi, end);			this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]);	/* read from hardware */			break;		default:			printk ( "Invalid NAND_ECC_MODE %d\n", this->eccmode);			return -EIO;		}		/* read oobdata */		for (j = 0; j <  mtd->oobsize; j++) 			oob_data[oob + j] = this->read_byte(mtd);				/* 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(mtd, &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);			printk("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(mtd, &data_poi[256], &ecc_code[3], &ecc_calc[3]);			if (oob_buf) {				*((int *)&oob_data[oob]) = ecc_status;				oob += sizeof(int);			}

⌨️ 快捷键说明

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