MTD中的nand驱动初步分析

el/2024/3/2 11:56:10

下面是Linux MTD中,获取nand flash型号,各个参数,以及硬件特性的函数,其实也就是

nand_get_flash_type,下面对其详细解析:

 

【看此文之前,一些有必要先解释的术语】

1.       Program(编程):此处的编程,不是写软件,写代码,而是对于硬件来说的,可以理解为对硬件编程,只不过其工具是硬件内部的逻辑,而不是你用的软件。对Nand Flash的编程,本质上就是实现写操作,将数据写到Nand Flash里面去,所以对于nand flash,可以简单的理解为program编程=write写(数据)。

2.       Datasheet(数据手册):这个词,本来没啥好说的,接触多了,自然就知道了。但是对于和我类似,最开始接触的时候,就是没搞懂这个词的具体含义。其中文翻译,一般称作,数据手册,意思就是,一个关于描述硬件各个硬件特性,参数以及/或者如何操作,如何使用的文档。

3.       Erasesize / Writesize:这个是Linux MTD中,关于块大小和页大小的别名,第一次见到的时候,把我搞糊涂了,后来才慢慢明白的。因为,nand 操作的写基本单位页,所以,writesize,对应的就是pagesize,页大小。而擦除操作的基本单位是blocksize,块大小,所以也叫它erasesize。在此简单提一下这几个名词,方便和我遇到类似问题的朋友。

4.       Spare Area Redundant Area OOBnand flash中每一页对应一块区域,用于存放校验的ECC数据和其他一些信息,比如上层文件系统放的和自己文件系统相关的数据。这个区域,在Linux MTD相关系统中,被称作oobout of band),可以翻译为带外,也就是nand flash的一个页,可以称作一个bandband之外,对应的就是指那个多出来的,特殊的区域了。而nand flashdatasheet中,一般成为spare area,可译为空闲区域,另外,在ID的含义解释中也叫做redundant area,可译为冗余区域,归根结底,都是一个含义。不要被搞糊涂了就好。

5.       Page Register(页寄存器)nand flash硬件中的一块地方,名字叫做register,实际就是一个数据缓存,一个buffer,用于存放那些从flash读出来或者将要写入到flash中的。其实叫做页缓存,更合适,更容易明白其含义。此页寄存器的大小=页大小+ oob 大小,即pagesize+oob,对于常见的页是2KB的,此页寄存器就是2KB+64=2112字节。

6.       ChipPlane:对于chip,其实任何某个型号的flash,都可以称其是一个chip,但是实际上,此处的chip,是针对内部来说的,也就是某型号的flash,内部有几个chip,比如下面会举例说到的,三星的2GBK9WAG08U1A芯片(可以理解为外部芯片/型号)内部装了2个单片是1GBK9K8G08U0A,此时就称 K9WAG08U1A内部有2chip,而有些单个的chip,内部又包含多个plane,比如上面的K9K8G08U0A内部包含4个单片是2GbPlane。只有搞清楚了此处的chipplane的关系,才能明白后面提到的多页(Multi Plane / Multi Page)编程和交互(interleave)编程的含义。

7.       编程(Program)此处的编程,不是写软件,写代码,而是对于硬件来说的,可以理解为对硬件编程,只不过其工具是硬件内部的逻辑,而不是你用的软件。对Nand Flash的编程,本质上就是实现写操作,将数据写到Nand Flash里面去,所以对于nand flash,可以简单的理解为program编程=write写(数据)。

 

详细代码可以在这里找到:

linux/drivers/mtd/nand/nand_base.c

 

2407/*

2408 * Get the flash and manufacturer id and lookup if the type is supported

2409 */

2410static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,

2411                                                  struct nand_chip *chip,

2412                                                  int busw, int *maf_id)

