linux nand flash 驱动简单介绍

来源:互联网 发布:苹果mac怎么收藏网页 编辑:程序博客网 时间:2024/05/01 00:13

linux中为nand flash驱动提供了很多操作接口,开发只需要填充相应的接口即可。


nand flash只需要完成读页、写页、读oob、写oob、擦除页,这几个接口完成了,基本的操作也就完了,基本上就完成了大部分操作。最后,基于这些操作,完成ecc(软件或者硬件,现在大多数nand flash都是硬件ecc了,方便多了),坏块标记位置的正确读写,这个就可以正常的标记坏块和扫描坏块了。


几个与nand相关的核心层代码:

drivers/mtd/nand/nand_ids.c

这个里面很简单,就两个结构体赋值

/**Manufacturer ID list*/struct nand_manufacturers nand_manuf_ids[] = {{NAND_MFR_TOSHIBA, "Toshiba"},{NAND_MFR_SAMSUNG, "Samsung"},{NAND_MFR_FUJITSU, "Fujitsu"},{NAND_MFR_NATIONAL, "National"},{NAND_MFR_RENESAS, "Renesas"},{NAND_MFR_STMICRO, "ST Micro"},{NAND_MFR_HYNIX, "Hynix"},{NAND_MFR_MICRON, "Micron"},{NAND_MFR_AMD, "AMD"},{0x0, "Unknown"}};
为芯片添加厂家ID和厂家名称,ID是芯片手册上的,名称随便填,规范点还是填厂家名字

