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

📄 nand_bbt.c

📁 freescale atk source code
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *  drivers/mtd/nand_bbt.c
 *
 *  Overview:
 *   Bad block table support for the NAND driver
 *
 *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
 *
 * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Description:
 *
 * When nand_scan_bbt is called, then it tries to find the bad block table
 * depending on the options in the bbt descriptor(s). If a bbt is found
 * then the contents are read and the memory based bbt is created. If a
 * mirrored bbt is selected then the mirror is searched too and the
 * versions are compared. If the mirror has a greater version number
 * than the mirror bbt is used to build the memory based bbt.
 * If the tables are not versioned, then we "or" the bad block information.
 * If one of the bbt's is out of date or does not exist it is (re)created.
 * If no bbt exists at all then the device is scanned for factory marked
 * good / bad blocks and the bad block tables are created.
 *
 * For manufacturer created bbts like the one found on M-SYS DOC devices
 * the bbt is searched and read but never created
 *
 * The autogenerated bad block table is located in the last good blocks
 * of the device. The table is mirrored, so it can be updated eventually.
 * The table is marked in the oob area with an ident pattern and a version
 * number which indicates which of both tables is more up to date.
 *
 * The table uses 2 bits per block
 * 11b: 	block is good
 * 00b: 	block is factory marked bad
 * 01b, 10b: 	block is marked bad due to wear
 *
 * The memory bad block table uses the following scheme:
 * 00b:		block is good
 * 01b:		block is marked bad due to wear
 * 10b:		block is reserved (to protect the bbt area)
 * 11b:		block is factory marked bad
 *
 * Multichip devices like DOC store the bad block info per floor.
 *
 * Following assumptions are made:
 * - bbts start at a page boundary, if autolocated on a block boundary
 * - the space necessary for a bbt in FLASH does not exceed a block boundary
 *
 */

#include "type.h"
#include "flash_lib.h"
#include "string.h"
#include "stdlib.h"
#include "nand_flash.h"
#include "nfc_base.h"

/* The number of bits used per block in the bbt on the device */
#define NAND_BBT_NRBITS_MSK	0x0000000F
#define NAND_BBT_1BIT		0x00000001
#define NAND_BBT_2BIT		0x00000002
#define NAND_BBT_4BIT		0x00000004
#define NAND_BBT_8BIT		0x00000008
/* The bad block table is in the last good block of the device */
#define	NAND_BBT_LASTBLOCK	0x00000010
/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_ABSPAGE	0x00000020
/* The bbt is at the given page, else we must scan for the bbt */
#define NAND_BBT_SEARCH		0x00000040
/* bbt is stored per chip on multichip devices */
#define NAND_BBT_PERCHIP	0x00000080
/* bbt has a version counter at offset veroffs */
#define NAND_BBT_VERSION	0x00000100
/* Create a bbt if none axists */
#define NAND_BBT_CREATE		0x00000200
/* Search good / bad pattern through all pages of a block */
#define NAND_BBT_SCANALLPAGES	0x00000400
/* Scan block empty during good / bad block scan */
#define NAND_BBT_SCANEMPTY	0x00000800
/* Write bbt if neccecary */
#define NAND_BBT_WRITE		0x00001000
/* Read and write back block contents when writing bbt */
#define NAND_BBT_SAVECONTENT	0x00002000
/* Search good / bad pattern on the first and the second page */
#define NAND_BBT_SCAN2NDPAGE	0x00004000

/* The maximum number of blocks to scan for a bbt */
#define NAND_BBT_SCAN_MAXBLOCKS	4
#define NAND_MAX_CHIPS		8

#define min(a, b)  (((a) < (b)) ? (a) : (b))

/**
 * struct nand_bbt_descr - bad block table descriptor
 * @options:	options for this descriptor
 * @pages:	the page(s) where we find the bbt, used with option BBT_ABSPAGE
 *		when bbt is searched, then we store the found bbts pages here.
 *		Its an array and supports up to 8 chips now
 * @offs:	offset of the pattern in the oob area of the page
 * @veroffs:	offset of the bbt version counter in the oob are of the page
 * @version:	version read from the bbt page during scan
 * @len:	length of the pattern, if 0 no pattern check is performed
 * @maxblocks:	maximum number of blocks to search for a bbt. This number of
 *		blocks is reserved at the end of the device where the tables are
 *		written.
 * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
 *              bad) block in the stored bbt
 * @pattern:	pattern to identify bad block table or factory marked good /
 *		bad blocks, can be NULL, if len = 0
 *
 * Descriptor for the bad block table marker and the descriptor for the
 * pattern which identifies good and bad blocks. The assumption is made
 * that the pattern and the version count are always located in the oob area
 * of the first block.
 */