2413{

2414        struct nand_flash_dev *type = NULL;

2415        int idev_idmaf_idx;

2416        int tmp_idtmp_manf;

2417

/* 选中芯片,才能对其操作。 */

2418        /* Select the device */

2419        chip->select_chip(mtd, 0);

2420

2421        /*

2422         * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)

2423         * after power-up

2424         */

2425        chip->cmdfunc(mtdNAND_CMD_RESET, -1, -1);

2426

/* 发送ReadID的命令:0x90,去驱动芯片的ID信息 */

2427        /* Send the command for reading device ID */

2428        chip->cmdfunc(mtdNAND_CMD_READID, 0x00, -1);

2429

/* 根据datasheet中的定义,第一个字节,简称byte1,是生产厂商的信息,不同的厂商,对应不同的数字。而byte2是芯片类型,不同的nand flash芯片,对应不同的设备ID,也就是一个字节的数字。

关于读取出来的ID的具体含义,可以参考三星K9K8G08U0Adatasheet中解释:

Linux MTD下获取Nand flash各个参数的过程的详细解析 - 东东 - work and job

1.Nand Flash读取出来的各个ID的含义

 */

2430        /* Read manufacturer and device IDs */

2431        *maf_id = chip->read_byte(mtd);

2432        dev_id = chip->read_byte(mtd);

2433

2434        /* Try again to make sure, as some systems the bus-hold or other

2435         * interface concerns can cause random data which looks like a

2436         * possibly credible NAND flash to appear. If the two results do

2437         * not match, ignore the device completely.

2438         */

2439

/* 再次发送ReadID命令,其目的,上面注释代码中说了,有些特殊的系统中,第一次读取的信息,看起来是很正常,但是实际是错的,所以这里读两次,正常的设备,肯定都会一样的,如果两次不一样,那么说明设备有问题,也就直接函数返回了。*/

2440        chip->cmdfunc(mtdNAND_CMD_READID, 0x00, -1);

2441

2442        /* Read manufacturer and device IDs */

2443

2444        tmp_manf = chip->read_byte(mtd);

2445        tmp_id = chip->read_byte(mtd);

2446

2447        if (tmp_manf != *maf_id || tmp_id != dev_id) {

2448                printk(KERN_INFO "%s: second ID read did not match "

2449                       "%02x,%02x against %02x,%02x\n", __func__,

2450                       *maf_iddev_idtmp_manftmp_id);

2451                return ERR_PTR(-ENODEV);

2452        }

2453

/* 下面根据读取出来的flash ID,也就是具体flash芯片,或叫做设备ID,不同的数值,对应不同的容量和物理参数的flash

其中,nand_flash_ids是个预先定义好的数组,其定义在:

drivers\mtd\nand\nand_ids.c中,此处简要摘录如下:

/*

*     Chip ID list

*

*     Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, options

*

*     Pagesize; 0, 256, 512

*     0     get this information from the extended chip ID

+     256  256 Byte page size

*     512  512 Byte page size

*/

struct nand_flash_dev nand_flash_ids[] = {

。。。。。

       /* 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},

。。。。。

}

 

而结构体nand_flash_dev的定义如下:

include\linux\mtd\nand.h 

/**

 * 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;

};

在结构体数组nand_flash_ids[]中,预先定义了,目前所支持的很多类型Nand Flash的具体物理参数,主要是上面结构体中的页大小pagesize,芯片大小chipsize,块大小erasesize,而id变量表示此类型的芯片,用哪个数字来表示。

 

下面代码中,通过刚读取到的设备ID,去和预先定义好的那个结构体数组nand_flash_ids[]中的每一个ID去比较,如果相等,那么说明支持此款nand falsh,而其他的信息,就可以直接从后面几项中直接获得了。

 

其中,有个要注意的是,前面代码注释中也解释了,就是如果pagesize0,那么说明关于pagesize和其他一些信息,要通过读取额外的ID来获得,这也就是待会下面要详细解释的。

而对于旧的一些nand flash,在表项中其pagesize不是0,就可以直接可以从上面的预定义的表里面获得了。

 

比如,对于常见的三星的型号为K9K8G08U0Anand flash,其设备号是0xD3,找到匹配的表项就是;

       {"NAND 1GiB 3,3V 8-bit",  0xD3, 0, 1024, 0, LP_OPTIONS},

因此也就知道,其容量是1024MB,设备相关物理特性是1GiB 3,3V 8-bit了。

而关于pagesize和块大小erasesize此处都是0,就只能另外从后面读取的ID中获得了。

  */

2454        /* Lookup the flash id */

2455        for (i = 0; nand_flash_ids[i].name != NULLi++) {

2456                if (dev_id == nand_flash_ids[i].id) {

2457                        type =  &nand_flash_ids[i];

2458                        break;

2459                }

2460        }

2461

2462        if (!type)

2463                return ERR_PTR(-ENODEV);

2464

2465        if (!mtd->name)

2466                mtd->name = type->name;

2467

/* 此处由于上面表中的chipsizeMB2^10为单位的,所以要左移20位,换算成byte单位 */

2468        chip->chipsize = (uint64_t)type->chipsize << 20;

2469

2470        /* Newer devices have all the information in additional id bytes */

2471        if (!type->pagesize) {

2472                int extid;

/* 解释下面代码第三个字节之前,要先把图标帖出来,才更容易看得懂具体的解释:

Linux MTD下获取Nand flash各个参数的过程的详细解析 - 东东 - work and job

2.Nand Flash 第三个ID的具体含义

由表中定义可以看出:

1. Internal Chip Number

意思是,内部芯片有几颗。有些型号的Nand Flash,为了实现更高的容量,在芯片内部封装了多个芯片,比如三星的K9WAG08U1A容量是2GB,内部是装了2个单片是1GBK9K8G08U0A,对应地,里面要包含2个片选CE1CE2(均是低电平有效),而4GBK9NBG08U5A包含了4片的K9K8G08U0A

 

2. Cell TypeSLC / MLC

bit2&bit3表示的是芯片的类型,是SLC还是某种MLC

Bit2,bit3=0x00  SLC,简单说就是内部单个存储单元,存储一位的数据,所能表示的数值只有01,也就需要两种不同的电压来表示,所以叫做2 LevelCell

Bit2,bit3=0x01/0x10/0x11  4 /8/16 Level Cell,都叫做MLC,其含义是内部单个存储单元设计成可以表示多个,即4/8/16个不同的电压,对应地,可以表示234位的数据。

这类的MLCnand flash,由于单个存储单元,要存储更多的数据,所以内部结构更复杂,读取和写入数据的逻辑更复杂,相对数据出错的几率也比SLC要大。所以,一般MLC的使用,都需要检错和纠错能力更强的硬件或软件算法,以保证数据的正确性。软件实现此类的多位数据的检错和纠错的效率相对较低,一般是硬件本身就已经提供此功能。

对应的其为硬件ECC,也就是Linux内核MTD中的HW_ECC

其他关于SLC/MLC的更详细解释,感兴趣的可以去看另一个帖子:

【简介】如何编写linuxnand flash驱动 v1.0 .pdf

http://www.rayfile.com/zh-cn/files/f513b02b-778b-11de-91d4-0014221b798a/

 

3. Number of Simultaneously Programmed Pages

可以对几个页同时编程/写。此功能简单的说就是,一次性地写多个页的数据到对应的不同的页。对应支持此操作的,硬件上必须要有多个plane,而每个plane,都有一个自己的页寄存器。比如K9K8G08U0A4plane,分别叫做,plane0plane1plane2plane3

它们共分成2组,plane0plane1plane2plane3。如图:

Linux MTD下获取Nand flash各个参数的过程的详细解析 - 东东 - work and job

3.Nand Flash中多页编程对应的多个Plane的组织架构

 

在多页编程时候,只能对某一组中的两个plane操作,不允许类似于plane0plane2plane3一起去做多页编程。以plane0plane1为例,在实现具体的编程动作之前,将你要写入的2个页的数据,分别写入plane0plane1中的页寄存器,然后才能发命令,去实现具体的编程操作。

正是因为多页编程需要底层的多plane支持,底层实现的时候,是同时对多个plane编程,所以,也被叫做Multi Plane Program

 

4. Interleave Program Between Multiple chips

交错,从字面意思就可以看出,此操作涉及对象就不止一个。交错编程,就是对多个chip,交错地进行编程,先对一个编程,充分利用第一个编程过程中需要等待的时间,转去操作另一个,以此实现总体效率的提高。

 

如果支持Interleave Program的话,那么前面的chip number必然大于1

 

5. Cache Program

Cache读:在开始了一次cache读之后,在你把数据读出去的这段时间,nand flash会自动地把下一页的数据读取出来放到页寄存器。

Cache写:在你写入数据的时候,对应的内存中的数据,不是直接写到页寄存器中,而是到了cache buffer中,然后再发cache 写的命令,此时,数据才从cache buffer中,转递到页寄存器中,然后把数据一点点编程到nand flash,此时,你可以去利用页编程的时间,去准备下一次的数据,然后依此地写入下一个页。

 

Cache读或写,是充分利用了读一页数据出来,或者将一页数据写到flash里面去的时间,去准备新的一页的数据,这样就可以实现连续的读或写,大大提高读写效率。

 

 

2.SLC/MLC

*/

2473                /* The 3rd id byte holds MLC / multichip data */

2474                chip->cellinfo = chip->read_byte(mtd);

/* 读取4th ID */

2475                /* The 4th id byte is the important one */

2476                extid = chip->read_byte(mtd);

/* 4th ID的含义,如图

Linux MTD下获取Nand flash各个参数的过程的详细解析 - 东东 - work and job

4.Nand Flash 4ID的具体含义

 

1Page Size

如图,页大小,是bit0bit1组合起来所表示的。

extid & 0x3,就是取得bit0bit1的值,而左移1024位,是因为上面表中的单位是KB2^10=1024。此处关于1024 << (extid & 0x3)这样的写法,再多说一下。

我之前也是看了很长时间,都没看懂,后来才看懂具体的意思的。

1024 << (extid & 0x3) 其实就是

1024 × 1<< (extid & 0x3))= 前面的1024是因为单位是KB,而后面的写法,就是2extid & 0x3的次方,比如,如果extid & 0x33,那么,1<< (extid & 0x3)就是1<<38,对应的上面的8KB

*/

 

2477                /* Calc pagesize */

2478                mtd->writesize = 1024 << (extid & 0x3);

2479                extid >>= 2;

/*

(2)Redundant Area Size(byte/512byte)

前面介绍过了,此处的oob,就是datasheet中的redundant area size就是linux中的oob大小。

上面表中的意思是,512byte,对应8还是16个字节的redundant area

之所以是512字节对应多少个是因为以前的nand flash页大小是512(除了最早的好像是256之外),所以估计是硬件设计就这样设计了,512个字节对应多少个冗余的数据用作oob,而后来的页大小,对应的是512的整数倍,比如2K4K等,所以,此处,可以按照每个512对应几个字节的oob,然后再算页大小是512的多少倍,即:

此处的extid & 0x01算出来的值,对应上面的816,而mtd->writesize >> 9,其实就是

td->writesize /512,到此,才算清楚,为何此处oob是这么算的。

 */

2480                /* Calc oobsize */

2481                mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);

2482                extid >>= 2;

/*

(3)Block Size

具体算法很清楚,算出是64KB的多少倍,得出总大小。

*/

2483                /* Calc blocksize. Blocksize is multiples of 64KiB */

2484                mtd->erasesize = (64 * 1024) << (extid & 0x03);

2485                extid >>= 2;

/*

(4)Organization 

X8/X16,表示的是,硬件I/O位宽(Bus Width)是8位的还是16位的。

目前大多数,都是X8的。

*/

2486                /* Get buswidth information */

2487                busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;

2488

2489        } else {

/*

旧的nand flash的一些参数,是知道设备ID后,可以直接从表中读取出来的。

*/

2490                /*

2491                 * Old devices have chip data hardcoded in the device id table

2492                 */

2493                mtd->erasesize = type->erasesize;

2494                mtd->writesize = type->pagesize;

2495                mtd->oobsize = mtd->writesize / 32;

2496                busw = type->options & NAND_BUSWIDTH_16;

2497        }

2498

/*

根据读取出来的生长厂商的ID,去和表中对应项匹配,找到是哪家的nand flash芯片。

其中,nand_manuf_ids和上面nand_flash_ids类似,也是个预先定义好的数组,其定义和nand_flash_ids同文件:

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"}

};

 

比如最对应的宏和结构体定义在:

include\linux\mtd\nand.h 中:

/*

 * NAND Flash Manufacturer ID Codes

 */

#define NAND_MFR_TOSHIBA   0x98

#define NAND_MFR_SAMSUNG 0xec

#define NAND_MFR_FUJITSU    0x04

#define NAND_MFR_NATIONAL       0x8f

#define NAND_MFR_RENESAS  0x07

#define NAND_MFR_STMICRO  0x20

#define NAND_MFR_HYNIX              0xad

#define NAND_MFR_MICRON           0x2c

#define NAND_MFR_AMD          0x01

 

/**

 * struct nand_manufacturers - NAND Flash Manufacturer ID Structure

 * @name:     Manufacturer name

 * @id:          manufacturer ID code of device.

*/

struct nand_manufacturers {

       int id;

       char * name;

};

 

比如我们读到的是,最常见的0xEC,对照上面的定义,就是Samsung,表示此款nand flash是三星家的。

*/

2499        /* Try to identify manufacturer */

2500        for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {

2501                if (nand_manuf_ids[maf_idx].id == *maf_id)

2502                        break;

2503        }

2504

/*

检测你的驱动中的关于位宽的定义,适合和硬件所一致。

*/

2505        /*

2506         * Check, if buswidth is correct. Hardware drivers should set

2507         * chip correct !

2508         */

2509        if (busw != (chip->options & NAND_BUSWIDTH_16)) {

2510                printk(KERN_INFO "NAND device: Manufacturer ID:"

2511                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,

2512                       dev_idnand_manuf_ids[maf_idx].namemtd->name);

2513                printk(KERN_WARNING "NAND bus width %d instead %d bit\n",

2514                       (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,

2515                       busw ? 16 : 8);

2516                return ERR_PTR(-EINVAL);

2517        }

2518

/*

此处计算的pagesizeblocksize等的shift,是为了后期的对这些值的除操作更加高效而做的。

对于代码中的除操作,如果直接只是/pagesize,则没有直接算出其是2的多少次方,然后用位移操作,更加高效。因此,此处直接计算好是多少个shift,以后的除于pagesizeblocksize,就可以直接用对应的位移操作了。

*/

2519        /* Calculate the address shift from the page size */

2520        chip->page_shift = ffs(mtd->writesize) - 1;

/*

算出mask,为了后期保证传入的地址不越界,所以会对其mask一下。

*/

2521        /* Convert chipsize to number of pages per chip -1. */

2522        chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;

2523

2524        chip->bbt_erase_shift = chip->phys_erase_shift =

2525                ffs(mtd->erasesize) - 1;

/*

这段,貌似是新的kernel里面新加的,而且把chip->chipsize定义换成uint64_t了,支持超过4GB大小的nand flash了,否则,如果你正好是4GB,对于旧的代码chip->chipsizeuint32_t类型的,那么正好就变成0了。

此处之所以去chip->chipsize & 0xffffffff判断是超过4GB,看起来,估计是ffs函数最多支持32位,所以,没法计算超过此大小的ffs

简单说一下,ffs是计算一个数值的第一个被置位的位置,全称好像是 find first set bit,其简单解释如下:

ffs

查找第一个已设置的位

int ffs (int x)

x为要搜索的字。

刚百度了一下,好像还有个对应的函数:ffz,找到第一个0的位置,估计就是find first zero bit了。呵呵。

而且,这些,好像是Linux提供的基本函数库里面的,自己之前都没怎么听说过呢。汗一个先。。。

*/

2526        if (chip->chipsize & 0xffffffff)

2527                chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;

2528        else

2529                chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;

2530

/*

设置坏块的标记位置。

关于nand flashsmall blocklarge block,据我了解,好像就是对应的small pagesizelarge pagesize,而此处的大小,是针对于旧的nand flash,其页大小pagesize512,所以,

Small block就是页大小是512Bnand flash,而larger block就是新的,页大小大于512B的,比如2KB4KB等的nand flash

下面的宏定义在

include\linux\mtd\nand.h 中:

/*

* Constants for oob configuration

*/

#define NAND_SMALL_BADBLOCK_POS        5

#define NAND_LARGE_BADBLOCK_POS         0

约定俗成的,small blocknand ,坏块标记在byte5,而large blocknand flashbyte0

 

关于坏块标记,实际情况更复杂些:

Nand Flash坏块标记位置】

对于2K页的nand flash,标记位置都是页内oob开始处,都是非0xFF表示坏块,

但是,对于是第几页,不同nand flash就有不同的规定了:

有些nand flash,是标记在坏块的第一个页(或者是第二个页,这点是考虑到,万一第一个页是坏的,所以才做此规定的。一般都是在第一个页处做标记),比如三星的多数SLCHynix等;另一些,是在一个块内的最后一页或倒数第二页做此标记,比如samsung MLC , Numonyx等。所以,真正比较完整的检查坏块的做法,至少要检测块内第一,第二,倒数第一,倒数第二页,是否是0xFF,才能比较全面的判断是否是坏块的。

*/

2531        /* Set the bad block position */

2532        chip->badblockpos = mtd->writesize > 512 ?

2533                NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;

2534

/*

获得上面nand id表中的默认设置的那些optionLP_OPTIONS(如果是X16则是,LP_OPTIONS16)。

*/

2535        /* Get chip options, preserve non chip based options */

2536        chip->options &= ~NAND_CHIPOPTIONS_MSK;

2537        chip->options |= type->options & NAND_CHIPOPTIONS_MSK;

2538

/*

自动增加页数??? 没太搞懂啥意思,估计是cache program/read相关的吧,目前据我了解的,好像页只有cache program/read,能和auto increment pages有点关系。

*/

2539        /*

2540         * Set chip as a default. Board drivers can override it, if necessary

2541         */

2542        chip->options |= NAND_NO_AUTOINCR;

2543

/*

如果有extentID且不是三星的nand flash,则清除掉上面我们默认设置的那些参数:LP_OPTIONS

*/

2544        /* Check if chip is a not a samsung device. Do not clear the

2545         * options for chips which are not having an extended id.

2546         */

2547        if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)

2548                chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;

2549

/*

一种特殊的nand flashAND chip。所以,也要赋值给特殊的擦除函数。

具体关于此类nand flash的介绍,感兴趣的自己参考上面drivers\mtd\nand\nand_ids.cnand_flash_ids数组中的解释。

*/

2550        /* Check for AND chips with 4 page planes */

2551        if (chip->options & NAND_4PAGE_ARRAY)

2552                chip->erase_cmd = multi_erase_cmd;

2553        else

2554                chip->erase_cmd = single_erase_cmd;

2555

/*

如果nand flash的页大小是大于512B,也就是2KB4KB等新的,被称作large blocklargepagenand flash,此处的lp,应该也就是large page的缩写。

此类的nand flash比旧的,在发送地址的时候,多一个地址周期。具体参考datasheet

*/

2556        /* Do not replace user supplied command function ! */

2557        if (mtd->writesize > 512 && chip->cmdfunc == nand_command)

2558                chip->cmdfunc = nand_command_lp;

2559

/*

终于检测完所有需要的信息了。最后打印出nand flash的相关信息。

*/

2560        printk(KERN_INFO "NAND device: Manufacturer ID:"

2561               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_iddev_id,

2562               nand_manuf_ids[maf_idx].nametype->name);

2563

/*

活干完了,就可以return回家了,呵呵。

*/

2564        return type;

2565}


