uboot nand 备份

本文详细介绍了U-Boot中针对NAND Flash的初始化过程,包括board_nand_init()和nand_scan()函数的调用,以及如何设置NAND Flash的读写函数和片选。在初始化过程中,着重讲解了硬件ECC的配置和坏块管理,特别是如何通过读取和校验OOB区域来识别和标记坏块。同时,文章提到了nand_scan_bbt()函数用于查找和建立坏块表,确保数据的可靠性。
摘要由CSDN通过智能技术生成

1.nand_init_chip()顺序调用board_nand_init()和nand_scan()实现NAND FLASH初始化工作。

2.其中board_nand_init()实现S3C2440 NAND FLASH控制器相关的初始化,设置控制器的时序,设置寄存器的读写地址。

3.nand_scan()主要实现NAND FLASH各种参数设置(比如自动识别NAND FLASH的大小、每一页的大小、数据宽度等信息),设置对NAND FLASH的片选、读写函数以及NAND FLASH的控制命令。

二、读数据函数调用关系

    调用到最后,使用的是一个宏readb,读取nand_chip->IO_ADDR_R地址处的数据,就完成了读数据的过程。对于S3C2440来说,nand_chip->IO_ADDR_R对应的就是NAND FLASH控制器的数据寄存器NFDATA,地址为0x4E000010。


三、关键数据结构

控制NAND FLASH时,通过结构体mtd_info的*priv成员找到对应的结构体nand_chip,然后调用读写、片选等函数,最终实现对NANDFLASH的控制。

struct nand_flash_dev {
char *name;
int id;
unsigned long pagesize;
unsigned long chipsize;
unsigned long erasesize;
unsigned long options;

};

结构nand_flash_dev的内容比较少,其各项含义为:

name:NAND FLASH的厂家名字

id:   NAND FLASH的ID

pagesize:一页的大小,单位为字节Byte

chipsize:整个NAND FLASH 的大小,单位为MB

erasesize:最小擦除大小单位为字节Byte

options:选项
四、获知外接NAND容量大小

   u-boot先读取外接NAND FLASH的ID,根据ID 在struct nand_flash_dev nand_flash_ids[]定义的数组中找到匹配的项,这样就确定NAND FLASH的大小了。

struct nand_flash_dev nand_flash_ids[] = {

……

{"NAND 256MiB 1,8V 8-bit",0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},

};

首先在配置文件smdk2410.h(路径:include/configs/smdk2410.h)的宏CONFIG_COMMANDS中增加CFG_CMD_NAND

   然后,增加NAND FLASH的一些宏,启用NAND FLASH设备。在配置文件smdk2410.h(路径:include/configs/smdk2410.h)中增加以下有关NAND FLASH的宏定义:

/*NAND FLASH config*/

#define CFG_NAND_BASE                         0

#define CFG_MAX_NAND_DEVICE           1

#define NAND_MAX_CHIPS                      1

2.增加NAND FLASH底层驱动

    board_nand_init()主要实现开发板上NAND FLASH芯片K9F2G08的底层驱动。包括芯片时序设置,底层函数的实现。

3.解决其他错误

    增加驱动后,再次编译,出现错误:

In function `s3c2440_nand_select_chip':

undefined reference to `S3C2440_GetBase_NAND'

    提示函数S3C2440_GetBase_NAND()未定义,参考S3C2410_GetBase_NAND(),在s3c2410.h(路径:include/s3c2410.h)中增加函数

static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)

{


return (S3C2440_NAND * const)S3C2440_NAND_BASE;

}

    然后增加S3C2440_NAND_BASE的基址

#define S3C2410_NAND_BASE  0x4E000000

#define S3C2440_NAND_BASE  0x4E000000

nand视作一个MTD设备

ubootnand视作一个mtd设备,所以使用mtd机制对nand设备进行管理。单个nand设备用nand_info_t来描述。而nand_info_t实际上就是mtd结构。最多支持的nand设备数CONFIG_SYS_MAX_NAND_DEVICE可自行配置。

typedef struct mtd_info nand_info_t; 

nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE];

但是仅使用mtd结构来描述不够,因为MTD只是一个通用的存储描述结构,而Nand设备特定的某些属性,如ECC布局等不能简单的添加到mtd结构中。所以,uboot定义了nand_chip结构。

