歡迎您光臨本站 註冊首頁

u-boot-2011.06在基於s3c2440開發板的移植之硬體ECC

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  

在上一篇關於“支持NandFlash讀寫”的文章中,我們很好地完成了u-boot對NandFlash的讀寫,但這個讀寫進行的是軟體ECC,即用軟體編程的方法實現ECC。我們知道S3C2440的NandFlash控制器是支持硬體ECC的,因此在這裡我們就來講解如何實現硬體ECC。

NandFlash的每一頁分為main區和spare區,S3C2440的NandFlash控制器支持這兩個區的硬體ECC,但為了兼容u-boot-2011.06,我們只實現main區的硬體ECC。

為了實現硬體ECC,首先需要在include/configs/zhaocj2440.h文件內定義宏CONFIG_S3C2440_NAND_HWECC,這樣在drivers/mtd/nand/s3c2440_nand.c文件內就定義了硬體ECC所需要的三個函數:s3c2440_nand_enable_hwecc函數、s3c2440_nand_calculate_ecc函數和s3c2440_nand_correct_data函數,而且在board_nand_init函數內,又把這三個函數分別賦給了相對應的結構體的三個成員,這樣在進行NandFlash讀寫時,就會調用這三個函數,從而實現了硬體ECC。s3c2440_nand_enable_hwecc函數負責使能硬體ECC,s3c2440_nand_calculate_ecc函數負責計算ECC(當然這種計算是由硬體來完成的),s3c2440_nand_correct_data函數負責進行ECC的校驗(同樣地,這種校驗也是由硬體自動完成的)。

相關閱讀:

U-Boot源代碼下載地址 http://www.linuxidc.com/Linux/2011-07/38897.htm

U-Boot-2011.06啟動流程分析 http://www.linuxidc.com/Linux/2011-07/39310.htm

u-boot-2011.06在基於s3c2440開發板的移植之編譯配置 http://www.linuxidc.com/Linux/2011-10/45455.htm

u-boot-2011.06在基於s3c2440開發板的移植之NorFlash啟動 http://www.linuxidc.com/Linux/2011-10/45456.htm

u-boot-2011.06在基於S3C2440開發板的移植之解決raise: Signal # 8 caught http://www.linuxidc.com/Linux/2011-10/454554.htm

u-boot-2011.06在基於s3c2440開發板的移植之支持NandFlash讀寫 http://www.linuxidc.com/Linux/2011-10/45457.htm

u-boot-2011.06在基於s3c2440開發板的移植之硬體ECC http://www.linuxidc.com/Linux/2011-10/454558.htm

為了理解u-boot是如何進行硬體ECC的,我們先來簡要地分析一下相關的函數。NandFlash是以頁為最小單位進行讀寫操作的,支持硬體ECC的讀操作最終是由nand_read_page_hwecc函數(在drivers/mtd/nand目錄下)來完成的,支持硬體ECC的寫操作最終是由nand_write_page_hwecc函數(在drivers/mtd/nand目錄下)來完成的。nand_read_page_hwecc函數的流程為先讀取main區數據,同時通過調用s3c2440_nand_calculate_ecc函數來得到硬體ECC;再讀取spare區數據;然後提取出儲存在spare區內的main區ECC;最後通過調用s3c2440_nand_correct_data函數來對剛剛讀取的main區數據進行校驗。nand_write_page_hwecc函數的流程比較簡單,它先寫入main區數據,同時通過調用s3c2440_nand_calculate_ecc函數來得到硬體ECC;然後就是把硬體ECC寫入到spare區內。

 

無論是nand_write_page_hwecc函數,還是nand_write_page_hwecc函數,內部都有一個這樣的for循環體:

