本文共 15709 字,大约阅读时间需要 52 分钟。
[转]u-boot-2010.12移植到2440(五,yaffs2文件系统移植
转自
Yaffs2文件系统的移植主要涉及到u-boot对yaffs2文件系统的烧写支持、linux内核对yaffs2文件系统的支持,以及yaffs2文件系统的制作,现在我们按照从下到上的顺序来实现各部分的功能。本文重点参考黄刚的博文。
1、实现u-boot对yaffs/yaffs2文件系统下载的支持。
注意:这里对Nand的操作是基于MTD架构方式。
通常一个Nnad Flash存储设备由若干块组成,1个块由若干页组成。一般128MB以下容量的Nand Flash芯片,一页大小为528B,被依次分为2个256B的主数据区和16B的额外空间;128MB以上容量的Nand Flash芯片,一页大小通常为2KB。由于Nand Flash出现位反转的概率较大,一般在读写时需要使用ECC进行错误检验和恢复。
Yaffs/yaffs2文件系统的设计充分考虑到Nand Flash以页为存取单位等的特点,将文件组织成固定大小的段(Chunk)。以528B的页为例,Yaffs/yaffs2文件系统使用前512B存储 数据和16B的额外空间存放数据的ECC和文件系统的组织信息等(称为OOB数据)。通过OOB数据,不但能实现错误检测和坏块处理,同时还可以避免加载 时对整个存储介质的扫描,加快了文件系统的加载速度。以下是Yaffs/yaffs2文件系统页的结构说明:
Yaffs页结构说明============================================== 字节 用途============================================== 0 - 511 存储数据(分为两个半部)512 - 515 系统信息 516 数据状态字 517 块状态字518 - 519 系统信息520 - 522 后半部256字节的ECC523 - 524 系统信息525 - 527 前半部256字节的ECC==============================================
好了,在了解Nand Flash组成和Yaffs/yaffs2文件系统结构后,我们再回到u-boot中。目前,在u-boot中已经有对Cramfs、Jffs2等文件系 统的读写支持,但与带有数据校验等功能的OOB区的Yaffs/Yaffs2文件系统相比,他们是将所有文件数据简单的以线性表形式组织的。所以,我们只要在此基础上通过修改u-boot的Nand Flash读写命令,增加处理00B区域数据的功能,即可以实现对Yaffs/Yaffs2文件系统的读写支持。
实现u-boot对Yaffs或者Yaffs2文件系统的读写支持步骤如下:
①、在include/configs/smdk2440.h头文件中定义一个管理对Yaffs2支持的宏和开启u-boot中对Nand Flash默认分区的宏,如下:
#define CONFIG_MTD_NAND_YAFFS2 1 //定义一个管理对Yaffs2支持的宏
//开启Nand Flash默认分区,注意此处的分区要和你的内核中的分区保持一致#define MTDIDS_DEFAULT "nand0=nandflash0"#define MTDPARTS_DEFAULT "mtdparts=nandflash0:192k(bootloader)," / "64k(params)," / "2m(kernel)," / "-(root)"
②、在common/cmd_nand.c 原来对Nand操作的命令集列表中添加Yaffs2对Nand的写命令,如下://在U_BOOT_CMD中添加
U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand, "NAND sub-system", "info - show available NAND devices/n" "nand device [dev] - show or set current device/n" "nand read - addr off|partition size/n" "nand write - addr off|partition size/n" " read/write 'size' bytes starting at offset 'off'/n" " to/from memory address 'addr', skipping bad blocks./n"
//注意:这里只添加了yaffs2的写命令,因为我们只用u-boot下载(即写)功能,所以我们没有添加yaffs2读的命令#if defined(CONFIG_MTD_NAND_YAFFS2) "nand write[.yaffs2] - addr off|partition size - write `size' byte yaffs image/n" " starting at offset off' from memory address addr' (.yaffs2 for 512+16 NAND)/n"#endif
"nand erase [clean] [off size] - erase 'size' bytes from/n" " offset 'off' (entire device if not specified)/n" "nand bad - show bad blocks/n" "nand dump[.oob] off - dump page/n" "nand scrub - really clean NAND erasing bad blocks (UNSAFE)/n" "nand markbad off [...] - mark bad block(s) at offset (UNSAFE)/n" "nand biterr off - make a bit error at offset (UNSAFE)"#ifdef CONFIG_CMD_NAND_LOCK_UNLOCK "/n" "nand lock [tight] [status]/n" " bring nand to lock state or display locked pages/n" "nand unlock [offset] [size] - unlock section"#endif);
接着,在该文件中对nand操作的do_nand函数中添加yaffs2对nand的操作,如下:
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read;
if (argc < 4) goto usage;
addr = (ulong)simple_strtoul(argv[2], NULL, 16);
read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("/nNAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1;
s = strchr(cmd, '.'); if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr); }
//添加yaffs2相关操作,注意该处又关联到nand_write_skip_bad函数
#if defined(CONFIG_MTD_NAND_YAFFS2) else if (s != NULL && (!strcmp(s, ".yaffs2"))) { nand->rw_oob = 1; nand->skipfirstblk = 1; ret = nand_write_skip_bad(nand,off,&size,(u_char *)addr); nand->skipfirstblk = 0; nand->rw_oob = 0; }#endif
else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = size, .mode = MTD_OOB_RAW };
if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else { printf("Unknown nand command suffix '%s'./n", s); return 1; }
printf(" %zu bytes %s: %s/n", size, read ? "read" : "written", ret ? "ERROR" : "OK");
return ret == 0 ? 0 : 1; }
③、在include/linux/mtd/mtd.h头文件的mtd_info结构体中添加上面用到rw_oob和skipfirstblk数据成员,如下:
#if defined(CONFIG_MTD_NAND_YAFFS2) u_char rw_oob; u_char skipfirstblk;#endif
④、在第二步关联的drivers/mtd/nand/nand_util.c 的nand_write_skip_bad函数中添加对Nand OOB的相关操作,如下:
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, u_char *buffer){ int rval; size_t left_to_write = *length; size_t len_incl_bad; u_char *p_buffer = buffer;
#if defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support if(nand->rw_oob==1) { size_t oobsize = nand->oobsize; size_t datasize = nand->writesize; int datapages = 0;
if (((*length)%(nand->oobsize+nand->writesize)) != 0) { printf ("Attempt to write error length data!/n"); return -EINVAL; }
datapages = *length/(datasize+oobsize); *length = datapages*datasize; left_to_write = *length; }#endif
/* Reject writes, which are not page aligned */ if ((offset & (nand->writesize - 1)) != 0 || (*length & (nand->writesize - 1)) != 0) { printf ("Attempt to write non page aligned data/n"); return -EINVAL; }
len_incl_bad = get_len_incl_bad (nand, offset, *length);
if ((offset + len_incl_bad) >= nand->size) { printf ("Attempt to write outside the flash area/n"); return -EINVAL; }
#if !defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support if (len_incl_bad == *length) { rval = nand_write (nand, offset, length, buffer); if (rval != 0) printf ("NAND write to offset %llx failed %d/n", offset, rval);
return rval; }#endif
while (left_to_write > 0) { size_t block_offset = offset & (nand->erasesize - 1); size_t write_size;
WATCHDOG_RESET ();
if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) { printf ("Skip bad block 0x%08llx/n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; }
#if defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support if(nand->skipfirstblk==1) { nand->skipfirstblk=0; printf ("Skip the first good block %llx/n", offset & ~(nand->erasesize - 1)); offset += nand->erasesize - block_offset; continue; }#endif
if (left_to_write < (nand->erasesize - block_offset)) write_size = left_to_write; else write_size = nand->erasesize - block_offset;
printf("/rWriting at 0x%llx -- ",offset); //add yaffs2 file system support
rval = nand_write (nand, offset, &write_size, p_buffer); if (rval != 0) { printf ("NAND write to offset %llx failed %d/n", offset, rval); *length -= left_to_write; return rval; }
left_to_write -= write_size; printf("%d%% is complete.",100-(left_to_write/(*length/100))); offset += write_size;
#if defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support if(nand->rw_oob==1) { p_buffer += write_size+(write_size/nand->writesize*nand->oobsize); } else { p_buffer += write_size; }#else p_buffer += write_size;#endif
}
return 0;}
⑤、在第四步nand_write_skip_bad函数中我们看到又对nand_write函数进行了访问,所以这一步是到drivers/mtd/nand/nand_base.c 的nand_write函数中添加对yaffs2的支持,如下:
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf){ struct nand_chip *chip = mtd->priv; int ret;
#if defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support
int oldopsmode = 0;
if(mtd->rw_oob==1) { int i = 0; int datapages = 0;
size_t oobsize = mtd->oobsize; size_t datasize = mtd->writesize;
uint8_t oobtemp[oobsize]; datapages = len / (datasize);
for(i = 0; i < (datapages); i++) { memcpy((void *)oobtemp, (void *)(buf + datasize * (i + 1)), oobsize); memmove((void *)(buf + datasize * (i + 1)), (void *)(buf + datasize * (i + 1) + oobsize), (datapages - (i + 1)) * (datasize) + (datapages - 1) * oobsize); memcpy((void *)(buf+(datapages) * (datasize + oobsize) - oobsize), (void *)(oobtemp), oobsize); } }#endif
/* Do not allow reads past end of device */ if ((to + len) > mtd->size) return -EINVAL; if (!len) return 0;
nand_get_device(chip, mtd, FL_WRITING);
chip->ops.len = len; chip->ops.datbuf = (uint8_t *)buf;
#if defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support
if(mtd->rw_oob!=1) { chip->ops.oobbuf = NULL; } else { chip->ops.oobbuf = (uint8_t *)(buf + len); chip->ops.ooblen = mtd->oobsize; oldopsmode = chip->ops.mode; chip->ops.mode = MTD_OOB_RAW; }#else chip->ops.oobbuf = NULL;#endif
ret = nand_do_write_ops(mtd, to, &chip->ops);
*retlen = chip->ops.retlen;
nand_release_device(mtd);
#if defined(CONFIG_MTD_NAND_YAFFS2) //add yaffs2 file system support
chip->ops.mode = oldopsmode;#endif
return ret;}
OK,对yaffs2支持的代码已修改完毕,重新编译u-boot并下载到nand中,启动开发板,在u-boot的命令行输入:nand help查看nand的命令,可以看到多了一个nand write[.yaffs2]的命令,这个就是用来下载yaffs2文件系统到nand中的命令了。
⑥、使用nand write[.yaffs2]命令把事前制作好的yaffs2文件系统下载到Nand Flash中(yaffs2文件系统的制作请参考后文),下载操作步骤和效果图如下:
tftp 0x30000000 root.bin //用tftp将yaffs2文件系统下载到内存的0x30000000位置nand erase 0x250000 0x3db0000 //擦除Nand的文件系统分区nand write.yaffs2 0x30000000 0x250000 0x658170 //将内存中的yaffs2文件系统写入Nand的文件系统分区,注意这里的0x658170是yaffs2文件系统的实际大小(可以在tftp传送完后可以看到),要写正确,否则会形成假坏块
2、Linux2.6.37下移植yaffs文件系统
原始的linux内核是不支持Yaffs2文件系统的,我们首先需要下载yaffs2的内核补丁,给内核打上yaff2补丁才能使内核支持该文件系统。
yaffs2 老版本不支持2.6.36以上内核。 网上下载的yaffs2常见版本(点击下方的进行下载)一般不支持2.6.36/37。但2.6.36一下版本依然可以使用。
最新的yaffs2采用git发布,利用git工具下载到最新的yaffs2源代码,即可支持。办法是使用到发布的git方法获得最新版,并且查看readme确认其支持2.6.36/37。yaffs有一个较大的变化,是在2.6.36/37内核发布之后的一段时间里出现的,主要就是patch-ker.sh多了一个参数,m/s 是选择multi version支持,还是single version支持。(注意:在最新的linux版本下用multi version支持。)
(1)下载源代码
如果系统已经安装git工具,就直接执行:
git clone git://www.aleph1.co.uk/yaffs2
如果没有git工具,请首先下载安装git()。当然,也可以在windows下用git工具下载。
(2)给内核打补丁
yaffs源代码下载完后,放到某个目录下(但不要放在内核目录下!)进入yaffs源代码目录:
#cd yaffs2
打补丁(注意参数顺序不能错):
#./patch-kernel.sh c m ../linux-2.6.37.1
(3)然后配置内核:
#cd ../linux-2.6.37.1 //返回内核根目录
# make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
File systems -->
Miscellaneous filesystems -->
<*> YAFFS2 file system support
(4) 重新编译内核
# make ARCH=arm CROSS_COMPILE=arm-linux-
然后制作新的uImage,加载或者烧写到FLASH,如果能正确引导并加载yaffs文件系统则移植成功。
特别说明:一旦在使用新版本yaffs补丁之前使用过旧版本补丁,新版本的补丁则打不上了,建议使用新版本重新编译内核。
=======================
需要注意:因为windows中下载导致文件编码和linux的不同。所以,如果是在windows下用git下载并传递到linux下的,则需要修改两个文件的编码:
(1) 在linux下,进入yaffs2源代码目录
#vi patch-kernel.sh
然后在vi中执行如下命令:
:set ff=unix
保存退出
然后修改权限使patch-kernel.sh具有可执行权限:
#chmod 755 patch-kernel.sh
(3)修改fs/yaffs2/Kconfig的编码
#vi fs/yaffs2/Kconfig
在vi中执行命令:
:set ff=unix
保存退出,按照上述步骤进行打补丁。
3、用busybox制作yaffs2根文件系统
所谓的根文件系统,就是创建各个目录,并且在里面创建各种文件,比如在/bin,/sbin/目录下存放各种可执行的程序,在/etc目录下存放配置文件,在/lib目录下存放库文件,下面就可以文件系统的移植。
1、根文件系统的目录结构bin 存放所有用户都可以使用的、基本的命令。sbin 存放的是基本的系统命令,它们用于启动系统、修复系统等。usr 里面存放的是共享、只读的程序和数据。proc 这是个空目录,常作为proc文件系统的挂载点。dev 该目录存放设备文件和其它特殊文件。etc 存放系统配置文件,包括启动文件。lib 存放共享库和可加载块(即驱动程序),共享库用于启动系统、运行根文件系统中的可执行程序。boot 引导加载程序使用的静态文件home 用户主目录,包括供服务账号锁使用的主目录,如FTPmnt 用于临时挂接某个文件系统的挂接点,通常是空目录。也可以在里面创建空的子目录。opt 给主机额外安装软件所摆放的目录。root root用户的主目录tmp 存放临时文件,通常是空目录。var 存放可变的数据。
2、建立根文件系统的目录
进入工作目录,创建一个shell的脚本用于构建根文件系统的各个目录。mkrootfs.sh,平且改变执行的权限。
sudo chmod 777 mkrootfs.sh
脚本内容如下:
#!/bin/shecho "------Create rootfs directons start...--------"mkdir rootfscd rootfsecho "--------Create root,dev....----------"mkdir root dev etc boot tmp var sys proc lib mnt homemkdir etc/init.d etc/rc.d etc/sysconfigmkdir usr/sbin usr/bin usr/lib usr/modules
mkidr proc/sys mkidr proc/sys/kernel
mkidr proc/sys/kernel/
echo "make node in dev/console dev/null"mknod -m 600 dev/console c 5 1mknod -m 600 dev/null c 1 3mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/tempmkdir var/lib var/lock var/run var/tmpchmod 1777 tmpchmod 1777 var/tmpecho "-------make direction done---------"
改变了tmp目录的使用权,让它开启sticky位,为tmp目录的使用权开启此位,可确保tmp目录底下建立的文件,,只有建立它的用户有权删除。
3、编译和安装Busybox
Bosybox 是一个遵循 GPL v2协议的开源项目,它在编写过程总对文件大小进行优化,并考虑了系统资源有限(比如内存等)的情况,使用 Busybox 可以自动生成根文件系统所需的bin、sbin、usr 目录和 linuxrc 文件。
首先下载busybox,下载地址:www.busybox.net
下载链接:http://www.busybox.net/downloads/busybox-1.18.3.tar.bz2
解压源代码:
#tar -jxvf busybox-1.18.3.tar.bz2
修改Makefile中的交叉链和系统架构:
CROSS_COMPILE ?=arm-linux-
ARCH ?=arm
配置编译选项:
如果修改了Makefile则使用如下命令
#make menuconfig
如果未修改Makefile则使用如下命令:
# make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig
[A]指定安装位置:
Busybox Settings --->
Installation Options ("make install" behavior) --->
BusyBox installation prefix-->
输入:../rootfs //实际中,要根据计划的文件系统根设定!
[B]指定mdev动态文件系统
Linux System Utilities --->
[*]Support /etc/mdev.conf
[*]Support command execution at device addition/removal
说明:在busybox中配置对dev下设备类型的支持dev的创建有三种方法: (1)手动创建:在制作根文件系统的时候,就在 dev目录下创建好要使用的设备文件,系统挂接根文件系统后,就可以使用 dev目录下的设备文件了。 (2)使用 devfs 文件系统:这种方法已经过时,具有不确定的设备映射、没有足够的主/次设备号、devfs 消耗大量的内存。 (3)udev: 它是个用户程序,(u是指user space ,dev 是指device)能根据系统中硬件设备的状态动态的更新设备文件,包括设备文件的创建、删除等。使用udev机制也不需要/dev目录下创建设备节点, 它需要一些用户程序的支持,并且内核要支持sysfs文件系统。它的操作相对复杂,但灵活性很高 。mdev 是 busybox 自带的一个简化版的 udev,适合于嵌入式的应用埸合。其具有使用简单的特点。它的作用,就是在系统启动和热插拔或动态加载驱动程序时,自动产生驱动程序所需的节点文件。在以busybox 为基础构建嵌入式linux 的根文件系统时,使用它是最优的选择。配置时需要增加对 mdev的支持。 4、编译busybox # make ARCH=arm CROSS_COMPILE=arm-linux- install 在 rootfs 目录下会生成目录 bin、sbin、usr 和文件 linuxrc 的内容。5、 建立etc目录 init进程根据/etc/inittab文件来创建其他的子进程,比如调用脚本文件配置IP地址,挂载其他的文件系统,最后启动shell等。(1)、拷贝主机 etc 目录下的passwd、group、shadow文件到 rootfs/etc目录下。(2) etc/sysconfig目录下新建文件HOSTNAME,内容为”smdk2440” 。 (3) etc/inittab文件: 仿照Busybox的examples/inittab文件,在etc/目录下创建一个inittab文件.
#etc/inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a –r
6、创建etc/init.d/rcS文件:这是一个脚本文件,可以在里面添加自动执行的命令,
#!/bin/shPATH=/sbin:/bin:/usr/sbin:/usr/binrunlevel=S //运行的级别prevlevel=Numask 022 //文件夹的掩码export PATH runlevel prevlevelmount -a //挂载/etc/fstab/文件指定的所有的文件系统
mount -t tmpfs none /tmp
mount -t tmpfs none /var
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev>/proc/sys/kernel/hotplug
mdev -s
/bin/hostname -F /etc/sysconfig/HOSTNAME //主机的名字
最后,还要改变它的属性,使它能够运行“
sudo chmod 777 etc/init.d/rcS
7、创建etc/fstab文件: 内容如下,表示执行完,“mount -a”命令后将挂载proc,tmpfs 等包含在该文件中的所有的文件系统。
#device mount-point type options dump fsck orderproc /proc proc defaults 0 0sysfs /sys sysfs defaults 0 0tmpfs /tmp tmpfs defaults 0 0tmpfs /var tmpfs defaults 0 0tmpfs /dev tmpfs defaults 0 0
/etc/fstab/文件被用来定义文件系统的“静态信息”,这些信息被用来控制mount命令的行为,各个字段的含义以如下:device: 要挂载的设备 比如/dev/hda2 /dev/mtdblock1 等设备文件,也可以是其他格式的,比如对于proc文件系统这个字段就没有意义,可以就任意的值,对于NFS文件系统,这个字段是,<host>:<dir>.mount-point: 挂载点type 文件系统类型: 比如 proc,jffs2,yaffs,ext2 ,nfs等,也可以是auto,表示自动检测文件系统类型options: 挂接参数,以逗号隔开/etc /fstab的作用不仅仅是用来控制'mount -a'的行为,即使是一般的mount命令,也受它的控制,常用的取值还有 auto noauto user 只允许普通用户挂载设备 nouser exec 允许运行所挂载设备上的程序 noexec Ro 只读方式 rw 以读写的方式 sync 修改文件是,它会同步写入设备中 async 不同步 defaults rw suid dev exec auto nouser async 等的组合。 dump 和fsck order:用来控制dump fsck程序的行为dump是一个用来备份的文件的程序,fsck是一个用来检查磁盘的程序,8、 创建etc/profile文件:
#Ash profile#vim:syntax=sh#No core file by defaults#ulimit -S -c 0>/dev/null 2>&1USER="id -un"LOGNAME=$USERPS1='[/u@/h/W]#'PATH=$PATHHOSTNAME='/bin/hostname'export USER LOGNAME PS1 PATH
9、 制作根文件系统映像文件
我的目标板NandFlash是64MB的,所以要使用mkyaffs2image的64M版本这个可执行的文件生成映像文件。使用命令mkyaffs2image rootfs rootfs.img生成根文件系统映像文件。把生成的rootsfs.img文件烧写到nandFlash中的根文件系统区。重新引导操作系统即可实现文件系统的正确挂载。
4、移植过程中遇到的问题及处理:
如果出现“Kernel panic - not syncing: Attempted to kill init!”错误,请在编译内核时选择EABI支持。
Kernel Features --->
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel (EXPERIMENTA)
把这个选上重新编译就可以了,如果文件系统镜像也是新做的则也要考虑文件系统本身有问题的可能性。此外请注意mkyaffs2image 工具是否正确,我使用友善之臂的工具就出现此错误,但是使用天嵌提供的工具则可以正常使用。
如果出现“Failed_to_execute_/linuxrc”可以根据下面的建议逐个检查。1. bin/busybox文件是可以执行的。2. 在配置busybox的时候要选中shell选项中的一个选项3. linuxrc 是可执行的。4. 制作文件系统的时候利用的工具也要留意区分: mkcramfs 制作cramfs镜像的工具 mkimage 制作jffs2镜像的工具 mkyaffs2image 制作2.6的yaffs2的镜像工具(针对Nand Flash是128MB到1G的) mkyaffsimage 制作2.6.13的yaffs2的镜像工具 mkyaffsimage_2 制作2.6.25.8或2.6.30.4或更高版本内核的yaffs2的镜像工具(针对Nand Flash是 64MB的)
5、配置内核时是否取消ECC(我遇到此问题是通过取消ECC解决此问题。)
NAND Flash support for Samsung S3C SoCs
□Samsung S3C NAND Hardware ECC
转载地址:http://hhpsi.baihongyu.com/