/**Chip ID list**Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,*options**Pagesize; 0, 256, 512*0get this information from the extended chip ID+256256 Byte page size*512512 Byte page size*/struct nand_flash_dev nand_flash_ids[] = {#ifdef CONFIG_MTD_NAND_MUSEUM_IDS{"NAND 1MiB 5V 8-bit",0x6e, 256, 1, 0x1000, 0},{"NAND 2MiB 5V 8-bit",0x64, 256, 2, 0x1000, 0},{"NAND 4MiB 5V 8-bit",0x6b, 512, 4, 0x2000, 0},{"NAND 1MiB 3,3V 8-bit",0xe8, 256, 1, 0x1000, 0},{"NAND 1MiB 3,3V 8-bit",0xec, 256, 1, 0x1000, 0},{"NAND 2MiB 3,3V 8-bit",0xea, 256, 2, 0x1000, 0},{"NAND 4MiB 3,3V 8-bit",0xd5, 512, 4, 0x2000, 0},{"NAND 4MiB 3,3V 8-bit",0xe3, 512, 4, 0x2000, 0},{"NAND 4MiB 3,3V 8-bit",0xe5, 512, 4, 0x2000, 0},{"NAND 8MiB 3,3V 8-bit",0xd6, 512, 8, 0x2000, 0},{"NAND 8MiB 1,8V 8-bit",0x39, 512, 8, 0x2000, 0},{"NAND 8MiB 3,3V 8-bit",0xe6, 512, 8, 0x2000, 0},{"NAND 8MiB 1,8V 16-bit",0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},{"NAND 8MiB 3,3V 16-bit",0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},#endif{"NAND 16MiB 1,8V 8-bit",0x33, 512, 16, 0x4000, 0},{"NAND 16MiB 3,3V 8-bit",0x73, 512, 16, 0x4000, 0},{"NAND 16MiB 1,8V 16-bit",0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},{"NAND 16MiB 3,3V 16-bit",0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},{"NAND 32MiB 1,8V 8-bit",0x35, 512, 32, 0x4000, 0},{"NAND 32MiB 3,3V 8-bit",0x75, 512, 32, 0x4000, 0},{"NAND 32MiB 1,8V 16-bit",0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},{"NAND 32MiB 3,3V 16-bit",0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},{"NAND 64MiB 1,8V 8-bit",0x36, 512, 64, 0x4000, 0},{"NAND 64MiB 3,3V 8-bit",0x76, 512, 64, 0x4000, 0},{"NAND 64MiB 1,8V 16-bit",0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},{"NAND 64MiB 3,3V 16-bit",0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},{"NAND 128MiB 1,8V 8-bit",0x78, 512, 128, 0x4000, 0},{"NAND 128MiB 1,8V 8-bit",0x39, 512, 128, 0x4000, 0},{"NAND 128MiB 3,3V 8-bit",0x79, 512, 128, 0x4000, 0},{"NAND 128MiB 1,8V 16-bit",0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},{"NAND 128MiB 1,8V 16-bit",0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},{"NAND 128MiB 3,3V 16-bit",0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},{"NAND 128MiB 3,3V 16-bit",0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},{"NAND 256MiB 3,3V 8-bit",0x71, 512, 256, 0x4000, 0},/* * These are the new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR)#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)/*512 Megabit */{"NAND 64MiB 1,8V 8-bit",0xA2, 0,  64, 0, LP_OPTIONS},{"NAND 64MiB 3,3V 8-bit",0xF2, 0,  64, 0, LP_OPTIONS},{"NAND 64MiB 1,8V 16-bit",0xB2, 0,  64, 0, LP_OPTIONS16},{"NAND 64MiB 3,3V 16-bit",0xC2, 0,  64, 0, LP_OPTIONS16},/* 1 Gigabit */{"NAND 128MiB 1,8V 8-bit",0xA1, 0, 128, 0, LP_OPTIONS},{"NAND 128MiB 3,3V 8-bit",0xF1, 0, 128, 0, LP_OPTIONS},{"NAND 128MiB 1,8V 16-bit",0xB1, 0, 128, 0, LP_OPTIONS16},{"NAND 128MiB 3,3V 16-bit",0xC1, 0, 128, 0, LP_OPTIONS16},/* 2 Gigabit */{"NAND 256MiB 1,8V 8-bit",0xAA, 0, 256, 0, LP_OPTIONS},{"NAND 256MiB 3,3V 8-bit",0xDA, 0, 256, 0, LP_OPTIONS},{"NAND 256MiB 1,8V 16-bit",0xBA, 0, 256, 0, LP_OPTIONS16},{"NAND 256MiB 3,3V 16-bit",0xCA, 0, 256, 0, LP_OPTIONS16},/* 4 Gigabit */{"NAND 512MiB 1,8V 8-bit",0xAC, 0, 512, 0, LP_OPTIONS},{"NAND 512MiB 3,3V 8-bit",0xDC, 0, 512, 0, LP_OPTIONS},{"NAND 512MiB 1,8V 16-bit",0xBC, 0, 512, 0, LP_OPTIONS16},{"NAND 512MiB 3,3V 16-bit",0xCC, 0, 512, 0, LP_OPTIONS16},/* 8 Gigabit */{"NAND 1GiB 1,8V 8-bit",0xA3, 0, 1024, 0, LP_OPTIONS},{"NAND 1GiB 3,3V 8-bit",0xD3, 0, 1024, 0, LP_OPTIONS},{"NAND 1GiB 1,8V 16-bit",0xB3, 0, 1024, 0, LP_OPTIONS16},{"NAND 1GiB 3,3V 16-bit",0xC3, 0, 1024, 0, LP_OPTIONS16},/* 16 Gigabit */{"NAND 2GiB 1,8V 8-bit",0xA5, 0, 2048, 0, LP_OPTIONS},{"NAND 2GiB 3,3V 8-bit",0xD5, 0, 2048, 0, LP_OPTIONS},{"NAND 2GiB 1,8V 16-bit",0xB5, 0, 2048, 0, LP_OPTIONS16},{"NAND 2GiB 3,3V 16-bit",0xC5, 0, 2048, 0, LP_OPTIONS16},/* * Renesas AND 1 Gigabit. Those chips do not support extended id and * have a strange page/block layout !  The chosen minimum erasesize is * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page * planes 1 block = 2 pages, but due to plane arrangement the blocks * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would * increase the eraseblock size so we chose a combined one which can be * erased in one go There are more speed improvements for reads and * writes possible, but not implemented now */{"AND 128MiB 3,3V 8-bit",0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},{NULL,}};
/** * struct nand_flash_dev - NAND Flash Device ID Structure * @name:Identify the device type * @id:device ID code * @pagesize:Pagesize in bytes. Either 256 or 512 or 0 *If the pagesize is 0, then the real pagesize *and the eraseize are determined from the *extended id bytes in the chip * @erasesize:Size of an erase block in the flash device. * @chipsize:Total chipsize in Mega Bytes * @options:Bitfield to store chip relevant options */struct nand_flash_dev {char *name;int id;unsigned long pagesize;unsigned long chipsize;unsigned long erasesize;unsigned long options;};

这个结构体是给设备赋值,名字,id为设备id,不是厂家id,pagesize在新的nand中都是为0,表示设备信息从芯片id的第三个和第四个中获取,叫extid,第一个为厂家id,第二个为设备id。chipsize为芯片容量,单位为MB,比如上面的128,表示的是128M,1Gbits。erasesize在新的nand中也为0,同理从芯片中读取出来。最后一个是选项,即代表芯片的特性。


drivers/mtd/nand/nand_bbt.c

这个函数主要负责扫描坏块,坏块表建立,标记坏块。

/* *  drivers/mtd/nand_bbt.c * *  Overview: *   Bad block table support for the NAND driver * *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the bbt descriptor(s). If a bbt is found * then the contents are read and the memory based bbt is created. If a * mirrored bbt is selected then the mirror is searched too and the * versions are compared. If the mirror has a greater version number * than the mirror bbt is used to build the memory based bbt. * If the tables are not versioned, then we "or" the bad block information. * If one of the bbt's is out of date or does not exist it is (re)created. * If no bbt exists at all then the device is scanned for factory marked * good / bad blocks and the bad block tables are created. * * For manufacturer created bbts like the one found on M-SYS DOC devices * the bbt is searched and read but never created * * The autogenerated bad block table is located in the last good blocks * of the device. The table is mirrored, so it can be updated eventually. * The table is marked in the oob area with an ident pattern and a version * number which indicates which of both tables is more up to date. * * The table uses 2 bits per block * 11b: block is good * 00b: block is factory marked bad * 01b, 10b: block is marked bad due to wear * * The memory bad block table uses the following scheme: * 00b:block is good * 01b:block is marked bad due to wear * 10b:block is reserved (to protect the bbt area) * 11b:block is factory marked bad * * Multichip devices like DOC store the bad block info per floor. * * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space necessary for a bbt in FLASH does not exceed a block boundary * */#include <linux/slab.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <linux/mtd/compatmac.h>#include <linux/bitops.h>#include <linux/delay.h>#include <linux/vmalloc.h>/** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf:the buffer to search * @len:the length of buffer to search * @paglen:the pagelength * @td:search pattern descriptor * * Check for a pattern at the given place. Used to search bad block * tables and good / bad block identifiers. * If the SCAN_EMPTY option is set then check, if all bytes except the * pattern area contain 0xff **/static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td){int i, end = 0;uint8_t *p = buf;end = paglen + td->offs;if (td->options & NAND_BBT_SCANEMPTY) {for (i = 0; i < end; i++) {if (p[i] != 0xff)return -1;}}p += end;/* Compare the pattern */for (i = 0; i < td->len; i++) {if (p[i] != td->pattern[i])return -1;}if (td->options & NAND_BBT_SCANEMPTY) {p += td->len;end += td->len;for (i = end; i < len; i++) {if (*p++ != 0xff)return -1;}}return 0;}/** * check_short_pattern - [GENERIC] check if a pattern is in the buffer * @buf:the buffer to search * @td:search pattern descriptor * * Check for a pattern at the given place. Used to search bad block * tables and good / bad block identifiers. Same as check_pattern, but * no optional empty check **/static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td){int i;uint8_t *p = buf;/* Compare the pattern */for (i = 0; i < td->len; i++) {if (p[td->offs + i] != td->pattern[i])return -1;}return 0;}/** * read_bbt - [GENERIC] Read the bad block table starting from page * @mtd:MTD device structure * @buf:temporary buffer * @page:the starting page * @num:the number of bbt descriptors to read * @bits:number of bits per block * @offs:offset in the memory table * @reserved_block_code:Pattern to identify reserved blocks * * Read the bad block table starting from page. * */static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,    int bits, int offs, int reserved_block_code){int res, i, j, act = 0;struct nand_chip *this = mtd->priv;size_t retlen, len, totlen;loff_t from;uint8_t msk = (uint8_t) ((1 << bits) - 1);totlen = (num * bits) >> 3;from = ((loff_t) page) << this->page_shift;while (totlen) {len = min(totlen, (size_t) (1 << this->bbt_erase_shift));res = mtd->read(mtd, from, len, &retlen, buf);if (res < 0) {if (retlen != len) {printk(KERN_INFO "nand_bbt: Error reading bad block table\n");return res;}printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");}/* Analyse data */for (i = 0; i < len; i++) {uint8_t dat = buf[i];for (j = 0; j < 8; j += bits, act += 2) {uint8_t tmp = (dat >> j) & msk;if (tmp == msk)continue;if (reserved_block_code && (tmp == reserved_block_code)) {printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);mtd->ecc_stats.bbtblocks++;continue;}/* Leave it for now, if its matured we can move this * message to MTD_DEBUG_LEVEL0 */printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);/* Factory marked bad or worn out ? */if (tmp == 0)this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);elsethis->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);mtd->ecc_stats.badblocks++;}}totlen -= len;from += len;}return 0;}/** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page * @mtd:MTD device structure * @buf:temporary buffer * @td:descriptor for the bad block table * @chip:read the table for a specific chip, -1 read all chips. *Applies only if NAND_BBT_PERCHIP option is set * * Read the bad block table for all chips starting at a given page * We assume that the bbt bits are in consecutive order.*/static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip){struct nand_chip *this = mtd->priv;int res = 0, i;int bits;bits = td->options & NAND_BBT_NRBITS_MSK;if (td->options & NAND_BBT_PERCHIP) {int offs = 0;for (i = 0; i < this->numchips; i++) {if (chip == -1 || chip == i)res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);if (res)return res;offs += this->chipsize >> (this->bbt_erase_shift + 2);}} else {res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);if (res)return res;}return 0;}/* * Scan read raw data from flash */static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len){struct mtd_oob_ops ops;ops.mode = MTD_OOB_RAW;ops.ooboffs = 0;ops.ooblen = mtd->oobsize;ops.oobbuf = buf;ops.datbuf = buf;ops.len = len;return mtd->read_oob(mtd, offs, &ops);}/* * Scan write data with oob to flash */static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,  uint8_t *buf, uint8_t *oob){struct mtd_oob_ops ops;ops.mode = MTD_OOB_PLACE;ops.ooboffs = 0;ops.ooblen = mtd->oobsize;ops.datbuf = buf;ops.oobbuf = oob;ops.len = len;return mtd->write_oob(mtd, offs, &ops);}/** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd:MTD device structure * @buf:temporary buffer * @td:descriptor for the bad block table * @md:descriptor for the bad block table mirror * * Read the bad block table(s) for all chips starting at a given page * We assume that the bbt bits are in consecutive order. **/static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md){struct nand_chip *this = mtd->priv;/* Read the primary version, if available */if (td->options & NAND_BBT_VERSION) {scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,      mtd->writesize);td->version[0] = buf[mtd->writesize + td->veroffs];printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",       td->pages[0], td->version[0]);}/* Read the mirror version, if available */if (md && (md->options & NAND_BBT_VERSION)) {scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,      mtd->writesize);md->version[0] = buf[mtd->writesize + md->veroffs];printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",       md->pages[0], md->version[0]);}return 1;}/* * Scan a given block full */static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,   loff_t offs, uint8_t *buf, size_t readlen,   int scanlen, int len){int ret, j;ret = scan_read_raw(mtd, buf, offs, readlen);if (ret)return ret;for (j = 0; j < len; j++, buf += scanlen) {if (check_pattern(buf, scanlen, mtd->writesize, bd))return 1;}return 0;}/* * Scan a given block partially */static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,   loff_t offs, uint8_t *buf, int len){struct mtd_oob_ops ops;int j, ret;ops.ooblen = mtd->oobsize;ops.oobbuf = buf;ops.ooboffs = 0;ops.datbuf = NULL;ops.mode = MTD_OOB_PLACE;for (j = 0; j < len; j++) {/* * Read the full oob until read_oob is fixed to * handle single byte reads for 16 bit * buswidth */ret = mtd->read_oob(mtd, offs, &ops);if (ret)return ret;if (check_short_pattern(buf, bd))return 1;offs += mtd->writesize;}return 0;}/** * create_bbt - [GENERIC] Create a bad block table by scanning the device * @mtd:MTD device structure * @buf:temporary buffer * @bd:descriptor for the good/bad block search pattern * @chip:create the table for a specific chip, -1 read all chips. *Applies only if NAND_BBT_PERCHIP option is set * * Create a bad block table by scanning the device * for the given good/bad block identify pattern */static int create_bbt(struct mtd_info *mtd, uint8_t *buf,struct nand_bbt_descr *bd, int chip){struct nand_chip *this = mtd->priv;int i, numblocks, len, scanlen;int startblock;loff_t from;size_t readlen;printk(KERN_INFO "Scanning device for bad blocks\n");if (bd->options & NAND_BBT_SCANALLPAGES)len = 1 << (this->bbt_erase_shift - this->page_shift);else {if (bd->options & NAND_BBT_SCAN2NDPAGE)len = 2;elselen = 1;}if (!(bd->options & NAND_BBT_SCANEMPTY)) {/* We need only read few bytes from the OOB area */scanlen = 0;readlen = bd->len;} else {/* Full page content should be read */scanlen = mtd->writesize + mtd->oobsize;readlen = len * mtd->writesize;}if (chip == -1) {/* Note that numblocks is 2 * (real numblocks) here, see i+=2 * below as it makes shifting and masking less painful */numblocks = mtd->size >> (this->bbt_erase_shift - 1);startblock = 0;from = 0;} else {if (chip >= this->numchips) {printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",       chip + 1, this->numchips);return -EINVAL;}numblocks = this->chipsize >> (this->bbt_erase_shift - 1);startblock = chip * numblocks;numblocks += startblock;from = (loff_t)startblock << (this->bbt_erase_shift - 1);}for (i = startblock; i < numblocks;) {int ret;if (bd->options & NAND_BBT_SCANALLPAGES)ret = scan_block_full(mtd, bd, from, buf, readlen,      scanlen, len);elseret = scan_block_fast(mtd, bd, from, buf, len);if (ret < 0)return ret;if (ret) {this->bbt[i >> 3] |= 0x03 << (i & 0x6);printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n",       i >> 1, (unsigned long long)from);mtd->ecc_stats.badblocks++;}i += 2;from += (1 << this->bbt_erase_shift);}return 0;}/** * search_bbt - [GENERIC] scan the device for a specific bad block table * @mtd:MTD device structure * @buf:temporary buffer * @td:descriptor for the bad block table * * Read the bad block table by searching for a given ident pattern. * Search is preformed either from the beginning up or from the end of * the device downwards. The search starts always at the start of a * block. * If the option NAND_BBT_PERCHIP is given, each chip is searched * for a bbt, which contains the bad block information of this chip. * This is necessary to provide support for certain DOC devices. * * The bbt ident pattern resides in the oob area of the first page * in a block. */static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td){struct nand_chip *this = mtd->priv;int i, chips;int bits, startblock, block, dir;int scanlen = mtd->writesize + mtd->oobsize;int bbtblocks;int blocktopage = this->bbt_erase_shift - this->page_shift;/* Search direction top -> down ? */if (td->options & NAND_BBT_LASTBLOCK) {startblock = (mtd->size >> this->bbt_erase_shift) - 1;dir = -1;} else {startblock = 0;dir = 1;}/* Do we have a bbt per chip ? */if (td->options & NAND_BBT_PERCHIP) {chips = this->numchips;bbtblocks = this->chipsize >> this->bbt_erase_shift;startblock &= bbtblocks - 1;} else {chips = 1;bbtblocks = mtd->size >> this->bbt_erase_shift;}/* Number of bits for each erase block in the bbt */bits = td->options & NAND_BBT_NRBITS_MSK;for (i = 0; i < chips; i++) {/* Reset version information */td->version[i] = 0;td->pages[i] = -1;/* Scan the maximum number of blocks */for (block = 0; block < td->maxblocks; block++) {int actblock = startblock + dir * block;loff_t offs = (loff_t)actblock << this->bbt_erase_shift;/* Read first page */scan_read_raw(mtd, buf, offs, mtd->writesize);if (!check_pattern(buf, scanlen, mtd->writesize, td)) {td->pages[i] = actblock << blocktopage;if (td->options & NAND_BBT_VERSION) {td->version[i] = buf[mtd->writesize + td->veroffs];}break;}}startblock += this->chipsize >> this->bbt_erase_shift;}/* Check, if we found a bbt for each requested chip */for (i = 0; i < chips; i++) {if (td->pages[i] == -1)printk(KERN_WARNING "Bad block table not found for chip %d\n", i);elseprintk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i],       td->version[i]);}return 0;}/** * search_read_bbts - [GENERIC] scan the device for bad block table(s) * @mtd:MTD device structure * @buf:temporary buffer * @td:descriptor for the bad block table * @md:descriptor for the bad block table mirror * * Search and read the bad block table(s)*/static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md){/* Search the primary table */search_bbt(mtd, buf, td);/* Search the mirror table */if (md)search_bbt(mtd, buf, md);/* Force result check */return 1;}/** * write_bbt - [GENERIC] (Re)write the bad block table * * @mtd:MTD device structure * @buf:temporary buffer * @td:descriptor for the bad block table * @md:descriptor for the bad block table mirror * @chipsel:selector for a specific chip, -1 for all * * (Re)write the bad block table **/static int write_bbt(struct mtd_info *mtd, uint8_t *buf,     struct nand_bbt_descr *td, struct nand_bbt_descr *md,     int chipsel){struct nand_chip *this = mtd->priv;struct erase_info einfo;int i, j, res, chip = 0;int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;int nrchips, bbtoffs, pageoffs, ooboffs;uint8_t msk[4];uint8_t rcode = td->reserved_block_code;size_t retlen, len = 0;loff_t to;struct mtd_oob_ops ops;ops.ooblen = mtd->oobsize;ops.ooboffs = 0;ops.datbuf = NULL;ops.mode = MTD_OOB_PLACE;if (!rcode)rcode = 0xff;/* Write bad block table per chip rather than per device ? */if (td->options & NAND_BBT_PERCHIP) {numblocks = (int)(this->chipsize >> this->bbt_erase_shift);/* Full device write or specific chip ? */if (chipsel == -1) {nrchips = this->numchips;} else {nrchips = chipsel + 1;chip = chipsel;}} else {numblocks = (int)(mtd->size >> this->bbt_erase_shift);nrchips = 1;}/* Loop through the chips */for (; chip < nrchips; chip++) {/* There was already a version of the table, reuse the page * This applies for absolute placement too, as we have the * page nr. in td->pages. */if (td->pages[chip] != -1) {page = td->pages[chip];goto write;}/* Automatic placement of the bad block table *//* Search direction top -> down ? */if (td->options & NAND_BBT_LASTBLOCK) {startblock = numblocks * (chip + 1) - 1;dir = -1;} else {startblock = chip * numblocks;dir = 1;}for (i = 0; i < td->maxblocks; i++) {int block = startblock + dir * i;/* Check, if the block is bad */switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {case 0x01:case 0x03:continue;}page = block <<(this->bbt_erase_shift - this->page_shift);/* Check, if the block is used by the mirror table */if (!md || md->pages[chip] != page)goto write;}printk(KERN_ERR "No space left to write bad block table\n");return -ENOSPC;write:/* Set up shift count and masks for the flash table */bits = td->options & NAND_BBT_NRBITS_MSK;msk[2] = ~rcode;switch (bits) {case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;msk[3] = 0x01;break;case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;msk[3] = 0x03;break;case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;msk[3] = 0x0f;break;case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;msk[3] = 0xff;break;default: return -EINVAL;}bbtoffs = chip * (numblocks >> 2);to = ((loff_t) page) << this->page_shift;/* Must we save the block contents ? */if (td->options & NAND_BBT_SAVECONTENT) {/* Make it block aligned */to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));len = 1 << this->bbt_erase_shift;res = mtd->read(mtd, to, len, &retlen, buf);if (res < 0) {if (retlen != len) {printk(KERN_INFO "nand_bbt: Error "       "reading block for writing "       "the bad block table\n");return res;}printk(KERN_WARNING "nand_bbt: ECC error "       "while reading block for writing "       "bad block table\n");}/* Read oob data */ops.ooblen = (len >> this->page_shift) * mtd->oobsize;ops.oobbuf = &buf[len];res = mtd->read_oob(mtd, to + mtd->writesize, &ops);if (res < 0 || ops.oobretlen != ops.ooblen)goto outerr;/* Calc the byte offset in the buffer */pageoffs = page - (int)(to >> this->page_shift);offs = pageoffs << this->page_shift;/* Preset the bbt area with 0xff */memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));ooboffs = len + (pageoffs * mtd->oobsize);} else {/* Calc length */len = (size_t) (numblocks >> sft);/* Make it page aligned ! */len = (len + (mtd->writesize - 1)) &~(mtd->writesize - 1);/* Preset the buffer with 0xff */memset(buf, 0xff, len +       (len >> this->page_shift)* mtd->oobsize);offs = 0;ooboffs = len;/* Pattern is located in oob area of first page */memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);}if (td->options & NAND_BBT_VERSION)buf[ooboffs + td->veroffs] = td->version[chip];/* walk through the memory table */for (i = 0; i < numblocks;) {uint8_t dat;dat = this->bbt[bbtoffs + (i >> 2)];for (j = 0; j < 4; j++, i++) {int sftcnt = (i << (3 - sft)) & sftmsk;/* Do not store the reserved bbt blocks ! */buf[offs + (i >> sft)] &=~(msk[dat & 0x03] << sftcnt);dat >>= 2;}}memset(&einfo, 0, sizeof(einfo));einfo.mtd = mtd;einfo.addr = to;einfo.len = 1 << this->bbt_erase_shift;res = nand_erase_nand(mtd, &einfo, 1);if (res < 0)goto outerr;res = scan_write_bbt(mtd, to, len, buf, &buf[len]);if (res < 0)goto outerr;printk(KERN_DEBUG "Bad block table written to 0x%012llx, version "       "0x%02X\n", (unsigned long long)to, td->version[chip]);/* Mark it as used */td->pages[chip] = page;}return 0; outerr:printk(KERN_WARNING       "nand_bbt: Error while writing bad block table %d\n", res);return res;}/** * nand_memory_bbt - [GENERIC] create a memory based bad block table * @mtd:MTD device structure * @bd:descriptor for the good/bad block search pattern * * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks*/static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd){struct nand_chip *this = mtd->priv;bd->options &= ~NAND_BBT_SCANEMPTY;return create_bbt(mtd, this->buffers->databuf, bd, -1);}/** * check_create - [GENERIC] create and write bbt(s) if necessary * @mtd:MTD device structure * @buf:temporary buffer * @bd:descriptor for the good/bad block search pattern * * The function checks the results of the previous call to read_bbt * and creates / updates the bbt(s) if necessary * Creation is necessary if no bbt was found for the chip/device * Update is necessary if one of the tables is missing or the * version nr. of one table is less than the other*/static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd){int i, chips, writeops, chipsel, res;struct nand_chip *this = mtd->priv;struct nand_bbt_descr *td = this->bbt_td;struct nand_bbt_descr *md = this->bbt_md;struct nand_bbt_descr *rd, *rd2;/* Do we have a bbt per chip ? */if (td->options & NAND_BBT_PERCHIP)chips = this->numchips;elsechips = 1;for (i = 0; i < chips; i++) {writeops = 0;rd = NULL;rd2 = NULL;/* Per chip or per device ? */chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;/* Mirrored table avilable ? */if (md) {if (td->pages[i] == -1 && md->pages[i] == -1) {writeops = 0x03;goto create;}if (td->pages[i] == -1) {rd = md;td->version[i] = md->version[i];writeops = 1;goto writecheck;}if (md->pages[i] == -1) {rd = td;md->version[i] = td->version[i];writeops = 2;goto writecheck;}if (td->version[i] == md->version[i]) {rd = td;if (!(td->options & NAND_BBT_VERSION))rd2 = md;goto writecheck;}if (((int8_t) (td->version[i] - md->version[i])) > 0) {rd = td;md->version[i] = td->version[i];writeops = 2;} else {rd = md;td->version[i] = md->version[i];writeops = 1;}goto writecheck;} else {if (td->pages[i] == -1) {writeops = 0x01;goto create;}rd = td;goto writecheck;}create:/* Create the bad block table by scanning the device ? */if (!(td->options & NAND_BBT_CREATE))continue;/* Create the table in memory by scanning the chip(s) */create_bbt(mtd, buf, bd, chipsel);td->version[i] = 1;if (md)md->version[i] = 1;writecheck:/* read back first ? */if (rd)read_abs_bbt(mtd, buf, rd, chipsel);/* If they weren't versioned, read both. */if (rd2)read_abs_bbt(mtd, buf, rd2, chipsel);/* Write the bad block table to the device ? */if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {res = write_bbt(mtd, buf, td, md, chipsel);if (res < 0)return res;}/* Write the mirror bad block table to the device ? */if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {res = write_bbt(mtd, buf, md, td, chipsel);if (res < 0)return res;}}return 0;}/** * mark_bbt_regions - [GENERIC] mark the bad block table regions * @mtd:MTD device structure * @td:bad block table descriptor * * The bad block table regions are marked as "bad" to prevent * accidental erasures / writes. The regions are identified by * the mark 0x02.*/static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td){struct nand_chip *this = mtd->priv;int i, j, chips, block, nrblocks, update;uint8_t oldval, newval;/* Do we have a bbt per chip ? */if (td->options & NAND_BBT_PERCHIP) {chips = this->numchips;nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);} else {chips = 1;nrblocks = (int)(mtd->size >> this->bbt_erase_shift);}for (i = 0; i < chips; i++) {if ((td->options & NAND_BBT_ABSPAGE) ||    !(td->options & NAND_BBT_WRITE)) {if (td->pages[i] == -1)continue;block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);block <<= 1;oldval = this->bbt[(block >> 3)];newval = oldval | (0x2 << (block & 0x06));this->bbt[(block >> 3)] = newval;if ((oldval != newval) && td->reserved_block_code)nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));continue;}update = 0;if (td->options & NAND_BBT_LASTBLOCK)block = ((i + 1) * nrblocks) - td->maxblocks;elseblock = i * nrblocks;block <<= 1;for (j = 0; j < td->maxblocks; j++) {oldval = this->bbt[(block >> 3)];newval = oldval | (0x2 << (block & 0x06));this->bbt[(block >> 3)] = newval;if (oldval != newval)update = 1;block += 2;}/* If we want reserved blocks to be recorded to flash, and some   new ones have been marked, then we need to update the stored   bbts.  This should only happen once. */if (update && td->reserved_block_code)nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));}}/** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) * @mtd:MTD device structure * @bd:descriptor for the good/bad block search pattern * * The function checks, if a bad block table(s) is/are already * available. If not it scans the device for manufacturer * marked good / bad blocks and writes the bad block table(s) to * the selected place. * * The bad block table memory is allocated here. It must be freed * by calling the nand_free_bbt function. **/int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd){struct nand_chip *this = mtd->priv;int len, res = 0;uint8_t *buf;struct nand_bbt_descr *td = this->bbt_td;struct nand_bbt_descr *md = this->bbt_md;len = mtd->size >> (this->bbt_erase_shift + 2);/* Allocate memory (2bit per block) and clear the memory bad block table */this->bbt = kzalloc(len, GFP_KERNEL);if (!this->bbt) {printk(KERN_ERR "nand_scan_bbt: Out of memory\n");return -ENOMEM;}/* If no primary table decriptor is given, scan the device * to build a memory based bad block table */if (!td) {if ((res = nand_memory_bbt(mtd, bd))) {printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");kfree(this->bbt);this->bbt = NULL;}return res;}/* Allocate a temporary buffer for one eraseblock incl. oob */len = (1 << this->bbt_erase_shift);len += (len >> this->page_shift) * mtd->oobsize;buf = vmalloc(len);if (!buf) {printk(KERN_ERR "nand_bbt: Out of memory\n");kfree(this->bbt);this->bbt = NULL;return -ENOMEM;}/* Is the bbt at a given page ? */if (td->options & NAND_BBT_ABSPAGE) {res = read_abs_bbts(mtd, buf, td, md);} else {/* Search the bad block table using a pattern in oob */res = search_read_bbts(mtd, buf, td, md);}if (res)res = check_create(mtd, buf, bd);/* Prevent the bbt regions from erasing / writing */mark_bbt_region(mtd, td);if (md)mark_bbt_region(mtd, md);vfree(buf);return res;}/** * nand_update_bbt - [NAND Interface] update bad block table(s) * @mtd:MTD device structure * @offs:the offset of the newly marked block * * The function updates the bad block table(s)*/int nand_update_bbt(struct mtd_info *mtd, loff_t offs){struct nand_chip *this = mtd->priv;int len, res = 0, writeops = 0;int chip, chipsel;uint8_t *buf;struct nand_bbt_descr *td = this->bbt_td;struct nand_bbt_descr *md = this->bbt_md;if (!this->bbt || !td)return -EINVAL;/* Allocate a temporary buffer for one eraseblock incl. oob */len = (1 << this->bbt_erase_shift);len += (len >> this->page_shift) * mtd->oobsize;buf = kmalloc(len, GFP_KERNEL);if (!buf) {printk(KERN_ERR "nand_update_bbt: Out of memory\n");return -ENOMEM;}writeops = md != NULL ? 0x03 : 0x01;/* Do we have a bbt per chip ? */if (td->options & NAND_BBT_PERCHIP) {chip = (int)(offs >> this->chip_shift);chipsel = chip;} else {chip = 0;chipsel = -1;}td->version[chip]++;if (md)md->version[chip]++;/* Write the bad block table to the device ? */if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {res = write_bbt(mtd, buf, td, md, chipsel);if (res < 0)goto out;}/* Write the mirror bad block table to the device ? */if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {res = write_bbt(mtd, buf, md, td, chipsel);} out:kfree(buf);return res;}/* Define some generic bad / good block scan pattern which are used * while scanning a device for factory marked good / bad blocks. */static uint8_t scan_ff_pattern[] = { 0xff, 0xff };static struct nand_bbt_descr smallpage_memorybased = {.options = NAND_BBT_SCAN2NDPAGE,.offs = 5,.len = 1,.pattern = scan_ff_pattern};static struct nand_bbt_descr largepage_memorybased = {.options = 0,.offs = 0,.len = 2,.pattern = scan_ff_pattern};static struct nand_bbt_descr smallpage_flashbased = {.options = NAND_BBT_SCAN2NDPAGE,.offs = 5,.len = 1,.pattern = scan_ff_pattern};static struct nand_bbt_descr largepage_flashbased = {.options = NAND_BBT_SCAN2NDPAGE,.offs = 0,.len = 2,.pattern = scan_ff_pattern};static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };static struct nand_bbt_descr agand_flashbased = {.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,.offs = 0x20,.len = 6,.pattern = scan_agand_pattern};/* Generic flash bbt decriptors*/static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };static struct nand_bbt_descr bbt_main_descr = {.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,.offs =8,.len = 4,.veroffs = 12,.maxblocks = 4,.pattern = bbt_pattern};static struct nand_bbt_descr bbt_mirror_descr = {.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,.offs =8,.len = 4,.veroffs = 12,.maxblocks = 4,.pattern = mirror_pattern};/** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device * @mtd:MTD device structure * * This function selects the default bad block table * support for the device and calls the nand_scan_bbt function **/int nand_default_bbt(struct mtd_info *mtd){struct nand_chip *this = mtd->priv;/* Default for AG-AND. We must use a flash based * bad block table as the devices have factory marked * _good_ blocks. Erasing those blocks leads to loss * of the good / bad information, so we _must_ store * this information in a good / bad table during * startup */if (this->options & NAND_IS_AND) {/* Use the default pattern descriptors */if (!this->bbt_td) {this->bbt_td = &bbt_main_descr;this->bbt_md = &bbt_mirror_descr;}this->options |= NAND_USE_FLASH_BBT;return nand_scan_bbt(mtd, &agand_flashbased);}/* Is a flash based bad block table requested ? */if (this->options & NAND_USE_FLASH_BBT) {/* Use the default pattern descriptors */if (!this->bbt_td) {this->bbt_td = &bbt_main_descr;this->bbt_md = &bbt_mirror_descr;}if (!this->badblock_pattern) {this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;}} else {this->bbt_td = NULL;this->bbt_md = NULL;if (!this->badblock_pattern) {this->badblock_pattern = (mtd->writesize > 512) ?    &largepage_memorybased : &smallpage_memorybased;}}return nand_scan_bbt(mtd, this->badblock_pattern);}/** * nand_isbad_bbt - [NAND Interface] Check if a block is bad * @mtd:MTD device structure * @offs:offset in the device * @allowbbt:allow access to bad block table region **/int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt){struct nand_chip *this = mtd->priv;int block;uint8_t res;/* Get block number * 2 */block = (int)(offs >> (this->bbt_erase_shift - 1));res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",      (unsigned int)offs, block >> 1, res);switch ((int)res) {case 0x00:return 0;case 0x01:return 1;case 0x02:return allowbbt ? 0 : 1;}return 1;}EXPORT_SYMBOL(nand_scan_bbt);EXPORT_SYMBOL(nand_default_bbt);

drivers/mtd/nand/nand_ecc.c

nand flash计算ecc相关的 函数,选择不同的ecc校验方式,调用这个文件中不同的函数。这里面有一些默认的校验ecc的方式,如果没有自己实现的话,就会调用这个里面的校验方式。

/* * This file contains an ECC algorithm that detects and corrects 1 bit * errors in a 256 byte block of data. * * drivers/mtd/nand/nand_ecc.c * * Copyright 漏 2008 Koninklijke Philips Electronics NV. *                  Author: Frans Meulenbroeks * * Completely replaces the previous ECC implementation which was written by: *   Steven J. Hill (sjhill@realitydiluted.com) *   Thomas Gleixner (tglx@linutronix.de) * * Information on how this algorithm works and how it was developed * can be found in Documentation/mtd/nand_ecc.txt * * This file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 or (at your option) any * later version. * * This file is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this file; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * *//* * The STANDALONE macro is useful when running the code outside the kernel * e.g. when running the code in a testbed or a benchmark program. * When STANDALONE is used, the module related macros are commented out * as well as the linux include files. * Instead a private definition of mtd_info is given to satisfy the compiler * (the code does not use mtd_info, so the code does not care) */#ifndef STANDALONE#include <linux/types.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <asm/byteorder.h>#else#include <stdint.h>struct mtd_info;#define EXPORT_SYMBOL(x)  /* x */#define MODULE_LICENSE(x)/* x */#define MODULE_AUTHOR(x)/* x */#define MODULE_DESCRIPTION(x)/* x */#define printk printf#define KERN_ERR""#endif/* * invparity is a 256 byte table that contains the odd parity * for each byte. So if the number of bits in a byte is even, * the array element is 1, and when the number of bits is odd * the array eleemnt is 0. */static const char invparity[256] = {1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};/* * bitsperbyte contains the number of bits per byte * this is only used for testing and repairing parity * (a precalculated value slightly improves performance) */static const char bitsperbyte[256] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,};/* * addressbits is a lookup table to filter out the bits from the xor-ed * ecc data that identify the faulty location. * this is only used for repairing parity * see the comments in nand_correct_data for more details */static const char addressbits[256] = {0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f};/** * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte * block * @mtd:MTD block structure * @buf:input buffer with raw data * @code:output buffer with ECC */int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,       unsigned char *code){int i;const uint32_t *bp = (uint32_t *)buf;/* 256 or 512 bytes/ecc  */const uint32_t eccsize_mult =(((struct nand_chip *)mtd->priv)->ecc.size) >> 8;uint32_t cur;/* current value in buffer *//* rp0..rp15..rp17 are the various accumulated parities (per byte) */uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;uint32_t uninitialized_var(rp17);/* to make compiler happy */uint32_t par;/* the cumulative parity for all data */uint32_t tmppar;/* the cumulative parity for this iteration;   for rp12, rp14 and rp16 at the end of the   loop */par = 0;rp4 = 0;rp6 = 0;rp8 = 0;rp10 = 0;rp12 = 0;rp14 = 0;rp16 = 0;/* * The loop is unrolled a number of times; * This avoids if statements to decide on which rp value to update * Also we process the data by longwords. * Note: passing unaligned data might give a performance penalty. * It is assumed that the buffers are aligned. * tmppar is the cumulative sum of this iteration. * needed for calculating rp12, rp14, rp16 and par * also used as a performance improvement for rp6, rp8 and rp10 */for (i = 0; i < eccsize_mult << 2; i++) {cur = *bp++;tmppar = cur;rp4 ^= cur;cur = *bp++;tmppar ^= cur;rp6 ^= tmppar;cur = *bp++;tmppar ^= cur;rp4 ^= cur;cur = *bp++;tmppar ^= cur;rp8 ^= tmppar;cur = *bp++;tmppar ^= cur;rp4 ^= cur;rp6 ^= cur;cur = *bp++;tmppar ^= cur;rp6 ^= cur;cur = *bp++;tmppar ^= cur;rp4 ^= cur;cur = *bp++;tmppar ^= cur;rp10 ^= tmppar;cur = *bp++;tmppar ^= cur;rp4 ^= cur;rp6 ^= cur;rp8 ^= cur;cur = *bp++;tmppar ^= cur;rp6 ^= cur;rp8 ^= cur;cur = *bp++;tmppar ^= cur;rp4 ^= cur;rp8 ^= cur;cur = *bp++;tmppar ^= cur;rp8 ^= cur;cur = *bp++;tmppar ^= cur;rp4 ^= cur;rp6 ^= cur;cur = *bp++;tmppar ^= cur;rp6 ^= cur;cur = *bp++;tmppar ^= cur;rp4 ^= cur;cur = *bp++;tmppar ^= cur;par ^= tmppar;if ((i & 0x1) == 0)rp12 ^= tmppar;if ((i & 0x2) == 0)rp14 ^= tmppar;if (eccsize_mult == 2 && (i & 0x4) == 0)rp16 ^= tmppar;}/* * handle the fact that we use longword operations * we'll bring rp4..rp14..rp16 back to single byte entities by * shifting and xoring first fold the upper and lower 16 bits, * then the upper and lower 8 bits. */rp4 ^= (rp4 >> 16);rp4 ^= (rp4 >> 8);rp4 &= 0xff;rp6 ^= (rp6 >> 16);rp6 ^= (rp6 >> 8);rp6 &= 0xff;rp8 ^= (rp8 >> 16);rp8 ^= (rp8 >> 8);rp8 &= 0xff;rp10 ^= (rp10 >> 16);rp10 ^= (rp10 >> 8);rp10 &= 0xff;rp12 ^= (rp12 >> 16);rp12 ^= (rp12 >> 8);rp12 &= 0xff;rp14 ^= (rp14 >> 16);rp14 ^= (rp14 >> 8);rp14 &= 0xff;if (eccsize_mult == 2) {rp16 ^= (rp16 >> 16);rp16 ^= (rp16 >> 8);rp16 &= 0xff;}/* * we also need to calculate the row parity for rp0..rp3 * This is present in par, because par is now * rp3 rp3 rp2 rp2 in little endian and * rp2 rp2 rp3 rp3 in big endian * as well as * rp1 rp0 rp1 rp0 in little endian and * rp0 rp1 rp0 rp1 in big endian * First calculate rp2 and rp3 */#ifdef __BIG_ENDIANrp2 = (par >> 16);rp2 ^= (rp2 >> 8);rp2 &= 0xff;rp3 = par & 0xffff;rp3 ^= (rp3 >> 8);rp3 &= 0xff;#elserp3 = (par >> 16);rp3 ^= (rp3 >> 8);rp3 &= 0xff;rp2 = par & 0xffff;rp2 ^= (rp2 >> 8);rp2 &= 0xff;#endif/* reduce par to 16 bits then calculate rp1 and rp0 */par ^= (par >> 16);#ifdef __BIG_ENDIANrp0 = (par >> 8) & 0xff;rp1 = (par & 0xff);#elserp1 = (par >> 8) & 0xff;rp0 = (par & 0xff);#endif/* finally reduce par to 8 bits */par ^= (par >> 8);par &= 0xff;/* * and calculate rp5..rp15..rp17 * note that par = rp4 ^ rp5 and due to the commutative property * of the ^ operator we can say: * rp5 = (par ^ rp4); * The & 0xff seems superfluous, but benchmarking learned that * leaving it out gives slightly worse results. No idea why, probably * it has to do with the way the pipeline in pentium is organized. */rp5 = (par ^ rp4) & 0xff;rp7 = (par ^ rp6) & 0xff;rp9 = (par ^ rp8) & 0xff;rp11 = (par ^ rp10) & 0xff;rp13 = (par ^ rp12) & 0xff;rp15 = (par ^ rp14) & 0xff;if (eccsize_mult == 2)rp17 = (par ^ rp16) & 0xff;/* * Finally calculate the ecc bits. * Again here it might seem that there are performance optimisations * possible, but benchmarks showed that on the system this is developed * the code below is the fastest */#ifdef CONFIG_MTD_NAND_ECC_SMCcode[0] =    (invparity[rp7] << 7) |    (invparity[rp6] << 6) |    (invparity[rp5] << 5) |    (invparity[rp4] << 4) |    (invparity[rp3] << 3) |    (invparity[rp2] << 2) |    (invparity[rp1] << 1) |    (invparity[rp0]);code[1] =    (invparity[rp15] << 7) |    (invparity[rp14] << 6) |    (invparity[rp13] << 5) |    (invparity[rp12] << 4) |    (invparity[rp11] << 3) |    (invparity[rp10] << 2) |    (invparity[rp9] << 1)  |    (invparity[rp8]);#elsecode[1] =    (invparity[rp7] << 7) |    (invparity[rp6] << 6) |    (invparity[rp5] << 5) |    (invparity[rp4] << 4) |    (invparity[rp3] << 3) |    (invparity[rp2] << 2) |    (invparity[rp1] << 1) |    (invparity[rp0]);code[0] =    (invparity[rp15] << 7) |    (invparity[rp14] << 6) |    (invparity[rp13] << 5) |    (invparity[rp12] << 4) |    (invparity[rp11] << 3) |    (invparity[rp10] << 2) |    (invparity[rp9] << 1)  |    (invparity[rp8]);#endifif (eccsize_mult == 1)code[2] =    (invparity[par & 0xf0] << 7) |    (invparity[par & 0x0f] << 6) |    (invparity[par & 0xcc] << 5) |    (invparity[par & 0x33] << 4) |    (invparity[par & 0xaa] << 3) |    (invparity[par & 0x55] << 2) |    3;elsecode[2] =    (invparity[par & 0xf0] << 7) |    (invparity[par & 0x0f] << 6) |    (invparity[par & 0xcc] << 5) |    (invparity[par & 0x33] << 4) |    (invparity[par & 0xaa] << 3) |    (invparity[par & 0x55] << 2) |    (invparity[rp17] << 1) |    (invparity[rp16] << 0);return 0;}EXPORT_SYMBOL(nand_calculate_ecc);/** * __nand_correct_data - [NAND Interface] Detect and correct bit error(s) * @buf:raw data read from the chip * @read_ecc:ECC from the chip * @calc_ecc:the ECC calculated from raw data * @eccsize:data bytes per ecc step (256 or 512) * * Detect and correct a 1 bit error for eccsize byte block */int __nand_correct_data(unsigned char *buf,unsigned char *read_ecc, unsigned char *calc_ecc,unsigned int eccsize){unsigned char b0, b1, b2, bit_addr;unsigned int byte_addr;/* 256 or 512 bytes/ecc  */const uint32_t eccsize_mult = eccsize >> 8;/* * b0 to b2 indicate which bit is faulty (if any) * we might need the xor result  more than once, * so keep them in a local var*/#ifdef CONFIG_MTD_NAND_ECC_SMCb0 = read_ecc[0] ^ calc_ecc[0];b1 = read_ecc[1] ^ calc_ecc[1];#elseb0 = read_ecc[1] ^ calc_ecc[1];b1 = read_ecc[0] ^ calc_ecc[0];#endifb2 = read_ecc[2] ^ calc_ecc[2];/* check if there are any bitfaults *//* repeated if statements are slightly more efficient than switch ... *//* ordered in order of likelihood */if ((b0 | b1 | b2) == 0)return 0;/* no error */if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&    (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&    ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||     (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {/* single bit error *//* * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty * byte, cp 5/3/1 indicate the faulty bit. * A lookup table (called addressbits) is used to filter * the bits from the byte they are in. * A marginal optimisation is possible by having three * different lookup tables. * One as we have now (for b0), one for b2 * (that would avoid the >> 1), and one for b1 (with all values * << 4). However it was felt that introducing two more tables * hardly justify the gain. * * The b2 shift is there to get rid of the lowest two bits. * We could also do addressbits[b2] >> 1 but for the * performace it does not make any difference */if (eccsize_mult == 1)byte_addr = (addressbits[b1] << 4) + addressbits[b0];elsebyte_addr = (addressbits[b2 & 0x3] << 8) +    (addressbits[b1] << 4) + addressbits[b0];bit_addr = addressbits[b2 >> 2];/* flip the bit */buf[byte_addr] ^= (1 << bit_addr);return 1;}/* count nr of bits; use table lookup, faster than calculating it */if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)return 1;/* error in ecc data; no action needed */printk(KERN_ERR "uncorrectable error : ");return -1;}EXPORT_SYMBOL(__nand_correct_data);/** * nand_correct_data - [NAND Interface] Detect and correct bit error(s) * @mtd:MTD block structure * @buf:raw data read from the chip * @read_ecc:ECC from the chip * @calc_ecc:the ECC calculated from raw data * * Detect and correct a 1 bit error for 256/512 byte block */int nand_correct_data(struct mtd_info *mtd, unsigned char *buf,      unsigned char *read_ecc, unsigned char *calc_ecc){return __nand_correct_data(buf, read_ecc, calc_ecc,   ((struct nand_chip *)mtd->priv)->ecc.size);}EXPORT_SYMBOL(nand_correct_data);MODULE_LICENSE("GPL");MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");MODULE_DESCRIPTION("Generic NAND ECC support");


drivers/mtd/nand/nand_base.c

nand flash linux驱动最重要的核心层代码,自己的驱动程序多看看这个核心层的调用,就清楚怎么写了。包括flash的识别,识别后扫描坏块,建立坏块表,读写、擦除flash,读写oob,ecc校验,都是在这个里面完成。


/* *  drivers/mtd/nand.c * *  Overview: *   This is the generic MTD driver for NAND flash devices. It should be *   capable of working with almost all NAND chips currently available. *   Basic support for AG-AND chips is provided. * *Additional technical information is available on *http://www.linux-mtd.infradead.org/doc/nand.html * *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) *  2002-2006 Thomas Gleixner (tglx@linutronix.de) * *  Credits: *David Woodhouse for adding multichip support * *Aleph One Ltd. and Toby Churchill Ltd. for supporting the *rework for 2K page size chips * *  TODO: *Enable cached programming for 2k page size chips *Check, if mtd->ecctype should be set to MTD_ECC_HW *if we have HW ecc support. *The AG-AND chips have nice features for speed improvement, *which are not supported yet. Read / program 4 pages in one go. *BBT table is not serialized, has to be fixed * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/err.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <linux/mtd/compatmac.h>#include <linux/mtd/nand_bch.h>#include <linux/interrupt.h>#include <linux/bitops.h>#include <linux/leds.h>#include <asm/io.h>#ifdef CONFIG_MTD_PARTITIONS#include <linux/mtd/partitions.h>#endif/* Define default oob placement schemes for large and small page devices */static struct nand_ecclayout nand_oob_8 = {.eccbytes = 3,.eccpos = {0, 1, 2},.oobfree = {{.offset = 3, .length = 2},{.offset = 6, .length = 2}}};static struct nand_ecclayout nand_oob_16 = {.eccbytes = 6,.eccpos = {0, 1, 2, 3, 6, 7},.oobfree = {{.offset = 8, . length = 8}}};static struct nand_ecclayout nand_oob_64 = {.eccbytes = 24,.eccpos = {   40, 41, 42, 43, 44, 45, 46, 47,   48, 49, 50, 51, 52, 53, 54, 55,   56, 57, 58, 59, 60, 61, 62, 63},.oobfree = {{.offset = 2, .length = 38}}};static struct nand_ecclayout nand_oob_128 = {.eccbytes = 48,.eccpos = {   80, 81, 82, 83, 84, 85, 86, 87,   88, 89, 90, 91, 92, 93, 94, 95,   96, 97, 98, 99, 100, 101, 102, 103,   104, 105, 106, 107, 108, 109, 110, 111,   112, 113, 114, 115, 116, 117, 118, 119,   120, 121, 122, 123, 124, 125, 126, 127},.oobfree = {{.offset = 2, .length = 78}}};static struct nand_ecclayout nand_oob_224 = {.eccbytes = 48,.eccpos = {   80, 81, 82, 83, 84, 85, 86, 87,   88, 89, 90, 91, 92, 93, 94, 95,   96, 97, 98, 99, 100, 101, 102, 103,   104, 105, 106, 107, 108, 109, 110, 111,   112, 113, 114, 115, 116, 117, 118, 119,   120, 121, 122, 123, 124, 125, 126, 127},.oobfree = {{.offset = 2, .length = 78}}};static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,   int new_state);static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,     struct mtd_oob_ops *ops);/* * For devices which display every fart in the system on a separate LED. Is * compiled away when LED support is disabled. */DEFINE_LED_TRIGGER(nand_led_trigger);/** * nand_release_device - [GENERIC] release chip * @mtd:MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device */static void nand_release_device(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;/* De-select the NAND device */chip->select_chip(mtd, -1);/* Release the controller and the chip */spin_lock(&chip->controller->lock);chip->controller->active = NULL;chip->state = FL_READY;wake_up(&chip->controller->wq);spin_unlock(&chip->controller->lock);}/** * nand_read_byte - [DEFAULT] read one byte from the chip * @mtd:MTD device structure * * Default read function for 8bit buswith */static uint8_t nand_read_byte(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;return readb(chip->IO_ADDR_R);}/** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd:MTD device structure * * Default read function for 16bit buswith with * endianess conversion */static uint8_t nand_read_byte16(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R));}/** * nand_read_word - [DEFAULT] read one word from the chip * @mtd:MTD device structure * * Default read function for 16bit buswith without * endianess conversion */static u16 nand_read_word(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;return readw(chip->IO_ADDR_R);}/** * nand_select_chip - [DEFAULT] control CE line * @mtd:MTD device structure * @chipnr:chipnumber to select, -1 for deselect * * Default select function for 1 chip devices. */static void nand_select_chip(struct mtd_info *mtd, int chipnr){struct nand_chip *chip = mtd->priv;switch (chipnr) {case -1:chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);break;case 0:break;default:BUG();}}/** * nand_write_buf - [DEFAULT] write buffer to chip * @mtd:MTD device structure * @buf:data buffer * @len:number of bytes to write * * Default write function for 8bit buswith */static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len){int i;struct nand_chip *chip = mtd->priv;for (i = 0; i < len; i++)writeb(buf[i], chip->IO_ADDR_W);}/** * nand_read_buf - [DEFAULT] read chip data into buffer * @mtd:MTD device structure * @buf:buffer to store date * @len:number of bytes to read * * Default read function for 8bit buswith */static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len){int i;struct nand_chip *chip = mtd->priv;for (i = 0; i < len; i++)buf[i] = readb(chip->IO_ADDR_R);}/** * nand_verify_buf - [DEFAULT] Verify chip data against buffer * @mtd:MTD device structure * @buf:buffer containing the data to compare * @len:number of bytes to compare * * Default verify function for 8bit buswith */static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len){int i;struct nand_chip *chip = mtd->priv;for (i = 0; i < len; i++)if (buf[i] != readb(chip->IO_ADDR_R))return -EFAULT;return 0;}/** * nand_write_buf16 - [DEFAULT] write buffer to chip * @mtd:MTD device structure * @buf:data buffer * @len:number of bytes to write * * Default write function for 16bit buswith */static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len){int i;struct nand_chip *chip = mtd->priv;u16 *p = (u16 *) buf;len >>= 1;for (i = 0; i < len; i++)writew(p[i], chip->IO_ADDR_W);}/** * nand_read_buf16 - [DEFAULT] read chip data into buffer * @mtd:MTD device structure * @buf:buffer to store date * @len:number of bytes to read * * Default read function for 16bit buswith */static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len){int i;struct nand_chip *chip = mtd->priv;u16 *p = (u16 *) buf;len >>= 1;for (i = 0; i < len; i++)p[i] = readw(chip->IO_ADDR_R);}/** * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer * @mtd:MTD device structure * @buf:buffer containing the data to compare * @len:number of bytes to compare * * Default verify function for 16bit buswith */static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len){int i;struct nand_chip *chip = mtd->priv;u16 *p = (u16 *) buf;len >>= 1;for (i = 0; i < len; i++)if (p[i] != readw(chip->IO_ADDR_R))return -EFAULT;return 0;}/** * nand_block_bad - [DEFAULT] Read bad block marker from the chip * @mtd:MTD device structure * @ofs:offset from device start * @getchip:0, if the chip is already selected * * Check, if the block is bad. */static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip){int page, chipnr, res = 0;struct nand_chip *chip = mtd->priv;u16 bad;page = (int)(ofs >> chip->page_shift) & chip->pagemask;if (getchip) {chipnr = (int)(ofs >> chip->chip_shift);nand_get_device(chip, mtd, FL_READING);/* Select the NAND device */chip->select_chip(mtd, chipnr);}if (chip->options & NAND_BUSWIDTH_16) {chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE,      page);bad = cpu_to_le16(chip->read_word(mtd));if (chip->badblockpos & 0x1)bad >>= 8;if ((bad & 0xFF) != 0xff)res = 1;} else {chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);if (chip->read_byte(mtd) != 0xff)res = 1;}if (getchip)nand_release_device(mtd);return res;}/** * nand_default_block_markbad - [DEFAULT] mark a block bad * @mtd:MTD device structure * @ofs:offset from device start * * This is the default implementation, which can be overridden by * a hardware specific driver.*/static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs){struct nand_chip *chip = mtd->priv;uint8_t buf[2] = { 0, 0 };int block, ret;/* Get block number */block = (int)(ofs >> chip->bbt_erase_shift);if (chip->bbt)chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);/* Do we have a flash based bad block table ? */if (chip->options & NAND_USE_FLASH_BBT)ret = nand_update_bbt(mtd, ofs);else {/* We write two bytes, so we dont have to mess with 16 bit * access */nand_get_device(chip, mtd, FL_WRITING);ofs += mtd->oobsize;chip->ops.len = chip->ops.ooblen = 2;chip->ops.datbuf = NULL;chip->ops.oobbuf = buf;chip->ops.ooboffs = chip->badblockpos & ~0x01;ret = nand_do_write_oob(mtd, ofs, &chip->ops);nand_release_device(mtd);}if (!ret)mtd->ecc_stats.badblocks++;return ret;}/** * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd:MTD device structure * Check, if the device is write protected * * The function expects, that the device is already selected */static int nand_check_wp(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;/* Check the WP bit */chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;}/** * nand_block_checkbad - [GENERIC] Check if a block is marked bad * @mtd:MTD device structure * @ofs:offset from device start * @getchip:0, if the chip is already selected * @allowbbt:1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,       int allowbbt){struct nand_chip *chip = mtd->priv;if (!chip->bbt)return chip->block_bad(mtd, ofs, getchip);/* Return info from the table */return nand_isbad_bbt(mtd, ofs, allowbbt);}/* * Wait for the ready pin, after a command * The timeout is catched later. */void nand_wait_ready(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;unsigned long timeo = jiffies + 2;led_trigger_event(nand_led_trigger, LED_FULL);/* wait until command is processed or timeout occures */do {if (chip->dev_ready(mtd))break;touch_softlockup_watchdog();} while (time_before(jiffies, timeo));led_trigger_event(nand_led_trigger, LED_OFF);}EXPORT_SYMBOL_GPL(nand_wait_ready);/** * nand_command - [DEFAULT] Send command to NAND device * @mtd:MTD device structure * @command:the command to be sent * @column:the column address for this command, -1 if none * @page_addr:the page address for this command, -1 if none * * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr){register struct nand_chip *chip = mtd->priv;int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE;/* * Write out the command to the device. */if (command == NAND_CMD_SEQIN) {int readcmd;if (column >= mtd->writesize) {/* OOB area */column -= mtd->writesize;readcmd = NAND_CMD_READOOB;} else if (column < 256) {/* First 256 bytes --> READ0 */readcmd = NAND_CMD_READ0;} else {column -= 256;readcmd = NAND_CMD_READ1;}chip->cmd_ctrl(mtd, readcmd, ctrl);ctrl &= ~NAND_CTRL_CHANGE;}chip->cmd_ctrl(mtd, command, ctrl);/* * Address cycle, when necessary */ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE;/* Serially input address */if (column != -1) {/* Adjust columns for 16 bit buswidth */if (chip->options & NAND_BUSWIDTH_16)column >>= 1;chip->cmd_ctrl(mtd, column, ctrl);ctrl &= ~NAND_CTRL_CHANGE;}if (page_addr != -1) {chip->cmd_ctrl(mtd, page_addr, ctrl);ctrl &= ~NAND_CTRL_CHANGE;chip->cmd_ctrl(mtd, page_addr >> 8, ctrl);/* One more address cycle for devices > 32MiB */if (chip->chipsize > (32 << 20))chip->cmd_ctrl(mtd, page_addr >> 16, ctrl);}chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);/* * program and erase have their own busy handlers * status and sequential in needs no delay */switch (command) {case NAND_CMD_PAGEPROG:case NAND_CMD_ERASE1:case NAND_CMD_ERASE2:case NAND_CMD_SEQIN:case NAND_CMD_STATUS:return;case NAND_CMD_RESET:if (chip->dev_ready)break;udelay(chip->chip_delay);chip->cmd_ctrl(mtd, NAND_CMD_STATUS,       NAND_CTRL_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd,       NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;return;/* This applies to read commands */default:/* * If we don't have access to the busy pin, we apply the given * command delay */if (!chip->dev_ready) {udelay(chip->chip_delay);return;}}/* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ndelay(100);nand_wait_ready(mtd);}/** * nand_command_lp - [DEFAULT] Send command to NAND large page device * @mtd:MTD device structure * @command:the command to be sent * @column:the column address for this command, -1 if none * @page_addr:the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page * devices We dont have the separate regions as we have in the small page * devices.  We must emulate NAND_CMD_READOOB to keep the code compatible. */static void nand_command_lp(struct mtd_info *mtd, unsigned int command,    int column, int page_addr){register struct nand_chip *chip = mtd->priv;/* Emulate NAND_CMD_READOOB */if (command == NAND_CMD_READOOB) {column += mtd->writesize;command = NAND_CMD_READ0;}/* Command latch cycle */chip->cmd_ctrl(mtd, command & 0xff,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);if (column != -1 || page_addr != -1) {int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;/* Serially input address */if (column != -1) {/* Adjust columns for 16 bit buswidth */if (chip->options & NAND_BUSWIDTH_16)column >>= 1;chip->cmd_ctrl(mtd, column, ctrl);ctrl &= ~NAND_CTRL_CHANGE;chip->cmd_ctrl(mtd, column >> 8, ctrl);}if (page_addr != -1) {chip->cmd_ctrl(mtd, page_addr, ctrl);chip->cmd_ctrl(mtd, page_addr >> 8,       NAND_NCE | NAND_ALE);/* One more address cycle for devices > 128MiB */if (chip->chipsize > (128 << 20))chip->cmd_ctrl(mtd, page_addr >> 16,       NAND_NCE | NAND_ALE);}}chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);/* * program and erase have their own busy handlers * status, sequential in, and deplete1 need no delay */switch (command) {case NAND_CMD_CACHEDPROG:case NAND_CMD_PAGEPROG:case NAND_CMD_ERASE1:case NAND_CMD_ERASE2:case NAND_CMD_SEQIN:case NAND_CMD_RNDIN:case NAND_CMD_STATUS:case NAND_CMD_DEPLETE1:return;/* * read error status commands require only a short delay */case NAND_CMD_STATUS_ERROR:case NAND_CMD_STATUS_ERROR0:case NAND_CMD_STATUS_ERROR1:case NAND_CMD_STATUS_ERROR2:case NAND_CMD_STATUS_ERROR3:udelay(chip->chip_delay);return;case NAND_CMD_RESET:if (chip->dev_ready)break;udelay(chip->chip_delay);chip->cmd_ctrl(mtd, NAND_CMD_STATUS,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,       NAND_NCE | NAND_CTRL_CHANGE);while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ;return;case NAND_CMD_RNDOUT:/* No ready / busy check necessary */chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,       NAND_NCE | NAND_CTRL_CHANGE);return;case NAND_CMD_READ0:chip->cmd_ctrl(mtd, NAND_CMD_READSTART,       NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);chip->cmd_ctrl(mtd, NAND_CMD_NONE,       NAND_NCE | NAND_CTRL_CHANGE);/* This applies to read commands */default:/* * If we don't have access to the busy pin, we apply the given * command delay */if (!chip->dev_ready) {udelay(chip->chip_delay);return;}}/* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ndelay(100);nand_wait_ready(mtd);}/** * nand_get_device - [GENERIC] Get chip for selected access * @chip:the nand chip descriptor * @mtd:MTD device structure * @new_state:the state which is requested * * Get the device and lock it for exclusive access */static intnand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state){spinlock_t *lock = &chip->controller->lock;wait_queue_head_t *wq = &chip->controller->wq;DECLARE_WAITQUEUE(wait, current); retry:spin_lock(lock);/* Hardware controller shared among independent devices */if (!chip->controller->active)chip->controller->active = chip;if (chip->controller->active == chip && chip->state == FL_READY) {chip->state = new_state;spin_unlock(lock);return 0;}if (new_state == FL_PM_SUSPENDED) {spin_unlock(lock);return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;}set_current_state(TASK_UNINTERRUPTIBLE);add_wait_queue(wq, &wait);spin_unlock(lock);schedule();remove_wait_queue(wq, &wait);goto retry;}/** * nand_wait - [DEFAULT]  wait until the command is done * @mtd:MTD device structure * @chip:NAND chip structure * * Wait for command done. This applies to erase and program only * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs */static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip){unsigned long timeo = jiffies;int status, state = chip->state;if (state == FL_ERASING)timeo += (HZ * 400) / 1000;elsetimeo += (HZ * 20) / 1000;led_trigger_event(nand_led_trigger, LED_FULL);/* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ndelay(100);if ((state == FL_ERASING) && (chip->options & NAND_IS_AND))chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1);elsechip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);while (time_before(jiffies, timeo)) {if (chip->dev_ready) {if (chip->dev_ready(mtd))break;} else {if (chip->read_byte(mtd) & NAND_STATUS_READY)break;}cond_resched();}led_trigger_event(nand_led_trigger, LED_OFF);status = (int)chip->read_byte(mtd);return status;}/** * nand_read_page_raw - [Intern] read raw page data without ecc * @mtd:mtd info structure * @chip:nand chip info structure * @buf:buffer to store read data * @page:page number to read * * Not for syndrome calculating ecc controllers, which use a special oob layout */static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,      uint8_t *buf, int page){chip->read_buf(mtd, buf, mtd->writesize);chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);return 0;}/** * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc * @mtd:mtd info structure * @chip:nand chip info structure * @buf:buffer to store read data * @page:page number to read * * We need a special oob layout and handling even when OOB isn't used. */static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,      uint8_t *buf, int page){int eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;uint8_t *oob = chip->oob_poi;int steps, size;for (steps = chip->ecc.steps; steps > 0; steps--) {chip->read_buf(mtd, buf, eccsize);buf += eccsize;if (chip->ecc.prepad) {chip->read_buf(mtd, oob, chip->ecc.prepad);oob += chip->ecc.prepad;}chip->read_buf(mtd, oob, eccbytes);oob += eccbytes;if (chip->ecc.postpad) {chip->read_buf(mtd, oob, chip->ecc.postpad);oob += chip->ecc.postpad;}}size = mtd->oobsize - (oob - chip->oob_poi);if (size)chip->read_buf(mtd, oob, size);return 0;}/** * nand_read_page_swecc - [REPLACABLE] software ecc based page read function * @mtd:mtd info structure * @chip:nand chip info structure * @buf:buffer to store read data * @page:page number to read */static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,uint8_t *buf, int page){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *p = buf;uint8_t *ecc_calc = chip->buffers->ecccalc;uint8_t *ecc_code = chip->buffers->ecccode;uint32_t *eccpos = chip->ecc.layout->eccpos;chip->ecc.read_page_raw(mtd, chip, buf, page);for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)chip->ecc.calculate(mtd, p, &ecc_calc[i]);for (i = 0; i < chip->ecc.total; i++)ecc_code[i] = chip->oob_poi[eccpos[i]];eccsteps = chip->ecc.steps;p = buf;for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {int stat;stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);if (stat < 0)mtd->ecc_stats.failed++;elsemtd->ecc_stats.corrected += stat;}return 0;}/** * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function * @mtd:mtd info structure * @chip:nand chip info structure * @data_offs:offset of requested data within the page * @readlen:data length * @bufpoi:buffer to store read data */static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi){int start_step, end_step, num_steps;uint32_t *eccpos = chip->ecc.layout->eccpos;uint8_t *p;int data_col_addr, i, gaps = 0;int datafrag_len, eccfrag_len, aligned_len, aligned_pos;int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;/* Column address wihin the page aligned to ECC size (256bytes). */start_step = data_offs / chip->ecc.size;end_step = (data_offs + readlen - 1) / chip->ecc.size;num_steps = end_step - start_step + 1;/* Data size aligned to ECC ecc.size*/datafrag_len = num_steps * chip->ecc.size;eccfrag_len = num_steps * chip->ecc.bytes;data_col_addr = start_step * chip->ecc.size;/* If we read not a page aligned data */if (data_col_addr != 0)chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);p = bufpoi + data_col_addr;chip->read_buf(mtd, p, datafrag_len);/* Calculate  ECC */for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size)chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]);/* The performance is faster if to position offsets   according to ecc.pos. Let make sure here that   there are no gaps in ecc positions */for (i = 0; i < eccfrag_len - 1; i++) {if (eccpos[i + start_step * chip->ecc.bytes] + 1 !=eccpos[i + start_step * chip->ecc.bytes + 1]) {gaps = 1;break;}}if (gaps) {chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);} else {/* send the command to read the particular ecc bytes *//* take care about buswidth alignment in read_buf */aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1);aligned_len = eccfrag_len;if (eccpos[start_step * chip->ecc.bytes] & (busw - 1))aligned_len++;if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1))aligned_len++;chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1);chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);}for (i = 0; i < eccfrag_len; i++)chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]];p = bufpoi + data_col_addr;for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) {int stat;stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]);if (stat == -1)mtd->ecc_stats.failed++;elsemtd->ecc_stats.corrected += stat;}return 0;}/** * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function * @mtd:mtd info structure * @chip:nand chip info structure * @buf:buffer to store read data * @page:page number to read * * Not for syndrome calculating ecc controllers which need a special oob layout */static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,uint8_t *buf, int page){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *p = buf;uint8_t *ecc_calc = chip->buffers->ecccalc;uint8_t *ecc_code = chip->buffers->ecccode;uint32_t *eccpos = chip->ecc.layout->eccpos;for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {chip->ecc.hwctl(mtd, NAND_ECC_READ);chip->read_buf(mtd, p, eccsize);chip->ecc.calculate(mtd, p, &ecc_calc[i]);}chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);for (i = 0; i < chip->ecc.total; i++)ecc_code[i] = chip->oob_poi[eccpos[i]];eccsteps = chip->ecc.steps;p = buf;for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {int stat;stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);if (stat < 0)mtd->ecc_stats.failed++;elsemtd->ecc_stats.corrected += stat;}return 0;}/** * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first * @mtd:mtd info structure * @chip:nand chip info structure * @buf:buffer to store read data * @page:page number to read * * Hardware ECC for large page chips, require OOB to be read first. * For this ECC mode, the write_page method is re-used from ECC_HW. * These methods read/write ECC from the OOB area, unlike the * ECC_HW_SYNDROME support with multiple ECC steps, follows the * "infix ECC" scheme and reads/writes ECC from the data area, by * overwriting the NAND manufacturer bad block markings. */static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,struct nand_chip *chip, uint8_t *buf, int page){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *p = buf;uint8_t *ecc_code = chip->buffers->ecccode;uint32_t *eccpos = chip->ecc.layout->eccpos;uint8_t *ecc_calc = chip->buffers->ecccalc;/* Read the OOB area first */chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);for (i = 0; i < chip->ecc.total; i++)ecc_code[i] = chip->oob_poi[eccpos[i]];for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {int stat;chip->ecc.hwctl(mtd, NAND_ECC_READ);chip->read_buf(mtd, p, eccsize);chip->ecc.calculate(mtd, p, &ecc_calc[i]);stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL);if (stat < 0)mtd->ecc_stats.failed++;elsemtd->ecc_stats.corrected += stat;}return 0;}/** * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read * @mtd:mtd info structure * @chip:nand chip info structure * @buf:buffer to store read data * @page:page number to read * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,   uint8_t *buf, int page){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *p = buf;uint8_t *oob = chip->oob_poi;for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {int stat;chip->ecc.hwctl(mtd, NAND_ECC_READ);chip->read_buf(mtd, p, eccsize);if (chip->ecc.prepad) {chip->read_buf(mtd, oob, chip->ecc.prepad);oob += chip->ecc.prepad;}chip->ecc.hwctl(mtd, NAND_ECC_READSYN);chip->read_buf(mtd, oob, eccbytes);stat = chip->ecc.correct(mtd, p, oob, NULL);if (stat < 0)mtd->ecc_stats.failed++;elsemtd->ecc_stats.corrected += stat;oob += eccbytes;if (chip->ecc.postpad) {chip->read_buf(mtd, oob, chip->ecc.postpad);oob += chip->ecc.postpad;}}/* Calculate remaining oob bytes */i = mtd->oobsize - (oob - chip->oob_poi);if (i)chip->read_buf(mtd, oob, i);return 0;}/** * nand_transfer_oob - [Internal] Transfer oob to client buffer * @chip:nand chip structure * @oob:oob destination address * @ops:oob ops structure * @len:size of oob to transfer */static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  struct mtd_oob_ops *ops, size_t len){switch(ops->mode) {case MTD_OOB_PLACE:case MTD_OOB_RAW:memcpy(oob, chip->oob_poi + ops->ooboffs, len);return oob + len;case MTD_OOB_AUTO: {struct nand_oobfree *free = chip->ecc.layout->oobfree;uint32_t boffs = 0, roffs = ops->ooboffs;size_t bytes = 0;for(; free->length && len; free++, len -= bytes) {/* Read request not from offset 0 ? */if (unlikely(roffs)) {if (roffs >= free->length) {roffs -= free->length;continue;}boffs = free->offset + roffs;bytes = min_t(size_t, len,      (free->length - roffs));roffs = 0;} else {bytes = min_t(size_t, len, free->length);boffs = free->offset;}memcpy(oob, chip->oob_poi + boffs, bytes);oob += bytes;}return oob;}default:BUG();}return NULL;}/** * nand_do_read_ops - [Internal] Read data with ECC * * @mtd:MTD device structure * @from:offset to read from * @ops:oob ops structure * * Internal function. Called with chip held. */static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,    struct mtd_oob_ops *ops){int chipnr, page, realpage, col, bytes, aligned;struct nand_chip *chip = mtd->priv;struct mtd_ecc_stats stats;int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;int sndcmd = 1;int ret = 0;uint32_t readlen = ops->len;uint32_t oobreadlen = ops->ooblen;uint8_t *bufpoi, *oob, *buf;stats = mtd->ecc_stats;chipnr = (int)(from >> chip->chip_shift);chip->select_chip(mtd, chipnr);realpage = (int)(from >> chip->page_shift);page = realpage & chip->pagemask;col = (int)(from & (mtd->writesize - 1));buf = ops->datbuf;oob = ops->oobbuf;while(1) {bytes = min(mtd->writesize - col, readlen);aligned = (bytes == mtd->writesize);/* Is the current page in the buffer ? */if (realpage != chip->pagebuf || oob) {bufpoi = aligned ? buf : chip->buffers->databuf;if (likely(sndcmd)) {chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);sndcmd = 0;}/* Now read the page into the buffer */if (unlikely(ops->mode == MTD_OOB_RAW))ret = chip->ecc.read_page_raw(mtd, chip,      bufpoi, page);else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);elseret = chip->ecc.read_page(mtd, chip, bufpoi,  page);if (ret < 0)break;/* Transfer not aligned data */if (!aligned) {if (!NAND_SUBPAGE_READ(chip) && !oob)chip->pagebuf = realpage;memcpy(buf, chip->buffers->databuf + col, bytes);}buf += bytes;if (unlikely(oob)) {/* Raw mode does data:oob:data:oob */if (ops->mode != MTD_OOB_RAW) {int toread = min(oobreadlen,chip->ecc.layout->oobavail);if (toread) {oob = nand_transfer_oob(chip,oob, ops, toread);oobreadlen -= toread;}} elsebuf = nand_transfer_oob(chip,buf, ops, mtd->oobsize);}if (!(chip->options & NAND_NO_READRDY)) {/* * Apply delay or wait for ready/busy pin. Do * this before the AUTOINCR check, so no * problems arise if a chip which does auto * increment is marked as NOAUTOINCR by the * board driver. */if (!chip->dev_ready)udelay(chip->chip_delay);elsenand_wait_ready(mtd);}} else {memcpy(buf, chip->buffers->databuf + col, bytes);buf += bytes;}readlen -= bytes;if (!readlen)break;/* For subsequent reads align to page boundary. */col = 0;/* Increment page address */realpage++;page = realpage & chip->pagemask;/* Check, if we cross a chip boundary */if (!page) {chipnr++;chip->select_chip(mtd, -1);chip->select_chip(mtd, chipnr);}/* Check, if the chip supports auto page increment * or if we have hit a block boundary. */if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))sndcmd = 1;}ops->retlen = ops->len - (size_t) readlen;if (oob)ops->oobretlen = ops->ooblen - oobreadlen;if (ret)return ret;if (mtd->ecc_stats.failed - stats.failed)return -EBADMSG;return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;}/** * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd:MTD device structure * @from:offset to read from * @len:number of bytes to read * @retlen:pointer to variable to store the number of read bytes * @buf:the databuffer to put data * * Get hold of the chip and call nand_do_read */static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,     size_t *retlen, uint8_t *buf){struct nand_chip *chip = mtd->priv;int ret;/* Do not allow reads past end of device */if ((from + len) > mtd->size)return -EINVAL;if (!len)return 0;nand_get_device(chip, mtd, FL_READING);chip->ops.len = len;chip->ops.datbuf = buf;chip->ops.oobbuf = NULL;ret = nand_do_read_ops(mtd, from, &chip->ops);*retlen = chip->ops.retlen;nand_release_device(mtd);return ret;}/** * nand_read_oob_std - [REPLACABLE] the most common OOB data read function * @mtd:mtd info structure * @chip:nand chip info structure * @page:page number to read * @sndcmd:flag whether to issue read command or not */static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,     int page, int sndcmd){if (sndcmd) {chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);sndcmd = 0;}chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);return sndcmd;}/** * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC *    with syndromes * @mtd:mtd info structure * @chip:nand chip info structure * @page:page number to read * @sndcmd:flag whether to issue read command or not */static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  int page, int sndcmd){uint8_t *buf = chip->oob_poi;int length = mtd->oobsize;int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;int eccsize = chip->ecc.size;uint8_t *bufpoi = buf;int i, toread, sndrnd = 0, pos;chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);for (i = 0; i < chip->ecc.steps; i++) {if (sndrnd) {pos = eccsize + i * (eccsize + chunk);if (mtd->writesize > 512)chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);elsechip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);} elsesndrnd = 1;toread = min_t(int, length, chunk);chip->read_buf(mtd, bufpoi, toread);bufpoi += toread;length -= toread;}if (length > 0)chip->read_buf(mtd, bufpoi, length);return 1;}/** * nand_write_oob_std - [REPLACABLE] the most common OOB data write function * @mtd:mtd info structure * @chip:nand chip info structure * @page:page number to write */static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,      int page){int status = 0;const uint8_t *buf = chip->oob_poi;int length = mtd->oobsize;chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);chip->write_buf(mtd, buf, length);/* Send command to program the OOB data */chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);status = chip->waitfunc(mtd, chip);return status & NAND_STATUS_FAIL ? -EIO : 0;}/** * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC *     with syndrome - only for large page flash ! * @mtd:mtd info structure * @chip:nand chip info structure * @page:page number to write */static int nand_write_oob_syndrome(struct mtd_info *mtd,   struct nand_chip *chip, int page){int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;int eccsize = chip->ecc.size, length = mtd->oobsize;int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;const uint8_t *bufpoi = chip->oob_poi;/* * data-ecc-data-ecc ... ecc-oob * or * data-pad-ecc-pad-data-pad .... ecc-pad-oob */if (!chip->ecc.prepad && !chip->ecc.postpad) {pos = steps * (eccsize + chunk);steps = 0;} elsepos = eccsize;chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);for (i = 0; i < steps; i++) {if (sndcmd) {if (mtd->writesize <= 512) {uint32_t fill = 0xFFFFFFFF;len = eccsize;while (len > 0) {int num = min_t(int, len, 4);chip->write_buf(mtd, (uint8_t *)&fill,num);len -= num;}} else {pos = eccsize + i * (eccsize + chunk);chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);}} elsesndcmd = 1;len = min_t(int, length, chunk);chip->write_buf(mtd, bufpoi, len);bufpoi += len;length -= len;}if (length > 0)chip->write_buf(mtd, bufpoi, length);chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);status = chip->waitfunc(mtd, chip);return status & NAND_STATUS_FAIL ? -EIO : 0;}/** * nand_do_read_oob - [Intern] NAND read out-of-band * @mtd:MTD device structure * @from:offset to read from * @ops:oob operations description structure * * NAND read out-of-band data from the spare area */static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,    struct mtd_oob_ops *ops){int page, realpage, chipnr, sndcmd = 1;struct nand_chip *chip = mtd->priv;int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;int readlen = ops->ooblen;int len;uint8_t *buf = ops->oobbuf;DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n",__func__, (unsigned long long)from, readlen);if (ops->mode == MTD_OOB_AUTO)len = chip->ecc.layout->oobavail;elselen = mtd->oobsize;if (unlikely(ops->ooboffs >= len)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read ""outside oob\n", __func__);return -EINVAL;}/* Do not allow reads past end of device */if (unlikely(from >= mtd->size ||     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -(from >> chip->page_shift)) * len)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end ""of device\n", __func__);return -EINVAL;}chipnr = (int)(from >> chip->chip_shift);chip->select_chip(mtd, chipnr);/* Shift to get page */realpage = (int)(from >> chip->page_shift);page = realpage & chip->pagemask;while(1) {sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);len = min(len, readlen);buf = nand_transfer_oob(chip, buf, ops, len);if (!(chip->options & NAND_NO_READRDY)) {/* * Apply delay or wait for ready/busy pin. Do this * before the AUTOINCR check, so no problems arise if a * chip which does auto increment is marked as * NOAUTOINCR by the board driver. */if (!chip->dev_ready)udelay(chip->chip_delay);elsenand_wait_ready(mtd);}readlen -= len;if (!readlen)break;/* Increment page address */realpage++;page = realpage & chip->pagemask;/* Check, if we cross a chip boundary */if (!page) {chipnr++;chip->select_chip(mtd, -1);chip->select_chip(mtd, chipnr);}/* Check, if the chip supports auto page increment * or if we have hit a block boundary. */if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))sndcmd = 1;}ops->oobretlen = ops->ooblen;return 0;}/** * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band * @mtd:MTD device structure * @from:offset to read from * @ops:oob operation description structure * * NAND read data and/or out-of-band data */static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops){struct nand_chip *chip = mtd->priv;int ret = -ENOTSUPP;ops->retlen = 0;/* Do not allow reads past end of device */if (ops->datbuf && (from + ops->len) > mtd->size) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read ""beyond end of device\n", __func__);return -EINVAL;}nand_get_device(chip, mtd, FL_READING);switch(ops->mode) {case MTD_OOB_PLACE:case MTD_OOB_AUTO:case MTD_OOB_RAW:break;default:goto out;}if (!ops->datbuf)ret = nand_do_read_oob(mtd, from, ops);elseret = nand_do_read_ops(mtd, from, ops); out:nand_release_device(mtd);return ret;}/** * nand_write_page_raw - [Intern] raw page write function * @mtd:mtd info structure * @chip:nand chip info structure * @buf:data buffer * * Not for syndrome calculating ecc controllers, which use a special oob layout */static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf){chip->write_buf(mtd, buf, mtd->writesize);chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);}/** * nand_write_page_raw_syndrome - [Intern] raw page write function * @mtd:mtd info structure * @chip:nand chip info structure * @buf:data buffer * * We need a special oob layout and handling even when ECC isn't checked. */static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf){int eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;uint8_t *oob = chip->oob_poi;int steps, size;for (steps = chip->ecc.steps; steps > 0; steps--) {chip->write_buf(mtd, buf, eccsize);buf += eccsize;if (chip->ecc.prepad) {chip->write_buf(mtd, oob, chip->ecc.prepad);oob += chip->ecc.prepad;}chip->read_buf(mtd, oob, eccbytes);oob += eccbytes;if (chip->ecc.postpad) {chip->write_buf(mtd, oob, chip->ecc.postpad);oob += chip->ecc.postpad;}}size = mtd->oobsize - (oob - chip->oob_poi);if (size)chip->write_buf(mtd, oob, size);}/** * nand_write_page_swecc - [REPLACABLE] software ecc based page write function * @mtd:mtd info structure * @chip:nand chip info structure * @buf:data buffer */static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,  const uint8_t *buf){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *ecc_calc = chip->buffers->ecccalc;const uint8_t *p = buf;uint32_t *eccpos = chip->ecc.layout->eccpos;/* Software ecc calculation */for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)chip->ecc.calculate(mtd, p, &ecc_calc[i]);for (i = 0; i < chip->ecc.total; i++)chip->oob_poi[eccpos[i]] = ecc_calc[i];chip->ecc.write_page_raw(mtd, chip, buf);}/** * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function * @mtd:mtd info structure * @chip:nand chip info structure * @buf:data buffer */static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,  const uint8_t *buf){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;uint8_t *ecc_calc = chip->buffers->ecccalc;const uint8_t *p = buf;uint32_t *eccpos = chip->ecc.layout->eccpos;for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {chip->ecc.hwctl(mtd, NAND_ECC_WRITE);chip->write_buf(mtd, p, eccsize);chip->ecc.calculate(mtd, p, &ecc_calc[i]);}for (i = 0; i < chip->ecc.total; i++)chip->oob_poi[eccpos[i]] = ecc_calc[i];chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);}/** * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write * @mtd:mtd info structure * @chip:nand chip info structure * @buf:data buffer * * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */static void nand_write_page_syndrome(struct mtd_info *mtd,    struct nand_chip *chip, const uint8_t *buf){int i, eccsize = chip->ecc.size;int eccbytes = chip->ecc.bytes;int eccsteps = chip->ecc.steps;const uint8_t *p = buf;uint8_t *oob = chip->oob_poi;for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {chip->ecc.hwctl(mtd, NAND_ECC_WRITE);chip->write_buf(mtd, p, eccsize);if (chip->ecc.prepad) {chip->write_buf(mtd, oob, chip->ecc.prepad);oob += chip->ecc.prepad;}chip->ecc.calculate(mtd, p, oob);chip->write_buf(mtd, oob, eccbytes);oob += eccbytes;if (chip->ecc.postpad) {chip->write_buf(mtd, oob, chip->ecc.postpad);oob += chip->ecc.postpad;}}/* Calculate remaining oob bytes */i = mtd->oobsize - (oob - chip->oob_poi);if (i)chip->write_buf(mtd, oob, i);}/** * nand_write_page - [REPLACEABLE] write one page * @mtd:MTD device structure * @chip:NAND chip descriptor * @buf:the data to write * @page:page number to write * @cached:cached programming * @raw:use _raw version of write_page */static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,   const uint8_t *buf, int page, int cached, int raw){int status;chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);if (unlikely(raw))chip->ecc.write_page_raw(mtd, chip, buf);elsechip->ecc.write_page(mtd, chip, buf);/* * Cached progamming disabled for now, Not sure if its worth the * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) */cached = 0;if (!cached || !(chip->options & NAND_CACHEPRG)) {chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);status = chip->waitfunc(mtd, chip);/* * See if operation failed and additional status checks are * available */if ((status & NAND_STATUS_FAIL) && (chip->errstat))status = chip->errstat(mtd, chip, FL_WRITING, status,       page);if (status & NAND_STATUS_FAIL)return -EIO;} else {chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);status = chip->waitfunc(mtd, chip);}#ifdef CONFIG_MTD_NAND_VERIFY_WRITE/* Send command to read back the data */chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);if (chip->verify_buf(mtd, buf, mtd->writesize))return -EIO;#endifreturn 0;}/** * nand_fill_oob - [Internal] Transfer client buffer to oob * @chip:nand chip structure * @oob:oob data buffer * @ops:oob ops structure */static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,  struct mtd_oob_ops *ops){size_t len = ops->ooblen;switch(ops->mode) {case MTD_OOB_PLACE:case MTD_OOB_RAW:memcpy(chip->oob_poi + ops->ooboffs, oob, len);return oob + len;case MTD_OOB_AUTO: {struct nand_oobfree *free = chip->ecc.layout->oobfree;uint32_t boffs = 0, woffs = ops->ooboffs;size_t bytes = 0;for(; free->length && len; free++, len -= bytes) {/* Write request not from offset 0 ? */if (unlikely(woffs)) {if (woffs >= free->length) {woffs -= free->length;continue;}boffs = free->offset + woffs;bytes = min_t(size_t, len,      (free->length - woffs));woffs = 0;} else {bytes = min_t(size_t, len, free->length);boffs = free->offset;}memcpy(chip->oob_poi + boffs, oob, bytes);oob += bytes;}return oob;}default:BUG();}return NULL;}#define NOTALIGNED(x)(x & (chip->subpagesize - 1)) != 0/** * nand_do_write_ops - [Internal] NAND write with ECC * @mtd:MTD device structure * @to:offset to write to * @ops:oob operations description structure * * NAND write with ECC */static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,     struct mtd_oob_ops *ops){int chipnr, realpage, page, blockmask, column;struct nand_chip *chip = mtd->priv;uint32_t writelen = ops->len;uint8_t *oob = ops->oobbuf;uint8_t *buf = ops->datbuf;int ret, subpage;ops->retlen = 0;if (!writelen)return 0;/* reject writes, which are not page aligned */if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {printk(KERN_NOTICE "%s: Attempt to write not ""page aligned data\n", __func__);return -EINVAL;}column = to & (mtd->writesize - 1);subpage = column || (writelen & (mtd->writesize - 1));if (subpage && oob)return -EINVAL;chipnr = (int)(to >> chip->chip_shift);chip->select_chip(mtd, chipnr);/* Check, if it is write protected */if (nand_check_wp(mtd))return -EIO;realpage = (int)(to >> chip->page_shift);page = realpage & chip->pagemask;blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;/* Invalidate the page cache, when we write to the cached page */if (to <= (chip->pagebuf << chip->page_shift) &&    (chip->pagebuf << chip->page_shift) < (to + ops->len))chip->pagebuf = -1;/* If we're not given explicit OOB data, let it be 0xFF */if (likely(!oob))memset(chip->oob_poi, 0xff, mtd->oobsize);while(1) {int bytes = mtd->writesize;int cached = writelen > bytes && page != blockmask;uint8_t *wbuf = buf;/* Partial page write ? */if (unlikely(column || writelen < (mtd->writesize - 1))) {cached = 0;bytes = min_t(int, bytes - column, (int) writelen);chip->pagebuf = -1;memset(chip->buffers->databuf, 0xff, mtd->writesize);memcpy(&chip->buffers->databuf[column], buf, bytes);wbuf = chip->buffers->databuf;}if (unlikely(oob))oob = nand_fill_oob(chip, oob, ops);ret = chip->write_page(mtd, chip, wbuf, page, cached,       (ops->mode == MTD_OOB_RAW));if (ret)break;writelen -= bytes;if (!writelen)break;column = 0;buf += bytes;realpage++;page = realpage & chip->pagemask;/* Check, if we cross a chip boundary */if (!page) {chipnr++;chip->select_chip(mtd, -1);chip->select_chip(mtd, chipnr);}}ops->retlen = ops->len - writelen;if (unlikely(oob))ops->oobretlen = ops->ooblen;return ret;}/** * nand_write - [MTD Interface] NAND write with ECC * @mtd:MTD device structure * @to:offset to write to * @len:number of bytes to write * @retlen:pointer to variable to store the number of written bytes * @buf:the data to write * * NAND write with ECC */static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,  size_t *retlen, const uint8_t *buf){struct nand_chip *chip = mtd->priv;int ret;/* Do not allow reads past end of device */if ((to + len) > mtd->size)return -EINVAL;if (!len)return 0;nand_get_device(chip, mtd, FL_WRITING);chip->ops.len = len;chip->ops.datbuf = (uint8_t *)buf;chip->ops.oobbuf = NULL;ret = nand_do_write_ops(mtd, to, &chip->ops);*retlen = chip->ops.retlen;nand_release_device(mtd);return ret;}/** * nand_do_write_oob - [MTD Interface] NAND write out-of-band * @mtd:MTD device structure * @to:offset to write to * @ops:oob operation description structure * * NAND write out-of-band */static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,     struct mtd_oob_ops *ops){int chipnr, page, status, len;struct nand_chip *chip = mtd->priv;DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen);if (ops->mode == MTD_OOB_AUTO)len = chip->ecc.layout->oobavail;elselen = mtd->oobsize;/* Do not allow write past end of page */if ((ops->ooboffs + ops->ooblen) > len) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write ""past end of page\n", __func__);return -EINVAL;}if (unlikely(ops->ooboffs >= len)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start ""write outside oob\n", __func__);return -EINVAL;}/* Do not allow reads past end of device */if (unlikely(to >= mtd->size ||     ops->ooboffs + ops->ooblen >((mtd->size >> chip->page_shift) - (to >> chip->page_shift)) * len)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond ""end of device\n", __func__);return -EINVAL;}chipnr = (int)(to >> chip->chip_shift);chip->select_chip(mtd, chipnr);/* Shift to get page */page = (int)(to >> chip->page_shift);/* * Reset the chip. Some chips (like the Toshiba TC5832DC found in one * of my DiskOnChip 2000 test units) will clear the whole data page too * if we don't do this. I have no clue why, but I seem to have 'fixed' * it in the doc2000 driver in August 1999.  dwmw2. */chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);/* Check, if it is write protected */if (nand_check_wp(mtd))return -EROFS;/* Invalidate the page cache, if we write to the cached page */if (page == chip->pagebuf)chip->pagebuf = -1;memset(chip->oob_poi, 0xff, mtd->oobsize);nand_fill_oob(chip, ops->oobbuf, ops);status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);memset(chip->oob_poi, 0xff, mtd->oobsize);if (status)return status;ops->oobretlen = ops->ooblen;return 0;}/** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band * @mtd:MTD device structure * @to:offset to write to * @ops:oob operation description structure */static int nand_write_oob(struct mtd_info *mtd, loff_t to,  struct mtd_oob_ops *ops){struct nand_chip *chip = mtd->priv;int ret = -ENOTSUPP;ops->retlen = 0;/* Do not allow writes past end of device */if (ops->datbuf && (to + ops->len) > mtd->size) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond ""end of device\n", __func__);return -EINVAL;}nand_get_device(chip, mtd, FL_WRITING);switch(ops->mode) {case MTD_OOB_PLACE:case MTD_OOB_AUTO:case MTD_OOB_RAW:break;default:goto out;}if (!ops->datbuf)ret = nand_do_write_oob(mtd, to, ops);elseret = nand_do_write_ops(mtd, to, ops); out:nand_release_device(mtd);return ret;}/** * single_erease_cmd - [GENERIC] NAND standard block erase command function * @mtd:MTD device structure * @page:the page address of the block which will be erased * * Standard erase command for NAND chips */static void single_erase_cmd(struct mtd_info *mtd, int page){struct nand_chip *chip = mtd->priv;/* Send commands to erase a block */chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);}/** * multi_erease_cmd - [GENERIC] AND specific block erase command function * @mtd:MTD device structure * @page:the page address of the block which will be erased * * AND multi block erase command function * Erase 4 consecutive blocks */static void multi_erase_cmd(struct mtd_info *mtd, int page){struct nand_chip *chip = mtd->priv;/* Send commands to erase a block */chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);}/** * nand_erase - [MTD Interface] erase block(s) * @mtd:MTD device structure * @instr:erase instruction * * Erase one ore more blocks */static int nand_erase(struct mtd_info *mtd, struct erase_info *instr){return nand_erase_nand(mtd, instr, 0);}#define BBT_PAGE_MASK0xffffff3f/** * nand_erase_nand - [Internal] erase block(s) * @mtd:MTD device structure * @instr:erase instruction * @allowbbt:allow erasing the bbt area * * Erase one ore more blocks */int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,    int allowbbt){int page, status, pages_per_block, ret, chipnr;struct nand_chip *chip = mtd->priv;loff_t rewrite_bbt[NAND_MAX_CHIPS]={0};unsigned int bbt_masked_page = 0xffffffff;loff_t len;DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n",__func__, (unsigned long long)instr->addr,(unsigned long long)instr->len);/* Start address must align on block boundary */if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__);return -EINVAL;}/* Length must align on block boundary */if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n",__func__);return -EINVAL;}/* Do not allow erase past end of device */if ((instr->len + instr->addr) > mtd->size) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Erase past end of device\n",__func__);return -EINVAL;}instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;/* Grab the lock and see if the device is available */nand_get_device(chip, mtd, FL_ERASING);/* Shift to get first page */page = (int)(instr->addr >> chip->page_shift);chipnr = (int)(instr->addr >> chip->chip_shift);/* Calculate pages in each block */pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);/* Select the NAND device */chip->select_chip(mtd, chipnr);/* Check, if it is write protected */if (nand_check_wp(mtd)) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n",__func__);instr->state = MTD_ERASE_FAILED;goto erase_exit;}/* * If BBT requires refresh, set the BBT page mask to see if the BBT * should be rewritten. Otherwise the mask is set to 0xffffffff which * can not be matched. This is also done when the bbt is actually * erased to avoid recusrsive updates */if (chip->options & BBT_AUTO_REFRESH && !allowbbt)bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;/* Loop through the pages */len = instr->len;instr->state = MTD_ERASING;while (len) {/* * heck if we have a bad block, we do not erase bad blocks ! */if (nand_block_checkbad(mtd, ((loff_t) page) <<chip->page_shift, 0, allowbbt)) {printk(KERN_WARNING "%s: attempt to erase a bad block ""at page 0x%08x\n", __func__, page);instr->state = MTD_ERASE_FAILED;goto erase_exit;}/* * Invalidate the page cache, if we erase the block which * contains the current cached page */if (page <= chip->pagebuf && chip->pagebuf <    (page + pages_per_block))chip->pagebuf = -1;chip->erase_cmd(mtd, page & chip->pagemask);status = chip->waitfunc(mtd, chip);/* * See if operation failed and additional status checks are * available */if ((status & NAND_STATUS_FAIL) && (chip->errstat))status = chip->errstat(mtd, chip, FL_ERASING,       status, page);/* See if block erase succeeded */if (status & NAND_STATUS_FAIL) {DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, ""page 0x%08x\n", __func__, page);instr->state = MTD_ERASE_FAILED;instr->fail_addr =((loff_t)page << chip->page_shift);goto erase_exit;}/* * If BBT requires refresh, set the BBT rewrite flag to the * page being erased */if (bbt_masked_page != 0xffffffff &&    (page & BBT_PAGE_MASK) == bbt_masked_page)    rewrite_bbt[chipnr] =((loff_t)page << chip->page_shift);/* Increment page address and decrement length */len -= (1 << chip->phys_erase_shift);page += pages_per_block;/* Check, if we cross a chip boundary */if (len && !(page & chip->pagemask)) {chipnr++;chip->select_chip(mtd, -1);chip->select_chip(mtd, chipnr);/* * If BBT requires refresh and BBT-PERCHIP, set the BBT * page mask to see if this BBT should be rewritten */if (bbt_masked_page != 0xffffffff &&    (chip->bbt_td->options & NAND_BBT_PERCHIP))bbt_masked_page = chip->bbt_td->pages[chipnr] &BBT_PAGE_MASK;}}instr->state = MTD_ERASE_DONE; erase_exit:ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;/* Deselect and wake up anyone waiting on the device */nand_release_device(mtd);/* Do call back function */if (!ret)mtd_erase_callback(instr);/* * If BBT requires refresh and erase was successful, rewrite any * selected bad block tables */if (bbt_masked_page == 0xffffffff || ret)return ret;for (chipnr = 0; chipnr < chip->numchips; chipnr++) {if (!rewrite_bbt[chipnr])continue;/* update the BBT for chip */DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt ""(%d:0x%0llx 0x%0x)\n", __func__, chipnr,rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]);nand_update_bbt(mtd, rewrite_bbt[chipnr]);}/* Return more or less happy */return ret;}/** * nand_sync - [MTD Interface] sync * @mtd:MTD device structure * * Sync is actually a wait for chip ready function */static void nand_sync(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__);/* Grab the lock and see if the device is available */nand_get_device(chip, mtd, FL_SYNCING);/* Release it and go back */nand_release_device(mtd);}/** * nand_block_isbad - [MTD Interface] Check if block at offset is bad * @mtd:MTD device structure * @offs:offset relative to mtd start */static int nand_block_isbad(struct mtd_info *mtd, loff_t offs){/* Check for invalid offset */if (offs > mtd->size)return -EINVAL;return nand_block_checkbad(mtd, offs, 1, 0);}/** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad * @mtd:MTD device structure * @ofs:offset relative to mtd start */static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs){struct nand_chip *chip = mtd->priv;int ret;if ((ret = nand_block_isbad(mtd, ofs))) {/* If it was bad already, return success and do nothing. */if (ret > 0)return 0;return ret;}return chip->block_markbad(mtd, ofs);}/** * nand_suspend - [MTD Interface] Suspend the NAND flash * @mtd:MTD device structure */static int nand_suspend(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;return nand_get_device(chip, mtd, FL_PM_SUSPENDED);}/** * nand_resume - [MTD Interface] Resume the NAND flash * @mtd:MTD device structure */static void nand_resume(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;if (chip->state == FL_PM_SUSPENDED)nand_release_device(mtd);elseprintk(KERN_ERR "%s called for a chip which is not "       "in suspended state\n", __func__);}/* * Set default functions */static void nand_set_defaults(struct nand_chip *chip, int busw){/* check for proper chip_delay setup, set 20us if not */if (!chip->chip_delay)chip->chip_delay = 20;/* check, if a user supplied command function given */if (chip->cmdfunc == NULL)chip->cmdfunc = nand_command;/* check, if a user supplied wait function given */if (chip->waitfunc == NULL)chip->waitfunc = nand_wait;if (!chip->select_chip)chip->select_chip = nand_select_chip;if (!chip->read_byte)chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;if (!chip->read_word)chip->read_word = nand_read_word;if (!chip->block_bad)chip->block_bad = nand_block_bad;if (!chip->block_markbad)chip->block_markbad = nand_default_block_markbad;if (!chip->write_buf)chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;if (!chip->read_buf)chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;if (!chip->verify_buf)chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;if (!chip->scan_bbt)chip->scan_bbt = nand_default_bbt;if (!chip->controller) {chip->controller = &chip->hwcontrol;spin_lock_init(&chip->controller->lock);init_waitqueue_head(&chip->controller->wq);}}/* * Get the flash and manufacturer id and lookup if the type is supported */static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,  struct nand_chip *chip,  int busw, int *maf_id){struct nand_flash_dev *type = NULL;int i, dev_id, maf_idx;int tmp_id, tmp_manf;/* Select the device */chip->select_chip(mtd, 0);/* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up */chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);/* Send the command for reading device ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);/* Read manufacturer and device IDs */*maf_id = chip->read_byte(mtd);dev_id = chip->read_byte(mtd);/* Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);/* Read manufacturer and device IDs */tmp_manf = chip->read_byte(mtd);tmp_id = chip->read_byte(mtd);if (tmp_manf != *maf_id || tmp_id != dev_id) {printk(KERN_INFO "%s: second ID read did not match "       "%02x,%02x against %02x,%02x\n", __func__,       *maf_id, dev_id, tmp_manf, tmp_id);return ERR_PTR(-ENODEV);}/* Lookup the flash id */for (i = 0; nand_flash_ids[i].name != NULL; i++) {if (dev_id == nand_flash_ids[i].id) {type =  &nand_flash_ids[i];break;}}if (!type)return ERR_PTR(-ENODEV);if (!mtd->name)mtd->name = type->name;chip->chipsize = (uint64_t)type->chipsize << 20;/* Newer devices have all the information in additional id bytes */if (!type->pagesize) {int extid;/* The 3rd id byte holds MLC / multichip data */chip->cellinfo = chip->read_byte(mtd);/* The 4th id byte is the important one */extid = chip->read_byte(mtd);/* Calc pagesize */mtd->writesize = 1024 << (extid & 0x3);extid >>= 2;/* Calc oobsize */mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);extid >>= 2;/* Calc blocksize. Blocksize is multiples of 64KiB */mtd->erasesize = (64 * 1024) << (extid & 0x03);extid >>= 2;/* Get buswidth information */busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;} else {/* * Old devices have chip data hardcoded in the device id table */mtd->erasesize = type->erasesize;mtd->writesize = type->pagesize;mtd->oobsize = mtd->writesize / 32;busw = type->options & NAND_BUSWIDTH_16;}/* Try to identify manufacturer */for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {if (nand_manuf_ids[maf_idx].id == *maf_id)break;}/* * Check, if buswidth is correct. Hardware drivers should set * chip correct ! */if (busw != (chip->options & NAND_BUSWIDTH_16)) {printk(KERN_INFO "NAND device: Manufacturer ID:"       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,       dev_id, nand_manuf_ids[maf_idx].name, mtd->name);printk(KERN_WARNING "NAND bus width %d instead %d bit\n",       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,       busw ? 16 : 8);return ERR_PTR(-EINVAL);}/* Calculate the address shift from the page size */chip->page_shift = ffs(mtd->writesize) - 1;/* Convert chipsize to number of pages per chip -1. */chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;chip->bbt_erase_shift = chip->phys_erase_shift =ffs(mtd->erasesize) - 1;if (chip->chipsize & 0xffffffff)chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;elsechip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;/* Set the bad block position */chip->badblockpos = mtd->writesize > 512 ?NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;/* Get chip options, preserve non chip based options */chip->options &= ~NAND_CHIPOPTIONS_MSK;chip->options |= type->options & NAND_CHIPOPTIONS_MSK;/* * Set chip as a default. Board drivers can override it, if necessary */chip->options |= NAND_NO_AUTOINCR;/* Check if chip is a not a samsung device. Do not clear the * options for chips which are not having an extended id. */if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;/* Check for AND chips with 4 page planes */if (chip->options & NAND_4PAGE_ARRAY)chip->erase_cmd = multi_erase_cmd;elsechip->erase_cmd = single_erase_cmd;/* Do not replace user supplied command function ! */if (mtd->writesize > 512 && chip->cmdfunc == nand_command)chip->cmdfunc = nand_command_lp;printk(KERN_INFO "NAND device: Manufacturer ID:"       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,       nand_manuf_ids[maf_idx].name, type->name);return type;}/** * nand_scan_ident - [NAND Interface] Scan for the NAND device * @mtd:     MTD device structure * @maxchips:     Number of chips to scan for * * This is the first phase of the normal nand_scan() function. It * reads the flash ID and sets up MTD fields accordingly. * * The mtd->owner field must be set to the module of the caller. */int nand_scan_ident(struct mtd_info *mtd, int maxchips){int i, busw, nand_maf_id;struct nand_chip *chip = mtd->priv;struct nand_flash_dev *type;/* Get buswidth to select the correct functions */busw = chip->options & NAND_BUSWIDTH_16;/* Set the default functions */nand_set_defaults(chip, busw);/* Read the flash type */type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id);if (IS_ERR(type)) {printk(KERN_WARNING "No NAND device found!!!\n");chip->select_chip(mtd, -1);return PTR_ERR(type);}/* Check for a chip array */for (i = 1; i < maxchips; i++) {chip->select_chip(mtd, i);/* See comment in nand_get_flash_type for reset */chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);/* Send the command for reading device ID */chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);/* Read manufacturer and device IDs */if (nand_maf_id != chip->read_byte(mtd) ||    type->id != chip->read_byte(mtd))break;}if (i > 1)printk(KERN_INFO "%d NAND chips detected\n", i);/* Store the number of chips and calc total size for mtd */chip->numchips = i;mtd->size = i * chip->chipsize;return 0;}/** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd:    MTD device structure * * This is the second phase of the normal nand_scan() function. It * fills out all the uninitialized function pointers with the defaults * and scans for a bad block table if appropriate. */int nand_scan_tail(struct mtd_info *mtd){int i;struct nand_chip *chip = mtd->priv;struct nand_ecc_ctrl *ecc = &chip->ecc;if (!(chip->options & NAND_OWN_BUFFERS))chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);if (!chip->buffers)return -ENOMEM;/* Set the internal oob buffer location, just after the page data */chip->oob_poi = chip->buffers->databuf + mtd->writesize;/* * If no default placement scheme is given, select an appropriate one */if (!ecc->layout && (ecc->mode != NAND_ECC_SOFT_BCH)) {switch (mtd->oobsize) {case 8:chip->ecc.layout = &nand_oob_8;break;case 16:chip->ecc.layout = &nand_oob_16;break;case 64:chip->ecc.layout = &nand_oob_64;break;case 128:chip->ecc.layout = &nand_oob_128;break;                case 224:chip->ecc.layout = &nand_oob_224;break;default:printk(KERN_WARNING "No oob scheme defined for "       "oobsize %d\n", mtd->oobsize);BUG();}}if (!chip->write_page)chip->write_page = nand_write_page;/* * check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */switch (chip->ecc.mode) {case NAND_ECC_HW_OOB_FIRST:/* Similar to NAND_ECC_HW, but a separate read_page handle */if (!chip->ecc.calculate || !chip->ecc.correct ||     !chip->ecc.hwctl) {printk(KERN_WARNING "No ECC functions supplied; "       "Hardware ECC not possible\n");BUG();}if (!chip->ecc.read_page)chip->ecc.read_page = nand_read_page_hwecc_oob_first;case NAND_ECC_HW:/* Use standard hwecc read page function ? */if (!chip->ecc.read_page)chip->ecc.read_page = nand_read_page_hwecc;if (!chip->ecc.write_page)chip->ecc.write_page = nand_write_page_hwecc;if (!chip->ecc.read_page_raw)chip->ecc.read_page_raw = nand_read_page_raw;if (!chip->ecc.write_page_raw)chip->ecc.write_page_raw = nand_write_page_raw;if (!chip->ecc.read_oob)chip->ecc.read_oob = nand_read_oob_std;if (!chip->ecc.write_oob)chip->ecc.write_oob = nand_write_oob_std;case NAND_ECC_HW_SYNDROME:if ((!chip->ecc.calculate || !chip->ecc.correct ||     !chip->ecc.hwctl) &&    (!chip->ecc.read_page ||     chip->ecc.read_page == nand_read_page_hwecc ||     !chip->ecc.write_page ||     chip->ecc.write_page == nand_write_page_hwecc)) {printk(KERN_WARNING "No ECC functions supplied; "       "Hardware ECC not possible\n");BUG();}/* Use standard syndrome read/write page function ? */if (!chip->ecc.read_page)chip->ecc.read_page = nand_read_page_syndrome;if (!chip->ecc.write_page)chip->ecc.write_page = nand_write_page_syndrome;if (!chip->ecc.read_page_raw)chip->ecc.read_page_raw = nand_read_page_raw_syndrome;if (!chip->ecc.write_page_raw)chip->ecc.write_page_raw = nand_write_page_raw_syndrome;if (!chip->ecc.read_oob)chip->ecc.read_oob = nand_read_oob_syndrome;if (!chip->ecc.write_oob)chip->ecc.write_oob = nand_write_oob_syndrome;if (mtd->writesize >= chip->ecc.size)break;printk(KERN_WARNING "%d byte HW ECC not possible on "       "%d byte page size, fallback to SW ECC\n",       chip->ecc.size, mtd->writesize);chip->ecc.mode = NAND_ECC_SOFT;case NAND_ECC_SOFT:chip->ecc.calculate = nand_calculate_ecc;chip->ecc.correct = nand_correct_data;chip->ecc.read_page = nand_read_page_swecc;chip->ecc.read_subpage = nand_read_subpage;chip->ecc.write_page = nand_write_page_swecc;chip->ecc.read_page_raw = nand_read_page_raw;chip->ecc.write_page_raw = nand_write_page_raw;chip->ecc.read_oob = nand_read_oob_std;chip->ecc.write_oob = nand_write_oob_std;if (!chip->ecc.size)chip->ecc.size = 256;chip->ecc.bytes = 3;break;case NAND_ECC_NONE:printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "       "This is not recommended !!\n");chip->ecc.read_page = nand_read_page_raw;chip->ecc.write_page = nand_write_page_raw;chip->ecc.read_oob = nand_read_oob_std;chip->ecc.read_page_raw = nand_read_page_raw;chip->ecc.write_page_raw = nand_write_page_raw;chip->ecc.write_oob = nand_write_oob_std;chip->ecc.size = mtd->writesize;chip->ecc.bytes = 0;break;case NAND_ECC_SOFT_BCH:if (!mtd_nand_has_bch()) {pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n");BUG();}ecc->calculate = nand_bch_calculate_ecc;ecc->correct = nand_bch_correct_data;ecc->read_page = nand_read_page_swecc;ecc->read_subpage = nand_read_subpage;ecc->write_page = nand_write_page_swecc;ecc->read_page_raw = nand_read_page_raw;ecc->write_page_raw = nand_write_page_raw;ecc->read_oob = nand_read_oob_std;ecc->write_oob = nand_write_oob_std;/* * Board driver should supply ecc.size and ecc.strength values * to select how many bits are correctable. Otherwise, default * to 4 bits for large page devices. */if (!ecc->size && (mtd->oobsize >= 64)) {ecc->size = 512;ecc->strength = 4;}/* See nand_bch_init() for details. */ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * ecc->size), 8);ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,       &ecc->layout);if (!ecc->priv) {pr_warn("BCH ECC initialization failed!\n");BUG();}break;default:printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",       chip->ecc.mode);BUG();}/* * The number of bytes available for a client to place data into * the out of band area */chip->ecc.layout->oobavail = 0;for (i = 0; chip->ecc.layout->oobfree[i].length&& i < ARRAY_SIZE(chip->ecc.layout->oobfree); i++)chip->ecc.layout->oobavail +=chip->ecc.layout->oobfree[i].length;mtd->oobavail = chip->ecc.layout->oobavail;/* * Set the number of read / write steps for one page depending on ECC * mode */chip->ecc.steps = mtd->writesize / chip->ecc.size;if(chip->ecc.steps * chip->ecc.size != mtd->writesize) {printk(KERN_WARNING "Invalid ecc parameters\n");BUG();}chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;/* * Allow subpage writes up to ecc.steps. Not possible for MLC * FLASH. */if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&    !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {switch(chip->ecc.steps) {case 2:mtd->subpage_sft = 1;break;case 4:case 8:case 16:mtd->subpage_sft = 2;break;}}chip->subpagesize = mtd->writesize >> mtd->subpage_sft;/* Initialize state */chip->state = FL_READY;/* De-select the device */chip->select_chip(mtd, -1);/* Invalidate the pagebuffer reference */chip->pagebuf = -1;/* Fill in remaining MTD driver data */mtd->type = MTD_NANDFLASH;mtd->flags = MTD_CAP_NANDFLASH;mtd->erase = nand_erase;mtd->point = NULL;mtd->unpoint = NULL;mtd->read = nand_read;mtd->write = nand_write;mtd->read_oob = nand_read_oob;mtd->write_oob = nand_write_oob;mtd->sync = nand_sync;mtd->lock = NULL;mtd->unlock = NULL;mtd->suspend = nand_suspend;mtd->resume = nand_resume;mtd->block_isbad = nand_block_isbad;mtd->block_markbad = nand_block_markbad;/* propagate ecc.layout to mtd_info */mtd->ecclayout = chip->ecc.layout;/* Check, if we should skip the bad block table scan */if (chip->options & NAND_SKIP_BBTSCAN)return 0;/* Build bad block table */return chip->scan_bbt(mtd);}/* is_module_text_address() isn't exported, and it's mostly a pointless   test if this is a module _anyway_ -- they'd have to try _really_ hard   to call us from in-kernel code if the core NAND support is modular. */#ifdef MODULE#define caller_is_module() (1)#else#define caller_is_module() \is_module_text_address((unsigned long)__builtin_return_address(0))#endif/** * nand_scan - [NAND Interface] Scan for the NAND device * @mtd:MTD device structure * @maxchips:Number of chips to scan for * * This fills out all the uninitialized function pointers * with the defaults. * The flash ID is read and the mtd/chip structures are * filled with the appropriate values. * The mtd->owner field must be set to the module of the caller * */int nand_scan(struct mtd_info *mtd, int maxchips){int ret;/* Many callers got this wrong, so check for it for a while... */if (!mtd->owner && caller_is_module()) {printk(KERN_CRIT "%s called with NULL mtd->owner!\n",__func__);BUG();}ret = nand_scan_ident(mtd, maxchips);if (!ret)ret = nand_scan_tail(mtd);return ret;}/** * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd:MTD device structure*/void nand_release(struct mtd_info *mtd){struct nand_chip *chip = mtd->priv;if (chip->ecc.mode == NAND_ECC_SOFT_BCH)nand_bch_free((struct nand_bch_control *)chip->ecc.priv);#ifdef CONFIG_MTD_PARTITIONS/* Deregister partitions */del_mtd_partitions(mtd);#endif/* Deregister the device */del_mtd_device(mtd);/* Free bad block table memory */kfree(chip->bbt);if (!(chip->options & NAND_OWN_BUFFERS))kfree(chip->buffers);}EXPORT_SYMBOL_GPL(nand_scan);EXPORT_SYMBOL_GPL(nand_scan_ident);EXPORT_SYMBOL_GPL(nand_scan_tail);EXPORT_SYMBOL_GPL(nand_release);static int __init nand_base_init(void){led_trigger_register_simple("nand-disk", &nand_led_trigger);return 0;}static void __exit nand_base_exit(void){led_trigger_unregister_simple(nand_led_trigger);}module_init(nand_base_init);module_exit(nand_base_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");MODULE_DESCRIPTION("Generic NAND flash driver code");

