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

📄 nand_base.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	uint32_t *eccpos = chip->ecc.layout->eccpos;	/* Software ecc calculation */	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)		chip->ecc.calculate(mtd, p, &ecc_calc[i]);	for (i = 0; i < chip->ecc.total; i++)		chip->oob_poi[eccpos[i]] = ecc_calc[i];	chip->ecc.write_page_raw(mtd, chip, buf);}/** * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	data buffer */static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,				  const uint8_t *buf){	int i, eccsize = chip->ecc.size;	int eccbytes = chip->ecc.bytes;	int eccsteps = chip->ecc.steps;	uint8_t *ecc_calc = chip->buffers->ecccalc;	const uint8_t *p = buf;	uint32_t *eccpos = chip->ecc.layout->eccpos;	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);		chip->write_buf(mtd, p, eccsize);		chip->ecc.calculate(mtd, p, &ecc_calc[i]);	}	for (i = 0; i < chip->ecc.total; i++)		chip->oob_poi[eccpos[i]] = ecc_calc[i];	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);}/** * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	data buffer * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */static void nand_write_page_syndrome(struct mtd_info *mtd,				    struct nand_chip *chip, const uint8_t *buf){	int i, eccsize = chip->ecc.size;	int eccbytes = chip->ecc.bytes;	int eccsteps = chip->ecc.steps;	const uint8_t *p = buf;	uint8_t *oob = chip->oob_poi;	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);		chip->write_buf(mtd, p, eccsize);		if (chip->ecc.prepad) {			chip->write_buf(mtd, oob, chip->ecc.prepad);			oob += chip->ecc.prepad;		}		chip->ecc.calculate(mtd, p, oob);		chip->write_buf(mtd, oob, eccbytes);		oob += eccbytes;		if (chip->ecc.postpad) {			chip->write_buf(mtd, oob, chip->ecc.postpad);			oob += chip->ecc.postpad;		}	}	/* Calculate remaining oob bytes */	i = mtd->oobsize - (oob - chip->oob_poi);	if (i)		chip->write_buf(mtd, oob, i);}/** * nand_write_page - [REPLACEABLE] write one page * @mtd:	MTD device structure * @chip:	NAND chip descriptor * @buf:	the data to write * @page:	page number to write * @cached:	cached programming * @raw:	use _raw version of write_page */static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,			   const uint8_t *buf, int page, int cached, int raw){	int status;	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);	if (unlikely(raw))		chip->ecc.write_page_raw(mtd, chip, buf);	else		chip->ecc.write_page(mtd, chip, buf);	/*	 * Cached progamming disabled for now, Not sure if its worth the	 * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)	 */	cached = 0;	if (!cached || !(chip->options & NAND_CACHEPRG)) {		chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);		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_WRITING, status,					       page);		if (status & NAND_STATUS_FAIL)			return -EIO;	} else {		chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);		status = chip->waitfunc(mtd, chip);	}#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	/* 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 & (chip->subpagesize - 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, column;	struct nand_chip *chip = mtd->priv;	uint32_t writelen = ops->len;	uint8_t *oob = ops->oobbuf;	uint8_t *buf = ops->datbuf;	int ret, subpage;	ops->retlen = 0;	if (!writelen)		return 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;	}	column = to & (mtd->writesize - 1);	subpage = column || (writelen & (mtd->writesize - 1));	if (subpage && oob)		return -EINVAL;	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;	/* If we're not given explicit OOB data, let it be 0xFF */	if (likely(!oob))		memset(chip->oob_poi, 0xff, mtd->oobsize);	while(1) {		int bytes = mtd->writesize;		int cached = writelen > bytes && page != blockmask;		uint8_t *wbuf = buf;		/* Partial page write ? */		if (unlikely(column || writelen < (mtd->writesize - 1))) {			cached = 0;			bytes = min_t(int, bytes - column, (int) writelen);			chip->pagebuf = -1;			memset(chip->buffers->databuf, 0xff, mtd->writesize);			memcpy(&chip->buffers->databuf[column], buf, bytes);			wbuf = chip->buffers->databuf;		}		if (unlikely(oob))			oob = nand_fill_oob(chip, oob, ops);		ret = chip->write_page(mtd, chip, wbuf, page, cached,				       (ops->mode == MTD_OOB_RAW));		if (ret)			break;		writelen -= bytes;		if (!writelen)			break;		column = 0;		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);		}	}	ops->retlen = ops->len - writelen;	if (unlikely(oob))		ops->oobretlen = ops->ooblen;	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, len;	struct nand_chip *chip = mtd->priv;	DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",	      (unsigned int)to, (int)ops->ooblen);	if (ops->mode == MTD_OOB_AUTO)		len = chip->ecc.layout->oobavail;	else		len = mtd->oobsize;	/* Do not allow write past end of page */	if ((ops->ooboffs + ops->ooblen) > len) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "		      "Attempt to write past end of page\n");		return -EINVAL;	}	if (unlikely(ops->ooboffs >= len)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "			"Attempt to start write outside oob\n");		return -EINVAL;	}	/* Do not allow reads past end of device */	if (unlikely(to >= mtd->size ||		     ops->ooboffs + ops->ooblen >			((mtd->size >> chip->page_shift) -			 (to >> chip->page_shift)) * len)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "			"Attempt write beyond end of device\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;	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->oobretlen = ops->ooblen;	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 (ops->datbuf && (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

⌨️ 快捷键说明

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