Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1867102
  • 博文数量: 473
  • 博客积分: 13997
  • 博客等级: 上将
  • 技术积分: 5953
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 11:52
文章分类

全部博文(473)

文章存档

2014年(8)

2013年(38)

2012年(95)

2011年(181)

2010年(151)

分类: LINUX

2010-11-10 10:19:10

具体flash芯片的探测及映射

(1)flash芯片映射信息结构

flash芯片映射信息结构map_info描述了每一排闪存的映射信息。如:每一排闪存的驱动程序、物理地址、读写操作函数和映射地址 等。如果设备需要它,系统就必须把它传递到芯片探测例程do_map_probe中。JEDEC和CFI接口的芯片都用这个探测函数。如果芯片被识别,就 会激活合适的芯片驱动程序并返回一个mtd_info结构。同时,系统使用这个驱动程序的模块地址填充mtd->module,并把它注册到MTD 核心代码中。或者如果有分区,就注册分区。map_info结构保存在mtd->priv域,芯片驱动程序需要的更多的信息通过链接 mtd->priv->fldrv_priv可得到。

flash芯片映射信息结构map_info列出如下(在include/linux/mtd/mtd.h中):
struct map_info {
    char *name;
    unsigned long size;  //flash大小
    unsigned long phys;    //起始物理地址
 
#define NO_XIP (-1UL)
    void __iomem *virt;  //I/O映射的虚拟地址
     void *cached; //8位的字节,它不是实际总线的必要宽度。
    //在再次与第一个芯片通信之前,它是字节上重复的间隔
    int bankwidth;  
#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
 
    map_word (*read)(struct map_info *, unsigned long);
    void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
    void (*write)(struct map_info *, const map_word, unsigned long);
     void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
    /* We can perhaps put in ‘point’ and ‘unpoint’ methods, if we really
        want to enable XIP for non-linear mappings. Not yet though. */
#endif
 
    /*在映射驱动程序的copy_from应用中,映射驱动程序使用缓存是可能的。然而,当芯片驱动程序知道一些flash区域已改变内容时,系统在必要时将通过这个例程发信号给芯片驱动程序,让映射驱动程序使缓存无效。如果没有缓存时,把这个域设为NULL。*/
    void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
    /* set_vpp() must handle being reentered—enable, enable, disable 
        must leave it enabled. */
    void (*set_vpp)(struct map_info *, int);
    unsigned long map_priv_1;
    unsigned long map_priv_2;
    void *fldrv_priv;
    struct mtd_chip_driver *fldrv; //flash芯片驱动程序
};

结构mtd_chip_driver是flash芯片驱动程序的描述,列出如下:
struct mtd_chip_driver {
   struct mtd_info *(*probe)(struct map_info *map);//探测函数
   void (*destroy)(struct mtd_info *);
   struct module *module; //驱动程序的模块结构
   char *name; //驱动程序名
   struct list_head list;
};

(2)flash芯片探测方法及接口标准

每种flash控制芯片可控制多种闪存,这个控制芯片的驱动程序有自己的读写和探测操作函数或者使用通用的操作函数,它注册MTD驱动程序结构 mtd_chip_driver到一个全局链表chip_drvs_list中。当用户使用一种flash闪存时,用户在称为"映射驱动程序"的文件中分 配好地址、进行闪存空间分区后,使用探测程序查找相应的控制芯片驱动程序。映射驱动程序用来填充一些闪存空间分配的一些信息,代码放在 drivers/mtd/map目录下。

在/drivers/mtd/chips目录下有各种flash控制芯片的驱动程序及芯片探测程序,这些文件有chipreg.c、 gen_probe.c、cfi_probe.c、jedec_probe.c、cfi_cmdset_0001.c、 cfi_cmdset_0002.c、map_rom.c、map_ram.c、map_absent.c、amd_flash.c、jedec.c和 sharp.c。CFI设备和JEDEC设备都要用到gen_probe.c文件。

确定flash闪存芯片是否支持CFI接口的方法是:向flash闪存的地址0x55H写入数据0x98H,再从flash闪存的地址 0x10H处开始,读取3个存储单元,如果字符分别为’Q’,’R’和’Y’,那么flash闪存芯片是支持CFI接口的。这个方法在文件 cfi_probe.c函数qry_present中实现。支持CFI接口flash闪存芯片的类型名称为 "cfi_probe"。

也可以用JEDEC(电子电器设备联合会)标准设备模仿CFI接口,探测JEDEC设备的程序在jedec_probe.c中,JEDEC设备的类型为"jedec_probe"。

对于flash芯片,不同的制造商使用不同的命令集,目前Linux的MTD实现的命令集有AMD/Fujitsu的标准命令集和 Intel/Sharp的扩展命令集(兼容Intel/Sharp标准命令集)两个,这两个命令集分别在cfi_cmdset_0002.c和 cfi_cmdset_0001.c中实现。

此外还有一些非CFI标准的Flash,其中"jedec"类型的Flash的探测程序在jedec.c中,"sharp"类型的Flash的探测程序在sharp.c中,"amd_flash"类型的Flash的探测程序在amd_flash.c中。

