移植u-boot-2019.10到jz2440

目录

  • 前言
  • 1 u-boot简介
  • 2 第一步——根据自己的硬件初步修改u-boot
    • 2.1 移植的不同硬件层次
    • 2.2 选择合适的坯子
    • 2.3 将旧版本中支持SMDK2410的文件拷贝到新版u-boot
      • 2.3.1 拷贝s3c24x0目录
      • 2.3.2 拷贝smdk2410目录
      • 2.3.3 拷贝arch-s3c24x0目录
      • 2.3.4 拷贝零散分布的驱动源程序
      • 2.3.5 拷贝smdk2410.h
      • 2.3.6 拷贝smdk2410_defconfig文件
  • 3 第二步——编译并解决出现的问题
  • 4 第三步——运行测试并进一步修改u-boot
    • 4.1 u-boot-2019.10源码分析
    • 4.2 初步修改源码
      • 4.2.1 关看门狗、关中断、配置MPLL
      • 4.2.2 初始化sdram
      • 4.2.3 初始化串口
      • 4.2.4 烧写程序并调试
    • 4.3 修改程序以支持Nand启动
    • 4.4 修改程序以支持NorFlash
    • 4.5 修改程序以支持DM9000C网卡
    • 4.6 修改程序以支持NandFlash
    • 4.7
    • 4.8
  • 参考文献

前言

本文主要记录移植当前最新版u-boot(u-boot-2019.10)到jz2440的过程。做这个移植主要是为了从这个过程中学习移植u-boot的一般流程、u-boot的使用以及u-boot的实现。本文主要参考的内容是韦东山老师的二期视频教程,以及网上的相关博文,这些都会在参考文献中列出。

1 u-boot简介

u-boot是一种bootloader,用于引导操作系统内核的启动。字母u表示“通用”的意思,正如其名所说,u-boot目前已经支持arm、x86、mips、riscv等多种体系结构,支持引导linux、VxWorks、Solaris等多种操作系统。如何使用u-boot(主要是使用它提供的命令)来做开发,这个有很多资料讲解,u-boot自身也提供了命令的使用说明,因此使用u-boot本身并不困难,这里不再赘述。

2 第一步——根据自己的硬件初步修改u-boot

2.1 移植的不同硬件层次

我们要在不同的硬件平台之间移植u-boot,必然需要搞清楚不同硬件平台之间的差别。而硬件的差别体现在多个层次上,比如说,我们的目标开发板是jz2440,使用的SoC是三星公司的s3c2440,该SoC使用的内核(CPU)是ARM设计的ARM920T,该内核基于armv4t架构。

从一种硬件平台向另一种硬件平台移植时,需要知道两者之间在哪个硬件层次上开始有区别:

  1. 如果是同一种SoC,不同的开发板,那么区别可能就只存在于板载外设,需要修改或添加一些驱动;
  2. 如果是同一种内核,不同的SoC,不同的开发板,比如TI基于ARM920T做的SoC和三星基于ARM920T做的SoC,以及更下游厂商做的不同开发板,那么除了板载外设的不同,移植时还要根据不同SoC之间的差别做修改;
  3. 如果是同一种架构,不同的内核,不同的SoC,不同的开发板,比如Cortex-A53的板子和Cortex-A57的板子,那么移植的时候,板载外设、SoC、内核相关的程序都可能要修改;
  4. 如果什么都不同,即不同的架构,不同的内核,不同的SoC,不同的开发板,比如ARM9的板子和cortex-A8的板子(同出于ARM,架构还有一定的相似性),更有甚者ARM架构的板子和MIPS架构的板子,那么移植的工作量就非常大了,基本上,除了u-boot的硬件无关的程序,所有硬件相关的程序都要修改,修改的程度视两者的差异大小而定。

一般越是上游的厂商面对的不同点越多,而下游的厂商在上游厂商移植的基础上进行,比如ARM提供armv5架构以及ARM920T内核相关的程序,三星再此基础上为其推出的SMDK2410做移植,就只需要提供SoC层面和开发板层面的程序。而下游厂商使用S3C2440做产品,就可以在三星提供的SMDK2410的基础上做一些修改以支持自己的板子。

最后,值得说明的是
在u-boot中,提取硬件部分的程序时,并没有严格按照上述的四个硬件层次进行。比如u-boot-2019.10\arch\arm\cpu\armv7m目录下,并没有再细分cortex-m4cortex-m7等子目录,可能是这两个内核的区别对于u-boot来说没必要去考虑(u-boot也只是使用一部分内核特性)。因此,上述硬件层次的划分仅有指导意义,还需具体情况具体分析。

2.2 选择合适的坯子

如上文所述,我们在移植的时候会在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

2.3 将旧版本中支持SMDK2410的文件拷贝到新版u-boot

在u-boot-2015.10中,搜索s3csmdk等关键词,发现对SMDK2410的支持主要体现在六个部分

  1. u-boot-2015.10\arch\arm\cpu\arm920t目录下的s3c24x0目录,其中包含了一些SoC相关的源码;
  2. u-boot-2015.10\board\samsung目录下的smdk2410目录,其中包含了一些板级支持的源码;
  3. u-boot-2015.10\arch\arm\include\asm目录下的arch-s3c24x0目录,其中包含了一些头文件;
  4. u-boot-2015.10\drivers\xxx诸多目录下的一些驱动源文件,这些源文件主要用于驱动s3c24x0的i2c、rtc、nand、usb等外设;
  5. u-boot-2015.10\include\configs目录下的smdk2410.h文件,这个头文件主要包含了一些配置宏;
  6. u-boot-2015.10\configs目录下的smdk2410_defconfig文件,这是一个对于SMDK2410开发板的默认配置。