http://www.ngui.cc/el/4465817.html

相关文章

malloc()和free()的原理

遇到一笔试题没看懂 修改下面代码&#xff0c;使其正常运行 void getmemory(char *p) {p (char *)malloc(100);strcpy(p, "hello,world"); }int main(void) {char *str NULL;getmemory(str);printf("%s\n", str);free(str);return 0; } 这里bug分析有下…

Constructors and Destructors in C++

原文地址&#xff1a;http://www.cprogramming.com/tutorial/constructor_destructor_ordering.html Constructors and Destructors in C By Andrei Milea Constructor and Destructor Order The process of creating and deleting objects in C is not a trivial task. Ever…

Detail about How VPTR and Virtual table works

原文地址&#xff1a;http://cboard.cprogramming.com/cplusplus-programming/100179-detail-about-how-vptr-virtual-table-works.html Assumption: machine is 32-bit . Here I am going to explain How Virtual table, Virtual pointer for Virtual functions are internall…

解决:No configuration found for the specified action

原文地址:http://javasunnyboy.iteye.com/blog/254753 今天首次使用Struts2&#xff0c;配置一切正常&#xff0c;使用常用tag也正常&#xff0c;但是在使用<s:form>标记时&#xff0c;发现控制台总是输出警告信息&#xff0c; 警告信息内容如下&#xff1a; 警告: N…

