1. 程式人生 > >【轉】U-BOOT支援燒寫yaffs2檔案系統

【轉】U-BOOT支援燒寫yaffs2檔案系統

U-BOOT 支援yaffs2檔案系統的燒寫。
其實移植這步燒寫很簡單,只是將打包的檔案系統一次寫入NAND即可,以頁為單位,一次寫入2K+64B。
包含main和spare區,其中spare的ECC資料等在yaffs2檔案系統製作時就已經寫好了。是通過軟體ECC
每256B產生3B的規則進行的。所以必須保證mkyaffs2image工具能正確製作YAFFS2檔案系統。否則系統是
啟動不了。

具體移植步驟:
1.在include/configs/xxxxx.h增加巨集
#define CONFIG_MTD_NAND_YAFFS2
2.新增write.yaffs2燒寫命令,U-BOOT只需要寫命令即可
 vim common/cmd_nand.c中

 501 #if defined(CONFIG_MTD_NAND_YAFFS2)
 502            "nand read.yaffs2 - addr off|partition size\n"
 503            "nand write.yaffs2 - addr off|partiton size\n"
 504 #endif

新增以上幫助說明資訊

增加解析yaffs2命令的函式

 344 #if defined(CONFIG_MTD_NAND_YAFFS2)
 345                  else if(s != NULL && !strcmp(s, ".yaffs2") ) {
 346                         if (read) {
 347 /*                              nand->rw_oob = 1;
 348                                 nand->skipfirstblk = 1;
 349                                 ret = nand_read_skip_bad(nand,off,&size,(u_     chat *)addr);
 350                                 nand->skipfirstblk = 0;
 351                                 nand->rw_oob = 0;
 352 */
 353                         }
 354                         else {/* 主要關心寫命令 */
 355                                 nand->rw_oob = 1;
 356                                 nand->skipfirstblk = 1;
 357                                 ret = nand_write_skip_bad(nand, off, &size,      (u_char *)addr);
 358                                 nand->skipfirstblk = 0;
 359                                 nand->rw_oob = 0;
 360                         }
 361                 }
 362 #endif
nand->rw_oob  和 nand->skipfirstblk 一個作為燒寫YAFFS的標誌,檔案系統跳過的塊,因為YAFFS2檔案系統燒寫時需要跳過
第一塊。這是由於其特性決定的,第一塊用於構建BBT(bad block table)

這兩個新成員需要新增在include/linux/mtd/mtd.h的mtd_info結構體中
128 #if defined(CONFIG_MTD_NAND_YAFFS2)
129         u_char rw_oob;
130         u_char skipfirstblk;
131 #endif

3.由於寫操作會呼叫nand_write_skip_bad()函式,這裡也需要修改,位於nand_util.c

474 #if defined(CONFIG_MTD_NAND_YAFFS2)
475         if (nand->rw_oob == 1) {/* 燒寫的YAFFS2檔案 */
476
477                 size_t oobsize = nand->oobsize;
478                 size_t datasize = nand->writesize;
479                 int datapages = 0;
480                 datapages = (*length)/(datasize+oobsize);/* 注意這裡是整個長度 */
481                 *length = datapages*datasize; /* 實際main區大小 */
482                 left_to_write = *length; /* 在具體燒寫時會以left_to_write做引數 */
483         }
484 #endif
傳入這個函式的size 是nand命令引數給的,對於YAFFS2為實際大小,即2112的倍數,off也是經由命令列傳遞來的
而addr是對應記憶體BUF的地址
466 int nand_write_skip_bad(nand_info_t *nand, ulong offset, size_t *length,
467                         u_char *buffer)
這是函式原型
所以以上新增程式碼的意思是,如註釋,也就是從yaffs2檔案大小中提取main區的資料大小
在以下程式碼新增如是巨集,避免影響其他燒寫
498 #if !defined (CONFIG_MTD_NAND_YAFFS2)
499         if (len_incl_bad == *length) {
500                 rval = nand_write (nand, offset, length, buffer);
501                 if (rval != 0)
502                         printf ("NAND write to offset %x failed %d\n",
503                                 offset, rval);
504
505                 return rval;
506         }
507 #endif

518 #if defined(CONFIG_MTD_NAND_YAFFS2)
519                 if (nand->skipfirstblk == 1) {/* 需要跳過第一塊 */
520                         nand->skipfirstblk = 0;
521                         printf("Skip the first good block 0x%08x\n",offset &   
522                                 ~(nand->erasesize - 1));
523                         offset += nand->erasesize - block_offset;/* 故偏移地址 + 1block */
524                         continue;
525                 }
526 #endif
527          

542 #if defined(CONFIG_MTD_NAND_YAFFS2)
543                 if (nand->rw_oob == 1)
544                         p_buffer += write_size+(write_size/nand->writesize*nand->oobsize);
  /* 注意因為是一次燒寫main和spare 故指向映象的指標編譯量要加上OOB區的大小,一次寫入一塊,不足一塊以頁寫入*/
545                 else
546                         p_buffer += write_size;
547 #else
548
549                 p_buffer      += write_size;
550 #endif
551         }
552
553         return 0;
554 }

4.下面看nand_write()的實現
536                 rval = nand_write (nand, offset, &write_size, p_buffer);
這是傳遞的引數,函式位於nand_base.c中

2011 #if defined(CONFIG_MTD_NAND_YAFFS2)
2012         int oldopsmode = 0;
2013         if (mtd->rw_oob != 1)
2014                 chip->ops.oobbuf = NULL;
2015         else {
2016                 chip->ops.oobbuf = (uint8_t *)(buf+mtd->writesize);/* oob資料起始地址 */
2017                 chip->ops.ooblen = mtd->oobsize; /* 64B */
2018                 chip->ops.ooboffs = 0;
2019                 oldopsmode = chip->ops.mode;
2020                 chip->ops.mode =MTD_OOB_RAW; /* 原始模式,不進行ECC計算 */
2021         }
2022 #else
2023         chip->ops.oobbuf = NULL;
2024 #endif

其實這個函式只是填充nand_chip這個結構體然後呼叫
2053         ret = nand_do_write_ops(mtd, to, &chip->ops);

函式原型如下
1887 /**
1888  * nand_do_write_ops - [Internal] NAND write with ECC
1889  * @mtd:        MTD device structure
1890  * @to:         offset to write to
1891  * @ops:        oob operations description structure
1892  *
1893  * NAND write with ECC
1894  */
1895 static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
1896                              struct mtd_oob_ops *ops)

這個函式功能,選擇具體的一片NAND,當然大多情況只有一片,然後會處理OOB區資料
根據chip->ops.mode,這裡為原始模式,即不進行處理,則將OOB區資料複製到對應的ops


這是裡面新增的內容
然後會呼叫具體的write_page寫一頁資料

1972 #if defined(CONFIG_MTD_NAND_YAFFS2)
1973                 if (mtd->rw_oob == 1) {
1974                 oob = oob + bytes;
1975                 buf = buf + ops->ooblen;
1976                 }
1977 #endif
每寫一次oob和databuf都移動2112B。

1962                 ret = chip->write_page(mtd, chip, wbuf, page, cached,
1963