1.Nand Flash
1.1 (Bad) Block Management(坏)块管理
Nand Flash由于其物理特性,只有有限的擦写次数,超过那个次数,基本上就是坏了。在使用过程中,有些Nand Flash的block会出现被用坏了,当发现了,要及时将此block标注为坏块,不再使用。于此相关的管理工作,属于Nand Flash的坏块管理的一部分工作。
1.2 Wear-Leveling负载平衡
Nand Flash的block的管理,还包括负载平衡。正是由于Nand Flash的block,都是有一定寿命限制的,所以如果你每次都往同一个block擦除然后写入数据,那么那个block就很容易被用坏了,所以我们要去管理一下,将这么多次的对同一个block的操作,平均分布到其他一些block上面,使得在block的使用上,相对较平均,这样相对来说,可以更能充分利用Nand Flash。关于wear-leveling这个词,再简单解释一下,wear就是穿(衣服)等,用(东西)导致磨损,而leveling就是使得均衡,所以放在一起就是,使得对于Nand Flash的那么多的block的使用磨损,相对均衡一些,以此延长Nand Flash的使用寿命或者说更加充分利用Nand Flash。
1.3 ECC错误校验码
Nand Flash物理特性上使得其数据读写过程中会发生一定几率的错误,所以要有个对应的错误检测和纠正的机制,于是才有此ECC,用于数据错误的检测与纠正。Nand Flash的ECC,常见的算法有海明码和BCH,这类算法的实现,可以是软件也可以是硬件。不同系统,根据自己的需求,采用对应的软件或者是硬件。
相对来说,硬件实现这类ECC算法,肯定要比软件速度要快,但是多加了对应的硬件部分,所以成本相对要高些。如果系统对于性能要求不是很高,那么可以采用软件实现这类ECC算法,但是由于增加了数据读取和写入前后要做的数据错误检测和纠错,所以性能相对要降低一些,即Nand Flash的读取和写入速度相对会有所影响。
其中,Linux中的软件实现ECC算法,即NAND_ECC_SOFT模式,就是用的对应的海明码。而对于目前常见的MLC的Nand Flash来说,由于容量比较大,动辄2GB,4GB,8GB等,常用BCH算法。BCH算法,相对来说,算法比较复杂。
2、Nand flash硬件特性
2.1什么是Nand flash
nand flash是flash的一种,Flash全名叫做Flash Memory,从名字就能看出,是种数据存储设备,存储设备有很多类,Flash属于非易失性存储设备(Non-volatile Memory Device),与此相对应的是易失性存储设备(Volatile Memory Device)。关于什么是非易失性/易失性,从名字中就可以看出,非易失性就是不容易丢失,数据存储在这类设备中,即使断电了,也不会丢失,这类设备,除了Flash,还有其他比较常见的入硬盘,ROM等,与此相对的,易失性就是断电了,数据就丢失了,比如大家常用的内存,不论是以前的SDRAM,DDR SDRAM,还是现在的DDR2,DDR3等,都是断电后,数据就没了。
Nand flash成本相对低,说白了就是便宜,缺点是使用中数据读写容易出错,所以一般都需要有对应的软件或者硬件的数据校验算法,统称为ECC。但优点是,相对来说容量比较大,现在常见的Nand Flash都是1GB,2GB,更大的8GB的都有了,相对来说,价格便宜,因此适合用来存储大量的数据。其在嵌入式系统中的作用,相当于PC上的硬盘,用于存储大量数据。
2.2 Nand Flash数据存储单元的整体架构
简单说就是,常见的Nand Flash,内部只有一个chip,每个chip只有一个plane。
而有些复杂的,容量更大的Nand Flash,内部有多个chip,每个chip有多个plane。这类的Nand Flash,往往也有更加高级的功能,比如下面要介绍的Multi Plane Program和Interleave Page Program等。
概念上,由大到小来说,就是:
Nand Flash ⇒ Chip ⇒ Plane ⇒ Block ⇒ Page ⇒ oob
用图表来表示,更加易懂,如下图:
2.3 擦除/写入特性
由于Flash的物理特性,使得内部存储的数据,只能从1变成0,对于最初始值,都是1,所以是0xFFFFFFFF,而数据的写入,即是将对应的变成0,而将数据擦除掉,就是统一地,以block为单位,全部一起充电,所有位,都变成初始的1,而不是像普通存储设备那样,每一个位去擦除为0。而数据的写入,就是电荷放电的过程,代表的数据也从1变为了0。所以,总结一下Flash的特殊性如下:
2.4位反转特性
所谓的位反转,bit flip,指的是原先Nand Flash中的某个位,变化了,即要么从1变成0了,要么从0变成1了。
对应的位反转的类型,有两种:
(1) 第一种是Nand flash物理上的数据存储的单元上的数据,是正确的,只是在读取此数据出来的数据中的某位,发生变化,出现了位反转,即读取出来的数据中,某位错了,本来是0变成1,或者本来是1变成0了。此处可以称为软件上位反转。此数据位的错误,当然可以通过一定的校验算法检测并纠正;
(2) Nand flash中的物理存储单元中,对应的某个位,物理上发生了变化,原来是1的,变成了0,或原来是0的,变成了1,发生了物理上的位的数据变化。此处可以称为硬件上的位反转。
2.5坏块管理
对于坏块的管理,在Linux系统中,叫做坏块管理(BBM,Bad Block Management),对应的会有一个表去记录好块,坏块的信息,以及坏块是出厂就有的,还是后来使用产生的,这个表叫做坏块表(BBT,Bad Block Table),在加载完驱动之后,如果你没有加入参数主动要求跳过坏块扫描的话,那么都会去主动扫描坏块,建立必要的BBT的,以备后面坏块管理所使用。
3、Linux MTD体系下的nand flash驱动
3.1 MTD概述
MTD(memory technology device)是用于访问memory设备(比如NOR Flash、NAND Flash)的Linux的子系统。MTD将 Nand Flash,nor flash 和其他类型的 flash 等设备,统一抽象成MTD 设备来管理,根据这些设备的特点,上层实现了常见的操作函数封装,而底层具体的内部实现(具体的内部硬件设备的读/写/擦除函数),就需要驱动设计者自己来实现了。
MTD的主要目的是为了使新的存储设备的驱动更加简单并有通用接口函数可用。MTD将文件系统与底层的Flash存储器进行了隔离,使Flash驱动工程师无须关心Flash作为字符设备和块设备与Linux内核的接口。MTD的所有源代码在/kerne/drivers/mtd子目录下。
MTD子系统的层次框图如下:
MTD子系统
3.2 Linux MTD系统层次
通过上图可以再一步凝结成更加简单的系统层次图,如下图:在引入MTD后,Linux系统中的flash设备驱动及接口可以分成4层:设备节点、MTD设备层、MTD原始层和硬件驱动。
Linux MTD系统
设备节点:
通过mknod在dev子目录下建立MTD字符设备节点(90)和MTD块设备节点(31)。
设备层:
字符设备的定义在mtdchar.c文件中实现,通过注册一系列file_opreation函数可实现对MTD设备的读写和控制。MTD块设备则是定义了一个描述MTD块设备的结构体mtd_dev,并声明了一个名为mtdblks的指针数组,该数组中的每一个mtd_dev都与mtd_info一一对应。
原始设备层:
MTD原始设备层的通用代码(mtdpart.c)。其中mtdcore.c中定义了描述mtd设备的核心结构mtdinfo。
硬件驱动层:
负责flash硬件设备的读、写、擦除,Linux MTD设备的NAND型flash的驱动代码位于/kerne/drivers/mtd/nand子目录下。
了解了上面的知识,我们就可以了解下他们各个层的接口关系,这样我们能更好的熟悉代码,和他们之间的接口调用关系,接口图如下:
3.3 一些重要c文件以及结构体介绍
3.3.1 涉及nand flash的重要c文件
1)nand_base.c
定义了NAND 驱动中对NAND 芯片最基本的操作函数和操作流程,如擦除、读写page 、读写oob 等。当然这些函数都只是进行一些default 的操作,若你的系统在对NAND 操作时有一些特殊的动作,则需要在你自己的驱动代码中进行定义,然后Replace 这些default 的函数。
2)nand_bbt.c
定义了NAND 驱动中与坏块管理有关的函数和结构体。
3)nand_ids.c
定义了两个全局类型的结构体:struct nand_flash_dev nand_flash_ids[ ] 和struct nand_manufacturers nand_manuf_ids[ ] 。其中前者定义了一些NAND 芯片的类型,后者定义了NAND 芯片的几个厂商。NAND 芯片的ID 至少包含两项内容:厂商ID 和厂商为自己的NAND 芯片定义的芯片ID 。当NAND 驱动被加载的时候,它会去读取具体NAND 芯片的ID ,然后根据读取的内容到上述定义的nand_manuf_ids[ ] 和nand_flash_ids[ ] 两个结构体中去查找,以此判断该NAND 芯片是那个厂商的产品,以及该NAND 芯片的类型。若查找不到,则NAND 驱动就会加载失败,因此在开发NAND 驱动前必须事先将你的NAND 芯片添加到这两个结构体中去(其实这两个结构体中已经定义了市场上绝大多数的NAND 芯片,所以除非你的NAND 芯片实在比较特殊,否则一般不需要额外添加)。
值得一提的是,nand_flash_ids[ ] 中有三项属性比较重要,即pagesize 、chipsize 和erasesize ,驱动就是依据这三项属性来决定对NAND 芯片进行擦除,读写等操作时的大小的。其中pagesize 即NAND 芯片的页大小,一般为256 、512 或2048 ;chipsize 即NAND 芯片的容量;erasesize 即每次擦除操作的大小,通常就是NAND 芯片的block 大小。
4)nand_ecc.c
定义了NAND 驱动中与softeware ECC 有关的函数和结构体,若你的系统支持hardware ECC ,且不需要software ECC ,则该文件也不需理会。
5)nandsim.c
定义了Nokia 开发的模拟NAND 设备,默认是Toshiba NAND 8MiB 1,8V 8-bit (根据ManufactureID ),开发普通NAND 驱动时不用理会。
6)diskonechip.c
定义了片上磁盘(DOC) 相关的一些函数,开发普通NAND 驱动时不用理会。
3.3.2 MTD下NAND所涉及的几个重要的结构体
1)mtd_info数据结构。(重要的的结构体之一)
mtd_info结构是MTD原始设备层的一个重要结构,表示MTD原始设备的结构,该结构定义了大量的关于MTD的数据和操作,定义在include/linux/mtd/mtd.h头文件。mtd_info结构成员主要由数据成员和操作函数两部分组成。
每个分区也被实现为一个mtd_info,如果有两个MTD原始设备,每个上有三个分区,在系统中就一共有6个mtd_info结构,这些mtd_info的指针被存放在名为mtd_table的数组里.
要强调的是:包含的这些函数指针指向的函数是MTD驱动提供的接口函数(每一个驱动程序的最终目的就是提供一些接口函数实现对底层硬件设备的操作),这些函数是在整个MTD驱动框架中层次最高的函数,他们可以在应用程序中直接调用实现对MTD设备底层硬件的操作。如:static int nand_read_ecc ()。它实现了对NAND flash的读操作。
struct mtd_info {
u_char type;
//内存技术类型,例如MTD_RAM,MTD_ROM,MTD_NORFLASH,MTD_NAND_FLASH等
u_int32_t flags;
//标志位,MTD设备的性能描述
u_int32_t size;
//MTD设备的大小
u_int32_t erasesize;
//最小的擦除块大小
u_int32_t writesize;
//编程大小
u_int32_t oobsize;
//oob(Out of band)块大小
u_int32_t ecctype;
//ECC校验类型
u_int32_t eccsize;
#define MTD_PROGREGION_CTRLMODE_VALID(mtd) (mtd)->oobsize
#define MTD_PROGREGION_CTRLMODE_INVALID(mtd) (mtd)->ecctype
char *name;
int index;
struct nand_ecclayout *ecclayout;
//eec布局结构
int numeraseregions;
//擦除区域个数,通常为1
struct mtd_erase_region_info *eraseregions;
//擦除区域的区域信息地址
u_int32_t bank_size;
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
//函数指针,erase函数的功能是将一个erase_info加入擦除队列
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
//point函数功能是允许片内执行(XIP)
void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
//unpoint函数与point函数相反,是禁止片内执行(XIP)
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
//MTD设备的读写函数
int (*read_oob) (struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
int (*write_oob) (struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops);
//用于MTD设备的OBB数据读写
int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
//访问保护寄存器区
int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
//基于kevc的读写方法
void (*sync) (struct mtd_info *mtd);
//MTD设备的同步函数
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
//芯片的加锁和解锁
int (*suspend) (struct mtd_info *mtd);
void (*resume) (struct mtd_info *mtd);
//支持电源管理函数
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
//坏块管理函数
struct notifier_block reboot_notifier;
struct mtd_ecc_stats ecc_stats; //ECC状态信息
void *priv;
//私有数据指针 ,这个指针指向MTD驱动中另一个重要的数据结构struct nand_chip
struct module *owner;
int usecount;
};
2)mtd_part结构体信息
mtd_part(mtd_part.c)是用于表示 MTD 原始设备分区的结构,其中包含了 mtd_info,因为每一个分区都是被看成一个MTD 原始设备加在 mtd_table 中的,mtd_part.mtd_info中的大部分数据都从该分区的主分区 mtd_part->master中获得。
static LIST_HEAD(mtd_partitions);
//分区链表
/* Our partition node structure */
//分区结构信息
struct mtd_part {
struct mtd_info mtd; //mtd_info数据结构体,加入到mtd_table中
struct mtd_info *master;//该分区的主分区
uint64_t offset;//该分区的偏移量
struct list_head list;
};
3)mtd_notifier结构体、
mtd_notifier:MTD通知器,加入/删除MTD设备和原始设备时调用的函数,在设备层,当MTD字符设备或块设备注册时,如果定义了CONFIG_DEVFS_FS,则会将一个mtd_notifier加入MTD原始设备层的mtd_notifiers链表,其中的函数会在两种情况下被调用,一是加入/删除新的MTD字符/块设备时,此时调用该MTD字符/块设备的notifier对下层所有的MTD原始设备操作一遍,二是加入/删除新的MTD原始设备时,此时调用所有的notifier对该原始设备执行一遍。
struct mtd_notifier {
void (*add)(struct mtd_info *mtd);//加入MTD原始/字符/块设备时执行
void (*remove)(struct mtd_info *mtd);//移除MTD原始/字符/块设备时执行
struct list_head list;//list是双向链表,定义在include/linux/list.h
};
4)nand_chip(重要结构体之二)
这个数据结构从结构名nand_chip就可以知道它主要针对MTD设备中NAND flash的描述。在这个数据结构中包含了许多参数和函数指针。其中的成员大致可以分为以下几类:
a)与芯片有关的参数
如:page_shift、phys_erase_shift、bbt_erase_shift、chip_shift、chipsize、numchips
b)与坏块管理、ECC校验及oob区管理有关的参数:
如:eccmode、eccsize、eccbyte、eccsteps、calculate_ecc、oob_buf、oobdirty、autooob、bbt、badblockpos、bbt_td、bbt_md、badblock_pattern
c)与NAND flash控制器寄存器操作有关的参数
如:IO_ADDR_R、IO_ADDR_W
d)与NAND flash控制器寄存器操作有关的函数指
如:read_byte、write_byte、read_word、write_word、hwcontrol、dev_ready、cmdfunc、select_chip
e)与NAND flash操作功能有关的函数指针
如:write_buf、read_buf、verify_buf、waitfunc、erase_cmd
f)与坏块管理、ECC校验及oob区管理有关的函数指针:
如:block_bad、block_markbad、calculate_ecc、correct_data、enable_hwecc、scan_bbt
综上,nand_chip主要包括了MTD驱动的低层和底层硬件操作函数的函数指针以及坏块管理、ECC校验和oob区管理需要相关函数的函数指针,这些指针指向的函数一部分在源码目录下的driver/nand/nand_base.c定义为通用函数,一部分需要用户在移植时自行编写。那些需要用户自行编写在后续的分析将会提到。nand_chip还包括了一些参数,这些参数与具体芯片型号及坏块管理策略有关,它们会在nand_scan()函数中被初始化。
struct nand_chip的结构声明
它在include/linux/mtd/nand.h中被声明定义,去掉一些编译选项、无关成员及原有注释,添加一些注释后如下;
struct nand_chip {
void __iomem *IO_ADDR_R; //NAND flash控制器的寄存器读访问指针,
void __iomem *IO_ADDR_W; //NAND flash控制器的寄存器写访问指针,
u_char (*read_byte)(struct mtd_info *mtd);
//写一字节到NAND flash控制器的寄存器函数的函数指针
void (*write_byte)(struct mtd_info *mtd, u_char byte);
//从NAND flash控制器的寄存器读一字节函数的函数指针
u16 (*read_word)(struct mtd_info *mtd); //读字函数指针
void (*write_word)(struct mtd_info *mtd, u16 word); //写字函数指针
//读写缓冲区函数指针,所谓缓冲区无非就是自行定义的一个数组
void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
//缓存校验韩式指针,验证从Flash中读取的内容是否与缓存中一致
void (*select_chip)(struct mtd_info *mtd, int chip);
//芯片片选函数指针,由于涉及底层寄存器操作该函数在移植时一般要自己编写
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
//读取坏块标记函数指针
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
//标记坏块函数指针
void (*hwcontrol)(struct mtd_info *mtd, int cmd);
//寄存器访问控制函数指针,该函数根据第二个参数cmd使O_ADDR_R/W指向不同的寄存器
int (*dev_ready)(struct mtd_info *mtd);
//设备状态读取函数指针,该函数读取NAND flash控制器的NFSTAT的bit0,获取R/B状态
void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
//向NAND flash写一个命令字,如果形参column、page_addr不都为-1则还向NAND flash写一个地址
int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
//操作超时处理函数指针,该函数根据命令的不同设定不同的超时时间并时刻检查R/B位直到R/B状态进入Ready状态否则为操作超时。
int (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
//ECC编码计算函数指针,该函数通过软件算法计算256字节的3字节ECC编码
int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
//ECC检测纠正函数,该函数检测并纠正256字节块中的1位错误。
void (*enable_hwecc)(struct mtd_info *mtd, int mode);
//使能硬件计算ECC码函数指针
void (*erase_cmd)(struct mtd_info *mtd, int page);
//擦除指定块函数的函数指针
int (*scan_bbt)(struct mtd_info *mtd);
//坏块标记表创建函数指针
int eccmode;// ECC的计算方法, NAND_ECC_SOFT时意指软件运算,即采用calculate_ecc进行运算,利用correct_data进行校正
int eccsize;// ECC校准的数据长度,用calculate_ecc进行校准时,数据长度固定为256字节
int eccbytes;// ECC校验码字节数,软件校准时为3字节
int eccsteps;// ECC校验的步数,当FLASH每页的字节数为512字节,而calculate_ecc每次仅能校验256字节,则需要两步才能校验完成。
int chip_delay;// 等待时间,一般用于等待Flash的R/B管脚
int page_shift;// 页的地址移位数,当为512(2^9)字节的空间,其该值为9
int phys_erase_shift;// 块的地址移位数
int bbt_erase_shift;// 在bbt表中,相间隔两个内容之间的地址差的位数,也即是块的地址位数
int chip_shift;// 芯片总的地址位数
u_char *data_buf; //数据缓冲区指针
u_char *oob_buf;//oob缓冲区指针
int oobdirty;// 表示oob_buf内是否有内容,如为0表示oob_buf为空(0xFF),为1表示oob_buf中已有内容
u_char *data_poi;// 指向一个临时使用的数据区
unsigned int options;
//MTD驱动中配置NAND FALSH芯片的扩展功能,如NAND_IS_AND、NAND_USE_FLASH_BBT、NAND_COPYBACK等等和重要参数,如位宽NAND_BUSWIDTH_16。上述的这些宏在include/linux/mtd/nand.h均有定义,这些宏的定义能保证当它们进行或运算是能保证options能同时接受这些扩展功能和参数。及options某bit位为1时则使用对应的扩展功能。如有:
//#define NAND_COPYBACK 0x00000010
//那么如果options的bit4位为1则使用copyback功能,在MTD中大量使用了这种技巧,需要注意
int badblockpos;// 坏块标记的位置。当芯片为小页面NAND flashs时值为NAND_SMALL_BADBLOCK_POS(即为5);为大页面时值为NAND_BIG _BADBLOCK_POS(即为0)
int numchips;//开发板上NAND flash芯片的片数
unsigned long chipsize;// 芯片的容量
int pagemask;//页地址掩码
int pagebuf;// 存储Data_buf内的相关的页号
struct nand_oobinfo*autooob;
/* oob区布局设计结构体指针。从功能上看,oob区和数据存储区一样可以存储数据,但是oob区一般不会用于存储数据,而是做为坏块标记和ECC校验数据存储。其中坏块标记位置一般有约定俗成的位置,而oob区的布局设计有很多不同的设计,MTD使用一个结构体来描述这种设计,oob区布局设计结构体在include/linux/mtd/mtd_abi.h中定义如下:
其中useecc 为使用ECC校验标志,eccbyte为ECC校验的位数,eccpos为ECC校验所存的位号,oobfree为OOB中ECC未使用到的字节(起始地址+长度)*/
uint8_t *bbt;// 指向内存中坏块表的指针
struct nand_bbt_descr*bbt_td;// 用以Flash中坏块表搜索的相关描述
struct nand_bbt_descr *bbt_md;// 上述描述的镜像
struct nand_hw_control*controller;// 用以实现互锁操作,此处并未使用
void *priv;//用途不明
};
5)nand_flash_dev结构体
这个数据结构主要描述的是具体的NAND flash芯片型号。这个数据结构比较简单,它在include/linux/mtd/nand.h中被声明定义为一个结构体:
```c
struct nand_flash_dev {
char *name; //NAND flash的名称
int id; //NAND flashd 的设备ID
unsigned long pagesize;//页面大小,单位为KB
unsigned long chipsize;//芯片容量,单位为MB
unsigned long erasesize;//擦除单位大小
unsigned long options;// NAND flashd的扩展功能配置及位宽配置
};
4、驱动例程分析
此部分后续再写。
5、高通平台Nand Flash配置
高通平台的nand flash配置一般在四个部分进行配置,分别是SBL部分、lk部分、boot部分和modem部分。
5.1 SBL部分
boot_images/core/storage/flash/src/dal/flash_nand_config.c
根据相应的nand flash数据手册,来更改上面结构体数组的变量。每个变量的含义已经在代码里注释过,可以根据代码注释进行更改变量。
其中, Page Count:一个block包含的page数,一般为block包含64块;
Page Size: page的大小(字节)一般为2048 或 4096;
Spare Size:空闲区大小 2176-2048=128;
TWB:根据手册配置一般为100ns。
参数2:为第二个ID 可忽略
参数3:第一个ID的mask码 :
参数4: 第二个ID的mask码,可忽略
参数5:nand flash的大小,0x08000000 = 128M
参数6:widebus
参数7:page 大小 2048
参数8:block 大小0x20000 = 131072=128K
参数9:oob空闲区大小 0x80 = 128byte
参数10:是否为8bit的ECC校验
注意:
在lk阶段,如果配置的nand flash列表中有所使用的MCP型号,在lk阶段会直接ASSERT掉,所以在lk必须配置MCP型号。
5.3 boot部分
路径:/bootable/bootloader/lk/platform/msm_shared/qpic_nand.c
参数:
0x98:厂商ID
0xa1:设备ID
0x80:chip number 和 cell type
0x15:page_size block_size IO width
NAND_ECC_INFO(8, SZ_512): 每512bytes一个8bit的ECC校验 ,可从手册中获取:
注意:
在boot阶段,初始化nand flash 时,会优先使用onfi标准初始化获取mcp信息,如果MCP不支持onfi标准,再通过读取的nand id匹配支持列表中的mcp。
5.4 modem部分
路径:/modem_proc/core/storage/flash/src/dal/flash_nand_config.c
modem的配置与SBL阶段配置基本一致,有这样的情况,modem不需要配置也能正常启动,不过建议modem进行配置。
注意:modem如果匹配不到支持列表中MCP型号,和sbl阶段一样会通过onfi标准读取parament page 获取MCP配置。
版权声明
内容来源及使用限制
欢迎访问 TomgZHE研习社(网址:https://blog.tomgzhe.com)。本网站部分文章内容源自网络,仅作学习交流与参考分享;若您发现有内容涉嫌侵权,请立即联系 tomgzhe@qq.com,我们将在接到通知后的 48 小时内核实并删除相关侵权内容。
软件资源相关规定
本网站为个人非盈利性质的站点,所有软件资源均来自网络。这些资源仅用于个人学习、研究和参考,严禁用于任何商业用途。您下载和使用本网站软件资源即表示您同意仅将其用于学习目的,若因违反此规定导致任何法律纠纷或损失,责任由您自行承担。
原创版权
本网站上的原创内容,包括但不限于文字作品、自行设计的图片、独家制作的音频视频等,其版权均归本网站所有。未经本网站书面授权,任何组织或个人不得擅自复制、转载、摘编、传播或以其他任何方式使用这些原创内容。如需使用,请提前与我们联系并获得书面许可,同时需在显著位置注明出处及作者信息。
转载与引用规范
若您需转载本网站文章,务必注明文章来源为 “[],原文链接:[]”;对于有明确作者署名的文章,还需完整保留作者姓名。在引用本网站内容时,请确保内容准确无误,并遵循学术及行业的引用规范。
微信扫一扫打赏
支付宝扫一扫打赏