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

📄 cmd_nand.c

📁 F:worksip2440a board可启动u-boot-like.tar.gz F:worksip2440a board可启动u-boot-like.tar.gz
💻 C
📖 第 1 页 / 共 4 页
字号:
#ifdef CONFIG_MTD_NAND_ECC		/* Do we have this page in cache ? */		if (nand->cache_page == page)			goto readdata;		/* Send the read command */		NanD_Command(nand, NAND_CMD_READ0);		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);		/* Read in a page + oob data */		NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);		/* copy data into cache, for read out of cache and if ecc fails */		if (nand->data_cache)			memcpy (nand->data_cache, nand->data_buf, nand->oobblock + nand->oobsize);		/* Pick the ECC bytes out of the oob data */		for (j = 0; j < 6; j++)			ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])];		/* Calculate the ECC and verify it */		/* If block was not written with ECC, skip ECC */		if (oob_config.eccvalid_pos != -1 &&		    (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) {			nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]);			switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) {			case -1:				printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);				ecc_failed++;				break;			case 1:			case 2:	/* transfer ECC corrected data to cache */				if (nand->data_cache)					memcpy (nand->data_cache, nand->data_buf, 256);				break;			}		}		if (oob_config.eccvalid_pos != -1 &&		    nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) {			nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]);			switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) {			case -1:				printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);				ecc_failed++;				break;			case 1:			case 2:	/* transfer ECC corrected data to cache */				if (nand->data_cache)					memcpy (&nand->data_cache[256], &nand->data_buf[256], 256);				break;			}		}readdata:		/* Read the data from ECC data buffer into return buffer */		data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf;		data_poi += col;		if ((*retlen + (nand->oobblock - col)) >= len) {			memcpy (buf + *retlen, data_poi, len - *retlen);			*retlen = len;		} else {			memcpy (buf + *retlen, data_poi,  nand->oobblock - col);			*retlen += nand->oobblock - col;		}		/* Set cache page address, invalidate, if ecc_failed */		nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1;		ecc_status += ecc_failed;		ecc_failed = 0;#else		/* Send the read command */		NanD_Command(nand, NAND_CMD_READ0);		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);		/* Read the data directly into the return buffer */		if ((*retlen + (nand->oobblock - col)) >= len) {			NanD_ReadBuf(nand, buf + *retlen, len - *retlen);			*retlen = len;			/* We're done */			continue;		} else {			NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col);			*retlen += nand->oobblock - col;			}#endif		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		page++;	}	/* De-select the NAND device */	NAND_DISABLE_CE(nand);  /* set pin high */	/*	 * Return success, if no ECC failures, else -EIO	 * fs driver will take care of that, because	 * retlen == desired len and result == -EIO	 */	return ecc_status ? -1 : 0;}/* *	Nand_page_program function is used for write and writev ! */static int nand_write_page (struct nand_chip *nand,			    int page, int col, int last, u_char * ecc_code){	int i;#ifndef CONFIG_S3C2440	unsigned long nandptr = nand->IO_ADDR;#endif#ifdef CONFIG_MTD_NAND_ECC#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;#endif#endif	/* pad oob area */	for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++)		nand->data_buf[i] = 0xff;#ifdef CONFIG_MTD_NAND_ECC	/* Zero out the ECC array */	for (i = 0; i < 6; i++)		ecc_code[i] = 0x00;	/* Read back previous written data, if col > 0 */	if (col) {		NanD_Command(nand, NAND_CMD_READ0);		NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);		for (i = 0; i < col; i++)			nand->data_buf[i] = READ_NAND (nandptr);	}	/* Calculate and write the ECC if we have enough data */	if ((col < nand->eccsize) && (last >= nand->eccsize)) {		nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0]));		for (i = 0; i < 3; i++)			nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i];		if (oob_config.eccvalid_pos != -1)			nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] = 0xf0;	}	/* Calculate and write the second ECC if we have enough data */	if ((nand->oobblock == 512) && (last == nand->oobblock)) {		nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3]));		for (i = 3; i < 6; i++)			nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i];		if (oob_config.eccvalid_pos != -1)			nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] &= 0x0f;	}#endif	/* Prepad for partial page programming !!! */	for (i = 0; i < col; i++)		nand->data_buf[i] = 0xff;	/* Postpad for partial page programming !!! oob is already padded */	for (i = last; i < nand->oobblock; i++)		nand->data_buf[i] = 0xff;	/* Send command to begin auto page programming */	NanD_Command(nand, NAND_CMD_READ0);	NanD_Command(nand, NAND_CMD_SEQIN);	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);	/* Write out complete page of data */	for (i = 0; i < (nand->oobblock + nand->oobsize); i++)		WRITE_NAND(nand->data_buf[i], nand->IO_ADDR);	/* Send command to actually program the data */	NanD_Command(nand, NAND_CMD_PAGEPROG);	NanD_Command(nand, NAND_CMD_STATUS);#ifdef NAND_NO_RB	{ u_char ret_val;	  do{		ret_val = READ_NAND(nandptr);	/* wait till ready */	  } while((ret_val & 0x40) != 0x40);	}#endif	/* See if device thinks it succeeded */	if (READ_NAND(nand->IO_ADDR) & 0x01) {		printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, page);		return -1;	}#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 */	if (col < nand->eccsize)		NanD_Command(nand, NAND_CMD_READ0);	else		NanD_Command(nand, NAND_CMD_READ1);	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);	/* Loop through and verify the data */	for (i = col; i < last; i++) {		if (nand->data_buf[i] != readb (nand->IO_ADDR)) {			printf ("%s: Failed write verify, page 0x%08x ", __FUNCTION__, page);			return -1;		}	}#ifdef CONFIG_MTD_NAND_ECC	/*	 * We also want to check that the ECC bytes wrote	 * correctly for the same reasons stated above.	 */	NanD_Command(nand, NAND_CMD_READOOB);	NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col);	for (i = 0; i < nand->oobsize; i++)		nand->data_buf[i] = readb (nand->IO_ADDR);	for (i = 0; i < ecc_bytes; i++) {		if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {			printf ("%s: Failed ECC write "			       "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);			return -1;		}	}#endif#endif	return 0;}static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,			   size_t * retlen, const u_char * buf, u_char * ecc_code){	int i, page, col, cnt, ret = 0;	/* Do not allow write past end of device */	if ((to + len) > nand->totlen) {		printf ("%s: Attempt to write past end of page\n", __FUNCTION__);		return -1;	}	/* Shift to get page */	page = ((int) to) >> nand->page_shift;	/* Get the starting column */	col = to & (nand->oobblock - 1);	/* Initialize return length value */	*retlen = 0;	/* Select the NAND device */#ifdef CONFIG_OMAP1510	archflashwp(0,0);#endif    	NAND_ENABLE_CE(nand);  /* set pin low */	/* Check the WP bit */	NanD_Command(nand, NAND_CMD_STATUS);	if (!(READ_NAND(nand->IO_ADDR) & 0x80)) {		printf ("%s: Device is write protected!!!\n", __FUNCTION__);		ret = -1;		goto out;	}	/* Loop until all data is written */	while (*retlen < len) {		/* Invalidate cache, if we write to this page */		if (nand->cache_page == page)			nand->cache_page = -1;		/* Write data into buffer */		if ((col + len) >= nand->oobblock)			for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++)				nand->data_buf[i] = buf[(*retlen + cnt)];		else			for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++)				nand->data_buf[i] = buf[(*retlen + cnt)];		/* We use the same function for write and writev !) */		ret = nand_write_page (nand, page, col, i, ecc_code);		if (ret)			goto out;		/* Next data start at page boundary */		col = 0;		/* Update written bytes count */		*retlen += cnt;		/* Increment page address */		page++;	}	/* Return happy */	*retlen = len;out:	/* De-select the NAND device */	NAND_DISABLE_CE(nand);  /* set pin high */#ifdef CONFIG_OMAP1510    	archflashwp(0,1);#endif	return ret;}/* read from the 16 bytes of oob data that correspond to a 512 byte * page or 2 256-byte pages. *//* static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,			 size_t * retlen, u_char * buf) */int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,			 size_t * retlen, u_char * buf){	int len256 = 0;	struct Nand *mychip;	int ret = 0;	mychip = &nand->chips[ofs >> nand->chipshift];	/* update address for 2M x 8bit devices. OOB starts on the second */	/* page to maintain compatibility with nand_read_ecc. */	if (nand->page256) {		if (!(ofs & 0x8))			ofs += 0x100;		else			ofs -= 0x8;	}	NAND_ENABLE_CE(nand);  /* set pin low */	NanD_Command(nand, NAND_CMD_READOOB);	NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);	/* treat crossing 8-byte OOB data for 2M x 8bit devices */	/* Note: datasheet says it should automaticaly wrap to the */	/*       next OOB block, but it didn't work here. mf.      */	if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {		len256 = (ofs | 0x7) + 1 - ofs;		NanD_ReadBuf(nand, buf, len256);		NanD_Command(nand, NAND_CMD_READOOB);		NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));	}	NanD_ReadBuf(nand, &buf[len256], len - len256);	*retlen = len;	/* Reading the full OOB data drops us off of the end of the page,	 * causing the flash device to go into busy mode, so we need	 * to wait until ready 11.4.1 and Toshiba TC58256FT nands */	ret = NanD_WaitReady(nand, 1);	NAND_DISABLE_CE(nand);  /* set pin high */	return ret;}/* write to the 16 bytes of oob data that correspond to a 512 byte * page or 2 256-byte pages. *//* static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,		  size_t * retlen, const u_char * buf) */int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,		  size_t * retlen, const u_char * buf){	int len256 = 0;	int i;#ifndef CONFIG_S3C2440	unsigned long nandptr = nand->IO_ADDR;#endif#ifdef PSYCHO_DEBUG	printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",	       (long)ofs, len, buf[0], buf[1], buf[2], buf[3],	       buf[8], buf[9], buf[14],buf[15]);#endif	NAND_ENABLE_CE(nand);  /* set pin low to enable chip */	/* Reset the chip */	NanD_Command(nand, NAND_CMD_RESET);	/* issue the Read2 command to set the pointer to the Spare Data Area. */	NanD_Command(nand, NAND_CMD_READOOB);	NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);	/* update address for 2M x 8bit devices. OOB starts on the second */	/* page to maintain compatibility with nand_read_ecc. */	if (nand->page256) {		if (!(ofs & 0x8))			ofs += 0x100;		else			ofs -= 0x8;	}	/* issue the Serial Data In command to initial the Page Program process */	NanD_Command(nand, NAND_CMD_SEQIN);	NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);	/* treat crossing 8-byte OOB data for 2M x 8bit devices */	/* Note: datasheet says it should automaticaly wrap to the */	/*       next OOB block, but it didn't work here. mf.      */	if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {		len256 = (ofs | 0x7) + 1 - ofs;		for (i = 0; i < len256; i++)			WRITE_NAND(buf[i], nandptr);		NanD_Command(nand, NAND_CMD_PAGEPROG);		NanD_Command(nand, NAND_CMD_STATUS);#ifdef NAND_NO_RB   		{ u_char ret_val;    		  do{		  	ret_val = READ_NAND(nandptr); /* wait till ready */    		  }while((ret_val & 0x40) != 0x40);		}#endif		if (READ_NAND(nandptr) & 1) {			puts ("Error programming oob data\n");			/* There was an error */			NAND_DISABLE_CE(nand);  /* set pin high */			*retlen = 0;			return -1;		}		NanD_Command(nand, NAND_CMD_SEQIN);		NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));	}	for (i = len256; i < len; i++)		WRITE_NAND(buf[i], nandptr);	NanD_Command(nand, NAND_CMD_PAGEPROG);	NanD_Command(nand, NAND_CMD_STATUS);#ifdef NAND_NO_RB	{ u_char ret_val;	  do{		ret_val = READ_NAND(nandptr); /* wait till ready */	  } while((ret_val & 0x40) != 0x40);	}#endif	if (READ_NAND(nandptr) & 1) {		puts ("Error programming oob data\n");		/* There was an error */		NAND_DISABLE_CE(nand);  /* set pin high */		*retlen = 0;

⌨️ 快捷键说明

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