U-BOOT Nand命令支持

    技术2022-06-08  36

     

    原文链接:http://blogold.chinaunix.net/u1/47239/showart_376731.html

     

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

    . 关键数据结构

    1.struct mtd_info

    该结构在 include/linux/mtd/Mtd.h 中定义,字段比较多,有很多还是函数指针,它是 MTD 设备操作的通用接口,这个结构中有一个比较重要的成员 void *priv priv 被声明成 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 为单位的芯片大小,比如 64 M

    erasesize : 擦除块的大小,比如 0x4000 16K

    options : 一些选项,比较重要的是 Flash 的数据位宽,如果你的 Nand Flash 16 位宽的,则必须包含 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.c start_armboot 中调用。是 u-boot Nand 的主函数。 nand_init 的主要功能是对 CFG_MAX_NAND_DEVICE Nand 设备进行初始化(调用 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_chip cmdfunc 指针的代码,如果在 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_t mtd_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_info read 方法。 nand_info read 方法是在 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 完成读的操作。具体可以看看代码,老长的一段。


    最新回复(0)