基于Local Bus访问的Linux Nand Flash驱动中遇到的时序问题

1. 调试过程

     工作上要调试一款基于Local Bus访问(因为板上CPU没有原生Nand控制器接口)的Micron Nand Flash。硬件结构很简单,主要是使用一个CPU的Local Bus片选,然后基于该片选的两个偏移地址,可以分别选中Flash ALE和CLE管脚,再使用一个GPIO用来获取Nand Flash的RDY管脚状态。

      网上关于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_RIO_ADDR_Wcmd_ctrl等,甚至read_byteread_bufwrite_buf这几个都可能不用设定),同时指定ecc的模式,此处使用了micron手册推荐的NAND_ECC_SOFT_BCH方式。

      然后将该结构赋值给struct mtd_info结构中的priv,再调用nand_scan_identnand_scan_tailmtd_device_parse_register即可完成Flash硬件检测,硬件信息获取(如blockpage的大小数量等等),最终生成相应的mtd分区,理论上nand flash驱动的开发也基本大功告成了。

2. 遇到问题

     在驱动probe对struct nand_chip结构进行赋值的过程中,有两个跟Flash操作状态有关的项:dev_readychip_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的时序仔细学习了下。

3. Nand Flash操作中的一些时序要求

     Nand Flash跟Nor Flash一样,也是基于命令访问的。因此,要使这些命令正常运行,需要满足一定的操作时序。其中,Read ID、Get Features这种管理配置命令与读写、擦除命令略有不同。

3.1 非读写命令

     以必不可少的Read ID(90h)为例,其操作时序如下图所示:

基于Local Bus访问的Linux Nand Flash驱动中遇到的时序问题_第1张图片

操作比较简单,只有一个tWHR需要满足,一般要求时长为60-80ns:


nand_base.c中一般使用Read Status(70h)命令来确保这些操作能够满足命令时序要求。

3.2 读写、擦除命令

     Nand Flash的读写、擦除操作则要复杂一些,如Read Page(30h)操作,其时序如下图所示:

基于Local Bus访问的Linux Nand Flash驱动中遇到的时序问题_第2张图片

总共有三个不同的时序定义:tWB, tR, tRR。在将命令0x30发送到硬件后,必须等待tWB+tR+tRR,软件才能继续进行下一步操作:

基于Local Bus访问的Linux Nand Flash驱动中遇到的时序问题_第3张图片

     标准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);

即等待100ns,再判断flash是否处于ready状态,以便继续执行后续操作。

4. 问题解决

     从上述的时序分析中可以看出,nand flash驱动的操作总体流程应该是没问题的。经过跟踪调试,发现是在 dev_ready的实现函数中,状态获取总是为ready状态,于是在其中做了更长时间的判断,发现在等待了18us左右,Flash才开始处于busy状态,又过了约20us返回到了ready状态,20us比较符合上述tR的时序要求。如果代码按照这种判断方法来确定ready状态,驱动就变为正常了。也就是说,当前的操作时长比正常Nand Flash整整多出了至少18个微秒。
     经过示波器量波形,软硬协调,最后确认需要18us这么长的时间是因为CPU Local Bus的访问比较慢的缘故。通过优化CPU片选的时间参数,最后把这个等待时间缩短了10倍左右,但仍然是微秒级别,跟理想的纳秒级别还是有一个数量级的差异。反映在最终的flash读写性能上,采用 dev_readychip_delay=100的方式并没有什么差别,说明读写的性能瓶颈还是在CPU对Nand Flash的Local Bus访问上。所以,最终出于简单起见,还是使用了一刀切的 chip_delay=100的方式。

      最后,我们将生成的Nand MTD分区,与UBIFS文件系统挂接,基本满足了系统的数据读写需求。

5. 总结

      在Linux驱动的开发调试过程中,由于Linux提供的驱动框架的便捷性,反倒容易忽视了硬件芯片所需要具备的时序要求。自己想当然的认为,既然跟其他参考实现方式类似,那代码肯定没问题,出错大概是硬件同事的责任。一般想法,总是认为CPU的访问速度是很快的,对Nand Flash的命令操作的生效时间可以忽略不计,而事实上,这次基于Local Bus的访问,恰恰成为了性能的的瓶颈。因此,后续有类似的设计需求时,或许需要先好好测试、优化CPU的Local Bus访问效率,然后再决定是否要进行相应的硬件线路设计、开发,才会得到一个性能最优的结果。

       

你可能感兴趣的:(flash)