logo资料库

Linux MTD 下获取Nand flash 各个参数的过程的详细解析.pdf

第1页 / 共14页
第2页 / 共14页
第3页 / 共14页
第4页 / 共14页
第5页 / 共14页
第6页 / 共14页
第7页 / 共14页
第8页 / 共14页
资料共14页,剩余部分请下载后查看
Linux MTD 下获取 Nand flash 各个参数的过程的详细解析 version: 1.0 date:20090728 Author:crifan Mail:green-waste(At)163.com 下面是 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 / OOB:nand flash 中每一页对应一块区域,用于存放校验 的 ECC 数据和其他一些信息,比如上层文件系统放的和自己文件系统相关的数据。这 个区域,在 Linux MTD 相关系统中,被称作 oob(out of band),可以翻译为带外,也就 是 nand flash 的一个页,可以称作一个 band,band 之外,对应的就是指那个多出来的, 特殊的区域了。而 nand flash 的 datasheet 中,一般成为 spare area,可译为空闲区域,另 外,在 ID 的含义解释中也叫做 redundant area,可译为冗余区域,归根结底,都是一个 含义。不要被搞糊涂了就好。 5. Page Register(页寄存器):nand flash 硬件中的一块地方,名字叫做 register,实际就是一 个数据缓存,一个 buffer,用于存放那些从 flash 读出来或者将要写入到 flash 中的。其 实叫做页缓存,更合适,更容易明白其含义。此页寄存器的大小=页大小+ oob 大小, 即 pagesize+oob,对于常见的页是 2KB 的,此页寄存器就是 2KB+64=2112 字节。 6. Chip 和 Plane:对于 chip,其实任何某个型号的 flash,都可以称其是一个 chip,但是实 际上,此处的 chip,是针对内部来说的,也就是某型号的 flash,内部有几个 chip,比如 下面会举例说到的,三星的 2GB 的 K9WAG08U1A 芯片(可以理解为外部芯片/型号) 内部装了 2 个单片是 1GB 的 K9K8G08U0A,此时就称 K9WAG08U1A 内部有 2 个 chip, 而有些单个的 chip,内部又包含多个 plane,比如上面的 K9K8G08U0A 内部包含 4 个单 片是 2Gb 的 Plane。只有搞清楚了此处的 chip 和 plane 的关系,才能明白后面提到的多 页(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 i, dev_id, maf_idx; 2416 int tmp_id, tmp_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(mtd, NAND_CMD_RESET, -1, -1); 2426 /* 发送 ReadID 的命令:0x90,去驱动芯片的 ID 信息 */ 2427 /* Send the command for reading device ID */ 2428 chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); 2429 /* 根据 datasheet 中的定义,第一个字节,简称 byte1,是生产厂商的信息,不同的厂商,对 应不同的数字。而 byte2 是芯片类型,不同的 nand flash 芯片,对应不同的设备 ID,也就是 一个字节的数字。 关于读取出来的 ID 的具体含义,可以参考三星 K9K8G08U0A 的 datasheet 中解释:
图 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(mtd, NAND_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_id, dev_id, tmp_manf, tmp_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 * * * + * */ struct nand_flash_dev nand_flash_ids[] = { Pagesize; 0, 256, 512 0 256 256 Byte page size 512 512 Byte page size get this information from the extended chip ID
0xAC, 0, 512, 0, LP_OPTIONS}, 0xDC, 0, 512, 0, LP_OPTIONS}, /* 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}, /* 4 Gigabit */ {"NAND 512MiB 1,8V 8-bit", {"NAND 512MiB 3,3V 8-bit", {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16}, {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16}, 。。。。。 。。。。。 } 而结构体 nand_flash_dev 的定义如下: include\linux\mtd\nand.h : /** * struct nand_flash_dev - NAND Flash Device ID Structure * @name: * @id: * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 * * * * @erasesize: * @chipsize: Total chipsize in Mega Bytes * @options: Bitfield to store chip relevant options */ struct nand_flash_dev { }; 在结构体数组 nand_flash_ids[]中,预先定义了,目前所支持的很多类型 Nand Flash 的具体 物理参数,主要是上面结构体中的页大小 pagesize,芯片大小 chipsize,块大小 erasesize, 而 id 变量表示此类型的芯片,用哪个数字来表示。 下面代码中,通过刚读取到的设备 ID,去和预先定义好的那个结构体数组 nand_flash_ids[] 中的每一个 ID 去比较,如果相等,那么说明支持此款 nand falsh,而其他的信息,就可以直 接从后面几项中直接获得了。 char *name; int id; unsigned long pagesize; unsigned long chipsize; unsigned long erasesize; unsigned long options; Identify the device type device ID code If the pagesize is 0, then the real pagesize and the eraseize are determined from the extended id bytes in the chip Size of an erase block in the flash device.
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS}, 其中,有个要注意的是,前面代码注释中也解释了,就是如果 pagesize 是 0,那么说明关于 pagesize 和其他一些信息,要通过读取额外的 ID 来获得,这也就是待会下面要详细解释的。 而对于旧的一些 nand flash,在表项中其 pagesize 不是 0,就可以直接可以从上面的预定义 的表里面获得了。 比如,对于常见的三星的型号为 K9K8G08U0A 的 nand flash,其设备号是 0xD3,找到匹配 的表项就是; 因此也就知道,其容量是 1024MB,设备相关物理特性是 1GiB 3,3V 8-bit 了。 而关于 pagesize 和块大小 erasesize 此处都是 0,就只能另外从后面读取的 ID 中获得了。 */ 2454 /* Lookup the flash id */ 2455 for (i = 0; nand_flash_ids[i].name != NULL; i++) { 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 /* 此处由于上面表中的 chipsize 是 MB=2^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; /* 解释下面代码第三个字节之前,要先把图标帖出来,才更容易看得懂具体的解释:
图 2.Nand Flash 第三个 ID 的具体含义 由表中定义可以看出: 1. Internal Chip Number 意思是,内部芯片有几颗。有些型号的 Nand Flash,为了实现更高的容量,在芯片内部封装 了多个芯片,比如三星的 K9WAG08U1A 容量是 2GB,内部是装了 2 个单片是 1GB 的 K9K8G08U0A,对应地,里面要包含 2 个片选 CE1 和 CE2(均是低电平有效),而 4GB 的 K9NBG08U5A 包含了 4 片的 K9K8G08U0A。 2. Cell Type:SLC / MLC bit2&bit3 表示的是芯片的类型,是 SLC 还是某种 MLC。 Bit2,bit3=0x00 : SLC,简单说就是内部单个存储单元,存储一位的数据,所能表示的数值 只有 0,1,也就需要两种不同的电压来表示,所以叫做 2 Level 的 Cell。 Bit2,bit3=0x01/0x10/0x11 : 4 /8/16 Level Cell,都叫做 MLC,其含义是内部单个存储单元 设计成可以表示多个,即 4/8/16 个不同的电压,对应地,可以表示 2,3,4 位的数据。 这类的 MLC 的 nand flash,由于单个存储单元,要存储更多的数据,所以内部结构更复杂, 读取和写入数据的逻辑更复杂,相对数据出错的几率也比 SLC 要大。所以,一般 MLC 的使 用,都需要检错和纠错能力更强的硬件或软件算法,以保证数据的正确性。软件实现此类的 多位数据的检错和纠错的效率相对较低,一般是硬件本身就已经提供此功能。 对应的其为硬件 ECC,也就是 Linux 内核 MTD 中的 HW_ECC。 其他关于 SLC/MLC 的更详细解释,感兴趣的可以去看另一个帖子: 【简介】如何编写 linux 下 nand flash 驱动 v1.0 .pdf http://www.rayfile.com/zh-cn/files/f513b02b-778b-11de-91d4-0014221b798a/ 3. Number of Simultaneously Programmed Pages 可以对几个页同时编程/写。此功能简单的说就是,一次性地写多个页的数据到对应的不同 的页。对应支持此操作的,硬件上必须要有多个 plane,而每个 plane,都有一个自己的页寄 存器。比如 K9K8G08U0A 有 4 个 plane,分别叫做,plane0,plane1,plane2,plane3。 它们共分成 2 组,plane0 和 plane1,plane2 和 plane3。如图:
图 3.Nand Flash 中多页编程对应的多个 Plane 的组织架构 在多页编程时候,只能对某一组中的两个 plane 操作,不允许类似于 plane0 和 plane2 或 plane3 一起去做多页编程。以 plane0 和 plane1 为例,在实现具体的编程动作之前,将你要写入的 2 个页的数据,分别写入 plane0 和 plane1 中的页寄存器,然后才能发命令,去实现具体的 编程操作。 正是因为多页编程需要底层的多 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的含义,如图 图 4.Nand Flash 第 4 个 ID 的具体含义 (1)Page Size: 如图,页大小,是 bit0 和 bit1 组合起来所表示的。 extid & 0x3,就是取得 bit0 和 bit1 的值,而左移 1024 位,是因为上面表中的单位是 KB= 2^10=1024。此处关于 1024 << (extid & 0x3)这样的写法,再多说一下。 我之前也是看了很长时间,都没看懂,后来才看懂具体的意思的。 1024 << (extid & 0x3) 其实就是 1024 × (1<< (extid & 0x3))= 前面的 1024 是因为单位是 KB,而后面的写法,就是 2 的 extid & 0x3 的次方,比如,如果 extid & 0x3 是 3,那么,1<< (extid & 0x3)就是 1<<3=8, 对应的上面的 8KB。 */
分享到:
收藏