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

📄 smc_core.c

📁 比较好的VIVI开发源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 < mtd->eccsize)
			nand_command(mtd, NAND_CMD_READ0, col, page);
		else
			nand_command(mtd, NAND_CMD_READ1, col - 256, page);

		this->wait_for_ready();

		/* Loop through and verify the data */
		for (i = col; i < cnt; i++) {
			if (this->data_buf[i] != this->read_data()) {
				DEBUG(MTD_DEBUG_LEVEL0,
					__FUNCTION__"(): Failed write verify, " \
					"page 0x%08x, %6i bytes were succesful\n",
					page, *retlen);
				i = -EIO;
				goto nand_write_exit;
			}
		}
#endif

		/* 
		 * If we are writing a large amount of data and/or it
		 * crosses page or half-page boundaries, we set the
		 * the column to zero. It simplifies the program logic.
		 */
		if (col)
			col = 0x00;

		/* Update written bytes count */
		*retlen += cnt;

		/* Increment page address */
		page++;
		
	}

	/* Return happy */
	*retlen = len;
	i = 0;

nand_write_exit:
	/* De-select the NAND device */
	nand_deselect();

	return i;
}

/*
 * NAND write witdh ECC, but only 1 sector!
 */
static int
nand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
               size_t *retlen, const u_char *buf, u_char *ecc_code)
{
	int i, page, cnt, status, ret;
	struct nand_chip *this = mtd->priv;
	unsigned int sector_size, page_size, oob_size;

	DEBUG(MTD_DEBUG_LEVEL3,
		__FUNCTION__"(): to = 0x%08x, len = %i\n", (unsigned int)to,
		(int)len);

	sector_size = this->dev->szS;
	page_size = mtd->oobblock;
	oob_size = mtd->oobsize;
	if (to & (sector_size - 1)) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Not Sector aligned\n");
		return -EINVAL;
	}
	if (len != sector_size) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Only 1 Sector\n");
		return -EINVAL;
	}
	/* Do not allow write past end of page */
	if ((to + len) > mtd->size) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Attempted write past end of device\n");
		return -EINVAL;
	}

	/* Shift to get page */
	page = ((int) to) >> this->page_shift;

	/* Initialize return length value */
	*retlen = 0;

	/* Select the NAND device */
	nand_select();

	/* Check the WP bit */
	nand_command(mtd, NAND_CMD_STATUS, -1, -1);

	this->wait_for_ready();

	if (!(this->read_data() & SMC_STAT_NOT_WP)) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Device is write protected!!!\n");
		ret = -EPERM;
		goto nand_write_err;
	}

	/* Loop until all data is written */
	while (*retlen < len) {
		/* Send command to begin auto page programming */
		nand_command(mtd, NAND_CMD_SEQIN, 0x00, page);

		this->hwcontrol(NAND_CTL_DAT_OUT);

		/* Write out complete page of data */
		for (i = 0, cnt = 0; i < page_size; i++, cnt++)
			this->write_data(buf[(*retlen) + cnt]);

		/* Write ones for partial page programming */
		for (i = 0; i < oob_size; i++) {
#ifdef USE_256BYTE_NAND_FLASH
			if (*retlen & (sector_size -1))
				this->write_data(ecc_code[SMC_OOB256_SIZE + i]);
			else
#endif
				this->write_data(ecc_code[i]);
		}

		this->hwcontrol(NAND_CTL_DAT_IN);

		/* Send command to actually program the data */
		nand_command(mtd, NAND_CMD_PAGEPROG, -1, -1);

		this->wait_for_ready();

		/*
		 * Wait for program operation to complete. This could
		 * take up to 3000us (3ms) on some devices, so we try
		 * and exit as quickly as possible
		 */
		status = 0;
		for (i = 0; i < 25; i++) {
			/* Delay for 125us */
			udelay(125);		    

			/* Check the status */
			nand_command(mtd, NAND_CMD_STATUS, -1, -1);
			status = (int)this->read_data();
			if (status & SMC_STAT_READY)
				break;
		}

		/* See if device thins it succeeded */
		if (status & SMC_STAT_WRITE_ERR) {
			DEBUG(MTD_DEBUG_LEVEL0,
				__FUNCTION__"(): Failed write, page 0x%08x, " \
				"%6i bytes were succesful\n", page, *retlen);
			ret = -EIO;
			goto nand_write_err;
		}

#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 tha 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 */
#ifdef USE_256BYTE_NAND_FLASH
		if (*retlen & (sector_size - 1))
			nand_command(mtd, NAND_CMD_READ0, 0x00, page + 1);
		else
#endif
			nand_command(mtd, NAND_CMD_READ0, 0x00, page);

		this->wait_for_ready();

		/* Loop through and verify the data */
		for (i = 0; i < page_size; i++) {
			if (this->data_buf[i] != this->read_data()) {
				DEBUG(MTD_DEBUG_LEVEL0,
					__FUNCTION__"(): Failed write verify, " \
					"page 0x%08x, %6i bytes were succesful\n",
					page, *retlen);
				ret = -EIO;
				goto nand_write_err;
			}
		}
#endif
		/* Update written bytes count */
		*retlen += cnt;

		/* Increment page address */
		page++;
	}

	*retlen = len;
	ret = 0;