for(i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {

……  ……

}

其中三個主要變數的定義為:

eccsize= chip->ecc.size;

eccbytes= chip->ecc.bytes;

eccsteps= chip->ecc.steps;

下面我們就來介紹一下這個循環的作用:不同的CPU的NandFlash控制器一次所能完成的硬體ECC的位元組數是不一樣的,例如有些CPU一次只能完成512位元組的硬體ECC,但如果開發板上的NandFlash每頁有2048個位元組,那該怎麼辦呢?這時就要用到一個循環體,通過循環多次來得到一頁的硬體ECC。例如上面這種情況,就要循環4次(2048÷512=4),才能得到這個頁內數據完整的硬體ECC。另外每一次硬體ECC,不同的CPU所生成的ECC位元組數也是不同的,有的是3個位元組,有的是4個位元組。

那麼,上面那三個變數的含義就分別為:

ecc.size:每一次硬體ECC所檢驗的位元組個數

ecc.bytes:每一次硬體ECC所生成的位元組個數

ecc.steps:每一頁需要進行硬體ECC的次數

對於S3C2440來說,一次硬體ECC可以檢驗2048個位元組,並且生成4個位元組的ECC,因此ecc.size應該為2048,ecc.bytes應該為4。而ecc.steps是通過計算得到的,即系統上電后能夠獲知NandFlash的每頁的大小,用這個值除以ecc.size就等於ecc.steps。所以對於這三個參數,只需事先定義好前兩個參數即可。而這兩個參數是在drivers/mtd/nand/s3c2440_nand.c文件中的board_nand_init函數內被定義賦值的,即:

nand->ecc.size = 2048;

nand->ecc.bytes = 4;

 

u-boot-2011.06對S3C2440的NandFlash控制器的寄存器定義得不完整,而且有錯誤,因此我們還需要對此進行修改。刪除arch/arm/include/asm/arch-s3c24x0/s3c24x0.h文件內的第167行至第178行內容,添加進下面的內容:

struct s3c2440_nand {

       u32  nfconf;

       u32  nfcont;

       u32  nfcmd;

       u32  nfaddr;

       u32  nfdata;

       u32  nfmeccd0;

       u32  nfmeccd1;

       u32  nfseccd;

       u32  nfstat;

       u32  nfestat0;

       u32  nfestat1;

       u32  nfmecc0;

       u32  nfmecc1;

       u32  nfsecc;

       u32  nfsblk;

       u32  nfeblk;

};

 

最後,我們對s3c2440_nand_enable_hwecc函數、s3c2440_nand_calculate_ecc函數和s3c2440_nand_correct_data函數進行修改。

 

void s3c2440_nand_enable_hwecc(structmtd_info *mtd, int mode)

{

       struct  s3c2440_nand *nand = s3c2440_get_base_nand();

       debugX(1,"s3c2440_nand_enable_hwecc(%p,%d)\n", mtd, mode);

       writel(readl(&nand->nfcont)| S3C2440_NFCONT_INITECC& ~S3C2440_NFCONT_MECCL,&nand->nfcont);

}

該函數的任務就是初始化ECC(即複位ECC),並解鎖main區ECC。

 

static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, constu_char *dat,

                                  u_char *ecc_code)

{

       struct  s3c2440_nand *nand = s3c2440_get_base_nand();

       u32  mecc0;

 

       writel(readl(&nand->nfcont)| S3C2440_NFCONT_MECCL,&nand->nfcont);

 

       mecc0= readl(&nand->nfmecc0);

       ecc_code[0]= mecc0 & 0xff;

       ecc_code[1] = (mecc0 >> 8) &0xff;

       ecc_code[2] = (mecc0 >> 16) &0xff;

       ecc_code[3] =(mecc0 >> 24) & 0xff;

      

       debugX(1,"s3c2440_nand_calculate_hwecc(%p,):0x%02x 0x%02x 0x%02x 0x%02x\n",

         mtd , ecc_code[0], ecc_code[1], ecc_code[2], ecc_code[3]);

 

       return 0;

}



[火星人 ] u-boot-2011.06在基於s3c2440開發板的移植之硬體ECC已經有308次圍觀

http://coctec.com/docs/program/show-post-71497.html