2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 移植u-boot v

移植u-boot v

时间:2021-01-22 00:07:20

相关推荐

移植u-boot v

本篇文章阐述移植u-boot v.01S5PV210开发板上的主要流程和细节。市场上的S5PV210开发板,均是基于三星smdkv210公版平台山寨出来的。我使用的GEC210开发板也与公版只数个元器件的差异。所以,若你也用S5PV210类开发板,参考本篇文章,或者直接使用我发布的补丁打到源码上,能帮你解决许多困惑及运行最新的u-boot。

最新更新

[-12-2 15:17:41] 可直接下载我发布到github已经移植好的源码:u-boot-v.01_for_gec210

结果

下载u-boot-.01.tar.bz2,或通过git下载:

$ git clone git://git.denx.de/u-boot.git

$ git checkout v.01该源码要求使用>=6.0版本GCC编译,下载最新编译好的linaro arm交叉编译工具链,选择对应Linux环境的工具链下载并解压,如:我的为32位 ubuntu则选如下标注的文件:

下载我已发布到github的补丁到源码目录:u-boot-v.01_gec210.patch打补丁到源码:$ git apply u-boot-v.01_gec210.patch,如下所示,有警告无影响;由于补丁中含有二进制数据,使用patch命令打补丁将出错。

设置交叉编译工具链前缀:设置u-boot/MakefileCROSS_COMPILE变量为前面解压好的工具链可执行文件的前缀,如:

配置源码为目标板:$ make gec210_defconfig编译:$ make,最终产生u-boot.bin文件

以下阐述移植的过程,由于篇幅有限,重点难点的修改才会作详细的解释,参考上述补丁文件更详尽。开始移植时还需要分析u-boot的流程,可以参考我另一篇博文《u-boot v.01 启动流程分析》。

以下章节中出现的脚本名字有如下关系,每一个章节对应一次git提交,一次对u-boot源码打上所有阶段补丁等效于一次性打上补丁u-boot-v.01_gec210.patch

一、建立新板

1.设置交叉编译工具链,参考上面;

CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-7.2.1-.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_GEC210config SYS_BOARD-default "smdkc100"+default "gec210"config SYS_VENDORdefault "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+endchoiceconfig SYS_SOC@@ -19,5 +23,6 @@ config SYS_SOCsource "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 Lucifer Zhu, LuciferZhu@.** 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.hs5pc110.h文件中定义及引用了当前源码未定义的内容,所以还需做裁剪,具体参考u-boot-v.01_gec210.patch

2.修改lowlevel_init.S以实现SOC级别硬件初始化,包括WATCHDOG,clock,DDR2,uart,nand。第一章已经从smdkc100单板中移植了lowlevel_init.S,其代码流程与S5PV210一致,但各硬件的初始化需重写,需修改函数包括:lowlevel_initsystem_clock_inituart_asm_inittzpc_asm_init,还需添加nand_asm_initmem_ctrl_asm_init(定义于mem_init.S文件),另外引用的宏需在include/configs/gec210.h里定义。这些基础的soc级别初始化均可移植于u-boot-samsung-dev,详细参考补丁:

