U-Boot源码之NAND Flash驱动

       这里以u-boot-2009.08版本介绍U-Boot的NAND Flash驱动的实现。要明白U-Boot的NAND Flash驱动的实现,首先要了解NAND Flash的基础知识。

一、NAND Flash简介

       关于NAND Flash的介绍,可以参看下面两篇博文:

       https://blog.csdn.net/shengnan_wu/article/details/8116861?utm_medium=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control

      https://blog.csdn.net/qq_38880380/article/details/78884522

       这里根据上面两篇博文,总结一下NAND Flash的关键知识:

1、NAND Flash和NOR Flash主要区别:

(1)NOR Flash是芯片内执行(XIP, eXecute In Place),采用了内存的随机读取技术。这样应用程序可以直接在NOR flash内运行,不必再把代码读到系统RAM中。

       NAND Flash没有采取内存的随机读取技术,它的读取是以一次读取一块的形式来进行的。用户不能直接运行 NAND Flash上的代码。

(2)NOR Flash的传输(读取)效率很高,但是写入和擦除速度很慢(擦除64~128KB的块约5秒钟)。NAND Flash的读取速度比NOR Flash稍慢,但是NAND Flash的写入和擦除速度比NOR Flash快很多(擦除8~32KB的块约4ms)。

(3)NAND flash的单元尺寸几乎是NOR器件的一半,由于生产过程更为简单,NAND结构可以在给定的模具尺寸内提供更高的容量,也就相应地降低了价格。NOR flash占据了容量为1~16MB闪存市场的大部分,而NAND flash只是用在8~128MB的产品当中,这也说明NOR主要应用在代码存储介质中,NAND适合于数据存储,NAND在CompactFlash、Secure Digital、PC Cards和MMC存储卡市场上所占份额最大。

(4)NOR flash带有SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内部的每一个字节。NAND器件使用复杂的I/O口来串行地存取数据,各个产品或厂商的方法可能各不相同。8个引脚用来传送控制、地址和数据信息。

(5)NAND Flash中每个块的最大擦写次数是一百万次,而NOR Flash的擦写次数是十万次。NAND Flash的位交换概率比NOR Flash的大,必须使用EDC/ECC系统以确保可靠性。

(6)NAND Flash的坏块是随机分布的,需要对其进行初始化扫描以发现坏块,并将坏块标记为不可用。

(7)NOR Flash较之NAND Flash方便使用很多。可以非常直接地使用基于NOR的闪存,可以像其他存储器那样连接,并可以在上面直接运行代码。由于需要I/O接口,NAND要复杂得多。各种NAND器件的存取方法因厂家而异。在使用NAND器件时,必须先写入驱动程序,才能继续执行其他操作。向NAND器件写入信息需要相当的技巧,因为设计师绝不能向坏块写入,这就意味着在NAND器件上自始至终都必须进行虚拟映射。

(8)在NOR器件上运行代码不需要任何的软件支持,在NAND器件上进行同样操作时,通常需要驱动程序,也就是内存技术驱动程序(MTD),NAND和NOR器件在进行写入和擦除操作时都需要MTD。使用NOR器件时所需要的MTD要相对少一些,许多厂商都提供用于NOR器件的更高级软件,这其中包括M-System的TrueFFS驱动,该驱动被Wind River System、Microsoft、QNX Software System、Symbian和Intel等厂商所采用。驱动还用于对DiskOnChip产品进行仿真和NAND闪存的管理,包括纠错、坏块处理和损耗平衡。

2、NAND Flash的地址分为三部分:块号,块内页号,页内字节号;正因为如此,NAND的一次数据访问,要经过3次寻址,先后确定块号,块内页号,页内字节号,至少占用了三个时间周期。

3、Nand flash的数据是以bit的方式保存在memory cell,一个cell里面只能存储一个bit。这些cell以8个或者16个为单元,连成bit line,形成所谓的byte(X8)/word(X16),这就是NAND Device的位宽。这些line会再组成page,page又分为main area(一般用来做普通数据的存储区)和spare area(一般用于存放ECC校验码、坏块标记等信息),最后再又多个page形成一个block。

