Chinaunix首页 | 论坛 | 博客
  • 博客访问: 851727
  • 博文数量: 213
  • 博客积分: 5048
  • 博客等级: 大校
  • 技术积分: 1883
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-14 10:14
文章分类

全部博文(213)

文章存档

2011年(4)

2010年(55)

2009年(47)

2008年(107)

我的朋友

分类: 嵌入式

2009-12-14 22:12:54

我们可以先跟着代码走,我把函数间关系和主要代码列出来。
上来是一个mtd选择的过程,cfi部分将会走下面个过程:(我们假设我们cpu是s3c2410,以后都是)
第一个过程:
mtd_dev_init() [mtdcore.c] -> mtd_init() [s3c2410_flash.c] -> cfi_init()[s3c2410_flash.c]
前面两个函数是mtd的公共函数。
 

static int
cfi_init(void)
{
    s3c2410_map.buswidth = FLASH_BUSWIDTH;

    s3c2410_map.size = FLASH_SIZE;

    s3c2410_map.set_vpp = set_vpp;

    mymtd = do_map_probe("cfi_probe", &s3c2410_map);
    if (!mymtd) return -ENXIO;

    return 0;
}

首先对s3c2410_map结构体的初始化。
s3c2410_map是一个map_info结构体全局变量,前面已经做了标记化结构初始化(对于这个初始化解释可以看http://blog.chinaunix.net/u2/66435/showart.php?id=1299732

static struct map_info s3c2410_map = {
    name:        "S3C2410 flash",
    read8:        s3c2410_read8,
    read16:        s3c2410_read16,
    read32:        s3c2410_read32,
    copy_from:    s3c2410_copy_from,
    write8:        s3c2410_write8,
    write16:    s3c2410_write16,
    write32:    s3c2410_write32,
    copy_to:    s3c2410_copy_to,

    map_priv_1:    WINDOW_ADDR,
    map_priv_2:    -1,
};

然后调用do_map_probe函数,获得一个mtd_info结构体。

第二个过程:

do_map_probe()[chipreg.c]->get_mtd_chip_driver()[chipreg.c]->cfi_probe()[cfi_probe.c]->mtd_do_chip_probe()[gen_probe.c]

前面两个函数是norflash的公共函数,针对cfi和amd分别调用不同函数。

cfi_probe函数

struct mtd_info *cfi_probe(struct map_info *map)
{
    return mtd_do_chip_probe(map, &cfi_chip_probe);
}

cfi_probe函数传了两个参数map_info前面已经说了,cfi_chip_probe这个参数是struct chip_probe,初始化如下:

static struct chip_probe cfi_chip_probe = {
    name: "CFI",
    probe_chip: cfi_probe_chip
};

其实就是给mtd_do_chip_probe一个函数指针cfi_probe_chip[cfi_probe.c],这个函数后面会用来嗅探芯片类型

我们来好好看看这个函数:

struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)

{
    struct mtd_info *mtd = NULL;
    struct cfi_private *cfi;

    cfi = genprobe_ident_chips(map, cp);
    
    if (!cfi)
        return NULL;

    map->fldrv_priv = cfi;

    mtd = check_cmd_set(map, 1); /* First the primary cmdset */
    if (!mtd)
        mtd = check_cmd_set(map, 0); /* Then the secondary */
    
    if (mtd)
        return mtd;

    return NULL;
}
这个函数主要做了两件事:
1、调用genprobe_ident_chips得到struct cfi_private结构,这个结构保存芯片cfi的信息,在结构体那篇我讲了他们的关系。
2、调用check_cmd_set得到一个信息齐全的mtd_info结构体,这也是我们最终想要的。
第三个过程:
genprobe_ident_chips()[gen_probe.c]->genprobe_new_chip()[gen_probe.c]
genprobe_new_chip()函数中:

switch (map->buswidth) {   
    case CFIDEV_BUSWIDTH_1:
        cfi->interleave = CFIDEV_INTERLEAVE_1;

        cfi->device_type = CFI_DEVICETYPE_X8;
        if (cp->probe_chip(map, 0, NULL, cfi))
            return 1;

        cfi->device_type = CFI_DEVICETYPE_X16;
        if (cp->probe_chip(map, 0, NULL, cfi))
            return 1;
        break;   
上面就是genprobe_new_chip函数所要做的事情的一个case
根据buswidth来猜测interleave和device_type的类型,然后调用cfi_probe_chip[cfi_probe.c]函数来嗅探,失败则会把剩下的可能都嗅探一遍,成功则cfi被适当的赋值了,返回1,如果都失败了,返回0
cfi_probe_chip在这次调用主要作用是调用cfi_chip_setup[cfi_probe.c]来读取芯片的cfi信息,然后填进struct cfi_private结构的struct cfi_ident结构中去。我们会发现在cfi_probe_chip中是通过cfi->numchips来判断是不是首次调用。
我们这样直到genprobe_new_chip的作用就是得到芯片的cfi信息,然后填到struct cfi_ident中去。
接着genprobe_ident_chips在做必要struct cfi_private结构初始化,而且在根据interleave,多次调用cfi_probe_chip,这次cfi_probe_chip函数主要作用是确定每块芯片的存在,然后在struct flchip中填写每块芯片的start地址。
最后我们得到了主要的芯片cfi信息,和每块芯片的一些必要信息,如start地址。
第四个过程:
check_cmd_set()[gen_probe.c]->cfi_cmdset_0001()[cfi_cmdset_0001.c]
check_cmd_set函数先通过cfi信息中的P_ID或者A_ID决定调用什么cmdset,vivi中只支持0001,也就是intel命令集。
cfi_cmdset_0001主要就两件事,首先或者cfi接口的额外信息如intel的用结构体struct cfi_pri_intelext表示,amd里面用struct cfi_pri_amdstd表示(vivi中没有cfi_cmdset_0002(),所以这个结构也不存在),然后就是mtd的进一步初始化,主要有像写,读,擦等操作的函数。

这个时候关于cfi的mtd_info就生成了。以后对flash的操作就可以通过他来了,而不要关心底层的实现了。

btw:vivi对cfi里面支持不是很好,比如只支持intel类型的,amd类型的不支持,sst这种怪胎的cfi那就更不支持了,还需要修改很多。不过vivi好像很早出现,以后没人维护了。。
阅读(2783) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~