3.保证lowlevel_init.Smem_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.oobj-$(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.dtbdtb-$(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 的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.ldsindex 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/Makefileindex fe65af4..ddeb488 100755--- a/board/samsung/gec210/Makefile+++ b/board/samsung/gec210/Makefile@@ -12,3 +12,4 @@obj-$(CONFIG_SAMSUNG_ONENAND)+= onenand.oextra-y+= lowlevel_init.oextra-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 filelsrr2, #9@ r2 >>= 9, as r2/=512addr2, #1@ r2 += 1/* @param_3 u32* memoryPtr */ldrr3, _TEXT_PHY_BASE/* @param_4 bool with_init */ldrr4, =0@ no initpush{r4}@ fourth arg at stackldrr4, copy_sd_mmc_to_memmovlr, pcldrpc, [r4]pop{r4, pc}ENDPROC(copy_from_mmcsd)

3.调用以上函数从指定存储设备加载BL2到ddr2。在arch/arm/cpu/armv7/start.S实现调用过程,具体修改需参考03_boot_from_nand_sd.patch第25行:

4.加载完BL2后跳转到DDR2中:

after_copy:ldrpc, =_main@ jump into ddr

5.到此已经跳转到ddr2中_main函数的位置,该函数定义于arch/arm/lib/crt0.S。该函数一开始就将sp定义到了0x2f000000上,而该地址并不在DDR2上,导致后面代码运行出错,如下所示:

修改关联的宏以让sp=0x34700000,修改如下:

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex 61c38ef..adbb872 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -209,7 +207,7 @@/* memtest works on */#define CONFIG_SYS_MEMTEST_STARTCONFIG_SYS_SDRAM_BASE#define CONFIG_SYS_MEMTEST_END(CONFIG_SYS_SDRAM_BASE + 0x5e00000)-#define CONFIG_SYS_LOAD_ADDRCONFIG_SYS_SDRAM_BASE+#define CONFIG_SYS_LOAD_ADDRCONFIG_SYS_TEXT_BASE

参考03_boot_from_nand_sd.patch作其他方面的细致修改。至此,u-boot可以运行起来,并可进入命令行模式如下图所示。从中可看到net驱动初始化失败,接下来作dm9000和nand flash读写的驱动移植。

四、修改dm9000驱动

u-boot v.01源码已经实现了dm9000系列驱动drivers/net/dm9000x.c,我们只需定义寄存器级别的内容就行。

1.设置dm9000的内存地址。由上图知DM9000的片选线CS#接到了S5PV210的CSn1,也就是SROMC_BANK1,而观下图可知访问DM9000的基址是0x88000000,DM9000的CMD接到了地址线ADDR2,所以访问DM9000数据的地址为0x88000000+2x4Byte

include/configs/gec210.h中定义被drivers/net/dm9000x.c驱动引用到的宏:

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex 843eba2..f66ecb5 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -24,6 +24,7 @@#endif#include <asm/arch/cpu.h> /* get chip and board defs */+#include <asm/arch/s5pc110.h>#define CONFIG_ARCH_CPU_INIT@@ -256,8 +262,13 @@/** Ethernet Contoller driver*/+#define CONFIG_DRIVER_DM9000 1+#define CONFIG_DM9000_BASE (0x88000000)+#define DM9000_IO (CONFIG_DM9000_BASE)+#define DM9000_DATA(CONFIG_DM9000_BASE+8)+#ifdef CONFIG_CMD_NET-#define CONFIG_ENV_SROM_BANK 3 /* Select SROM Bank-3 for Ethernet*/+#define CONFIG_ENV_SROM_BANK 1 /* Select SROM Bank-1 for Ethernet*/#endif /* CONFIG_CMD_NET */#endif /* __CONFIG_H */

2.添加SROM控制器和dm9000设备驱动初始化的代码。板级设备驱动初始化代码board/samsung/gec210/gec210.c中只存在网卡smc9115的驱动初始化代码,需要将其注释掉且添加进dm9000驱动初始化相关的代码:

diff --git a/board/samsung/gec210/gec210.c b/board/samsung/gec210/gec210.cindex 8011259..f5a6249 100755--- a/board/samsung/gec210/gec210.c+++ b/board/samsung/gec210/gec210.c@@ -18,6 +18,7 @@ DECLARE_GLOBAL_DATA_PTR;/** Miscellaneous platform dependent initialisations*/+#ifdef CONFIG_SMC911Xstatic void smc9115_pre_init(void){u32 smc_bw_conf, smc_bc_conf;@@ -34,11 +35,34 @@ static void smc9115_pre_init(void)/* Select and configure the SROMC bank */s5p_config_sromc(CONFIG_ENV_SROM_BANK, smc_bw_conf, smc_bc_conf);}+#endif++#ifdef CONFIG_DRIVER_DM9000+static void dm9000_pre_init(void)+{+ unsigned int tmp;++ /* DM9000 on SROM BANK1, 16 bit */+ SROM_BW_REG &= ~(0xf << 4);+ SROM_BW_REG |= (0x1 << 4);+ SROM_BC1_REG = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0));+ /* Set MP01_1 as SROM_CSn[1] */+ tmp = MP01CON_REG;+ tmp &=~(0xf<<4);+ tmp |=(2<<4);+ MP01CON_REG = tmp;+}+#endifint board_init(void){+#ifdef CONFIG_SMC911Xsmc9115_pre_init();+#endif+#ifdef CONFIG_DRIVER_DM9000+ dm9000_pre_init();+#endifgd->bd->bi_arch_number = MACH_TYPE_SMDKC110;gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;@@ -75,8 +99,13 @@int board_eth_init(bd_t *bis){int rc = 0;+#ifdef CONFIG_SMC911Xrc = smc911x_initialize(0, CONFIG_SMC911X_BASE);#endif++#ifdef CONFIG_DRIVER_DM9000+ rc = dm9000_initialize(bis);+#endifreturn rc;}

3.配置关闭smc9115网卡相关的代码。GEC210板不像SMDKC100那样搭载了smc9115网卡,所以通过$ make menuconfig关闭该网卡的配置,菜单-> Device Drivers -> Network device support -> [ ] SMSC LAN911x and LAN921x controller driver取消选择:

4.定义网络相关的环境变量。在默认环境变量集(include/env_default.h)中定义了数个与网络参数相关的变量如下图:

我们需要在include/configs/gec210.h中定义其值:

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex 843eba2..f66ecb5 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -118,6 +119,11 @@"ubiblock=4\0" \"ubi=enabled"+#define CONFIG_NETMASK 255.255.255.0+#define CONFIG_IPADDR192.168.1.48+#define CONFIG_SERVERIP 192.168.1.46+#define CONFIG_GATEWAYIP 192.168.1.1

另外我们没有定义网卡的MAC地址,但u-boot中提供生成随机MAC地址的功能,需要配置菜单开启:-*- Networking support ---> [*] Random ethaddr if unset

现在我们可以通过TFTP命令tftp 0x40000000 uImage.bin来下载网络服务器中的文件。

五、移植nand flash驱动

移植nand的驱动目的是使u-boot支持向nand烧写uboot.bin,uImage以及文件系统等。u-boot v.01对于存储设备驱动的实现是移植了kernel的mtd层次结构,所以对于nand flash的驱动实现,我们只需实现并填充struct nand_chip的成员就行。

1.移植u-boot-samsung-dev/cpu/s5pc11x/nand.c驱动。执行$ cp xxx/u-boot-samsung-dev/cpu/s5pc11x/nand.c drivers/mtd/nand/s5p_nand.c;u-boot v.01与1.3.4版本的MTD相比,部分结构体增减了结构体的成员,所以针对该差异修改nand驱动代码,参考s5p_nand.patch了解全部细节。其中由于两版本结构体nand_flash_dev参考如下图,老版本的成员id为nand的设备id,而新版本的中表示设备id的成员是dev_id,没注意到这个差异的话,将导致在初始化中识别到错误的nand型号,进而读取操作nand时出错。

所以,移植时需要做对应的修改:

--- ../u-boot-samsung-dev/cpu/s5pc11x/nand.c-03-21 15:15:23.000000000 +0800+++ drivers/mtd/nand/s5p_nand.c-06-06 22:05:44.121795642 +0800@@ -1012,20 +994,23 @@tmp = readb(nand->IO_ADDR_R); /* Device ID */for (i = 0; nand_flash_ids[i].name != NULL; i++) {-if (tmp == nand_flash_ids[i].id) {+if (tmp == nand_flash_ids[i].dev_id) {type = &nand_flash_ids[i];break;}}

2.移植lowlevel_init.S中nand控制器初始化的代码。由于我们要启用nand控制器的硬件ecc功能,所以nand控制器初始化时也需要做相应的设置,作如下所示修改,具体参考04_05_nand_dm9000_drv.patch第101行。

3.屏蔽掉nand id表中dev_id与GEC210上所搭载nand(K9K8G08U1A)相同但并不兼容的设备。由于nand初始化过程中,会根据从nand读回来的dev_idnand_flash_ids[]中遍历找到第一个对应设备,所以"TC58NVG3S0F 8G 3.3V 8-bit"会首先被匹配到,但它各项属性并不兼容当前板的flash,使用其中的属性将会运行出错,所以需要将其注释掉:

diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.cindex 4009d64..af83901 100755--- a/drivers/mtd/nand/nand_ids.c+++ b/drivers/mtd/nand/nand_ids.cstruct nand_flash_dev nand_flash_ids[] = {@@ -49,9 +49,11 @@{"TC58NVG2S0H 4G 3.3V 8-bit",{ .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} },SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) },+#if 0/* ignore this incompatible NAND chips */{"TC58NVG3S0F 8G 3.3V 8-bit",{ .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },+#endif{"TC58NVG5D2 32G 3.3V 8-bit",{ .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },

4.修改MakefileKconfig以添加编译s5p_nand.c文件的菜单配置选项。

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfigindex 78a39ab..077fc5f 100755--- a/drivers/mtd/nand/Kconfig+++ b/drivers/mtd/nand/Kconfig@@ -160,6 +160,24 @@This flag prevent U-boot reconfigure NAND flash controller and reusethe NAND timing from 1st stage bootloader.+config NAND_S5P+bool "Support for Samsung S5PV210 Nand controller"+imply CMD_NAND+help+ This enables Nand driver support for Nand flash controller+ on Samsung S5P1XX SoC.++config S5P_NAND_HWECC+bool "Enable use of S5P1XX nand flash controller's hardware ecc"+depends on NAND_S5P++config NAND_BL1_8BIT_ECC+bool "Enable write bootloader stage 1 in nand flash with 8-bit ecc"+depends on NAND_S5P+help+ Soc s5pc11x's BL0 require BL1 which located in block 0 on nand to carry+ with 8-bit ecc, otherwise it will be failed when boot the BL1 in nand.+comment "Generic NAND options"# Enhance depends when converting drivers to Kconfig which use this configdiff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefileindex 9f7d9d6..43efb21 100755--- a/drivers/mtd/nand/Makefile+++ b/drivers/mtd/nand/Makefile@@ -66,6 +66,7 @@obj-$(CONFIG_NAND_PLAT) += nand_plat.oobj-$(CONFIG_NAND_SUNXI) += sunxi_nand.oobj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o+obj-$(CONFIG_NAND_S5P) += s5p_nand.oelse # minimal SPL drivers

5.配置菜单开启nand驱动功能。选择菜单Device Drivers ---> [*] NAND Device Support --->中的如下选项:

另外开启nand相关的命令功能:Command line interface ---> Device access commands ---> [*] nand

6.支持烧写u-boot.bin到nand中。CPU S5PV210要求BL1头部附带16Byte的信息,用以表示BL1的大小及其校验和如下图所示;我们在第一章中已经设定了u-boot镜像偏移地址0x0处为0x2000即8KB,即表示BL1 size为8KB;而偏移地址0x8处填了0x0,通过当前移植状态的nand驱动,将u-boot.bin烧写进nand的block0处(使用命令nand write 0x40000000 0 0x80000),u-boot是启动不起来的。由下图BL0启动流程可知,u-boot.bin偏移地址0x8处应填充u-boot.bin前8KB内容的校验和checksum,使得iROM内的BL0在对BL1进行校验和时检测成功,才可以执行u-boot;否则将尝试其他启动方式最终启动失败。

烧写u-boot.bin前计算校验和并填充到0x8偏移地址处。校验和的填充不像BL1 size那样在代码编写时就确定,需要在生成u-boot.bin后才可以确定。所以,在命令nand write addr 0 0x80000执行流程上添加计算校验和及修改u-boot.bin之0x8偏移地址处内容:

diff --git a/cmd/nand.c b/cmd/nand.cindex a22945d..234a7b7 100755--- a/cmd/nand.c+++ b/cmd/nand.c@@ -1,4 +1,4 @@-/*+/** Driver for NAND support, Rick Bronson* borrowed heavily from:* (c) 1999 Machine Vision Holdings, Inc.@@ -387,6 +387,11 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])int dev = nand_curr_device;int repeat = flag & CMD_FLAG_REPEAT;+#if defined(CONFIG_S5PC110) && !defined(CONFIG_FUSED) && !defined(CONFIG_SECURE)+ulong checksum;+uint8_t *ptr;+#endif+/* at least two arguments please */if (argc < 2)goto usage;@@ -611,11 +616,23 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])ret = nand_read_skip_bad(mtd, off, &rwsize,NULL, maxsize,(u_char *)addr);-else+else {+#if defined(CONFIG_S5PC110) && !defined(CONFIG_FUSED) && !defined(CONFIG_SECURE)+if (off == 0) {+ptr = (u_char *)(addr + 16);+for(i = 16, checksum = 0; i < COPY_BL1_SIZE; i++) {+checksum += *ptr;+ptr++;+}+*((volatile u32 *)(addr + 0x8)) = checksum;+pr_info("BL1's checksum is calculated.\n");+}+#endifret = nand_write_skip_bad(mtd, off, &rwsize,NULL, maxsize,(u_char *)addr,WITH_WR_VERIFY);+}#ifdef CONFIG_CMD_NAND_TRIMFFS} else if (!strcmp(s, ".trimffs")) {if (read) {

烧写和读取nand上block0的数据需作8bit ecc。GEC210单板搭载的nand flash的oob大小为64Byte,由文件《S5PV210_iROM_ApplicationNote_Preliminary_1126.pdf》可知,烧写进nand中的BL1需作8bit ecc如下图所示,而其他区域没有要求则默认为1bit ecc。在烧写和读nand数据的流程中添加条件判断是否操作block0的内容,是则直接调用s5p_nand.c硬件驱动中的s3c_nand_read_page_8bit()或者s3c_nand_write_page_8bit()

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.cindex eb9f121..5383cd5 100755--- a/drivers/mtd/nand/nand_base.c+++ b/drivers/mtd/nand/nand_base.c@@ -1,4 +1,4 @@-/*+/** Overview:* This is the generic MTD driver for NAND flash devices. It should be* capable of working with almost all NAND chips currently available.@@ -353,6 +353,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs)ofs += mtd->erasesize - mtd->writesize;page = (int)(ofs >> chip->page_shift) & chip->pagemask;++#if defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S5PC110)+if (page < CFG_NAND_PAGES_IN_BLOCK)+return 0;+#endifdo {if (chip->options & NAND_BUSWIDTH_16) {@@ -1677,6 +1682,9 @@ static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)return chip->setup_read_retry(mtd, retry_mode);}+extern int s3c_nand_read_page_8bit(struct mtd_info *mtd, struct nand_chip *chip,+uint8_t *buf);+/*** nand_do_read_ops - [INTERN] Read data with ECC* @mtd: MTD device structure@@ -1744,18 +1752,26 @@ read_retry:* Now read the page into the buffer. Absent an error,* the read methods return max bitflips per ecc step.*/-if (unlikely(ops->mode == MTD_OPS_RAW))-ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,-oob_required,-page);-else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&- !oob)-ret = chip->ecc.read_subpage(mtd, chip,-col, bytes, bufpoi,-page);-else-ret = chip->ecc.read_page(mtd, chip, bufpoi,- oob_required, page);+#if defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S5PC110)+if (page < CFG_NAND_PAGES_IN_BLOCK) {+ret = s3c_nand_read_page_8bit(mtd, chip, bufpoi);+} else+#endif+{+if (unlikely(ops->mode == MTD_OPS_RAW))+ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,+oob_required,+page);+else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&+ !oob)+ret = chip->ecc.read_subpage(mtd, chip,+col, bytes, bufpoi,+page);+else+ret = chip->ecc.read_page(mtd, chip, bufpoi,+ oob_required, page);+}+if (ret < 0) {if (use_bufpoi)/* Invalidate page cache */@@ -2404,6 +2420,9 @@ static int nand_write_page_syndrome(struct mtd_info *mtd,return 0;}+ +extern int s3c_nand_write_page_8bit(struct mtd_info *mtd, struct nand_chip *chip,+const uint8_t *buf);/*** nand_write_page - [REPLACEABLE] write one page@@ -2431,15 +2450,23 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,if (nand_standard_page_accessors(&chip->ecc))chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);-if (unlikely(raw))-status = chip->ecc.write_page_raw(mtd, chip, buf,- oob_required, page);-else if (subpage)-status = chip->ecc.write_subpage(mtd, chip, offset, data_len,- buf, oob_required, page);-else-status = chip->ecc.write_page(mtd, chip, buf, oob_required,-page);+#if defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S5PC110)+if (page < CFG_NAND_PAGES_IN_BLOCK) {+memset(chip->oob_poi, 0xff, mtd->oobsize);+status = s3c_nand_write_page_8bit(mtd, chip, buf);+} else+#endif+{+if (unlikely(raw))+status = chip->ecc.write_page_raw(mtd, chip, buf,+ oob_required, page);+else if (subpage)+status = chip->ecc.write_subpage(mtd, chip, offset, data_len,+ buf, oob_required, page);+else+status = chip->ecc.write_page(mtd, chip, buf, oob_required,+page);+}if (status < 0)return status;

