本篇文章阐述移植 u-boot v2018.01 至 S5PV210 开发板上的主要流程和细节。市场上的S5PV210开发板,均是基于三星smdkv210公版平台山寨出来的。我使用的GEC210开发板也与公版只数个元器件的差异。所以,若你也用S5PV210类开发板,参考本篇文章,或者直接使用我发布的补丁打到源码上,能帮你解决许多困惑及运行最新的u-boot。
最新更新
[2018-12-2 15:17:41] 可直接下载我发布到github已经移植好的源码:u-boot-v2018.01_for_gec210
结果
下载u-boot-2018.01.tar.bz2,或通过git下载:
① $ git clone git://git.denx.de/u-boot.git
② $ git checkout v2018.01
该源码要求使用>=6.0版本GCC编译,下载最新编译好的linaro arm交叉编译工具链,选择对应Linux环境的工具链下载并解压,如:我的为32位 ubuntu则选如下标注的文件:
下载我已发布到github的补丁到源码目录:u-boot-v2018.01_gec210.patch
打补丁到源码:$ git apply u-boot-v2018.01_gec210.patch,如下所示,有警告无影响;由于补丁中含有二进制数据,使用patch命令打补丁将出错。
设置交叉编译工具链前缀:设置u-boot/Makefile中CROSS_COMPILE变量为前面解压好的工具链可执行文件的前缀,如:
配置源码为目标板:$ make gec210_defconfig
编译:$ make,最终产生u-boot.bin文件
以下阐述移植的过程,由于篇幅有限,重点难点的修改才会作详细的解释,参考上述补丁文件更详尽。开始移植时还需要分析u-boot的流程,可以参考我另一篇博文《u-boot v2018.01 启动流程分析》。
以下章节中出现的脚本名字有如下关系,每一个章节对应一次git提交,一次对u-boot源码打上所有阶段补丁等效于一次性打上补丁u-boot-v2018.01_gec210.patch:
一、建立新板
1.设置交叉编译工具链,参考上面;
CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-7.2.1-2017.11-i686_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
2.板级相关驱动移植smdkc100的代码:$ cp board/samsung/smdkc100 board/samsung/gec210 -r
① 修改配置菜单board/samsung/gec210/Kconfig:
@@ -1,7 +1,7 @@
-if TARGET_SMDKC100
+if TARGET_GEC210
config SYS_BOARD
-default "smdkc100"
+default "gec210"
config SYS_VENDOR
default "samsung"
@@ -10,6 +10,6 @@
default "s5pc1xx"
config SYS_CONFIG_NAME
-default "smdkc100"
+default "gec210"
endif
② 修改板级初始化文件名:$ mv board/samsung/gec210/smdkc100.c board/samsung/gec210/gec210.c,相应修改
board/samsung/gec210/Makefile:
@@ -8,6 +8,6 @@
# SPDX-License-Identifier:GPL-2.0+
#
-obj-y:= smdkc100.o
+obj-y:= gec210.o
③ 建立了新板代码,但还没能被编译和链接,所以修改arch/arm/mach-s5pc1xx/Kconfig,才能在配置菜单中选中
gec210单板进行编译:
@@ -12,6 +12,10 @@
bool "Support smdkc100 board"
select OF_CONTROL
+config TARGET_GEC210
+bool "Support gec210 board"
+select OF_CONTROL
+
endchoice
config SYS_SOC
@@ -19,5 +23,6 @@ config SYS_SOC
source "board/samsung/goni/Kconfig"
source "board/samsung/smdkc100/Kconfig"
+source "board/samsung/gec210/Kconfig"
3.移植smdkc100的菜单配置文件:$ cp configs/smdkc100_defconfig configs/gec210_defconfig,配置源码$ make gec210_defconfig,$ make menuconfig,在菜单-> ARM architecture -> S5PC1XX board select中选择Support gec210 board,如下图。完后需及时保存好配置:$ cp .config configs/gec210_defconfig;
4.移植非菜单的配置:$ cp include/configs/smdkc100.h include/configs/gec210.h:
@@ -19,7 +19,9 @@
#define CONFIG_SAMSUNG1/* in a SAMSUNG core */
#define CONFIG_S5P1/* which is in a S5P Family */
-#define CONFIG_S5PC1001/* which is in a S5PC100 */
-#define CONFIG_SMDKC1001/* working with SMDKC100 */
+//#define CONFIG_SMDKC1001/* working with SMDKC100 */
5.芯片S5PV210上电启动时,首先运行位于irom内BL0,它根据BL1开始的16Byte加载BL1;所以需要定义BL1的头部信息,创建文件:$ touch arch/arm/mach-s5pc1xx/include/mach/boot0.h,文件内容如下;u-boot称这个头部信息为"hook"(钩子),开启该功能还需在菜单里选中:-> ARM architecture -> [*] prepare BOOT0 header。
/*
* Copyright 2018 Lucifer Zhu, LuciferZhu@yeah.net.
*
* SPDX-License-Identifier:GPL-2.0+
*/
/* BOOT0 header information */
.word 0x2000@ indicate BL1 size for irom
.word 0x0
.word 0x0
.word 0x0
_start:
ARM_VECTORS
二、底层初始化(clock,ddr2,uart,nand)
1.移植S5PV210的特殊寄存器定义。采用三星发布的u-boot-1.3.4中s5pc110.h文件(s5pc110与s5pv210的寄存器地址相同):$ cp ../u-boot-samsung-dev/include/s5pc110.h arch/arm/mach-s5pc1xx/include/mach/s5pc110.h。s5pc110.h文件中定义及引用了当前源码未定义的内容,所以还需做裁剪,具体参考u-boot-v2018.01_gec210.patch:
2.修改lowlevel_init.S以实现SOC级别硬件初始化,包括WATCHDOG,clock,DDR2,uart,nand。第一章已经从smdkc100单板中移植了lowlevel_init.S,其代码流程与S5PV210一致,但各硬件的初始化需重写,需修改函数包括:lowlevel_init,system_clock_init,uart_asm_init,tzpc_asm_init,还需添加nand_asm_init及mem_ctrl_asm_init(定义于mem_init.S文件),另外引用的宏需在include/configs/gec210.h里定义。这些基础的soc级别初始化均可移植于u-boot-samsung-dev,详细参考补丁:
3.保证lowlevel_init.S和mem_init.S的text位于u-boot.bin前8KB内。启动流程中运行于iRAM的BL1大小为8KB,所以soc级别的lowlevel_init也应被包含在内,所以修改链接脚本arch/arm/cpu/u-boot.lds如下。
@@ -44,6 +44,8 @@
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
+board/samsung/gec210/lowlevel_init.o (.text*)
+board/samsung/gec210/mem_init.o (.text*)
*(.text*)
}
另外,这两文件的目标文件不应追加到变量obj-y,否则编译时被认为重复定义,所以修改board/samsung/gec210/Makefile:
@@ -10,4 +10,5 @@
obj-y:= gec210.o
obj-$(CONFIG_SAMSUNG_ONENAND)+= onenand.o
-obj-y+= lowlevel_init.o
+extra-y+= lowlevel_init.o
+extra-y+= mem_init.o
4.移植smdkc100的设备树:$ cp arch/arm/dts/s5pc1xx-smdkc100.dts arch/arm/dts/s5pc1xx-gec210.dts,修改如下:
@@ -9,26 +9,26 @@
/dts-v1/;
#include "skeleton.dtsi"
-#include "s5pc100-pinctrl.dtsi"
+#include "s5pc110-pinctrl.dtsi"
/ {
-model = "Samsung SMDKC100 based on S5PC100";
-compatible = "samsung,smdkc100", "samsung,s5pc100";
+model = "Samsung GEC210 based on S5PV210";
+compatible = "samsung,gec210", "samsung,s5pc110";
aliases {
-serial0 = "/serial@ec000000";
-console = "/serial@ec000000";
+serial0 = "/serial@e2900000";
+console = "/serial@e2900000";
pinctrl0 = &pinctrl0;
};
-pinctrl0: pinctrl@e0300000 {
-compatible = "samsung,s5pc100-pinctrl";
+pinctrl0: pinctrl@e0200000 {
+compatible = "samsung,s5pc110-pinctrl";
reg = <0xe0200000 0x1000>;
};
-serial@ec000000 {
+serial@e2900000 {
compatible = "samsung,exynos4210-uart";
-reg = <0xec000000 0x100>;
+reg = <0xe2900000 0x400>;
另外还需修改arch/arm/dts/Makefile使该设备树被编译和附加到u-boot.bin尾部:
@@ -9,6 +9,7 @@
dtb-$(CONFIG_S5PC100) += s5pc1xx-smdkc100.dtb
dtb-$(CONFIG_S5PC110) += s5pc1xx-goni.dtb
+dtb-$(CONFIG_S5PV210) += s5pc1xx-gec210.dtb
dtb-$(CONFIG_EXYNOS4) += exynos4210-origen.dtb \
exynos4210-smdkv310.dtb \
exynos4210-universal_c210.dtb \
至此,底层基础的初始化代码移植完成,运行之会打印“OK”:
三、从Nand和mmc/sd加载启动u-boot
到目前为止,代码只是在soc的iRAM内执行,在不使用u-boot新功能SPL(secondary program loader)的话,我们需要在arch/arm/cpu/armv7/start.S中实现进行从Nand和mmc/sd加载BL2到DDR2并跳转之的操作。
1.移植读nand的底层裸机驱动。它的唯一使命是读取Nand flash中BL2代码到DDR2,从u-boot 1.3.4中移植cpu/s5pc11x/nand_cp.c到u-boot 2018的board/samsung/gec210/nand_cp.c路径。参考03_boot_from_nand_sd.patch:
需要注意的是,我们需指定加载BL2到的目标内存地址CONFIG_SYS_TEXT_BASE,以及BL2大小COPY_BL2_SIZE,将其定义于include/configs/gec210.h:
由于nand_cp.c的代码依然是在iram中被调用,意味着需将nand_cp.c链接进u-boot.bin前8KB内,否则程序跑飞:
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index a6bfd3b..6c3feac 100755
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -46,6 +46,7 @@
CPUDIR/start.o (.text*)
board/samsung/gec210/lowlevel_init.o (.text*)
board/samsung/gec210/mem_init.o (.text*)
+board/samsung/gec210/nand_cp.o (.text*)
*(.text*)
}
diff --git a/board/samsung/gec210/Makefile b/board/samsung/gec210/Makefile
index fe65af4..ddeb488 100755
--- a/board/samsung/gec210/Makefile
+++ b/board/samsung/gec210/Makefile
@@ -12,3 +12,4 @@
obj-$(CONFIG_SAMSUNG_ONENAND)+= onenand.o
extra-y+= lowlevel_init.o
extra-y+= mem_init.o
+extra-y+= nand_cp.o
2.实现mmc/sd的读取操作。S5PV210的iROM中保存着实现诸如mmc/sd,各类型nand flash,eSSD的读取操作的代码。所以直接调用irom内的读取mmc/sd函数,来加载位于mmc/sd内第49扇区开始的BL2代码,参考03_boot_from_nand_sd.patch中第172行,代码如下:
/*************************************************************************
*
* copy U-Boot to SDRAM and jump to ram (from SD/MMC)
* size align with a block (512Byte)
*
*************************************************************************/
ENTRY(copy_from_mmcsd)
push{lr}/* save return address */
/* @param_0 channel */
ldrr0, =0
/* @param_1 u32 StartBlkAddress */
ldrr1, =49@ BL1 at block1,BL2 at block49
/* @param_2 u16 blockSize */
ldrr2, =512<<10@ 512kB, BL2 should include dtb file
lsrr2, #9@ r2 >>= 9, as r2/=512
addr2, #1@ r2 += 1
/* @param_3 u32* memoryPtr */
ldrr3, _TEXT_PHY_BASE
/* @param_4 bool with_init */
ldrr4, =0@ no init
push{r4}@ fourth arg at stack
ldrr4, copy_sd_mmc_to_mem
movlr, pc
ldrpc, [r4]
pop{r4, pc}
ENDPROC(copy_from_mmcsd)
3.调用以上函数从指定存储设备加载BL2到ddr2。在arch/arm/cpu/armv7/start.S实现调用过程,具体修改需参考03_boot_from_nand_sd.patch第25行: