tools/build-R2_19_3/fsboot/cbl/nand/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:03 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 // we don't have kmalloc() here, so use top RAM memory for BBT buffer
00060 
00061 #define BBT_LEN_1       1024
00062 //#define BBT_LEN_2     135168
00063 #define BBT_LEN_2       (512 * 1024)
00064 char bbt_b_1[BBT_LEN_1];
00065 #define bbt_b_2 (void *)(0xc4000000 - BBT_LEN_2)
00066 
00067 #if 0
00068 #include <linux/slab.h>
00069 #endif
00070 //#include <linux/types.h>
00071 #if 0
00072 #include <linux/mtd/mtd.h>
00073 #include <linux/mtd/nand.h>
00074 #include <linux/mtd/nand_ecc.h>
00075 #include <linux/mtd/compatmac.h>
00076 #include <linux/bitops.h>
00077 #include <linux/delay.h>
00078 #endif
00079 
00080 #include "mtd_nand.h"
00081 //#include "nand.h"
00082 #include "nand_ecc.h"
00083 //#include "delay.h"
00084 
00085 #define dprintf if(0)printf
00086 
00087 #if 0
00088 #include <linux/delay.h>
00089 #include <linux/errno.h>
00090 #include <linux/sched.h>
00091 #include <linux/slab.h>
00092 #include <linux/types.h>
00093 #endif
00094 
00095 
00096 #include <axisrfl/mtd.h>
00097 #include <axisrfl/mtd_nand.h>
00098 #include <axisrfl/nand_ecc.h>
00099 
00100 #include <axisrfl/funcs.h>
00101 
00102 //#include <cyg/hal/hardware.h>
00103 #include <bitops.h>
00104 
00105 #include <hal_intr.h>           /* HAL_DELAY_US */
00106 #include <string.h> /* memcpy */
00107 
00108 #if 0
00109 #include <linux/mtd/compatmac.h>
00110 #include <linux/interrupt.h>
00111 #include <linux/bitops.h>
00112 #include <asm/io.h>
00113 
00114 #ifdef CONFIG_MTD_PARTITIONS
00115 #include <linux/mtd/partitions.h>
00116 
00117 #endif
00118 #endif
00119 
00120 //#include <cyg/hal/hal_intr.h>  /* for hal_delay_us */
00121 
00122 #include <axisrfl/linuxerr.h> /* must be after all eCos files */
00123 
00124 #define udelay(x) HAL_DELAY_US(x)
00125 #undef nop
00126 #define nop() __asm__("nop")
00127 /* only used for ndelay(100) so junk argument */
00128 #define ndelay(x) do { nop(); nop(); nop(); nop(); \
00129                        nop(); nop(); nop(); nop(); } while (0)
00130 
00131 #define GPIO_SYNC 0
00132 
00133 #undef DEBUG /* from mtd.h */
00134 #define DEBUG(n, args...) do { } while(0)
00135 
00136 #define D(x) x
00137 
00138 
00152 static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
00153 {
00154         int i, end = 0;
00155         uint8_t *p = buf;
00156 
00157         end = paglen + td->offs;
00158         if (td->options & NAND_BBT_SCANEMPTY) {
00159                 for (i = 0; i < end; i++) {
00160                         if (p[i] != 0xff)
00161                                 return -1;
00162                 }
00163         }
00164         p += end;
00165 
00166         /* Compare the pattern */
00167         for (i = 0; i < td->len; i++) {
00168                 if (p[i] != td->pattern[i])
00169                         return -1;
00170         }
00171 
00172         if (td->options & NAND_BBT_SCANEMPTY) {
00173                 p += td->len;
00174                 end += td->len;
00175                 for (i = end; i < len; i++) {
00176                         if (*p++ != 0xff)
00177                                 return -1;
00178                 }
00179         }
00180         return 0;
00181 }
00182 
00193 static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
00194 {
00195         int i;
00196         uint8_t *p = buf;
00197 
00198         /* Compare the pattern */
00199         for (i = 0; i < td->len; i++) {
00200                 if (p[td->offs + i] != td->pattern[i])
00201                         return -1;
00202         }
00203         return 0;
00204 }
00205 
00219 size_t min(size_t a, size_t b) {
00220         if(a < b)
00221                 return a;
00222         return b;
00223 }
00224 
00225 static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
00226         int bits, int offs, int reserved_block_code)
00227 {
00228         int res, i, j, act = 0;
00229         struct nand_chip *this = mtd->priv;
00230         size_t retlen, len, totlen;
00231         loff_t from;
00232         uint8_t msk = (uint8_t) ((1 << bits) - 1);
00233 
00234         totlen = (num * bits) >> 3;
00235         from = ((loff_t)page) << this->page_shift;
00236 
00237         while (totlen) {
00238                 len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
00239                 res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
00240                 if (res < 0) {
00241                         if (retlen != len) {
00242                                 printf ("nand_bbt: Error reading bad block table\n");
00243                                 return res;
00244                         }
00245                         printf ("nand_bbt: ECC error while reading bad block table\n");
00246                 }
00247 
00248                 /* Analyse data */
00249                 for (i = 0; i < len; i++) {
00250                         uint8_t dat = buf[i];
00251                         for (j = 0; j < 8; j += bits, act += 2) {
00252                                 uint8_t tmp = (dat >> j) & msk;
00253                                 if (tmp == msk)
00254                                         continue;
00255                                 if (reserved_block_code &&
00256                                     (tmp == reserved_block_code)) {
00257                                         printf ( "nand_read_bbt: Reserved block at 0x%08x\n",
00258                                                 ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
00259                                         this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
00260                                         continue;
00261                                 }
00262                                 /* Leave it for now, if its matured we can move this
00263                                  * message to MTD_DEBUG_LEVEL0 */
00264                                 printf ( "nand_read_bbt: Bad block at 0x%08x\n",
00265                                         ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
00266                                 /* Factory marked bad or worn out ? */
00267                                 if (tmp == 0)
00268                                         this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
00269                                 else
00270                                         this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
00271                         }
00272                 }
00273                 totlen -= len;
00274                 from += len;
00275         }
00276         return 0;
00277 }
00278 
00290 static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
00291 {
00292         struct nand_chip *this = mtd->priv;
00293         int res = 0, i;
00294         int bits;
00295 
00296         bits = td->options & NAND_BBT_NRBITS_MSK;
00297         if (td->options & NAND_BBT_PERCHIP) {
00298                 int offs = 0;
00299                 for (i = 0; i < this->numchips; i++) {
00300                         if (chip == -1 || chip == i)
00301                                 res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);
00302                         if (res)
00303                                 return res;
00304                         offs += this->chipsize >> (this->bbt_erase_shift + 2);
00305                 }
00306         } else {
00307                 res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);
00308                 if (res)
00309                         return res;
00310         }
00311         return 0;
00312 }
00313 
00325 static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td,
00326         struct nand_bbt_descr *md)
00327 {
00328         struct nand_chip *this = mtd->priv;
00329 
00330         /* Read the primary version, if available */
00331         if (td->options & NAND_BBT_VERSION) {
00332                 nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
00333                 td->version[0] = buf[mtd->oobblock + td->veroffs];
00334                 printf ( "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
00335         }
00336 
00337         /* Read the mirror version, if available */
00338         if (md && (md->options & NAND_BBT_VERSION)) {
00339                 nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
00340                 md->version[0] = buf[mtd->oobblock + md->veroffs];
00341                 printf ( "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
00342         }
00343 
00344         return 1;
00345 }
00346 
00358 static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
00359 {
00360         struct nand_chip *this = mtd->priv;
00361         int i, j, numblocks, len, scanlen;
00362         int startblock;
00363         loff_t from;
00364         size_t readlen, ooblen;
00365 
00366         printf ( "Scanning device for bad blocks\n");
00367 
00368         if (bd->options & NAND_BBT_SCANALLPAGES)
00369                 len = 1 << (this->bbt_erase_shift - this->page_shift);
00370         else {
00371                 if (bd->options & NAND_BBT_SCAN2NDPAGE)
00372                         len = 2;
00373                 else
00374                         len = 1;
00375         }
00376 
00377         if (!(bd->options & NAND_BBT_SCANEMPTY)) {
00378                 /* We need only read few bytes from the OOB area */
00379                 scanlen = ooblen = 0;
00380                 readlen = bd->len;
00381         } else {
00382                 /* Full page content should be read */
00383                 scanlen = mtd->oobblock + mtd->oobsize;
00384                 readlen = len * mtd->oobblock;
00385                 ooblen = len * mtd->oobsize;
00386         }
00387 
00388         if (chip == -1) {
00389                 /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
00390                  * makes shifting and masking less painful */
00391                 numblocks = mtd->size >> (this->bbt_erase_shift - 1);
00392                 startblock = 0;
00393                 from = 0;
00394         } else {
00395                 if (chip >= this->numchips) {
00396                         printf ( "create_bbt(): chipnr (%d) > available chips (%d)\n",
00397                                 chip + 1, this->numchips);
00398                         return -1;
00399                 }
00400                 numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
00401                 startblock = chip * numblocks;
00402                 numblocks += startblock;
00403                 from = startblock << (this->bbt_erase_shift - 1);
00404         }
00405 
00406         for (i = startblock; i < numblocks;) {
00407                 int ret;
00408 
00409 /*
00410                 if (bd->options & NAND_BBT_SCANEMPTY)
00411                         if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
00412                                 return ret;
00413 */
00414                 for (j = 0; j < len; j++) {
00415 //                      if (!(bd->options & NAND_BBT_SCANEMPTY)) {
00416                                 size_t retlen;
00417 
00418                                 /* Read the full oob until read_oob is fixed to
00419                                  * handle single byte reads for 16 bit buswidth */
00420                                 ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
00421                                                         mtd->oobsize, &retlen, buf);
00422                                 if (ret)
00423                                         return ret;
00424 
00425                                 if (check_short_pattern (buf, bd)) {
00426                                         this->bbt[i >> 3] |= 0x03 << (i & 0x6);
00427                                         printf ( "1 Bad eraseblock %d at 0x%08x\n",
00428                                                 i >> 1, (unsigned int) from);
00429                                         break;
00430                                 }
00431 /*
00432                         } else {
00433                                 if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
00434                                         this->bbt[i >> 3] |= 0x03 << (i & 0x6);
00435                                         printf ( "2 Bad eraseblock %d at 0x%08x\n",
00436                                                 i >> 1, (unsigned int) from);
00437                                         break;
00438                                 }
00439                         }
00440 */
00441                 }
00442                 i += 2;
00443                 from += (1 << this->bbt_erase_shift);
00444         }
00445         return 0;
00446 }
00447 
00465 static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
00466 {
00467         struct nand_chip *this = mtd->priv;
00468         int i, chips;
00469         int bits, startblock, block, dir;
00470         int scanlen = mtd->oobblock + mtd->oobsize;
00471         int bbtblocks;
00472 
00473         /* Search direction top -> down ? */
00474         if (td->options & NAND_BBT_LASTBLOCK) {
00475                 startblock = (mtd->size >> this->bbt_erase_shift) -1;
00476                 dir = -1;
00477         } else {
00478                 startblock = 0;
00479                 dir = 1;
00480         }
00481 
00482         /* Do we have a bbt per chip ? */
00483         if (td->options & NAND_BBT_PERCHIP) {
00484                 chips = this->numchips;
00485                 bbtblocks = this->chipsize >> this->bbt_erase_shift;
00486                 startblock &= bbtblocks - 1;
00487         } else {
00488                 chips = 1;
00489                 bbtblocks = mtd->size >> this->bbt_erase_shift;
00490         }
00491 
00492         /* Number of bits for each erase block in the bbt */
00493         bits = td->options & NAND_BBT_NRBITS_MSK;
00494 
00495         for (i = 0; i < chips; i++) {
00496                 /* Reset version information */
00497                 td->version[i] = 0;
00498                 td->pages[i] = -1;
00499                 /* Scan the maximum number of blocks */
00500                 for (block = 0; block < td->maxblocks; block++) {
00501                         int actblock = startblock + dir * block;
00502                         /* Read first page */
00503                         nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
00504                         if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
00505                                 td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
00506                                 if (td->options & NAND_BBT_VERSION) {
00507                                         td->version[i] = buf[mtd->oobblock + td->veroffs];
00508                                 }
00509                                 break;
00510                         }
00511                 }
00512                 startblock += this->chipsize >> this->bbt_erase_shift;
00513         }
00514         /* Check, if we found a bbt for each requested chip */
00515         for (i = 0; i < chips; i++) {
00516                 if (td->pages[i] == -1)
00517                         printf ( "Bad block table not found for chip %d\n", i);
00518                 else
00519                         printf ( "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
00520         }
00521         return 0;
00522 }
00523 
00533 static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
00534         struct nand_bbt_descr *td, struct nand_bbt_descr *md)
00535 {
00536         /* Search the primary table */
00537         search_bbt (mtd, buf, td);
00538 
00539         /* Search the mirror table */
00540         if (md)
00541                 search_bbt (mtd, buf, md);
00542 
00543         /* Force result check */
00544         return 1;
00545 }
00546 
00547 
00560 static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
00561         struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
00562 {
00563         struct nand_chip *this = mtd->priv;
00564         struct nand_oobinfo oobinfo;
00565         struct erase_info einfo;
00566         int i, j, res, chip = 0;
00567         int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
00568         int nrchips, bbtoffs, pageoffs;
00569         uint8_t msk[4];
00570         uint8_t rcode = td->reserved_block_code;
00571         size_t retlen, len = 0;
00572         loff_t to;
00573 
00574         if (!rcode)
00575                 rcode = 0xff;
00576         /* Write bad block table per chip rather than per device ? */
00577         if (td->options & NAND_BBT_PERCHIP) {
00578                 numblocks = (int) (this->chipsize >> this->bbt_erase_shift);
00579                 /* Full device write or specific chip ? */
00580                 if (chipsel == -1) {
00581                         nrchips = this->numchips;
00582                 } else {
00583                         nrchips = chipsel + 1;
00584                         chip = chipsel;
00585                 }
00586         } else {
00587                 numblocks = (int) (mtd->size >> this->bbt_erase_shift);
00588                 nrchips = 1;
00589         }
00590 
00591         /* Loop through the chips */
00592         for (; chip < nrchips; chip++) {
00593 
00594                 /* There was already a version of the table, reuse the page
00595                  * This applies for absolute placement too, as we have the
00596                  * page nr. in td->pages.
00597                  */
00598                 if (td->pages[chip] != -1) {
00599                         page = td->pages[chip];
00600                         goto write;
00601                 }
00602 
00603                 /* Automatic placement of the bad block table */
00604                 /* Search direction top -> down ? */
00605                 if (td->options & NAND_BBT_LASTBLOCK) {
00606                         startblock = numblocks * (chip + 1) - 1;
00607                         dir = -1;
00608                 } else {
00609                         startblock = chip * numblocks;
00610                         dir = 1;
00611                 }
00612 
00613                 for (i = 0; i < td->maxblocks; i++) {
00614                         int block = startblock + dir * i;
00615                         /* Check, if the block is bad */
00616                         switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
00617                         case 0x01:
00618                         case 0x03:
00619                                 continue;
00620                         }
00621                         page = block << (this->bbt_erase_shift - this->page_shift);
00622                         /* Check, if the block is used by the mirror table */
00623                         if (!md || md->pages[chip] != page)
00624                                 goto write;
00625                 }
00626                 printf ( "No space left to write bad block table\n");
00627                 return -1;
00628 write:
00629 
00630                 /* Set up shift count and masks for the flash table */
00631                 bits = td->options & NAND_BBT_NRBITS_MSK;
00632                 switch (bits) {
00633                 case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
00634                 case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
00635                 case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
00636                 case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
00637                 default: return -1;
00638                 }
00639 
00640                 bbtoffs = chip * (numblocks >> 2);
00641 
00642                 to = ((loff_t) page) << this->page_shift;
00643 
00644                 memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
00645                 oobinfo.useecc = MTD_NANDECC_PLACEONLY;
00646 
00647                 /* Must we save the block contents ? */
00648                 if (td->options & NAND_BBT_SAVECONTENT) {
00649                         /* Make it block aligned */
00650                         to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
00651                         len = 1 << this->bbt_erase_shift;
00652                         res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
00653                         if (res < 0) {
00654                                 if (retlen != len) {
00655                                         printf ( "nand_bbt: Error reading block for writing the bad block table\n");
00656                                         return res;
00657                                 }
00658                                 printf ( "nand_bbt: ECC error while reading block for writing bad block table\n");
00659                         }
00660                         /* Calc the byte offset in the buffer */
00661                         pageoffs = page - (int)(to >> this->page_shift);
00662                         offs = pageoffs << this->page_shift;
00663                         /* Preset the bbt area with 0xff */
00664                         memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
00665                         /* Preset the bbt's oob area with 0xff */
00666                         memset (&buf[len + pageoffs * mtd->oobsize], 0xff,
00667                                 ((len >> this->page_shift) - pageoffs) * mtd->oobsize);
00668                         if (td->options & NAND_BBT_VERSION) {
00669                                 buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
00670                         }
00671                 } else {
00672                         /* Calc length */
00673                         len = (size_t) (numblocks >> sft);
00674                         /* Make it page aligned ! */
00675                         len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1);
00676                         /* Preset the buffer with 0xff */
00677                         memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
00678                         offs = 0;
00679                         /* Pattern is located in oob area of first page */
00680                         memcpy (&buf[len + td->offs], td->pattern, td->len);
00681                         if (td->options & NAND_BBT_VERSION) {
00682                                 buf[len + td->veroffs] = td->version[chip];
00683                         }
00684                 }
00685 
00686                 /* walk through the memory table */
00687                 for (i = 0; i < numblocks; ) {
00688                         uint8_t dat;
00689                         dat = this->bbt[bbtoffs + (i >> 2)];
00690                         for (j = 0; j < 4; j++ , i++) {
00691                                 int sftcnt = (i << (3 - sft)) & sftmsk;
00692                                 /* Do not store the reserved bbt blocks ! */
00693                                 buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
00694                                 dat >>= 2;
00695                         }
00696                 }
00697 
00698                 memset (&einfo, 0, sizeof (einfo));
00699                 einfo.mtd = mtd;
00700                 einfo.addr = (unsigned long) to;
00701                 einfo.len = 1 << this->bbt_erase_shift;
00702                 res = nand_erase_nand (mtd, &einfo, 1);
00703                 if (res < 0) {
00704                         printf ( "nand_bbt: Error during block erase: %d\n", res);
00705                         return res;
00706                 }
00707 
00708                 res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
00709                 if (res < 0) {
00710                         printf ( "nand_bbt: Error while writing bad block table %d\n", res);
00711                         return res;
00712                 }
00713                 printf ( "Bad block table written to 0x%08x, version 0x%02X\n",
00714                         (unsigned int) to, td->version[chip]);
00715 
00716                 /* Mark it as used */
00717                 td->pages[chip] = page;
00718         }
00719         return 0;
00720 }
00721 
00730 static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
00731 {
00732         struct nand_chip *this = mtd->priv;
00733 
00734         bd->options &= ~NAND_BBT_SCANEMPTY;
00735         return create_bbt (mtd, this->data_buf, bd, -1);
00736 }
00737 
00750 static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
00751 {
00752         int i, chips, writeops, chipsel, res;
00753         struct nand_chip *this = mtd->priv;
00754         struct nand_bbt_descr *td = this->bbt_td;
00755         struct nand_bbt_descr *md = this->bbt_md;
00756         struct nand_bbt_descr *rd, *rd2;
00757 
00758         /* Do we have a bbt per chip ? */
00759         if (td->options & NAND_BBT_PERCHIP)
00760                 chips = this->numchips;
00761         else
00762                 chips = 1;
00763 
00764         for (i = 0; i < chips; i++) {
00765                 writeops = 0;
00766                 rd = NULL;
00767                 rd2 = NULL;
00768                 /* Per chip or per device ? */
00769                 chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
00770                 /* Mirrored table avilable ? */
00771                 if (md) {
00772                         if (td->pages[i] == -1 && md->pages[i] == -1) {
00773                                 writeops = 0x03;
00774                                 goto create;
00775                         }
00776 
00777                         if (td->pages[i] == -1) {
00778                                 rd = md;
00779                                 td->version[i] = md->version[i];
00780                                 writeops = 1;
00781                                 goto writecheck;
00782                         }
00783 
00784                         if (md->pages[i] == -1) {
00785                                 rd = td;
00786                                 md->version[i] = td->version[i];
00787                                 writeops = 2;
00788                                 goto writecheck;
00789                         }
00790 
00791                         if (td->version[i] == md->version[i]) {
00792                                 rd = td;
00793                                 if (!(td->options & NAND_BBT_VERSION))
00794                                         rd2 = md;
00795                                 goto writecheck;
00796                         }
00797 
00798                         if (((int8_t) (td->version[i] - md->version[i])) > 0) {
00799                                 rd = td;
00800                                 md->version[i] = td->version[i];
00801                                 writeops = 2;
00802                         } else {
00803                                 rd = md;
00804                                 td->version[i] = md->version[i];
00805                                 writeops = 1;
00806                         }
00807 
00808                         goto writecheck;
00809 
00810                 } else {
00811                         if (td->pages[i] == -1) {
00812                                 writeops = 0x01;
00813                                 goto create;
00814                         }
00815                         rd = td;
00816                         goto writecheck;
00817                 }
00818 create:
00819                 /* Create the bad block table by scanning the device ? */
00820                 if (!(td->options & NAND_BBT_CREATE))
00821                         continue;
00822 
00823                 /* Create the table in memory by scanning the chip(s) */
00824                 create_bbt (mtd, buf, bd, chipsel);
00825 
00826                 td->version[i] = 1;
00827                 if (md)
00828                         md->version[i] = 1;
00829 writecheck:
00830                 /* read back first ? */
00831                 if (rd)
00832                         read_abs_bbt (mtd, buf, rd, chipsel);
00833                 /* If they weren't versioned, read both. */
00834                 if (rd2)
00835                         read_abs_bbt (mtd, buf, rd2, chipsel);
00836 
00837                 /* Write the bad block table to the device ? */
00838                 if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
00839                         res = write_bbt (mtd, buf, td, md, chipsel);
00840                         if (res < 0)
00841                                 return res;
00842                 }
00843 
00844                 /* Write the mirror bad block table to the device ? */
00845                 if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
00846                         res = write_bbt (mtd, buf, md, td, chipsel);
00847                         if (res < 0)
00848                                 return res;
00849                 }
00850         }
00851         return 0;
00852 }
00853 
00863 static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
00864 {
00865         struct nand_chip *this = mtd->priv;
00866         int i, j, chips, block, nrblocks, update;
00867         uint8_t oldval, newval;
00868 
00869         /* Do we have a bbt per chip ? */
00870         if (td->options & NAND_BBT_PERCHIP) {
00871                 chips = this->numchips;
00872                 nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
00873         } else {
00874                 chips = 1;
00875                 nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
00876         }
00877 
00878         for (i = 0; i < chips; i++) {
00879                 if ((td->options & NAND_BBT_ABSPAGE) ||
00880                     !(td->options & NAND_BBT_WRITE)) {
00881                         if (td->pages[i] == -1) continue;
00882                         block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
00883                         block <<= 1;
00884                         oldval = this->bbt[(block >> 3)];
00885                         newval = oldval | (0x2 << (block & 0x06));
00886                         this->bbt[(block >> 3)] = newval;
00887                         if ((oldval != newval) && td->reserved_block_code)
00888                                 nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
00889                         continue;
00890                 }
00891                 update = 0;
00892                 if (td->options & NAND_BBT_LASTBLOCK)
00893                         block = ((i + 1) * nrblocks) - td->maxblocks;
00894                 else
00895                         block = i * nrblocks;
00896                 block <<= 1;
00897                 for (j = 0; j < td->maxblocks; j++) {
00898                         oldval = this->bbt[(block >> 3)];
00899                         newval = oldval | (0x2 << (block & 0x06));
00900                         this->bbt[(block >> 3)] = newval;
00901                         if (oldval != newval) update = 1;
00902                         block += 2;
00903                 }
00904                 /* If we want reserved blocks to be recorded to flash, and some
00905                    new ones have been marked, then we need to update the stored
00906                    bbts.  This should only happen once. */
00907                 if (update && td->reserved_block_code)
00908                         nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
00909         }
00910 }
00911 
00926 int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
00927 {
00928         struct nand_chip *this = mtd->priv;
00929         int len, res = 0;
00930         uint8_t *buf;
00931         struct nand_bbt_descr *td = this->bbt_td;
00932         struct nand_bbt_descr *md = this->bbt_md;
00933 
00934         len = mtd->size >> (this->bbt_erase_shift + 2);
00935         /* Allocate memory (2bit per block) */
00936 //printf("BBT: len 1 == %d\n", len);
00937 //      this->bbt = kmalloc (len, GFP_KERNEL);
00938         this->bbt = NULL;
00939         if(len <= BBT_LEN_1)
00940                 this->bbt = bbt_b_1;
00941         if (!this->bbt) {
00942                 printf ( "nand_scan_bbt: Out of memory\n");
00943                 return -ENOMEM;
00944         }
00945         /* Clear the memory bad block table */
00946         memset (this->bbt, 0x00, len);
00947 
00948         /* If no primary table decriptor is given, scan the device
00949          * to build a memory based bad block table
00950          */
00951         if (!td) {
00952                 if ((res = nand_memory_bbt(mtd, bd))) {
00953                         printf ( "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
00954 //                      kfree (this->bbt);
00955                         this->bbt = NULL;
00956                 }
00957                 return res;
00958         }
00959 
00960         /* Allocate a temporary buffer for one eraseblock incl. oob */
00961         len = (1 << this->bbt_erase_shift);
00962         len += (len >> this->page_shift) * mtd->oobsize;
00963 //printf("BBT: len 2 == %d\n", len);
00964 //      buf = kmalloc (len, GFP_KERNEL);
00965         buf = NULL;
00966         if(len <= BBT_LEN_2)
00967                 buf = bbt_b_2;
00968         if (!buf) {
00969                 printf ( "nand_bbt: Out of memory\n");
00970 //              kfree (this->bbt);
00971                 this->bbt = NULL;
00972                 return -ENOMEM;
00973         }
00974 
00975         /* Is the bbt at a given page ? */
00976         if (td->options & NAND_BBT_ABSPAGE) {
00977                 res = read_abs_bbts (mtd, buf, td, md);
00978         } else {
00979                 /* Search the bad block table using a pattern in oob */
00980                 res = search_read_bbts (mtd, buf, td, md);
00981         }
00982 
00983         if (res)
00984                 res = check_create (mtd, buf, bd);
00985 
00986         /* Prevent the bbt regions from erasing / writing */
00987         mark_bbt_region (mtd, td);
00988         if (md)
00989                 mark_bbt_region (mtd, md);
00990 
00991 //      kfree (buf);
00992         return res;
00993 }
00994 
00995 
01003 int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
01004 {
01005         struct nand_chip *this = mtd->priv;
01006         int len, res = 0, writeops = 0;
01007         int chip, chipsel;
01008         uint8_t *buf;
01009         struct nand_bbt_descr *td = this->bbt_td;
01010         struct nand_bbt_descr *md = this->bbt_md;
01011 
01012         if (!this->bbt || !td)
01013                 return -1;
01014 
01015         len = mtd->size >> (this->bbt_erase_shift + 2);
01016         /* Allocate a temporary buffer for one eraseblock incl. oob */
01017         len = (1 << this->bbt_erase_shift);
01018         len += (len >> this->page_shift) * mtd->oobsize;
01019 //printf("BBT: len 3 == %d", len);
01020 //      buf = kmalloc (len, GFP_KERNEL);
01021         buf = NULL;
01022         if(len <= BBT_LEN_2)
01023                 buf = bbt_b_2;
01024         if (!buf) {
01025                 printf ( "nand_update_bbt: Out of memory\n");
01026                 return -ENOMEM;
01027         }
01028 
01029         writeops = md != NULL ? 0x03 : 0x01;
01030 
01031         /* Do we have a bbt per chip ? */
01032         if (td->options & NAND_BBT_PERCHIP) {
01033                 chip = (int) (offs >> this->chip_shift);
01034                 chipsel = chip;
01035         } else {
01036                 chip = 0;
01037                 chipsel = -1;
01038         }
01039 
01040         td->version[chip]++;
01041         if (md)
01042                 md->version[chip]++;
01043 
01044         /* Write the bad block table to the device ? */
01045         if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
01046                 res = write_bbt (mtd, buf, td, md, chipsel);
01047                 if (res < 0)
01048                         goto out;
01049         }
01050         /* Write the mirror bad block table to the device ? */
01051         if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
01052                 res = write_bbt (mtd, buf, md, td, chipsel);
01053         }
01054 
01055 out:
01056 //      kfree (buf);
01057         return res;
01058 }
01059 
01060 /* Define some generic bad / good block scan pattern which are used
01061  * while scanning a device for factory marked good / bad blocks. */
01062 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
01063 
01064 static struct nand_bbt_descr smallpage_memorybased = {
01065         .options = NAND_BBT_SCAN2NDPAGE,
01066         .offs = 5,
01067         .len = 1,
01068         .pattern = scan_ff_pattern
01069 };
01070 
01071 static struct nand_bbt_descr largepage_memorybased = {
01072         .options = 0,
01073         .offs = 0,
01074         .len = 2,
01075         .pattern = scan_ff_pattern
01076 };
01077 
01078 static struct nand_bbt_descr smallpage_flashbased = {
01079         .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
01080         .offs = 5,
01081         .len = 1,
01082         .pattern = scan_ff_pattern
01083 };
01084 
01085 static struct nand_bbt_descr largepage_flashbased = {
01086         .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
01087         .offs = 0,
01088         .len = 2,
01089         .pattern = scan_ff_pattern
01090 };
01091 
01092 static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
01093 
01094 static struct nand_bbt_descr agand_flashbased = {
01095         .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
01096         .offs = 0x20,
01097         .len = 6,
01098         .pattern = scan_agand_pattern
01099 };
01100 
01101 /* Generic flash bbt decriptors
01102 */
01103 static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
01104 static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
01105 
01106 static struct nand_bbt_descr bbt_main_descr = {
01107         .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
01108                 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
01109         .offs = 8,
01110         .len = 4,
01111         .veroffs = 12,
01112         .maxblocks = 4,
01113         .pattern = bbt_pattern
01114 };
01115 
01116 static struct nand_bbt_descr bbt_mirror_descr = {
01117         .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
01118                 | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
01119         .offs = 8,
01120         .len = 4,
01121         .veroffs = 12,
01122         .maxblocks = 4,
01123         .pattern = mirror_pattern
01124 };
01125 
01134 int nand_default_bbt (struct mtd_info *mtd)
01135 {
01136         struct nand_chip *this = mtd->priv;
01137 
01138         /* Default for AG-AND. We must use a flash based
01139          * bad block table as the devices have factory marked
01140          * _good_ blocks. Erasing those blocks leads to loss
01141          * of the good / bad information, so we _must_ store
01142          * this information in a good / bad table during
01143          * startup
01144         */
01145         if (this->options & NAND_IS_AND) {
01146                 /* Use the default pattern descriptors */
01147                 if (!this->bbt_td) {
01148                         this->bbt_td = &bbt_main_descr;
01149                         this->bbt_md = &bbt_mirror_descr;
01150                 }
01151                 this->options |= NAND_USE_FLASH_BBT;
01152                 return nand_scan_bbt (mtd, &agand_flashbased);
01153         }
01154 
01155 
01156         /* Is a flash based bad block table requested ? */
01157         if (this->options & NAND_USE_FLASH_BBT) {
01158                 /* Use the default pattern descriptors */
01159                 if (!this->bbt_td) {
01160                         this->bbt_td = &bbt_main_descr;
01161                         this->bbt_md = &bbt_mirror_descr;
01162                 }
01163                 if (!this->badblock_pattern) {
01164                         this->badblock_pattern = (mtd->oobblock > 512) ?
01165                                 &largepage_flashbased : &smallpage_flashbased;
01166                 }
01167         } else {
01168                 this->bbt_td = NULL;
01169                 this->bbt_md = NULL;
01170                 if (!this->badblock_pattern) {
01171                         this->badblock_pattern = (mtd->oobblock > 512) ?
01172                                 &largepage_memorybased : &smallpage_memorybased;
01173                 }
01174         }
01175         return nand_scan_bbt (mtd, this->badblock_pattern);
01176 }
01177 
01185 int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
01186 {
01187         struct nand_chip *this = mtd->priv;
01188         int block;
01189         uint8_t res;
01190 
01191         /* Get block number * 2 */
01192         block = (int) (offs >> (this->bbt_erase_shift - 1));
01193         res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
01194 
01195         DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
01196                 (unsigned int)offs, block >> 1, res);
01197 
01198         switch ((int)res) {
01199         case 0x00:      return 0;
01200         case 0x01:      return 1;
01201         case 0x02:      return allowbbt ? 0 : 1;
01202         }
01203         return 1;
01204 }
01205 
01206 EXPORT_SYMBOL (nand_scan_bbt);
01207 EXPORT_SYMBOL (nand_default_bbt);

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