struct nand_bbt_descr {
	int	options;
	int	pages[NAND_MAX_CHIPS];
	int	offs;
	int	veroffs;
	u8	version[NAND_MAX_CHIPS];
	int	len;
	int	maxblocks;
	int	reserved_block_code;
	u8	*pattern;
};

/* Generic flash bbt decriptors
*/
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };

static struct nand_bbt_descr bbt_main_descr = {
	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
	.offs =	0,
	.len = 4,
	.veroffs = 4,
	.maxblocks = 4,
	.pattern = bbt_pattern
};

static struct nand_bbt_descr bbt_mirror_descr = {
	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
	.offs =	0,
	.len = 4,
	.veroffs = 4,
	.maxblocks = 4,
	.pattern = mirror_pattern
};

/**
 * check_pattern - [GENERIC] check if a pattern is in the buffer
 * @buf:	the buffer to search
 * @len:	the length of buffer to search
 * @paglen:	the pagelength
 * @td:		search pattern descriptor
 *
 * Check for a pattern at the given place. Used to search bad block
 * tables and good / bad block identifiers.
 * If the SCAN_EMPTY option is set then check, if all bytes except the
 * pattern area contain 0xff
 *
*/
static int check_pattern(u8 *buf, int len, int paglen, struct nand_bbt_descr *td)
{
	int i, end = 0;
	u8 *p = buf;

	end = paglen + td->offs;
	if (td->options & NAND_BBT_SCANEMPTY) {
		for (i = 0; i < end; i++) {
			if (p[i] != 0xff)
				return -1;
		}
	}
	p += end;

	/* Compare the pattern */
	for (i = 0; i < td->len; i++) {
		if (p[i] != td->pattern[i])
			return -1;
	}

	if (td->options & NAND_BBT_SCANEMPTY) {
		p += td->len;
		end += td->len;
		for (i = end; i < len; i++) {
			if (*p++ != 0xff)
				return -1;
		}
	}
	return 0;
}

/**
 * read_bbt - [GENERIC] Read the bad block table starting from page
 * @nd:	    nand  device structure
 * @buf:	temporary buffer
 * @page:	the starting page
 * @num:	the number of bbt descriptors to read
 * @bits:	number of bits per block
 * @offs:	offset in the memory table
 * @reserved_block_code:	Pattern to identify reserved blocks
 *
 * Read the bad block table starting from page.
 *
 */
static int read_bbt(nand_t *nd, u8 *buf, int page, int num,
		    int bits, int offs, int reserved_block_code)
{
	int res, i, j, act = 0;
	u32 retlen, len, totlen;
	u64 from;
	u8 msk = (u8) ((1 << bits) - 1);

	totlen = (num * bits) >> 3;
	from = ((u64) page) * nd->page_size;

	while (totlen) {
		len = min(totlen, (u32) (nd->page_size * nd->ppb));

		res = nand_read((u32)from,(u32)buf,len,NULL);
		
		if (res < 0) {
			if (retlen != len) {
				return res;
			}
		}

		/* Analyse data */
		for (i = 0; i < len; i++) {
			u8 dat = buf[i];
			for (j = 0; j < 8; j += bits, act += 2) {
				u8 tmp = (dat >> j) & msk;
				if (tmp == msk)
					continue;
				if (reserved_block_code && (tmp == reserved_block_code)) {
					nd->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
					continue;
				}
				/* Leave it for now, if its matured we can move this
				 * message to nand_DEBUG_LEVEL0 */
				
				/* Factory marked bad or worn out ? */
				if (tmp == 0)
					nd->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
				else
					nd->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
			}
		}
		totlen -= len;
		from += len;
	}
	return 0;
}
/**
 * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
 * @nd:		nand device structure
 * @buf:	temporary buffer
 * @td:		descriptor for the bad block table
 * @chip:	read the table for a specific chip, -1 read all chips.
 *		Applies only if NAND_BBT_PERCHIP option is set
 *
 * Read the bad block table for all chips starting at a given page
 * We assume that the bbt bits are in consecutive order.
*/
static int read_abs_bbt(nand_t *nd, u8 *buf, struct nand_bbt_descr *td, int chip)
{
	int res = 0, i;
	int bits;

	bits = td->options & NAND_BBT_NRBITS_MSK;
	if (td->options & NAND_BBT_PERCHIP) {
		int offs = 0;
		for (i = 0; i < 1; i++) {
			if (chip == -1 || chip == i)
				res = read_bbt (nd, buf, td->pages[i], nd->blk_count, bits, offs, td->reserved_block_code);
			if (res)
				return res;
			offs += (nd->blk_count >> 2);
		}
	} else {
		res = read_bbt (nd, buf, td->pages[0], nd->blk_count, bits, 0, td->reserved_block_code);
		if (res)
			return res;
	}
	return 0;
}
/*
 * Scan read raw data from flash
 */