4、NAND flash以页为单位读写数据,而以块为单位擦除数据。按照这样的组织方式可以形成所谓的三类地址:

――Block address――page address――column address

      对于NANDFLASH来说,地址,命令和数据都只能在I/O[7:0]上传递,数据宽度为8bits或16bits。

      在一个块内,对每一个页进行编程(写操作)的话,必须是顺序的,而不能是随机的。比如,一个块中有128个页,那么你只能先对page0编程,再对page1编程,。。。。,而不能随机的,比如先对page3,再page1,page2.,page0,page4,.。。。

5、Nand Flash中,一个块中含有1个或多个位是坏的,就成为其为坏块。坏块的稳定性是无法保证的,也就是说,不能保证你写入的数据是对的,或者写入对了,读出来也不一定对的。而正常的块,肯定是写入读出都是正常的。坏块有两种:

(1)一种是出厂的时候,也就是,你买到的新的,还没用过的Nand Flash,就可以包含了坏块。此类出厂时就有的坏块,被称作factory (masked)bad block或initial bad/invalid block,在出厂之前,就会做对应的标记,标为坏块。具体标记的地方是,对于现在常见的页大小为2K的NandFlash,是块中第一个页列地址为2048的位置(旧的小页面,pagesize是512B甚至256B的nandflash,坏块标记是spare area的第6个字节),如果不是0xFF,就说明是坏块。相对应的是,所有正常的块,好的块,里面所有数据都是0xFF的。

(2)第二类叫做在使用过程中产生的,由于使用过程时间长了,在擦块除的时候,出错了,说明此块坏了,也要在程序运行过程中,发现,并且标记成坏块的。具体标记的位置,和上面一样。这类块叫做worn-out bad block。对于坏块的管理,在Linux系统中,叫做坏块管理(BBM,Bad Block Managment),对应的会有一个表去记录好块,坏块的信息,以及坏块是出厂就有的,还是后来使用产生的,这个表叫做坏块表(BBT,Bad Block Table)。在Linux内核MTD架构下的Nand Flash驱动,和Uboot中Nand Flash驱动中,在加载完驱动之后,如果你没有加入参数主动要求跳过坏块扫描的话,那么都会去主动扫描坏块,建立必要的BBT的,以备后面坏块管理所使用。(这样每次使用之之前,都会自动扫描一下,建立BBT,这样就可以跳过怀块进行别的方面的处理了)       

       关于好的,可以使用的块的数目达到一定的数目,比如三星的K9G8G08U0M,整个flash一共有4096个块,出厂的时候,保证好的块至少大于3996个,也就是意思是,你新买到这个型号的nand flash,最坏的可能,有3096-3996=100个坏块。不过,事实上,现在出厂时的坏块,比较少,绝大多数,都是使用时间长了,在使用过程中出现的。
       保证第一个块是好的,并且一般相对来说比较耐用。做此保证的主要原因是,很多Nand Flash坏块管理方法中,就是将第一个块,用来存储上面提到的BBT,否则,都是出错几率一样的块,那么也就不太好管理了,连放BBT的地方,都不好找了,^_^。一般来说,不同型号的Nand Flash的数据手册中,也会提到,自己的这个nand flash,最多允许多少个坏块。就比如上面提到的,三星的K9G8G08U0M,最多有100个坏块。 对于坏块的标记,本质上,也只是对应的flash上的某些字节的数据是非0xFF而已,所以,只要是数据,就是可以读取和写入的。也就意味着,可以写入其他值,也就把这个坏块标记信息破坏了。对于出厂时的坏块,一般是不建议将标记好的信息擦除掉的。uboot中有个命令是“nand scrub”就可以将块中所有的内容都擦除了,包括坏块标记,不论是出厂时的,还是后来使用过程中出现而新标记的。一般来说,不建议用这个。不过,我倒是经常用,其实也没啥大碍,呵呵。最好用“nand erase”只擦除好的块,对于已经标记坏块的块,不擦除。

       如果在对一个块的某个page进行编程的时候发生了错误就要把这个块标记为坏块,首先就要把块里其他好的面的内容备份到另外一个空的好块里面,然后,把这个块标记为坏块。当然,这可能会犯“错杀”之误,一个补救的办法,就是在进行完块备份之后,再将这个坏块擦除一遍,如果Block Erase发生错误,那就证明这个块是个真正的坏块,那就毫不犹豫地将它打个“戳”吧!

