mtd: rawnand: Support bad block markers in first, second or last page

Currently supported bad block marker positions within the block are:
* in first page only
* in last page only
* in first or second page

Some ESMT NANDs are known to have been shipped by the manufacturer
with bad block markers in the first or last page, instead of the
first or second page.

Also the datasheets for Cypress/Spansion/AMD NANDs claim that the
first, second *and* last page needs to be checked.

Therefore we make it possible to set NAND_BBM_FIRSTPAGE,
NAND_BBM_SECONDPAGE and NAND_BBM_LASTPAGE independently in any
combination.

To simplify the code, the logic to evaluate the flags is moved to a
a new function nand_bbm_get_next_page().

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Reviewed-by: Boris Brezillon <bbrezillon@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
Frieder Schrempf
2019-04-17 12:36:37 +00:00
committed by Miquel Raynal
parent bb5925480b
commit f90da7818b
3 changed files with 56 additions and 37 deletions

View File

@@ -416,11 +416,12 @@ static void read_abs_bbts(struct nand_chip *this, uint8_t *buf,
/* Scan a given block partially */
static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
loff_t offs, uint8_t *buf, int numpages)
loff_t offs, uint8_t *buf)
{
struct mtd_info *mtd = nand_to_mtd(this);
struct mtd_oob_ops ops;
int j, ret;
int ret, page_offset;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
@@ -428,12 +429,15 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
ops.datbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
for (j = 0; j < numpages; j++) {
page_offset = nand_bbm_get_next_page(this, 0);
while (page_offset >= 0) {
/*
* Read the full oob until read_oob is fixed to handle single
* byte reads for 16 bit buswidth.
*/
ret = mtd_read_oob(mtd, offs, &ops);
ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize),
&ops);
/* Ignore ECC errors when checking for BBM */
if (ret && !mtd_is_bitflip_or_eccerr(ret))
return ret;
@@ -441,8 +445,9 @@ static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
if (check_short_pattern(buf, bd))
return 1;
offs += mtd->writesize;
page_offset = nand_bbm_get_next_page(this, page_offset + 1);
}
return 0;
}
@@ -462,18 +467,11 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf,
{
u64 targetsize = nanddev_target_size(&this->base);
struct mtd_info *mtd = nand_to_mtd(this);
int i, numblocks, numpages;
int startblock;
int i, numblocks, startblock;
loff_t from;
pr_info("Scanning device for bad blocks\n");
if ((this->options & NAND_BBM_FIRSTPAGE) &&
(this->options & NAND_BBM_SECONDPAGE))
numpages = 2;
else
numpages = 1;
if (chip == -1) {
numblocks = mtd->size >> this->bbt_erase_shift;
startblock = 0;
@@ -490,15 +488,12 @@ static int create_bbt(struct nand_chip *this, uint8_t *buf,
from = (loff_t)startblock << this->bbt_erase_shift;
}
if (this->options & NAND_BBM_LASTPAGE)
from += mtd->erasesize - (mtd->writesize * numpages);
for (i = startblock; i < numblocks; i++) {
int ret;
BUG_ON(bd->options & NAND_BBT_NO_OOB);
ret = scan_block_fast(this, bd, from, buf, numpages);
ret = scan_block_fast(this, bd, from, buf);
if (ret < 0)
return ret;