android模拟器访问本地站点

原文地址&#xff1a;http://weizhulin.blog.51cto.com/1556324/311704

Struts2常量详解

原文地址&#xff1a;http://riddickbryant.iteye.com/blog/557373 通常struts2加载struts2常量的顺序如下: 1. struts-default.xml&#xff1a;该文件保存在struts2-core-2.0.6.jar文件中。 2. struts-plugin.xml&#xff1a;该文件保存在struts2-Xxx-2.0.6.jar等Struts2插件J…

Spring依赖注入例子

从Spring手册中摘录的一段&#xff0c;有关依赖注入的例子 The following example uses XML-based configuration metadata for setter-based DI. A small part of a Spring XML configuration file specifies some bean definitions: <bean id"exampleBean" clas…

Twitter的禁用口令

原文地址&#xff1a;http://coolshell.cn/articles/2451.html 打开Twitter的注册页面&#xff0c;https://twitter.com/signup&#xff0c;查看一下源码&#xff0c;你会看到一个很长的禁用口令列表&#xff08;见本文最下面&#xff09;&#xff0c;其中的某些口令的确很雷人…

使用库org.json 和 Gson 解析 JSON格式字符串

org.json库为JSON创始人编写的解析JSON的java库&#xff0c;Gson为Google为我们提供的解析JSON格式数据的库。有关库内容的的下载参见&#xff1a;http://www.json.org 以下是两个简单的测试程序 使用Gson库&#xff1a; public class User {String username;String password;p…

Programs as Data: Function Pointers(函数指针)

原文链接&#xff1a;http://www.cprogramming.com/tutorial/function-pointers.html A function pointer is a variable that stores the address of a function that can later be called through that function pointer. This is useful because functions encapsulate beh…