6、NAND Flash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出错。一般使用一种比较专用的校验——ECC。ECC能纠正单比特错误和检测双比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。
      ECC一般每256字节原始数据生成3字节ECC校验数据,这三字节共24比特分成两部分:6比特的列校验和16比特的行校验,多余的两个比特置1。(512生成两组ECC,共6字节) 
      当往NAND Flash的page中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存到PAGE的spare area中。校验的时候,根据上述ECC生成原理不难推断:将从spare area中读出的原ECC校验和新ECC校验和按位异或,若结果为0,则表示不存在错(或是出现了ECC无法检测的错误);若3个字节异或结果中存在11个比特位为1,表示存在一个比特错误,且可纠正;若3个字节异或结果中只存在1个比特位为1,表示spare area出错;其他情况均表示出现了无法纠正的错误。

7、很多Nand flash支持一个叫做CE don’t-care的技术,字面意思就是,不关心是否片选,那有人会问了,如果不片选,那还能对其操作吗?答案就是,这个技术,主要用在当时是不需要选中芯片却还可以继续操作的这些情况:在某些应用,比如录音,音频播放等应用中,外部使用的微秒(us)级的时钟周期,此处假设是比较少的2us,在进行读取一页或者对页编程时,是对Nand Flash操作,这样的串行(SerialAccess)访问的周期都是20/30/50ns,都是纳秒(ns)级的,此处假设是50ns,当你已经发了对应的读或写的命令之后,接下来只是需要Nand Flash内部去自己操作,将数据读取或写入进去到内部的数据寄存器中而已,此处,如果可以把片选取消,CE#是低电平有效,取消片选就是拉高电平,这样会在下一个外部命令发送过来之前,即微秒量级的时间里面,即2us-50ns≈2us,这段时间的取消片选,可以降低很少的系统功耗,但是多次的操作,就可以在很大程度上降低整体的功耗了。总结起来简单解释就是:由于某些外部应用的频率比较低。

二、Linux MTD系统解析

       U-Boot的NAND Flash驱动是从Linux的MTD系统里移植过来的。所以必须首先理解Linux的MTD系统,才能理解U-Boot的NAND Flash驱动。

1、Linux MTD系统框架

      MTD,Memory Technology Device即内存技术设备,在Linux内核中,引入MTD层为NOR FLASH和NAND FLASH设备提供统一接口。MTD将文件系统与底层FLASH存储器进行了隔离。

      Linux内核的MTD框架如图1所示。

 

                                                                     图1 Linux内核的MTD框架

      如上图所示,MTD设备通常可分为四层,从上到下依次是:设备节点、MTD设备层、MTD原始设备层、硬件驱动层。

(1)设备节点:通过mknod在/dev子目录下建立MTD块设备节点(主设备号为31)和MTD字符设备节点(主设备号为90)。通过访问此设备节点即可访问MTD字符设备和块设备。

(2)MTD设备层:基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90)。其中mtdchar.c 是MTD字符设备接口相关实现,mtdblock.c是MTD块设备接口相关实现。

(3)MTD原始设备层:用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。其中mtdcore.c是MTD原始设备接口相关实现,mtdpart.c 是MTD分区接口相关实现。

