本文主要记录移植当前最新版u-boot(u-boot-2019.10)到jz2440的过程。做这个移植主要是为了从这个过程中学习移植u-boot的一般流程、u-boot的使用以及u-boot的实现。本文主要参考的内容是韦东山老师的二期视频教程,以及网上的相关博文,这些都会在参考文献中列出。
u-boot是一种bootloader,用于引导操作系统内核的启动。字母u表示“通用”的意思,正如其名所说,u-boot目前已经支持arm、x86、mips、riscv等多种体系结构,支持引导linux、VxWorks、Solaris等多种操作系统。如何使用u-boot(主要是使用它提供的命令)来做开发,这个有很多资料讲解,u-boot自身也提供了命令的使用说明,因此使用u-boot本身并不困难,这里不再赘述。
我们要在不同的硬件平台之间移植u-boot,必然需要搞清楚不同硬件平台之间的差别。而硬件的差别体现在多个层次上,比如说,我们的目标开发板
是jz2440,使用的SoC
是三星公司的s3c2440,该SoC使用的内核(CPU)是ARM设计的ARM920T
,该内核基于armv4t
架构。
从一种硬件平台向另一种硬件平台移植时,需要知道两者之间在哪个硬件层次上开始有区别:
一般越是上游的厂商面对的不同点越多,而下游的厂商在上游厂商移植的基础上进行,比如ARM提供armv5
架构以及ARM920T
内核相关的程序,三星再此基础上为其推出的SMDK2410做移植,就只需要提供SoC层面和开发板层面的程序。而下游厂商使用S3C2440做产品,就可以在三星提供的SMDK2410的基础上做一些修改以支持自己的板子。
最后,值得说明的是:
在u-boot中,提取硬件部分的程序时,并没有严格按照上述的四个硬件层次进行。比如u-boot-2019.10\arch\arm\cpu\armv7m
目录下,并没有再细分cortex-m4
、cortex-m7
等子目录,可能是这两个内核的区别对于u-boot来说没必要去考虑(u-boot也只是使用一部分内核特性)。因此,上述硬件层次的划分仅有指导意义,还需具体情况具体分析。
如上文所述,我们在移植的时候会在SMDK2410的基础上进行,这是三星推出的开发板,使用的是s3c2410这款SoC。其实很多芯片厂商在推出新款SoC的时候,都会推出基于此SoC的开发板,以帮助用户使用该SoC设计产品,从而达到推广该SoC的目的。而三星在推出SMDK2410的时候,也向u-boot官方提供了相应的移植程序,这正是我们移植的重要参照(坯子)。
s3c2410和s3c2440都是基于ARM920T内核的,或许有人会问,为什么不直接找一个s3c2440的开发板呢?因为u-boot官方并没有直接支持基于s3c2440的板子。不仅如此,就是对SMDK2410的支持,也在最新的版本中移除了。具体是在哪个版本中移除的,我没有仔细查过。
遇到这种相似的平台被移除的情况该怎么办呢?我们可以往回看,毕竟之前的u-boot是支持的。具体的做法是,下载尚且支持SMDK2410的u-boot版本,将其中的相关目录和文件拷贝到最新的版本中,然后在根据需要去修改。至于找哪个之前的版本呢?通常越接近最新版本兼容性越好。这里我就随便选择了u-boot-2015.10。
在u-boot-2015.10中,搜索s3c
、smdk
等关键词,发现对SMDK2410的支持主要体现在六个部分:
s3c24x0
目录,其中包含了一些SoC相关的源码;smdk2410
目录,其中包含了一些板级支持的源码;arch-s3c24x0
目录,其中包含了一些头文件;驱动源文件
,这些源文件主要用于驱动s3c24x0的i2c、rtc、nand、usb等外设;smdk2410.h
文件,这个头文件主要包含了一些配置宏;smdk2410_defconfig
文件,这是一个对于SMDK2410开发板的默认配置。现在我也不能确定这些文件是否全都被使用,我们可以先将这些文件都拷贝到u-boot-2019.10,如果有什么问题,后面编译测试暴露出来后,再进行修改。
将u-boot-2015.10/arch/arm/cpu/arm920t/中的s3c24x0
目录整个拷贝到u-boot-2019.10/arch/arm/cpu/arm920t/目录下。此外,还需要修改u-boot-2019.10/arch/arm/cpu/arm920t
目录下的Makefile:
...
obj-$(CONFIG_EP93XX) += ep93xx/
obj-$(CONFIG_IMX) += imx/
# 仿照上面的内容添加如下一行
obj-$(CONFIG_S3C24X0) += s3c24x0/
...
修改Makefile的目的是告诉u-boot的编译体系,如果CONFIG_S3C24X0=y
,就编译s3c24x0
目录下的源文件。
在u-boot-2019.10/board目录下创建新目录100ask/jz2440
,并将u-boot-2015.10中的smdk2410
目录下的所有文件拷贝到新创建的目录下。此外,还需要修改的内容如下:
① 修改源文件名
将smdk2410.c
修改为jz2440.c
。
② 修改源文件中2410相关内容:
int board_init(void)
{
/* arch number of JZ2440-Board */
// gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;
// 将这句程序修改如下:
gd->bd->bi_arch_number = MACH_TYPE_JZ2440;
...
}
MACH_TYPE_JZ2440
并没有在u-boot中定义,因此我们要添加它的定义。至于在哪里添加,我们可以参考MACH_TYPE_SMDK2410
,使用Linux的grep命令不难找到这个宏定义在u-boot-2019.10/arch/arm/include/asm/mach-types.h
,在其中增加宏定义:
// MACH_TYPE_SMDK2440与目标平台JZ2440最为接近
#define MACH_TYPE_JZ2440 MACH_TYPE_SMDK2440
以上两步的修改仅仅是将2410的痕迹抹去,毕竟我们是要移植到2440平台。这些修改只是名称层面的,没有什么实质的修改。
③ 修改Makefile
# obj-y := smdk2410.o
# 将上式修改为
obj-y := jz2440.o
④ 修改Kconfig
将原来的内容做如下修改:
if TARGET_JZ2440
config SYS_BOARD
default "jz2440"
config SYS_VENDOR
default "100ask"
config SYS_SOC
default "s3c24x0"
config SYS_CONFIG_NAME
default "jz2440"
endif
这个目录下存在Kconfig,也就意味着我们要在恰当的上层Kconfig中使用source
来引用这个Kconfig,从而将这个目录下的内容纳入u-boot的配置体系。这里所说的“恰当的目录”其实是arch/arm/Kconfig
,属于arm体系的board
的Kconfig会在其中被引用。
在arch/arm/Kconfig
中加上这么一句:
......
source "board/xilinx/zynq/Kconfig"
source "board/xilinx/zynqmp/Kconfig"
# 添加如下内容
source "board/100ask/jz2440/Kconfig"
......
此外,需要注意到TARGET_JZ2440
是我们后来改的,在原来的配置体系中没有定义。同样是arch/arm/Kconfig
,其中定义了目标开发板的选项群:
choice
prompt "Target select"
default TARGET_HIKEY
......
endchoice
我们在endchoice
之前添加如下内容:
config TARGET_JZ2440
bool "support jz2440"
select CPU_ARM920T
help
"support jz2440, a board based on s3c2440"
将u-boot-2015.10/arch/arm/include/asm中的arch-s3c24x0
目录整个拷贝到u-boot-2019.10/arch/arm/include/asm目录下即可。
将这些驱动源文件列表如下:
目录 | 文件名 |
---|---|
u-boot-2015.10/drivers/usb/host | ohci-s3c24xx.c ,ohci-s3c24xx.h |
u-boot-2015.10/include/usb | s3c_udc.h |
u-boot-2015.10/drivers/usb/gadget | s3c_udc_otg.c ,s3c_udc_otg_phy.c ,s3c_udc_otg_xfer_dma.c |
u-boot-2015.10/drivers/i2c | s3c24x0_i2c.c ,s3c24x0_i2c.h |
u-boot-2015.10/drivers/rtc | s3c24x0_rtc.c |
u-boot-2015.10/drivers/mtd/nand | s3c2410_nand.c |
u-boot-2015.10/drivers/gpio | s3c2440_gpio.c |
u-boot-2015.10/drivers/serial | serial_s3c24x0.c |
同时,还要修改Makefile,参照u-boot-2015.10中的相应Makefile修改即可,比如将u-boot-2015.10/drivers/usb/host目录下Makefile中的:
obj-$(CONFIG_USB_OHCI_S3C24XX) += ohci-s3c24xx.o
添加到u-boot-2019.10/drivers/usb/host目录下的Makefile中,不再赘述。
需要说明的是,上述驱动程序我们只是简单的拷贝,以及将命名中的2410改为了2440。但这种层次的修改是不够的,可能部分驱动程序不适用于2440,需要修改源程序本身,这些修改我们放在后面说。
将u-boot-2015.10/include/configs目录下的smdk2410.h
拷贝到u-boot-2019.10/include/configs目录下,并将文件名修改为jz2440.h
。查看这个文件的内容,对其中与2410
、smdk2410
相关的内容做如下修改:
// #define CONFIG_S3C2410改为
#define CONFIG_S3C2440
// #define CONFIG_SMDK2410改为
#define CONFIG_JZ2440
......
// #define CONFIG_NAND_S3C2410改为
#define CONFIG_NAND_S3C2440
// #define CONFIG_SYS_S3C2410_NAND_HWECC改为
#define CONFIG_SYS_S3C2440_NAND_HWECC
......
此外,应该在所有原来的宏名出现的地方做同步的修改:
通过在源码中搜索发现,CONFIG_S3C2410和CONFIG_S3C2440是相互替代的关系(目标板的SoC不可能既是2410又是2440),而CONFIG_SMDK2410和CONFIG_SYS_S3C2410_NAND_HWECC没有使用到,因此仅在这个头文件中做修改即可。
CONFIG_NAND_S3C2410
在u-boot-2015.10中决定了3c2410_nand.c
是否要编译:
obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
之前拷贝3c2410_nand.c
的时候已经将其命名改为了3c2440_nand.c
,且在相应的Makefile中添加了:
obj-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
因此这个配置项也仅需要在这个头文件中做修改。
将u-boot-2015.10/configs/smdk2410_defconfig拷贝到u-boot-2019.10/configs目录下,并重命名为jz2440_defconfig,并将其中内容修改如下:
CONFIG_ARM=y
# 联系上文中的TARGET_JZ2440
CONFIG_TARGET_JZ2440=y
CONFIG_SYS_PROMPT="JZ2440 # "
# CONFIG_CMD_SETEXPR is not set
至此,我已经将能想到的可能用到的文件都拷贝到u-boot-2019.10了,至于这些文件会不会都被用到,是不是还有一些需要修改的地方尚未被注意到,或者还有一些需要用到的文件没有拷过去,这些只能通过阅读源码、实际编译测试等方式来发现了。接下来就进行编译,应该不可能一次通过,编译暴露出的问题正好指引后面的移植工作。
关于u-boot的编译体系及其编译过程,不在这里多说。值得一提的是,我使用的交叉编译工具链版本为4.3.2。下面就开始编译u-boot-2019.10:
1 执行make jz2440_defconfig,使用默认配置。
出现错误:
board/jz2440/Kconfig:15: 'endif' in different file than 'if'
分析与解决:
endif后面要加一个空行,这是Kconfig格式的问题。
2 执行make CROSS_COMPILE=arm-linux-进行编译
出现提示:
scripts/kconfig/conf --syncconfig Kconfig
.config:151:warning: symbol value '' invalid for SYS_TEXT_BASE
*
* Restart config...
*
分析与解决:
看提示,应该是SYS_TEXT_BASE(链接基地址)没有配置。搜索SYS_TEXT_BASE,发现该配置项通常在xxx_defconfig中配置,所以在jz2440_defconfig中添加:
CONFIG_SYS_TEXT_BASE=0x00000000
3 再次编译
出现错误:
cc1: error: unrecognized command line option "-std=gnu11"
分析与解决:
从错误提示来看,错误的原因是工具链的版本太老,不支-std=gnu11
选项。为了解决这个问题,很是折腾了一番还没有结果。新版的工具链不一定支持arm9,而且更换了更新的工具链之后,-std=gnu11
选项这里没有报错,但又出现的了新的问题,诸如:
*** Your GCC is older than 6.0 and is not supported
将GCC版本校验注释掉,再编译,又出错:
error while loading shared libraries: libstdc++.so.6: wrong ELF class: ELFCLASS64
我对工具链理解不深,因此如果再在工具链上耗下去,就偏离了学习u-boot的主线,所以决定还是硬着头皮用现在的工具链(gcc version 4.3.2
)。毕竟,没有c11的特性,难道u-boot这个项目就做不成了?当然用旧的工具链需要做些修改:
# u-boot-2019.10/Makefile中将-std=gnu11改为-std=gnu99
# CSTD_FLAG := -std=gnu11
CSTD_FLAG := -std=gnu99
------------------------------------------------------------
# u-boot-2019.10/arch/arm/config.mk中注释掉GCC版本的校验
# archprepare: checkgcc6
4 再次编译
出现错误:
配置头文件jz2440.h中出现了一大堆宏重复定义的警告,还有个别类型的重复定义。
分析与解决:
重复的宏定义同时出现在u-boot-2019.10/include/configs/jz2440.h
和u-boot-2019.10/include/generated/autoconf.h
中,后者就是从.config
文件中生成的。看样子,u-boot的配置被分为两个部分,一个部分源于Kconfig配置体系生成的.config
文件;另一个部分需要手动配置,通常放在u-boot-2019.10/include/configs/
中。可能是一部分原先需要手动配置的项,现在被纳入了Kconfig配置体系,因此出现了重复定义。我们只需要把重复的项注释掉即可(注释jz2440.h中的,不去动自动生成的autoconf.h)。
5 再次编译
出现错误:
arch/arm/cpu/arm920t/s3c24x0/cpu_info.c:15: error: 'get_FCLK' undeclared here (not in a function)
arch/arm/cpu/arm920t/s3c24x0/cpu_info.c:16: error: 'get_HCLK' undeclared here (not in a function)
arch/arm/cpu/arm920t/s3c24x0/cpu_info.c:17: error: 'get_PCLK' undeclared here (not in a function)
分析与解决:
简单搜索过程可知,get_FCLK
、get_HCLK
、get_PCLK
等函数都是定义在与cpu_info.c相同目录的speed.c中,而在cpu_info.c中使用时,并未声明,因此我们在cpu_info.c的开头添加如下声明即可:
/* 添加函数声明 */
ulong get_FCLK(void);
ulong get_HCLK(void);
ulong get_PCLK(void);
ulong get_UCLK(void);
6 再次编译
出现错误:
arch/arm/cpu/arm920t/s3c24x0/timer.c: In function 'timer_init':
arch/arm/cpu/arm920t/s3c24x0/timer.c:38: warning: implicit declaration of function 'get_PCLK'
arch/arm/cpu/arm920t/s3c24x0/timer.c: In function 'get_timer':
arch/arm/cpu/arm920t/s3c24x0/timer.c:60: warning: implicit declaration of function 'get_timer_masked'
arch/arm/cpu/arm920t/s3c24x0/timer.c: At top level:
arch/arm/cpu/arm920t/s3c24x0/timer.c:76: error: conflicting types for 'get_timer_masked'
arch/arm/cpu/arm920t/s3c24x0/timer.c:60: error: previous implicit declaration of 'get_timer_masked' was here
分析与解决:
仍然是函数声明的问题,在timer.c的开头添加函数声明:
/* 添加函数声明 */
ulong get_timer_masked(void);
ulong get_PCLK(void);
7 再次编译
出现错误:
board/100ask/jz2440/jz2440.c: In function 'board_init':
board/100ask/jz2440/jz2440.c:100: error: 'MACH_TYPE_JZ2440' undeclared (first use in this function)
board/100ask/jz2440/jz2440.c:100: error: (Each undeclared identifier is reported only once
board/100ask/jz2440/jz2440.c:100: error: for each function it appears in.)
分析与解决:
MACH_TYPE_JZ2440定义在u-boot-2019.10/arch/arm/include/asm/mach-types.h
中,只要在jz2440.c中包含这个头文件即可:
#include
8 再次编译
出现错误:
cmd/reginfo.c:9:21: error: asm/ppc.h: No such file or directory
cmd/reginfo.c: In function 'do_reginfo':
cmd/reginfo.c:14: warning: implicit declaration of function 'print_reginfo'
分析与解决:
搜索print_reginfo
发现这个函数定义在powerpc架构下,而我们是arm架构,因此可以将整个打印寄存器信息的功能都注释掉,即注释掉jz2440.h中的相应配置项:
// #define CONFIG_CMD_REGINFO
9 再次编译
出现错误:
cmd/ubi.c: In function 'display_ubi_info':
cmd/ubi.c:64: error: 'CONFIG_MTD_UBI_WL_THRESHOLD' undeclared (first use in this function)
cmd/ubi.c:64: error: (Each undeclared identifier is reported only once
分析与解决:
UBI的配置项在.config
中是被注释的:
# CONFIG_MTD_UBI is not set
而CONFIG_MTD_UBI_WL_THRESHOLD
是依赖于CONFIG_MTD_UBI
的:
也就是说UBI相关的配置是没有选中的,UBI相关的源文件也不应该被编译,但实际被编译了。这是因为jz2440.h中配置了相关选项,为什么会出现这种前后矛盾的情况呢?上文已经说过u-boot的配置被割裂成两部分,一部分可以通过图形化配置,配置结果保存在.config
文件中;另一部分保存在u-boot-2019.10/include/configs目录下的用于配置的头文件中,需要手动用宏来配置,本文中这个配置头文件就是jz2440.h
。这两部分应该是互补的,而不应该相互矛盾,但我们的jz2440.h是从之前的版本拷贝过来的,本身就不是u-boot-2019.10自带的,因此存在一些矛盾之处也不足为奇。对于眼下这个问题,我们把jz2440.h中的UBI相关的配置项注释掉即可:
// #define CONFIG_CMD_UBI
// #define CONFIG_CMD_UBIFS
10 再次编译
出现警告和错误:
drivers/mtd/nand/raw/nand_base.c: In function 'nand_maximize_ecc':
drivers/mtd/nand/raw/nand_base.c:4887: warning: 'best_ecc_bytes' may be used uninitialized in this function
drivers/mtd/nand/raw/nand_base.c:4887: warning: 'best_strength' may be used uninitialized in this function
drivers/mtd/nand/raw/nand_base.c: In function 'nand_match_ecc_req':
drivers/mtd/nand/raw/nand_base.c:4803: warning: 'best_ecc_bytes' may be used uninitialized in this function
drivers/mtd/nand/raw/nand_base.c:4803: warning: 'best_strength' may be used uninitialized in this function
drivers/mtd/nand/raw/nand_base.c:4803: warning: 'best_step' may be used uninitialized in this function
......
drivers/serial/serial_s3c24x0.c: In function '_serial_setbrg':
drivers/serial/serial_s3c24x0.c:79: warning: implicit declaration of function 'get_PCLK'
......
drivers/usb/host/ohci-s3c24xx.c:1330: error: conflicting types for 'submit_int_msg'
include/usb.h:186: error: previous declaration of 'submit_int_msg' was here
分析与解决:
开头一大堆的未初始化警告,源码中本就没有初始化,因此不去管它们。而警告get_PCLK
未声明,只需声明一下即可。最后的一个错误是因为submit_int_msg
函数的原型在u-boot-2019.10
中已经发生了改变:
// 旧的原型是:
// int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval)
// 修改为如下:
int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval, bool nonblock)
11 再次编译
出现警告和错误:
arm-linux-ld: ERROR: Source object drivers/dma/built-in.o has EABI version 0, but target u-boot has EABI version 5
cmd/built-in.o: In function `do_fat_fsinfo':
/root/work/u-boot/u-boot-2019.10/cmd/fat.c:84: undefined reference to `fat_set_blk_dev'
/root/work/u-boot/u-boot-2019.10/cmd/fat.c:89: undefined reference to `file_fat_detectfs'
......
cmd/built-in.o: In function `usb_find_device':
/root/work/u-boot/u-boot-2019.10/cmd/usb.c:308: undefined reference to `usb_get_dev_index'
env/built-in.o: In function `env_flash_save':
/root/work/u-boot/u-boot-2019.10/env/flash.c:270: undefined reference to `flash_sect_protect'
/root/work/u-boot/u-boot-2019.10/env/flash.c:278: undefined reference to `flash_sect_erase'
/root/work/u-boot/u-boot-2019.10/env/flash.c:282: undefined reference to `flash_write'
/root/work/u-boot/u-boot-2019.10/env/flash.c:300: undefined reference to `flash_perror'
/root/work/u-boot/u-boot-2019.10/env/flash.c:305: undefined reference to `flash_sect_protect'
arm-linux-ld: BFD (Sourcery G++ Lite 2008q3-72) 2.18.50.20080215 assertion fail /scratch/julian/lite-respin/linux/obj/binutils-src-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:9537
arm-linux-ld: BFD (Sourcery G++ Lite 2008q3-72) 2.18.50.20080215 assertion fail /scratch/julian/lite-respin/linux/obj/binutils-src-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:9537
......
arm-linux-ld: BFD (Sourcery G++ Lite 2008q3-72) 2.18.50.20080215 assertion fail /scratch/julian/lite-respin/linux/obj/binutils-src-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:9771
Segmentation fault (core dumped)
make: *** [u-boot] Error 139
make: *** Deleting file `u-boot'
分析与解决:
首先是EABI
版本不一致这个错误,大概说的是我们编译源码的时候用的是老版本的EABI,而u-boot-2019.10在链接的时候需要用新版的EABI。这可能就是用旧版编译工具链编译新版u-boot会出现的问题,我是参照本文参考文献[2]解决的,关于工具链、ABI的知识真是让人头疼,后面得找时间专门深入学一下相关内容。
剩下的是一堆链接时找不到函数定义的错误。搜索了一下,发现还是因为u-boot的两部分配置相互矛盾造成的,我们先简单处理:注释掉jz2440.h
中配置的,但.config
中未配置的内容,即注释掉jz2440.h
中的如下配置项:
// #define CONFIG_CMD_USB
......
/************************************************************
* USB support (currently only works with D-cache off)
************************************************************/
// #define CONFIG_USB_OHCI
// #define CONFIG_USB_OHCI_S3C24XX
// #define CONFIG_USB_KEYBOARD
// #define CONFIG_USB_STORAGE
......
// #define CONFIG_ENV_IS_IN_FLASH
......
/*
* File system
*/
// #define CONFIG_CMD_FAT
需要说明的是,这里注释掉相关配置项,只是为了先编译通过,而不是说这些配置项所配置的功能用不着。后面如果使用到相关功能,我们还会重新配置。但再来配置的时候,会优先通过Kconfig配置体系来配置,这样可以统一配置的来源,避免两部分配置出现重复或矛盾的地方,如此,即便再出问题,也更好分析和解决。
12 再次编译
这次编译终于生成了u-boot.bin等文件:
但Makefile仍旧给出了一些警告:
===================== WARNING ======================
This board does not use CONFIG_DM. CONFIG_DM will be
compulsory starting with the v2020.01 release.
Failure to update may result in board removal.
See doc/driver-model/migration.rst for more info.
====================================================
===================== WARNING ======================
This board does not use CONFIG_DM_MMC. Please update
the board to use CONFIG_DM_MMC before the v2019.04 release.
Failure to update by the deadline may result in board removal.
See doc/driver-model/MIGRATION.txt for more info.
====================================================
===================== WARNING ======================
This board does not use CONFIG_DM_ETH (Driver Model
for Ethernet drivers). Please update the board to use
CONFIG_DM_ETH before the v2020.07 release. Failure to
update by the deadline may result in board removal.
See doc/driver-model/migration.rst for more info.
====================================================
CFGCHK u-boot.cfg
Error: You must add new CONFIG options using Kconfig
The following new ad-hoc CONFIG options were detected:
CONFIG_CS8900
CONFIG_CS8900_BASE
CONFIG_JZ2440
CONFIG_NAND_S3C2440
CONFIG_RTC_S3C24X0
CONFIG_S3C2440
CONFIG_S3C24X0
CONFIG_S3C24X0_SERIAL
CONFIG_SERIAL1
CONFIG_SYS_GENERIC_BOARD
CONFIG_SYS_HUSH_PARSER
CONFIG_SYS_S3C2440_NAND_HWECC
CONFIG_ZERO_BOOTDELAY_CHECK
Please add these via Kconfig instead. Find a suitable Kconfig
file and add a 'config' or 'menuconfig' option.
这些警告的意思不难解读,u-boot强制使用CONFIG_DM
、CONFIG_DM_MMC
、CONFIG_DM_ETH
等配置项,而我们没有使用。同时,警告信息中给出的CONFIG_CS8900
等配置项不是官方维护的,我们需要通过Kconfig配置体系来添加属于自己的新的配置项。
看来官方也比较倾向于Kconfig配置体系,我个人也觉得两种配置方式并存不好,这样会将配置割裂成两部分,如果两部分不是严格互补的,而是存在重复的配置项,那么就可能出现CONFIG_XXX在Kconfig配置体系中没有选中,而头文件中却进行了宏定义。导致的结果是,我们的本意是不需要该项功能,但最后该项功能却被编译进去了,当然还有可能连编译都通不过。
为了使配置体系更合理,我会将上述配置项移到Kconfig配置体系中,jz2440.h
中的其他重复项会在后续的移植过程中处理。简单起见,我们将专门为jz2440定义的配置项移至u-boot-2019.10/board/100ask/jz2440/Kconfig
文件中:
if TARGET_JZ2440
......
config CS8900
bool
default y
config CS8900_BASE
hex
default 0x19000300
config JZ2440
bool
default y
config NAND_S3C2440
bool
default y
config RTC_S3C24X0
bool
default y
config S3C2440
bool
default y
config S3C24X0
bool
default y
config S3C24X0_SERIAL
bool
default y
config SERIAL1
int
default 1
config SYS_GENERIC_BOARD
bool
default y
config SYS_HUSH_PARSER
bool
default y
config SYS_S3C2440_NAND_HWECC
bool
default y
config ZERO_BOOTDELAY_CHECK
bool
default y
endif
至于CONFIG_DM
、CONFIG_DM_MMC
、CONFIG_DM_ETH
这几个配置项,先不去管,后续的移植过程中,若有需要再去配置。
经过上述步骤,我们完成了对u-boot-2019.10的编译,成功得到了bin文件。但显然,由于smdk2410
和jz2440
的差别,这个bin文件几乎不可能顺利运行。因此我们需要进一步修改u-boot,同时也要将bin文件烧写到开发板测试。在测试过程中,如果发现问题,还需要再修改程序,这样不断迭代,直到u-boot在目标开发板上运行没有问题。
想要修改u-boot,就必须先知道u-boot的源码是怎么写的,否则根本不知道该改哪里。因此,我们先分析源码。考虑到本文已经比较长了,所以另一起一篇博客来记录我对u-boot源码的分析:u-boot-2019.10源码分析。
在分析源码的过程中,不难发现,u-boot-2019.10/arch/arm/cpu/arm920t/start.S
将关看门狗、关中断、设置时钟分频系数的程序移除了(因为移除了对SMDK2410的支持,相应的程序也就移除了)。我们自己实现这些功能并添加到start.S中设置SVC模式相关程序的后面:
#if CONFIG_S3C2440
#define WTCON 0x53000000 /* 看门狗控制寄存器 */
#define INTMSK 0x4A000008 /* 中断屏蔽寄存器 */
#define INTSUBMSK 0x4A00001C /* 子级中断屏蔽寄存器 */
#define CLKDIVN 0x4C000014 /* 时钟分频寄存器 */
#define MPLLCON 0x4C000004 /* MPLL控制寄存器 */
#define S3C2440_MPLL_400MHZ ((0x5c<<12) | (0x01<<4) | (0x01<<0))
/* 关看门狗 */
ldr r0, =WTCON
mov r1, #0x0
str r1, [r0]
/* 关中断 */
/* 屏蔽第一级中断 */
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
/* 屏蔽第二级中断 */
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
/* 配置MPLL(FCLK = 400MHz) */
ldr r0, =MPLLCON
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
/* 设置分频比为FCLK:HCLK:PCLK = 8:2:1 */
/* FCLK = 400MHz, HCLK = 100MHz, PCLK = 50MHz */
ldr r0, =CLKDIVN
mov r1, #0x05
str r1, [r0]
/* 设置异步总线模式(HDIVN不为0) */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0xc0000000
mcr p15, 0, r0, c1, c0, 0
#endif
同时,通过前面对源码的分析,在u-boot-2019.10/board/100ask/jz2440/jz2440.c
中的board_early_init_f
函数中有对MPLL的配置,为了避免重复且不一致的配置,将该函数中配置MPLL的程序注释掉。
由于S3C2410的时钟频率和S3C2440的不同,后者时钟频率更高。因此原来的sdram初始化使用的参数就不对了。在u-boot-2019.10/board/100ask/jz2440/lowlevel_init.S
中,将sdram控制器的参数修改如下:
.long 0x22011110 @BWSCON
.long 0x00000700 @BANKCON0
.long 0x00000700 @BANKCON1
.long 0x00000700 @BANKCON2
.long 0x00000700 @BANKCON3
.long 0x00000700 @BANKCON4
.long 0x00000700 @BANKCON5
.long 0x00018005 @BANKCON6
.long 0x00018005 @BANKCON7
.long 0x008C04F4 @REFRESH
.long 0x000000B1 @BANKSIZE
.long 0x00000030 @MRSRB6
.long 0x00000030 @MRSRB7
为了能在运行移植后的u-boot时打印出一些信息,必须初始化串口。前面分析源码的时候已经说过,串口在硬件层面的初始化u-boot已经做了,而u-boot没做的是注册串口设备,因此需要在u-boot-2019.10/drivers/serial/serial.c
中的serial_initialize
函数里面添加注册S3C2440的串口的函数:
/* 相当于函数声明 */
serial_initfunc(s3c24xx_serial_initialize);
......
void serial_initialize(void)
{
......
#if CONFIG_S3C2440
/* 注册S3C2440的串口设备 */
s3c24xx_serial_initialize();
#endif
......
}
至此,我们保存上述修改,然后编译、烧写,看看做了上述修改后u-boot-2019.10能在jz2440上运行到哪一步。
将开发板设置为Nor启动,使用jlink将bin文件烧写到NorFlash之后,重新上电,令人失望的是没有任何串口输出,哪怕是乱码都没有。仔细检查程序以及反汇编文件,没有看出来有什么问题。只能请出LED大法了,从reset
开始,以点灯的方式一点一点找问题出在哪里。最后发现是配置MPLL、设置分频比、设置异步总线模式三者的顺序导致的问题,将顺序调整如下:
/* 设置分频比为FCLK:HCLK:PCLK = 8:2:1 */
/* FCLK = 400MHz, HCLK = 100MHz, PCLK = 50MHz */
ldr r0, =CLKDIVN
mov r1, #0x05
str r1, [r0]
/* 设置异步总线模式(HDIVN不为0) */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0xc0000000
mcr p15, 0, r0, c1, c0, 0
/* 配置MPLL(FCLK = 400MHz) */
ldr r0, =MPLLCON
ldr r1, =S3C2440_MPLL_400MHZ
str r1, [r0]
然后再次编译烧写,重新上电后,终于看到了u-boot-2019.10的输出:
U-Boot 2019.10 (Dec 24 2019 - 14:55:28 +0800)
CPUID: 32440001
FCLK: 400 MHz
HCLK: 100 MHz
PCLK: 50 MHz
DRAM: 64 MiB
WARNING: Caches not enabled
NAND: 0 MiB
MMC:
In: serial
Out: serial
Err: serial
Net: CS8900-0
Error: CS8900-0 address not set.
JZ2440 #
至此,u-boot-2019.10成功在jz2440上面运行起来,但移植工作并未结束。从上述输出信息就可以看出一些问题,比如NandFlash还未支持,网卡驱动使用的是CS8900的,而jz2440使用的网卡是DM9000。当然,存在的问题还不止这些,要想移植的u-boot能够用于开发,还有不少事情要做。因此,让我们愉快的继续!
根据本文4.1节对u-boot-2019.10源码的分析,不难看出,其使用了动态链接的一些技术,在编译时添加了-pie
选项,因此需要额外保存很多函数和变量的地址,增加了程序的体积。且在重定位之前还要调用init_sequence_f
中的许多初始化函数,这使得我们很难确保重定位之前的所有程序都位于bin文件的前4K。然而,S3C2440的Nand启动只能拷贝NandFlash的前4K至片内的SRAM。因此,要想让u-boot-2019.10支持Nand启动,我们需要把重定位提前。同样为了确保本文的阅读体验,我们另起一文来记录如何修改u-boot-2019.10以支持S3C2440的Nand启动:移植u-boot-2019.10到jz2440——修改程序以支持Nand启动。
目前我们的u-boot可以从NorFlash启动,但未能支持NorFlash,注意两者的区别:从NorFlash启动只需要读NorFlash就可以了,而u-boot提供了一些命令如mw、erase,这些命令需要写/擦除NorFlash。NorFlash是不能随机写的,只能通过特定的操作序列来实现擦除、写等功能。而不同型号的NorFlash所需要的操作序列可能不同,所以u-boot不太可能不需要任何修改就支持我们所使用的NorFlash,毕竟选择什么型号的NorFlash不是u-boot决定的,而我们至少要通过某种方式(u-boot提供的某种机制)把我们所用的NorFlash的一些信息告诉u-boot。那么到底要做哪些修改呢?且看移植u-boot-2019.10到jz2440——修改程序以支持NorFlash。
通过分析源码可以获知,当前u-boot使用的网卡驱动是CS8900的驱动,而jz2440实际使用的网卡是DM9000C,因此当前网卡是无法使用的,与网卡相关的一些好用的功能,比如通过tftp下载程序这些都无法使用。现在我们就修改程序来支持网卡:移植u-boot-2019.10到jz2440——修改程序以支持DM9000C网卡。
当前我们移植的u-boot已经可以从NandFlash启动了,但还不支持一些NandFlash相关的命令,比如nand read/write
等。这是因为NandFlash相关的程序是我们直接从SMDK2410那里拷贝来的,尚未经过修改,不适合jz2440。现在我们就修改程序来支持NandFlash:移植u-boot-2019.10到jz2440——修改程序以支持NandFlash。
[1] 韦东山老师二期视频教程
[2] u-boot 2015.01 :has EABI version 0, but target u-boot has EABI version 4
[3] 游戏进行中的博客