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中解释:
Linux MTD下获取Nand flash各个参数的过程的详细解析 - bsky - 要有追求,要去奋斗! Nand Flash ID Table.gif
下载 (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;
/* 解释下面代码第三个字节之前,要先把图标帖出来,才更容易看得懂具体的解释:
Linux MTD下获取Nand flash各个参数的过程的详细解析 - bsky - 要有追求,要去奋斗! Nand Flash 3rd ID.gif
下载 (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。如图:
Linux MTD下获取Nand flash各个参数的过程的详细解析 - bsky - 要有追求,要去奋斗! Nand Flash Multi Plane Program.gif
下载 (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的含义,如图
Linux MTD下获取Nand flash各个参数的过程的详细解析 - bsky - 要有追求,要去奋斗! Nand Flash 4th ID.gif
下载 (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        }
阅读(573) | 评论(0) | 转发(0) |
0

上一篇:程序的自我改写

下一篇:笔试必考-C语言之sizeof详解

相关热门文章
  • SecureCRT提示"数据库里没找到...
  •  世界杰出华商协会集合企业ji...
  • PMBOK笔记: 第六章 项目成本管...
  • 光明牛奶 守护孩子成长的爱心...
  •  卢俊卿倡导净化互联网大环境...
  • 承接自动化测试培训、外包、实...
  • Solaris PowerTOP 1.0 发布
  • For STKMonitor
  • busybox的httpd使用CGI脚本(Bu...
  • 项目小体会
  • 初学UNIX环境高级编程的,关于...
  • chinaunix博客什么时候可以设...
  • 一个访问量较大网站的服务器。...
  • 收音机驱动与v4l2架构的关系,...
  • 如何将linux驱动改为裸机驱动(...
给主人留下些什么吧!~~
评论热议
0 0