==========================================================================

分割线,上面是核心层的代码,内核标配,以下是与自己flash驱动编写相关的代码

==========================================================================

先填充一个nand_chip的结构,必备的

    u8 id;struct nand_chip *this = &info->nand_chip;this->options = NAND_CACHEPRG;//芯片特性this->waitfunc = my_nand_waitfunc;//等待芯片完成回调this->select_chip = my_nand_select_chip;//有些nand有几块chip,如果只有一片,直接返回0this->dev_ready = my_nand_dev_ready;//等待设备准备好this->read_word = my_nand_read_word;//读一个字this->read_byte = my_nand_read_byte;//读一个byte,在读id时要用到this->read_buf = my_nand_read_buf;//读取buf,实现自己需要读取的大小this->write_buf = my_nand_write_buf;//写buf,实现需要写数据的大小this->verify_buf = my_nand_verify_buf;//如果是verify写,就会将写入的数读出来跟写的比较this->ecc.mode = NAND_ECC_NONE;//ecc模式,不同的模式读写oob不一样this->ecc.hwctl = my_nand_ecc_hwctl;//如果是硬件ecc,这里选择的是ecc none,直接返回0this->ecc.calculate = my_nand_ecc_calculate;//同上this->ecc.correct = my_nand_ecc_correct;//同上        this->ecc.size = 2048;//2k也大小的ecc大小this->ecc.bytes = 24;//ecc的位数id = nand_read_id(0x0);//this->cmdfunc = my_nand_cmdfunc;//操作命令函数this->ecc.layout = &my_hw_largepage_ecclayout;//与ecc相关的表,具体与平台相关mtd->owner = THIS_MODULE;

