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

📄 nand_base.c

📁 飞思卡尔芯片imx27下的MTD模块的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* Send command to read back the data */	chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);	if (chip->verify_buf(mtd, buf, mtd->writesize))		return -EIO;#endif	return 0;}/** * nand_fill_oob - [Internal] Transfer client buffer to oob * @chip:	nand chip structure * @oob:	oob data buffer * @ops:	oob ops structure */static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,				  struct mtd_oob_ops *ops){	size_t len = ops->ooblen;	switch(ops->mode) {	case MTD_OOB_PLACE:	case MTD_OOB_RAW:		memcpy(chip->oob_poi + ops->ooboffs, oob, len);		return oob + len;	case MTD_OOB_AUTO: {		struct nand_oobfree *free = chip->ecc.layout->oobfree;		uint32_t boffs = 0, woffs = ops->ooboffs;		size_t bytes = 0;		for(; free->length && len; free++, len -= bytes) {			/* Write request not from offset 0 ? */			if (unlikely(woffs)) {				if (woffs >= free->length) {					woffs -= free->length;					continue;				}				boffs = free->offset + woffs;				bytes = min_t(size_t, len,					      (free->length - woffs));				woffs = 0;			} else {				bytes = min_t(size_t, len, free->length);				boffs = free->offset;			}			memcpy(chip->oob_poi + boffs, oob, bytes);			oob += bytes;		}		return oob;	}	default:		BUG();	}	return NULL;}#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0/** * nand_do_write_ops - [Internal] NAND write with ECC * @mtd:	MTD device structure * @to:		offset to write to * @ops:	oob operations description structure * * NAND write with ECC */static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,			     struct mtd_oob_ops *ops){	int chipnr, realpage, page, blockmask;	struct nand_chip *chip = mtd->priv;	uint32_t writelen = ops->len;	uint8_t *oob = ops->oobbuf;	uint8_t *buf = ops->datbuf;	int bytes = mtd->writesize;	int ret;	ops->retlen = 0;	/* reject writes, which are not page aligned */	if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {		printk(KERN_NOTICE "nand_write: "		       "Attempt to write not page aligned data\n");		return -EINVAL;	}	if (!writelen)		return 0;	chipnr = (int)(to >> chip->chip_shift);	chip->select_chip(mtd, chipnr);	/* Check, if it is write protected */	if (nand_check_wp(mtd))		return -EIO;	realpage = (int)(to >> chip->page_shift);	page = realpage & chip->pagemask;	blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;	/* Invalidate the page cache, when we write to the cached page */	if (to <= (chip->pagebuf << chip->page_shift) &&	    (chip->pagebuf << chip->page_shift) < (to + ops->len))		chip->pagebuf = -1;	chip->oob_poi = chip->buffers->oobwbuf;	while(1) {		int cached = writelen > bytes && page != blockmask;		if (unlikely(oob))			oob = nand_fill_oob(chip, oob, ops);		ret = chip->write_page(mtd, chip, buf, page, cached,				       (ops->mode == MTD_OOB_RAW));		if (ret)			break;		writelen -= bytes;		if (!writelen)			break;		buf += bytes;		realpage++;		page = realpage & chip->pagemask;		/* Check, if we cross a chip boundary */		if (!page) {			chipnr++;			chip->select_chip(mtd, -1);			chip->select_chip(mtd, chipnr);		}	}	if (unlikely(oob))		memset(chip->oob_poi, 0xff, mtd->oobsize);	ops->retlen = ops->len - writelen;	return ret;}/** * nand_write - [MTD Interface] NAND write with ECC * @mtd:	MTD device structure * @to:		offset to write to * @len:	number of bytes to write * @retlen:	pointer to variable to store the number of written bytes * @buf:	the data to write * * NAND write with ECC */static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,			  size_t *retlen, const uint8_t *buf){	struct nand_chip *chip = mtd->priv;	int ret;	/* Do not allow reads past end of device */	if ((to + len) > mtd->size)		return -EINVAL;	if (!len)		return 0;	nand_get_device(chip, mtd, FL_WRITING);	chip->ops.len = len;	chip->ops.datbuf = (uint8_t *)buf;	chip->ops.oobbuf = NULL;	ret = nand_do_write_ops(mtd, to, &chip->ops);	*retlen = chip->ops.retlen;	nand_release_device(mtd);	return ret;}/** * nand_do_write_oob - [MTD Interface] NAND write out-of-band * @mtd:	MTD device structure * @to:		offset to write to * @ops:	oob operation description structure * * NAND write out-of-band */static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,			     struct mtd_oob_ops *ops){	int chipnr, page, status;	struct nand_chip *chip = mtd->priv;	DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",	      (unsigned int)to, (int)ops->len);	/* Do not allow write past end of page */	if ((ops->ooboffs + ops->len) > mtd->oobsize) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "		      "Attempt to write past end of page\n");		return -EINVAL;	}	chipnr = (int)(to >> chip->chip_shift);	chip->select_chip(mtd, chipnr);	/* Shift to get page */	page = (int)(to >> chip->page_shift);	/*	 * 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.	 */	chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);	/* Check, if it is write protected */	if (nand_check_wp(mtd))		return -EROFS;	/* Invalidate the page cache, if we write to the cached page */	if (page == chip->pagebuf)		chip->pagebuf = -1;	chip->oob_poi = chip->buffers->oobwbuf;	memset(chip->oob_poi, 0xff, mtd->oobsize);	nand_fill_oob(chip, ops->oobbuf, ops);	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);	memset(chip->oob_poi, 0xff, mtd->oobsize);	if (status)		return status;	ops->retlen = ops->len;	return 0;}/** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @mtd:	MTD device structure * @to:		offset to write to * @ops:	oob operation description structure */static int nand_write_oob(struct mtd_info *mtd, loff_t to,			  struct mtd_oob_ops *ops){	struct nand_chip *chip = mtd->priv;	int ret = -ENOTSUPP;	ops->retlen = 0;	/* Do not allow writes past end of device */	if ((to + ops->len) > mtd->size) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "		      "Attempt read beyond end of device\n");		return -EINVAL;	}	nand_get_device(chip, mtd, FL_WRITING);	switch(ops->mode) {	case MTD_OOB_PLACE:	case MTD_OOB_AUTO:	case MTD_OOB_RAW:		break;	default:		goto out;	}	if (!ops->datbuf)		ret = nand_do_write_oob(mtd, to, ops);	else		ret = nand_do_write_ops(mtd, to, ops); out:	nand_release_device(mtd);	return ret;}/** * single_erease_cmd - [GENERIC] NAND standard block erase command function * @mtd:	MTD device structure * @page:	the page address of the block which will be erased * * Standard erase command for NAND chips */static void single_erase_cmd(struct mtd_info *mtd, int page){	struct nand_chip *chip = mtd->priv;	/* Send commands to erase a block */	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);}/** * multi_erease_cmd - [GENERIC] AND specific block erase command function * @mtd:	MTD device structure * @page:	the page address of the block which will be erased * * AND multi block erase command function * Erase 4 consecutive blocks */static void multi_erase_cmd(struct mtd_info *mtd, int page){	struct nand_chip *chip = mtd->priv;	/* Send commands to erase a block */	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);	chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);	chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);}/** * nand_erase - [MTD Interface] erase block(s) * @mtd:	MTD device structure * @instr:	erase instruction * * Erase one ore more blocks */static int nand_erase(struct mtd_info *mtd, struct erase_info *instr){	return nand_erase_nand(mtd, instr, 0);}#define BBT_PAGE_MASK	0xffffff3f/** * nand_erase_nand - [Internal] erase block(s) * @mtd:	MTD device structure * @instr:	erase instruction * @allowbbt:	allow erasing the bbt area * * Erase one ore more blocks */int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,		    int allowbbt){	int page, len, status, pages_per_block, ret, chipnr;	struct nand_chip *chip = mtd->priv;	int rewrite_bbt[NAND_MAX_CHIPS]={0};	unsigned int bbt_masked_page = 0xffffffff;	DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",	      (unsigned int)instr->addr, (unsigned int)instr->len);	/* Start address must align on block boundary */	if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "		      "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, "nand_erase: "		      "Erase past end of device\n");		return -EINVAL;	}	instr->fail_addr = 0xffffffff;	/* Grab the lock and see if the device is available */	nand_get_device(chip, mtd, FL_ERASING);	/* Shift to get first page */	page = (int)(instr->addr >> chip->page_shift);	chipnr = (int)(instr->addr >> chip->chip_shift);	/* Calculate pages in each block */	pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);	/* Select the NAND device */	chip->select_chip(mtd, chipnr);	/* Check, if it is write protected */	if (nand_check_wp(mtd)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "		      "Device is write protected!!!\n");		instr->state = MTD_ERASE_FAILED;		goto erase_exit;	}	/*	 * If BBT requires refresh, set the BBT page mask to see if the BBT	 * should be rewritten. Otherwise the mask is set to 0xffffffff which	 * can not be matched. This is also done when the bbt is actually	 * erased to avoid recusrsive updates	 */	if (chip->options & BBT_AUTO_REFRESH && !allowbbt)		bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;	/* Loop through the pages */	len = instr->len;	instr->state = MTD_ERASING;	while (len) {		/*		 * heck if we have a bad block, we do not erase bad blocks !		 */		if (nand_block_checkbad(mtd, ((loff_t) page) <<					chip->page_shift, 0, allowbbt)) {			printk(KERN_WARNING "nand_erase: attempt to erase a "			       "bad block at page 0x%08x\n", page);			instr->state = MTD_ERASE_FAILED;			goto erase_exit;		}		/*		 * Invalidate the page cache, if we erase the block which		 * contains the current cached page		 */		if (page <= chip->pagebuf && chip->pagebuf <		    (page + pages_per_block))			chip->pagebuf = -1;		chip->erase_cmd(mtd, page & chip->pagemask);		status = chip->waitfunc(mtd, chip);		/*		 * See if operation failed and additional status checks are		 * available		 */		if ((status & NAND_STATUS_FAIL) && (chip->errstat))			status = chip->errstat(mtd, chip, FL_ERASING,					       status, page);		/* See if block erase succeeded */		if (status & NAND_STATUS_FAIL) {			DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "			      "Failed erase, page 0x%08x\n", page);			instr->state = MTD_ERASE_FAILED;			instr->fail_addr = (page << chip->page_shift);			goto erase_exit;		}		/*		 * If BBT requires refresh, set the BBT rewrite flag to the		 * page being erased		 */		if (bbt_masked_page != 0xffffffff &&		    (page & BBT_PAGE_MASK) == bbt_masked_page)			    rewrite_bbt[chipnr] = (page << chip->page_shift);		/* Increment page address and decrement length */		len -= (1 << chip->phys_erase_shift);		page += pages_per_block;		/* Check, if we cross a chip boundary */		if (len && !(page & chip->pagemask)) {			chipnr++;			chip->select_chip(mtd, -1);			chip->select_chip(mtd, chipnr);			/*			 * If BBT requires refresh and BBT-PERCHIP, set the BBT			 * page mask to see if this BBT should be rewritten			 */			if (bbt_masked_page != 0xffffffff &&			    (chip->bbt_td->options & NAND_BBT_PERCHIP))				bbt_masked_page = chip->bbt_td->pages[chipnr] &					BBT_PAGE_MASK;		}	}	instr->state = MTD_ERASE_DONE; erase_exit:	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;	/* Do call back function */	if (!ret)		mtd_erase_callback(instr);	/* Deselect and wake up anyone waiting on the device */	nand_release_device(mtd);	/*	 * If BBT requires refresh and erase was successful, rewrite any	 * selected bad block tables	 */	if (bbt_masked_page == 0xffffffff || ret)		return ret;	for (chipnr = 0; chipnr < chip->numchips; chipnr++) {		if (!rewrite_bbt[chipnr])			continue;		/* update the BBT for chip */		DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "		      "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],		      chip->bbt_td->pages[chipnr]);		nand_update_bbt(mtd, rewrite_bbt[chipnr]);	}	/* Return more or less happy */	return ret;}

⌨️ 快捷键说明

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