首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

如何编写Linux下Nand Flash驱动 - 07

如何编写Linux下Nand Flash驱动 - 07

本帖最后由 samwalton 于 2013-9-7 15:30 编辑

可以看出,此处的实现相当地的简单,就是读取对应的IO的地址,然后就可以把数据读出来就可以了。不过,要注意的是,并不是所有的驱动都是这么简单,具体情况则是不同的Nand Flash控制器对应不同实现方法。
    至此,关于整个的Nand Flash的读取一页的数据的操作,是如何将硬件的逻辑时序图,映射到对应的软件的实现的,就已经介绍完了。而看懂了这个过程,你才会更加明白,原来MTD层,已经帮助我们实现了很多很多通用的操作所对应的软件部分,而只需要我们实现剩下那些和具体硬件相关的操作的函数,就可以了,可以说大大减轻了驱动开发者的工作量。
    因为,如果没了MTD层,那么上面那么多的函数,几乎都要我们自己实现,单单是代码量,就很庞大,而且再加上写完代码后的驱动测试功能是否正常,使得整个驱动开发,变得难的多得多。
    2.2.3.Nand flash驱动工作原理
    在介绍具体如何写Nand Flash驱动之前,我们先要了解,大概的整个系统,和Nand Flash相关的部分的驱动工作流程,这样,对于后面的驱动实现,才能更加清楚机制,才更容易实现,否则就是,即使写完了代码,也还是没搞懂系统是如何工作的了。
    让我们以最常见的,Linux内核中已经有的三星的Nand Flash驱动,来解释Nand Flash驱动具体流程和原理。
    此处是参考2.6.29版本的Linux源码中的\drivers\mtd\nand\s3c2410.c,以2410为例。
    在Nand Flash驱动加载后,第一步,就是去调用对应的init函数,s3c2410_nand_init,去将在Nand Flash驱动注册到Linux驱动框架中。
    驱动本身,真正开始,是从probe函数,s3c2410_nand_probe->s3c24xx_nand_probe,
    在probe过程中,去用clk_enable打开Nand Flash控制器的clock时钟,用request_mem_region去申请驱动所需要的一些内存等相关资源。然后,在s3c2410_nand_inithw中,去初始化硬件相关的部分,主要是关于时钟频率的计算,以及启用Nand Flash控制器,使得硬件初始化好了,后面才能正常工作。
    需要多解释一下的,是这部分代码:
    for (setno = 0; setno < nr_sets; setno++, nmtd++) {
    pr_debug("initialising set %d (%p, info %p)\n", setno, nmtd, info);
    /* 调用init chip去挂载你的nand 驱动的底层函数到Nand Flash的结构体中,以及设置对应的ecc mode,挂载ecc相关的函数 */
    s3c2410_nand_init_chip(info, nmtd, sets);
    /* scan_ident,扫描nand 设备,设置Nand Flash的默认函数,获得物理设备的具体型号以及对应各个特性参数,这部分算出来的一些值,对于Nand Flash来说,是最主要的参数,比如nand falsh的芯片的大小,块大小,页大小等。 */
    nmtd->scan_res = nand_scan_ident(&nmtd->mtd,
    (sets) ? sets->nr_chips : 1);
    if (nmtd->scan_res == 0) {
    s3c2410_nand_update_chip(info, nmtd);
    /* scan tail,从名字就可以看出来,是扫描的后一阶段,此时,经过前面的scan_ident,我们已经获得对应Nand Flash的硬件的各个参数,然后就可以在scan tail中,根据这些参数,去设置其他一些重要参数,尤其是ecc的layout,即ecc是如何在oob中摆放的,最后,再去进行一些初始化操作,主要是根据你的驱动,如果没有实现一些函数的话,那么就用系统默认的。 */
    nand_scan_tail(&nmtd->mtd);
    /* add partion,根据你的Nand Flash的分区设置,去分区 */
    s3c2410_nand_add_partition(info, nmtd, sets);
    }
    if (sets != NULL)
    sets++;
    }
    等所有的参数都计算好了,函数都挂载完毕,系统就可以正常工作了。
    上层访问你的nand falsh中的数据的时候,通过MTD层,一层层调用,最后调用到你所实现的那些底层访问硬件数据/缓存的函数中。
    3.     Linux下Nand Flash驱动编写步骤简介
    关于上面提到的,在nand_scan_tail的时候,系统会根据你的驱动,如果没有实现一些函数的话,那么就用系统默认的。如果实现了自己的函数,就用你的。
    估计很多人就会问了,那么到底我要实现哪些函数呢,而又有哪些是可以不实现,用系统默认的就可以了呢。
    此问题的,就是我们下面要介绍的,也就是,你要实现的,你的驱动最少要做哪些工作,才能使整个Nand Flash工作起来。
    3.1. 对于驱动框架部分
    其实,要了解,关于驱动框架部分,你所要做的事情的话,只要看看三星的整个Nand Flash驱动中的这个结构体,就差不多了:
    static struct platform_driver s3c2410_nand_driver = {
    .probe            = s3c2410_nand_probe,
    .remove         = s3c2410_nand_remove,
    .suspend = s3c24xx_nand_suspend,
    .resume         = s3c24xx_nand_resume,
    .driver           = {
    .name     = "s3c2410-nand",
    .owner    = THIS_MODULE,
    },
    };
    对于上面这个结构体,没多少要解释的。从名字,就能看出来:
    (1)probe就是系统“探测”,就是前面解释的整个过程,这个过程中的多数步骤,都是和你自己的Nand Flash相关的,尤其是那些硬件初始化部分,是你必须要自己实现的。
    (2)remove,就是和probe对应的,“反初始化”相关的动作。主要是释放系统相关资源和关闭硬件的时钟等常见操作了。
    (3)suspend和resume,对于很多没用到电源管理的情况下,至少对于我们刚开始写基本的驱动的时候,可以不用关心,放个空函数即可。
    3.2. 对于Nand Flash底层操作实现部分
    而对于底层硬件操作的有些函数,总体上说,都可以在上面提到的s3c2410_nand_init_chip中找到:
    static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
    struct s3c2410_nand_mtd *nmtd,
    struct s3c2410_nand_set *set)
    {
    struct nand_chip *chip = &nmtd->chip;
    void __iomem *regs = info->regs;
    chip->write_buf    = s3c2410_nand_write_buf;
    chip->read_buf     = s3c2410_nand_read_buf;
    chip->select_chip  = s3c2410_nand_select_chip;
    chip->chip_delay   = 50;
    chip->priv         = nmtd;
    chip->options    = 0;
    chip->controller   = &info->controller;
    switch (info->cpu_type) {
    case TYPE_S3C2410:
返回列表