nand_write_err:
	/* De-select the NAND device */
	nand_deselect();

	return ret;
}

/*
 * 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 i, offset, page, status, ret;
	struct nand_chip *this = mtd->priv;

	DEBUG(MTD_DEBUG_LEVEL3,
		__FUNCTION__"(): 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 */
	offset = to & 0x1f;

	/* Initialize return length value */
	*retlen = 0;

	/* Do not allow write past end of page */
	if ((offset + len) > mtd->oobsize) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Attempt to write past end of page\n");
		return -EINVAL;
	}

	/* Select the NAND device */
	nand_select();

	/* Check the WP bit */
	nand_command(mtd, NAND_CMD_STATUS, -1, -1);

	this->wait_for_ready();

	if (!(this->read_data() & SMC_STAT_NOT_WP)) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Device is write protected!!!\n");
		ret = -EPERM;
		goto nand_write_oob_err;
	}

	/* Write out desired data */
	nand_command(mtd, NAND_CMD_SEQIN, offset + mtd->oobblock, page);
	this->hwcontrol(NAND_CTL_DAT_OUT);
	for (i = 0; i < len; i++)
		this->write_data(buf[i]);
	this->hwcontrol(NAND_CTL_DAT_IN);

	/* Send command to program the OOB data */
	nand_command(mtd, NAND_CMD_PAGEPROG, -1, -1);

	this->wait_for_ready();

	/*
	 * Wait for program operation to complete. This could
	 * take up to 3000us (3ms) on some devices, so we try
	 * and exit as quickly as possible.
	 */
	status = 0;
	for (i = 0; i < 24; i++) {
		/* Delay for 125us */
		udelay(125);

		/* Check the status */
		nand_command(mtd, NAND_CMD_STATUS, -1, -1);

		this->wait_for_ready();

		status = (int)this->read_data();
		if (status & SMC_STAT_READY)
			break;
	}

	/* See if device thinks it succeeded */
	if (status & SMC_STAT_WRITE_ERR) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Failed write, page 0x%08x\n", page);
		ret = -EIO;
		goto nand_write_oob_err;
	}

#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
	/* Send command to read back the data */
	nand_command(mtd, NAND_CMD_READOOB, offset, page);

	this->wait_for_ready();

	/* Loop through and verify the data */
	for (i = 0; i < len; i++) {
		if (buf[i] != this->read_data()) {
			DEBUG(MTD_DEBUG_LEVEL0,
				__FUNCTION__"(): Failed write verify, page 0x%08x\n",
				page);
			ret = -EIO;
			goto nand_write_oob_err;
		}
	}
#endif

	/* Return happy */
	*retlen = len;
	ret = 0;
	
