韩大卫@吉林师范大学
2015.1.27.
转载请表明出处
*********************************************
uboot 和linux 下flash 的写入速度不一样, 主要原因是两者使用的延迟最小延时时间不一样. linux比较大. 原因如下:
flash 芯片手册中有两个重要的时间参数:
第一个是一般的块写入超时时间, 记为time-ty, 第二个是最大的块写入超时时间, 记为time-max.
假设有两个CFI nor flash 芯片, A 的time-ty 为10, B 的time-ty 为8 ; A, B 的time-max 都为2.
下面会看到, 在uboot 下, A, B 的flash 写入速度差异很小. 但在linux 下, A和B的flash 写入时间有很大的差异. 假设时钟均稳定.
uboot中的算法:
1,先得出超时时间 info->buffer_write_tout :
info->buffer_write_tout = (((1 << time-ty) * (1 << time-max)) + 999) / 1000;
A的flash : time-ty = 10, time-max = 2, 计算得 5 ms
B 的flash : time-ty = 8, time-max = 2, 计算得 2 ms
2, 再使用 info->buffer_write_tout :
while (1) {
...
if (ready) //这个标志表示写指令已经完成,
break;
if (get_timer() > info->buffer_write_tout) {
return ERR_TIMOUT;
}
udelay(1); //每次使用1 us 的延时, 直到出现 ready 退出循环. 一般地, 写指令的执行时间不会等到buffer_write_tout这么长时间就会成功, 因此很块快跳出循环
}
uboot写flash 时使用的延时都是在 us 级别的. 所以用户几乎感觉不到flash "Typical timeout for maximum size buffer program " 时间参数不同所造成的影响.
linux 下的延时时间:
1, 先得出chip->buffer_write_time
chips[i].buffer_write_time = 1<<time-ty;
A : buffer_write_time = 1024 us
B : buffer_write_time = 256 us
2, linux 使用 buffer_write_time 作为最小延时函数的变量 :
static inline void cfi_udelay(int us){
if (us >= 1000) { //A的buffer_write_time 为1024, 使用msleep 延时, 时间单位为 ms
msleep((us+999)/1000);
} else {
udelay(us); // B 的buffer_write_time 为256, 使用udelay 延时, 时间单位为 us
cond_resched();
}
}
可以看到, 由于A和B 的flash 的 "Typical timeout for maximum size buffer program " 参数不一样. 会导致了底层使用的延时函数差异很大.
这就是在linux 下flash 的写入时间会有很大的差异的原因.
备注:
一个 flash 芯片实例信息:
vendor ID is 2 (AMD 系列)
manufacturer id is 0x89
device id is 0x7e
device id2 is 0x2201
cfi version is 0x3133
芯片大小: 33554687 B, 32MB
扇区个数 256 个
扇区大小/一次可以缓存擦写大小: 131072 B, 128KB
缓存写等待时间: 1024 us
缓存写最大时间: 4096 us
以上可以参考uboot/linux/openwrt的源代码:
uboot:
drivers/mtd/cfi_flash.c (cfi 规范的flash驱动)
common/cmd_flash.c (uboot 的upgrade 命令的实现)
linux:
drivers/mtd/chips/cfi_probe.c (CFI 规范通用驱动入口)
drivers/mtd/chips/cfi_cmdset_0002.c (AMD 规范flash驱动)
arch/mips/cavium-octeon/flash_setup.c (octeon平台flash驱动)
drivers/mtd/cmdlinepart.c (解析分区)
drivers/mtd/mtdpart.c (系统mtd操作调用中心)
openwrt:
package/mtd/src/mtd.c (mtd 工具的源代码)
原文地址:http://blog.csdn.net/han_dawei/article/details/43203565