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

📄 nand.c

📁 Boot code for ADM5120 with serial console for Edimax router.
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (ecc_status == -1) {//          DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);			ecc_failed++;		}		if (eccmode != NAND_ECC_HW3_512) {			ecc_status = nand_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 += NAND_PAGE_SIZE;		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		page++;	}	/* De-select the NAND device */	nand_select_chip(-1);	/* 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(loff_t from, size_t len, size_t * retlen, u_char * buf){	int i, j, k, col, page;	int erase_state = 0;	/* Shift to get page */	page = ((int) from) >> NAND_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) > NAND_FLASH_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( FL_READING, &erase_state);	/* Select the NAND device */	nand_select_chip(0);	/* Send the read command */	nand_command(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 = (NAND_PAGE_OOB_SIZE - col) & (NAND_PAGE_OOB_SIZE - 1);		if (!thislen)			thislen = NAND_PAGE_OOB_SIZE;		//		thislen = min_t(int, thislen, len);		nand_read_buf(&buf[i], thislen);		i += thislen;		col += thislen;		/* Delay between pages *///      udelay (this->chip_delay);		for (k = 0; k < 10; k++)			for (j = 0; j < 1000; j++);	}	/* De-select the NAND device */	nand_select_chip(-1);	/* Return happy */	*retlen = len;	return 0;}#define NOTALIGNED(x) ((x & (NAND_PAGE_SIZE-1)) != 0)///** NAND write with ECC */static int nand_write_ecc(loff_t to, size_t len, size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel){	unsigned long page1st, blkAddr = -1;	int page, ret = 0, oob = 0, written = 0;//  struct nand_chip *this = mtd->priv;	u_char *data_poi;	/* Do not allow write past end of device */	if ((to + len) > NAND_FLASH_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)) {//      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 = &oobinfo_buf;	/* Shift to get page */	page = ((int) to) >> ADD2SHIFT;	/* Grab the lock and see if the device is available *///  nand_get_chip ( FL_WRITING, NULL);	/* Select the NAND device */	nand_select_chip(0);	nand_command(NAND_CMD_RESET, -1, -1);	// set the WP	*(base + NAND_SET_WP_REG) = 1;	/* Check the WP bit */	nand_command(NAND_CMD_STATUS, -1, -1);	if (!(nand_read_byte() & 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) {		// before doing write, checking if this block is bad block or not ?		// 32-pages per block, determine the 1st page		page1st = ((unsigned long) page / NAND_BLK_PER_PAGE) * NAND_BLK_PER_PAGE;		/* get the first page of this current block */		if (blkAddr != page1st) {	// checking this block, if not checked yet			blkAddr = page1st;			if (nand_block_bad(blkAddr) != 0) {	// this block is bad block, double confirm this is bad one, then try next block				buart_print("\n\rBad flash block detected!");				// move forward to the 1st page of next block				page = ((page + NAND_BLK_PER_PAGE) / NAND_BLK_PER_PAGE) * NAND_BLK_PER_PAGE;				continue;			}		}		//		data_poi = (u_char *) & buf[written];	// ???? this->data_poi		/* We use the same function for write and writev */		if (eccbuf) {			ret = nand_write_page(data_poi, page, &eccbuf[oob], oobsel);			oob += NAND_PAGE_OOB_SIZE;		} else			ret = nand_write_page(data_poi, page, NULL, oobsel);		//		if (ret)			goto out;		/* Update written bytes count */		written += NAND_PAGE_SIZE;		/* Increment page address */		page++;	}  out:	// clear the WP	*(base + NAND_CLR_WP_REG) = 1;	/* De-select the NAND device */	nand_select_chip(-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(loff_t to, size_t len, size_t * retlen, const u_char * buf){	int column, page, status, ret = 0, i;//  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) >> ADD2SHIFT;	/* Mask to get column */	column = to & 0x1f;	/* Initialize return length value */	*retlen = 0;	/* Do not allow write past end of page */	if ((column + len) > NAND_PAGE_OOB_SIZE) {//      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 ( FL_WRITING, NULL);	/* Select the NAND device */	nand_select_chip(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. */	nand_command(NAND_CMD_RESET, -1, -1);	// set the WP	*(base + NAND_SET_WP_REG) = 1;	/* Check the WP bit */	nand_command(NAND_CMD_STATUS, -1, -1);	if (!(nand_read_byte() & 0x80)) {//      DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");		ret = -EIO;		goto out;	}	/* Write out desired data */	nand_command(NAND_CMD_SEQIN, NAND_PAGE_SIZE, page);	/* prepad 0xff for partial programming */	nand_write_buf(ffchars, column);	/* write data */	nand_write_buf(buf, len);	/* postpad 0xff for partial programming */	nand_write_buf(ffchars, NAND_PAGE_OOB_SIZE - (len + column));	/* Send command to program the OOB data */	nand_command(NAND_CMD_PAGEPROG, -1, -1);	status = nand_wait(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 */	nand_command(NAND_CMD_READOOB, column, page);	/* Loop through and verify the data */	for (i = 0; i < len; i++) {		if (buf[i] != nand_read_byte()) {//          DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);			ret = -EIO;			goto out;		}	}//#endif  out:	// clear the WP	*(base + NAND_CLR_WP_REG) = 1;	/* De-select the NAND device */	nand_select_chip(-1);	return ret;}//================================================================// original APIs// src points to the beginning flash addressint nand_read(UINT8 * dst, UINT8 * src, UINT32 len){#ifdef	NAND_ECC				// testing by ProChao	size_t retlen;	nand_read_ecc((loff_t) src, (size_t) len, &retlen, (u_char *) dst, NULL, NULL);	return (int) retlen;#else	UINT32 i, j, col, row1, row2;	int page;					// ProChao	*(base + NAND_CLR_CE_REG) = 1;	for (i = 0; i < len; i += NAND_PAGE_SIZE, src += NAND_PAGE_SIZE) {		*(base + NAND_CLR_SPn_REG) = 1;		col = (int) src & ADD1MASK;		row1 = ((int) src & ADD2MASK) >> ADD2SHIFT;		row2 = ((int) src & ADD3MASK) >> ADD3SHIFT;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = 0;		*(base + NAND_CLR_CLE_REG) = 1;		*(base + NAND_SET_ALE_REG) = 1;		*(base + NAND_RW_REG) = col;		*(base + NAND_RW_REG) = row1;		*(base + NAND_RW_REG) = row2;		*(base + NAND_CLR_ALE_REG) = 1;		// wait 1us */		for (j = 0; j < 1000; j++) {			;;		}		for (j = 0; j < NAND_PAGE_SIZE; j++)			dst[i + j] = *(base + NAND_RW_REG);	}	*(base + NAND_SET_CE_REG) = 1;#endif	return 0;}int nand_write(UINT8 * dst, UINT8 * src, UINT32 len){#ifdef	NAND_ECC				// testing by ProChao	size_t retlen;	nand_write_ecc((loff_t) dst, (size_t) len, &retlen, (const u_char *) src, NULL, NULL);//  return (int) retlen;#else	UINT32 i, j, col, row1, row2;	base = (UINT8 *) NAND_REG_BASE;	*(base + NAND_SET_WP_REG) = 1;	*(base + NAND_CLR_CE_REG) = 1;	for (i = 0; i < len; i += NAND_PAGE_SIZE, dst += NAND_PAGE_SIZE) {		*(base + NAND_CLR_SPn_REG) = 1;		col = (int) dst & ADD1MASK;		row1 = ((int) dst & ADD2MASK) >> ADD2SHIFT;		row2 = ((int) dst & ADD3MASK) >> ADD3SHIFT;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_WRITE1;		*(base + NAND_CLR_CLE_REG) = 1;		*(base + NAND_SET_ALE_REG) = 1;		*(base + NAND_RW_REG) = col;		*(base + NAND_RW_REG) = row1;		*(base + NAND_RW_REG) = row2;		*(base + NAND_CLR_ALE_REG) = 1;		for (j = 0; j < NAND_PAGE_SIZE; j++)			*(base + NAND_RW_REG) = src[j + i];		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_WRITE2;		*(base + NAND_CLR_CLE_REG) = 1;		/* wait 200 us */		for (j = 0; j < 20000; j++) {			;;		}	}	*(base + NAND_SET_CE_REG) = 1;	*(base + NAND_CLR_WP_REG) = 1;#endif	return 0;}// note that, the addr must be the block starting addressint nand_erase(UINT8 * addr, UINT32 len){	UINT32 i, j, row1, row2;	unsigned long page;	base = (UINT8 *) NAND_REG_BASE;	*(base + NAND_SET_WP_REG) = 1;	*(base + NAND_CLR_SPn_REG) = 1;	*(base + NAND_CLR_CE_REG) = 1;	// here, NAND_SIZE_PER_BLK=0x4000	for (i = 0; i < len; i += NAND_SIZE_PER_BLK, addr += NAND_SIZE_PER_BLK) {	// check if bad (invalid) blocks detected		/* Shift to get first page */		page = (unsigned long) addr >> ADD2SHIFT;		/*		   if (nand_block_bad( page) != 0)		   {    // this block is bad block, double confirm this is bad one, then try next block		   buart_print("\n\rBad flash block detected!");		   continue;		   }		 */		// erasing		row1 = ((int) addr & ADD2MASK) >> ADD2SHIFT;		row2 = ((int) addr & ADD3MASK) >> ADD3SHIFT;		//		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_ERASE1;		*(base + NAND_CLR_CLE_REG) = 1;		*(base + NAND_SET_ALE_REG) = 1;		*(base + NAND_RW_REG) = row1;		*(base + NAND_RW_REG) = row2;		*(base + NAND_CLR_ALE_REG) = 1;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_ERASE2;		*(base + NAND_CLR_CLE_REG) = 1;		/* wait 1ms */		for (j = 0; j < 100000; j++);	}	*(base + NAND_SET_CE_REG) = 1;	*(base + NAND_CLR_WP_REG) = 1;	return 0;}// for writing bootloaderint nand_write_boot(UINT8 * dst, UINT8 * src, UINT32 len){	volatile UINT8 *base, *dstorig;	UINT32 i, j, col, row1, row2, k;	base = (UINT8 *) NAND_REG_BASE;	*(base + NAND_SET_WP_REG) = 1;	*(base + NAND_CLR_CE_REG) = 1;	i = 0;	/* write spare area if < NAND_PAGE_OOB_SIZE */	while (i < NAND_BOOT_SIZE) {		*(base + NAND_CLR_SPn_REG) = 1;		col = (int) dst & ADD1MASK;		row1 = ((int) dst & ADD2MASK) >> ADD2SHIFT;		row2 = ((int) dst & ADD3MASK) >> ADD3SHIFT;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_WRITE1;		*(base + NAND_CLR_CLE_REG) = 1;		*(base + NAND_SET_ALE_REG) = 1;		*(base + NAND_RW_REG) = col;		*(base + NAND_RW_REG) = row1;		*(base + NAND_RW_REG) = row2;		*(base + NAND_CLR_ALE_REG) = 1;		for (j = 0; j < NAND_PAGE_SIZE; j++)			*(base + NAND_RW_REG) = src[i + j];		i += NAND_PAGE_SIZE;		dst += NAND_PAGE_SIZE;		// enable spare area		*(base + NAND_SET_SPn_REG) = 1;		for (k = 0; k < NAND_PAGE_OOB_SIZE; k++)			*(base + NAND_RW_REG) = src[i + k];		i += NAND_PAGE_OOB_SIZE;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_WRITE2;		*(base + NAND_CLR_CLE_REG) = 1;		/* wait 200 us */		for (j = 0; j < 20000; j++) {			;;		}	}	i = NAND_BOOT_SIZE;	while (i < len) {		*(base + NAND_CLR_SPn_REG) = 1;		col = (int) dst & ADD1MASK;		row1 = ((int) dst & ADD2MASK) >> ADD2SHIFT;		row2 = ((int) dst & ADD3MASK) >> ADD3SHIFT;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_WRITE1;		*(base + NAND_CLR_CLE_REG) = 1;		*(base + NAND_SET_ALE_REG) = 1;		*(base + NAND_RW_REG) = col;		*(base + NAND_RW_REG) = row1;		*(base + NAND_RW_REG) = row2;		*(base + NAND_CLR_ALE_REG) = 1;		for (j = 0; j < NAND_PAGE_SIZE; j++)			*(base + NAND_RW_REG) = src[i + j];		i += NAND_PAGE_SIZE;		dst += NAND_PAGE_SIZE;		*(base + NAND_SET_CLE_REG) = 1;		*(base + NAND_RW_REG) = CMD_WRITE2;		*(base + NAND_CLR_CLE_REG) = 1;		/* wait 200 us */		for (j = 0; j < 20000; j++) {			;;		}	}	*(base + NAND_SET_CE_REG) = 1;	*(base + NAND_CLR_WP_REG) = 1;	return 0;}

⌨️ 快捷键说明

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