(4)硬件驱动层:硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设备的Nand Flash芯片的驱动则drivers/mtd/nand/子目录下,Nor Flash芯片驱动位于drivers/mtd/chips/子目录下。

       实现各层的关键文件、数据结构和之间联系如图2所示。

                                                            图2 实现各层的关键文件、数据结构和之间联系

       U-Boot只使用了Linux内核中的MTD原始设备层和硬件驱动层。

2、Linux MTD各层数据结构及接口函数

(1)MTD设备层       

       mtd字符设备接口:/drivers/mtd/mtdchar.c文件实现了MTD字符设备接口,通过它,可以直接访问Flash设备,与前面的字符驱动一样,通过file_operations结构体里面的open()、read()、write()、ioctl()可以读写Flash,通过一系列IOCTL 命令可以获取Flash 设备信息、擦除Flash、读写NAND 的OOB、获取OOB layout 及检查NAND 坏块等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL) 。

      mtd块设备接口:/drivers/mtd/mtdblock.c文件实现了MTD块设备接口,主要原理是将Flash的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash上的block,将内存中的映射块写入Flash块。整个过程被称为read/modify/erase/rewrite 周期。 但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。

(2)MTD原始设备层

       mtdcore.c文件实现了MTD原始设备相关接口,mtdpart.c文件实现了MTD分区相关接口。

       用于描述MTD原始设备的数据结构是mtd_info,它定义了大量的关于MTD的数据和操作函数。所有的mtd_info结构体存放在mtd_table结构体数据里。在/drivers/mtd/mtdcore.c里:

struct mtd_info *mtd_table[MAX_MTD_DEVICES];  

       Linux内核使用mtd_part结构体表示分区,其中mtd_info结构体成员用于描述该分区,大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。

struct mtd_part {  
2.    struct mtd_info mtd;        /* 分区信息, 大部分由master决定 */  
3.    struct mtd_info *master;    /* 分区的主分区 */  
4.    uint64_t offset;            /* 分区的偏移地址 */  
5.    int index;                  /* 分区号 (Linux3.0后不存在该字段) */  
6.    struct list_head list;      /* 将mtd_part链成一个链表mtd_partitons */  
7.    int registered;  
8.};

       下面重点介绍下数据结构是mtd_info。为了便于观察,将重要的数据放在前面,不大重要的编写在后面。

