在此首先要特別感謝網友李明老師和Alex Ling對我無私的幫助和支持。
這次更新,主要實現了Nand啓動,並修改了前幾個版本的幾個小bug。ver3.0已經基本完成了u-boot的主線功能。後面我還會繼續更新其它輔助功能。
之前上傳的幾個版本,對nandflash燒寫時ECC校驗是基於軟件ECC,由於S5PV210的IROM中固化的啓動代碼(暫且稱其爲BL0)在讀nandflash時
用的是8bit 硬件ECC。因此在燒寫u-boot for tiny210到nandflash時,需要用開啓了8bit 硬件ECC的 SD卡啓動的u-boot 進行燒寫(詳見後面分析)。
您可以從下面的鏈接獲得源碼,也可以下載歷史版本,並參考後面的步驟修改獲得ver3.0.
ver3.0源碼下載:u-boot for tiny 210 ver3.0
您也可以打開下面的鏈接閱讀ver3.0源碼
Git source tree(這是我在Gitorious建的第一個工程,對它的管理還是顯的比較混亂。等我整理好另一個clone的工程,我會把鏈接貼上來)。
下面的鏈接提供了歷史版本的源碼
ver2.2源碼下載: u-boot for tiny210 ver2.2
ver2.1源碼下載:u-boot for tiny210 ver2.2
ver2.1源碼下載:u-boot for tiny210 ver2.1
ver2.0源碼下載:u-boot for tiny210 ver2.0
ver3.0的基本功能:
1. SD boot,基於linaro u-boot的SPL功能實現
2. 從SD卡的FAT分區上加載文件到SDRAM
3. 將環境變量保存至SD卡
4. 添加DM9000網卡驅動,開啓網絡功能(例如:tftp,nfs等)
5. 添加TAB鍵命令自動補全功能
6.修復bug:
修復bug 1:SD卡保存環境變量出現Writing to MMC(0)... mmc_send_cmd: error during transfer: 0x00208001 mmc write failed。
修復bug 2:每次啓動只能保存一次環境變量。
7.添加NandFlash驅動,開啓所有Nand cmd。
8.添加Yaffs文件系統燒寫支持。
+9.修改在SD卡啓動時對nandflash的燒寫爲8bit 硬件ECC校驗。(nand啓動仍爲軟件ECC)
The booting sequence in internal ROM is as follows:
1. Disable the watchdog timer.
3. Initialize the stack and heap region.
4. Check secure key.
6. Check OM pin and load the first boot loader (The size of boot loader depends on S/W) from specific device (block number 0) to iRAM.
7. If secure booting is successful, execute integrity check
8. If integrity check passes, then jump to the first boot loader in iRAM (0xD002_0010)
The booting sequence in internal SRAM is as follows:
1. Load the second boot loader from boot device to iRAM.
2. If secure booting is successful, execute integrity check.
3. If integrity check passes, then jump to the second boot loader in iRAM (The jumping address depends on user's software)
4. If integrity check fails, then stop the first boot loader.
5. The second boot loader Initializes the DRAM controller.
6. Load the OS image from specific device (block number 1) to DRAM.
7. Jump to OS code in DRAM (0x2000_0000 or 0x4000_0000)
for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
checksum += (0x000000FF) & *a++;
-/* FLASH and environment organization */
-#define CONFIG_SYS_NO_FLASH 1
-#undef CONFIG_CMD_IMLS
-#define CONFIG_IDENT_STRING " for FriendlyLEG-TINY210"
-
-#define CONFIG_ENV_IS_IN_MMC 1
-#define CONFIG_SYS_MMC_ENV_DEV 0
-#define CONFIG_ENV_SIZE 0x4000 /* 16KB */
-#define RESERVE_BLOCK_SIZE (512)
-#define BL1_SIZE (8 << 10) /*8 K reserved for BL1*/
-#define CONFIG_ENV_OFFSET (RESERVE_BLOCK_SIZE + BL1_SIZE + ((16 + 512) * 1024))
-#define CONFIG_DOS_PARTITION 1
然後在
460:
+/* FLASH and environment organization */
+#define CONFIG_SYS_NO_FLASH 1
+#undef CONFIG_CMD_IMLS
+#define CONFIG_IDENT_STRING " for FriendlyLEG-TINY210"
+#if 1
+#define CONFIG_TINY210_NAND_BOOT
1
+#endif
+#if 0
+#define CONFIG_TINY210_MMC_BOOT
1
+#endif
+/*MMC BOOT */
+#if defined(CONFIG_TINY210_MMC_BOOT)
+#define CFG_NAND_HWECC
+#define CONFIG_NAND_BL1_8BIT_ECC
+#define CONFIG_ENV_IS_IN_MMC 1
+#define CONFIG_SYS_MMC_ENV_DEV 0
+#define CONFIG_ENV_SIZE 0x4000 /* 16KB */
+#define RESERVE_BLOCK_SIZE (512)
+#define BL1_SIZE (8 << 10) /*8 K reserved for BL1*/
+#define CONFIG_ENV_OFFSET (RESERVE_BLOCK_SIZE + BL1_SIZE + ((16 + 512) * 1024))
+#endif
+
+#define CONFIG_DOS_PARTITION 1
+
+/*NAND_BOOT by lk */
+#if defined(CONFIG_TINY210_NAND_BOOT)
+#define CONFIG_S5PC11X
+#define CONFIG_ENV_IS_IN_NAND 1
+#define CONFIG_ENV_SIZE 0x4000 /* 16KB */
+#define CONFIG_ENV_OFFSET 0x40000
+#endif
#define CONFIG_TINY210_NAND_BOOT 1
即可實現nand啓動
#define CONFIG_TINY210_MMC_BOOT 1
即可實現sd啓動
2.修改board/samsung/tiny210/Makefile 即可通過定義CONFIG_TINY210_MMC_BOOT/CONFIG_TINY210_NAND_BOOT,分別實現SD啓動和NAND啓動。
ifdef CONFIG_SPL_BUILD
+
+ifdef CONFIG_TINY210_MMC_BOOT
COBJS += mmc_boot.o
endif
+ifdef CONFIG_TINY210_NAND_BOOT
COBJS += nand_cp.o
+endif
+endif
屏蔽掉38行的COBJS += nand_cp.o
3.修改實現8bit 硬件ECC校驗。board/samsung/tiny210/nand.c中
44:static struct nand_ecclayout s3c_nand_oob_16 = {
.eccbytes = 4,
.eccpos = {1, 2, 3, 4},
.oobfree = {
{.offset = 6,
. length = 10}}
};
-
52:+static struct nand_ecclayout s3c_nand_oob_64_8bit = {
+ .eccbytes = 52,
+ .eccpos = {
+ 12,13,14,15,
+ 16,17,18,19,20,21,22,23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63},
+ .oobfree = {
+ {.offset = 2,
+ .length = 10}}
+};
/* Nand flash oob definition for SLC 2k page size by jsgood */
static struct nand_ecclayout s3c_nand_oob_64 = {
屏蔽掉下面兩個函數中的while
上面的信息可見【25】【24】位是對MLC nandflash的狀態位,而tiny210上用的是SLC的nandflash。所以進行下面的屏蔽。
static void s3c_nand_wait_enc(void)
{
+// while (!(readl(NFECCSTAT) & NFSTAT_ECCENCDONE)) {}
}
/*
@@ -187,7 +200,7 @@ static void s3c_nand_wait_enc(void)
*/
static void s3c_nand_wait_dec(void)
{
+// while (!(readl(NFECCSTAT) & NFSTAT_ECCDECDONE)) {}
}
@@ -1042,9 +1067,24 @@
int board_nand_init(struct nand_chip *nand)
nand_type = S3C_NAND_TYPE_SLC;
nand->ecc.size = 512;
nand->ecc.bytes = 4;
-
1060:+
+ if ((1024 << (tmp & 3)) == 4096) {
+ /* Page size is 4Kbytes */
+ nand->ecc.read_page = s3c_nand_read_page_8bit;
+ nand->ecc.write_page = s3c_nand_write_page_8bit;
+ nand->ecc.read_oob = s3c_nand_read_oob_8bit;
+ nand->ecc.write_oob = s3c_nand_write_oob_8bit;
+ nand->ecc.layout = &s3c_nand_oob_128;
+ nand->ecc.hwctl = s3c_nand_enable_hwecc_8bit;
+ nand->ecc.calculate = s3c_nand_calculate_ecc_8bit;
+ nand->ecc.correct = s3c_nand_correct_data_8bit;
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 13;
+ nand->options |= NAND_NO_SUBPAGE_WRITE;}
+ else
if ((1024 << (tmp & 0x3)) > 512) {
- nand->ecc.read_page = s3c_nand_read_page_1bit;
1073:+#if defined(CONFIG_NAND_4BIT_ECC)
+ nand->ecc.read_page = s3c_nand_read_page_1bit;
nand->ecc.write_page = s3c_nand_write_page_1bit;
nand->ecc.read_oob = s3c_nand_read_oob_1bit;
nand->ecc.write_oob = s3c_nand_write_oob_1bit;
@@ -1053,6 +1093,18 @@ int board_nand_init(struct nand_chip *nand)
nand->ecc.calculate = s3c_nand_calculate_ecc;
nand->ecc.correct = s3c_nand_correct_data;
nand->options |= NAND_NO_SUBPAGE_WRITE;
1083:+#endif
+nand->ecc.read_page = s3c_nand_read_page_8bit;
+ nand->ecc.write_page = s3c_nand_write_page_8bit;
+ nand->ecc.read_oob = s3c_nand_read_oob_8bit;
+ nand->ecc.write_oob = s3c_nand_write_oob_8bit;
+ nand->ecc.layout = &s3c_nand_oob_64_8bit;
+ nand->ecc.hwctl = s3c_nand_enable_hwecc_8bit;
+ nand->ecc.calculate = s3c_nand_calculate_ecc_8bit;
+ nand->ecc.correct = s3c_nand_correct_data_8bit;
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 13;
+ nand->options |= NAND_NO_SUBPAGE_WRITE;
} else {
nand->ecc.layout = &s3c_nand_oob_16;
}
4,修改nand_cp.c文件。
+//#include <regs.h>
+#include <s5pc110.h>
+#define COPY_BL2_SIZE 0x80000
@@ -98,7 +98,7 @@ static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
page_shift = 11;
/* Read pages */
98: for (i =(0x6000>>page_shift); i < (size>>page_shift); i++, buf+=(1<<page_shift)) {
nandll_read_page(buf, i, large_block);
}
0x6000是24k後的第一個地址,也就是從這個nandflash的這個偏移地址開始cp內容到DRAM。
@@ -128,8 +128,29 @@ int copy_uboot_to_ram (void)
128:+ return nandll_read_blocks(CONFIG_SYS_TEXT_BASE, COPY_BL2_SIZE, large_block);
+}
+void board_init_f(unsigned long bootflag)
+{
+ __attribute__((noreturn)) void (*uboot)(void);
+ copy_uboot_to_ram();
+
+ /* Jump to U-Boot image */
+ uboot = (void *)CONFIG_SYS_TEXT_BASE;
+ //while(1);
+ (*uboot)();
+ /* Never returns Here */
}
-
+
+/* Place Holders */
+void board_init_r(gd_t *id, ulong dest_addr)
+{
+ /* Function attribute is no-return */
+ /* This Function never executes */
+ while (1)
+ ;
+}
+
+void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) {}
5.修改board/samsung/tiny210/tools/mkv210_image.c
8:#define BUFSIZE (24*1024)
#define IMG_SIZE (24*1024)
這個參數的修改是爲了便於實現nandboot和SDboot的切換,因爲
在board/samsung/tiny210/mmc_boot.c第四十九行可以找到
#define MOVI_BL2_POS ((eFUSE_SIZE / MOVI_BLKSIZE) + MOVI_BL1_BLKCNT + MOVI_ENV_BLKCNT)
當sdboot的BL1階段要從MOVI_BL2_POS(24k + 1k(sd卡的第0扇區))這個偏移位置開始向DRAM cp代碼。雖然啓動時只會從nand或SD卡一次性讀取16K內容,但是爲了統一兩種啓動方式tiny210-spl.bin的大小,生成24k大小的tiny210-spl.bin(這並不會影響校驗和,因爲文件尾是由0填充)。
另外我在源碼的根目錄下寫了一個簡單的腳本make-tiny210-boot.sh,用於合併tiny210-spl.bin和u-boot.bin文件->生成tiny210-uboot.bin。這樣我們以後燒寫uboot時就不用像老版本那樣分別燒寫兩個文件了。
至此ver3,0修改完成.
$make ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- tiny210_config
$make ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- all spl
由於我的系統下裝有兩套交叉工具鏈,所以沒有把 /opt/FriendlyARM/toolschain/4.5.1/bin/ 添加到環境變量,在使用工具鏈時要指明路徑。
1.sd啓動
將SD卡通過讀卡器接上電腦(或直接插入筆記本卡槽),通過"cat /proc/partitions"找出SD卡對應的設備,我的設備節點是/dev/sdb.
執行下面的命令
$sudo dd iflag=dsync oflag=dsync if=tiny210-uboot.bin of=/dev/sdb seek=1
對於BCH算法目前通常以512Byte或者1024Byte爲單位處理,因爲BCH按位處理數據,所以是4096bit或者8192bit,這裏的4096/8192bit是原始數據,BCH需要生成一定的校驗數據。下面簡要介紹下原理
設最大糾錯能力爲t
如果選用4096bit的原始數據長度,則模式爲BCH(8191,8191-13×t,t,13)
如果選用8192bit的原始數據長度,則模式爲BCH(16383,16383-14×t,t,14)
校驗數據長度就是13×t,或者14×tbit
所以平均1024+32Byte的MLC 大多建議使用8bit/512Byte ECC
平均1024+45Byte的MLC大多建議使用24Bit/1024Byte ECC, 此時需要14×24bit=42Byte的檢驗數據空間
以8bit/512Byte BCH方式的ECC爲例,控制器寫數據到NAND Flash時,每512Byte數據經過BCH模塊就會生成13Byte的校驗數據(當然剩下的16-13=3Byte也可以作爲某種用途的數據,可以任意使用0-3Byte而不會改變ECC的使用),這些數據一起寫入到NAND Flash中。控制器從NAND Flash中讀取數據的時候需要將原始數據和校驗數據一起讀出經過BCH模塊,BCH模塊計算伴隨矩陣首先可以判斷出是否出現了錯誤,如果出現了錯誤需要計算錯誤位置多項式,然後解多項式,得到錯誤位置(目前主要使用Chien-search方法),因爲是位錯誤,找到錯誤的位置以後取反以後就是正確的數據。只要是錯誤個數小於等於8,BCH都能夠找到錯誤的位置,但是如果錯誤個數超過了8,對於BCH來說已經沒有辦法糾正錯誤了,只能報告出現了不可以糾正的情況。