u-boot的nand flash驅動有兩個版本,彷佛是以u-boot1.1.5爲分界點的,以前的版本使用的是本身寫的nand flash驅動,然後面的版本使用的是linux內核中nand flash的驅動。這兩個版本有可能在同一個u-boot中存在,都存放在 driver目錄下面,一個爲nand,一個爲nand_legacy,意思爲傳統的nand flash驅動。二者使用一個宏開關 CFG_NAND_LEGACY來打開,若是定義這個宏的話,將使用傳統的nand flash驅動,不然使用最新的flash驅動。 關於傳統的flash驅動中的yaffs文件映像的下載問題,我已經解決,能夠看個人另外的一篇文章,使用的內核版本是2.6.15,你去看內核的yaffs代碼,2.6.17是內核中yaffs的一個分界點,因此你2.6.17的內核可能能夠使用我說的方法,2.618的內核可能就不能用我說的那個方法,2.6.18以上的內核沒有驗證過,熱心的朋友能夠幫忙使用2.6.18以上的內核幫忙驗證一下,而後在這裏告訴一下在下。 最新的flash中的yaffs文件映像燒寫的問題,我放出一個老外的驅動,我驗證過映像下載是沒有問題,可是產生了一些其餘的問題,我一直沒有解決,因此這篇文章也拖到如今。 diff --git a/common/cmd_nand.c b/common/cmd_nand.c index b011b5e..2760874 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -351,6 +351,23 @@ #endif opts.quiet = quiet; ret = nand_write_opts(nand, &opts); } +#ifdef CFG_NAND_YAFFS_WRITE + } else if (!read && s != NULL && + (!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))) { + nand_write_options_t opts; + memset(&opts, 0, sizeof(opts)); + opts.buffer = (u_char*) addr; + opts.length = size; + opts.offset = off; + opts.pad = 0; + opts.blockalign = 1; + opts.quiet = quiet; + opts.writeoob = 1; + opts.autoplace = 1; + if (s[6] == '1') + opts.forceyaffs = 1; + ret = nand_write_opts(nand, &opts); +#endif } else { if (read) ret = nand_read(nand, off, &size, (u_char *)addr); @@ -462,6 +479,10 @@ U_BOOT_CMD(nand, 5, 1, do_nand, "nand read[.jffs2] - addr off|partition size\n" "nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting\n" " at offset `off' to/from memory address `addr'\n" +#ifdef CFG_NAND_YAFFS_WRITE + "nand write[.yaffs[1]] - addr off|partition size - write `size' byte yaffs image\n" + " starting at offset `off' from memory address `addr' (.yaffs1 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" diff --git a/drivers/nand/nand_util.c b/drivers/nand/nand_util.c index 10bf036..bea5c1e 100644 --- a/drivers/nand/nand_util.c +++ b/drivers/nand/nand_util.c @@ -343,6 +343,10 @@ int nand_write_opts(nand_info_t *meminfo struct nand_oobinfo *oobsel = opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo; +#ifdef CFG_NAND_YAFFS1_NEW_OOB_LAYOUT + /* jffs2_oobinfo matches 2.6.18+ MTD nand_oob_16 ecclayout */ + oobsel = &jffs2_oobinfo; +#endif if (meminfo->oobsize == 8) { if (opts->forceyaffs) { printf("YAFSS cannot operate on " @@ -443,6 +447,28 @@ int nand_write_opts(nand_info_t *meminfo memcpy(oob_buf, buffer, meminfo->oobsize); buffer += meminfo->oobsize; + if (opts->forceyaffs) { +#ifdef CFG_NAND_YAFFS1_NEW_OOB_LAYOUT + /* translate OOB for yaffs1 on Linux 2.6.18+ */ + oob_buf[15] = oob_buf[12]; + oob_buf[14] = oob_buf[11]; + oob_buf[13] = (oob_buf[7] & 0x3f) + | (oob_buf[5] == 'Y' ? 0 : 0x80) + | (oob_buf[4] == 0 ? 0 : 0x40); + oob_buf[12] = oob_buf[6]; + oob_buf[11] = oob_buf[3]; + oob_buf[10] = oob_buf[2]; + oob_buf[9] = oob_buf[1]; + oob_buf[8] = oob_buf[0]; + memset(oob_buf, 0xff, 8); +#else + /* set the ECC bytes to 0xff so MTD will + calculate it */ + int i; + for (i = 0; i meminfo->oobinfo.eccbytes; i++) + oob_buf[meminfo->oobinfo.eccpos[i]] = 0xff; +#endif + } /* write OOB data first, as ecc will be placed * in there*/ result = meminfo->write_oob(meminfo, 本身選擇性的添加吧。 這個補丁主要完成了一個oob字節順序的改變。 注意同時要查看一下你的mkyaffsimage命令的源文件裏面的oob的字節的順序! 這樣製做的u-boot下載yaffs文件系統映像沒有問題,可是垃圾回收(garbage collection)機制有問題,對該文件系統進行寫入操做(mkdir、 touch)時,系統提示: page 1302 in gc has no object: 0 0 0 . . . page 1311 in gc has no object : 0 0 0 具體緣由待查! 內核的一個編譯選項的意義: Device Drivers->Memory Technolovy Devices->FTL(Flash Translation Layer) Support 這個選項的意義在於? 因爲沒法重複的在flash的同一塊存儲位置上作寫入的操做(必須事先擦除該快以後才能寫入),所以通常在硬盤上使用的文件系統,如:fat16,fat32,ntfs,ext2,ext3等將沒法直接用到flash上,爲了沿用這些文件系統,則必須透過一層轉換層來將邏輯地址對應到flash的存儲器的物理位置上,使系統能把flash看成普通的硬盤來使用,咱們將這一層稱之爲ftl(flash translation layer),flash主要用於nor flash上,而nftl則應用於nand flash上。 最簡單的ftl的實現方法就是一對一的映射,那麼當上層的文件系統要寫一個塊設備的扇區的時候,閃存作下面的操做來完成這個請求。 1、將這個扇區的所在的擦處塊讀到內存中,放入緩衝 2、按照寫要求更新該緩衝塊 3、對該快進行擦除 4、回寫 存在的問題: 1、效率低,一個chunk更新要對整個block進行擦除 2、沒有磨損均衡策略 3、很是不安全!容易引發數據的丟失,若是3步與第4步之間,數據將所有丟失 因此閃存轉換層採用的算法比這個複雜一點 在flash上,儘可能避免使用傳統的依賴閃存轉換層的文件系統,最好採用專門的針對flash的文件系統,如 jffs3和yaffs2 問題:加載cramfs文件系統分區(mount -t cramfs /dev/mtdblock1 /mnt/flash1)的時候,報出以下的錯誤: end_request: I/O error, dev mtdblock2, sector 0 Buffer I/O error on device mtdblock2, logical block 0 end_request: I/O error, dev mtdblock2, sector 0 Buffer I/O error on device mtdblock2, logical block 0 end_request: I/O error, dev mtdblock2, sector 8 Buffer I/O error on device mtdblock2, logical block 1 end_request: I/O error, dev mtdblock2, sector 8 Buffer I/O error on device mtdblock2, logical block 1 end_request: I/O error, dev mtdblock2, sector 16 Buffer I/O error on device mtdblock2, logical block 2 end_request: I/O error, dev mtdblock2, sector 16 開始覺得是硬件錯誤,後來仔細一檢查發現:實際上是uboot寫入cramfs文件系統映像時使用的ecc校驗算法和內核使用的校驗算法不一致致使的,若是咱們將內核中的mtd層ecc校驗NAND_ECC_SOFT關掉,在/drivers/mtd/at91_nand.c文件中有定義。則系統在加載的時候將再也不報錯,驗證了這是校驗的問題,解覺的辦法是什麼? 首先在uboot中,使用nand erase 將cramfs分區擦除乾淨,以nfs的方式啓動linux,而後使用 cp root_fs_cramfs.img /dev/mtd1 將cramfs映像文件拷貝到相應的字符設備中。 而後使用mount -t cramfs /dev/mtdblock1 /mnt/flash1。 則cramfs文件系統加載正常。 這樣咱們能夠不使用ramdisk技術來加載根文件系統,能夠省去讀內存的時間,加快啓動速度。 這時的內核啓動參數爲: noinitrd init=/linuxrc root=/dev/mtdblock1 ro console=ttyS0,115200 mem=64M ip=192.168.0.11 netmask=255.255.255.0 修改u-boot的bootcmd ,就能夠加快啓動速度,同時節省ram的空間!直接從cramfs的nandflash上啓動