struct mtd_info {  
2.    u_char type;         /* MTD类型,包括MTD_NORFLASH,MTD_NANDFLASH等(可参考mtd-abi.h) */  
3.    uint32_t flags;      /* MTD属性标志,MTD_WRITEABLE,MTD_NO_ERASE等(可参考mtd-abi.h) */  
4.    uint64_t size;       /* mtd设备的大小 */  
5.    uint32_t erasesize;  /* MTD设备的擦除单元大小,对于NandFlash来说就是Block的大小 */  
6.    uint32_t writesize;  /* 写大小, 对于norFlash是字节,对nandFlash为一页 */  
7.    uint32_t oobsize;    /* OOB字节数 */  
8.    uint32_t oobavail;   /* 可用的OOB字节数 */  
9.    unsigned int erasesize_shift;   /* 默认为0,不重要 */  
10.    unsigned int writesize_shift;   /* 默认为0,不重要 */  
11.    unsigned int erasesize_mask;    /* 默认为1,不重要 */  
12.    unsigned int writesize_mask;    /* 默认为1,不重要 */  
13.    const char *name;               /* 名字,   不重要*/  
14.    int index;                      /* 索引号,不重要 */  
15.    int numeraseregions;            /* 通常为1 */  
16.    struct mtd_erase_region_info *eraseregions; /* 可变擦除区域 */  
17.      
18.    void *priv;     /* 设备私有数据指针,对于NandFlash来说指nand_chip结构体 */  
19.    struct module *owner;   /* 一般设置为THIS_MODULE */  
20.      
21.    /* 擦除函数 */  
22.    int (*erase) (struct mtd_info *mtd, struct erase_info *instr);  
23.  
24.    /* 读写flash函数 */  
25.    int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
26.    int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
27.  
28.    /* 带oob读写Flash函数 */  
29.    int (*read_oob) (struct mtd_info *mtd, loff_t from,  
30.             struct mtd_oob_ops *ops);  
31.    int (*write_oob) (struct mtd_info *mtd, loff_t to,  
32.             struct mtd_oob_ops *ops);  
33.  
34.    int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
35.    int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
36.    int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);  
37.    int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
38.    int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);  
39.    int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);  
40.  
41.    int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);  
42.    int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);  
43.    /* Sync */  
44.    void (*sync) (struct mtd_info *mtd);  
45.  
46.    /* Chip-supported device locking */  
47.    int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
48.    int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);  
49.  
50.    /* 电源管理函数 */  
51.    int (*suspend) (struct mtd_info *mtd);  
52.    void (*resume) (struct mtd_info *mtd);  
53.  
54.    /* 坏块管理函数 */  
55.    int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);  
56.    int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);  
57.  
58.    void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);  
59.    unsigned long (*get_unmapped_area) (struct mtd_info *mtd,  
60.                        unsigned long len,  
61.                        unsigned long offset,  
62.                        unsigned long flags);  
63.    struct backing_dev_info *backing_dev_info;  
64.    struct notifier_block reboot_notifier;  /* default mode before reboot */  
65.  
66.    /* ECC status information */  
67.    struct mtd_ecc_stats ecc_stats;  
68.    int subpage_sft;  
69.    struct device dev;  
70.    int usecount;  
71.    int (*get_device) (struct mtd_info *mtd);  
72.    void (*put_device) (struct mtd_info *mtd);  
73.};  

       mtd_info结构体中的read()、write()、read_oob()、write_oob()、erase()是MTD设备驱动要实现的主要函数,幸运的是Linux大牛已经帮我们实现了一套适合大部分FLASH设备的mtd_info成员函数。

       如果MTD设备只有一个分区,那么使用下面两个函数注册和注销MTD设备。

int add_mtd_device(struct mtd_info *mtd)  
int del_mtd_device (struct mtd_info *mtd)  

      如果MTD设备存在其他分区,那么使用下面两个函数注册和注销MTD设备。

int add_mtd_partitions(struct mtd_info *master,const struct mtd_partition *parts,int nbparts)  
int del_mtd_partitions(struct mtd_info *master)  

      其中mtd_partition结构体表示分区的信息。

struct mtd_partition {  
2.    char *name;             /* 分区名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2 */  
3.    uint64_t size;          /* 分区大小 */  
4.    uint64_t offset;        /* 分区偏移值 */  
5.    uint32_t mask_flags;    /* 掩码标识,不重要 */  
6.    struct nand_ecclayout *ecclayout;   /* OOB布局 */  
7.    struct mtd_info **mtdp;     /* pointer to store the MTD object */  
8.};

(3)MTD硬件驱动层       

       Linux内核再MTD层下实现了通用的NAND驱动(/driver/mtd/nand/nand_base.c),因此芯片级的NAND驱动不再需要实现mtd_info结构体中的read()、write()、read_oob()、write_oob()等成员函数。

       MTD使用nand_chip来表示一个NAND FLASH芯片, 该结构体包含了关于Nand Flash的地址信息,读写方法,ECC模式,硬件控制等一系列底层机制。

