在我们开始NAND 驱动编写之前,至少应该知道:数据在NAND 中是怎样存储的,以及以怎样的方式从NAND 中读写数据的。
![linux <wbr>NAND驱动之二:NAND存储原理](http://hi.csdn.net/attachment/201004/15/0_1271327879lOwX.gif)
1,NAND 的存储结构和操作方式
这方面的资料可以从任意一种NAND 的datasheet 中得到,而且事实上,大多数的NAND datasheet 都大同小异,所不同的大概只是该NAND 芯片的容量大小和读写速度等基本特性。
这里以每页512 字节的NAND FLASH 为例简单说明一下:每一块NAND 芯片由n 个block 组成-> 每一个block 由m 个page 组成-> 每一个page 由256 字节大小的column1( 也称1st half page) 、256 字节大小的column2( 也称2nd half page) 和16 字节大小的oob(out-of-band ,也称spare area) 组成。至于m 和n 的大小可以查看特定NAND 的datasheet 。相应的,若给定NAND 中的一个字节的地址,我们可以根据这个地址算出block 地址( 即第几个block) 、page 地址( 即该block 中的第几个page) 和column 地址( 即1st half page ,或2nd half page ,或oob 中的第几个字节) 。
在擦除NAND 时,必须每次至少擦除1 个block ;在写NAND 时,必须每次写1 个page( 有些NAND 也支持写不足一个page 大小的数据) ;在读NAND 时,分为三种情况( 对应三种不同的NAND 命令) ,即读column1 、读column2 和读oob ,那么为什么要分这三种情况呢?这是因为:基于MTD 的NAND 驱动在读写NAND 时,可以分两种情况,即:(1) 不进行ECC 检测时,一次读写一整个page 中的MAIN 部分( 也就是那真实存储数据的512 字节) ;(2) 进行ECC 检测时( 不管是hardware ECC 还是software ECC) ,一次读写一整个page( 包括16 字节的oob 部分) 。所以部分NAND 所支持的写不足一个page 大小数据的功能,对MTD 来说是用不着的。
那么,如果只需要读写不足一个page 大小的数据怎么办?这是MTD 更上层的部分需要处理的事。也就是说,对于NAND 驱动来说,它只会读写整整一个page 的数据!
最后值得一提的是,NAND 驱动有可能只去读oob 部分,这是因为除了ECC 信息之外,坏块信息也存储在oob 之中,NAND 驱动需要读取oob 中描述坏块的那个字节( 通常是每个block 的第一个page 的oob 中的第六个字节) 来判断该block 是不是一个坏块。所以,我们只有在读oob 时,才需要实现精确到读某一个byte 地址的函数。由此,我们也可以额外知道一件事,那就是NAND 驱动中用到的column 地址只在读oob 时才有用,而在其他情况下,column 地址都为0 。
2,ECC 相关的结构体
struct nand_ecclayout {
uint32_t eccbytes;
uint32_t eccpos[64];
uint32_t oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
这是用来定义ECC 在oob 中布局的一个结构体。
前面已经提及过,oob 中主要存储两种信息:坏块信息和ECC 数据。对与small page 的NAND 芯片来说,其中坏块信息占据1 个字节( 一般固定在第六个字节) ,ECC 数据占据三个字节。所以sturct nand_ecclayout 这个结构体,也就是用来告诉那些与ECC 操作无关的函数,Nand 芯片的oob 部分中,哪些字节是用来存储ECC 的( 即不可用作它用的) ,哪些字节是空闲的,即可用的。
其实之所以有这个结构体,主要是因为硬件ECC 的缘故。以写数据为例,在使用硬件ECC 的情况下,那三个字节的ECC 数据是由硬件计算得到,并且写到NAND 芯片的oob 中去的,同时也是由硬件决定写到oob 的哪三个字节中去。这些都是由硬件做的,而NAND 驱动并不知道,所以就需要用这个结构体来告诉驱动了。
所以,在写NAND 驱动时,就有可能需要对这个结构体进行赋值。这里说“有可能”,是因为MTD 对这个结构体有一个默认的赋值,假如这个赋值所定义的ECC 位置与你的硬件一致的话,那就不必在你的驱动中手动赋值了。其实对大多数硬件( 这里所说的硬件,不是指NAND 芯片,而是NAND 控制器) 来说,是不必手动赋值的,但也有许多例外。
现在对struct nand_ecclayout 这个结构体进行一下说明。
uint32_t eccbytes :ECC 的字节数,对于512B-per-page 的NAND 来说,eccbytes = 3 ,如果你需要额外用到oob 中的数据,那么也可以大于3.
uint32_t eccpos[64] :ECC 数据在oob 中的位置,这里之所以是个64 字节的数组,是因为对于2048-per-page 的NAND 来说,它的oob 有64 个字节。而对于512B-per-page 的NAND 来说,可以而且只可以定义它的前16 个字节。
uint32_t oobavail :oob 中可用的字节数,这个值不用赋值,MTD 会根据其它三个变量自动计算得到。
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES] :显示定义空闲的oob 字节。