From: Dinesh Maniyam Date: Wed, 26 Feb 2025 16:18:28 +0000 (+0800) Subject: drivers: mtd: nand: base: Add support for Hardware ECC for check bad block X-Git-Tag: v2025.07-rc1~18^2~32^2~5 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=597fe4098dabdd05c44ec1d68e990a61798cad38;p=pandora-u-boot.git 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 --- diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 1b65c6f6443..bb5460e0068 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -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; } /** diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 3bb0a3679f9..3e80b134063 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -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 */