增加Nand Flash ECC的支持
又參考了網址http://blog.csdn.net/fulinus/article/details/8737129
修改相關文件:
1. u-boot-2011.03\drivers\mtd\nand\s3c2440_nand.c
2. u-boot-2011.03\include\configs\mini2440.h
一開始一直不能確定的是:nand->ecc.size 和nand->ecc.bytes到底是多少?板子上帶的Nand Flash是:K9F1208U0B:64MB,8位。每1頁包含512字節的main數據區和16字節的spare數據區。main區用於存儲數據,spare區用於存儲其它附加信息。S3C2440一次可以產生4個字節的ECC,對於K9F1208U0B,頁大小是512字節的nand flash,只要讀取1頁(512字節)就產生4個字節的main區ECC。對於頁是2048字節的nand flash,同樣也是讀取1頁(2048字節)就產生4字節的ECC。參考網址,將nand->ecc.size=512,nand->ecc.bytes=4。
@2014-04-26:關於產生ECC字節數之前的誤解:
S3C2440到底讀/寫一頁數據上產生多少個字節的main區ECC和多少個字節的spare區ECC,是和Nand Flash的位數關聯的。如果Nand Flash是8位的,那麼一頁產生4字節的Main區ECC(在NFMECC0寄存器裏)和2個字節的spare區ECC(在NFSECC寄存器的低16位),如果Nand Flash是16位的,那麼一頁產生8個字節的Main區ECC(在NFMECC0和NFMECC1寄存器裏)和4個字節的spare區ECC(在NFSECC寄存器裏)。但是目前我們並沒有是spare區的ECC碼。
如下圖(摘自S3C2440A datasheet)
關於怎麼產生ECC:
在S3C2440數據手冊第6章有這麼一段。
產生ECC校驗碼的過程爲:在讀取或寫入哪個區的數據之前,先解鎖該區的ECC,以便產生該區的ECC。在讀取或寫入完數據之後,再鎖定該區的ECC,這樣系統就會把產生的ECC碼保存到相應的寄存器中。
以主數據區域爲例:解鎖ECC,將NFCONT中第5位MainECCLock置0。鎖定ECC,將NFCONT中第5位MainECCLock置1。
當讀或寫數據時,自動產生的ECC校驗在寄存器NFMECC0/1中。
ECC校驗可以糾正1個比特的錯誤和檢測2個比特的錯誤。
關於出現1位錯誤根據下圖校正。
1. 先計算哪個數據出錯:(NFESTAT0>>7) & 0x7ff;
2. 再計算哪個位出錯:(NFESTAT0>>4) & 0x7;
3. 校正:我們知道,1位出錯,要麼是0變1,要麼是1變0。用1與這位異或即可。
Repaired = Data[(NFESTAT0>>7)& 0x7ff] ^ (1<<((NFESTAT0>>4) & 0x7));
測試:
調試運行後的串口輸出如下圖:
讀參數時報了一個-74的錯誤,應該就是ECC校驗不過的原因。具體還沒有去查。下面還有一個warning。在串口中輸入saveenv,然後再次調試運行,如下圖。這時候沒有報上圖的錯誤了。
查看參數0x80000的nand flash值,發現oob的前4個字節已經與之前的不同了。其中0x80000是在mini2440.h文件內定義的nand flash 參數起始地址。nand dump命令並不會去進行數據的ECC校驗檢測,只是讀取數據,這區別與下面的nand read命令
當執行:nand read 0x31100000 0x80000 0x200時,程序會調用到這裏,在文件drivers/mtd/nand/nand_base.c,函數nand_read_page_hwecc。如下圖:
根據上圖可做函數簡要說明:
staticint s3c2440_nand_calculate_ecc(structmtd_info *mtd, const u_char *dat,
u_char *ecc_code)
當讀或寫完一頁後,調用該函數,讀取NFMECC0寄存器,就可以將該頁main區的ECC校驗碼取出。參考源碼
其中,u_char *ecc_code就是存取讀取的ECC校驗碼
staticint s3c2440_nand_correct_data(structmtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
該函數用來比較read_ecc和calc_ecc的校驗是否相等的。
其中,read_ecc是在spare區讀出來的ECC校驗值。
calc_ecc是讀完1頁後自動產生的ECC校驗值。針對main區的ECC校驗碼,此值同樣存在於NFMECC0寄存器內。
但是在該函數中並沒有直接去比較read_ecc和calc_ecc,而是將read_ecc的值寫入NFMECCD0和NFMECCD1,用硬件去比較,然後讀取寄存器NFSTAT的值來判斷。
其實直接比較read_ecc和calc_ecc,也是可以的,有的移植就是直接比較的。
本部分代碼下載地址:360雲盤http://yunpan.360.cn/,在《Uboot相關代碼》文件夾裏的《u-boot-2011.03_SRAM調試.zip》文件。
《u-boot-2011.03源碼無修改.tar.bz2》是從官網下的無修改代碼