aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Cernekee <cernekee@gmail.com>2010-05-04 23:58:10 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-05-13 20:56:12 -0400
commitb60b08b02ca8d9575985ae6711bd656dd67e9039 (patch)
tree9178d2431c98688c2d4665b6e79c12fba0bf768b
parent426c457a3216fac74e3d44dd39729b0689f4c7ab (diff)
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>
-rw-r--r--drivers/mtd/nand/nand_base.c15
-rw-r--r--drivers/mtd/nand/nand_bbt.c3
-rw-r--r--include/linux/mtd/nand.h2
3 files changed, 20 insertions, 0 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 85891dcc27ad..4a7b86423ee9 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -347,6 +347,9 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
347 struct nand_chip *chip = mtd->priv; 347 struct nand_chip *chip = mtd->priv;
348 u16 bad; 348 u16 bad;
349 349
350 if (chip->options & NAND_BB_LAST_PAGE)
351 ofs += mtd->erasesize - mtd->writesize;
352
350 page = (int)(ofs >> chip->page_shift) & chip->pagemask; 353 page = (int)(ofs >> chip->page_shift) & chip->pagemask;
351 354
352 if (getchip) { 355 if (getchip) {
@@ -396,6 +399,9 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
396 uint8_t buf[2] = { 0, 0 }; 399 uint8_t buf[2] = { 0, 0 };
397 int block, ret; 400 int block, ret;
398 401
402 if (chip->options & NAND_BB_LAST_PAGE)
403 ofs += mtd->erasesize - mtd->writesize;
404
399 /* Get block number */ 405 /* Get block number */
400 block = (int)(ofs >> chip->bbt_erase_shift); 406 block = (int)(ofs >> chip->bbt_erase_shift);
401 if (chip->bbt) 407 if (chip->bbt)
@@ -2933,6 +2939,15 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2933 if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) 2939 if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
2934 chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; 2940 chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
2935 2941
2942 /*
2943 * Bad block marker is stored in the last page of each block
2944 * on Samsung and Hynix MLC devices
2945 */
2946 if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
2947 (*maf_id == NAND_MFR_SAMSUNG ||
2948 *maf_id == NAND_MFR_HYNIX))
2949 chip->options |= NAND_BB_LAST_PAGE;
2950
2936 /* Check for AND chips with 4 page planes */ 2951 /* Check for AND chips with 4 page planes */
2937 if (chip->options & NAND_4PAGE_ARRAY) 2952 if (chip->options & NAND_4PAGE_ARRAY)
2938 chip->erase_cmd = multi_erase_cmd; 2953 chip->erase_cmd = multi_erase_cmd;
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 387c45c366fe..ad97c0ce73b2 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -432,6 +432,9 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
432 from = (loff_t)startblock << (this->bbt_erase_shift - 1); 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 for (i = startblock; i < numblocks;) { 438 for (i = startblock; i < numblocks;) {
436 int ret; 439 int ret;
437 440
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 50f3aa00a452..a81b185e23a7 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -181,6 +181,8 @@ typedef enum {
181#define NAND_NO_READRDY 0x00000100 181#define NAND_NO_READRDY 0x00000100
182/* Chip does not allow subpage writes */ 182/* Chip does not allow subpage writes */
183#define NAND_NO_SUBPAGE_WRITE 0x00000200 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/* Device is one of 'new' xD cards that expose fake nand command set */ 187/* Device is one of 'new' xD cards that expose fake nand command set */
186#define NAND_BROKEN_XD 0x00000400 188#define NAND_BROKEN_XD 0x00000400