现在我也不能确定这些文件是否全都被使用,我们可以先将这些文件都拷贝到u-boot-2019.10,如果有什么问题,后面编译测试暴露出来后,再进行修改。

2.3.1 拷贝s3c24x0目录

将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目录下的源文件。

2.3.2 拷贝smdk2410目录

在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"

2.3.3 拷贝arch-s3c24x0目录

将u-boot-2015.10/arch/arm/include/asm中的arch-s3c24x0目录整个拷贝到u-boot-2019.10/arch/arm/include/asm目录下即可。

2.3.4 拷贝零散分布的驱动源程序

将这些驱动源文件列表如下:

目录 文件名
u-boot-2015.10/drivers/usb/host ohci-s3c24xx.cohci-s3c24xx.h
u-boot-2015.10/include/usb s3c_udc.h
u-boot-2015.10/drivers/usb/gadget s3c_udc_otg.cs3c_udc_otg_phy.cs3c_udc_otg_xfer_dma.c
u-boot-2015.10/drivers/i2c s3c24x0_i2c.cs3c24x0_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,需要修改源程序本身,这些修改我们放在后面说。

2.3.5 拷贝smdk2410.h

将u-boot-2015.10/include/configs目录下的smdk2410.h拷贝到u-boot-2019.10/include/configs目录下,并将文件名修改为jz2440.h。查看这个文件的内容,对其中与2410smdk2410相关的内容做如下修改:

// #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

因此这个配置项也仅需要在这个头文件中做修改。

2.3.6 拷贝smdk2410_defconfig文件

将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了,至于这些文件会不会都被用到,是不是还有一些需要修改的地方尚未被注意到,或者还有一些需要用到的文件没有拷过去,这些只能通过阅读源码、实际编译测试等方式来发现了。接下来就进行编译,应该不可能一次通过,编译暴露出的问题正好指引后面的移植工作。

3 第二步——编译并解决出现的问题

关于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.hu-boot-2019.10/include/generated/autoconf.h中,后者就是从.config文件中生成的。看样子,u-boot的配置被分为两个部分,一个部分源于Kconfig配置体系生成的.config文件;另一个部分需要手动配置,通常放在u-boot-2019.10/include/configs/.h中。可能是一部分原先需要手动配置的项,现在被纳入了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_FCLKget_HCLKget_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的:
移植u-boot-2019.10到jz2440_第1张图片
也就是说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等文件:
移植u-boot-2019.10到jz2440_第2张图片
但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_DMCONFIG_DM_MMCCONFIG_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_DMCONFIG_DM_MMCCONFIG_DM_ETH这几个配置项,先不去管,后续的移植过程中,若有需要再去配置。


4 第三步——运行测试并进一步修改u-boot

经过上述步骤,我们完成了对u-boot-2019.10的编译,成功得到了bin文件。但显然,由于smdk2410jz2440的差别,这个bin文件几乎不可能顺利运行。因此我们需要进一步修改u-boot,同时也要将bin文件烧写到开发板测试。在测试过程中,如果发现问题,还需要再修改程序,这样不断迭代,直到u-boot在目标开发板上运行没有问题。

4.1 u-boot-2019.10源码分析

想要修改u-boot,就必须先知道u-boot的源码是怎么写的,否则根本不知道该改哪里。因此,我们先分析源码。考虑到本文已经比较长了,所以另一起一篇博客来记录我对u-boot源码的分析:u-boot-2019.10源码分析。

4.2 初步修改源码

4.2.1 关看门狗、关中断、配置MPLL

在分析源码的过程中,不难发现,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的程序注释掉。

4.2.2 初始化sdram

由于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

4.2.3 初始化串口

为了能在运行移植后的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
	......
}

4.2.4 烧写程序并调试

至此,我们保存上述修改,然后编译、烧写,看看做了上述修改后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.3 修改程序以支持Nand启动

根据本文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启动。

4.4 修改程序以支持NorFlash

目前我们的u-boot可以从NorFlash启动,但未能支持NorFlash,注意两者的区别:从NorFlash启动只需要读NorFlash就可以了,而u-boot提供了一些命令如mwerase,这些命令需要写/擦除NorFlash。NorFlash是不能随机写的,只能通过特定的操作序列来实现擦除、写等功能。而不同型号的NorFlash所需要的操作序列可能不同,所以u-boot不太可能不需要任何修改就支持我们所使用的NorFlash,毕竟选择什么型号的NorFlash不是u-boot决定的,而我们至少要通过某种方式(u-boot提供的某种机制)把我们所用的NorFlash的一些信息告诉u-boot。那么到底要做哪些修改呢?且看移植u-boot-2019.10到jz2440——修改程序以支持NorFlash。

4.5 修改程序以支持DM9000C网卡

通过分析源码可以获知,当前u-boot使用的网卡驱动是CS8900的驱动,而jz2440实际使用的网卡是DM9000C,因此当前网卡是无法使用的,与网卡相关的一些好用的功能,比如通过tftp下载程序这些都无法使用。现在我们就修改程序来支持网卡:移植u-boot-2019.10到jz2440——修改程序以支持DM9000C网卡。

4.6 修改程序以支持NandFlash

当前我们移植的u-boot已经可以从NandFlash启动了,但还不支持一些NandFlash相关的命令,比如nand read/write等。这是因为NandFlash相关的程序是我们直接从SMDK2410那里拷贝来的,尚未经过修改,不适合jz2440。现在我们就修改程序来支持NandFlash:移植u-boot-2019.10到jz2440——修改程序以支持NandFlash。

4.7

4.8

参考文献

[1] 韦东山老师二期视频教程
[2] u-boot 2015.01 :has EABI version 0, but target u-boot has EABI version 4
[3] 游戏进行中的博客

你可能感兴趣的:(嵌入式Linux-u-boot)