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

📄 nand_bbt.c

📁 freescale atk source code
💻 C
📖 第 1 页 / 共 2 页
字号:
		     int chipsel)
{
	int i, j, res, chip = 0;
	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
	int nrchips, bbtoffs, ooboffs;
	u8 msk[4];
	u8 rcode = td->reserved_block_code;
	u32 len = 0;
	u64 to;

	if (!rcode)
		rcode = 0xff;
	/* Write bad block table per chip rather than per device ? */
	if (td->options & NAND_BBT_PERCHIP) {
		numblocks = nd->blk_count;
		/* Full device write or specific chip ? */
		if (chipsel == -1) {
			nrchips = 1;
		} else {
			nrchips = chipsel + 1;
			chip = chipsel;
		}
	} else {
		numblocks = nd->blk_count;
		nrchips = 1;
	}

	/* Loop through the chips */
	for (; chip < nrchips; chip++) {

		/* There was already a version of the table, reuse the page
		 * This applies for absolute placement too, as we have the
		 * page nr. in td->pages.
		 */
		if (td->pages[chip] != -1) {
			page = td->pages[chip];
			goto write;
		}

		/* Automatic placement of the bad block table */
		/* Search direction top -> down ? */
		if (td->options & NAND_BBT_LASTBLOCK) {
			startblock = numblocks * (chip + 1) - 1;
			dir = -1;
		} else {
			startblock = chip * numblocks;
			dir = 1;
		}

		for (i = 0; i < td->maxblocks; i++) {
			int block = startblock + dir * i;
			/* Check, if the block is bad */
			switch ((nd->bbt[block >> 2] >>
				 (2 * (block & 0x03))) & 0x03) {
			case 0x01:
			case 0x03:
				continue;
			}
			page = block * nd->ppb;
			/* Check, if the block is used by the mirror table */
			if (!md || md->pages[chip] != page)
				goto write;
		}
		
		return -1;
	write:

		/* Set up shift count and masks for the flash table */
		bits = td->options & NAND_BBT_NRBITS_MSK;
		msk[2] = ~rcode;
		switch (bits) {
		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
			msk[3] = 0x01;
			break;
		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
			msk[3] = 0x03;
			break;
		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
			msk[3] = 0x0f;
			break;
		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
			msk[3] = 0xff;
			break;
		default: return -1;
		}

		bbtoffs = chip * (numblocks >> 2);

		to = ((u64) page) * nd->page_size;

		
		/* Calc length */
		len = (u32) (numblocks >> sft);
		/* Make it page aligned ! */
		len = (len + (nd->page_size - 1)) & ~(nd->page_size - 1);
		/* Preset the buffer with 0xff */
		memset(buf, 0xff, len + (len / nd->page_size)* nd->oob_size);
		offs = 0;
		ooboffs = len;
		/* Pattern is located in oob area of first page */
		memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
		
		if (td->options & NAND_BBT_VERSION)
			buf[ooboffs + td->veroffs] = td->version[chip];

		/* walk through the memory table */
		for (i = 0; i < numblocks;) {
			u8 dat;
			dat = nd->bbt[bbtoffs + (i >> 2)];
			for (j = 0; j < 4; j++, i++) {
				int sftcnt = (i << (3 - sft)) & sftmsk;
				/* Do not store the reserved bbt blocks ! */
				buf[offs + (i >> sft)] &=
					~(msk[dat & 0x03] << sftcnt);
				dat >>= 2;
			}
		}

		res = nand_erase_block(page / nd->ppb);
		
		if (res < 0)
			goto outerr;

		res = scan_write_bbt(nd, to, len, buf, &buf[len]);
		if (res < 0)
			goto outerr;

		/* Mark it as used */
		td->pages[chip] = page;
	}
	return 0;

 outerr:
	return res;
}

