U-BOOT Nand命令支持

U-BOOT Nand命令支持

u-boot1.1.6 nand_legacy驱动提供了u-bootnand相关命令的一个轻量级的实现,但好象可扩展性不足。本文主要分析u-boot 1.16/drivers/nand文件夹下的源程序。

.关键数据结构

1.struct mtd_info

该结构在include/linux/mtd/Mtd.h中定义,字段比较多,有很多还是函数指针,它是MTD设备操作的通用接口,这个结构中有一个比较重要的成员 void *privpriv被声明成void指针,在下文的分析中会知道priv实际上指向了nand_chip结构。

2.struct nand_chip

   该结构在include/linux/mtd/Nand.h中定义,从名字上看就知道u-boot用它来描述Nand Flash芯片的结构,比如它定义了页地址的偏移,页地址的位掩码等。struct nand_chip不用我们手动的初始化,而是由另外一个结构,struct nand_flash_dev在程序中动态的初始化。

3.struct nand_flash_dev

    该结构的定义有两处地方分别是

include/linux/mtd/nand_legacy.h nand_legacy模块使用

include/linux/mtd/nand.h       u-boot通用nand架构使用

特别是在移植的时候要小心把两者混淆。我们先来看看改结构的定义

struct nand_flash_dev {

       char *name;           

       int id;

       unsigned long pagesize;

       unsigned long chipsize;

       unsigned long erasesize;

       unsigned long options;

};

name : Nand Flash名称

id : u-boot内部id编号???

chipsize : MB为单位的芯片大小,比如64M

erasesize : 擦除块的大小,比如0x400016K

options : 一些选项,比较重要的是Flash的数据位宽,如果你的Nand Flash16位宽的,则必须包含NAND_BUSWIDTH_16选项。我们必须根据所使用的Nand Flash来填充里面的字段。

4.关键数据结构在程序中的使用

struct nand_info_t nand_info[ CFG_MAX_NAND_DEVICE ];

drivers/nand/nand.c中定义。CFG_MAX_NAND_DEVICE是板子的Nand Flash芯片的数量必须在板子的配置文件中定义(比如 include/configs/smdk2410.h)。

 

static struct nand_chip nand_chip[CFG_MAX_NAND_DEVICE];

drivers/nand/nand.c中定义。CFG_MAX_NAND_DEVICE的定义同上。

 

struct nand_flash_dev nand_flash_ids[] = { … };

drivers/nand/nand_ids.c中定义。这里要注意一点,在include/linux/mtd/nand_ids.h里面也nand_flash_ids[]的定义,那是由nand legacy驱动模块使用的。两者不能混淆!!!。在nand_flash_ids的定义中我找到了适合我的Nand Flash的结构描述:

{"NAND 64MiB 3,3V 8-bit",        0x76, 512, 64, 0x4000, 0}

设备 ID 0x76 ,页大小为 512Byte ,总的容量为 64M ,擦除块为 0x4000 16K ),数据位宽 8Bit 。如果你的 Nand Flash 没有合适的描述,需要自己在该数组中添加相应的定义。
 

.Nand Flash初始化

 

1.nand_init drivers/nand/nand.c

nand_init函数在lib_xxx/Board.cstart_armboot中调用。是u-boot Nand的主函数。nand_init的主要功能是对CFG_MAX_NAND_DEVICENand设备进行初始化(调用nand_init_chip,累加Nand Flash的总大小。在nand_init结束时,可以配置是否执行board_nand_select_device,选择Nand芯片。

2.nand_init_chip drivers/nand/nand.c

static void nand_init_chip struct mtd_info *mtd, struct nand_chip *nand, ulong base_addr )调用各个开发板提供的 board_nand_init 函数( board/<board name>/<board name>.c )让开发板获得初始化Nand Flash芯片的机会。调用 nand_scan

3.nand_scan drivers/nand/nand_base.c

int nand_scan( struct mtd_info *mtd, int maxchips )

这是u-boot初始化nand设备的核心函数。它主要完成以下工作

 

1)初始化nand_chip的函数指针,这些函数一般在 board/<board name>/<board name>.c中定义。

struct nand_chip *this = mtd->priv

....

if( this-> cmdfunc == NULL )

       this->cmdfunc = nand_command;

上面是初始化nand_chipcmdfunc指针的代码,如果在board_init_nand中开发板没有提供自己的nand_command函数,u-boot 将使用默认的nand_command函数(我觉得u-boot提供的这些默认的函数都不适合特定的硬件,所以很多都要自己重新写)。

 

2)使用上面注册的函数指针,读取Nand Flash的设备,并且在上文提到的nand_flash_ids[]中找是否有匹配项,若找到匹配的项,则初始化 nand_chip mtd_info,它们的初始化代码老长的一段,一般没什么问题。

 

. Nand Flash 操作

1. Read

函数调用层次:(如下图)。 

common/env_nand.c里面读取Nand Flash中的环境变量为例

common/env_nand.c

ret = nand_read( &nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr );

 

nand_info[]就是我们在1.4讲到的nand_info_tmtd_info的别名)数组。此处的nand_read是个inline函数,下面是它的实现:

 

include/nand.h

static inline int nand_read(nand_info_t *info, ulong ofs, ulong *len, u_char *buf)

{

       return info->read(info, ofs, *len, (size_t*)len, buf);

}

 

可以看出nand_read实际上调用的是nand_inforead方法。nand_inforead方法是在2.3中讲到的nand_scan中初始化

drivers/nand/nand_base.c

int nand_scan(struct mtd_info *mtd, int machips)

{

      

       mtd->read = nand_read;

      

}

此处又一个nand_read!!!

 

drivers/nand/nand_base.c

static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)

{

       return nand_read_ecc( mtd, from, len, retlen, buf, NULL, NULL );

}

 

又一层包装!!!

 

drivers/nand/nand_base.c

static int nand_read_ecc(…)

{

      

}

终于到达最后一层了,nand_read_ecc通过调用nand_chip里面提供的函数对nand flash完成读的操作。具体可以看看代码,老长的一段。

你可能感兴趣的:(数据结构,struct,command,Flash,null,byte)