摘要
关于上面提到的,在nand_scan_tail的时候,系统会根据你的驱动,如果没有实现一些函数的话,那么就用系统默认的。如果实现了自己的函数,就用你的。
估计很多人就会问了,那么到底我要实现哪些函数呢,而又有哪些是可以不实现,用系统默认的就可以了呢。
此问题的,就是我们下面要介绍的,也就是,你要实现的,你的驱动最少要做哪些工作,才能使整个Nand Flash工作起来。
其实,要了解,关于驱动框架部分,你所要做的事情的话,只要看看三星的整个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, }, };
而对于底层硬件操作的有些函数,总体上说,都可以在上面提到的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: chip->IO_ADDR_W = regs + S3C2410_NFDATA; info->sel_reg = regs + S3C2410_NFCONF; info->sel_bit = S3C2410_NFCONF_nFCE; chip->cmd_ctrl = s3c2410_nand_hwcontrol; chip->dev_ready = s3c2410_nand_devready; break; 。。。。。。 } chip->IO_ADDR_R = chip->IO_ADDR_W; nmtd->info = info; nmtd->mtd.priv = chip; nmtd->mtd.owner = THIS_MODULE; nmtd->set = set; if (hardware_ecc) { chip->ecc.calculate = s3c2410_nand_calculate_ecc; chip->ecc.correct = s3c2410_nand_correct_data; chip->ecc.mode = NAND_ECC_HW; switch (info->cpu_type) { case TYPE_S3C2410: chip->ecc.hwctl = s3c2410_nand_enable_hwecc; chip->ecc.calculate = s3c2410_nand_calculate_ecc; break; ...... } } else { chip->ecc.mode = NAND_ECC_SOFT; } if (set->ecc_layout != NULL) chip->ecc.layout = set->ecc_layout; if (set->disable_ecc) chip->ecc.mode = NAND_ECC_NONE; }
s3c2410_nand_write_buf 和 s3c2410_nand_read_buf:这是两个最基本的操作函数,其功能,就是往你的Nand Flash的控制器中的FIFO读写数据。一般情况下,是MTD上层的操作,比如要读取一页的数据,那么在发送完相关的读命令和等待时间之后,就会调用到你底层的read_buf,去Nand Flash的FIFO中,一点点把我们要的数据,读取出来,放到我们制定的内存的缓存中去。写操作也是类似,将我们内存中的数据,写到Nand Flash的FIFO中去。 |
|
s3c2410_nand_select_chip : 实现Nand Flash的片选。 |
|
Nand Flash控制器中,一般都有对应的数据寄存器,用于给你往里面写数据,表示将要读取或写入多少个字节(byte,u8)/字(word,u32) ,所以,此处,你要给出地址,以便后面的操作所使用 |
|
s3c2410_nand_hwcontrol:给底层发送命令或地址,或者设置具体操作的模式,都是通过此函数。 |
|
s3c2410_nand_devready:Nand Flash的一些操作,比如读一页数据,写入(编程)一页数据,擦除一个块,都是需要一定时间的,在命发送完成后,就是硬件开始忙着工作的时候了,而硬件什么时候完成这些操作,什么时候不忙了,变就绪了,就是通过这个函数去检查状态的。 一般具体实现都是去读硬件的一个状态寄存器,其中某一位是否是1,对应着是出于“就绪/不忙”还是“忙”的状态。这个寄存器,也就是我们前面分析时序图中的R/B#。 |
|
s3c2410_nand_calculate_ecc:如果是上面提到的硬件ECC的话,就不用我们用软件去实现校验算法了,而是直接去读取硬件产生的ECC数值就可以了。 |
|
s3c2410_nand_correct_data:当实际操作过程中,读取出来的数据所对应的硬件或软件计算出来的ECC,和从oob中读出来的ECC不一样的时候,就是说明数据有误了,就需要调用此函数去纠正错误。对于现在SLC常见的ECC算法来说,可以发现2位,纠正1位。如果错误大于1位,那么就无法纠正回来了。一般情况下,出错超过1位的,好像几率不大。至少我看到的不是很大。更复杂的情况和更加注重数据安全的情况下,一般是需要另外实现更高效和检错和纠错能力更强的ECC算法的。 |
|
此处,多数情况下,你所用的Nand Flash的控制器,都是支持硬件ECC的,所以,此处设置硬件ECC(HW_ECC) ,也是充分利用硬件的特性,而如果此处不用硬件去做的ECC的话,那么下面也会去设置成NAND_ECC_SOFT,系统会用默认的软件去做ECC校验,相比之下,比硬件ECC的效率就低很多,而你的Nand Flash的读写,也会相应地要慢不少 |
|
s3c2410_nand_enable_hwecc: 在硬件支持的前提下,前面设置了硬件ECC的话,要实现这个函数,用于每次在读写操作前,通过设置对应的硬件寄存器的某些位,使得启用硬件ECC,这样在读写操作完成后,就可以去读取硬件校验产生出来的ECC数值了。 |
当然,除了这些你必须实现的函数之外,在你更加熟悉整个框架之后,你可以根据你自己的Nand Flash的特点,去实现其他一些原先用系统默认但是效率不高的函数,而用自己的更高效率的函数替代他们,以提升你的Nand Flash的整体性能和效率。