Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: nand: support alternate BB marker locations on MLC

This is a slightly modified version of a patch submitted last year by
Reuben Dowle <reuben.dowle@navico.com>. His original comments follow:

This patch adds support for some MLC NAND flashes that place the BB
marker in the LAST page of the bad block rather than the FIRST page used
for SLC NAND and other types of MLC nand.

Lifted from Samsung datasheet for K9LG8G08U0A (1Gbyte MLC NAND):
"
Identifying Initial Invalid Block(s)
All device locations are erased(FFh) except locations where the initial
invalid block(s) information is written prior to shipping. The initial
invalid block(s) status is defined by the 1st byte in the spare area.
Samsung makes sure that the last page of every initial invalid block has
non-FFh data at the column address of 2,048.
...
"

As far as I can tell, this is the same for all Samsung MLC nand, and in
fact the samsung bsp for the processor used in our project (s3c6410)
actually contained a hack similar to this patch but less portable to
enable use of their NAND parts. I discovered this problem when trying to
use a Micron NAND which does not used this layout - I wish samsung would
put their stuff in main-line to avoid this type of problem.

Currently this patch causes all MLC nand with manufacturer codes from
Samsung and ST(Numonyx) to use this alternative location, since these
are the manufactures that I know of that use this layout.

Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>

authored by

Kevin Cernekee and committed by
David Woodhouse
b60b08b0 426c457a

+20
+15
drivers/mtd/nand/nand_base.c
··· 347 347 struct nand_chip *chip = mtd->priv; 348 348 u16 bad; 349 349 350 + if (chip->options & NAND_BB_LAST_PAGE) 351 + ofs += mtd->erasesize - mtd->writesize; 352 + 350 353 page = (int)(ofs >> chip->page_shift) & chip->pagemask; 351 354 352 355 if (getchip) { ··· 398 395 struct nand_chip *chip = mtd->priv; 399 396 uint8_t buf[2] = { 0, 0 }; 400 397 int block, ret; 398 + 399 + if (chip->options & NAND_BB_LAST_PAGE) 400 + ofs += mtd->erasesize - mtd->writesize; 401 401 402 402 /* Get block number */ 403 403 block = (int)(ofs >> chip->bbt_erase_shift); ··· 2938 2932 */ 2939 2933 if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) 2940 2934 chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; 2935 + 2936 + /* 2937 + * Bad block marker is stored in the last page of each block 2938 + * on Samsung and Hynix MLC devices 2939 + */ 2940 + if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && 2941 + (*maf_id == NAND_MFR_SAMSUNG || 2942 + *maf_id == NAND_MFR_HYNIX)) 2943 + chip->options |= NAND_BB_LAST_PAGE; 2941 2944 2942 2945 /* Check for AND chips with 4 page planes */ 2943 2946 if (chip->options & NAND_4PAGE_ARRAY)
+3
drivers/mtd/nand/nand_bbt.c
··· 432 432 from = (loff_t)startblock << (this->bbt_erase_shift - 1); 433 433 } 434 434 435 + if (this->options & NAND_BB_LAST_PAGE) 436 + from += mtd->erasesize - (mtd->writesize * len); 437 + 435 438 for (i = startblock; i < numblocks;) { 436 439 int ret; 437 440
+2
include/linux/mtd/nand.h
··· 181 181 #define NAND_NO_READRDY 0x00000100 182 182 /* Chip does not allow subpage writes */ 183 183 #define NAND_NO_SUBPAGE_WRITE 0x00000200 184 + /* Chip stores bad block marker on the last page of the eraseblock */ 185 + #define NAND_BB_LAST_PAGE 0x00000400 184 186 185 187 /* Device is one of 'new' xD cards that expose fake nand command set */ 186 188 #define NAND_BROKEN_XD 0x00000400