📄 nand_bbt.c
字号:
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 + -