最后,还有一些非Flash的MTD,比如ROM或absent(无)设备。这些设备的探测程序在map_rom.c、map_ram.c和map_absent.c中。

chip_drvs_list是所有芯片类型的驱动器链表,flash控制芯片的驱动程序通过调用register_mtd_chip_driver() 和unregister_mtd_chip_driver()向此链表中添加或去除MTD芯片驱动结构。这两个函数列出如下(在drivers/mtd /chips/chipreg.c中):
void register_mtd_chip_driver(struct mtd_chip_driver *drv)
{
    spin_lock(&chip_drvs_lock);
    list_add(&drv->list, &chip_drvs_list);
    spin_unlock(&chip_drvs_lock);
}
void unregister_mtd_chip_driver(struct mtd_chip_driver *drv)
{
    spin_lock(&chip_drvs_lock);
    list_del(&drv->list);
    spin_unlock(&chip_drvs_lock);
}

映射驱动程序调用函数do_map_probe来查找对应的控制芯片驱动程序。函数中参数name是控制芯片类型名称,参数是映射驱动程序中设置的flash闪存空间信息。若调用成功时返回MTD设备的结构mtd_info,失败时返回NULL。

函数do_map_probe分析如下(在drivers/mtd/chips/chipreg.c中):

struct mtd_info *do_map_probe(const char *name, struct map_info *map)
{
    struct mtd_chip_driver *drv;
    struct mtd_info *ret;
    //查找得到name类型的控制芯片驱动程序结构
    drv = get_mtd_chip_driver(name);
    if (!drv && !request_module(%s”, name))
        drv = get_mtd_chip_driver(name); 
    if (!drv)
        return NULL;
 
    ret = drv->probe(map); //具体控制芯片驱动程序的探测函数
    //使用计数减1,它可能已是一个探测过的模块,在这不需要再探测, 
    //而在实际的驱动程序中已做处理。
    module_put(drv->module);
    if (ret)
        return ret;
    return NULL;
}


驱动程序实例分析

(1)CFI控制芯片驱动程序

CFI控制芯片驱动程序cfi_probe在drivers/mtd/chip/cfi_probe.c中,这里只做了简单的说明。
static struct mtd_chip_driver cfi_chipdrv = {
    .probe		= cfi_probe,
    .name		= “cfi_probe”,
    .module		= THIS_MODULE
};

函数cfi_probe_init注册驱动程序cfi_chipdrv到全局链表中,函数列出如下:
int __init cfi_probe_init(void)

{

   register_mtd_chip_driver(&cfi_chipdrv);
   return 0;

}; static void __exit cfi_probe_exit(void) {

   unregister_mtd_chip_driver(&cfi_chipdrv);
};

函数cfi_probe调用mtd_do_chip_probe函数来完成了探测操作,在函数cfi_chip_probe中,它调用 qry_present来查询是否是CFI接口,调用函数cfi_chip_setup)初始化cfi_private结构,调用函数 cfi_chip_setup则读出CFI查询结构中的数据。然后,函数mtd_do_chip_probe调用函数check_cmd_set根据 map_info中的信息来设备不同的命令集:cfi_cmdset_0001()或cfi_cmdset_0002(),如果符合的类型没有则调用 cfi_cmdset_unkown。 函数cfi_probe列出如下:
struct mtd_info *cfi_probe(struct map_info *map)
{
    return mtd_do_chip_probe(map, &cfi_chip_probe);
}
 
static struct chip_probe cfi_chip_probe = {
	.name		= “CFI”,
	.probe_chip	= cfi_probe_chip
};

(2)映射驱动程序

用户可设置flash空间映射信息填充在映射驱动程序中,包括该MTD原始设备的起始物理地址、大小、分区情况等。映射驱动程序都在drivers/mtd/maps子目录下。这里简单说明cfi_flagadm映射驱动程序(在cfi_flagadm.c中)。

flagadm_map是映射信息结构,它含有flash存储空间的配置信息,列出如下:
struct map_info flagadm_map = {
		.name =		“FlagaDM flash device”,
		.size =		FLASH_SIZE,
		.bankwidth =	2,
};

flagadm_parts是flash存储空间的分区,列出如下:
struct mtd_partition flagadm_parts[] = {
  {
       .name =		“Bootloader”,
       .offset	=	FLASH_PARTITION0_ADDR,
       .size =		FLASH_PARTITION0_SIZE
   },
   {
       .name =		“Kernel image”,
       .offset =	FLASH_PARTITION1_ADDR,
       .size =		FLASH_PARTITION1_SIZE
   },
   {
       .name =		“Initial ramdisk image”,
       .offset =	FLASH_PARTITION2_ADDR,
       .size =		FLASH_PARTITION2_SIZE
   },
   {	
       .name =		“Persistant storage”,
       .offset =	FLASH_PARTITION3_ADDR,
       .size =		FLASH_PARTITION3_SIZE
   }

};   #define PARTITION_COUNT (sizeof(flagadm_parts)/sizeof(struct mtd_partition

阅读(931) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-11-10 20:30:03

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com