加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Nand flash驱动的编写与移植

发布时间:2020-12-15 18:22:40 所属栏目:百科 来源:网络整理
导读:1 Nand flash工作原理 ??? S3C2410板的Nand?Flash支持由两部分组成:Nand?Flash控制器(集成在S3C2410?CPU)和Nand?Flash存储 芯片(K9F1208U0B)两大部分组成。当要访问Nand Flash中的数据时,必须通过Nand Flash控制器发送命 令才能完成。所以,Nand Flash相当于
1 Nand flash工作原理
??? S3C2410板的Nand?Flash支持由两部分组成:Nand?Flash控制器(集成在S3C2410?CPU)和Nand?Flash存储
芯片(K9F1208U0B)两大部分组成。当要访问Nand Flash中的数据时,必须通过Nand Flash控制器发送命
令才能完成。所以,Nand Flash相当于S3C2410的一个外设,而不位于它的内存地址区.
1.1 Nand flash芯片工作原理
???? Nand?flash芯片型号为Samsung?K9F1208U0B,数据存储容量为64MB,采用块页式存储管理。8个I/O
引脚充当数据、地址、命令的复用端口。
1.1.1 芯片内部存储布局及存储操作特点
??? 一片Nand?flash为一个设备(device),?其数据存储分层为:
1设备(Device)?=?4096?块(Blocks)
1块(Block)?=?32页/行(Pages/rows)???;页与行是相同的意思,叫法不一样
1块(Page)?=?528字节(Bytes)?=?数据块大小(512Bytes)?+?OOB块大小(16Bytes)
??? 在每一页中,最后16个字节(又称OOB)用于Nand?Flash命令执行完后设置状态用,剩余512个字节又
分为前半部分和后半部分。可以通过Nand?Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位通过
Nand?Flash内置的指针指向各自的首地址。
存储操作特点:
1.?擦除操作的最小单位是块。
2.?Nand?Flash芯片每一位(bit)只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前要一定将相应
块擦除(擦除即是将相应块得位全部变为1).
3.?OOB部分的第六字节(即517字节)标志是否是坏块,如果不是坏块该值为FF,否则为坏块。
4.?除OOB第六字节外,通常至少把OOB的前3个字节存放Nand?Flash硬件ECC码(关于硬件ECC码请参看
Nandflash?控制器一节).
1.1.2 重要芯片引脚功能
??? I/O0-I/O7:复用引脚。可以通过它向nand?flash芯片输入数据、地址、nand?flash命令以及输出数据和操作
状态信息。
??? CLE(Command?Latch?Enable):??命令锁存允许
??? ALE(Address?Lactch?Enable):?地址锁存允许
??? -CE:?芯片选择????
??? -RE:?读允许
??? -WE:?写允许
??? -WP:?在写或擦除期间,提供写保护
??? R/-B:?读/忙输出
1.1.3 寻址方式
?? Samsung?K9F1208U0B?Nand?Flash?片内寻址采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行
传送,并进行片内寻址。具体含义如下:
?? 0-7位:字节在上半部、下半部及OOB内的偏移地址
?? 8位:值为0代表对一页内前256个字节进行寻址
???????? 值为1代表对一页内后256个字节进行寻址
?? 9-13位:对页进行寻址?? 14-25位:对块进行寻址
?? 当传送地址时,从位0开始
1.1.4 Nand flash主要内设命令详细介绍
Nand?Flash命令执行是通过将命令字送到Nand?Flash控制器的命令寄存器来执行。
Nand?Flash的命令是分周期执行的,每条命令都有一个或多个执行周期,每个执行周期都有相映代码表示该周
期将要执行的动作。
主要命令有:Read?1、Read?2、Read?ID、Reset、Page?Program、Block?Erase、Read?Status。
详细介绍如下:
1.?Read?1:
功能:表示将要读取Nand?flash存储空间中一个页的前半部分,并且将内置指针定位到前半部分的第一个字节。
命令代码:00h
2.?Read?2:
功能:表示将要读取Nand?flash存储空间中一个页的后半部分,并且将内置指针定位到后半部分的第一个字节。
命令代码:01h
3.?Read?ID:
功能:读取Nand?flash芯片的ID号
命令代码:90h
4.?Reset:
功能:重启芯片。
命令代码:FFh
5.?Page?Program:
功能:对页进行编程命令,?用于写操作。
命令代码:首先写入00h(A区)/01h(B区)/05h(C区),?表示写入那个区;?再写入80h开始编程模式(写入模式),接
下来写入地址和数据;?最后写入10h表示编程结束.
6.?Block?Erase
功能:块擦除命令。
命令代码:首先写入60h进入擦写模式,然后输入块地址;?接下来写入D0h,?表示擦写结束.
7.?Read?Status
功能:读取内部状态寄存器值命令。
命令代码:70h
1.2 Nand Flash 控制器工作原理
?? 对Nand?Flash存储芯片进行操作,?必须通过Nand?Flash控制器的专用寄存器才能完成。所以,不能对Nand?
Flash进行总线操作。而Nand?Flash的写操作也必须块方式进行。对Nand?Flash的读操作可以按字节读取。
1.2.1 Nand Flash控制器特性
1.?支持对Nand?Flash芯片的读、检验、编程控制
2.?如果支持从Nand?Flash启动,?在每次重启后自动将前Nand?Flash的前4KB数据搬运到ARM的内部RAM中
3.?支持ECC校验
1.2.2 Nand Flash控制器工作原理
?? Nand?Flash控制器在其专用寄存器区(SFR)地址空间中映射有属于自己的特殊功能寄存器,就是通过将Nand?
Flash芯片的内设命令写到其特殊功能寄存器中,从而实现对Nand?flash芯片读、检验和编程控制的。特殊功能
寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存详细说明见下一节。
1.3 Nand flash 控制器中特殊功能寄存器详细介绍
1.?配置寄存器(NFCONF)功能:用于对Nand?Flash控制器的配置状态进行控制。
在地址空间中地址:0x4E000000,其中:
Bit15:Nand?Flash控制器使能位,置0代表禁止Nand?Flash控制器,置1代表激活Nand?Flash控制器;
要想访问Nand?Flash芯片上存储空间,必须激活Nand?Flash控制器。在复位后该位自动置0,因此在初始化时
必须将该位置为1。
Bit12:初始化ECC位,置1为初始化ECC;置0为不初始化ECC。
Bit11:Nand?Flash芯片存储空间使能位,置0代表可以对存储空间进行操作;置1代表禁止对存储空
间进行操作。在复位后,该位自动为1。
Bit10-8:TACLS位。根据此设定CLE&ALE的周期。TACLS的值范围在0-7之间。
Bit6-4、2-0分别为:TWRPH0、TWRPH1位。设定写操作的访问周期。其值在0-7之间。
2.?命令寄存器(NFCMD)
功能:用于存放Nand?flash芯片内设的操作命令。
在地址空间中地址:0x4E000004,其中:
Bit0-7:存放具体Nand?flash芯片内设的命令值。其余位保留以后用。
3.?地址寄存器(NFADDR)
功能:用于存放用于对Nand?flash芯片存储单元寻址的地址值。
在地址空间中地址:0x4E000008,其中:
Bit0-7:用于存放地址值。因为本款Nand?flash芯片只有I/O0-7的地址/数据复用引脚且地址是四周
期每次8位送入的,所以这里只用到8位。其余位保留待用。
4.?数据寄存器(NFDATA)
功能:Nand?flash芯片所有内设命令执行后都会将其值放到该寄存器中。同时,读出、写入Nand?flash
存储空间的值也是放到该寄存器。
在地址空间中地址:0x4E00000C,其中:
Bit0-7:用于存放需要读出和写入的数据。其余位保留代用。
5.?状态寄存器(NFSTAT)
功能:用于检测Nand?flash芯片上次对其存储空间的操作是否完成。
在地址空间中地址:0x4E000010,其中:
Bit0:置0表示Nand?flash芯片正忙于上次对存储空间的操作;置1表示Nand?flash芯片准备好接收新
的对存储空间操作的请求。
6.?ECC校验寄存器(NFECC)
功能:ECC校验寄存器
在地址空间中地址:0x4E000014,其中:
??????? Bit0-Bit7:?ECC0
??????? Bit8-Bit15:?ECC1
??????? Bit16-Bit23:?ECC2
1.4 Nand Flash 控制器中的硬件ECC介绍
1.4.1 ECC产生方法
?? ECC是用于对存储器之间传送数据正确进行校验的一种算法,分硬件ECC和软件ECC算法两种,在
S3C2410的Nand?Flash?控制器中实现了由硬件电路(ECC?生成器)实现的硬件ECC。1.4.2 ECC生成器工作过程
?? 当写入数据到Nand?flash存储空间时, ECC生成器会在写入数据完毕后自动生成ECC码,将其放入到
ECC0-ECC2。当读出数据时Nand?Flash?同样会在读数据完毕后,自动生成ECC码将其放到ECC0-ECC2当
中。
1.4.3 ECC的运用
??? 当写入数据时,可以在每页写完数据后将产生的ECC码放入到OOB指定的位置(Byte?6)去,这样就完成了
ECC码的存储。这样当读出该页数据时,将所需数据以及整个OOB读出,然后将指定位置的ECC码与读出数
据后在ECC0-ECC1的实际产生的ECC码进行对比,如果相等则读出正确,若不相等则读取错误需要进行重
读。
2 在ADS下flash烧写程序
2.1 ADS下flash烧写程序原理及结构
??? 基本原理:在windows环境下借助ADS仿真器将在SDRAM中的一段存储区域中的数据写到Nand?flash存
储空间中。烧写程序在纵向上分三层完成:
??? 第一层:?主烧写函数(完成将在SDRAM中的一段存储区域中的数据写到Nand?flash存储空间中);
??? 第二层:?为第一层主烧写函数提供支持的对Nand?flash进行操作的页读、写,块擦除等函数;
??? 第三层:为第二层提供具体Nand?flash控制器中对特殊功能寄存器进行操作的核心函数,该层也是真正的
将数据能够在SDRAM和Nand?flash之间实现传送的函数。
??? 下面对其三层进行分述:
2.2 第三层实现说明
2.1.1 特殊功能寄存器定义
#define?rNFCONF??????(*(volatile?unsigned?int?*)0x4e000000)?
#define?rNFCMD???????(*(volatile?unsigned?char?*)0x4e000004)????????????
#define?rNFADDR?????(*(volatile?unsigned?char?*)0x4e000008)????????????
#define?rNFDATA?????(*(volatile?unsigned?char?*)0x4e00000c)???????????
#define?rNFSTAT??????(*(volatile?unsigned?int?*)0x4e000010)??????
#define?rNFECC????????(*(volatile?unsigned?int?*)0x4e000014)?????
#define?rNFECC0?????(*(volatile?unsigned?char??*)0x4e000014)
#define?rNFECC1?????(*(volatile?unsigned?char?*)0x4e000015)
#define?rNFECC2?????(*(volatile?unsigned?char?*)0x4e000016)
2.1.2 操作的函数实现
1.?发送命令
#define?NF_CMD(cmd) ??????{rNFCMD=cmd;}
2.?写入地址
#define?NF_ADDR(addr) ??????{rNFADDR=addr;}
3.?Nand?Flash芯片选中
#define?NF_nFCE_L() ??????{rNFCONF&=~(1<<11);}
4.?Nand?Flash芯片不选中
#define?NF_nFCE_H() ??????{rNFCONF|=(1<<11);}
5.?初始化ECC
#define?NF_RSTECC() ??????{rNFCONF|=(1<<12);}
6.?读数据#define?NF_RDDATA()? ??????(rNFDATA)
7.?写数据
#define?NF_WRDATA(data)?{rNFDATA=data;}
8.?获取Nand?Flash芯片状态
#define?NF_WAITRB()?????????{while(!(rNFSTAT&(1<<0)));}
0/假:?表示Nand?Flash芯片忙状态
1/真:表示Nand?Flash已经准备好
2.3 第二层实现说明
2.3.1 Nand Flash 初始化
void?NF_Init(void)
{
??? /*?设置Nand?Flash配置寄存器,?每一位的取值见1.3节 */
??? rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
??? /*?复位外部Nand?Flash芯片 */ ?
??? NF_Reset();
}
2.3.2 Nand flash复位
static?void?NF_Reset(void)
??? int?i;
????
??? NF_nFCE_L();??????????/*?片选Nand?Flash芯片*/
??? NF_CMD(0xFF); /*?复位命令????????? */
??? for(i=0;i<10;i++);?????/*?等待tWB?=?100ns.?????*/
??? NF_WAITRB();???????/*?wait?200~500us;??????????*/
??? NF_nFCE_H();?????????/*?取消Nand?Flash?选中*/
2.3.3 获取Nand flash ID
返回值为Nand?flash芯片的ID号
unsigned?short??NF_CheckId(void)
??? unsigned?short?id;
??? NF_nFCE_L();????????????????/*?片选Nand?Flash芯片*/
??? NF_CMD(0x90);?????????????/*?发送读ID命令到Nand?Flash芯片 */
??? NF_ADDR(0x0);?????????????/*?指定地址0x0,芯片手册要求??? */
??? for(i=0;i<10;i++);?????????????/*?等待tWB?=?100ns.?????????????*/
??? id=NF_RDDATA()<<8;??/*?厂商ID(K9S1208V:0xec)???*/
??? id|=NF_RDDATA(); ???????/*?设备ID(K9S1208V:0x76)??*/
??? NF_nFCE_H();?????????????????/*?取消Nand?Flash?选中*/
??? return?id;
}2.3.4 Nand flash写入
以页为单位写入.
参数说明:block??块号
????????? page???页号
????????? buffer??指向内存中待写入Nand?flash中的数据起始位置
返回值:?????0:写错误
???????? 1:写成功
static?int?NF_WritePage(unsigned?int?block,?unsigned?int?page,?unsigned?char?*buffer)
??? unsigned?int?blockPage?=?(block<<5)+page;
??? unsigned?char?*bufPt?=?buffer;
??? NF_RSTECC();????/*?初始化 ECC??????????????*/
??? NF_nFCE_L();?????/*?片选Nand?Flash芯片*/
??? NF_CMD(0x0);????/*?从A区开始写????? */
??? NF_CMD(0x80);??/*?写第一条命令????? */
??? NF_ADDR(0);?????/*??A0~A7?位(Column?Address)???*/
??? NF_ADDR(blockPage&0xff); ???/*?A9-A16,?(Page?Address)?*/
??? NF_ADDR((blockPage>>8)&0xff);???/*?A17-A24,51); font-family:Arial; font-size:14px; line-height:26px">??? NF_ADDR((blockPage>>16)&0xff);??/*?A25,??(Page?Address)?*/
??? for(i=0;i<512;i++)
??? {
NF_WRDATA(*bufPt++); /*?写一个页512字节到Nand?Flash芯片 */
??? }??
??? /*
??? *?OOB一共16?Bytes,?每一个字节存放什么由程序员自己定义,?通常,
??? *?我们在Byte0-Byte2存ECC检验码.?Byte6?存放坏块标志.
??? */
??? seBuf[0]=rNFECC0;??/*?读取ECC检验码0?*/
??? seBuf[1]=rNFECC1;??/*?读取ECC检验码1?*/
??? seBuf[2]=rNFECC2;??/*?读取ECC检验码2?*/
??? seBuf[5]=0xff; ?/*?非坏块标志?????? */
??? for(i=0;i<16;i++)
NF_WRDATA(seBuf[i]); /*?写该页的OOB数据块? */
??? NF_CMD(0x10);???/*?结束写命令 */
??? /*?等待Nand?Flash处于准备状态 */???
??? for(i=0;i<10;i++);???
??? NF_WAITRB();????
?
??? /*?发送读状态命令给Nand?Flash??*/
??? NF_CMD(0x70);
??? for(i=0;i<3;i++);????
??? if?(NF_RDDATA()&0x1)
??? {????/*如果写有错,?则标示为坏块??? */
???? NF_nFCE_H();??/*?取消Nand?Flash?选中*/
NF_MarkBadBlock(block);
return?0;
??? }?else?{?/*?正常退出 */
???? NF_nFCE_H();?/*?取消Nand?Flash?选中*/
???? return?1;
??? }
2.3.5 Nand flash读取
参数说明:block:块号
????????? page:页号
????????? buffer:指向将要读取到内存中的起始位置
返回值:1:读成功
??????? 0:读失败
static?int?NF_ReadPage(unsigned?int?block,51); font-family:Arial; font-size:14px; line-height:26px">??? unsigned?int?blockPage;
??? unsigned?char?ecc0,?ecc1,?ecc2;
??? unsigned?char?*bufPt=buffer;
??? unsigned?char?se[16];???
??? page=page&0x1f;
??? blockPage=(block<<5)+page;
??? NF_RSTECC();????/*?初始化 ECC??????????????*/????
??? NF_nFCE_L();??????/*?片选Nand?Flash芯片*/?
??? NF_CMD(0x00);???/*?从A区开始读????? */
??? NF_ADDR(0);??????/*??A0~A7?位(Column?Address)???*/
??? NF_ADDR(blockPage&0xff); ????/*?A9-A16,51); font-family:Arial; font-size:14px; line-height:26px">??? NF_ADDR((blockPage>>8)&0xff);????/*?A17-A24,51); font-family:Arial; font-size:14px; line-height:26px">??? /*?等待Nand?Flash处于再准备状态 */??
??? for(i=0;i<10;i++);?
??? NF_WAITRB();????/*等待 tR(max?12us)?*/
??? /*?读整个页,?512字节????????????? */
???? *bufPt++=NF_RDDATA();
??? /*?读取ECC码 */
??? ecc0=rNFECC0;
??? ecc1=rNFECC1;
??? ecc2=rNFECC2;
??????? /*?读取该页的OOB块 */
???? se[i]=NF_RDDATA();?
??? NF_nFCE_H();????/*?取消Nand?Flash?选中*/
??? /*?校验ECC码,?并返回 */
??? if(ecc0==se[0]?&&?ecc1==se[1]?&&?ecc2==se[2])
??return?1;
??? else
???? ?return?0;??
2.3.6 Nand flash标记坏块
如果是坏块,?通过写OOB块的Byte6把该块标记为坏块。
参数说明:block块号
返回值:1:ok,成功完成标记。
??????? 0:表示写OOB块正确.
static?int?NF_MarkBadBlock(unsigned?int?block)
??? unsigned?int?blockPage=(block<<5);
??? seBuf[0]=0xff;
??? seBuf[1]=0xff;????
??? seBuf[2]=0xff;????
??? seBuf[5]=0x44;???/*?设置坏块标记 */
??? NF_nFCE_L();???/*?片选Nand?Flash芯片*/?
??? NF_CMD(0x50);???/*?从C区开始写??? */?
??? NF_CMD(0x80);???/*?发送编程命令,?让Nand?Flash处理写状态 */
??? NF_ADDR(0x0);??/*??A0~A7?位(Column?Address)???*/
??? /*?写OOB数据块 */
NF_WRDATA(seBuf[i]);
??? NF_CMD(0x10);????/*?结束写命令 */
??? /*?等待NandFlash准备好 */
??? for(i=0;i<10;i++);??/*?tWB?=?100ns.??*/
??? NF_WAITRB();???? /*读NandFlash的写状态 */??
??? NF_CMD(0x70);????
??? for(i=0;i<3;i++);??/*?twhr=60ns??*/
??? if?(NF_RDDATA()&0x1)?
???? return?0;
???? }?else?{
??? return?1;
2.3.7 Nand Flash检查坏块
检查指定块是否是坏块.
返回值:1:指定块是坏块
??????? 0:指定块不是坏块。
static?int?NF_IsBadBlock(U32?block)
??? U8?data;
????????
??? blockPage=(block<<5);
??? NF_nFCE_L();?????????/*?片选Nand?Flash芯片*/?
??? NF_CMD(0x50);??????/*?Read?OOB数据块?? */
??? NF_ADDR(517&0xf);??/*?A0~A7?位(Column?Address)???*/
??? NF_ADDR(blockPage&0xff);?/*?A9-A16,51); font-family:Arial; font-size:14px; line-height:26px">??? for(i=0;i<10;i++); /*?wait?tWB(100ns)??*/
??? NF_WAITRB();
??? /*?读取读出值 */?
??? data=NF_RDDATA();
??? NF_nFCE_H();???/*?取消Nand?Flash?选中*/
??? /*?如果data不为0xff时,?表示该块是坏块 */
??? if(data?!=?0xff)
???? return?0;????
2.3.8 擦除指定块中数据
参数说明:block?块号
返回值:0:擦除错误。(若是坏块直接返回0;若擦除出现错误则标记为坏块然后返回0)??1:成功擦除。
static?int?NF_EraseBlock(unsigned?int?block)
??? /*?如果该块是坏块,?则返回 */
??? if(NF_IsBadBlock(block))
??????? return?0;
??? NF_nFCE_L();??????/*?片选Nand?Flash芯片*/
??? NF_CMD(0x60);???/*?设置擦写模式????? */
??? NF_CMD(0xd0);???/*?发送擦写命令,?开始擦写 */
??? for(i=0;i<10;i++);?/*?tWB(100ns)?*/
??? NF_WAITRB();?
??? /*?读取操作状态???????? */
??? NF_CMD(0x70);?
NF_MarkBadBlock(block);?/*?标记为坏块 */
??? }??else??{
???????? return?1;
2.4? 第一层的实现
2.4.1?NandFlash烧写主函数说明
参数说明: block?块号
?????????? srcAddress?SDRAM中数据起始地址
?????????? fileSize?要烧写的数据长度
返回值:?无
void?K9S1208_Program(unsigned?int?block,?unsigned?int?srcAddress,?unsigned?int?fileSize)
????? int??i;
???? int??programError=0;
???? U32??blockIndex;
???? U8??*srcPt,??*saveSrcPt;
???? srcPt=(U8?*)srcAddress;?/*?文件起始地址 */
????? blockIndex?=?block;?/*?块号 */???? while(1)
???? {
?????? ??????????saveSrcPt=srcPt;
??????????? /*?如果当前块是坏块,??跳过当前块 */
??????????if(NF_IsBadBlock(blockIndex))
?????? ??????????{
??? ????????????????????blockIndex++;???/*?到下一个块 */
????????????????? continue;
?????????}
??????????? /*?在写之前,?必须先擦除,?如果擦除不成功,?跳过当前块 */
??????????? if(!NF_EraseBlock(blockIndex))
?????????{
?????????????????? blockIndex++;??/*?到下一个块 */
?? ?????????????????????continue;
??????????? /*?写一个块,?一块有32页 */
?????????for(i=0;i<32;i++)
????????????????? /*?写入一个页,?如果出错,?停止写当前块 */
????????????????? if(!NF_WritePage(blockIndex,i,srcPt))
???? ???????????????????{
?????????????????????? programError=1;
?????????????????????? break;
????????????????? }
????????????????? /*?如果操作正常,?文件的写位置加上1页偏移,到下一页的起始位置 */
?????srcPt+=512;
????????????????? /*?如果写地址没有超过文件长度,?继续;?超出则终止写 */
????????????????? if((U32)srcPt>=(srcAddress+fileSize))
???break;
?????????? }
????????/*?如果写一个块时,?其中某一页写失败,?则把写地址恢复写该块之前,?并跳过当前块 */
??????????? if(programError==1)
??????????? {
????????????????? blockIndex++;
????????????????? srcPt=saveSrcPt;
????????????????? programError=0;
??????????? }
??????????? /*?如果写地址没有超过文件长度,51); font-family:Arial; font-size:14px; line-height:26px">??????????? if((U32)srcPt?>=?(srcAddress+fileSize))
????????????????? break;
??????????? /*?如果正常写成功,?继续写下一个块 */
??????????? blockIndex++;
????? }
}3 在U-BOOT对Nand Flash的支持
3.1 U-BOOT对从Nand Flash启动的支持
3.1.1 从Nand Flash启动U-BOOT的基本原理
1.?前4K的问题
??? 如果S3C2410被配置成从Nand?Flash启动(配置由硬件工程师在电路板设置),?S3C2410的Nand?Flash控制器
有一个特殊的功能,?在S3C2410上电后,?Nand?Flash控制器会自动的把Nand?Flash上的前4K数据搬移到4K内部
RAM中,?并把0x00000000设置内部RAM的起始地址,?CPU从内部RAM的0x00000000位置开始启动。这个过
程不需要程序干涉。
??? 程序员需要完成的工作,是把最核心的启动程序放在Nand?Flash的前4K中。
2.??启动程序的安排
???? 由于Nand?Flash控制器从Nand?Flash中搬移到内部RAM的代码是有限的,所以,?在启动代码的前4K里,我
们必须完成S3C2410的核心配置以及把启动代码(UBOOT)剩余部分搬到RAM中运行。以UBOOT为例,?前4K
完成的主要工作,?见第四部分的2.2节。
3.1.2 支持Nand Flash启动代码说明
??? 首先在include/configs/crane2410.h中加入CONFIG_S3C2410_NAND_BOOT,?如下:
#define?CONFIG_S3C2410_NAND_BOOT?????1
支持从Nand?Flash中启动.
1.?执行Nand?Flash初始化
下面代码在cpu/arm920t/start.S中
#ifdef?CONFIG_S3C2410_NAND_BOOT
copy_myself:
mov?r10,?lr
ldr?sp,?DW_STACK_START???@安装栈的起始地址
mov?fp,?#0?????????????????????????????????@初始化帧指针寄存器
bl?nand_reset?????????????????????????????@跳到复位C函数去执行
...
DW_STACK_START:
.word??????STACK_BASE+STACK_SIZE-4
2.?nand_reset?C代码
下面代码被加在/board/crane2410/crane2410.c中
void?nand_reset(void)
??????? int?i;
/*?设置Nand?Flash控制器 */
rNFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);
??????? /*?给Nand?Flash芯片发送复位命令 */
??????? NF_nFCE_L();
??????? NF_CMD(0xFF);
??????? for(i=0;?i<10;?i++);
??????? NF_WAITRB();??????? NF_nFCE_H();
3.??从Nand?Flash中把UBOOT拷贝到RAM
@read?U-BOOT?from?Nand?Flash?to?RAM
ldr???r0,?=UBOOT_RAM_BASE???@?设置第1个参数:?UBOOT在RAM中的起始地址
mov???r1,?#0x0????????????????????????????????@?设置第2个参数:Nand?Flash的起始地址
mov???r2,?#0x20000????????????????????????@?设置第3个参数:?UBOOT的长度(128KB)
bl????nand_read_whole????????????????????@?调用nand_read_whole(),?该函数在board/crane2410/crane2410.c中
tst???r0,?#0x0???????????????????????????????????@?如果函数的返回值为0,表示执行成功.
beq???ok_nand_read????????????????????????@?执行内存比较
4.?从Nand?Flash中把数据读入到RAM中
int?nand_read_whole(unsigned?char?*buf,?unsigned?long?start_addr,?int?size)
int?i,?j;
/*?如果起始地址和长度不是512字节(1页)的倍数,?则返回错误代码 */
if?((start_addr?&?NAND_BLOCK_MASK)?||?(size?&?NAND_BLOCK_MASK))?{
return?-1;
/*?激活Nand?Flash?*/
NF_nFCE_L();
for(i=0;?i<10;?i++);
i?=?start_addr;
while(i?<?start_addr?+?size)?{
/*?读A区 */
rNFCMD?=?0;
/*?写入读取地址 */
rNFADDR?=?i?&?0xff;
rNFADDR?=?(i?>>?9)?&?0xff;
rNFADDR?=?(i?>>?17)?&?0xff;
rNFADDR?=?(i?>>?25)?&?0xff;
NF_WAITRB();
??????????????? /*?读出一页(512字节)?*/
for(j=0;?j?<?NAND_SECTOR_SIZE;?j++,?i++)?{
*buf?=?(rNFDATA?&?0xff);
buf++;
/*?停止驱动Nand?Flash?*/
NF_nFCE_H();
}5.??校查搬移后的数据
把RAM中的前4K与内部中前4K进行比较,?如果完全相同,?则表示搬移成功.
ok_nand_read:
mov?r0,?#0x00000000??????????????????@内部RAM的起始地址
ldr?r1,?=UBOOT_RAM_BASE???@UBOOT在RAM中的起始地址
mov?r2,?#0x400????????????????????????????@比较1024次,?每次4字节,?4?bytes?*?1024?=?4K-bytes
go_next:?????@?比较1024次,?每次4个字节
ldr???r3,?[r0],?#4
ldr???r4,?[r1],51); font-family:Arial; font-size:14px; line-height:26px">teq???r3,?r4
bne??notmatch
subs?r2,?r2,51); font-family:Arial; font-size:14px; line-height:26px">beq??done_nand_read
bne??go_next
notmatch:
1:b?????1b
done_nand_read:
mov?pc,?r10
3.2 U-BOOT对Nand Flash命令的支持
??? 在U-BOOT下对Nand?Flash的支持主要是在命令行下实现对nand?flash的操作。对nand?flash实现的命令
为:nand?info、nand?device、nand?read、nand?write、nand?erease、nand?bad。
??? 用到的主要数据结构有:struct?nand_flash_dev、struct?nand_chip。前者包括主要的芯片型号、存储容量、
设备ID、I/O总线宽度等信息;后者是具体对nand?flash进行操作时用到的信息。
3.2.1 主要数据结构介绍
1.?struct?nand_flash_dev数据结构
该数据结构在include/linux/mtd/nand.h中定义,在include/linux/mtd/nand_ids.h中赋初值。
struct?nand_flash_dev?{
char?*name; ?????????????/*?芯片名称 */
int?manufacture_id;??????????/*?厂商ID?????*/
int?model_id;????????????????????/*?模式ID?????*/
int?chipshift;?????????????????????/*??Nand?Flash地址位数 */
char?page256;???????????????????/*?表明是否时256字节一页。1:是;0:否。*/
char?pageadrlen; ?????????????/*?完成一次地址传送需要往NFADDR中传送几次。*/
unsigned?long?erasesize;??/*?一次块擦除可以擦除多少字节 */
int?bus16;??????????????????????????/*?地址线是否是16位,1:是;0:否 */
};
2.?struct?nand_chip数据结构
该数据结构在include/linux/mtd/nand.h中定义.?该结构体定义出一个Nand?Flash设备数组:
struct?nand_chip?nand_dev_desc[CFG_MAX_NAND_DEVICE];
该数组在nand_probe()中对其进行初始化.
struct?nand_chip?{
int? page_shift;???????????/*??Page?地址位数???????? */
u_char? *data_buf;????????????/*?本次读出的一页数据??? */
u_char? *data_cache;????????/*?读出的一页数据??????? */
int??????????cache_page;?????????/*?上次操作的页号??????? */u_char? ecc_code_buf[6];?/*?ECC校验码??????????? */
u_char? reserved[2];
char?ChipID; ???????????????/*?芯片ID号????????????? */
struct?Nand?*chips;????????????/*?Nand?Flash芯片列表,?表示支持几个芯片为一个设备*/
int?chipshift;
char*?chips_name;????????????/*?Nand?Flash芯片名称???? */
unsigned?long?erasesize;???/*?块擦写的大小?????????? */
unsigned?long?mfr;???????????/*?厂商ID?????????????????????????????????*/
unsigned?long?id;??????????????/*?模式ID????????????????????????????????*/
char*?name;??????????????????????/*?设备名称??????????????? */
int?numchips;???????????????????/*?有几块Nand?Flash芯片?? */
char?page256;??????????????????/*?一页是256字节,?还是512字节 */
char?pageadrlen;??????????????/*?页地址的长度?????????? */
unsigned?long?IO_ADDR;??/*?用于对nand?flash进行寻址的地址值存放处 */
unsigned?long?totlen;????/*?Nand?Flash总共大小?????? */
uint?oobblock;??????????????/*?一页的大小。本款nand?flash为512?????????????????*/
uint?oobsize;?? ?????????/*?spare?array大小。本款nand?flash为16????????????*/
uint?eccsize;?????????????????/*?ECC?大小????????????????? */????????????
int?bus16;?????????????????????/*?地址线是否是16位,1:是;0:否??????? */
3.2.2 支持的命令函数说明
1.?nand?info/nand?device
功能:显示当前nand?flash芯片信息。
函数调用关系如下(按先后顺序):
static?void?nand_print(struct?nand_chip?*nand)?;
2.?nand?erase
功能:擦除指定块上的数据。
int?nand_erase(struct?nand_chip*?nand,?size_t?ofs,?size_t?len,?int?clean);
3.?nand?bad
功能:显示坏块。
static?void?nand_print_bad(struct?nand_chip*?nand);
int?check_block?(struct?nand_chip?*nand,?unsigned?long?pos);
4.?nand?read
功能:读取nand?flash信息到SDRAM。
int?nand_rw?(struct?nand_chip*?nand,?int?cmd,size_t?start,??size_t?*?retlen,?u_char?*?buf);
static?int?nand_read_ecc(struct?nand_chip?*nand,?size_t?start,?
????????????????????? size_t?*?retlen,?u_char?*buf,?u_char?*ecc_code);
static?void?NanD_ReadBuf?(struct?nand_chip?*nand,?u_char?*?data_buf,?int?cntr);
READ_NAND(adr);
5.?nand?write
功能:从SDRAM写数据到nand?flash中。
函数调用关系如下(按先后顺序):int?nand_rw?(struct?nand_chip*?nand,?size_t?*?retlen,51); font-family:Arial; font-size:14px; line-height:26px">static?int?nand_write_ecc?(struct?nand_chip*?nand,?size_t?to,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????? size_t?*?retlen,?const?u_char?*?buf,?u_char?*?ecc_code);
static?int?nand_write_page?(struct?nand_chip?*nand,?int?page,?int?col,?int?last,51); font-family:Arial; font-size:14px; line-height:26px">WRITE_NAND(d?,?adr);
3.2.3 U-BOOT支持Nand Flash命令移植说明
1.?设置配置选项
? 在CONFIG_COMMANDS中,?打开CFG_CMD_NAND选项.
? #define?CONFIG_COMMANDS?
(CONFIG_CMD_DFL ?|?
CFG_CMD_CACHE ?|?
CFG_CMD_NAND ?|?
/*CFG_CMD_EEPROM?|*/?
/*CFG_CMD_I2C ?|*/?
/*CFG_CMD_USB ?|*/?
CFG_CMD_PING?????|?
CFG_CMD_REGINFO??|?
CFG_CMD_DATE ?|?
CFG_CMD_ELF)
#if?(CONFIG_COMMANDS?&?CFG_CMD_NAND)
#define?CFG_NAND_BASE???????????????????0x4E000000????/*?Nand?Flash控制器在SFR区中起始寄存器地址 */
#define?CFG_MAX_NAND_DEVICE???1??????????????????????/*?支持的最在Nand?Flash数据 */
#define?SECTORSIZE?????????????????????????????512?????????????????/*?1页的大小 */
#define?NAND_SECTOR_SIZE??????????????SECTORSIZE
#define?NAND_BLOCK_MASK????????????(NAND_SECTOR_SIZE?–?1)??/*?页掩码 */
#define?ADDR_COLUMN??????????????????????1????/*?一个字节的Column地址 */
#define?ADDR_PAGE?????????????????????????????3???/*?3字节的页块地址,?A9-A25*/
#define?ADDR_COLUMN_PAGE?????????4???/*??总共4字节的页块地址?? */
#define?NAND_ChipID_UNKNOWN???0x00??/*?未知芯片的ID号 */
#define?NAND_MAX_FLOORS????????????1???????
#define?NAND_MAX_CHIPS????????????????1
/*?Nand?Flash命令层底层接口函数 */
#define?WRITE_NAND_COMMAND(d,?adr)?do?{rNFCMD?=?d;}?while(0)
#define?WRITE_NAND_ADDRESS(d,?adr)?do?{rNFADDR?=?d;}?while(0)
#define?WRITE_NAND(d,?adr)?????????do?{rNFDATA?=?d;}?while(0)
#define?READ_NAND(adr)?????????????(rNFDATA)
#define?NAND_WAIT_READY(nand)??????{while(!(rNFSTAT&(1<<0)));}
#define?NAND_DISABLE_CE(nand)?{rNFCONF?|=?(1<<11);}
#define?NAND_ENABLE_CE(nand)?{rNFCONF?&=?~(1<<11);}
/*?下面一组操作对Nand?Flash无效 */
#define?NAND_CTL_CLRALE(nandptr)
#define?NAND_CTL_SETALE(nandptr)
#define?NAND_CTL_CLRCLE(nandptr)
#define?NAND_CTL_SETCLE(nandptr)/*?允许Nand?Flash写校验 */
#define?CONFIG_MTD_NAND_VERIFY_WRITE?1
#endif????/*?CONFIG_COMMANDS?&?CFG_CMD_NAND*/???
2.?加入自己的Nand?Flash芯片型号
??? 在include/linux/mtd/?nand_ids.h中的对如下结构体赋值进行修改:
?? static?struct?nand_flash_dev?nand_flash_ids[]?= {?
?????? ......
????? {"Samsung?K9F1208U0B",????NAND_MFR_SAMSUNG,?0x76,?26,?0,?4,?0x4000,?0},51); font-family:Arial; font-size:14px; line-height:26px">?????? .......
?? }
?? 这样对于该款Nand?Flash芯片的操作才能正确执行。
3.?编写自己的Nand?Flash初始化函数
在board/crane2410/crane2410.c中加入nand_init()函数.?
void?nand_init(void)
?????? /*?初始化Nand?Flash控制器,?以及Nand?Flash?芯片 */
nand_reset();??
?????? /*?调用nand_probe()来检测芯片类型 */
printf?("%4lu?MBn",?nand_probe(CFG_NAND_BASE)?>>?20);
该函数在启动时被start_armboot()调用.
4 在Linux对Nand Flash的支持
4.1 Linux下Nand Flash调用关系
4.1.1 Nand Flash设备添加时数据结构包含关系
??????? struct mtd_partition????????? partition_info[]
??? --> struct s3c2410_nand_set?????? nandset
??? --> struct s3c2410_plat form_nand? superlpplatfrom?
??? --> struct platform_device???????? s3c_device_nand
?在该数据结构的name字段的初始化值"s3c2410-nand",必须与Nand Flash设备驱动注册时
??????? struct device_driver结构中的name字段相同,因为platfrom bus是依靠名字来匹配的.
??? --> struct platform_device???????? *smdk2410_devices[]
4.1.2 Nand Flash设备注册时数据结构包含关系
??? struct device_driver s3c2410_n and_driver?
??? -->struct device *dev
?????? 该数据构由系统分配.
??? -->struct platform_device *pdev
??? -->struct s3c2410_plat form_nand *plat
??? -->struct s3c2410_nand_set nset
??? -->struct mtd_partition
4.1.3? 当发生系统调用时数据结构调用关系
struct mtd_info它的*priv指向chip
??? -->struct nand_chip
? 它的*priv指向nmtd
??? -->struct s3c2410_nand_mtd
它是s3c2410_nand_info的一个字段
??? -->s3c2410_nand_info
它被设为Nand Flash设备驱动的私有数据结构,在Nand Flash设备驱动注册时分配空间.
??? -->struct device
4.2 Linux下Nand Flash驱动主要数据结构说明
4.2.1 s3c2410专有数据结构
1.?s3c2410_nand_set
struct s3c2410_nand_set {
??????? int???????????????????? n r_chips;????? /* 芯片的数目 */
??????? int???????????????????? n r_partitions; /* 分区的数目 */
??????? char??????????????????? *n ame;???????? /* 集合名称?? */
??????? int????????????????????? nr_map;??????? /* 可选,底层逻辑到物理的芯片数目 */
??????? struct mtd_partition??? partitions;??? /* 分区列表?? */
2.?s3c2410_platform_and
struct s3c2410_platform_nand {
??????? /* timing information for controller,all times in nanoseconds */
??????? int???? tacls;? /* 从CLE/ALE有效到 nWE/nOE的时间 */
??????? int???? twrph0; /* nWE/nOE的有效时间 */
??????? int???? twrph1; /* 从释放CLE/ALE到nWE/nOE不活动的时间 */
??????? int???? nr_sets; /* 集合数目 */
??????? struct s3c2410_nand_set sets; /* 集合列表 */
?/* 根据芯片编号选择有效集合 */
??????? void (*select_chip)(struct s3c2410_nand_set,int chip);
3.??s3c2410_nand_mtd
在drivers/mtd/nand/s3c2410.c中,51); font-family:Arial; font-size:14px; line-height:26px">struct s3c2410_nand_mtd {
??????? struct mtd_info???????????????? mt d;??? /* MTD 信息 */
??????? struct nand_chip??????????????? ch ip;?? /* nand flash 芯片信息 */
??????? struct s3c2410_nand_set???????? set;??? /* nand flash 集合???? */
??????? struct s3c2410_nand_info??????? *info;? /* nand flash 信息???? */
??????? int???????????????????????????? scan _res;
};?
4.?s3c2410_nand_info
struct s3c2410_nand_info {
??????? /* mtd info */
??????? struct nand_hw_control????????? co ntroller; /* 硬件控制器 */
??????? struct s3c2410_nand_mtd???????? *mt ds;????? /* MTD 设备表 */
??????? struct s3c2410_platform_nand??? platform;?? /* Nand 设备的平台 */??????? /* device info */
??????? struct device?????????????????? *device;??? /*? 设备指针 */
??????? struct resource???????????????? *area;????? /*? 资源指针 */
??????? struct clk????????????????????? *clk;?????? /* N and Flash 时钟 */
??????? void __iomem??????????????????? *reg s;????? /* 寄存器基地址(map后的逻辑地址) */
??????? int???????????????????????????? mt d_count;? /* MTD的数目 */
??????? unsigned char?????????????????? is_s3c2440;
5.?struct?clk
在arch/arm/mach-s3c2410/clock.h中
struct clk {
??????? struct list_head????? list ;???? /* clock 列表结点 */
??????? struct module??????? *o wner;??? /* 所属模块?????? */?
??????? struct clk?????????? *paren t;?? /* 父结点???????? */
??????? const char?????????? *n ame;???? /* 名称?????????? */
??????? int?????????????????? id;?????? /*? 编号?????????? */
??????? atomic_t????????????? used;???? /*? 使用者计数???? */
??????? unsigned long???????? rate;???? /* 时钟速率?????? */
??????? unsigned long???????? ctrlbit;? /* 控制位???????? */
??????? int???????????????? (*en able)(struct clk *,int enable); /* Clock打开方法 */
4.2.2 Linux 通用数据结构说明
1.?device_driver
include/linux/device.h
struct device_driver {
??????? const char????????????? * n ame; /* 驱动名称? */
??????? struct bus_type???????? * b us;? /* 总线类型? */
??????? struct completion?????? unloaded;? /* 卸载事件通知机制 */
??????? struct kobject????????? kobj; /* sys中的对象 */
??????? struct klist??????????? klist _devices; /* 设备列表 */
??????? struct klist_node?????? knode_bus; /* 总线结点列表 */
??????? struct module?????????? * o wner;/* 所有者? */
??????? /* 设备驱动通用方法 */
??????? int???? (*probe)??????? (struct device * dev) ; /* 探测设备 */
??????? int???? (*remove)?????? (struct device * dev) ; /* 移除设备 */
??????? void??? (*shutdown)???? (struct device * dev) ; /* 关闭设备 */
??????? /* 挂起设备???????? */
??????? int???? (*suspend)????? (struct device * dev,pm_messag e_t state,u32 level) ;
??????? int???? (*resume)??????? (struct device * dev,u32 level) ; /* 恢复 */
2.?platform_device
struct platform_device {
??????? const char????? * name;? /* 名称 */
??????? u32???????????? id;????? /*? 设备编号,-1表示不支持同类多个设备 */
??????? struct device?? dev;???? /* 设备 */
??????? u32???????????? n um_resources; /* 资源数 */
??????? struct resource * resource; /* 资源列表 */};
3. resource
struct resource {
??????? const char name;?????????? /* 资源名称 */?
??????? unsigned long start,end;? /* 开始位置和结束位置 */
??????? unsigned long flags;?????? /* 资源类型 */
??????? /* 资源在资源树中的父亲,兄弟和孩子 */
??????? struct resource *parent,*sibling,*child;
4.?device
struct device {
??????? struct klist??????????? klist _children;? /* 在设备列表中的孩子列表 */
??????? struct klist_node?????? knode_parent;??? /* 兄弟结点 */
??????? struct klist_node?????? knode_driver;??? /* 驱动结点 */
??????? struct klist_node?????? knode_bus;?????? /* 总线结点 */
??????? struct device??????????? parent;????????? /* 父亲???? */
??????? struct kobject kobj;???????????????????? /* sys结点 */
??????? char??? bus_id[BUS_ID_SIZE];???????????
??????? struct semaphore??????? sem;??? /* 同步驱动的信号量? */
??????? struct bus_type * bus;????????? /* 总线类型????????? */
??????? struct device_driver *driver;?? /*? 设备驱动????????? */
??????? void??????????? *driver_dat a;?? /* 驱动的私有数据??? */
??????? void??????????? *plat form_data; /* 平台指定的数据,为device核心驱动保留 */
??????? void??????????? *firmw are_data; /* 固件指定的数据,51); font-family:Arial; font-size:14px; line-height:26px">??????? struct dev_pm_info? power;????? /* 设备电源管理信息 */
??????? u64???????????? *dma_mask;????? /* DMA掩码????????? */
??????? u64???????????? co herent_dma_mask;
??????? struct list_head dma_pools;???? /* DMA缓冲池??????? */
??????? struct dma_coherent_mem *dma_mem; /* 连续DMA内存的起始位置 */
??????? void??? (*release) (struct device * dev) ;? /* 释放设置方法 */
5. nand_hw_control
include/linux/mtd/nand.h
struct nand_hw_control {
??????? spinlock_t?????? lock;????? /* 自旋锁,用于硬件控制 */
??????? struct nand_chip *active;?? /* 正在处理MTD设备??? */
??????? wait_queue_head_t wq;?????? /* 等待队列??????????? */
6. nand_chip
struct nand_chip {
??????? void? __iomem?? *IO_ADDR_R; /* 读地址 */
??????? void? __iomem?? *IO_ADDR_W; /* 写地址 */ /* 字节操作?? */????????
??????? u_char????????? (*read_b yte)(struct mtd_info *mtd);? /* 读一个字节 */????????
??????? void??????????? (*w rite_byte)(struct mtd_info *mtd,u_char byte); /* 写一个字节 */??????
??????? /* 双字节操作 */
??????? u16???????????? (*read_w ord)(struct mtd_info mtd);? /* 读一个字?? */
??????? void??????????? (*w rite_word)(struct mtd_info *mtd,u16 word); /* 写一个字 */???????
??????? /* buffer操作 */
??????? void??????????? (*w rite_buf)(struct mtd_info *mtd,const u_char *buf,int len);
??????? void??????????? (*read_b uf)(struct mtd_info *mtd,u_char *buf,51); font-family:Arial; font-size:14px; line-height:26px">??????? int???????????? (*verify_b uf)(struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? /* 选择一个操作芯片 */????????
??????? void??????????? (*select _chip)(struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? /* 坏块检查操作 */
??????? int???????????? (*b lock_bad)(struct mtd_info *mtd,loff_t ofs,int getchip);
??????? /* 坏块标记操作 */
??????? int???????????? (*b lock_markbad)(struct mtd_info *mtd,loff_t ofs);
??????? /* 硬件控制操作 */
??????? void??????????? (*h wcontrol)(struct mtd_info *mtd,int cmd);
??????? /* 设备准备操作 */
??????? int???????????? (*dev_ready) (struct mtd_info *mtd);
??????? /* 命令发送操作 */
??????? void??????????? (*cmdfun c)(struct mtd_info *mtd,unsigned command,int column,int
page_addr);
??????? /* 等待命令完成 */
??????? int???????????? (*w aitfunc)(struct mtd_info *mtd,struct nand_chip *this,int state);
??????? /* 计算ECC码操作 */
??????? int???????????? (*calculat e_ecc)(struct mtd_info *mtd,const u_char *dat,u_char
*ecc_code);
??????? /* 数据纠错操作? */
??????? int???????????? (*co rrect_data)(struct mtd_info *mtd,u_char *dat,u_char *read_ecc,51); font-family:Arial; font-size:14px; line-height:26px">u_char *calc_ecc) ;
??????? /* 开启硬件ECC */
??????? void??????????? (*en able_hwecc)(struct mtd_info *mtd,int mode);
??????? /* 擦除操作???? */
??????? void??????????? (*erase_cmd) (struct mtd_info *mtd,int page);
??????? /* 检查坏块表?? */
??????? int???????????? (*scan _bbt)(struct mtd_info *mtd);????????
??????? int???????????? eccmo de;??? /* ECC模式????? */????????
??????? int???????????? eccsize;??? /* E CC 计算时使用的字节数 */
??????? int???????????? eccb ytes;?? /* ECC 码的字节数 */
??????? int???????????? eccst eps;?? /* ECC 码计算的步骤数 */
??????? int???????????? ch ip_delay; /* 芯片的延迟时间 */
??????? spinlock_t????? chip_lock;? /* 芯片访问的自旋锁 */
??????? wait_queue_head_t wq;?????? /* 芯片访问的等待队列 */
??????? nand_state_t??? state;????? /* Nand Flash状态 */
??????? int???????????? pag e_shift; /* 页右移的位数,即column地址位数 */
??????? int???????????? ph ys_erase_shift; /* 块右移的位数,即column和页一共的地址位数 */
??????? int???????????? b bt_erase_shift; /* 坏块页表的位数 */
??????? int???????????? ch ip_shift; /* 该芯片总共的地址位数 */
??????? u_char????????? *dat a_buf;? /* 数据缓冲区? */
??????? u_char????????? *o ob_buf;?? /* oob缓冲区? */
??????? int???????????? o obdirty;?? /* oob缓冲区是否需要重新初始化 */
??????? u_char????????? *dat a_poi;? /* 数据缓冲区指针 */
??????? unsigned int??? options;??? /* 芯片专有选项 */
??????? int???????????? b adblockpos;/* 坏块标示字节在OOB中的位置 */
??????? int???????????? n umchips;?? /* 芯片的个数?? */??????? unsigned long?? chipsize;?? /* 在多个芯片组中,一个芯片的大小 */
??????? int???????????? pag emask;?? /* 每个芯片页数的屏蔽字,通过它取出每个芯片包含多少个页 */
??????? int???????????? pag ebuf;??? /* 在页缓冲区中的页号 */
??????? struct nand_oobinfo???? *autooob; /* oob信息 */
??????? uint8_t???????? *bbt;?????? /* 坏块页表 */
??????? struct nand_bbt_descr?? *bbt_td; /* 坏块表描述 */
??????? struct nand_bbt_descr?? *bbt_md; /* 坏块表镜像描述 */
??????? struct nand_bbt_descr?? *badblock_pattern; /* 坏块检测模板 */
??????? struct nand_hw_control? *controller; /* 硬件控制 */
??????? void??????????? *priv; /* 私有数据结构 */
??????? /* 进行附加错误检查 */
??????? int???????????? (*errst at)(struct mtd_info *mtd,int state,51); font-family:Arial; font-size:14px; line-height:26px">status,51); font-family:Arial; font-size:14px; line-height:26px">7. mtd_info
include/linux/mtd/mtd.h
struct mtd_info {
??????? u_char type;????? /* 设备类型???????? */
??????? u_int32_t flags;? /* 设备标志位组???? */
??????? u_int32_t size;?? /* 总共设备的大小?? */
??????? u_int32_t erasesize;? /* 擦除块的大小 */
??????? u_int32_t oobblock; /* OOB块的大小,如:512个字节有一个OOB */
??????? u_int32_t oobsize;? /* OOB数据的大小,如:一个OOB块有16个字节 */
??????? u_int32_t ecctype;? /* ECC校验的类型 */
??????? u_int32_t eccsize;? /* E CC码的大小?? */
??????? char *name;???????? /* 设备名称?????? */
??????? int index;????????? /* 设备编号?????? */
??????? /* oobinfo信息,它可以通过 MEMSETOOBINFO ioctl命令来设置 */
??????? struct nand_oobinfo oobinfo;
??????? u_int32_t oobavail;? /* OOB区的有效字节数,为文件系统提供 */
??????? /* 数据擦除边界信息???????? */
??????? int numeraseregions;
??????? struct mtd_erase_region_info *eraseregions;
??????? u_int32_t bank_size; /* 保留 */
??????? /* 擦除操作 */
??????? int (*erase) (struct mtd_info *mtd,struct erase_info *instr);
??????? /* 指向某个执行代码位置 */
??????? int (*point) (struct mtd_info *mtd,loff_t from,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????? size_t len,size_t *retlen,u_char **mtdbuf);
??????? /* 取消指向 */
??????? void (*unpoint) (struct mtd_info *mtd,u_char * addr,lo ff_t from,size_t len);
?/* 读/写操作 */
??????? int (*read) (struct mtd_info *mtd,size_t len,u_char *buf);
??????? int (*write) (struct mtd_info *mtd,loff_t to,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????? size_t *retlen,const u_char *buf);
?/* 带ECC码的读/写操作 */
??????? int (*read_ecc) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">????????????????????????? u_char *buf,u_char *eccbuf,struct nand_oobinfo *oobsel);
??????? int (*write_ecc) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????????? const u_char *buf,struct nand_oobinfo *oobsel);??????? /* 带OOB码的读/写操作 */
??????? int (*read_oob) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">????????????????????????? u_char *buf);
??????? int (*write_oob) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????????? const u_char *buf);
??????? /* 提供访问保护寄存器区的方法 */
??????? int (*get_fact_prot_info) (struct mtd_info *mtd,struct otp_info *buf,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*read_fact_prot_reg) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????????????????????????????????? size_t *retlen,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*get_user_prot_info) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*read_user_pro t_reg) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*write_user_prot_reg) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">???????????????????????????????????? size_t *retlen,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*lock_user_prot_reg) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? /* 提供readv和writev方法??????? */
??????? int (*readv) (struct mtd_info *mtd,struct kvec *vecs,un signed long count,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????? loff_t from,size_t *retlen);
??????? int (*readv_ecc) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????????? loff_t from,51); font-family:Arial; font-size:14px; line-height:26px">?????????????????????????? struct nand_oobinfo *oobsel);
??????? int (*writev) (struct mtd_info *mtd,const struct kvec *vecs,51); font-family:Arial; font-size:14px; line-height:26px">??????????????????????? unsigned long count,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*writev_ecc) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????????????????????????? unsigned long count,51); font-family:Arial; font-size:14px; line-height:26px">??????????????????????????? u_char *eccbuf,51); font-family:Arial; font-size:14px; line-height:26px">??????? /* 同步操作 */
??????? void (*sync) (struct mtd_info *mtd);
??????? /* 芯片级支持的加/解锁操作 */
??????? int (*lock) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*unlock) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? /* 电源管理操作??????????? */
??????? int (*suspend) (struct mtd_info *mtd);
??????? void (*resume) (struct mtd_info *mtd);
??????? /* 坏块管理操作??????????? */
??????? int (*block_isbad) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">??????? int (*block_markbad) (struct mtd_info *mtd,51); font-family:Arial; font-size:14px; line-height:26px">?/* 重启前的通知事件??????? */
??????? struct notifier_block reboot_notifier;
??????? void *priv; /* 私有数据结构 */
??????? struct module *owner; /* 模块所有者 */
??????? int usecount; /* 使用次数 */
4.3 Linux下Nand Flash驱动说明4.3.1 注册driver_register
通过module_init(s3c2410_nand_init);注册Nand?Flash驱动.?在 s3c2410_nand_init?()中通过driver_register()注册
s3c2410_nand_driver驱动程序,如下所示:
static struct device_driver s3c2410_n and_driver = {
??????? .name?????????? = "s3c2410-n and",51); font-family:Arial; font-size:14px; line-height:26px">??????? .bus??????????? = &plat form_bus_type,/* 在drivers/base/platform.c中定义 */
??????? .probe????????? = s3c2410_n and_probe,51); font-family:Arial; font-size:14px; line-height:26px">??????? .remove???????? = s3c2410_n and_remove,51); font-family:Arial; font-size:14px; line-height:26px">4.3.2 探测设备probe
在注册的Nand Flash驱动程序中,probe方法为s3c2410_nand_probe(). s3c2410_nand_probe()再调用
s3c24xx_nand_probe().?在该函数中,?把*info作为Nand?Flash驱动的私有数据结构,?并通过dev_set_drvdata(dev,51); font-family:Arial; font-size:14px; line-height:26px">info)把*info保存在*device的*driver_data字段中.然后通过clk_get(dev,"nand")获取Nand Flash的时钟资
源,? clk_use(in fo->clk)增加时钟资源的使用计数,clk_enable(info->clk)开启资源.填写*info的其它字段,51); font-family:Arial; font-size:14px; line-height:26px">其中包括:
? 1.?通过request_mem_region()为Nand?Flash寄存器区申请I/O内存地址空间区,并通过ioremap()把它映射到虚
拟地址空间.
? 2.??调用s3c2410_nand_inithw()初始化Nand?Flash控制器.
? 3.??为mtd设备分配设备信息的存储空间.
? 4.??对当前mtd设备,调用s3c2410_nand_init_chip()进行初始化.
? 5.??对当前mtd设备,?调用nand_scan()检测Nand?Flash芯片,?nand_scan()函数在drivers/mtd/nand/nand_base.c中
定义.该函数的作用是初始化struct?nand_chip中一些方法,?并从Nand?Flash中读取芯片ID,?并初始化struct?
mtd_info中的方法.
? 6.??对当前mtd设备,加入其分区信息.
? 7.?如果还有更多mtd设备,到4执行.
4.3.3 初始化Nand Flash控制器
s3c2410_nand_inithw()函数会初始化Nand?Flash控制器,?通过设置Nand?Flash控制寄存器(S3C2410_NFCONF)来
完成,?这里最重要的是根据S3C2410的PCLK计算出tacls,?twrph0以及twrph1值.
4.3.4 移除设备
s3c2410_nand_remove()当设备被移除时,被device核心驱动调用.它完成的主要工作如下:
? 1.?把*device的*driver_data字段置空.
? 2.?释放mtd设备信息.
? 3.?释放clk资源.
? 4.?通过iounmap()取消映地址空间.
? 5.?释放申请的I/O内存资源.
? 6.?释放设备私有数据*info的空间.
4.3.5 Nand Flash芯片初始化
s3c2410_nand_init_chip()初始化struct?nand_chip中的一些主要字段以及方法.其中主要包括的方法有:
? 1.?s3c2410_nand_hwcontrol();?硬件控制
? 2.?s3c2410_nand_devready();?设备是否准备好
? 3.?s3c2410_nand_write_buf();?写一个buffer到nand?flash
? 4.?s3c2410_nand_read_buf();?读一个buffer到nand?flash
? 5.?s3c2410_nand_select_chip();?选择操作芯片
如果支持ECC硬件校验,还设置如下方法:? 1.?s3c2410_nand_correct_data();?通过ECC码校正数据
? 2.?s3c2410_nand_enable_hwecc();?开启硬件ECC检查
? 3.?s3c2410_nand_calculate_ecc();?计算ECC码
4.3.6? 读Nand? Flash
??? 当对nand?flash的设备文件(nand?flash在/dev下对应的文件)执行系统调用read(),或在某个文件系统中对该
设备进行读操作时.?会调用struct mtd_info中的read方法,他们缺省调用函数为nand_read(),在
drivers/mtd/nand/nand_base.c中定义.nand_read()调用nand_do_read_ecc(),执行读操作. 在
nand_do_read_ecc()函数中,主要完成如下几项工作:
1. 会调用在nand flash驱动中对struct nand_chip重载的select_chip方法,即
s3c2410_nand_select_chip()选择要操作的MTD芯片.
2. 会调用在struct nand_chip中系统缺省的方法cmdfunc发送读命令到nand flash.
3. 会调用在nand flash驱动中对struct nand_chip重载的read_buf(),即s3c2410_nand_read_buf()
从Nand Flash的控制器的数据寄存器中读出数据.
4. 如果有必要的话,会调用在nand flash驱动中对struct nand_chip重载的
enable_hwecc,correct_data以及calculate_ecc方法,进行数据ECC校验。
4.3.7? 写Nand Flash
当对nand?flash的设备文件(nand?flash在/dev下对应的文件)执行系统调用write(),或在某个文件系统中对该设备
进行读操作时,?会调用struct mtd_info中write方法,他们缺省调用函数为nand_write(),这两个函数在
drivers/mtd/nand/nand_base.c中定义. nand_write()调用nand_write_ecc(),执行写操作.在
nand_do_write_ecc()函数中,51); font-family:Arial; font-size:14px; line-height:26px">2. 调用nand_write_page()写一个页.
3. 在nand_write_page()中,会调用在struct nand_chip中系统缺省的方法cmdfunc发送写命令
到nand flash.
4. 在nand_write_page()中,51); font-family:Arial; font-size:14px; line-height:26px">write_buf(),即s3c2410_nand_write_buf()从Nand Flash的控制器的数据寄存器中写入数据.
5. 在nand_write_page()中,会调用在nand flash驱动中对struct nand_chip重载waitfunc方法,51); font-family:Arial; font-size:14px; line-height:26px">该方法调用系统缺省函数nand_wait(),该方法获取操作状态,并等待nand flash操作完成.等
待操作完成,是调用nand flash驱动中对struct nand_chip中重载的dev_ready方法,即?
s3c2410_nand_devready()函数.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读