/**
 * check_create - [GENERIC] create and write bbt(s) if necessary
 * @nd:		nand device structure
 * @buf:	temporary buffer
 * @bd:		descriptor for the good/bad block search pattern
 *
 * The function checks the results of the previous call to read_bbt
 * and creates / updates the bbt(s) if necessary
 * Creation is necessary if no bbt was found for the chip/device
 * Update is necessary if one of the tables is missing or the
 * version nr. of one table is less than the other
*/
static int check_create(nand_t *nd, u8 *buf, struct nand_bbt_descr *bd)
{
	int i, chips, writeops, chipsel, res;
	struct nand_bbt_descr *td = &bbt_main_descr;
	struct nand_bbt_descr *md = &bbt_mirror_descr;
	struct nand_bbt_descr *rd, *rd2;

	/* Do we have a bbt per chip ? */
	if (td->options & NAND_BBT_PERCHIP)
		chips = 1;

	for (i = 0; i < chips; i++) {
		writeops = 0;
		rd = NULL;
		rd2 = NULL;
		/* Per chip or per device ? */
		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
		/* Mirrored table avilable ? */
		if (md) {
			if (td->pages[i] == -1 && md->pages[i] == -1) {
				writeops = 0x03;
				goto create;
			}

			if (td->pages[i] == -1) {
				rd = md;
				td->version[i] = md->version[i];
				writeops = 1;
				goto writecheck;
			}

			if (md->pages[i] == -1) {
				rd = td;
				md->version[i] = td->version[i];
				writeops = 2;
				goto writecheck;
			}

			if (td->version[i] == md->version[i]) {
				rd = td;
				if (!(td->options & NAND_BBT_VERSION))
					rd2 = md;
				goto writecheck;
			}

			if (((u8) (td->version[i] - md->version[i])) > 0) {
				rd = td;
				md->version[i] = td->version[i];
				writeops = 2;
			} else {
				rd = md;
				td->version[i] = md->version[i];
				writeops = 1;
			}

			goto writecheck;

		} else {
			if (td->pages[i] == -1) {
				writeops = 0x01;
				goto create;
			}
			rd = td;
			goto writecheck;
		}
	create:
		/* Create the bad block table by scanning the device ? */
		if (!(td->options & NAND_BBT_CREATE))
			continue;

		/* Create the table in memory by scanning the chip(s) */
		create_bbt(nd, buf, bd, chipsel);

		td->version[i] = 1;
		if (md)
			md->version[i] = 1;
	writecheck:
		/* read back first ? */
		if (rd)
			read_abs_bbt(nd, buf, rd, chipsel);
		/* If they weren't versioned, read both. */
		if (rd2)
			read_abs_bbt(nd, buf, rd2, chipsel);

		/* Write the bad block table to the device ? */
		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
			res = write_bbt(nd, buf, td, md, chipsel);
			if (res < 0)
				return res;
		}

		/* Write the mirror bad block table to the device ? */
		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
			res = write_bbt(nd, buf, md, td, chipsel);
			if (res < 0)
				return res;
		}
	}
	return 0;
}

/**
 * nand_update_bbt - [NAND Interface] update bad block table(s)
 * @nd:		nand device structure
 * @offs:	the offset of the newly marked block
 *
 * The function updates the bad block table(s)
*/
int nand_update_bbt(nand_t *nd, u64 offs)
{
	int len, res = 0, writeops = 0;
	int chip, chipsel;
	u8 *buf;
	struct nand_bbt_descr *td = &bbt_main_descr;
	struct nand_bbt_descr *md = &bbt_mirror_descr;

	if (!nd->bbt || !td)
		return -1;

	len = (nd->blk_count >> 2);
	/* Allocate a temporary buffer for one eraseblock incl. oob */
	len = nd->page_size * nd->ppb;
	len += nd->ppb * nd->oob_size;
	buf = malloc(len);
	if (!buf) {
		return -2;
	}

	writeops = md != NULL ? 0x03 : 0x01;

	/* Do we have a bbt per chip ? */
	if (td->options & NAND_BBT_PERCHIP) {
		chip = 0;
		chipsel = chip;
	} else {
		chip = 0;
		chipsel = -1;
	}

	td->version[chip]++;
	if (md)
		md->version[chip]++;

	/* Write the bad block table to the device ? */
	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
		res = write_bbt(nd, buf, td, md, chipsel);
		if (res < 0)
			goto out;
	}
	/* Write the mirror bad block table to the device ? */
	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
		res = write_bbt(nd, buf, md, td, chipsel);
	}

 out:
	free(buf);
	return res;
}

