(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 */
(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 */
2481mtd->oobsize= (8 << (extid& 0x01)) * (mtd->writesize>> 9);
/*
(3)Block Size:
具体算法很清楚,算出是64KB的多少倍,得出总大小。
*/
2483/* Calc blocksize. Blocksize is multiples of 64KiB */
2484mtd->erasesize= (64 * 1024) << (extid& 0x03);
/*
(4)Organization:
X8/X16,表示的是,硬件I/O位宽(Bus Width)是8位的还是16位的。
目前大多数,都是X8的。
*/
2486/* Get buswidth information */
2489} else {
旧的nand flash的一些参数,是知道设备ID后,可以直接从表中读取出来的。
*/
2491* Old devices have chip data hardcoded in the device id table
/*
根据读取出来的生长厂商的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_TOSHIBA0x98
#define NAND_MFR_SAMSUNG0xec
#define NAND_MFR_FUJITSU0x04
#define NAND_MFR_NATIONAL0x8f
#define NAND_MFR_RENESAS0x07
#define NAND_MFR_STMICRO0x20
#define NAND_MFR_HYNIX0xad
#define NAND_MFR_MICRON0x2c
#define NAND_MFR_AMD0x01
/**
* 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 */
2502break;
/*
检测你的驱动中的关于位宽的定义,适合和硬件所一致。
*/
2506* Check, if buswidth is correct. Hardware drivers should set
2507* chip correct !
2510printk(KERN_INFO"NAND device: Manufacturer ID:"
2511"0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
2513printk(KERN_WARNING"NAND bus width %d instead %d bit\n",
2515busw? 16 : 8);
/*
此处计算的pagesize,blocksize等的shift,是为了后期的对这些值的除操作更加高效而做的。
对于代码中的除操作,如果直接只是/pagesize,则没有直接算出其是2的多少次方,然后用位移操作,更加高效。因此,此处直接计算好是多少个shift,以后的除于pagesize,blocksize,就可以直接用对应的位移操作了。
*/
2519/* Calculate the address shift from the page size */
算出mask,为了后期保证传入的地址不越界,所以会对其mask一下。
*/
2521/* Convert chipsize to number of pages per chip -1. */
/*
这段,貌似是新的kernel里面新加的,而且把chip->chipsize定义换成uint64_t了,支持超过4GB大小的nand flash了,否则,如果你正好是4GB,对于旧的代码chip->chipsize是uint32_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提供的基本函数库里面的,自己之前都没怎么听说过呢。汗一个先。。。
*/
2526if (chip->chipsize& 0xffffffff)
2528else
2529chip->chip_shift=ffs((unsigned)(chip->chipsize>> 32)) + 32 - 1;
/*
设置坏块的标记位置。
关于nand flash的small block和large block,据我了解,好像就是对应的small pagesize和large pagesize,而此处的大小,是针对于旧的nand flash,其页大小pagesize是512,所以,
Small block就是页大小是512B的nand flash,而larger block就是新的,页大小大于512B的,比如2KB,4KB等的nand flash。
下面的宏定义在
include\linux\mtd\nand.h中:
/*
* Constants for oob configuration
*/
#define NAND_SMALL_BADBLOCK_POS5
#define NAND_LARGE_BADBLOCK_POS0
约定俗成的,small block的nand,坏块标记在byte5,而large block的nand flash在byte0。
关于坏块标记,实际情况更复杂些:
【Nand Flash坏块标记位置】
对于2K页的nand flash,标记位置都是页内oob开始处,都是非0xFF表示坏块,
但是,对于是第几页,不同nand flash就有不同的规定了:
有些nand flash,是标记在坏块的第一个页(或者是第二个页,这点是考虑到,万一第一个页是坏的,所以才做此规定的。一般都是在第一个页处做标记),比如三星的多数SLC,Hynix等;另一些,是在一个块内的最后一页或倒数第二页做此标记,比如samsung MLC , Numonyx等。所以,真正比较完整的检查坏块的做法,至少要检测块内第一,第二,倒数第一,倒数第二页,是否是0xFF,才能比较全面的判断是否是坏块的。
*/
2531/* Set the bad block position */
获得上面nand id表中的默认设置的那些option:LP_OPTIONS(如果是X16则是,LP_OPTIONS16)。
*/
2535/* Get chip options, preserve non chip based options */
自动增加页数???没太搞懂啥意思,估计是cache program/read相关的吧,目前据我了解的,好像页只有cache program/read,能和auto increment pages有点关系。
*/
2540* Set chip as a default. Board drivers can override it, if necessary
/*
如果有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.
/*
一种特殊的nand flash,AND chip。所以,也要赋值给特殊的擦除函数。
具体关于此类nand flash的介绍,感兴趣的自己参考上面drivers\mtd\nand\nand_ids.c中nand_flash_ids数组中的解释。
*/
2550/* Check for AND chips with 4 page planes */
2553else
如果nand flash的页大小是大于512B,也就是2KB,4KB等新的,被称作large block或largepage的nand flash,此处的lp,应该也就是large page的缩写。
此类的nand flash比旧的,在发送地址的时候,多一个地址周期。具体参考datasheet。
*/
2556/* Do not replace user supplied command function ! */
/*
终于检测完所有需要的信息了。最后打印出nand flash的相关信息。
*/
2560printk(KERN_INFO"NAND device: Manufacturer ID:"
2561"0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,dev_id,
/*
活干完了,就可以return回家了,呵呵。
*/