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

📄 nandflash.c

📁 基于S3C2410和SM501的彩屏控制器程序
💻 C
📖 第 1 页 / 共 3 页
字号:
			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;
	unsigned long nandptr = nand->IO_ADDR;
#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 fix READ_NAND by kavin*/

	for (i = col; i < last; i++) {
		if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) {
			return -1;
		}
	}

#ifdef CONFIG_MTD_NAND_ECC
	/*
	 * We also want to check that the ECC bytes wrote
	 * correctly for the same reasons stated above.
	 * fix READ_NAND by kavin
	 */
	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] = READ_NAND(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 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 len256 = 0;
	int i;
	unsigned long nandptr = nand->IO_ADDR;

#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;
		return -1;
	}

	NAND_DISABLE_CE(nand);  /* set pin high */
	*retlen = len;
	return 0;

}

static int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
{
	/* This is defined as a structure so it will work on any system
	 * using native endian jffs2 (the default).
	 */
	static struct jffs2_unknown_node clean_marker = {
		JFFS2_MAGIC_BITMASK,
		JFFS2_NODETYPE_CLEANMARKER,
		8		/* 8 bytes in this node */
	};
	unsigned long nandptr;
	struct Nand *mychip;
	int ret = 0;

	if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) {
		printf ("Offset and size must be sector aligned, erasesize = %d\n",
			(int) nand->erasesize);
		return -1;
	}

	nandptr = nand->IO_ADDR;

	/* 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 ("nand_write_ecc: Device is write protected!!!\n");
		ret = -1;
		goto out;
	}

	/* 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;
	}

	/* FIXME: Do nand in the background. Use timers or schedule_task() */
	while(len) {
		/*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/
		mychip = &nand->chips[ofs >> nand->chipshift];

		/* always check for bad block first, genuine bad blocks
		 * should _never_  be erased.
		 */
		if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) {
			/* Select the NAND device */

⌨️ 快捷键说明

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