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

📄 nand_base.c

📁 uboot200903最新版本的通用uboot
💻 C
📖 第 1 页 / 共 5 页
字号:
/** * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	buffer to store read data * * Not for syndrome calculating ecc controllers which need a special oob layout */static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,				uint8_t *buf){	int i, eccsize = chip->ecc.size;	int eccbytes = chip->ecc.bytes;	int eccsteps = chip->ecc.steps;	uint8_t *p = buf;	uint8_t *ecc_calc = chip->buffers->ecccalc;	uint8_t *ecc_code = chip->buffers->ecccode;	uint32_t *eccpos = chip->ecc.layout->eccpos;	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {		chip->ecc.hwctl(mtd, NAND_ECC_READ);		chip->read_buf(mtd, p, eccsize);		chip->ecc.calculate(mtd, p, &ecc_calc[i]);	}	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);	for (i = 0; i < chip->ecc.total; i++)		ecc_code[i] = chip->oob_poi[eccpos[i]];	eccsteps = chip->ecc.steps;	p = buf;	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {		int stat;		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);		if (stat == -1)			mtd->ecc_stats.failed++;		else			mtd->ecc_stats.corrected += stat;	}	return 0;}/** * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	buffer to store read data * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,				   uint8_t *buf){	int i, eccsize = chip->ecc.size;	int eccbytes = chip->ecc.bytes;	int eccsteps = chip->ecc.steps;	uint8_t *p = buf;	uint8_t *oob = chip->oob_poi;	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {		int stat;		chip->ecc.hwctl(mtd, NAND_ECC_READ);		chip->read_buf(mtd, p, eccsize);		if (chip->ecc.prepad) {			chip->read_buf(mtd, oob, chip->ecc.prepad);			oob += chip->ecc.prepad;		}		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);		chip->read_buf(mtd, oob, eccbytes);		stat = chip->ecc.correct(mtd, p, oob, NULL);		if (stat < 0)			mtd->ecc_stats.failed++;		else			mtd->ecc_stats.corrected += stat;		oob += eccbytes;		if (chip->ecc.postpad) {			chip->read_buf(mtd, oob, chip->ecc.postpad);			oob += chip->ecc.postpad;		}	}	/* Calculate remaining oob bytes */	i = mtd->oobsize - (oob - chip->oob_poi);	if (i)		chip->read_buf(mtd, oob, i);	return 0;}/** * nand_transfer_oob - [Internal] Transfer oob to client buffer * @chip:	nand chip structure * @oob:	oob destination address * @ops:	oob ops structure * @len:	size of oob to transfer */static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,				  struct mtd_oob_ops *ops, size_t len){	switch(ops->mode) {	case MTD_OOB_PLACE:	case MTD_OOB_RAW:		memcpy(oob, chip->oob_poi + ops->ooboffs, len);		return oob + len;	case MTD_OOB_AUTO: {		struct nand_oobfree *free = chip->ecc.layout->oobfree;		uint32_t boffs = 0, roffs = ops->ooboffs;		size_t bytes = 0;		for(; free->length && len; free++, len -= bytes) {			/* Read request not from offset 0 ? */			if (unlikely(roffs)) {				if (roffs >= free->length) {					roffs -= free->length;					continue;				}				boffs = free->offset + roffs;				bytes = min_t(size_t, len,					      (free->length - roffs));				roffs = 0;			} else {				bytes = min_t(size_t, len, free->length);				boffs = free->offset;			}			memcpy(oob, chip->oob_poi + boffs, bytes);			oob += bytes;		}		return oob;	}	default:		BUG();	}	return NULL;}/** * nand_do_read_ops - [Internal] Read data with ECC * * @mtd:	MTD device structure * @from:	offset to read from * @ops:	oob ops structure * * Internal function. Called with chip held. */static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,			    struct mtd_oob_ops *ops){	int chipnr, page, realpage, col, bytes, aligned;	struct nand_chip *chip = mtd->priv;	struct mtd_ecc_stats stats;	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;	int sndcmd = 1;	int ret = 0;	uint32_t readlen = ops->len;	uint32_t oobreadlen = ops->ooblen;	uint8_t *bufpoi, *oob, *buf;	stats = mtd->ecc_stats;	chipnr = (int)(from >> chip->chip_shift);	chip->select_chip(mtd, chipnr);	realpage = (int)(from >> chip->page_shift);	page = realpage & chip->pagemask;	col = (int)(from & (mtd->writesize - 1));	buf = ops->datbuf;	oob = ops->oobbuf;	while(1) {		bytes = min(mtd->writesize - col, readlen);		aligned = (bytes == mtd->writesize);		/* Is the current page in the buffer ? */		if (realpage != chip->pagebuf || oob) {			bufpoi = aligned ? buf : chip->buffers->databuf;			if (likely(sndcmd)) {				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);				sndcmd = 0;			}			/* Now read the page into the buffer */			if (unlikely(ops->mode == MTD_OOB_RAW))				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);			else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)				ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);			else				ret = chip->ecc.read_page(mtd, chip, bufpoi);			if (ret < 0)				break;			/* Transfer not aligned data */			if (!aligned) {				if (!NAND_SUBPAGE_READ(chip) && !oob)					chip->pagebuf = realpage;				memcpy(buf, chip->buffers->databuf + col, bytes);			}			buf += bytes;			if (unlikely(oob)) {				/* Raw mode does data:oob:data:oob */				if (ops->mode != MTD_OOB_RAW) {					int toread = min(oobreadlen,						chip->ecc.layout->oobavail);					if (toread) {						oob = nand_transfer_oob(chip,							oob, ops, toread);						oobreadlen -= toread;					}				} else					buf = nand_transfer_oob(chip,						buf, ops, mtd->oobsize);			}			if (!(chip->options & NAND_NO_READRDY)) {				/*				 * Apply delay or wait for ready/busy pin. Do				 * this before the AUTOINCR check, so no				 * problems arise if a chip which does auto				 * increment is marked as NOAUTOINCR by the				 * board driver.				 */				if (!chip->dev_ready)					udelay(chip->chip_delay);				else					nand_wait_ready(mtd);			}		} else {			memcpy(buf, chip->buffers->databuf + col, bytes);			buf += bytes;		}		readlen -= bytes;		if (!readlen)			break;		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		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);		}		/* Check, if the chip supports auto page increment		 * or if we have hit a block boundary.		 */		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))			sndcmd = 1;	}	ops->retlen = ops->len - (size_t) readlen;	if (oob)		ops->oobretlen = ops->ooblen - oobreadlen;	if (ret)		return ret;	if (mtd->ecc_stats.failed - stats.failed)		return -EBADMSG;	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;}/** * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd:	MTD device structure * @from:	offset to read from * @len:	number of bytes to read * @retlen:	pointer to variable to store the number of read bytes * @buf:	the databuffer to put data * * Get hold of the chip and call nand_do_read */static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,		     size_t *retlen, uint8_t *buf){	struct nand_chip *chip = mtd->priv;	int ret;	/* Do not allow reads past end of device */	if ((from + len) > mtd->size)		return -EINVAL;	if (!len)		return 0;	nand_get_device(chip, mtd, FL_READING);	chip->ops.len = len;	chip->ops.datbuf = buf;	chip->ops.oobbuf = NULL;	ret = nand_do_read_ops(mtd, from, &chip->ops);	*retlen = chip->ops.retlen;	nand_release_device(mtd);	return ret;}/** * nand_read_oob_std - [REPLACABLE] the most common OOB data read function * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to read * @sndcmd:	flag whether to issue read command or not */static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,			     int page, int sndcmd){	if (sndcmd) {		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);		sndcmd = 0;	}	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);	return sndcmd;}/** * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC *			    with syndromes * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to read * @sndcmd:	flag whether to issue read command or not */static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,				  int page, int sndcmd){	uint8_t *buf = chip->oob_poi;	int length = mtd->oobsize;	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;	int eccsize = chip->ecc.size;	uint8_t *bufpoi = buf;	int i, toread, sndrnd = 0, pos;	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);	for (i = 0; i < chip->ecc.steps; i++) {		if (sndrnd) {			pos = eccsize + i * (eccsize + chunk);			if (mtd->writesize > 512)				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);			else				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);		} else			sndrnd = 1;		toread = min_t(int, length, chunk);		chip->read_buf(mtd, bufpoi, toread);		bufpoi += toread;		length -= toread;	}	if (length > 0)		chip->read_buf(mtd, bufpoi, length);	return 1;}/** * nand_write_oob_std - [REPLACABLE] the most common OOB data write function * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to write */static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,			      int page){	int status = 0;	const uint8_t *buf = chip->oob_poi;	int length = mtd->oobsize;	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);	chip->write_buf(mtd, buf, length);	/* Send command to program the OOB data */	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);	status = chip->waitfunc(mtd, chip);	return status & NAND_STATUS_FAIL ? -EIO : 0;}/** * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC *			     with syndrome - only for large page flash ! * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to write */static int nand_write_oob_syndrome(struct mtd_info *mtd,				   struct nand_chip *chip, int page){	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;	int eccsize = chip->ecc.size, length = mtd->oobsize;	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;	const uint8_t *bufpoi = chip->oob_poi;	/*	 * data-ecc-data-ecc ... ecc-oob	 * or	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob	 */	if (!chip->ecc.prepad && !chip->ecc.postpad) {		pos = steps * (eccsize + chunk);		steps = 0;	} else		pos = eccsize;	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);	for (i = 0; i < steps; i++) {		if (sndcmd) {			if (mtd->writesize <= 512) {				uint32_t fill = 0xFFFFFFFF;				len = eccsize;				while (len > 0) {					int num = min_t(int, len, 4);					chip->write_buf(mtd, (uint8_t *)&fill,							num);					len -= num;				}			} else {				pos = eccsize + i * (eccsize + chunk);				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);			}		} else			sndcmd = 1;		len = min_t(int, length, chunk);		chip->write_buf(mtd, bufpoi, len);		bufpoi += len;		length -= len;	}	if (length > 0)		chip->write_buf(mtd, bufpoi, length);	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);	status = chip->waitfunc(mtd, chip);	return status & NAND_STATUS_FAIL ? -EIO : 0;}/** * nand_do_read_oob - [Intern] NAND read out-of-band * @mtd:	MTD device structure * @from:	offset to read from * @ops:	oob operations description structure * * NAND read out-of-band data from the spare area */static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,			    struct mtd_oob_ops *ops){	int page, realpage, chipnr, sndcmd = 1;	struct nand_chip *chip = mtd->priv;	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;	int readlen = ops->ooblen;	int len;	uint8_t *buf = ops->oobbuf;	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",	          (unsigned long long)from, readlen);	if (ops->mode == MTD_OOB_AUTO)		len = chip->ecc.layout->oobavail;	else		len = mtd->oobsize;	if (unlikely(ops->ooboffs >= len)) {		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "		          "Attempt to start read outside oob\n");		return -EINVAL;	}	/* Do not allow reads past end of device */	if (unlikely(from >= mtd->size ||		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -					(from >> chip->page_shift)) * len)) {		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: "		          "Attempt read beyond end of device\n");		return -EINVAL;	}	chipnr = (int)(from >> chip->chip_shift);	chip->select_chip(mtd, chipnr);	/* Shift to get page */	realpage = (int)(from >> chip->page_shift);	page = realpage & chip->pagemask;	while(1) {

⌨️ 快捷键说明

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