struct nand_chip {  
2.    void  __iomem   *IO_ADDR_R;     /* 读8位I/O线地址 */  
3.    void  __iomem   *IO_ADDR_W;     /* 写8位I/O线地址 */  
4.  
5.    /* 从芯片中读一个字节 */  
6.    uint8_t (*read_byte)(struct mtd_info *mtd);       
7.    /* 从芯片中读一个字 */  
8.    u16     (*read_word)(struct mtd_info *mtd);       
9.    /* 将缓冲区内容写入芯片 */  
10.    void    (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);      
11.    /* 读芯片读取内容至缓冲区/ */  
12.    void    (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);  
13.    /* 验证芯片和写入缓冲区中的数据 */  
14.    int     (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);  
15.    /* 选中芯片 */  
16.    void    (*select_chip)(struct mtd_info *mtd, int chip);  
17.    /* 检测是否有坏块 */  
18.    int     (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);  
19.    /* 标记坏块 */  
20.    int     (*block_markbad)(struct mtd_info *mtd, loff_t ofs);  
21.    /* 命令、地址、数据控制函数 */  
22.    void    (*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);  
23.    /* 设备是否就绪 */  
24.    int     (*dev_ready)(struct mtd_info *mtd);  
25.    /* 实现命令发送 */  
26.    void    (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);  
27.    int     (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);  
28.    /* 擦除命令的处理 */  
29.    void    (*erase_cmd)(struct mtd_info *mtd, int page);  
30.    /* 扫描坏块 */  
31.    int     (*scan_bbt)(struct mtd_info *mtd);  
32.    int     (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);  
33.    /* 写一页 */  
34.    int     (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,  
35.                      const uint8_t *buf, int page, int cached, int raw);  
36.  
37.    int     chip_delay;         /* 由板决定的延迟时间 */  
38.    /* 与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等 */  
39.    unsigned int    options;      
40.  
41.    /* 用位表示的NAND芯片的page大小,如某片NAND芯片 
42.     * 的一个page有512个字节,那么page_shift就是9  
43.     */  
44.    int      page_shift;  
45.    /* 用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可 
46.     * 擦除16K字节(通常就是一个block的大小),那么phys_erase_shift就是14 
47.     */  
48.    int      phys_erase_shift;  
49.    /* 用位表示的bad block table的大小,通常一个bbt占用一个block, 
50.     * 所以bbt_erase_shift通常与phys_erase_shift相等 
51.     */  
52.    int      bbt_erase_shift;  
53.    /* 用位表示的NAND芯片的容量 */  
54.    int      chip_shift;  
55.    /* NADN FLASH芯片的数量 */  
56.    int      numchips;  
57.    /* NAND芯片的大小 */  
58.    uint64_t chipsize;  
59.    int      pagemask;  
60.    int      pagebuf;  
61.    int      subpagesize;  
62.    uint8_t  cellinfo;  
63.    int      badblockpos;  
64.    nand_state_t    state;  
65.    uint8_t     *oob_poi;  
66.    struct nand_hw_control  *controller;  
67.    struct nand_ecclayout   *ecclayout; /* ECC布局 */  
68.      
69.    struct nand_ecc_ctrl ecc;   /* ECC校验结构体,里面有大量的函数进行ECC校验 */  
70.    struct nand_buffers *buffers;  
71.    struct nand_hw_control hwcontrol;  
72.    struct mtd_oob_ops ops;  
73.    uint8_t     *bbt;  
74.    struct nand_bbt_descr   *bbt_td;  
75.    struct nand_bbt_descr   *bbt_md;  
76.    struct nand_bbt_descr   *badblock_pattern;  
77.    void        *priv;  
78.}; 

三、U-BOOT的NAND Flash驱动的实现

       U-BOOT的NAND Flash驱动实现的关键是对数据结构mtd_info和nand_chip各个成员的实现。

1、数据结构mtd_info的实现

       数据结构mtd_info各个成员已经由Linux内核实现,不需要自己单独实现。数据结构mtd_info各个成员的实现主要在mtd/nand/nand_base.c的函数nand_init_chip、函数nand_get_flash_type、函数nand_scan_ident、函数nand_scan_tail中实现的。比如,数据结构mtd_info的read()、write()、read_oob()、write_oob()等成员函数在函数nand_scan_tail中赋值,且这些函数都已经在mtd/nand/nand_base.c中实现了。

/**
 * nand_scan_tail - [NAND Interface] Scan for the NAND device
 * @mtd:	    MTD device structure
 * @maxchips:	    Number of chips to scan for
 *
 * This is the second phase of the normal nand_scan() function. It
 * fills out all the uninitialized function pointers with the defaults
 * and scans for a bad block table if appropriate.
 */
