os/nandboot-R2_0_4/mtd/nand_bbt.c

Go to the documentation of this file.
00001 /*
00002  * Taken from  drivers/mtd/nand/nand_bbt.c, from Linux 2.6.16 (IR2_6_16-9)
00003  * Modified to run outside Linux.
00004  * #if 0'd to remove non-essential functionality
00005  *
00006  *  drivers/mtd/nand_bbt.c
00007  *
00008  *  Overview:
00009  *   Bad block table support for the NAND driver
00010  *
00011  *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
00012  *
00013  * $Id: nand_bbt.c,v 1.1.1.1 2008/11/27 20:04:00 elphel Exp $
00014  *
00015  * This program is free software; you can redistribute it and/or modify
00016  * it under the terms of the GNU General Public License version 2 as
00017  * published by the Free Software Foundation.
00018  *
00019  * Description:
00020  *
00021  * When nand_scan_bbt is called, then it tries to find the bad block table
00022  * depending on the options in the bbt descriptor(s). If a bbt is found
00023  * then the contents are read and the memory based bbt is created. If a
00024  * mirrored bbt is selected then the mirror is searched too and the
00025  * versions are compared. If the mirror has a greater version number
00026  * than the mirror bbt is used to build the memory based bbt.
00027  * If the tables are not versioned, then we "or" the bad block information.
00028  * If one of the bbt's is out of date or does not exist it is (re)created.
00029  * If no bbt exists at all then the device is scanned for factory marked
00030  * good / bad blocks and the bad block tables are created.
00031  *
00032  * For manufacturer created bbts like the one found on M-SYS DOC devices
00033  * the bbt is searched and read but never created
00034  *
00035  * The autogenerated bad block table is located in the last good blocks
00036  * of the device. The table is mirrored, so it can be updated eventually.
00037  * The table is marked in the oob area with an ident pattern and a version
00038  * number which indicates which of both tables is more up to date.
00039  *
00040  * The table uses 2 bits per block
00041  * 11b:         block is good
00042  * 00b:         block is factory marked bad
00043  * 01b, 10b:    block is marked bad due to wear
00044  *
00045  * The memory bad block table uses the following scheme:
00046  * 00b:         block is good
00047  * 01b:         block is marked bad due to wear
00048  * 10b:         block is reserved (to protect the bbt area)
00049  * 11b:         block is factory marked bad
00050  *
00051  * Multichip devices like DOC store the bad block info per floor.
00052  *
00053  * Following assumptions are made:
00054  * - bbts start at a page boundary, if autolocated on a block boundary
00055  * - the space neccecary for a bbt in FLASH does not exceed a block boundary
00056  *
00057  */
00058 
00059 #include <linux/errno.h>
00060 #include <linux/types.h>
00061 #include <linux/bitops.h>
00062 
00063 #include "mtd.h"
00064 #include "nand.h"
00065 #include "nand_ecc.h"
00066 #include "delay.h"
00067 
00068 // we don't have kmalloc() here, so use top RAM memory for BBT buffer
00069 
00070 #define BBT_LEN_1       1024
00071 //#define BBT_LEN_2     135168
00072 #define BBT_LEN_2       (512 * 1024)
00073 //char bbt_b_1[BBT_LEN_1];
00074 #define bbt_b_1 ((void *)(0xc4000000 - BBT_LEN_2 - 0x02000000 - BBT_LEN_1))
00075 #define bbt_b_2 ((void *)(0xc4000000 - BBT_LEN_2 - 0x02000000))
00076 
00077 #if 0
00078 #include <linux/slab.h>
00079 #endif
00080 //#include <linux/types.h>
00081 #if 0
00082 #include <linux/mtd/mtd.h>
00083 #include <linux/mtd/nand.h>
00084 #include <linux/mtd/nand_ecc.h>
00085 #include <linux/mtd/compatmac.h>
00086 #include <linux/bitops.h>
00087 #include <linux/delay.h>
00088 #endif
00089 
00090 #include <linux/errno.h>
00091 //#include "mtd_nand.h"
00092 //#include "nand.h"
00093 //#include "nand_ecc.h"
00094 //#include "delay.h"
00095 
00096 #define dprintf if(0)printf
00097 
00098 #if 0
00099 #include <linux/delay.h>
00100 #include <linux/errno.h>
00101 #include <linux/sched.h>
00102 #include <linux/slab.h>
00103 #include <linux/types.h>
00104 #endif
00105 
00106 
00107 //#include <axisrfl/mtd.h>
00108 //#include <axisrfl/mtd_nand.h>
00109 //#include <axisrfl/nand_ecc.h>
00110 
00111 //#include <axisrfl/funcs.h>
00112 
00113 //#include <cyg/hal/hardware.h>
00114 //#include <bitops.h>
00115 
00116 //#include <hal_intr.h>         /* HAL_DELAY_US */
00117 //#include <string.h> /* memcpy */
00118 
00119 #if 0
00120 #include <linux/mtd/compatmac.h>
00121 #include <linux/interrupt.h>
00122 #include <linux/bitops.h>
00123 #include <asm/io.h>
00124 
00125 #ifdef CONFIG_MTD_PARTITIONS
00126 #include <linux/mtd/partitions.h>
00127 
00128 #endif
00129 #endif
00130 
00131 //#include <cyg/hal/hal_intr.h>  /* for hal_delay_us */
00132 
00133 //#include <axisrfl/linuxerr.h> /* must be after all eCos files */
00134 
00135 //#define udelay(x) HAL_DELAY_US(x)
00136 #undef nop
00137 #define nop() __asm__("nop")
00138 /* only used for ndelay(100) so junk argument */
00139 //#define ndelay(x) do { nop(); nop(); nop(); nop(); nop(); nop(); nop(); nop(); } while (0)
00140 
00141 #define GPIO_SYNC 0
00142 
00143 #undef DEBUG /* from mtd.h */
00144 #define DEBUG(n, args...) do { } while(0)
00145 
00146 #define D(x) x
00147 
00148 
00162 static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
00163 {
00164         int i, end = 0;
00165         uint8_t *p = buf;
00166 
00167         end = paglen + td->offs;
00168         if (td->options & NAND_BBT_SCANEMPTY) {
00169                 for (i = 0; i < end; i++) {
00170                         if (p[i] != 0xff)
00171                                 return -1;
00172                 }
00173         }
00174         p += end;
00175 
00176         /* Compare the pattern */
00177         for (i = 0; i < td->len; i++) {
00178                 if (p[i] != td->pattern[i])
00179                         return -1;
00180         }
00181 
00182         if (td->options & NAND_BBT_SCANEMPTY) {
00183                 p += td->len;
00184                 end += td->len;
00185                 for (i = end; i < len; i++) {
00186                         if (*p++ != 0xff)
00187                                 return -1;
00188                 }
00189         }
00190         return 0;
00191 }
00192 
00203 static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
00204 {
00205         int i;
00206         uint8_t *p = buf;
00207 
00208         /* Compare the pattern */
00209         for (i = 0; i < td->len; i++) {
00210                 if (p[td->offs + i] != td->pattern[i])
00211                         return -1;
00212         }
00213         return 0;
00214 }
00215 
00229 /*
00230 size_t min(size_t a, size_t b) {
00231         if(a < b)
00232                 return a;
00233         return b;
00234 }
00235 */
00236 static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
00237         int bits, int offs, int reserved_block_code)
00238 {
00239         int res, i, j, act = 0;
00240         struct nand_chip *this = mtd->priv;
00241         size_t retlen, len, totlen;
00242         loff_t from;
00243         uint8_t msk = (uint8_t) ((1 << bits) - 1);
00244 
00245         totlen = (num * bits) >> 3;
00246         from = ((loff_t)page) << this->page_shift;
00247 
00248         while (totlen) {
00249                 len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
00250                 res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
00251                 if (res < 0) {
00252                         if (retlen != len) {
00253                                 //printf ("nand_bbt: Error reading bad block table\n");
00254                                 return res;
00255                         }
00256                         //printf ("nand_bbt: ECC error while reading bad block table\n");
00257                 }
00258 
00259                 /* Analyse data */
00260                 for (i = 0; i < len; i++) {
00261                         uint8_t dat = buf[i];
00262                         for (j = 0; j < 8; j += bits, act += 2) {
00263                                 uint8_t tmp = (dat >> j) & msk;
00264                                 if (tmp == msk)
00265                                         continue;
00266                                 if (reserved_block_code &&
00267                                     (tmp == reserved_block_code)) {
00268                                         //printf ( "nand_read_bbt: Reserved block at 0x%08x\n",
00269 //                                              ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
00270 puts("nand_read_bbt: Reserved block at ");
00271 putx(((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
00272 putnl();
00273                                         this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
00274                                         continue;
00275                                 }
00276                                 /* Leave it for now, if its matured we can move this
00277                                  * message to MTD_DEBUG_LEVEL0 */
00278                                 //printf ( "nand_read_bbt: Bad block at 0x%08x\n",
00279 //                                      ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
00280 puts("nand_read_bbt: Bad block at ");
00281 putx(((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
00282 putnl();
00283                                 /* Factory marked bad or worn out ? */
00284                                 if (tmp == 0)
00285                                         this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
00286                                 else
00287                                         this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
00288                         }
00289                 }
00290                 totlen -= len;
00291                 from += len;
00292         }
00293         return 0;
00294 }
00295 
00307 static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
00308 {
00309         struct nand_chip *this = mtd->priv;
00310         int res = 0, i;
00311         int bits;
00312 
00313         bits = td->options & NAND_BBT_NRBITS_MSK;
00314         if (td->options & NAND_BBT_PERCHIP) {
00315                 int offs = 0;
00316                 for (i = 0; i < this->numchips; i++) {
00317                         if (chip == -1 || chip == i)
00318                                 res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);
00319                         if (res)
00320                                 return res;
00321                         offs += this->chipsize >> (this->bbt_erase_shift + 2);
00322                 }
00323         } else {
00324                 res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);
00325                 if (res)
00326                         return res;
00327         }
00328         return 0;
00329 }
00330 
00342 static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td,
00343         struct nand_bbt_descr *md)
00344 {
00345         struct nand_chip *this = mtd->priv;
00346 
00347         /* Read the primary version, if available */
00348         if (td->options & NAND_BBT_VERSION) {
00349                 nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
00350                 td->version[0] = buf[mtd->oobblock + td->veroffs];
00351                 //printf ( "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
00352         }
00353 
00354         /* Read the mirror version, if available */
00355         if (md && (md->options & NAND_BBT_VERSION)) {
00356                 nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
00357                 md->version[0] = buf[mtd->oobblock + md->veroffs];
00358                 //printf ( "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
00359         }
00360 
00361         return 1;
00362 }
00363 
00375 static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
00376 {
00377         struct nand_chip *this = mtd->priv;
00378         int i, j, numblocks, len, scanlen;
00379         int startblock;
00380         loff_t from;
00381         size_t readlen, ooblen;
00382 
00383         //printf ( "Scanning device for bad blocks\n");
00384 
00385         if (bd->options & NAND_BBT_SCANALLPAGES)
00386                 len = 1 << (this->bbt_erase_shift - this->page_shift);
00387         else {
00388                 if (bd->options & NAND_BBT_SCAN2NDPAGE)
00389                         len = 2;
00390                 else
00391                         len = 1;
00392         }
00393 
00394         if (!(bd->options & NAND_BBT_SCANEMPTY)) {
00395                 /* We need only read few bytes from the OOB area */
00396                 scanlen = ooblen = 0;
00397                 readlen = bd->len;
00398         } else {
00399                 /* Full page content should be read */
00400                 scanlen = mtd->oobblock + mtd->oobsize;
00401                 readlen = len * mtd->oobblock;
00402                 ooblen = len * mtd->oobsize;
00403         }
00404 
00405         if (chip == -1) {
00406                 /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
00407                  * makes shifting and masking less painful */
00408                 numblocks = mtd->size >> (this->bbt_erase_shift - 1);
00409                 startblock = 0;
00410                 from = 0;
00411         } else {
00412                 if (chip >= this->numchips) {
00413                         //printf ( "create_bbt(): chipnr (%d) > available chips (%d)\n",
00414 //                              chip + 1, this->numchips);
00415                         return -1;
00416                 }
00417                 numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
00418                 startblock = chip * numblocks;
00419                 numblocks += startblock;
00420                 from = startblock << (this->bbt_erase_shift - 1);
00421         }
00422 
00423         for (i = startblock; i < numblocks;) {
00424                 int ret;
00425 
00426 /*
00427                 if (bd->options & NAND_BBT_SCANEMPTY)
00428                         if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
00429                                 return ret;
00430 */
00431                 for (j = 0; j < len; j++) {
00432 //                      if (!(bd->options & NAND_BBT_SCANEMPTY)) {
00433                                 size_t retlen;
00434 
00435                                 /* Read the full oob until read_oob is fixed to
00436                                  * handle single byte reads for 16 bit buswidth */
00437                                 ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
00438                                                         mtd->oobsize, &retlen, buf);
00439                                 if (ret)
00440                                         return ret;
00441 
00442                                 if (check_short_pattern (buf, bd)) {
00443                                         this->bbt[i >> 3] |= 0x03 << (i & 0x6);
00444                                         //printf ( "1 Bad eraseblock %d at 0x%08x\n",
00445 //                                              i >> 1, (unsigned int) from);
00446                                         break;
00447                                 }
00448 /*
00449                         } else {
00450                                 if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
00451                                         this->bbt[i >> 3] |= 0x03 << (i & 0x6);
00452                                         //printf ( "2 Bad eraseblock %d at 0x%08x\n",
00453                                                 i >> 1, (unsigned int) from);
00454                                         break;
00455                                 }
00456                         }
00457 */
00458                 }
00459                 i += 2;
00460                 from += (1 << this->bbt_erase_shift);
00461         }
00462         return 0;
00463 }
00464 
00482 static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
00483 {
00484         struct nand_chip *this = mtd->priv;
00485         int i, chips;
00486         int bits, startblock, block, dir;
00487         int scanlen = mtd->oobblock + mtd->oobsize;
00488         int bbtblocks;
00489 
00490 puts("search_bbt() ...1");
00491 puts("; mtd->size == ");
00492 putx(mtd->size);
00493 putnl();
00494         /* Search direction top -> down ? */
00495         if (td->options & NAND_BBT_LASTBLOCK) {
00496                 startblock = (mtd->size >> this->bbt_erase_shift) -1;
00497                 dir = -1;
00498         } else {
00499                 startblock = 0;
00500                 dir = 1;
00501         }
00502 
00503         /* Do we have a bbt per chip ? */
00504         if (td->options & NAND_BBT_PERCHIP) {
00505                 chips = this->numchips;
00506                 bbtblocks = this->chipsize >> this->bbt_erase_shift;
00507                 startblock &= bbtblocks - 1;
00508         } else {
00509                 chips = 1;
00510                 bbtblocks = mtd->size >> this->bbt_erase_shift;
00511         }
00512 
00513 puts("search_bbt() ...2; ");
00514 puts("maxblocks: ");
00515 putx(td->maxblocks);
00516 puts("; mtd->size == ");
00517 putx(mtd->size);
00518 putnl();
00519         /* Number of bits for each erase block in the bbt */
00520         bits = td->options & NAND_BBT_NRBITS_MSK;
00521 
00522         for (i = 0; i < chips; i++) {
00523                 /* Reset version information */
00524                 td->version[i] = 0;
00525                 td->pages[i] = -1;
00526                 /* Scan the maximum number of blocks */
00527                 for (block = 0; block < td->maxblocks; block++) {
00528                         int actblock = startblock + dir * block;
00529                         /* Read first page */
00530                         nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
00531 puts("Block: ");
00532 putx(actblock);
00533 putnl();
00534                         if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
00535                                 td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
00536                                 if (td->options & NAND_BBT_VERSION) {
00537                                         td->version[i] = buf[mtd->oobblock + td->veroffs];
00538                                 }
00539                                 break;
00540                         }
00541                 }
00542                 startblock += this->chipsize >> this->bbt_erase_shift;
00543         }
00544         /* Check, if we found a bbt for each requested chip */
00545 puts("Check, if we found a bbt for each requested chip");
00546 putnl();
00548         for (i = 0; i < chips; i++) {
00549                 if (td->pages[i] == -1)
00550                         puts("Bad block table not found...");
00551                         //printf ( "Bad block table not found for chip %d\n", i);
00552                 else {
00553                         puts("Bad block table found at page");
00554                         putx(td->pages[i]);
00555                         puts(", version ");
00556                         putx(td->version[i]);
00557                 }
00558                 putnl();
00559                         //printf ( "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
00560         }
00561 //*/
00562         return 0;
00563 }
00564 
00574 static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
00575         struct nand_bbt_descr *td, struct nand_bbt_descr *md)
00576 {
00577 puts("search_read_bbts() search primary table; mtd->size == ");
00578 putx(mtd->size);
00579 putnl();
00580         /* Search the primary table */
00581         search_bbt (mtd, buf, td);
00582 
00583         /* Search the mirror table */
00584         if (md) {
00585 puts("search_read_bbts() search mirror table");
00586 putnl();
00587                 search_bbt (mtd, buf, md);
00588         }
00589 
00590         /* Force result check */
00591         return 1;
00592 }
00593 
00594 
00607 static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
00608         struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
00609 {
00610         struct nand_chip *this = mtd->priv;
00611         struct nand_oobinfo oobinfo;
00612         struct erase_info einfo;
00613         int i, j, res, chip = 0;
00614         int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
00615         int nrchips, bbtoffs, pageoffs;
00616         uint8_t msk[4];
00617         uint8_t rcode = td->reserved_block_code;
00618         size_t retlen, len = 0;
00619         loff_t to;
00620 
00621 return 0;
00622         if (!rcode)
00623                 rcode = 0xff;
00624         /* Write bad block table per chip rather than per device ? */
00625         if (td->options & NAND_BBT_PERCHIP) {
00626                 numblocks = (int) (this->chipsize >> this->bbt_erase_shift);
00627                 /* Full device write or specific chip ? */
00628                 if (chipsel == -1) {
00629                         nrchips = this->numchips;
00630                 } else {
00631                         nrchips = chipsel + 1;
00632                         chip = chipsel;
00633                 }
00634         } else {
00635                 numblocks = (int) (mtd->size >> this->bbt_erase_shift);
00636                 nrchips = 1;
00637         }
00638 
00639         /* Loop through the chips */
00640         for (; chip < nrchips; chip++) {
00641 
00642                 /* There was already a version of the table, reuse the page
00643                  * This applies for absolute placement too, as we have the
00644                  * page nr. in td->pages.
00645                  */
00646                 if (td->pages[chip] != -1) {
00647                         page = td->pages[chip];
00648                         goto write;
00649                 }
00650 
00651                 /* Automatic placement of the bad block table */
00652                 /* Search direction top -> down ? */
00653                 if (td->options & NAND_BBT_LASTBLOCK) {
00654                         startblock = numblocks * (chip + 1) - 1;
00655                         dir = -1;
00656                 } else {
00657                         startblock = chip * numblocks;
00658                         dir = 1;
00659                 }
00660 
00661                 for (i = 0; i < td->maxblocks; i++) {
00662                         int block = startblock + dir * i;
00663                         /* Check, if the block is bad */
00664                         switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
00665                         case 0x01:
00666                         case 0x03:
00667                                 continue;
00668                         }
00669                         page = block << (this->bbt_erase_shift - this->page_shift);
00670                         /* Check, if the block is used by the mirror table */
00671                         if (!md || md->pages[chip] != page)
00672                                 goto write;
00673                 }
00674                 //printf ( "No space left to write bad block table\n");
00675                 return -1;
00676 write:
00677 
00678                 /* Set up shift count and masks for the flash table */
00679                 bits = td->options & NAND_BBT_NRBITS_MSK;
00680                 switch (bits) {
00681                 case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
00682                 case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
00683                 case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
00684                 case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
00685                 default: return -1;
00686                 }
00687 
00688                 bbtoffs = chip * (numblocks >> 2);
00689 
00690                 to = ((loff_t) page) << this->page_shift;
00691 
00692                 memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
00693                 oobinfo.useecc = MTD_NANDECC_PLACEONLY;
00694 
00695                 /* Must we save the block contents ? */
00696                 if (td->options & NAND_BBT_SAVECONTENT) {
00697                         /* Make it block aligned */
00698                         to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
00699                         len = 1 << this->bbt_erase_shift;
00700                         res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
00701                         if (res < 0) {
00702                                 if (retlen != len) {
00703                                         //printf ( "nand_bbt: Error reading block for writing the bad block table\n");
00704                                         return res;
00705                                 }
00706                                 //printf ( "nand_bbt: ECC error while reading block for writing bad block table\n");
00707                         }
00708                         /* Calc the byte offset in the buffer */
00709                         pageoffs = page - (int)(to >> this->page_shift);
00710                         offs = pageoffs << this->page_shift;
00711                         /* Preset the bbt area with 0xff */
00712                         memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
00713                         /* Preset the bbt's oob area with 0xff */
00714                         memset (&buf[len + pageoffs * mtd->oobsize], 0xff,
00715                                 ((len >> this->page_shift) - pageoffs) * mtd->oobsize);
00716                         if (td->options & NAND_BBT_VERSION) {
00717                                 buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
00718                         }
00719                 } else {
00720                         /* Calc length */
00721                         len = (size_t) (numblocks >> sft);
00722                         /* Make it page aligned ! */
00723                         len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1);
00724                         /* Preset the buffer with 0xff */
00725                         memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
00726                         offs = 0;
00727                         /* Pattern is located in oob area of first page */
00728                         memcpy (&buf[len + td->offs], td->pattern, td->len);
00729                         if (td->options & NAND_BBT_VERSION) {
00730                                 buf[len + td->veroffs] = td->version[chip];
00731                         }
00732                 }
00733 
00734                 /* walk through the memory table */
00735                 for (i = 0; i < numblocks; ) {
00736                         uint8_t dat;
00737                         dat = this->bbt[bbtoffs + (i >> 2)];
00738                         for (j = 0; j < 4; j++ , i++) {
00739                                 int sftcnt = (i << (3 - sft)) & sftmsk;
00740                                 /* Do not store the reserved bbt blocks ! */
00741                                 buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
00742                                 dat >>= 2;
00743                         }
00744                 }
00745 
00746                 memset (&einfo, 0, sizeof (einfo));
00747                 einfo.mtd = mtd;
00748                 einfo.addr = (unsigned long) to;
00749                 einfo.len = 1 << this->bbt_erase_shift;
00750 //              res = nand_erase_nand (mtd, &einfo, 1);
00751                 if (res < 0) {
00752                         //printf ( "nand_bbt: Error during block erase: %d\n", res);
00753                         return res;
00754                 }
00755 
00756                 res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
00757                 if (res < 0) {
00758                         //printf ( "nand_bbt: Error while writing bad block table %d\n", res);
00759                         return res;
00760                 }
00761                 //printf ( "Bad block table written to 0x%08x, version 0x%02X\n",
00762 //                      (unsigned int) to, td->version[chip]);
00763 
00764                 /* Mark it as used */
00765                 td->pages[chip] = page;
00766         }
00767         return 0;
00768 }
00769 
00778 static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
00779 {
00780         struct nand_chip *this = mtd->priv;
00781 
00782         bd->options &= ~NAND_BBT_SCANEMPTY;
00783         return create_bbt (mtd, this->data_buf, bd, -1);
00784 }
00785 
00798 static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
00799 {
00800         int i, chips, writeops, chipsel, res;
00801         struct nand_chip *this = mtd->priv;
00802         struct nand_bbt_descr *td = this->bbt_td;
00803         struct nand_bbt_descr *md = this->bbt_md;
00804         struct nand_bbt_descr *rd, *rd2;
00805 
00806         /* Do we have a bbt per chip ? */
00807         if (td->options & NAND_BBT_PERCHIP)
00808                 chips = this->numchips;
00809         else
00810                 chips = 1;
00811 
00812         for (i = 0; i < chips; i++) {
00813                 writeops = 0;
00814                 rd = NULL;
00815                 rd2 = NULL;
00816                 /* Per chip or per device ? */
00817                 chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
00818                 /* Mirrored table avilable ? */
00819                 if (md) {
00820                         if (td->pages[i] == -1 && md->pages[i] == -1) {
00821                                 writeops = 0x03;
00822                                 goto create;
00823                         }
00824 
00825                         if (td->pages[i] == -1) {
00826                                 rd = md;
00827                                 td->version[i] = md->version[i];
00828                                 writeops = 1;
00829                                 goto writecheck;
00830                         }
00831 
00832                         if (md->pages[i] == -1) {
00833                                 rd = td;
00834                                 md->version[i] = td->version[i];
00835                                 writeops = 2;
00836                                 goto writecheck;
00837                         }
00838 
00839                         if (td->version[i] == md->version[i]) {
00840                                 rd = td;
00841                                 if (!(td->options & NAND_BBT_VERSION))
00842                                         rd2 = md;
00843                                 goto writecheck;
00844                         }
00845 
00846                         if (((int8_t) (td->version[i] - md->version[i])) > 0) {
00847                                 rd = td;
00848                                 md->version[i] = td->version[i];
00849                                 writeops = 2;
00850                         } else {
00851                                 rd = md;
00852                                 td->version[i] = md->version[i];
00853                                 writeops = 1;
00854                         }
00855 
00856                         goto writecheck;
00857 
00858                 } else {
00859                         if (td->pages[i] == -1) {
00860                                 writeops = 0x01;
00861                                 goto create;
00862                         }
00863                         rd = td;
00864                         goto writecheck;
00865                 }
00866 create:
00867                 /* Create the bad block table by scanning the device ? */
00868                 if (!(td->options & NAND_BBT_CREATE))
00869                         continue;
00870 
00871                 /* Create the table in memory by scanning the chip(s) */
00872                 create_bbt (mtd, buf, bd, chipsel);
00873 
00874                 td->version[i] = 1;
00875                 if (md)
00876                         md->version[i] = 1;
00877 writecheck:
00878                 /* read back first ? */
00879                 if (rd)
00880                         read_abs_bbt (mtd, buf, rd, chipsel);
00881                 /* If they weren't versioned, read both. */
00882                 if (rd2)
00883                         read_abs_bbt (mtd, buf, rd2, chipsel);
00884 
00885                 /* Write the bad block table to the device ? */
00886                 if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
00887                         res = write_bbt (mtd, buf, td, md, chipsel);
00888                         if (res < 0)
00889                                 return res;
00890                 }
00891 
00892                 /* Write the mirror bad block table to the device ? */
00893                 if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
00894                         res = write_bbt (mtd, buf, md, td, chipsel);
00895                         if (res < 0)
00896                                 return res;
00897                 }
00898         }
00899         return 0;
00900 }
00901 
00911 static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
00912 {
00913         struct nand_chip *this = mtd->priv;
00914         int i, j, chips, block, nrblocks, update;
00915         uint8_t oldval, newval;
00916 
00917         /* Do we have a bbt per chip ? */
00918         if (td->options & NAND_BBT_PERCHIP) {
00919                 chips = this->numchips;
00920                 nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
00921         } else {
00922                 chips = 1;
00923                 nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
00924         }
00925 
00926         for (i = 0; i < chips; i++) {
00927                 if ((td->options & NAND_BBT_ABSPAGE) ||
00928                     !(td->options & NAND_BBT_WRITE)) {
00929                         if (td->pages[i] == -1) continue;
00930                         block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
00931                         block <<= 1;
00932                         oldval = this->bbt[(block >> 3)];
00933                         newval = oldval | (0x2 << (block & 0x06));
00934                         this->bbt[(block >> 3)] = newval;
00935                         if ((oldval != newval) && td->reserved_block_code)
00936                                 nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
00937                         continue;
00938                 }
00939                 update = 0;
00940                 if (td->options & NAND_BBT_LASTBLOCK)
00941                         block = ((i + 1) * nrblocks) - td->maxblocks;
00942                 else
00943                         block = i * nrblocks;
00944                 block <<= 1;
00945                 for (j = 0; j < td->maxblocks; j++) {
00946                         oldval = this->bbt[(block >> 3)];
00947                         newval = oldval | (0x2 << (block & 0x06));
00948                         this->bbt[(block >> 3)] = newval;
00949                         if (oldval != newval) update = 1;
00950                         block += 2;
00951                 }
00952                 /* If we want reserved blocks to be recorded to flash, and some
00953                    new ones have been marked, then we need to update the stored
00954                    bbts.  This should only happen once. */
00955                 if (update && td->reserved_block_code)
00956                         nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
00957         }
00958 }
00959 
00974 int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
00975 {
00976         struct nand_chip *this = mtd->priv;
00977         int len, res = 0;
00978         uint8_t *buf;
00979         struct nand_bbt_descr *td = this->bbt_td;
00980         struct nand_bbt_descr *md = this->bbt_md;
00981 
00982 puts("scan_bbt()");
00983 puts("; mtd->size == ");
00984 putx(mtd->size);
00985 putnl();
00986         len = mtd->size >> (this->bbt_erase_shift + 2);
00987 puts("scan_bbt() ...01");
00988 puts("; mtd->size == ");
00989 putx(mtd->size);
00990 putnl();
00991         /* Allocate memory (2bit per block) */
00993 //      this->bbt = kmalloc (len, GFP_KERNEL);
00994         this->bbt = NULL;
00995 puts("len == ");
00996 putx(len);
00997 puts("; and BBT_LEN_1 == ");
00998 putx(BBT_LEN_1);
00999 putnl();
01000         if(len <= BBT_LEN_1)
01001                 this->bbt = bbt_b_1;
01002         if (!this->bbt) {
01003                 //printf ( "nand_scan_bbt: Out of memory\n");
01004 puts("scan_bbt() -ENOMEM ...1");
01005 putnl();
01006                 return -ENOMEM;
01007         }
01008         /* Clear the memory bad block table */
01009 puts("scan_bbt() ...02");
01010 puts("; mtd->size == ");
01011 putx(mtd->size);
01012 putnl();
01013         memset (this->bbt, 0x00, len);
01014 puts("scan_bbt() ...03");
01015 puts("; mtd->size == ");
01016 putx(mtd->size);
01017 putnl();
01018 
01019         /* If no primary table decriptor is given, scan the device
01020          * to build a memory based bad block table
01021          */
01022         if (!td) {
01023                 if ((res = nand_memory_bbt(mtd, bd))) {
01024                         //printf ( "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
01025 //                      kfree (this->bbt);
01026                         this->bbt = NULL;
01027                 }
01028 puts("scan_bbt() nand_memory_bbt()");
01029 putnl();
01030                 return res;
01031         }
01032 
01033 puts("scan_bbt() ...1");
01034 puts("; mtd->size == ");
01035 putx(mtd->size);
01036 putnl();
01037         /* Allocate a temporary buffer for one eraseblock incl. oob */
01038         len = (1 << this->bbt_erase_shift);
01039         len += (len >> this->page_shift) * mtd->oobsize;
01041 //      buf = kmalloc (len, GFP_KERNEL);
01042         buf = NULL;
01043         if(len <= BBT_LEN_2)
01044                 buf = bbt_b_2;
01045         if (!buf) {
01046                 //printf ( "nand_bbt: Out of memory\n");
01047 //              kfree (this->bbt);
01048                 this->bbt = NULL;
01049 puts("scan_bbt() -ENOMEM ...2");
01050 putnl();
01051                 return -ENOMEM;
01052         }
01053 
01054 puts("scan_bbt() ...2");
01055 puts("; mtd->size == ");
01056 putx(mtd->size);
01057 putnl();
01058         /* Is the bbt at a given page ? */
01059         if (td->options & NAND_BBT_ABSPAGE) {
01060 puts("scan_bbt() read_abs_bbts()");
01061 putnl();
01062                 res = read_abs_bbts (mtd, buf, td, md);
01063         } else {
01064 puts("scan_bbt() search_read_bbts(); mtd->size == ");
01065 putx(mtd->size);
01066 putnl();
01067                 /* Search the bad block table using a pattern in oob */
01068                 res = search_read_bbts (mtd, buf, td, md);
01069         }
01070 
01071         if (res)
01072                 res = check_create (mtd, buf, bd);
01073 
01074         /* Prevent the bbt regions from erasing / writing */
01075         mark_bbt_region (mtd, td);
01076         if (md)
01077                 mark_bbt_region (mtd, md);
01078 
01079 //      kfree (buf);
01080 puts("scan_bbt() ...3");
01081 putnl();
01082         return res;
01083 }
01084 
01085 
01093 int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
01094 {
01095         struct nand_chip *this = mtd->priv;
01096         int len, res = 0, writeops = 0;
01097         int chip, chipsel;
01098         uint8_t *buf;
01099         struct nand_bbt_descr *td = this->bbt_td;
01100         struct nand_bbt_descr *md = this->bbt_md;
01101 
01102         if (!this->bbt || !td)
01103                 return -1;
01104 
01105         len = mtd->size >> (this->bbt_erase_shift + 2);
01106         /* Allocate a temporary buffer for one eraseblock incl. oob */
01107         len = (1 << this->bbt_erase_shift);
01108         len += (len >> this->page_shift) * mtd->oobsize;
01110 //      buf = kmalloc (len, GFP_KERNEL);
01111         buf = NULL;
01112         if(len <= BBT_LEN_2)
01113                 buf = bbt_b_2;
01114         if (!buf) {
01115                 //printf ( "nand_update_bbt: Out of memory\n");
01116                 return -ENOMEM;
01117         }
01118 
01119         writeops = md != NULL ? 0x03 : 0x01;
01120 
01121         /* Do we have a bbt per chip ? */
01122         if (td->options & NAND_BBT_PERCHIP) {
01123                 chip = (int) (offs >> this->chip_shift);
01124                 chipsel = chip;
01125         } else {
01126                 chip = 0;
01127                 chipsel = -1;
01128         }
01129 
01130         td->version[chip]++;
01131         if (md)
01132                 md->version[chip]++;
01133 
01134         /* Write the bad block table to the device ? */
01135         if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
01136                 res = write_bbt (mtd, buf, td, md, chipsel);
01137                 if (res < 0)
01138                         goto out;
01139         }
01140         /* Write the mirror bad block table to the device ? */
01141         if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
01142                 res = write_bbt (mtd, buf, md, td, chipsel);
01143         }
01144 
01145 out:
01146 //      kfree (buf);
01147         return res;
01148 }
01149 
01150 /* Define some generic bad / good block scan pattern which are used
01151  * while scanning a device for factory marked good / bad blocks. */
01152 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
01153 
01154 static struct nand_bbt_descr smallpage_memorybased = {
01155         .options = NAND_BBT_SCAN2NDPAGE,
01156         .offs = 5,
01157         .len = 1,
01158         .pattern = scan_ff_pattern
01159 };
01160 
01161 static struct nand_bbt_descr largepage_memorybased = {
01162         .options = 0,
01163         .offs = 0,
01164         .len = 2,
01165         .pattern = scan_ff_pattern
01166 };
01167 
01168 static struct nand_bbt_descr smallpage_flashbased = {
01169         .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
01170         .offs = 5,
01171         .len = 1,
01172         .pattern = scan_ff_pattern
01173 };
01174 
01175 static struct nand_bbt_descr largepage_flashbased = {
01176         .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
01177         .offs = 0,
01178         .len = 2,
01179         .pattern = scan_ff_pattern
01180 };
01181 
01182 static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
01183 
01184 static struct nand_bbt_descr agand_flashbased = {
01185         .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
01186         .offs = 0x20,
01187         .len = 6,
01188         .pattern = scan_agand_pattern
01189 };
01190 
01191 /* Generic flash bbt decriptors
01192 */
01193 static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
01194 static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
01195 
01196 static struct nand_bbt_descr bbt_main_descr = {
01197         .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
01198                 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
01199         .offs = 8,
01200         .len = 4,
01201         .veroffs = 12,
01202         .maxblocks = 4,
01203         .pattern = bbt_pattern
01204 };
01205 
01206 static struct nand_bbt_descr bbt_mirror_descr = {
01207         .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
01208                 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
01209         .offs = 8,
01210         .len = 4,
01211         .veroffs = 12,
01212         .maxblocks = 4,
01213         .pattern = mirror_pattern
01214 };
01215 
01224 int nand_default_bbt (struct mtd_info *mtd)
01225 {
01226         struct nand_chip *this = mtd->priv;
01227 
01228         /* Default for AG-AND. We must use a flash based
01229          * bad block table as the devices have factory marked
01230          * _good_ blocks. Erasing those blocks leads to loss
01231          * of the good / bad information, so we _must_ store
01232          * this information in a good / bad table during
01233          * startup
01234         */
01235         if (this->options & NAND_IS_AND) {
01236                 /* Use the default pattern descriptors */
01237                 if (!this->bbt_td) {
01238                         this->bbt_td = &bbt_main_descr;
01239                         this->bbt_md = &bbt_mirror_descr;
01240                 }
01241                 this->options |= NAND_USE_FLASH_BBT;
01242                 return nand_scan_bbt (mtd, &agand_flashbased);
01243         }
01244 
01245 
01246         /* Is a flash based bad block table requested ? */
01247         if (this->options & NAND_USE_FLASH_BBT) {
01248                 /* Use the default pattern descriptors */
01249                 if (!this->bbt_td) {
01250                         this->bbt_td = &bbt_main_descr;
01251                         this->bbt_md = &bbt_mirror_descr;
01252                 }
01253                 if (!this->badblock_pattern) {
01254                         this->badblock_pattern = (mtd->oobblock > 512) ?
01255                                 &largepage_flashbased : &smallpage_flashbased;
01256                 }
01257         } else {
01258                 this->bbt_td = NULL;
01259                 this->bbt_md = NULL;
01260                 if (!this->badblock_pattern) {
01261                         this->badblock_pattern = (mtd->oobblock > 512) ?
01262                                 &largepage_memorybased : &smallpage_memorybased;
01263                 }
01264         }
01265         return nand_scan_bbt (mtd, this->badblock_pattern);
01266 }
01267 
01275 int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
01276 {
01277         struct nand_chip *this = mtd->priv;
01278         int block;
01279         uint8_t res;
01280 
01281         /* Get block number * 2 */
01282         block = (int) (offs >> (this->bbt_erase_shift - 1));
01283         res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
01284 
01285         DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
01286                 (unsigned int)offs, block >> 1, res);
01287 
01288         switch ((int)res) {
01289         case 0x00:      return 0;
01290         case 0x01:      return 1;
01291         case 0x02:      return allowbbt ? 0 : 1;
01292         }
01293         return 1;
01294 }
01295 
01296 EXPORT_SYMBOL (nand_scan_bbt);
01297 EXPORT_SYMBOL (nand_default_bbt);

Generated on Fri Nov 28 00:06:24 2008 for elphel by  doxygen 1.5.1