diff options
author | Brian Norris <norris@broadcom.com> | 2010-07-13 15:13:00 -0700 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-08-02 09:08:52 +0100 |
commit | c7b28e25cb9beb943aead770ff14551b55fa8c79 (patch) | |
tree | e51adab05413609c059daa827b454c66f1a207b7 /drivers/mtd | |
parent | 78d1022439e501bc4a1a32bfaad5a321b8a9d5d6 (diff) | |
download | linux-3.10-c7b28e25cb9beb943aead770ff14551b55fa8c79.tar.gz linux-3.10-c7b28e25cb9beb943aead770ff14551b55fa8c79.tar.bz2 linux-3.10-c7b28e25cb9beb943aead770ff14551b55fa8c79.zip |
mtd: nand: refactor BB marker detection
Some level of support for various scanning locations was already built in,
but this required clean-up. First, BB marker location cannot be determined
_only_ by the page size. Instead, I implemented some heuristic detection
based on data sheets from various manufacturers (all found in
nand_base.c:nand_get_flash_type()).
Second, once these options were identified, they were not handled properly
by nand_bbt.c:nand_default_bbt(). I updated the static nand_bbt_desc structs
to reflect the need for more combinations of detection. The memory allocation
here probably needs to be done dynamically in the very near future (see next
patches).
Signed-off-by: Brian Norris <norris@broadcom.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 24 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 45 |
2 files changed, 58 insertions, 11 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e6cf9aefef1..bd697909db5 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2920,9 +2920,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; /* Set the bad block position */ - chip->badblockpos = mtd->writesize > 512 ? - NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; - chip->badblockbits = 8; + if (!(busw & NAND_BUSWIDTH_16) && (*maf_id == NAND_MFR_STMICRO || + (*maf_id == NAND_MFR_SAMSUNG && + mtd->writesize == 512) || + *maf_id == NAND_MFR_AMD)) + chip->badblockpos = NAND_SMALL_BADBLOCK_POS; + else + chip->badblockpos = NAND_LARGE_BADBLOCK_POS; + /* Get chip options, preserve non chip based options */ chip->options &= ~NAND_CHIPOPTIONS_MSK; @@ -2941,12 +2946,23 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Bad block marker is stored in the last page of each block - * on Samsung and Hynix MLC devices + * on Samsung and Hynix MLC devices; stored in first two pages + * of each block on Micron devices with 2KiB pages and on + * SLC Samsung, Hynix, and AMD/Spansion. All others scan only + * the first page. */ if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX)) chip->options |= NAND_BBT_SCANLASTPAGE; + else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + (*maf_id == NAND_MFR_SAMSUNG || + *maf_id == NAND_MFR_HYNIX || + *maf_id == NAND_MFR_AMD)) || + (mtd->writesize == 2048 && + *maf_id == NAND_MFR_MICRON)) + chip->options |= NAND_BBT_SCAN2NDPAGE; + /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 71d83be24ff..ec1700eaf19 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1093,29 +1093,50 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static struct nand_bbt_descr smallpage_memorybased = { - .options = NAND_BBT_SCAN2NDPAGE, - .offs = 5, + .options = 0, + .offs = NAND_SMALL_BADBLOCK_POS, .len = 1, .pattern = scan_ff_pattern }; +static struct nand_bbt_descr smallpage_scan2nd_memorybased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = NAND_SMALL_BADBLOCK_POS, + .len = 2, + .pattern = scan_ff_pattern +}; + static struct nand_bbt_descr largepage_memorybased = { .options = 0, - .offs = 0, + .offs = NAND_LARGE_BADBLOCK_POS, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_bbt_descr largepage_scan2nd_memorybased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = NAND_LARGE_BADBLOCK_POS, .len = 2, .pattern = scan_ff_pattern }; +static struct nand_bbt_descr lastpage_memorybased = { + .options = NAND_BBT_SCANLASTPAGE, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern +}; + static struct nand_bbt_descr smallpage_flashbased = { .options = NAND_BBT_SCAN2NDPAGE, - .offs = 5, + .offs = NAND_SMALL_BADBLOCK_POS, .len = 1, .pattern = scan_ff_pattern }; static struct nand_bbt_descr largepage_flashbased = { .options = NAND_BBT_SCAN2NDPAGE, - .offs = 0, + .offs = NAND_LARGE_BADBLOCK_POS, .len = 2, .pattern = scan_ff_pattern }; @@ -1197,8 +1218,18 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = NULL; this->bbt_md = NULL; if (!this->badblock_pattern) { - this->badblock_pattern = (mtd->writesize > 512) ? - &largepage_memorybased : &smallpage_memorybased; + if (this->options & NAND_BBT_SCANLASTPAGE) + this->badblock_pattern = &lastpage_memorybased; + else if (this->options & NAND_BBT_SCAN2NDPAGE) + this->badblock_pattern = this->badblockpos == + NAND_SMALL_BADBLOCK_POS ? + &smallpage_scan2nd_memorybased : + &largepage_scan2nd_memorybased; + else + this->badblock_pattern = this->badblockpos == + NAND_SMALL_BADBLOCK_POS ? + &smallpage_memorybased : + &largepage_memorybased; } } return nand_scan_bbt(mtd, this->badblock_pattern); |