static int scan_read_raw(nand_t *nd, u8 *buf, u64 offs,
			 u32 len)
{
	nand_read ((u32)offs, (u32)buf, (u32)len,NULL);
	copy_spare(nd,(char *)&buf[len],0,nd->oob_size,1);
	return 0;
}

/*
 * Scan write data with oob to flash
 */
static int scan_write_bbt(nand_t *nd, u64 offs, u32 len,
			  u8 *buf, u8 *oob)
{
	/* write with user oob */
	copy_spare(nd,(char*)&buf[len],0,nd->oob_size,0);
	nand_write((u32)offs,(u32)buf,(u32)len,FILE_FORMAT_OPS,NULL);
	
	return 0;
}

/**
 * create_bbt - [GENERIC] Create a bad block table by scanning the device
 * @nd:		nand device structure
 * @buf:	temporary buffer
 * @bd:		descriptor for the good/bad block search pattern
 * @chip:	create the table for a specific chip, -1 read all chips.
 *		Applies only if NAND_BBT_PERCHIP option is set
 *
 * Create a bad block table by scanning the device
 * for the given good/bad block identify pattern
 */
static int create_bbt(nand_t *nd, u8 *buf,struct nand_bbt_descr *bd, int chip)
{
	int i, numblocks;
	int startblock;
	
	startblock = 0;
	numblocks = (nd->blk_count << 1);

	for (i = startblock; i < numblocks;) {
		int ret;

		ret = nand_block_is_good(i >> 1);

		if (ret < 0)
			return ret;

		if (!ret) {
			nd->bbt[i >> 3] |= 0x03 << (i & 0x6);
		}

		i += 2;
	}
	return 0;
}

/**
 * search_bbt - [GENERIC] scan the device for a specific bad block table
 * @nd:		nand device structure
 * @buf:	temporary buffer
 * @td:		descriptor for the bad block table
 *
 * Read the bad block table by searching for a given ident pattern.
 * Search is preformed either from the beginning up or from the end of
 * the device downwards. The search starts always at the start of a
 * block.
 * If the option NAND_BBT_PERCHIP is given, each chip is searched
 * for a bbt, which contains the bad block information of this chip.
 * This is necessary to provide support for certain DOC devices.
 *
 * The bbt ident pattern resides in the oob area of the first page
 * in a block.
 */
static int search_bbt(nand_t *nd, u8 *buf, struct nand_bbt_descr *td)
{
	int i, chips;
	int bits, startblock, block, dir;
	int scanlen = nd->page_size + nd->oob_size;
	int bbtblocks;

	/* Search direction top -> down ? */
	if (td->options & NAND_BBT_LASTBLOCK) {
		startblock = nd->blk_count - 1;
		dir = -1;
	} else {
		startblock = 0;
		dir = 1;
	}

	chips = 1;
	bbtblocks = nd->blk_count;
	

	/* Number of bits for each erase block in the bbt */
	bits = td->options & NAND_BBT_NRBITS_MSK;

	for (i = 0; i < chips; i++) {
		/* Reset version information */
		td->version[i] = 0;
		td->pages[i] = -1;
		/* Scan the maximum number of blocks */
		for (block = 0; block < td->maxblocks; block++) {

			int actblock = startblock + dir * block;
			u64 offs = actblock * nd->page_size * nd->ppb ;

			/* Read first page */
			scan_read_raw(nd, buf, offs, nd->page_size);
			if (!check_pattern(buf, scanlen, nd->page_size, td)) {
				td->pages[i] = actblock * nd->ppb ;
				if (td->options & NAND_BBT_VERSION) {
					td->version[i] = buf[nd->page_size + td->veroffs];
				}
				break;
			}
		}
		startblock += nd->blk_count;
	}

	return 0;
}

/**
 * search_read_bbts - [GENERIC] scan the device for bad block table(s)
 * @nd:		nand device structure
 * @buf:	temporary buffer
 * @td:		descriptor for the bad block table
 * @md:		descriptor for the bad block table mirror
 *
 * Search and read the bad block table(s)
*/
static int search_read_bbts(nand_t *nd, u8 * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
{
	/* Search the primary table */
	search_bbt(nd, buf, td);

	/* Search the mirror table */
	if (md)
		search_bbt(nd, buf, md);

	/* Force result check */
	return 1;
}

/**
 * write_bbt - [GENERIC] (Re)write the bad block table
 *
 * @nd:		nand device structure
 * @buf:	temporary buffer
 * @td:		descriptor for the bad block table
 * @md:		descriptor for the bad block table mirror
 * @chipsel:	selector for a specific chip, -1 for all
 *
 * (Re)write the bad block table
 *
*/
static int write_bbt(nand_t *nd, u8 *buf,
		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,

⌨️ 快捷键说明

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