新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > Linux下NAND FLASH驱动开发

Linux下NAND FLASH驱动开发

作者: 时间:2016-10-08 来源:网络 收藏

【 Nand flash 驱动工作原理】

在介绍具体如何写 Nand Flash 驱动之前,我们先要了解,大概的,整个系统,和 Nand Flash 相关的部分的驱动工作流程,这样,对于后面的驱动实现,才能更加清楚机制,才更容易实现,否则就是,即使写完了代码,也还是没搞懂系统是如何工作的了。

让我们以最常见的, Linux 内核中已经有的三星的 Nand Flash 驱动,来解释 Nand Flash 驱动具体流程和原理。

此处是参考 2.6.29 版本的 Linux 源码中的 /drivers/mtd/nand/s3c2410.c ,以 2410 为例。

1. 在 nand flash 驱动加载后,第一步,就是去调用对应的 init 函数, s3c2410_nand_init, 去将在 nand flash 驱动注册到 Linux 驱动框架中。

2. 驱动本身,真正开始,是从 probe 函数, s3c2410_nand_probe->s3c24xx_nand_probe,

在 probe 过程中,去用 clk_enable 打开 nand flash 控制器的 clock 时钟,用 request_mem_region 去申请驱动所需要的一些内存等相关资源。然后,在 s3c2410_nand_inithw 中,去初始化硬件相关的部分,主要是关于时钟频率的计算,以及启用 nand flash 控制器,使得硬件初始化好了,后面才能正常工作。

3. 需要多解释一下的,是这部分代码:

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++;

}

4. 等所有的参数都计算好了,函数都挂载完毕,系统就可以正常工作了。

上层访问你的 nand falsh 中的数据的时候,通过 MTD 层,一层层调用,最后调用到你所实现的那些底层访问硬件数据 / 缓存的函数中。

【 Linux 下 nand flash 驱动编写步骤简介】

关于上面提到的,在 nand_scan_tail 的时候,系统会根据你的驱动,如果没有实现一些函数的话,那么就用系统默认的。如果实现了自己的函数,就用你的。

估计很多人就会问了,那么到底我要实现哪些函数呢,而又有哪些是可以不实现,用系统默认的就可以了呢。

此问题的,就是我们下面要介绍的,也就是,你要实现的,你的驱动最少要做哪些工作,才能使整个 nand flash 工作起来。

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 ,对于很多没用到电源管理的情况下,至少对于我们刚开始写基本的驱动的时候,可以不用关心,放个空函数即可。

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:

/* nand flash 控制器中,一般都有对应的数据寄存器,用于给你往里面写数据,表示将要读取或写入多少个字节 (byte,u8)/ 字 (word,u32) ,所以,此处,你要给出地址,以便后面的操作所使用 */

chip->IO_ADDR_W = regs + S3C2410_NFDATA;



关键词:

评论


相关推荐

技术专区

关闭