diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 14 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 127 |
2 files changed, 86 insertions, 55 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index bd697909db53..c2901bd126f9 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -2963,6 +2963,15 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | |||
2963 | *maf_id == NAND_MFR_MICRON)) | 2963 | *maf_id == NAND_MFR_MICRON)) |
2964 | chip->options |= NAND_BBT_SCAN2NDPAGE; | 2964 | chip->options |= NAND_BBT_SCAN2NDPAGE; |
2965 | 2965 | ||
2966 | /* | ||
2967 | * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 | ||
2968 | */ | ||
2969 | if (!(busw & NAND_BUSWIDTH_16) && | ||
2970 | *maf_id == NAND_MFR_STMICRO && | ||
2971 | mtd->writesize == 2048) { | ||
2972 | chip->options |= NAND_BBT_SCANBYTE1AND6; | ||
2973 | chip->badblockpos = 0; | ||
2974 | } | ||
2966 | 2975 | ||
2967 | /* Check for AND chips with 4 page planes */ | 2976 | /* Check for AND chips with 4 page planes */ |
2968 | if (chip->options & NAND_4PAGE_ARRAY) | 2977 | if (chip->options & NAND_4PAGE_ARRAY) |
@@ -3322,6 +3331,11 @@ void nand_release(struct mtd_info *mtd) | |||
3322 | kfree(chip->bbt); | 3331 | kfree(chip->bbt); |
3323 | if (!(chip->options & NAND_OWN_BUFFERS)) | 3332 | if (!(chip->options & NAND_OWN_BUFFERS)) |
3324 | kfree(chip->buffers); | 3333 | kfree(chip->buffers); |
3334 | |||
3335 | /* Free bad block descriptor memory */ | ||
3336 | if (chip->badblock_pattern && chip->badblock_pattern->options | ||
3337 | & NAND_BBT_DYNAMICSTRUCT) | ||
3338 | kfree(chip->badblock_pattern); | ||
3325 | } | 3339 | } |
3326 | 3340 | ||
3327 | EXPORT_SYMBOL_GPL(nand_lock); | 3341 | EXPORT_SYMBOL_GPL(nand_lock); |
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ec1700eaf198..469de17107e5 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -93,6 +93,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc | |||
93 | return -1; | 93 | return -1; |
94 | } | 94 | } |
95 | 95 | ||
96 | /* Check both positions 1 and 6 for pattern? */ | ||
97 | if (td->options & NAND_BBT_SCANBYTE1AND6) { | ||
98 | if (td->options & NAND_BBT_SCANEMPTY) { | ||
99 | p += td->len; | ||
100 | end += NAND_SMALL_BADBLOCK_POS - td->offs; | ||
101 | /* Check region between positions 1 and 6 */ | ||
102 | for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; | ||
103 | i++) { | ||
104 | if (*p++ != 0xff) | ||
105 | return -1; | ||
106 | } | ||
107 | } | ||
108 | else { | ||
109 | p += NAND_SMALL_BADBLOCK_POS - td->offs; | ||
110 | } | ||
111 | /* Compare the pattern */ | ||
112 | for (i = 0; i < td->len; i++) { | ||
113 | if (p[i] != td->pattern[i]) | ||
114 | return -1; | ||
115 | } | ||
116 | } | ||
117 | |||
96 | if (td->options & NAND_BBT_SCANEMPTY) { | 118 | if (td->options & NAND_BBT_SCANEMPTY) { |
97 | p += td->len; | 119 | p += td->len; |
98 | end += td->len; | 120 | end += td->len; |
@@ -124,6 +146,13 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) | |||
124 | if (p[td->offs + i] != td->pattern[i]) | 146 | if (p[td->offs + i] != td->pattern[i]) |
125 | return -1; | 147 | return -1; |
126 | } | 148 | } |
149 | /* Need to check location 1 AND 6? */ | ||
150 | if (td->options & NAND_BBT_SCANBYTE1AND6) { | ||
151 | for (i = 0; i < td->len; i++) { | ||
152 | if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) | ||
153 | return -1; | ||
154 | } | ||
155 | } | ||
127 | return 0; | 156 | return 0; |
128 | } | 157 | } |
129 | 158 | ||
@@ -397,12 +426,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
397 | 426 | ||
398 | if (bd->options & NAND_BBT_SCANALLPAGES) | 427 | if (bd->options & NAND_BBT_SCANALLPAGES) |
399 | len = 1 << (this->bbt_erase_shift - this->page_shift); | 428 | len = 1 << (this->bbt_erase_shift - this->page_shift); |
400 | else { | 429 | else if (bd->options & NAND_BBT_SCAN2NDPAGE) |
401 | if (bd->options & NAND_BBT_SCAN2NDPAGE) | 430 | len = 2; |
402 | len = 2; | 431 | else |
403 | else | 432 | len = 1; |
404 | len = 1; | ||
405 | } | ||
406 | 433 | ||
407 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { | 434 | if (!(bd->options & NAND_BBT_SCANEMPTY)) { |
408 | /* We need only read few bytes from the OOB area */ | 435 | /* We need only read few bytes from the OOB area */ |
@@ -1092,41 +1119,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) | |||
1092 | * while scanning a device for factory marked good / bad blocks. */ | 1119 | * while scanning a device for factory marked good / bad blocks. */ |
1093 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; | 1120 | static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; |
1094 | 1121 | ||
1095 | static struct nand_bbt_descr smallpage_memorybased = { | ||
1096 | .options = 0, | ||
1097 | .offs = NAND_SMALL_BADBLOCK_POS, | ||
1098 | .len = 1, | ||
1099 | .pattern = scan_ff_pattern | ||
1100 | }; | ||
1101 | |||
1102 | static struct nand_bbt_descr smallpage_scan2nd_memorybased = { | ||
1103 | .options = NAND_BBT_SCAN2NDPAGE, | ||
1104 | .offs = NAND_SMALL_BADBLOCK_POS, | ||
1105 | .len = 2, | ||
1106 | .pattern = scan_ff_pattern | ||
1107 | }; | ||
1108 | |||
1109 | static struct nand_bbt_descr largepage_memorybased = { | ||
1110 | .options = 0, | ||
1111 | .offs = NAND_LARGE_BADBLOCK_POS, | ||
1112 | .len = 1, | ||
1113 | .pattern = scan_ff_pattern | ||
1114 | }; | ||
1115 | |||
1116 | static struct nand_bbt_descr largepage_scan2nd_memorybased = { | ||
1117 | .options = NAND_BBT_SCAN2NDPAGE, | ||
1118 | .offs = NAND_LARGE_BADBLOCK_POS, | ||
1119 | .len = 2, | ||
1120 | .pattern = scan_ff_pattern | ||
1121 | }; | ||
1122 | |||
1123 | static struct nand_bbt_descr lastpage_memorybased = { | ||
1124 | .options = NAND_BBT_SCANLASTPAGE, | ||
1125 | .offs = 0, | ||
1126 | .len = 1, | ||
1127 | .pattern = scan_ff_pattern | ||
1128 | }; | ||
1129 | |||
1130 | static struct nand_bbt_descr smallpage_flashbased = { | 1122 | static struct nand_bbt_descr smallpage_flashbased = { |
1131 | .options = NAND_BBT_SCAN2NDPAGE, | 1123 | .options = NAND_BBT_SCAN2NDPAGE, |
1132 | .offs = NAND_SMALL_BADBLOCK_POS, | 1124 | .offs = NAND_SMALL_BADBLOCK_POS, |
@@ -1175,6 +1167,43 @@ static struct nand_bbt_descr bbt_mirror_descr = { | |||
1175 | .pattern = mirror_pattern | 1167 | .pattern = mirror_pattern |
1176 | }; | 1168 | }; |
1177 | 1169 | ||
1170 | #define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ | ||
1171 | NAND_BBT_SCANBYTE1AND6) | ||
1172 | /** | ||
1173 | * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure | ||
1174 | * @this: NAND chip to create descriptor for | ||
1175 | * | ||
1176 | * This function allocates and initializes a nand_bbt_descr for BBM detection | ||
1177 | * based on the properties of "this". The new descriptor is stored in | ||
1178 | * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when | ||
1179 | * passed to this function. | ||
1180 | * | ||
1181 | * TODO: Handle other flags, replace other static structs | ||
1182 | * (e.g. handle NAND_BBT_FLASH for flash-based BBT, | ||
1183 | * replace smallpage_flashbased) | ||
1184 | * | ||
1185 | */ | ||
1186 | static int nand_create_default_bbt_descr(struct nand_chip *this) | ||
1187 | { | ||
1188 | struct nand_bbt_descr *bd; | ||
1189 | if (this->badblock_pattern) { | ||
1190 | printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); | ||
1191 | return -EINVAL; | ||
1192 | } | ||
1193 | bd = kzalloc(sizeof(*bd), GFP_KERNEL); | ||
1194 | if (!bd) { | ||
1195 | printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); | ||
1196 | return -ENOMEM; | ||
1197 | } | ||
1198 | bd->options = this->options & BBT_SCAN_OPTIONS; | ||
1199 | bd->offs = this->badblockpos; | ||
1200 | bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; | ||
1201 | bd->pattern = scan_ff_pattern; | ||
1202 | bd->options |= NAND_BBT_DYNAMICSTRUCT; | ||
1203 | this->badblock_pattern = bd; | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1178 | /** | 1207 | /** |
1179 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device | 1208 | * nand_default_bbt - [NAND Interface] Select a default bad block table for the device |
1180 | * @mtd: MTD device structure | 1209 | * @mtd: MTD device structure |
@@ -1217,20 +1246,8 @@ int nand_default_bbt(struct mtd_info *mtd) | |||
1217 | } else { | 1246 | } else { |
1218 | this->bbt_td = NULL; | 1247 | this->bbt_td = NULL; |
1219 | this->bbt_md = NULL; | 1248 | this->bbt_md = NULL; |
1220 | if (!this->badblock_pattern) { | 1249 | if (!this->badblock_pattern) |
1221 | if (this->options & NAND_BBT_SCANLASTPAGE) | 1250 | nand_create_default_bbt_descr(this); |
1222 | this->badblock_pattern = &lastpage_memorybased; | ||
1223 | else if (this->options & NAND_BBT_SCAN2NDPAGE) | ||
1224 | this->badblock_pattern = this->badblockpos == | ||
1225 | NAND_SMALL_BADBLOCK_POS ? | ||
1226 | &smallpage_scan2nd_memorybased : | ||
1227 | &largepage_scan2nd_memorybased; | ||
1228 | else | ||
1229 | this->badblock_pattern = this->badblockpos == | ||
1230 | NAND_SMALL_BADBLOCK_POS ? | ||
1231 | &smallpage_memorybased : | ||
1232 | &largepage_memorybased; | ||
1233 | } | ||
1234 | } | 1251 | } |
1235 | return nand_scan_bbt(mtd, this->badblock_pattern); | 1252 | return nand_scan_bbt(mtd, this->badblock_pattern); |
1236 | } | 1253 | } |