187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/* 287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * linux/drivers/mtd/onenand/onenand_bbt.c 387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Bad Block Table support for the OneNAND driver 587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Copyright(c) 2005 Samsung Electronics 787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Kyungmin Park <kyungmin.park@samsung.com> 887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Derived from nand_bbt.c 1087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 1187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * TODO: 1287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Split BBT core and chip specific BBT. 1387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 1487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 1587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park#include <linux/slab.h> 1687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park#include <linux/mtd/mtd.h> 1787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park#include <linux/mtd/onenand.h> 18f3bcc0179ab8145615a3b409d652cad1395fb7f3Paul Gortmaker#include <linux/export.h> 1987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 2087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/** 2187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * check_short_pattern - [GENERIC] check if a pattern is in the buffer 2287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param buf the buffer to search 2387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param len the length of buffer to search 2487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param paglen the pagelength 2587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param td search pattern descriptor 2687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 2787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Check for a pattern at the given place. Used to search bad block 2887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * tables and good / bad block identifiers. Same as check_pattern, but 2987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * no optional empty check and the pattern is expected to start 3087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * at offset 0. 3187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 3287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 3387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkstatic int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) 3487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park{ 3587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park int i; 3687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park uint8_t *p = buf; 3787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 3887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* Compare the pattern */ 3987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park for (i = 0; i < td->len; i++) { 4087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park if (p[i] != td->pattern[i]) 4187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return -1; 4287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park } 4387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return 0; 4487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park} 4587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 4687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/** 4787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * create_bbt - [GENERIC] Create a bad block table by scanning the device 4887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param mtd MTD device structure 4987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param buf temporary buffer 5087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param bd descriptor for the good/bad block search pattern 5187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param chip create the table for a specific chip, -1 read all chips. 5287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Applies only if NAND_BBT_PERCHIP option is set 5387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 5487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Create a bad block table by scanning the device 5587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * for the given good/bad block identify pattern 5687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 5787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkstatic int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) 5887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park{ 5987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct onenand_chip *this = mtd->priv; 6087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct bbm_info *bbm = this->bbm; 6187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park int i, j, numblocks, len, scanlen; 6287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park int startblock; 6387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park loff_t from; 6487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park size_t readlen, ooblen; 65211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park struct mtd_oob_ops ops; 665988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi int rgn; 6787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 6887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park printk(KERN_INFO "Scanning device for bad blocks\n"); 6987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 70ec255e34061bbc48fc702875336c6db969df9461Adrian Hunter len = 2; 7187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 7287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* We need only read few bytes from the OOB area */ 7387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park scanlen = ooblen = 0; 7487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park readlen = bd->len; 7587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 7687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* chip == -1 case only */ 7787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* Note that numblocks is 2 * (real numblocks) here; 7887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * see i += 2 below as it makses shifting and masking less painful 7987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 805988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1); 8187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park startblock = 0; 8287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park from = 0; 8387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 840612b9ddc2eeda014dd805c87c752b342d8f80f0Brian Norris ops.mode = MTD_OPS_PLACE_OOB; 85211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park ops.ooblen = readlen; 86211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park ops.oobbuf = buf; 87211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; 88211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park 8987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park for (i = startblock; i < numblocks; ) { 9087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park int ret; 9187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 9287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park for (j = 0; j < len; j++) { 9387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* No need to read pages fully, 9487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * just read required OOB bytes */ 9501039e4e63a8ea0d66fcfc71d7b99769bbbed9d6Roman Tereshonkov ret = onenand_bbt_read_oob(mtd, 9601039e4e63a8ea0d66fcfc71d7b99769bbbed9d6Roman Tereshonkov from + j * this->writesize + bd->offs, &ops); 9787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 98f62724873652ddb19edf7f92843e9456fe3be3eaKyungmin Park /* If it is a initial bad block, just ignore it */ 99211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park if (ret == ONENAND_BBT_READ_FATAL_ERROR) 100211ac75f5e867ab7a54811a514814149caca42c3Kyungmin Park return -EIO; 10187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 10201039e4e63a8ea0d66fcfc71d7b99769bbbed9d6Roman Tereshonkov if (ret || check_short_pattern(&buf[j * scanlen], 10301039e4e63a8ea0d66fcfc71d7b99769bbbed9d6Roman Tereshonkov scanlen, this->writesize, bd)) { 10487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); 105e0c1a921f62d22d1aa62c72ddb793f898945ff5aAdrian Hunter printk(KERN_INFO "OneNAND eraseblock %d is an " 106e0c1a921f62d22d1aa62c72ddb793f898945ff5aAdrian Hunter "initial bad block\n", i >> 1); 107f4f91ac3c833abbd7181ff2122c6b48a653b4e55Kyungmin Park mtd->ecc_stats.badblocks++; 10887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park break; 10987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park } 11087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park } 11187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park i += 2; 1125988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi 1135988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi if (FLEXONENAND(this)) { 1145988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi rgn = flexonenand_region(mtd, from); 1155988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi from += mtd->eraseregions[rgn].erasesize; 1165988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi } else 1175988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi from += (1 << bbm->bbt_erase_shift); 11887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park } 11987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 12087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return 0; 12187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park} 12287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 12387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 12487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/** 12587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * onenand_memory_bbt - [GENERIC] create a memory based bad block table 12687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param mtd MTD device structure 12787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param bd descriptor for the good/bad block search pattern 12887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 12987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * The function creates a memory based bbt by scanning the device 13087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * for manufacturer / software marked good / bad blocks 13187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 13287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkstatic inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) 13387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park{ 134532a37cf8d05dd1aa5631be836036204b0d2b4a1Kyungmin Park struct onenand_chip *this = mtd->priv; 13587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 13687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bd->options &= ~NAND_BBT_SCANEMPTY; 137532a37cf8d05dd1aa5631be836036204b0d2b4a1Kyungmin Park return create_bbt(mtd, this->page_buf, bd, -1); 13887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park} 13987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 14087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/** 14187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad 14287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param mtd MTD device structure 14387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param offs offset in the device 14487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param allowbbt allow access to bad block table region 14587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 14687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkstatic int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) 14787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park{ 14887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct onenand_chip *this = mtd->priv; 14987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct bbm_info *bbm = this->bbm; 15087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park int block; 15187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park uint8_t res; 15287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 15387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* Get block number * 2 */ 1545988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi block = (int) (onenand_block(this, offs) << 1); 15587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; 15687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 157289c05222172b51401dbbb017115655f241d94abBrian Norris pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", 15887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park (unsigned int) offs, block >> 1, res); 15987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 16087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park switch ((int) res) { 16187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park case 0x00: return 0; 16287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park case 0x01: return 1; 16387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park case 0x02: return allowbbt ? 0 : 1; 16487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park } 16587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 16687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return 1; 16787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park} 16887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 16987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/** 17087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s) 17187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param mtd MTD device structure 17287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param bd descriptor for the good/bad block search pattern 17387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 17487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * The function checks, if a bad block table(s) is/are already 17587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * available. If not it scans the device for manufacturer 17687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * marked good / bad blocks and writes the bad block table(s) to 17787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * the selected place. 17887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 179f00b0046d2eafac3e78e8def9374c7492820a9d2Adrian Hunter * The bad block table memory is allocated here. It is freed 180f00b0046d2eafac3e78e8def9374c7492820a9d2Adrian Hunter * by the onenand_release function. 18187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 18287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 18387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkint onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) 18487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park{ 18587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct onenand_chip *this = mtd->priv; 18687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct bbm_info *bbm = this->bbm; 18787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park int len, ret = 0; 18887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 1895988af2319781bc8e0ce418affec4e09cfa77907Rohit Hagargundgi len = this->chipsize >> (this->erase_shift + 2); 19095b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan /* Allocate memory (2bit per block) and clear the memory bad block table */ 19195b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan bbm->bbt = kzalloc(len, GFP_KERNEL); 1920870066d7e6c85bbe37741137e4c4731501a98e0Brian Norris if (!bbm->bbt) 19387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return -ENOMEM; 19487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 19587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* Set the bad block position */ 19687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm->badblockpos = ONENAND_BADBLOCK_POS; 19787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 19887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* Set erase shift */ 19987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm->bbt_erase_shift = this->erase_shift; 20087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 20187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park if (!bbm->isbad_bbt) 20287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm->isbad_bbt = onenand_isbad_bbt; 20387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 20487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* Scan the device to build a memory based bad block table */ 20587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park if ((ret = onenand_memory_bbt(mtd, bd))) { 20687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n"); 20787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park kfree(bbm->bbt); 20887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm->bbt = NULL; 20987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park } 21087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 21187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return ret; 21287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park} 21387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 21487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/* 21587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * Define some generic bad / good block scan pattern which are used 21687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * while scanning a device for factory marked good / bad blocks. 21787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 21887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkstatic uint8_t scan_ff_pattern[] = { 0xff, 0xff }; 21987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 22087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkstatic struct nand_bbt_descr largepage_memorybased = { 22187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park .options = 0, 22287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park .offs = 0, 22387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park .len = 2, 22487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park .pattern = scan_ff_pattern, 22587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park}; 22687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 22787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park/** 22887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device 22987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * @param mtd MTD device structure 23087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * 23187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * This function selects the default bad block table 23287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park * support for the device and calls the onenand_scan_bbt function 23387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park */ 23487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Parkint onenand_default_bbt(struct mtd_info *mtd) 23587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park{ 23687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct onenand_chip *this = mtd->priv; 23787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park struct bbm_info *bbm; 23887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 23995b93a0cd46682c6d9e8eea803fda510cb6b863aBurman Yan this->bbm = kzalloc(sizeof(struct bbm_info), GFP_KERNEL); 24087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park if (!this->bbm) 24187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return -ENOMEM; 24287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 24387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm = this->bbm; 24487590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 24587590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park /* 1KB page has same configuration as 2KB page */ 24687590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park if (!bbm->badblock_pattern) 24787590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park bbm->badblock_pattern = &largepage_memorybased; 24887590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 24987590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park return onenand_scan_bbt(mtd, bbm->badblock_pattern); 25087590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park} 25187590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin Park 25287590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin ParkEXPORT_SYMBOL(onenand_scan_bbt); 25387590e26ff4e7d57dfdaa81780b1b0d9e9970a4cKyungmin ParkEXPORT_SYMBOL(onenand_default_bbt); 254