至此,我们已经可以通过命令nand write/read来有效烧写u-boot.bin和uImage.bin。

六、修改以引导kernel启动

到当前为止,引导kernel启动之前必须的驱动及移植已经完成,现需要引导启动kernel,主要是修改环境变量bootcmd相关定义。另外还需通过配置菜单裁剪u-boot,减小尺寸。本章节所有修改细节参考补丁06_bootkernel.patch

1.设置环境变量bootcmd。如下图,从default_environment[]得知,通过定义CONFIG_BOOTCOMMAND来设置环境变量bootcmd的值。

include/configs/gec210.h中定义和修改CONFIG_BOOTCOMMAND相关的值如下中的run bootk

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex b95a833..62daaff 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -1,4 +1,4 @@-/*+/*@@ -63,30 +65,30 @@#define CONFIG_MTD_DEVICE#define CONFIG_MTD_PARTITIONS-#define CONFIG_BOOTCOMMAND"run ubifsboot"+#define CONFIG_BOOTCOMMAND"run bootk"#define CONFIG_RAMDISK_BOOT"root=/dev/ram0 rw rootfstype=ext2" \" console=ttySAC0,115200n8" \-" mem=128M"+" mem=512M"#define CONFIG_COMMON_BOOT"console=ttySAC0,115200n8" \-" mem=128M " \+" mem=512M " \" " CONFIG_MTDPARTS_DEFAULT-#define CONFIG_UPDATEB"updateb=onenand erase 0x0 0x40000;" \-" onenand write 0x3000 0x0 0x40000\0"+#define CONFIG_UPDATEB"updateb=nand erase.part boot;" \+"nand write 0x40000000 boot\0"#define CONFIG_ENV_OVERWRITE#define CONFIG_EXTRA_ENV_SETTINGS\CONFIG_UPDATEB \"updatek=" \-"onenand erase 0x60000 0x300000;" \-"onenand write 0x31008000 0x60000 0x300000\0" \+"nand erase.part kernel;" \+"nand write 0x40000000 kernel\0" \"updateu=" \"onenand erase block 147-4095;" \"onenand write 0x32000000 0x1260000 0x8C0000\0" \"bootk=" \-"onenand read 0x30007FC0 0x60000 0x300000;" \+"nand read 0x30007FC0 kernel;" \"bootm 0x30007FC0\0" \"flashboot=" \"set bootargs root=/dev/mtdblock${bootblock} " \

而环境变量bootk改为"nand read 0x30007FC0 kernel;bootm 0x30007FC0"。指示将uImage加载到地址0x30007FC0并启动之,该地址的确定需结合编译出来的uImage和u-boot流程来分析。u-boot加载启动kernel流程中的bootm_load_os(),进行了解压os数据或移动到images->os.load指定的地址,如下图所示。从流程中得知os数据用image->os.image_start表示(uboot 1.3.4中的image_start表示整个uImage的起始地址),有关系:image->os.image_start=image->os.start+header大小(64B);而images->os.load从uImage的头部信息中得到,即编译uImage输出log中的Load Address: xxxxxxxx。然后u-boot要求images->os.load等于image->os.image_start,意味kernel数据需加载到images->os.load地址,进而要求uImage的Load Address等于Entry Point

综上所述有0x30008000=Load Address=Entry Point=images->os.load=image->os.image_start=image->os.start+64B;即整个uImage需加载到image->os.start=0x30008000-64=0x30007FC0。所以与u-boot 1.3.4不同的是,编译完uImage后不需要更改Load AddressEntry Point即可直接烧写进nand。

2.设置启动参数和机器码。启动参数和机器码在uboot跳转到kernel时,需保存到寄存器R2和R1上。在配置菜单中选中[*] Enable boot arguments并编辑启动参数为:root=/dev/mtdblock4 rootfstype=yaffs console=ttySAC0,115200n8 mem=512M mtdparts=s5p-nand:1m(boot),5m@0x100000(recovery),5m@0x600000(kernel),3m@0xb00000(ramdisk),-(rootfs)如下图;告知kernel:根文件系统位于分区四,类型是yaffs,串口0作为控制台,DDR2空间为512MB,nand的分区表。

在文件include/configs/gec210.h中定义机器码,宏CONFIG_MACH_TYPE在函数setup_machine()中用于设置gd->bd->bi_arch_number,并最终在启动kernel前保存到R1,另外往后的流程中函数board_init()又设置了gd->bd->bi_arch_number,需将对应操作注释掉:

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex b95a833..62daaff 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -22,6 +22,8 @@#if 0#define CONFIG_GEC2101/* working with GEC210 */#endif+#define CONFIG_MACH_TYPEMACH_TYPE_SMDKV210+#include <asm/arch/cpu.h>/* get chip and board defs */#include <asm/arch/s5pc110.h>diff --git a/board/samsung/gec210/gec210.c b/board/samsung/gec210/gec210.cindex f5a6249..57e38c9 100755--- a/board/samsung/gec210/gec210.c+++ b/board/samsung/gec210/gec210.c@@ -63,7 +63,8 @@ int board_init(void)#ifdef CONFIG_DRIVER_DM9000dm9000_pre_init();#endif-gd->bd->bi_arch_number = MACH_TYPE_SMDKC110;+/* bi_arch_number has set in setup_machine(). */+/* gd->bd->bi_arch_number = MACH_TYPE_SMDKC110; */gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;return 0;

