网上关于Linux Nand Flash驱动的讲解说明已经很多了,比如:
【详解】如何编写Linux下Nand Flash驱动
Linux MTD下获取Nand flash各个参数的过程的详细解析
基于MTD的NAND驱动开发
对于Micron这种Flash标准制定者来说,它家的Nand Flash还是很好调试的,直接可以使用drivers/mtd中的nand代码框架,具体驱动调试可以参考drivers/mtd/nand中的atmel_nand.c,s3c2410.c,以及各种网上讲解。
驱动的实现,主要是在probe过程中完成对struct nand_chip 结构体中的函数指针赋值(关键的如IO_ADDR_R、IO_ADDR_W、cmd_ctrl等,甚至read_byte,read_buf, write_buf这几个都可能不用设定),同时指定ecc的模式,此处使用了micron手册推荐的NAND_ECC_SOFT_BCH方式。
然后将该结构赋值给struct mtd_info结构中的priv,再调用nand_scan_ident、nand_scan_tail、mtd_device_parse_register即可完成Flash硬件检测,硬件信息获取(如block、page的大小数量等等),最终生成相应的mtd分区,理论上nand flash驱动的开发也基本大功告成了。
在驱动probe对struct nand_chip结构进行赋值的过程中,有两个跟Flash操作状态有关的项:dev_ready和chip_delay,从nand_base.c中的代码可以看出,两个设置是二选一,不会同时使用——主要是为了满足一些Nand Flash操作的状态要求。dev_ready是用来判断当前flash的RDY管脚是否处于Ready状态;而chip_delay则不查询硬件状态,而直接delay chip_delay个微秒,此时chip_delay应该设置为大于等于所有操作的时序需求。
因此,一开始为了简单起见,在probe中直接设置了chip_delay = 100,在设备运行时,驱动很顺利的找到了flash设备,并正确生成了mtd分区,基于mtd分区的一些读写操作也都正常。但是鉴于chip_delay这种一刀切、统一等待100us时间的方式,总觉得不是很优化,会影响到设备整体读写性能。于是又使用硬件提供的GPIO管脚,实现了dev_ready的调用,可是很奇怪,在确定GPIO读取输入状态肯定没问题的情况下,驱动始终无法正常运行,可以正确读取设备ID,但是读写有问题,一直报错。
对比了下其他的Nand设备驱动代码,也没看出有什么明显不对。不过猜测可能是操作时序没有满足要求,于是拿出芯片手册又把Nand Flash的时序仔细学习了下。
Nand Flash跟Nor Flash一样,也是基于命令访问的。因此,要使这些命令正常运行,需要满足一定的操作时序。其中,Read ID、Get Features这种管理配置命令与读写、擦除命令略有不同。
以必不可少的Read ID(90h)为例,其操作时序如下图所示:
操作比较简单,只有一个tWHR需要满足,一般要求时长为60-80ns:
nand_base.c中一般使用Read Status(70h)命令来确保这些操作能够满足命令时序要求。
Nand Flash的读写、擦除操作则要复杂一些,如Read Page(30h)操作,其时序如下图所示:
总共有三个不同的时序定义:tWB, tR, tRR。在将命令0x30发送到硬件后,必须等待tWB+tR+tRR,软件才能继续进行下一步操作:
标准Nand Flash芯片的tWB时间都是100ns。针对上述需求,在nand_base.c的nand_command和nand_command_lp中,对于使用dev_ready方式的操作最后都有以下这样的内容:
/*
* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine.
*/
ndelay(100);
nand_wait_ready(mtd);
最后,我们将生成的Nand MTD分区,与UBIFS文件系统挂接,基本满足了系统的数据读写需求。
在Linux驱动的开发调试过程中,由于Linux提供的驱动框架的便捷性,反倒容易忽视了硬件芯片所需要具备的时序要求。自己想当然的认为,既然跟其他参考实现方式类似,那代码肯定没问题,出错大概是硬件同事的责任。一般想法,总是认为CPU的访问速度是很快的,对Nand Flash的命令操作的生效时间可以忽略不计,而事实上,这次基于Local Bus的访问,恰恰成为了性能的的瓶颈。因此,后续有类似的设计需求时,或许需要先好好测试、优化CPU的Local Bus访问效率,然后再决定是否要进行相应的硬件线路设计、开发,才会得到一个性能最优的结果。