新项目使用了 Micro 4Gb 16bit Nand 作为 Storage, 这样,我们需要对下载工具、bootloader、Linux 内核做一些修改。 这里主要记录了 Linux 内核 Nand 驱动调试过程中遇到的问题。
问题1: 擦除某个分区会导致系统不能启动
执行命令擦除某分区:
flash_eraseall /dev/mtd8
重启, 发现系统不能启动!
重新用 Jtag 烧入obm, 发现系统能够又正常启动!
该过程可重复! 奇怪的是,擦除其它分区则没有此问题!
使用 Jtag 读出问题后的分区0, 全为0xFF, 应该是被擦除了!
仔细分析, 发现mtd8 分区的“势力范围”跨256M, 于是想到是不是擦除第256M的第一个 block 时把 block 0 给擦除了!
想到写代码时是参考 Micro 2Gb 16bit Nand的, 再去仔细研究那段代码, 发现地址翻译跟 256M Nand 相同。 参考 LG 4Gb Nand 的地址翻译函数作如下更新:
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -878,7 +878,7 @@ static int Micron4GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
}
else if (cmd == micron4GbX16.erase) {
- ndcb1 = ((addr >> 17) << 6) & 0x1FFFF;
+ ndcb1 = ((addr >> 17) << 6) & 0x3FFFF;
}
#ifdef CONFIG_MTD_NAND_OTP
else if (cmd == micron4GbX16.otp_read || cmd == micron4GbX16.otp_write) {
@@ -896,7 +896,7 @@ static int Micron4GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
static int Micron4GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
{
if (cmd == micron4GbX16.read1 || cmd == micron4GbX16.program) {
- *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
+ *p = ((ndbbr & 0xf) << 8) | ((ndbbr >> 8) << 16);
}
else if (cmd == micron4GbX16.erase) {
*p = (ndbbr >> 6) << 17;
编译, 运行, 发现可以正常擦除 mtd8!
结论:不同容量的 nand 其地址位数不一样! 以后当出现 block 0 被莫名擦除的现象后首先应该考虑地址翻译问题。
问题2:写 oob 数据特别慢
项目组要求把 OMS 烧录到 Nand 上进行本地运行。
使用 SWdownloader 通过 usb 下载, 发现像 System.img 这种特别大的 image 总是会出现 CRC 错误。
于是使用通过 t 卡采用nandtool 将OMS 各镜像烧入。
实践发现 nandwrite 写 yaffs 镜像特别慢! 而少不带 oob 的数据则特别快。 在函数 nand_command 加入打印语句, 发现不写oob数据时, 命令序列为:
<4>[ 37.906250] command:0x80 at address:0x21072, column:0x0
<4>[ 37.906250] command:0x10 at address:0xffffffff, column:0xffffffff
<4>[ 37.906250] command:0x70 at address:0xffffffff, column:0xffffffff
<4>[ 37.906250] command:0x80 at address:0x21073, column:0x0
<4>[ 37.906250] command:0x10 at address:0xffffffff, column:0xffffffff
<4>[ 37.906250] command:0x70 at address:0xffffffff, column:0xffffffff
而写 oob 数据时,命令序列为:
<4>[ 28.742187] command:0x80 at address:0x21000, column:0x800
<4>[ 28.742187] command:0x10 at address:0xffffffff, column:0xffffffff
<4>[ 28.742187] command:0x70 at address:0xffffffff, column:0xffffffff
<4>[ 28.742187] command:0x80 at address:0x21000, column:0x0
<4>[ 28.742187] command:0x10 at address:0xffffffff, column:0xffffffff
<4>[ 28.742187] command:0xff at address:0xffffffff, column:0xffffffff
<4>[ 28.843750] command:0x70 at address:0xffffffff, column:0xffffffff
<4>[ 28.843750] command:0x80 at address:0x21001, column:0x800
<4>[ 28.843750] command:0x10 at address:0xffffffff, column:0xffffffff
<4>[ 28.843750] command:0x70 at address:0xffffffff, column:0xffffffff
<4>[ 28.843750] command:0x80 at address:0x21001, column:0x0
<4>[ 28.843750] command:0x10 at address:0xffffffff, column:0xffffffff
<4>[ 28.843750] command:0xff at address:0xffffffff, column:0xffffffff
<4>[ 28.945312] command:0x70 at address:0xffffffff, column:0xffffffff
发现每次写 oob 数据, 都会发送 0xff 命令, 对应的是 RESET 命令。这条命令花了大概100ms的时间。 这意味着每个 block (64个 page) 会花6.4秒的时间用于 reset!!
跟踪代码, 发现 nand_base.c 的函数 nand_do_write_oob中有:
1823 /*
1824 * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
1825 * of my DiskOnChip 2000 test units) will clear the whole data page too
1826 * if we don't do this. I have no clue why, but I seem to have 'fixed'
1827 * it in the doc2000 driver in August 1999. dwmw2.
1828 */
1829 chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1)
而 pxa935 平台的 reset 函数dfc_reset_flash会导致100ms的时延。
将 1829 行注释,再重新测试, 发现问题消失!