aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_bbt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/nand_bbt.c')
-rw-r--r--drivers/mtd/nand/nand_bbt.c103
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. */
1093static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; 1119static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
1094 1120
1095static struct nand_bbt_descr smallpage_memorybased = {
1096 .options = NAND_BBT_SCAN2NDPAGE,
1097 .offs = 5,
1098 .len = 1,
1099 .pattern = scan_ff_pattern
1100};
1101
1102static struct nand_bbt_descr largepage_memorybased = {
1103 .options = 0,
1104 .offs = 0,
1105 .len = 2,
1106 .pattern = scan_ff_pattern
1107};
1108
1109static struct nand_bbt_descr smallpage_flashbased = { 1121static 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
1116static struct nand_bbt_descr largepage_flashbased = { 1128static 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 */
1185static 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}