nand_init_chip()中通过以下代码关联nand_info结构和nand_chip结构:

mtd->priv = nand;

使得一个MTD结构既可以描述MTD结构的通用性,又能在需要时访问nand设备特定的属性和操作函数。

基本的nand操作算法

uboot提供了nand设备的通用操作算法,这些操作算法集中在nand_base.c

对于移植而言,开发者需要做的是重新定义board_nand_init(),在该函数中完成NAND设备中的MTD结构部分接口函数和属性的设置。其中某些属性是必须设置的,如下所示:

int board_nand_init(struct nand_chip *nand) 

nand->IO_ADDR_R   = (void __iomem *)(NFDATA); 

nand->IO_ADDR_W  = (void __iomem *)(NFDATA); 

nand->cmd_ctrl        = s3c_nand_hwcontrol; 

nand->dev_ready    = s3c_nand_device_ready; 

nand->ecc.mode        = NAND_ECC_HW;

虽然Nand型号非常多;但是其基本接口都一致,并且读写Nand块、页中数据的算法都是类似的。所以,ubootnand_base.c中提供了与nand控制器无关的操作算法,而与硬件相关的部分则由用户驱动实现。

ECC管理机制

借助存储在OOB区的ECC码,可以检测出读取的数据是否有错误位。而当出现的错误位数在容许的范围内时,可对数据进行纠正,保证读取数据正确,避免丢弃整个块。

uboot使用nand_ecc_ctrl结构来定义ecc相关的操作模式和接口。

对于ECC操作而言,最主要的两个操作为根据输入计算ECC(calculate)和根据ECC码对数据进行纠错(correct)

board_nand_init()中初始化nand驱动接口时,可以根据需要初始化ECC操作接口。

ECC的分组处理

通常ECC码需要分组计算,即将整个nand页划分为成多个部分,每部分数据计算一组ECC码,最后统一放置到OOB区。例如,s5pv2108Bit硬件ECC计算,每512字节生成一组ECC,单个页的ECC计算代码如下:

for (i = 0; eccsteps; eccsteps, i += eccbytes, p += eccsize) { 

s3c_nand_enable_hwecc_8bit(mtd, NAND_ECC_WRITE); 

chip->write_buf(mtd, p, eccsize); 

s3c_nand_calculate_ecc_8bit(mtd, p, &ecc_calc[i]); 

}

硬件ECC

s5pv210支持1位、4位、8位、12位、16位的硬件ECC,相应的ECC检错和纠错代码已经包含在nand驱动源码中。

坏块管理

uBootNand设备的坏块管理有两种:一种是读写时跳过坏块;一种是基于坏块表。

跳过坏块是最简单也是最常见处理方式,在nand_util.cnand_read_skip_badnand_write_skip_bad提供了该种处理方式。

Nand flash芯片工作原理:
------------------------------------
    Nand flash芯片型号为Samsung K9F2G08U0A,数据存储容量为256MB,总线宽度为8bit,页大小为2048字节,需要5个寻址命令,采用块页式存储管理。8I/O引脚充当数据、地址、命令的复用端口。

    芯片内部存储布局及存储操作特点:
    一片Nand flash为一个设备(device), 其数据存储分层为:
    1 (Device) = 2048 (Blocks)
    1 (Block) -= 64  (Pages/Rows) 页与行是相同的意思,叫法不一样

1 (Page)   =  数据块大小(2KB) + OOB 块大小(64Bytes)

在每一页中,最后64个字节(又称OOB)用于Nand Flash命令执行完后设置状态用,剩余2k字节又分为前半部分和后半部分。可以通过Nand Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位通过Nand Flash内置的指针指向各自的首地址。

存储操作特点:

1. 擦除操作的最小单位是块。

2. Nand Flash芯片每一位(bit)只能从1变为0,而不能从0变为1,所以在对其进行写入操作之前要一定将相应块擦除(擦除即是将相应块得位全部变为1).

3. 对于现在常见的页大小为2Knand flash,把块中第一页的OOB部分的第1个字节标志为是否是坏块,如果不是坏块该值为FF,否则为坏块。

4. OOB1字节外,通常至少把OOB的前3个字节存放Nand Flash硬件ECC

------------------------------------

