Linux MTD下获取Nand flash各个参数的过程的详细解析
来源:互联网 发布:javascript:; 编辑:程序博客网 时间:2024/05/17 21:53
Linux MTD下获取Nand flash各个参数的过程的详细解析
version: 1.0
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中解释:
下载 (11.78 KB)
2009-07-29 00:12
图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
*
* 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,而其他的信息,就可以直接从后面几项中直接获得了。
其中,有个要注意的是,前面代码注释中也解释了,就是如果pagesize是0,那么说明关于pagesize和其他一些信息,要通过读取额外的ID来获得,这也就是待会下面要详细解释的。
而对于旧的一些nand flash,在表项中其pagesize不是0,就可以直接可以从上面的预定义的表里面获得了。
比如,对于常见的三星的型号为K9K8G08U0A的nand 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.name != NULL; i++) {
2456 if (dev_id == nand_flash_ids.id) {
2457 type = &nand_flash_ids;
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;
/* 解释下面代码第三个字节之前,要先把图标帖出来,才更容易看得懂具体的解释:
下载 (15.13 KB)
2009-07-29 00:13
图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/fil ... -91d4-0014221b798a/
3. Number of Simultaneously Programmed Pages
可以对几个页同时编程/写。此功能简单的说就是,一次性地写多个页的数据到对应的不同的页。对应支持此操作的,硬件上必须要有多个plane,而每个plane,都有一个自己的页寄存器。比如K9K8G08U0A有4个plane,分别叫做,plane0,plane1,plane2,plane3。
它们共分成2组,plane0和plane1,plane2和plane3。如图:
下载 (30.02 KB)
2009-07-29 00:08
图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的含义,如图
下载 (15.94 KB)
2009-07-29 00:13
图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。
*/
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大小。
上面表中的意思是,512个byte,对应8还是16个字节的redundant area。
之所以是512字节对应多少个是因为以前的nand flash页大小是512(除了最早的好像是256之外),所以估计是硬件设计就这样设计了,512个字节对应多少个冗余的数据用作oob,而后来的页大小,对应的是512的整数倍,比如2K,4K等,所以,此处,可以按照每个512对应几个字节的oob,然后再算页大小是512的多少倍,即:
此处的extid & 0x01算出来的值,对应上面的8或16,而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 }
version: 1.0
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中解释:
下载 (11.78 KB)
2009-07-29 00:12
图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
*
* 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,而其他的信息,就可以直接从后面几项中直接获得了。
其中,有个要注意的是,前面代码注释中也解释了,就是如果pagesize是0,那么说明关于pagesize和其他一些信息,要通过读取额外的ID来获得,这也就是待会下面要详细解释的。
而对于旧的一些nand flash,在表项中其pagesize不是0,就可以直接可以从上面的预定义的表里面获得了。
比如,对于常见的三星的型号为K9K8G08U0A的nand 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.name != NULL; i++) {
2456 if (dev_id == nand_flash_ids.id) {
2457 type = &nand_flash_ids;
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;
/* 解释下面代码第三个字节之前,要先把图标帖出来,才更容易看得懂具体的解释:
下载 (15.13 KB)
2009-07-29 00:13
图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/fil ... -91d4-0014221b798a/
3. Number of Simultaneously Programmed Pages
可以对几个页同时编程/写。此功能简单的说就是,一次性地写多个页的数据到对应的不同的页。对应支持此操作的,硬件上必须要有多个plane,而每个plane,都有一个自己的页寄存器。比如K9K8G08U0A有4个plane,分别叫做,plane0,plane1,plane2,plane3。
它们共分成2组,plane0和plane1,plane2和plane3。如图:
下载 (30.02 KB)
2009-07-29 00:08
图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的含义,如图
下载 (15.94 KB)
2009-07-29 00:13
图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。
*/
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大小。
上面表中的意思是,512个byte,对应8还是16个字节的redundant area。
之所以是512字节对应多少个是因为以前的nand flash页大小是512(除了最早的好像是256之外),所以估计是硬件设计就这样设计了,512个字节对应多少个冗余的数据用作oob,而后来的页大小,对应的是512的整数倍,比如2K,4K等,所以,此处,可以按照每个512对应几个字节的oob,然后再算页大小是512的多少倍,即:
此处的extid & 0x01算出来的值,对应上面的8或16,而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 }
0
上一篇:程序的自我改写
下一篇:笔试必考-C语言之sizeof详解
相关热门文章
- SecureCRT提示"数据库里没找到...
- 世界杰出华商协会集合企业ji...
- PMBOK笔记: 第六章 项目成本管...
- 光明牛奶 守护孩子成长的爱心...
- 卢俊卿倡导净化互联网大环境...
- 承接自动化测试培训、外包、实...
- Solaris PowerTOP 1.0 发布
- For STKMonitor
- busybox的httpd使用CGI脚本(Bu...
- 项目小体会
- 初学UNIX环境高级编程的,关于...
- chinaunix博客什么时候可以设...
- 一个访问量较大网站的服务器。...
- 收音机驱动与v4l2架构的关系,...
- 如何将linux驱动改为裸机驱动(...
给主人留下些什么吧!~~
评论热议
0 0
- Linux MTD下获取Nand flash各个参数的过程的详细解析 (转)
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- 【转载】Linux MTD下获取Nand flash各个参数的过程的详细解析【转】
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- 【转载】上接Linux MTD下获取Nand flash各个参数的过程的详细解析【转】
- Linux MTD驱动下的Nand Flash驱动中 mtd->write_oob和ecc.write_oob
- NAND FLASH学习笔记之MTD下nand flash驱动(七)---我的调试
- NAND FLASH学习笔记之MTD下nand flash驱动(七)---我的调试
- MTD(1)---nand flash的基本知识 .
- MTD(1)---nand flash的基本知识
- MTD(1)---nand flash的基本知识
- MTD(1)---nand flash的基本知识
- MTD分区、NOR flash、NAND flash 的区别
- MTD分区、NOR flash、NAND flash 的区别
- 一个程序,让你清楚区分二进制文件和文本文件
- 本土战略 Ubuntu创始人宣布将发中国版
- 出现单边帐,该如何处理!
- 程序的自我改写
- tcpdump命令详解(整理)
- Linux MTD下获取Nand flash各个参数的过程的详细解析
- windows XP下安装Qt
- Qt-简单程序实例Hello,world
- iconv的转化脚本
- 笔试必考-C语言之sizeof详解
- java链表
- select函数用法详解(以例子剖析)
- Java 的工作原理
- java语言规范
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
汉语拼音韵母
韵母学习
韵母有那些
韵母音节
单韵母双韵母
韵母多少个
韵母有多少个
音节韵母
韵母儿歌
韵母拼音
英语韵母
双韵母
韵母是什么
声母韵母复韵母
所有韵母
韵母声母表
26个韵母
什么叫韵母
学韵母
所有的韵母
韵母读法
哪些是韵母
韵母怎么写
小学韵母
二十四个韵母
特殊韵母有哪些
前韵母有哪些
声母韵母整体
韵母有哪几个
前鼻音韵母有几个
学习声母韵母
韵母有
韵母几个
韵母卡片
汉语拼音韵母有哪些
韵母有几个
韵母ou的字
什么是韵母
声母韵母多少个
韵母o
韵母a