int nand_scan_tail(struct mtd_info *mtd)
{
  
    ......


/* Fill in remaining MTD driver data */
	mtd->type = MTD_NANDFLASH;
	mtd->flags = MTD_CAP_NANDFLASH;
	mtd->erase = nand_erase;
	mtd->point = NULL;
	mtd->unpoint = NULL;
	mtd->read = nand_read;
	mtd->write = nand_write;
	mtd->read_oob = nand_read_oob;
	mtd->write_oob = nand_write_oob;
	mtd->sync = nand_sync;
	mtd->lock = NULL;
	mtd->unlock = NULL;
	mtd->suspend = nand_suspend;
	mtd->resume = nand_resume;
	mtd->block_isbad = nand_block_isbad;
	mtd->block_markbad = nand_block_markbad;

    .......
}

2、数据结构nand_chip的实现       

       数据结构nand_chip里的绝大部分成员都由内核已经实现好了,少数成员需要根据控制器和NAND FLASH芯片单独实现,这些成员有:

(1)IO_ADDR_R、IO_ADDR_W

       读8位I/O线地址、写8位I/O线地址

(2)cmd_ctrl

       命令、地址、数据控制函数

(3)dev_ready

      设备是否就绪函数

(4)erase_cmd

      擦除命令的处理函数

(5)chip_delay

      由板决定的延迟时间

(6)options

      与具体的NAND芯片相关的一些选项,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等。

(7)ecc

       如果ecc计算等由硬件完成,则也需要根据具体的处理器实现ecc成员的某些成员。

四、U-BOOT的NAND Flash驱动的使用

       U-BOOT的NAND Flash驱动的使用范例可以参看common/cmd_nand.c文件里的函数do_nand。

五、U-BOOT的NAND Flash驱动的移植

        U-BOOT的NAND Flash驱动的移植可以参看博文https://blog.csdn.net/kunkliu/article/details/82183311

 

参考博文:

https://blog.csdn.net/qq_38880380/article/details/78884522

https://blog.csdn.net/shengnan_wu/article/details/8116861?utm_medium=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-searchFromBaidu-1.control

https://www.cnblogs.com/chd-zhangbo/p/5407754.html

