MINI2440 開發板使用的是8bit,256M blocksize= 128k,pagesize =2k的nandflash。編程
寬帶爲8bit ,由S3C2440 datasheet 可知硬件生產的ecc爲4byte。函數
S3C2440 硬件ecc 操做流程:spa
1.先讀出NFMECC0寄存器中由硬件生產的ecc data。debug
2.將讀出的ecc數據,進行處理以後,分別寫入NFMECCD0和NFMECCD1寄存器,code
硬件自動檢測,檢測結果可從NFESTAT0 寄存器讀取。ip
3. 讀取NFESTAT0寄存器,進行錯誤類別判斷。開發
4.若是是1bit error 進行數據糾正,數據錯誤>2bit沒法糾正。get
在上一篇關於「支持NandFlash讀寫」的文章中,咱們很好地完成了u-boot對NandFlash的讀寫,但這個讀寫進行的是軟件ECC,即用軟件編程的方法實現ECC。咱們知道S3C24x0的NandFlash控制器是支持硬件ECC的,所以在這裏咱們就來說解如何實現硬件ECC。flash
NandFlash的每一頁分爲main區和spare區,S3C24x0的NandFlash控制器支持這兩個區的硬件ECC,但只實現main區的硬件ECC。it
爲了實現硬件ECC,首先須要在include/configs/smdk2410.h文件內定義宏CONFIG_S3C2410_NAND_HWECC,這樣在drivers/mtd/nand/s3c2440_nand.c文件內就定義了硬件ECC所須要的三個函數:s3c24x0_nand_enable_hwecc函數、s3c24x0_nand_calculate_ecc函數和s3c24x0_nand_correct_data函數,並且在board_nand_init函數內,又把這三個函數分別賦給了相對應的結構體的三個成員,這樣在進行NandFlash讀寫時,就會調用這三個函數,從而實現了硬件ECC。s3c24x0_nand_enable_hwecc函數負責使能硬件ECC,s3c24x0_nand_calculate_ecc函數負責計算ECC(固然這種計算是由硬件來完成的),s3c24x0_nand_correct_data函數負責進行ECC的校驗(一樣地,這種校驗也是由硬件自動完成的)。
爲了理解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區數據,同時經過調用s3c24x0_nand_calculate_ecc函數來獲得硬件ECC;再讀取spare區數據;而後提取出儲存在spare區內的main區ECC;最後經過調用s3c24x0_nand_correct_data函數來對剛剛讀取的main區數據進行校驗。nand_write_page_hwecc函數的流程比較簡單,它先寫入main區數據,同時經過調用s3c24x0_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。
include/configs/smdk2410.h文件內定義
#define CONFIG_SYS_NAND_ECCSIZE 2048
#define CONFIG_SYS_NAND_ECCBYTES 4
如今準備開始移植,打開drivers/mtd/nand/s3c2410_nand.c 文件,修改爲以下函數
void s3c24x0_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
debug("s3c24x0_nand_enable_hwecc(%p, %d)\n", mtd, mode);
writel(readl(&nand->nfcont) | S3C2440_NFCONT_INITECC, &nand->nfcont);
}
static int s3c24x0_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
{
struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
unsigned int 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;
debug("s3c24x0_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;
}
static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
{
struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
u32 meccdata0,meccdata1,estat0,err_byte_addr;
int ret=-1;
u8 repaired;
meccdata0 = (read_ecc[1] << 16) | read_ecc[0];
meccdata1 = (read_ecc[3] << 16) | read_ecc[2];
writel(meccdata0,&nand->nfeccd0);
writel(meccdata1,&nand->nfeccd1);
/*read ecc status*/
estat0 = readl(&nand->nfstat0);
switch (estat0 &0x3){
case 0: /*no error*/
ret =0;
break;
case 1:
/*
*1bit error(correctable)
*(nfestat0 >>7) & 0x7ff error byte number
*(nfestat0 >>4) & 0x7 error bit number
*/
err_byte_addr = (estat0 >>7 ) & 0x7ff;
repaired = dat[err_byte_addr]^(1<<((estat0 >>4) & 0x7));
printf("S3C NAND: 1 bit error detected at byte%ld. "
"Correcting from 0x%02x to0x%02x...OK\n",
err_byte_addr, dat[err_byte_addr],repaired);
dat[err_byte_addr]= repaired;
ret= 1;
break;
case 2: /* Multiple error */
case 3: /* ECC area error */
printf("S3C NAND: ECC uncorrectable errordetected. "
"Not correctable.\n");
ret= -1;
break;
}
return ret;}