nand_write_oob_err:
	/* De-select the NAND device */
	nand_deselect();

	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,
		__FUNCTION__"(): start = 0x%08x, len = %i\n",
		(unsigned int)instr->addr, (unsigned int)instr->len);

	/* Start address must aligned on block boundary */
	if (instr->addr & (mtd->erasesize - 1)) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Unaligned address\n");
		return -EINVAL;
	}

	/* Length must align on block boundary */
	if (instr->len & (mtd->erasesize - 1)) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): 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,
			__FUNCTION__"(): 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 */
	nand_select();

	/* Check the WP bit */
	nand_command(mtd, NAND_CMD_STATUS, -1, -1);

	this->wait_for_ready();

	if (!(this->read_data() & SMC_STAT_NOT_WP)) {
		DEBUG(MTD_DEBUG_LEVEL0,
			__FUNCTION__"(): Device is write protected!!!\n");
		nand_deselect();
		return -EIO;
	}

	/* Loop through the pages */
	len = instr->len;
	while (len) {
		/* Send commands to erase a page */
		nand_command(mtd, NAND_CMD_ERASE1, -1, page);
		nand_command(mtd, NAND_CMD_ERASE2, -1, -1);

		this->wait_for_ready();

		/*
		 * Wait for program operation to complete. This could
		 * take up to 4000us (4ms) on some devices, so we try
		 * and exit as quickly as possible.
		 */
		status = 0;
		for (i = 0; i < 32; i++) {
			/* Delay for 125us */
			udelay(125);

			/* Check the status */
			nand_command(mtd, NAND_CMD_STATUS, -1, -1);

			this->wait_for_ready();

			status = (int)this->read_data();
			if (status & SMC_STAT_READY)
				break;
		}

		/* See if block erase succeeded */
		if (status & SMC_STAT_WRITE_ERR) {
			DEBUG(MTD_DEBUG_LEVEL0,
				__FUNCTION__"(): Failed erase, page 0x%08x\n", page);
			nand_deselect();
#if 0
			instr->state = MTD_ERASE_FAILED;
			if (instr->callback)
				instr->callback(instr);
#endif
			return -EIO;
		}

		/* Increment page address and decrement length */
		len -= mtd->erasesize;
		page += pages_per_block;
	}

	/* De-select the NAND device */
	nand_deselect();

#if 0
	/* Do call back function */
	instr->state = MTD_ERASE_DONE;
	if (instr->callback)
		instr->callback(instr);
#endif

	/* Return happy */
	return 0;	
}

/*
 * Scan for the SMC device
 */
int
smc_scan(struct mtd_info *mtd)
{
	int i, nand_maf_id, nand_dev_id;
	struct nand_chip *this = mtd->priv;

	/* Select the device */
	nand_select();

	/* Send the command for reading device ID */
	nand_command(mtd, NAND_CMD_READID, 0x00, -1);

	this->wait_for_ready();

	/* Read manufacturer and device IDs */
	nand_maf_id = this->read_data();
	nand_dev_id = this->read_data();

	/* Print and sotre flash device information */
	for (i = 0; nand_flash_ids[i].name != NULL; i++) {
		if (nand_maf_id == nand_flash_ids[i].manufacture_id &&
		    nand_dev_id == nand_flash_ids[i].model_id) {
#ifdef USE_256BYTE_NAND_FLASH
			if (!mtd->size) {
				mtd->name = nand_flash_ids[i].name;
				mtd->erasesize = nand_flash_ids[i].erasesize;
				mtd->size = (1 << nand_flash_ids[i].chipshift);
				mtd->eccsize = 256;
				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;
				}
				this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
			}
#else
			if (!(mtd->size) && !(nand_flash_ids[i].page256)) {
				mtd->name = nand_flash_ids[i].name;
				mtd->erasesize = nand_flash_ids[i].erasesize;
				mtd->size = (1 << nand_flash_ids[i].chipshift);
				mtd->eccsize = 256;
				mtd->oobblock = 512;
				mtd->oobsize = 16;
				this->page_shift = 9;
				this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];
			}
#endif
			printk("NAND device: Manufacture ID:" \
				" 0x%02x, Chip ID: 0x%02x (%s)\n",
				nand_maf_id, nand_dev_id, mtd->name);
			break;
		}	    
	}

	/* De-select the device */
	nand_deselect();

	/* Print warning message for no device */
	if (!mtd->size) {
		printk("No NAND device found!!!\n");
		return 1;
	}

	/* Fill in remaining MTD driver data */
	mtd->type = MTD_NANDFLASH;
	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
	mtd->module = NULL;
	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->lock = NULL;
	mtd->unlock = NULL;

	/* Return happy */
	return 0;
}

⌨️ 快捷键说明

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