10.nand_default_bby()选择一个坏块描述表,返回时调用本文件中的nand_scan_bbt()

11.nand_scan_bbt()寻找建立一个坏块描述表。

下面对命令nand read addr ofs size的执行流程进行分析:

1.nand read addr ofs size命令的作用是从nand flash地址的偏移量ofs处读取长度为size字节的数据存储到内存地址addr处。

2.common/main.c文件中的main_loop()主要执行read_line()读取命令行。

3.read_line()读取到命令行后会调用common/main.c文件中的run_command()

4.run_command()调用common/command.c文件中的find_cmd().u_boot_cmd段中寻找该命令的cmd_tbl_t结构,找到后返回该结构。该命令的结构是通过定义在include/command.h中的宏定义U_BOOT_CMD登记进.u_boot_cmd段中的。

5.run_command()找到该命令的cmd_tbl_t结构后则执行该命令对应的函数。对于本情景是nand命令对应的函数do_nand()

Nand flash读写模式下的管脚配置

D[7:0] : 数据/命令/地址 输入/输出端口(三线共享)

CLE :   Command Latch Enable   (output)

ALE :   Address Latch Enable     (output)

nFCE :  NAND Flash Chip Enable  (output)

nFRE :  NAND Flash Read Enable  (output)

nFWE :  NAND Flash Write Enable  (output)

R/nB :   NAND Flash Ready/nBusy  (input)

copy_main中,已经介绍的nand_flash的最底层的操作,结合SPC来看,以HY系列的NAND为例,首先是nand_flash的芯片,关注的是IO CE WE RE ALE CLE RB,这里WE REAT91sam9260直接相连,CE 片选 CLE 命令锁存, ALE地址锁存, R/B ready/busy

(1)flash相连的相关口线的配置

(2) 发送命令ReadId 读取marker CodeDevice Code,分析而到页大小,块大小,OOB大小,对于页大小大于512字节的,需要再读后面的2字节

3)发送read命令读取连续数据 

Sequential read 命令为00,页内地址,页偏移,等待ready,读取一页的数据,包括oob,然后再等待ready,在进行读

这里读完一页之后busy的原因是,此时flash将下一页数据从flash写到缓存中,不允许读

4)校验通过ECC

如果使用的是硬件ECC,在读取数据之后会将校验值放在相关寄存器中,读取相关寄存器,进行判断即可。

这里移植或者开发的时候需要注意 ECC校验位长度和起始字节 坏块的起始和长度

5)擦除命令

发送命令0x60,设置需要擦除的页地址(擦除一块),写擦除命令0Xd0,等待擦除完毕,读取I/O0数值,为0则表示擦除成功

6)写数据

写数据先发送命令0X80,页内地址,页偏移,后数据(在一页范围内数据),

Program command 0X10,接着FLASH进入BUSY,等待ready之后,写0x70(read status Command),之后通过读取I/O0判断写数据是否正确

以上就是NAND FLASH中一些比较基本的命令(read_oob之类略)

二层:封装(mtd

对于MTD(memory technology device)

将所有的方法封装在两个结构体中 mtd_info 和 nand_chip

在注册驱动时,调用nand_init_chip,最终注册的就是这两个结构体

上图是mtd_info 和 nand_chip的一些结构封装,对于移植(更换新的NAND FLASH,或者不同的SOC),只要改写底层(就是第二层)的相关函数就可以。

比如读数据的命令,在MTD封装中包括两部分,一部分是nand_chip->cmdctrl发送命令,一部分是nand_chip->read_page,而这两部分都封装在mtd_info *infoinfo->read中,Writeeraseisbad_block类似。

至于ECC部分(移植相关,可以参看stage1copy_main函数的实现),根据不同的页大小配置不同的ECC.Layout

其相关操作在nand_chip

所以移植过程只要注意修改nand_chip结构下的操作方法即可。

三层:驱动的注册和相关调用

U-BOOT中注册驱动的时候调用 nand_init_chip

有四个调用,Board_nand_init(mtd)Nand_scan_identBoard_nand_ecc_init

Nand_scan_tail

对于这四个调用不细说,注册之后只要学会第三层相关调用。

得到对应的mtd_info 结构指针之后,就可以调用相应方法了

包括

Info->read

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值