3.规划和设置nand分区。nand分区表最好与kernel中mtd设备驱动设置的分区一致。nand分区图如下:

菜单配置Command line interface ---> Filesystem commands ---> [*] MTD partition support分区表设为"mtdparts=s5p-nand:1m(boot),5m@0x100000(recovery),5m@0x600000(kernel),3m@0xb00000(ramdisk),-(rootfs)"

修改保存到nand中环境变量env数据的起始地址及大小:

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex b95a833..62daaff 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -246,8 +248,8 @@#define BOOT_SEC_DEV0x5#define CONFIG_ENV_SIZE(128 << 10)/* 128KiB, 0x20000 */-#define CONFIG_ENV_ADDR(256 << 10)/* 256KiB, 0x40000 */-#define CONFIG_ENV_OFFSET(256 << 10)/* 256KiB, 0x40000 */+#define CONFIG_ENV_ADDR(512 << 10)/* 512KiB, 0x80000 */+#define CONFIG_ENV_OFFSET(512 << 10)/* 512KiB, 0x80000 *//* nand copy size from nand to DRAM.*/#defineCOPY_BL1_SIZE(8 << 10)/* for irom's BL0 copy */

由于没有ramdisk相关的内容,还需要关闭引导启动kernel流程中与ramdisk有关的代码,否则会导致启动kernel失败:

diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.hindex 9f17829..c5d7658 100755--- a/arch/arm/include/asm/config.h+++ b/arch/arm/include/asm/config.h@@ -8,7 +8,7 @@#define _ASM_CONFIG_H_#define CONFIG_LMB-#define CONFIG_SYS_BOOT_RAMDISK_HIGH+/* #define CONFIG_SYS_BOOT_RAMDISK_HIGH */#if defined(CONFIG_ARCH_LS1021A) || \defined(CONFIG_CPU_PXA27X) || \

4.在第二章的底层初始化中uart_asm_init将作为控制台的uart初始化为fifo模式,linux 2.6启动流程中会调用putc函数作打印动作如下图所示,若uart为fifo模式则会执行图中if流程。圈内的fifo_max为全局变量,在该版本的内核中其未被初始化(即值被默认设为0),导致level < fifo_max条件永远不能成立,则导致kernel在初始化启动流程中调用putc函数时陷入死循环。所以需添加代码初始化这样的全局变量:

diff --git a/arch/arm/mach-s5pv210/include/mach/uncompress.h b/arch/arm/mach-s5pv210/include/mach/uncompress.hindex 08ff2fd..76db538 100755--- a/arch/arm/mach-s5pv210/include/mach/uncompress.h+++ b/arch/arm/mach-s5pv210/include/mach/uncompress.h@@ -19,6 +19,8 @@static void arch_detect_cpu(void){/* we do not need to do any cpu detection here at the moment. */+ fifo_mask = S5PV210_UFSTAT_TXMASK;+ fifo_max = 255 << S5PV210_UFSTAT_TXSHIFT;}#endif /* __ASM_ARCH_UNCOMPRESS_H */

到此为止,可以成功启动kernel输出log:

七、支持yaffs2烧写nand

目前为止,u-boot已经实现了其主要的工作——引导启动kernel,kernel启动流程中会加载根文件系统,若nand中rootfs分区中未有根文件系统则启动失败;所以我们还需要令u-boot支持根文件系统的烧写,u-boot v默认支持烧写jffs2格式的根文件系统)(# nand write.jffs2 addr off size),尚未支持烧写yaffs2格式根文件系统。本章节实现烧写yaffs2根文件系统,参考07_yaffs_fuse.patch了解全部细节;大致思路是,参考nand write.jffs2流程,在流程中添加yaffs实例化相关的代码,最终实现命令# nand write.yaffs2 addr off size

1.定义宏CONFIG_CMD_NAND_YAFFS。由于我们是在已有的流程中添加针对yaffs2相关的代码,那为了方便功能的开关,使用宏CONFIG_CMD_NAND_YAFFS将相关的代码框起来。由于宏定义CONFIG_CMD_NAND_YAFFS并不存在于配置宏白名单scripts/config_whitelist.txt中,如直接在include/configs/gec210.h重定义在编译时将报错。所以我们在Kconfig在添加该宏,且可以在配置菜单Command line interface -> Device access commands -> [*] nand -> [*] nand write.yaffs2中开关:

diff --git a/cmd/Kconfig b/cmd/Kconfigindex c033223..f2883cc 100755--- a/cmd/Kconfig+++ b/cmd/Kconfig@@ -774,6 +774,12 @@ config CMD_NAND_TRIMFFShelpAllows one to skip empty pages when flashing something on a NAND.+config CMD_NAND_YAFFS+bool "nand write.yaffs2"+default y+help+ Allows one to misalign write pages when flashing something on a NAND.+config CMD_NAND_LOCK_UNLOCKbool "nand lock/unlock"help

2.添加识别命令nand write.yaffs2的代码和命令帮助信息。同.jffs2命令同样需调用nand_write_skip_bad函数作底层的nand烧写动作,带入WITH_YAFFS_OOB参数用于区别不同的格式,因此还要定义WITH_YAFFS_OOB

diff --git a/cmd/nand.c b/cmd/nand.cindex 234a7b7..65d3da4 100755--- a/cmd/nand.c+++ b/cmd/nand.c@@ -643,6 +643,16 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])maxsize, (u_char *)addr,WITH_DROP_FFS | WITH_WR_VERIFY);#endif+#ifdef CONFIG_CMD_NAND_YAFFS+} else if (!strcmp(s, ".yaffs2")) {+if (read) {+printf("Unknown nand command suffix '%s'\n", s);+return 1;+}+ret = nand_write_skip_bad(mtd, off, &rwsize, NULL,+maxsize, (u_char *)addr,+WITH_YAFFS_OOB);+#endif} else if (!strcmp(s, ".oob")) {/* out-of-band data */mtd_oob_ops_t ops = {@@ -820,6 +830,11 @@ static char nand_help_text[] =" 'addr', skipping bad blocks and dropping any pages at the end\n"" of eraseblocks that contain only 0xFF\n"#endif+#ifdef CONFIG_CMD_NAND_YAFFS+"nand write.yaffs2 - addr off|partition size\n"+" write ‘size‘ bytes starting at offset ‘off‘ with yaffs format\n"+" from memory address ‘addr‘, skipping bad blocks.\n"+#endif"nand erase[.spread] [clean] off size - erase 'size' bytes ""from offset 'off'\n"" With '.spread', erase enough for given file size, otherwise,\n"