https://blog.csdn.net/liukun321/article/details/6598921

 

 

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1 章  BOOTLOADER 的概念与功能.................................................................................................................... 4   1.1  嵌入式LINUX软件结构与分布 ........................................................................................................................... 4   1.2  在嵌入式LINUX中B OOT LOADER 的必要性............................................................................................................. 4   1.3  BOOT LOADER的功能和选择 ............................................................................................................................... .. 5   第2 章  U‐BOOT简介............................................................................................................................................ 6   2.1  U‐BOOT的起源............................................................................................................................... .......................... 6   2.2  U‐BOOT的开发情况和资源 ............................................................................................................................... ...... 6   第3 章  开发环境搭建......................................................................................................................................... 8   3.1  交叉编译工具链的安装 ............................................................................................................................... ....8   3.2  网路服务的设置 ............................................................................................................................... ................8   3.2.1安装配置TFTP 服务............................................................................................................................... ............. 8   3.2.2安装配置NFS服务............................................................................................................................... ............... 9   3.3  串口终端程序的安装配置 ............................................................................................................................. 10  3.3.1  C‐kermit 的安装配置(推荐安装) ................................................................................................................ 10  3.3.2  minicom的安装配置 ............................................................................................................................... ....11  第4 章  熟悉U‐BOOT的使用与烧写.................................................................................................................... 13  4.1  烧写U‐BOOT到MINI2440开发板 ....................................................................................................................... 13  4.2  常用U‐BOOT命令详解............................................................................................................................... ....... 13  4.2.1获取帮助 ............................................................................................................................... ........................... 13  4.2.2环境变量与相关指令 ............................................................................................................................... ....... 15  4.2.3串口传输命令 ............................................................................................................................... ................... 17  4.2.4网络命令 ............................................................................................................................... ........................... 19  4.2.5  NanFlash操作指令 ............................................................................................................................... ... 21  4.2.6  内存/ 寄存器操作指令 ............................................................................................................................... 24  4.2.7  Nor Flash指令............................................................................................................................... .............. 26  4.2.8  USB 操作指令 ............................................................................................................................... .............. 29  4.2.9  SD卡(MMC) 指令 ............................................................................................................................... .......... 32  4.2.10   FAT文件系统指令 ............................................................................................................................... ........33  4.2.11 系统引导指令 ............................................................................................................................... ................. 34  4.2.13   其他指令............................................................................................................................... ................. 36  4.3  下载与烧写 ............................................................................................................................... ...................... 37   4.3.1  通过SD卡烧入Nand Flash:..................................................................................................................... 37   4.3.2  通过U盘烧入N or Flash:......................................................................................................................... 37   4.3.3  通过TFTP 服务烧入NanFlash:............................................................................................................... 38  4.3.4  通过NFS  服务烧入NanFlash:................................................................................................................ 38  4.4  内核引导............................................................................................................................... .......................... 39  4.4.1  通过SD卡引导内核: ............................................................................................................................... . 40  4.4.2  通过TFTP 服务引导内核 ............................................................................................................................. 41  4.4.3  通过NFS服务引导内核: .......................................................................................................................... 41  4.4.4  通过NanFlash引导内核:....................................................................................................................... 42  第5 章  U‐BOOT源码简要分析........................................................................................................................... 44  5.1  U-BOOT 源码整体框架............................................................................................................................... ..... 44  5.2  U‐BOOT代码的大致执行流程(以S3C24 X0 为例)............................................................................................. 45  第6 章  U‐BOOT在MINI2440上的移植............................................................................................................... 53  6.1  建立开发板文件,测试编译环境 ................................................................................................................. 53  6.1.1  修改顶层Makefile ...................................................................................................................................... 53  6.1.2  在/board 中建立mini2440 目录和文件 ..................................................................................................... 54  6.1.3  在include/configs/ 中建立开发板配置文件 ............................................................................................... 54  6.1.4  测试编译环境 ............................................................................................................................... ............. 55  .2  第一阶段: 探索启动代码 ............................................................................................................................... . 55  6.2.1  关闭为AT9200 写的LED 跳转 ...................................................................................................................... 56  6.2.2  修改CPU 频率初始化设置 .......................................................................................................................... 56  6.2.3  修改lowlevel_init.S 文件............................................................................................................................. 57   6.2.4  修改代码重定向部分............................................................................................................................... .. 58  6.2.5  增加LED 的点亮操作 ............................................................................................................................... ... 66  .3  第二阶段: 修改初始化代码 ............................................................................................................................ 67  6.3.1  修改lib_arm/board.c 文件.......................................................................................................................... 68  6.3.2  修改board/tekkamanninja/mini2440/mini2440.c 文件。 .......................................................................... 69  .4  第三阶段:完善目标板外设驱动 ................................................................................................................. 73  6.4.1  NanFlash相关代码的修改....................................................................................................................... 73  6.4.2  添加Yaffs(2)镜像烧写功能 ........................................................................................................................ 75  6.4.3  修改Nor  Flash写入功能的代码 ................................................................................................................. 79  6.4.4  修改网络相关代码............................................................................................................................... ...... 84  6.4.5  添加串口Xmodem 传输协议(可不修改) .............................................................................................. 85  6.4.6  添加LCD 显示功能 ............................................................................................................................... ....... 87   6.4.7  添加SD卡(MMC)读取功能 ................................................................................................................... 92  .5  第四阶段:修正配置文件 ........................................................................................................................... 108   6.5.1  添加CONFIG_S3C2440条件定义 ............................................................................................................. 108   6.5.2  修改配置文件include/configs/mini2440.h .............................................................................................. 116   .6  重新编译并测试 ............................................................................................................................... ............121   章  下载最新的源代码.............................................................................................................................. 121  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值