drivers: mtd: nand: base: Add support for Hardware ECC for check bad block

Leverage linux code to support hardware ECC interface
to verify nand bad block.

Signed-off-by: Dinesh Maniyam <dinesh.maniyam@intel.com>
This commit is contained in:
Dinesh Maniyam 2025-02-27 00:18:28 +08:00 committed by Michael Trimarchi
parent 7ed5c15a83
commit 597fe4098d
2 changed files with 56 additions and 24 deletions

View file

@ -306,6 +306,35 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
}
/*
* nand_bbm_get_next_page - Get the next page for bad block markers
* @chip: The NAND chip
* @page: First page to start checking for bad block marker usage
*
* Returns an integer that corresponds to the page offset within a block, for
* a page that is used to store bad block markers. If no more pages are
* available, -EINVAL is returned.
*/
int nand_bbm_get_next_page(struct nand_chip *chip, int page)
{
struct mtd_info *mtd = nand_to_mtd(chip);
int last_page = ((mtd->erasesize - mtd->writesize) >>
chip->page_shift) & chip->pagemask;
unsigned int bbm_flags = NAND_BBM_FIRSTPAGE | NAND_BBM_SECONDPAGE
| NAND_BBM_LASTPAGE;
if (page == 0 && !(chip->options & bbm_flags))
return 0;
if (page == 0 && chip->options & NAND_BBM_FIRSTPAGE)
return 0;
if (page <= 1 && chip->options & NAND_BBM_SECONDPAGE)
return 1;
if (page <= last_page && chip->options & NAND_BBM_LASTPAGE)
return last_page;
return -EINVAL;
}
/**
* nand_block_bad - [DEFAULT] Read bad block marker from the chip
* @mtd: MTD device structure
@ -315,40 +344,32 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
*/
static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)
{
int page, res = 0, i = 0;
struct nand_chip *chip = mtd_to_nand(mtd);
u16 bad;
int first_page, page_offset;
int res;
u8 bad;
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
first_page = (int)(ofs >> chip->page_shift) & chip->pagemask;
page_offset = nand_bbm_get_next_page(chip, 0);
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
while (page_offset >= 0) {
res = chip->ecc.read_oob(mtd, chip, first_page + page_offset);
if (res < 0)
return res;
do {
if (chip->options & NAND_BUSWIDTH_16) {
chip->cmdfunc(mtd, NAND_CMD_READOOB,
chip->badblockpos & 0xFE, page);
bad = cpu_to_le16(chip->read_word(mtd));
if (chip->badblockpos & 0x1)
bad >>= 8;
else
bad &= 0xFF;
} else {
chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos,
page);
bad = chip->read_byte(mtd);
}
bad = chip->oob_poi[chip->badblockpos];
if (likely(chip->badblockbits == 8))
res = bad != 0xFF;
else
res = hweight8(bad) < chip->badblockbits;
ofs += mtd->writesize;
page = (int)(ofs >> chip->page_shift) & chip->pagemask;
i++;
} while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE));
if (res)
return res;
return res;
page_offset = nand_bbm_get_next_page(chip, page_offset + 1);
}
return 0;
}
/**

View file

@ -131,6 +131,17 @@ void nand_wait_ready(struct mtd_info *mtd);
#define NAND_DATA_IFACE_CHECK_ONLY -1
/*
* There are different places where the manufacturer stores the factory bad
* block markers.
*
* Position within the block: Each of these pages needs to be checked for a
* bad block marking pattern.
*/
#define NAND_BBM_FIRSTPAGE BIT(24)
#define NAND_BBM_SECONDPAGE BIT(25)
#define NAND_BBM_LASTPAGE BIT(26)
/*
* Constants for ECC_MODES
*/