diff --git a/include/nand.h b/include/nand.hindex cead563..40ad5bf 100755--- a/include/nand.h+++ b/include/nand.h@@ -1,1 +1,1 @@-/*+/*@@ -103,6 +103,7 @@ int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,#define WITH_DROP_FFS(1 << 0) /* drop trailing all-0xff pages */#define WITH_WR_VERIFY(1 << 1) /* verify data was written correctly */+#define WITH_YAFFS_OOB(1 << 2)int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,size_t *actual, loff_t lim, u_char *buffer, int flags);

3.写nand流程中添加yaffs2相关的代码:

diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.cindex 9c8a373..1e94f23 100755--- a/drivers/mtd/nand/nand_util.c+++ b/drivers/mtd/nand/nand_util.c@@ -581,7 +581,22 @@ int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,if (actual)*actual = 0;-blocksize = mtd->erasesize;+#ifdef CONFIG_CMD_NAND_YAFFS+if (flags & WITH_YAFFS_OOB) {+if (flags & ~WITH_YAFFS_OOB)+return -EINVAL;++int pages;+pages = mtd->erasesize / mtd->writesize;+blocksize = (pages * mtd->oobsize) + mtd->erasesize;+if (*length % (mtd->writesize + mtd->oobsize)) {+printf ("Attempt to write incomplete page"+" in yaffs mode\n");+return -EINVAL;+}+} else+#endif+blocksize = mtd->erasesize;/** nand_write() handles unaligned, partial page writes.@@ -617,7 +632,7 @@ int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,return -EFBIG;}-if (!need_skip && !(flags & WITH_DROP_FFS)) {+if (!need_skip && !(flags & WITH_DROP_FFS) && !(flags & WITH_YAFFS_OOB)) {rval = nand_write(mtd, offset, length, buffer);if ((flags & WITH_WR_VERIFY) && !rval)@@ -650,22 +665,52 @@ int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length,elsewrite_size = blocksize - block_offset;-truncated_write_size = write_size;+#ifdef CONFIG_CMD_NAND_YAFFS+if (flags & WITH_YAFFS_OOB) {+int page, pages;+size_t pagesize = mtd->writesize;+size_t pagesize_oob = pagesize + mtd->oobsize;+struct mtd_oob_ops ops;++ops.len = pagesize;+ops.ooblen = mtd->oobsize;+ops.mode = MTD_OPS_AUTO_OOB;+ops.ooboffs = 0;++pages = write_size / pagesize_oob;+for (page = 0; page < pages; page++) {+WATCHDOG_RESET();++ops.datbuf = p_buffer;+ops.oobbuf = ops.datbuf + pagesize;++rval = mtd->_write_oob(mtd, offset, &ops);+if (rval != 0)+break;++offset += pagesize;+p_buffer += pagesize_oob;+}+} else+#endif+{+truncated_write_size = write_size;#ifdef CONFIG_CMD_NAND_TRIMFFS-if (flags & WITH_DROP_FFS)-truncated_write_size = drop_ffs(mtd, p_buffer,-&write_size);+if (flags & WITH_DROP_FFS)+truncated_write_size = drop_ffs(mtd, p_buffer,+&write_size);#endif-rval = nand_write(mtd, offset, &truncated_write_size,-p_buffer);+rval = nand_write(mtd, offset, &truncated_write_size,+p_buffer);-if ((flags & WITH_WR_VERIFY) && !rval)-rval = nand_verify(mtd, offset,-truncated_write_size, p_buffer);+if ((flags & WITH_WR_VERIFY) && !rval)+rval = nand_verify(mtd, offset,+truncated_write_size, p_buffer);-offset += write_size;-p_buffer += write_size;+offset += write_size;+p_buffer += write_size;+}if (rval != 0) {printf("NAND write to offset %llx failed %d\n",

经过本章节的操作,可直接通过命令# nand write.yaffs2 addr off size来烧写yaffs2格式的根文件系统,从而成功启动kernel。

八、移植LCD驱动并作控制台

前几张章节已经完成了u-boot的基本移植,本章操作额外增强了u-boot功能,最终目的是在LCD上定制显示LOGO,另外将LCD作为第二个输出控制台以显示启动过程中的log。本章移植的全部细节参考08_support_LCD.patch

1.LCD控制器初始化。在初始化启动流程中的stdio_add_devices()调用了drv_lcd_init()(依赖宏CONFIG_LCD);因此,通过实现drv_lcd_init()来初始化LCD相关资源,且需定义CONFIG_LCD。创建文件drivers/video/s5p_fb.c实现LCD控制器初始化函数LCD_Initialize_AT070TN90();并在drv_lcd_init()中调用它如下代码;另外需特别注意的是在drv_lcd_init()中需调用lcd_set_flush_dcache(1);使得每次操作完显存对应的内存地址,就调用flush_dcache_range()来回写dcache的内容,从而保持DMA一致性;否则将出现显示混乱、花屏等现象。

而结构体实例panel_info在lcd驱动通用层(common/lcd.c)中被引用来唯一确定LCD显示屏的分辨率和像素位数:

