u-boot for tiny210 ver3.0 (by liukun321咕唧咕唧)

在此首先要特别感谢亚嵌的李明老师和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

各版本修改分析链接: ver2.0    ver2.1   ver2.2  ver2.2.1  ver2.2.2
 

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)

+10.添加Nandflash启动。
 
在介绍修改步骤之前,先对S5PV210的启动流程,及BL0阶段需要注意的问题作简要分析:
(1)启动流程:
启动的详细过程见datasheet,如下:
Program code starts from internal ROM(iROM) and moves to internal SRAM(iRAM). Finally, program executes on DRAM.
The booting sequence in internal ROM is as follows:
1. Disable the watchdog timer.
2. Initialize the instruction cache controller.
3. Initialize the stack and heap region.
4. Check secure key.
5. Set Clock divider, lock time, PLL (MPS value), and source clock.
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)
(2)BL0阶段需要注意的几个问题:
1. 在BL0阶段 nand或SD启动,前16K内容搬运到IRAM。
S5PV210有64k的irom,里面固化的代码用于将Nandflash或sd卡中的前16K代码cp到IRAM中(这个过程暂且称之为BL0,例如:在2440中的nand启动时BL0复制的是nandflash的前4K内容),只有在BL0成功完成以后,u-boot的BL1和BL2阶段才能够完成。IROM和Iram在地址空间的分布如下图:
 
 
2. 关于BL0阶段的ECC校验。
 由于我之前用过2440,就拿2440与s5pv210对比分析。2440在BL0阶段读nandflash时并没有开启ECC校验,而s5pv210在BL0阶段开启了8bit 硬件ECC校验。所以我们在nandflash中烧写uboot时要开启8bit 硬件ECC校验(因此我将ver3.0的SDboot版对nand的读写修改为8bit 硬件ECC校验,用于向nandflash烧写uboot)。如
果用非 8bit 硬件ECC校验的方式向nandflash烧写uboot,BL0阶段就会stop(ECC校验错误:这是导致BL0 stop的第一个原因)。
ECC校验的算法有很多种,至于用哪一种,我是通过分析用Superboot210烧写过的nandflash的oob区猜得的:
 
通过uboot的nand dump命令 ,如上图我用nand dump 0 读取了第零页及其oob的内容,该校验算法使用了52个字节的oob区,而tiny210用的nand的每page大小为2048byte。
从datasheet可也以得到:
这似乎可以联系到BCH算法(详细内容见附录)。因为以8bit/512Byte BCH方式,控制器写数据到NAND Flash时,每512Byte数据经过BCH模块就会生成13Byte的校验数据。这样修改 8bit  硬件ECC校验(SD启动的uboot开启了此校验方式,因为我们要用它在nand中烧写uboot)的基本方向就确定了。更多关于ECC的信息请参考手册。
 
3. 关于spl/tiny210-spl.bin文件前16字节内容的分析。
u-boot for tiny210 是基于spl的。
在使用前几个版本的u-boot for tiny210时,我们会把spl/tiny210-spl.bin烧到SD卡第一扇区。分析spl/Makefile 及 u-boot-spl.map我们可以知道:libtiny210.o(start.S)  lowlevel_init.o  mem_setup.o  nand_cp.o  nand.o  这几个文件会被最先链接生成.bin,该.bin文件经board/samsung/tiny210/tools/mktiny210spl.exe处理后最终得到tiny210-spl.bin。mktiny210spl.exe是由board/samsung/tiny210/tools/mkv210_image.c文件得到。
 
board/samsung/tiny210/tools/mktiny210spl.exe处理过程:根据mkv210_image.c文件的内容不难看出它的功能是将未被处理的.bin文件内容读到BUFSIZE大小的缓冲区,然后统计.bin文件中1的个数(作为用于BL0过程的校验和)。校验和存放在tiny210-spl.bin 文件最前面16字节的高8个字节中,而低8个字节则是存放#define SPL_HEADER              "S5PC110 HEADER  "字串的前8个字符也就是"S5PC110 "   。高8个字节的校验和将直接决定BL0阶段是否能够成功完成(校验和错误:这是导致BL0 stop的第二个原因)。当#define IMG_SIZE                (X*1024)大于未被处理的.bin文件时,生成的新文件尾会被0填充直至生成的tiny210-spl.bin的大小等于IMG_SIZE。
 
在BL0阶段,Irom内固化的代码读取nandflash或SD卡前16K的内容,并比对前16字节中的校验和是否正确,正确则继续,错误则停止。
 
a = Buf + SPL_HEADER_SIZE;
 for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
  checksum += (0x000000FF) & *a++;
上面这段代码位于board/samsung/tiny210/tools/mkv210_image.c中即是统计校验和。
(3)下面介绍一下修改步骤(以下步骤是基于u-boot for tiny210 ver2.2.X的),并作简要的分析。
 
1.首先在 include/configs/tiny210.h 中修改下述宏:
删除172-183行:

-/* 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修改完成.

编译u-boot
$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
$./make-tiny210-boot.sh
由于我的系统下装有两套交叉工具链,所以没有把  /opt/FriendlyARM/toolschain/4.5.1/bin/ 添加到环境变量,在使用工具链时要指明路径。

1.sd启动
当我们在include/configs/tiny210.h定义了#define CONFIG_TINY210_MMC_BOOT               1 为SD启动
 
将u-boot镜像写入SD卡
将SD卡通过读卡器接上电脑(或直接插入笔记本卡槽),通过"cat /proc/partitions"找出SD卡对应的设备,我的设备节点是/dev/sdb.

执行下面的命令
$sudo dd iflag=dsync oflag=dsync if=tiny210-uboot.bin of=/dev/sdb seek=1
2.nandflash启动
当我们在include/configs/tiny210.h定义了#define CONFIG_TINY210_NAND_BOOT               1 为NANDFLASH启动
通过SD卡启动的u-boot for tiny210 将u-boot镜像写入nandflash

 

[FriendlyLEG-TINY210]# tftp 21000000 tiny210-uboot.bin
[FriendlyLEG-TINY210]# nand erase.chip
[FriendlyLEG-TINY210]# nand write 21000000 0 3b4c4
 
 
测试保存环境变量:
 
 
附录:BCH算法

对于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来说已经没有办法纠正错误了,只能报告出现了不可以纠正的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值