/**
 * mark_bbt_regions - [GENERIC] mark the bad block table regions
 * @nd:		nand device structure
 * @td:		bad block table descriptor
 *
 * The bad block table regions are marked as "bad" to prevent
 * accidental erasures / writes. The regions are identified by
 * the mark 0x02.
*/
static void mark_bbt_region(nand_t *nd, struct nand_bbt_descr *td)
{
	int i, j, chips, block, nrblocks, update;
	u8 oldval, newval;


	chips = 1;
	nrblocks = nd->blk_count;
	

	for (i = 0; i < chips; i++) {
		if ((td->options & NAND_BBT_ABSPAGE) ||
		    !(td->options & NAND_BBT_WRITE)) {
			if (td->pages[i] == -1)
				continue;
			block = td->pages[i] / nd->ppb;
			block <<= 1;
			oldval = nd->bbt[(block >> 3)];
			newval = oldval | (0x2 << (block & 0x06));
			nd->bbt[(block >> 3)] = newval;
			if ((oldval != newval) && td->reserved_block_code)
				nand_update_bbt(nd, td->pages[i] * nd->page_size);
			continue;
		}
		update = 0;
		if (td->options & NAND_BBT_LASTBLOCK)
			block = ((i + 1) * nrblocks) - td->maxblocks;
		else
			block = i * nrblocks;
		block <<= 1;
		for (j = 0; j < td->maxblocks; j++) {
			oldval = nd->bbt[(block >> 3)];
			newval = oldval | (0x2 << (block & 0x06));
			nd->bbt[(block >> 3)] = newval;
			if (oldval != newval)
				update = 1;
			block += 2;
		}
		/* If we want reserved blocks to be recorded to flash, and some
		   new ones have been marked, then we need to update the stored
		   bbts.  This should only happen once. */
		if (update && td->reserved_block_code)
			nand_update_bbt(nd, ((block - 2) >> 1) * nd->page_size * nd->ppb);
	}
}

/**
 * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
 * @nd:		nand device structure
 * @bd:		descriptor for the good/bad block search pattern
 *
 * The function checks, if a bad block table(s) is/are already
 * available. If not it scans the device for manufacturer
 * marked good / bad blocks and writes the bad block table(s) to
 * the selected place.
 *
 * The bad block table memory is allocated here. It must be freed
 * by calling the nand_free_bbt function.
 *
*/
int nand_scan_bbt(nand_t *nd)
{
	
	int len, res = 0;
	u8 *buf;
	struct nand_bbt_descr *td = &bbt_main_descr;
	struct nand_bbt_descr *md = &bbt_mirror_descr;
		
	/* Allocate a temporary buffer for one eraseblock incl. oob */
	len = (nd->page_size * nd->ppb);
	len += (nd->ppb) * nd->oob_size;
	buf = malloc(len);
	if (!buf) {
		return -1;
	}
	/* Search the bad block table using a pattern in oob */
	res = search_read_bbts(nd, buf, td, md);
	
	if (res)
		res = check_create(nd, buf, 0); //jason

	/* Prevent the bbt regions from erasing / writing */
	mark_bbt_region(nd, td);
	if (md)
		mark_bbt_region(nd, md);

	free(buf);
	return res;
}



/**
 * nand_isbad_bbt - [NAND Interface] Check if a block is bad
 * @nd:	nand device structure
 * @nrblk:	offset in the device
 * @allowbbt:	allow access to bad block table region
 *
*/
u8 nand_isbad_bbt(nand_t *nd, u32 nrblk, int allowbbt)
{

	int block;
	u8 res;

	/* Get block number * 2 */
	block = nrblk << 1;
	res = (nd->bbt[block >> 3] >> (block & 0x06)) & 0x03;


	switch ((int)res) {
	case 0x00:
		return 0;
	case 0x01:
		return 1;
	case 0x02:
		return allowbbt ? 0 : 1;
	}
	return 1;
}

/**
 * nand_default_block_markbad - [DEFAULT] mark a block bad
 * @nd:		nand device structure
 * @nrblk:	offset from device start
 *
 * This is the default implementation, which can be overridden by
 * a hardware specific driver.
*/
int nand_bbt_markbad(nand_t *nd, u32 nrblk)
{
	int ret;
	
	nd->bbt[nrblk >> 2] |= 0x01 << ((nrblk & 0x03) << 1);
	
	ret = nand_update_bbt(nd, 0); /* ofs not used */
	
	return ret;
}

⌨️ 快捷键说明

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