/** Copyright (c) Samsung Electronics Co., Ltd.* /** S5PC110 - LCD Driver for U-Boot** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.*/#include <common.h>#include <asm/io.h>#include <asm/types.h>#include <lcd.h>#include <asm/arch/s5pc110.h>#define LCD_BGCOLOR0x0//0x1428A0#define Inp32(_addr)readl(_addr)#define Outp32(addr, data)(*(volatile u32 *)(addr) = (data))#define Delay(_a)udelay(_a*1000)#if defined(CONFIG_LCD_AT070TN90)static void *fb_base;/* Start of framebuffer memory*/vidinfo_t panel_info = {.vl_col = 800,/* Number of columns (i.e. 160) */.vl_row = 480,/* Number of rows (i.e. 100) */.vl_bpix = LCD_BPP,/* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */} ;static void LCD_Initialize_AT070TN90(void *lcdbase){/* 1.配置引脚* LCD_HSYNC LCD_VSYNC LCD_VDEN LCD_VCLK* LCD_VD[0] LCD_VD[1] LCD_VD[2] LCD_VD[3]*/Outp32(GPF0CON, 0x22222222);/* 2.配置引脚* LCD_VD[4] LCD_VD[5] LCD_VD[6] LCD_VD[7]* LCD_VD[8] LCD_VD[9] LCD_VD[10] LCD_VD[11]*/Outp32(GPF1CON, 0x22222222);/* 3.配置引脚LCD_VD[12] LCD_VD[13] LCD_VD[14] LCD_VD[15]LCD_VD[16] LCD_VD[17] LCD_VD[18] LCD_VD[19] */Outp32(GPF2CON, 0x22222222);/* 4.配置引脚LCD_VD[20] LCD_VD[21] LCD_VD[22] LCD_VD[23]*/ Outp32(GPF3CON, Inp32(GPF3CON) & (~((0xF<<12)|(0xF<<8)|(0xF<<4)|(0xF<<0))));Outp32(GPF3CON, Inp32(GPF3CON) | ((0x2<<12)|(0x2<<8)|(0x2<<4)|(0x2<<0)));/* 5.VIDCON0Note:ENVID and ENVID_F are set to “1”[0]:1 Display On必须置1[1]:1 Display On必须置1[4]:1 因为显示的时钟需要用到33.3MHz的频率,那么要进行分频[6]:4 显示主区域的HCLK时钟为166MHz,为了得到33.3MHz左右的频率,当前的值要设置为4[18]:0 因为我们当前是RGB并行接口,意思就是说一次发送3个字节,什么是串行接口,3个字节分3次来发送[26]:0 配置为RGB接口*/Outp32(ELFIN_LCD_BASE, (0<<26)|(0<<18)|(4<<6)|(1<<4)|(1<<1)|(1<<0));/* 6.VIDCON1,通过观看S70-AT070TN92(GEC210).pdf中的13页发现VSYNC和HSYNC信号发现与210手册的1207页极性相反,需要进行配置[5]:1 VSYNC极性取反[6]:1 HSYNC极性取反*/Outp32( ELFIN_LCD_BASE+0x4, (1<<6)|(1<<5));/* 7.配置rVIDTCON0,这部分要查看S70-AT070TN92(GEC210).pdf中的14页中3.3.3Timing[7:0]:9+1VSPW垂直同步信号宽度,这是VSYNC同步信号的高电平持续时间[8:15]:21+1VFPD[16:23]:12+1 VBPD*/Outp32(ELFIN_LCD_BASE+0x10, (12<<16)|(21<<8)|(9<<0));/* 8.配置rVIDTCON1,这部分要查看S70-AT070TN92(GEC210).pdf中的14页中3.3.3 Timing[7:0]:19+1 HSPW水平同步信号宽度,这是VSYNC同步信号的高电平持续时间[8:15]:209+1 HFPD[16:23]:25+1 HBPD*/Outp32(ELFIN_LCD_BASE+0x14, (25<<16)|(209<<8)|(19<<0));/* 9.配置rVIDTCON2,这个要看LCD的分辨率,800x480[10:0]:799+1 一行有多少个像素点[11:21]:479+1 有多少行*/Outp32(ELFIN_LCD_BASE+0x18, (479<<11)|(799<<0));/* 10.配置rWINCON0[0]:1使能视频输出[5:2]:1011 显示格式是24位色,R:8 G:8 B:8[15]:1 发现EN_LOCAL=0,因为我们待会使用显存即DMA,使能字交换即每次DMA传输数据最小单元为字传输[22]:0使用DMA(直接内存访问:直接向某一地址写数据的时候会自动操作硬件,不需要CPU进行干预)*/Outp32(ELFIN_LCD_BASE+0x20, (1<<15)|(0xB<<2)|(1<<0));/* 11.配置rVIDW00ADD0B0,用于设置显示缓存的起始地址*/Outp32(ELFIN_LCD_BASE+0xA0, (u32)lcdbase);/* 12.rVIDW00ADD1B0,用于配置显示缓存的结束地址,告诉CPU我要占用多大的空间公式如下:VBASEL = VBASEU +(PAGEWIDTH+OFFSIZE) x (LINEVAL+1)= 0x48000000+(800+0)x(479+1)x4800x480*4[A:R:G:B]*/Outp32(ELFIN_LCD_BASE+0xD0, ((u32)lcdbase)+800*4*480);/* 13.rVIDW00ADD2:用于配置窗口的偏移值还有一行占用多少字节[12:0] : 800*4 因为Linux显示是32位色,为了兼容以后的Linux驱动部分,增加它的空间字对齐[13:25] : 因为当前显示不需要偏移,设置为0就可以了。*/Outp32(ELFIN_LCD_BASE+0x100, (0<<13)|((800*4)<<0));/* 14.rSHADOWCON 使能Channel 0[0]:1 */Outp32(ELFIN_LCD_BASE+0x34, Inp32(ELFIN_LCD_BASE+0x34) | (1<<0));/* 15.rVIDOSD0A 配置显示区域的左上角x/y坐标值[10:0] :0 左上角的Y坐标值[21:11]:0 左上角的X坐标值*/Outp32(ELFIN_LCD_BASE+0x40, (0<<11)|(0<<0));/* 16.rVIDOSD0B 配置显示区域的右下角x/y坐标值[10:0] :479 右下角的Y坐标值[21:11]:799 右下角的X坐标值*/Outp32(ELFIN_LCD_BASE+0x44, (799<<11)|(479<<0));/* 17.rVIDOSD0C 配置窗口的大小也就是窗口的分辨率[23:0] :800*480 For example, Height * Width*/Outp32(ELFIN_LCD_BASE+0x48, 800*480);/* 18.配置FIMD一定要为RGB接口*/Outp32(0xe0107008, 2<<0);}void lcd_ctrl_init(void *lcdbase){fb_base = lcdbase;LCD_Initialize_AT070TN90(lcdbase);/* Enable flushing if we enabled dcache for staying dma coherent */lcd_set_flush_dcache(1);}void lcd_enable (void){return;}void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue){return;}#endif