剩下的重要的函数就是my_nand_cmdfunc的实现

这个命令函数实现了对芯片的读、写、擦除和读oob,写oob,读id

static void my_nand_cmdfunc(struct mtd_info *mtd, unsigned command,      int column, int page_addr){struct my_nand_info *info = mtd->priv;unsigned cmd_prev;u8 fail_bit,ready_bit,wp_bit,feature;cmd_prev = info->cmd;init_completion(&info->cmd_complete);info->cmd = command;info->page_addr = page_addr;switch (command) {case NAND_CMD_READOOB://读oob命令if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;info->buf_count = mtd->oobsize;info->buf_start = 0;info->cac_size = info->buf_count;if (info->buf_count <= 0)break;nand_page_read_oob(info->data_buff ,page_addr,mtd->oobsize);//根据芯片手册实现break;case NAND_CMD_READ0://读数据命令if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;info->buf_count = mtd->oobsize + mtd->writesize;info->buf_start = 0;info->cac_size = info->buf_count;if (info->buf_count <= 0)break;nand_page_read(info->data_buff,page_addr,info->buf_count);//<span style="font-family: Arial, Helvetica, sans-serif;">//根据芯片手册实现</span>break;case NAND_CMD_SEQIN://在写前会调用这个命令,用于找到页地址和读取写入大小if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;info->buf_count = mtd->oobsize + mtd->writesize - column;info->buf_start = 0;info->seqin_column = column;info->seqin_page_addr = page_addr;complete(&info->cmd_complete);break;case NAND_CMD_PAGEPROG://写命令if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;if (cmd_prev != NAND_CMD_SEQIN) {printk("Prev cmd don't complete...\n");break;}if (info->buf_count <= 0)break;nand_page_program(info->data_buff,info->seqin_page_addr,info->seqin_column,info->buf_start);//根据芯片实现break;case NAND_CMD_RESET://复位芯片/*nand cmd set */nand_reset();//根据芯片实现complete(&info->cmd_complete);break;case NAND_CMD_ERASE1://擦除命令if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;nand_erase_one_block(page_addr);//根据芯片实现info->state = STATE_READY;complete(&info->cmd_complete);break;case NAND_CMD_STATUS://获取芯片状态,读写操作时会查询该状态if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;info->buf_count = 0x1;info->buf_start = 0x0;feature = nand_get_feature(NAND_STATUS_REG);//根据芯片实现wp_bit = NAND_STATUS_WP;ready_bit = ((~feature)&NAND_STATUS_OIP)<<6;if(cmd_prev == NAND_CMD_ERASE1){fail_bit = (feature&NAND_STATUS_EFAIL)>>2;}else if(cmd_prev == NAND_CMD_PAGEPROG){fail_bit = (feature&NAND_STATUS_PFAIL)>>3;}*(unsigned char *)info->data_buff = wp_bit|ready_bit|fail_bit;break;case NAND_CMD_READID://读id命令,芯片扫描时调用该命令if (info->state == STATE_BUSY) {printk("nandflash chip if busy...\n");return;}info->state = STATE_BUSY;info->buf_count = 0x4;info->buf_start = 0;{u8 id0,id1;unsigned char *data =    (unsigned char *)(info->data_buff);id0 = nand_read_id(0x0);//厂家IDid1 = nand_read_id(0x1);//设备ID#ifdef NAND_DEBUGprintk("id_val_l=0x%08x\nid_val_h=0x%08x\n", id0,       id1);#endifdata[0] = id0;data[1] = id1;data[2] = 0x0;//data[3] = 0x15;//extid#ifdef NAND_DEBUGprintk(KERN_ERR       "IDS=============================0x%x\n",       *((int *)(info->data_buff)));#endif  }complete(&info->cmd_complete);break;case NAND_CMD_ERASE2:case NAND_CMD_READ1:complete(&info->cmd_complete);break;default:printk(KERN_ERR "non-supported command.\n");complete(&info->cmd_complete);break;}wait_for_completion_timeout(&info->cmd_complete, timeout);info->state = STATE_READY;}




1 0