diff options
Diffstat (limited to 'drivers/mtd/nand/nand_bbt.c')
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 103 |
1 files changed, 75 insertions, 28 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ad97c0ce73b..5fedf4a74f1 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -55,7 +55,6 @@ | |||
55 | #include <linux/mtd/mtd.h> | 55 | #include <linux/mtd/mtd.h> |
56 | #include <linux/mtd/nand.h> | 56 | #include <linux/mtd/nand.h> |
57 | #include <linux/mtd/nand_ecc.h> | 57 | #include <linux/mtd/nand_ecc.h> |
58 | #include <linux/mtd/compatmac.h> | ||
59 | #include <linux/bitops.h> | 58 | #include <linux/bitops.h> |
60 | #include <linux/delay.h> | 59 | #include <linux/delay.h> |
61 | #include <linux/vmalloc.h> | 60 | #include <linux/vmalloc.h> |
@@ -93,6 +92,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc | |||
93 | return -1; | 92 | return -1; |
94 | } | 93 | } |
95 | 94 | ||
95 | /* Check both positions 1 and 6 for pattern? */ | ||
96 | if (td->options & NAND_BBT_SCANBYTE1AND6) { | ||
97 | if (td->options & NAND_BBT_SCANEMPTY) { | ||
98 | p += td->len; | ||
99 | end += NAND_SMALL_BADBLOCK_POS - td->offs; | ||
100 | /* Check region between positions 1 and 6 */ | ||
101 | for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; | ||
102 | i++) { | ||
103 | if (*p++ != 0xff) | ||
104 | return -1; | ||
105 | } | ||
106 | } | ||
107 | else { | ||
108 | p += NAND_SMALL_BADBLOCK_POS - td->offs; | ||
109 | } | ||
110 | /* Compare the pattern */ | ||
111 | for (i = 0; i < td->len; i++) { | ||
112 | if (p[i] != td->pattern[i]) | ||
113 | return -1; | ||
114 | } | ||
115 | } | ||
116 | |||
96 | if (td->options & NAND_BBT_SCANEMPTY) { | 117 | if (td->options & NAND_BBT_SCANEMPTY) { |
97 | p += td->len; | 118 | p += td->len; |
98 | end += td->len; | 119 | end += td->len; |
@@ -124,6 +145,13 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) | |||
124 | if (p[td->offs + i] != td->pattern[i]) | 145 | if (p[td->offs + i] != td->pattern[i]) |
125 | return -1; | 146 | return -1; |
126 | } | 147 | } |
148 | /* Need to check location 1 AND 6? */ | ||
149 | if (td->options & NAND_BBT_SCANBYTE1AND6) { | ||
150 | for (i = 0; i < td->len; i++) { | ||
151 | if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) | ||
152 | return -1; | ||
153 | } | ||
154 | } | ||
127 | return 0; | 155 | return 0; |
128 | } | 156 | } |
129 | 157 | ||
@@ -397,12 +425,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
397 | 425 | ||
398 | if (bd->options & NAND_BBT_SCANALLPAGES) | 426 | if (bd->options & NAND_BBT_SCANALLPAGES) |
399 | len = 1 << (this->bbt_erase_shift - this->page_shift); | 427 | len = 1 << (this->bbt_erase_shift - this->page_shift); |
400 | else { | 428 | else if (bd->options & NAND_BBT_SCAN2NDPAGE) |
401 | if (bd->options & NAND_BBT_SCAN2NDPAGE) | 429 | len = 2; |
402 | len = 2; | 430 | else |
403 | else | 431 | len = 1; |
404 | len = 1; | ||
405 | } | ||
406 | 432 | ||
407 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { | 433 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
408 | /* We need only read few bytes from the OOB area */ | 434 | /* We need only read few bytes from the OOB area */ |
@@ -432,7 +458,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
432 | from = (loff_t)startblock << (this->bbt_erase_shift - 1); | 458 | from = (loff_t)startblock << (this->bbt_erase_shift - 1); |
433 | } | 459 | } |
434 | 460 | ||
435 | if (this->options & NAND_BB_LAST_PAGE) | 461 | if (this->options & NAND_BBT_SCANLASTPAGE) |
436 | from += mtd->erasesize - (mtd->writesize * len); | 462 | from += mtd->erasesize - (mtd->writesize * len); |
437 | 463 | ||
438 | for (i = startblock; i < numblocks;) { | 464 | for (i = startblock; i < numblocks;) { |
@@ -1092,30 +1118,16 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) | |||
1092 | * while scanning a device for factory marked good / bad blocks. */ | 1118 | * while scanning a device for factory marked good / bad blocks. */ |
1093 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 1119 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
1094 | 1120 | ||
1095 | static struct nand_bbt_descr smallpage_memorybased = { | ||
1096 | .options = NAND_BBT_SCAN2NDPAGE, | ||
1097 | .offs = 5, | ||
1098 | .len = 1, | ||
1099 | .pattern = scan_ff_pattern | ||
1100 | }; | ||
1101 | |||
1102 | static struct nand_bbt_descr largepage_memorybased = { | ||
1103 | .options = 0, | ||
1104 | .offs = 0, | ||
1105 | .len = 2, | ||
1106 | .pattern = scan_ff_pattern | ||
1107 | }; | ||
1108 | |||
1109 | static struct nand_bbt_descr smallpage_flashbased = { | 1121 | static struct nand_bbt_descr smallpage_flashbased = { |
1110 | .options = NAND_BBT_SCAN2NDPAGE, | 1122 | .options = NAND_BBT_SCAN2NDPAGE, |
1111 | .offs = 5, | 1123 | .offs = NAND_SMALL_BADBLOCK_POS, |
1112 | .len = 1, | 1124 | .len = 1, |
1113 | .pattern = scan_ff_pattern | 1125 | .pattern = scan_ff_pattern |
1114 | }; | 1126 | }; |
1115 | 1127 | ||
1116 | static struct nand_bbt_descr largepage_flashbased = { | 1128 | static struct nand_bbt_descr largepage_flashbased = { |
1117 | .options = NAND_BBT_SCAN2NDPAGE, | 1129 | .options = NAND_BBT_SCAN2NDPAGE, |
1118 | .offs = 0, | 1130 | .offs = NAND_LARGE_BADBLOCK_POS, |
1119 | .len = 2, | 1131 | .len = 2, |
1120 | .pattern = scan_ff_pattern | 1132 | .pattern = scan_ff_pattern |
1121 | }; | 1133 | }; |
@@ -1154,6 +1166,43 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1154 | .pattern = mirror_pattern | 1166 | .pattern = mirror_pattern |
1155 | }; | 1167 | }; |
1156 | 1168 | ||
1169 | #define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ | ||
1170 | NAND_BBT_SCANBYTE1AND6) | ||
1171 | /** | ||
1172 | * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure | ||
1173 | * @this: NAND chip to create descriptor for | ||
1174 | * | ||
1175 | * This function allocates and initializes a nand_bbt_descr for BBM detection | ||
1176 | * based on the properties of "this". The new descriptor is stored in | ||
1177 | * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when | ||
1178 | * passed to this function. | ||
1179 | * | ||
1180 | * TODO: Handle other flags, replace other static structs | ||
1181 | * (e.g. handle NAND_BBT_FLASH for flash-based BBT, | ||
1182 | * replace smallpage_flashbased) | ||
1183 | * | ||
1184 | */ | ||
1185 | static int nand_create_default_bbt_descr(struct nand_chip *this) | ||
1186 | { | ||
1187 | struct nand_bbt_descr *bd; | ||
1188 | if (this->badblock_pattern) { | ||
1189 | printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); | ||
1190 | return -EINVAL; | ||
1191 | } | ||
1192 | bd = kzalloc(sizeof(*bd), GFP_KERNEL); | ||
1193 | if (!bd) { | ||
1194 | printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); | ||
1195 | return -ENOMEM; | ||
1196 | } | ||
1197 | bd->options = this->options & BBT_SCAN_OPTIONS; | ||
1198 | bd->offs = this->badblockpos; | ||
1199 | bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; | ||
1200 | bd->pattern = scan_ff_pattern; | ||
1201 | bd->options |= NAND_BBT_DYNAMICSTRUCT; | ||
1202 | this->badblock_pattern = bd; | ||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1157 | /** | 1206 | /** |
1158 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device | 1207 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device |
1159 | * @mtd: MTD device structure | 1208 | * @mtd: MTD device structure |
@@ -1196,10 +1245,8 @@ int nand_default_bbt(struct mtd_info *mtd) | |||
1196 | } else { | 1245 | } else { |
1197 | this->bbt_td = NULL; | 1246 | this->bbt_td = NULL; |
1198 | this->bbt_md = NULL; | 1247 | this->bbt_md = NULL; |
1199 | if (!this->badblock_pattern) { | 1248 | if (!this->badblock_pattern) |
1200 | this->badblock_pattern = (mtd->writesize > 512) ? | 1249 | nand_create_default_bbt_descr(this); |
1201 | &largepage_memorybased : &smallpage_memorybased; | ||
1202 | } | ||
1203 | } | 1250 | } |
1204 | return nand_scan_bbt(mtd, this->badblock_pattern); | 1251 | return nand_scan_bbt(mtd, this->badblock_pattern); |
1205 | } | 1252 | } |