添加文件进编译工程,以及在Kconfig中定义所依赖的宏,并在配置菜单中开启:

diff --git a/drivers/video/Makefile b/drivers/video/Makefileindex dfafe08..242f5a7 100755--- a/drivers/video/Makefile+++ b/drivers/video/Makefile@@ -53,6 +53,8 @@obj-$(CONFIG_AM335X_LCD) += am335x-fb.oobj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.oobj-$(CONFIG_VIDEO_SIMPLE) += simplefb.o+obj-$(CONFIG_S5P_FB) += s5p_fb.o+obj-${CONFIG_VIDEO_TEGRA124} += tegra124/obj-${CONFIG_EXYNOS_FB} += exynos/obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/diff --git a/drivers/video/Kconfig b/drivers/video/Kconfigindex 45a105d..8b12213 100755--- a/drivers/video/Kconfig+++ b/drivers/video/Kconfig@@ -658,4 +658,16 @@ config VIDEO_DT_SIMPLEFBThe video output is initialized by U-Boot, and kept by thekernel.+config S5P_FB+bool "Enable s5pc11x's fimd lcd driver support"+help+ Enable soc s5pc11x lcd driver without driver model.++config LCD_AT070TN90+bool "support lcd model named AT070TN90"+default y+depends on S5P_FB+help+ support the lcd model AT070TN90+endmenu

2.开启logo显示功能和定义像素位数。在配置文件include/configs/gec210.h中定义:

diff --git a/include/configs/gec210.h b/include/configs/gec210.hindex 62daaff..c05bcb2 100755--- a/include/configs/gec210.h+++ b/include/configs/gec210.h@@ -269,4 +271,8 @@#define CONFIG_ENV_SROM_BANK 1 /* Select SROM Bank-1 for Ethernet*/#endif /* CONFIG_CMD_NET */+#define CONFIG_LCD_LOGO1+#define LCD_BPPLCD_COLOR32++#endif/* __CONFIG_H */

增加lcd驱动通用层对24位像素LCD的支持。修改common/lcd.c

diff --git a/common/lcd.c b/common/lcd.cindex 4b3d7dc..15c2893 100755--- a/common/lcd.c+++ b/common/lcd.c@@ -1,4 +1,4 @@-/*+/*@@ -27,7 +27,8 @@#include <bmp_logo.h>#include <bmp_logo_data.h>#if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET) && (LCD_BPP != LCD_COLOR16)-#error Default Color Map overlaps with Logo Color Map+/* #error Default Color Map overlaps with Logo Color Map */+#warning Default Color Map overlaps with Logo Color Map#endif#endif@@ -349,8 +350,11 @@ void lcd_logo_plot(int x, int y)uchar *bmap = &bmp_logo_bitmap[0];unsigned bpix = NBITS(panel_info.vl_bpix);uchar *fb = (uchar *)(lcd_base + y * lcd_line_length + x * bpix / 8);+#if 0ushort *fb16;-+#else+uint *fb32;+#endifdebug("Logo: width %d height %d colors %d\n",BMP_LOGO_WIDTH, BMP_LOGO_HEIGHT, BMP_LOGO_COLORS);@@ -366,6 +370,7 @@ void lcd_logo_plot(int x, int y)}}else { /* true color mode */+#if 0u16 col16;fb16 = (ushort *)fb;for (i = 0; i < BMP_LOGO_HEIGHT; ++i) {@@ -379,6 +384,21 @@ void lcd_logo_plot(int x, int y)bmap += BMP_LOGO_WIDTH;fb16 += panel_info.vl_col;}+#else /* for 24bit color */+fb32 = (uint *)fb;+for (i=0; i < BMP_LOGO_HEIGHT; ++i) {+for (j=0; j < BMP_LOGO_WIDTH; j++) {+u32 color = bmp_logo_palette[(bmap[j]-BMP_LOGO_OFFSET)];+/* RGB-888 */+fb32[j] = ((color & 0x000F) << 4) |+ ((color & 0x00F0) << 8) |+ ((color & 0x0F00) << 12);+}+bmap += BMP_LOGO_WIDTH;+fb32 += panel_info.vl_col;+}+#endif+}WATCHDOG_RESET();

3.定制自己的logo。u-boot已有的logo保存于路径tools/logos/,并通过tools/Makefile来引用并被可执行文件bmp_logo转换成二进制文件,然后再u-boot代码中被引用显示到显示屏。准备好8位的bmp格式图片文件

修改tools/Makefile以引用自己的logo;修改bmp_logo工具的源文件使得转换logo图输出的二进制数据为8位色图,解决Logo显示模糊的问题:

diff --git a/tools/Makefile b/tools/Makefileindex 4d32fe5..0a27b04 100755--- a/tools/Makefile+++ b/tools/Makefile@@ -219,6 +219,8 @@ LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_H)LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_DATA_H)# Generic logo+LOGO_BMP= $(srctree)/$(src)/logos/zhoumou.bmp+ifeq ($(LOGO_BMP),)LOGO_BMP= $(srctree)/$(src)/logos/denx.bmpdiff --git a/tools/bmp_logo.c b/tools/bmp_logo.cindex 55f833f..47d9ecc 100755--- a/tools/bmp_logo.c+++ b/tools/bmp_logo.c@@ -1,4 +1,4 @@-#include "compiler.h"+#include "compiler.h"enum {MODE_GEN_INFO,@@ -12,7 +12,7 @@ typedef struct bitmap_s {/* bitmap description */uint8_t*data;} bitmap_t;-#define DEFAULT_CMAP_SIZE16/* size of default color map*/+#define DEFAULT_CMAP_SIZE8/* size of default color map*/void usage(const char *prog){

4.设置环境参数使得LCD作为输出控制台。通过配置菜单Console ---> [*] Enable console multiplexing使能多控制台功能,启动u-boot后输入命令setenv stdout serial,lcd; saveenv

到此阶段,上电开机准备引导kernel前LCD显示内容如下图:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。