基于tiny6410开发板移植官方uboot详解

1. 前言

本来友善支臂有提供tiny6410的移植好uboot源代码,但是本着学习的态度,总是希望能够自己开始从零开始,一步步自己实现uboot的移植,这样更能了解uboot的编程思想,也能更能了解硬件启动的原理。今后换了硬件平台,脱离了友善支臂,也能够自己独当一面,而不是单纯的复制粘贴。
本文将以最小化修改来达到移植目的。本次移植工程已托管到github,可通过查看提交记录,了解每个步骤的目的与修改了哪些文件

2. 移植的uboot目标版本选择

首次移植应降低难度,应选择与tiny6410最为接近的开发板进行移植,官方uboot中已经包含了诸多三星公司芯片的开发板,其中与tiny6410最为接近的为smdk6400。

下载uboot源代码,可直接克隆u-boot的代码仓库,或者直接在官网直接下载u-boot-v2013.01版本的压缩包,该版本我通过版本库查看,这是支持smdk6400开发板的最后一个版本,后续版本smdk6400就被删了。选择最后一个版本也是因为更加的稳定。

# 克隆uboot仓库
git clone git://www.denx.de/git/u-boot.git

# 检出需要的目标版本
git checkout v2013.01

3. 编译器的选择

我的编译器版本是:gcc-arm-linux-gnueabi version 4.3.2 (Sourcery G++ Lite 2008q3-72)
本来我的电脑已经安装了v6.3.0版本,但是编译时,会产生错误,缺少文件,如下

/home/eric/linux-develop/u-boot/include/linux/compiler-gcc.h:87:30: fatal error: linux/compiler-gcc6.h: 没有那个文件或目录
 #include gcc_header(__GNUC__)

这里我先不管编译器的问题,在网上下载了个v4版本的,编译就可以了。后续再试试高版本的能不能行,以防止后续由于编译器的问题出现更多的坑。

环境变量设置:将环境变量设置添加的bashrc文件中,避免每次使用都要设置

vim ~/.bashrc
# 尾部增加如下语句

# 将编译器安装路径添加到PATH
PATH=$PATH:/usr/local/arm/4.3.2/bin/
# 设置交叉编译命令前缀
CROSS_COMPILE=arm-linux-
# 导出环境变量
export CROSS_COMPILE PATH

4. sdmk6400工程编译问题

这里先确保sdmk6400工程能够编译通过,再进行后续的移植工作。
步骤如下:

cd u-boot/
# 清理工程目录
make distclean
# 开发板配置
make smdk6400_config
# 配置日志
eric@eric-PC:~/linux-develop/u-boot$ make smdk6400_config

warning: Please migrate to boards.cfg.  Failure to do so will
         mean removal of your board in the next release.

Configuring for smdk6400 board...

# 编译
make

4.1 u-boot.lds文件修改

首次编译工程,会报告如下错误

# 官方工程,此时编译会报告错误,日志如下:
arm-linux-ld:u-boot.lds:19: syntax error
Makefile:568: recipe for target 'u-boot' failed
make: *** [u-boot] Error 1

日志报告,u-boot.lds中存在语法错误,这是一个问题,打开u-boot.lds第19行,发现链接文件中存在几处对齐小写的align,而大写的ALIGN才是合法的,因此需要将链接文件的中align修改为全大写格式。

 . = ALIGN(4);
 .got : { *(.got) }
 . = align(4);

但并不是修改工程根目录下的u-boot.lds,此处的u-boot.lds也是从别处拷贝过来的,拷贝的源头可查看Makefile中以下语句

# If there is no specified link script, we look in a number of places for it
ifndef LDSCRIPT
	ifeq ($(CONFIG_NAND_U_BOOT),y)
		LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
		ifeq ($(wildcard $(LDSCRIPT)),)
			LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-nand.lds
		endif
	endif
	ifeq ($(wildcard $(LDSCRIPT)),)
		LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
	endif
	ifeq ($(wildcard $(LDSCRIPT)),)
		LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot.lds
	endif
	ifeq ($(wildcard $(LDSCRIPT)),)
		LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot.lds
		# We don't expect a Makefile here
		LDSCRIPT_MAKEFILE_DIR =
	endif
	ifeq ($(wildcard $(LDSCRIPT)),)
$(error could not find linker script)
	endif
endif

本项目中应该修改board/samsung/smdk6400/u-boot-nand.lds文件,将align更改为ALIGN.

4.2 nand_spl文件夹下Makefile文件修改

链接脚本修改完成后,再次make进行编译,会出现如下错误,提示"_main"未定义

start.o: In function `cpu_init_crit':
/home/eric/linux-develop/u-boot/nand_spl/board/samsung/smdk6400/start.S:227: undefined reference to `_main'
Makefile:59: recipe for target '/home/eric/linux-develop/u-boot/nand_spl/u-boot-spl' failed
make[1]: *** [/home/eric/linux-develop/u-boot/nand_spl/u-boot-spl] Error 1
make[1]: Leaving directory '/home/eric/linux-develop/u-boot/nand_spl/board/samsung/smdk6400'
Makefile:602: recipe for target 'nand_spl' failed
make: *** [nand_spl] Error 2

这时,需要修改nand_spl/board/samsung/smdk6400/Makefile文件

修改前
SOBJS   = start.o cpu_init.o lowlevel_init.o
修改后,添加crt0.o
SOBJS	= start.o cpu_init.o lowlevel_init.o crt0.o

在start.S目标底下添加crt0.S目标
# from cpu directory
$(obj)start.S:
	@rm -f $@
	@ln -s $(TOPDIR)/arch/arm/cpu/arm1176/start.S $@
	
# 以下为新增规则,链接crt0.S
$(obj)crt0.S:
	@rm -f $@
	@ln -s $(TOPDIR)/arch/arm/lib/crt0.S $@

4.2 crt0.S文件修改

Makefile文件修改后,再次编译,会出现如下错误

crt0.o: In function `clbss_l':
/home/eric/linux-develop/u-boot/nand_spl/board/samsung/smdk6400/crt0.S:153: undefined reference to `coloured_LED_init'
/home/eric/linux-develop/u-boot/nand_spl/board/samsung/smdk6400/crt0.S:154: undefined reference to `red_led_on'
Makefile:59: recipe for target '/home/eric/linux-develop/u-boot/nand_spl/u-boot-spl' failed
make[1]: *** [/home/eric/linux-develop/u-boot/nand_spl/u-boot-spl] Error 1
make[1]: Leaving directory '/home/eric/linux-develop/u-boot/nand_spl/board/samsung/smdk6400'
Makefile:602: recipe for target 'nand_spl' failed
make: *** [nand_spl] Error 2

修改arch/arm/lib/crt0.S添加如下宏定义,可以解决该问题

#ifndef CONFIG_NAND_SPL
	bl coloured_LED_init		bl coloured_LED_init
	bl red_led_on		bl red_led_on
#endif

至此,smdk6400工程编译就不会出现报错现象。可进入下一步tiny6410移植。

5. tiny6410开发板相关目录文件建立

先清理工程目录,执行make distclean

5.1 项目根目录Makefile文件修改

参考以下内容,建立tiny6410配置目标规则

smdk6400_noUSB_config	\
smdk6400_config	:	unconfig
	@mkdir -p $(obj)include $(obj)board/samsung/smdk6400
	@mkdir -p $(obj)nand_spl/board/samsung/smdk6400
	@echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
	@if [ -z "$(findstring smdk6400_noUSB_config,$@)" ]; then			\
		echo "RAM_TEXT = 0x57e00000" >> $(obj)board/samsung/smdk6400/config.tmp;\
	else										\
		echo "RAM_TEXT = 0xc7e00000" >> $(obj)board/samsung/smdk6400/config.tmp;\
	fi
	@$(MKCONFIG) smdk6400 arm arm1176 smdk6400 samsung s3c64xx
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk

添加以下内容

tiny6410_noUSB_config	\
tiny6410_config	:	unconfig
	@mkdir -p $(obj)include $(obj)board/samsung/tiny6410
	@mkdir -p $(obj)nand_spl/board/samsung/tiny6410
	@echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
	@if [ -z "$(findstring tiny6410_noUSB_config,$@)" ]; then			\
		echo "RAM_TEXT = 0x57e00000" >> $(obj)board/samsung/tiny6410/config.tmp;\
	else										\
		echo "RAM_TEXT = 0xc7e00000" >> $(obj)board/samsung/tiny6410/config.tmp;\
	fi
	@$(MKCONFIG) tiny6410 arm arm1176 tiny6410 samsung s3c64xx
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk

5.2 include/configs/tiny6410.h开发板配置文件建立

cd include/configs/
cp smdk6400.h tiny6410.h

5.3 board目录下文件建立

cd board/samsung/

# 拷贝文件夹
cp -r smdk6400/ tiny6410/

# 文件更名
mv smdk6400.c tiny6410.c
mv smdk6400_nand_spl.c tiny6410_nand_spl.c

# 修改Makefile文件,将smdk6400.o替换为tiny6410.o
vim Makefile

5.4 nand_spl目录下文件建立

cd nand_spl/board/samsung/

# 拷贝文件夹
cp -r smdk6400/ tiny6410/

# 修改Makefile文件,将smdk6400全部替换为tiny6410
vim Makefile
# 可使用以下命令进行替换
:1,$s/smdk6400/tiny6410/g

至此,文件建立完成,可以试下编译是否成功,编译不成功,一般为文件名与Makefile中的依赖不对应

# 配置
make tiny6410_config
# 编译
make

6. uboot工程代码修改

6.1 第一步,将UBOOT跑起来

6.1.1 board/samsung/tiny6410/lowlevel_init.S文件修改

该文件需要修改LED点亮代码,与时钟系统配置代码

<1> LED灯显示,方便初期调试,4个LED,这里设置为间隔点亮

 lowlevel_init:
	mov	r12, lr

	/* LED */
	ldr	r0, =ELFIN_GPIO_BASE
	ldr	r1, =0x11110000
	str	r1, [r0, #GPKCON0_OFFSET]

	ldr	r1, =0x5555aa55
	str	r1, [r0, #GPKPUD_OFFSET]

	ldr	r1, =0x000000a0
	str	r1, [r0, #GPKDAT_OFFSET]

<2> 时钟系统配置修改
以下代码在lowlevel_init.S文件185~200行之间,该部分代码本可以修改配置文件tiny6410.h中的CONFIG_S3C6400宏定义,但是该宏多处地方使用,为减少目前的移植工作,可直接将以下代码中的预编译命令删除。

#ifndef CONFIG_S3C6400  /* 此行删除 */    
	ldr	r1, [r0, #OTHERS_OFFSET]
	bic	r1, r1, #0xC0
	orr	r1, r1, #0x40
	str	r1, [r0, #OTHERS_OFFSET]

wait_for_async:
	ldr	r1, [r0, #OTHERS_OFFSET]
	and	r1, r1, #0xf00
	cmp	r1, #0x0
	bne	wait_for_async
#endif  /* 此行删除 */

6.1.2 arch/arm/include/asm/arch-s3c64xx/s3c6400.h文件修改

修改APLL, MPLL分频系数

// 775~779行
#elif defined(CONFIG_CLK_533_133_66)
#define STARTUP_AMDIV		266
#define STARTUP_MDIV		266
#define STARTUP_PDIV		3
#define STARTUP_SDIV		1

6.1.3 drivers/serial/s3c64xx.c 文件修改

这部分为串口功能的修改,这部分原理上是不需要修改的,但是由于我这边目前是使用友善之臂提供的uboot将本次移植的uboot下载到DRAM中直接运行,但由于友善之臂uboot串口所使用的使用,与本uboot时钟不同,且根据s3c6410芯片手册上描述了,时钟切换的特殊要求,因此需要做出如下修改:

static int s3c64xx_serial_init(void)
{
	s3c64xx_uart *const uart = s3c64xx_get_base_uart(UART_NR);

	/* reset and enable FIFOs, set triggers to the maximum */
	uart->UFCON = 0xff;
	uart->UMCON = 0;
	/* 8N1 */
	uart->ULCON = 3;
	/* No interrupts, no DMA, pure polling */
	if (uart->UCON & 0xC00 == 0xC00)
		uart->UCON = (2<<10) | 0x5;
	else
		uart->UCON = 5;

	serial_setbrg();

	return 0;
}

在S3C6410数据手册中,关于串口波特率时钟描述有如下一段,

  • 当串口波特率时钟从EXT_UCLK0切换到PCLK时,时钟设置需设置为2‘b00
  • 当串口波特率时钟从EXT_UCLK1切换到PCLK时,时钟设置需设置为2‘b10

When you want to change EXT_UCLK0 to PCLK for UART baudrate , clock selection field must be set to 2’b00. But, when you want to change EXT_UCLK1 to PCLK for UART baudrate , clock selection field must be set to 2’b10.

因为之前的uboot所使用的时钟为EXT_UCLK1,因此在本uboot中对UCON寄存器的设置,时钟选择需设置为2’b10

6.1.4 uboot地址修改

将uboot链接地址由0x57e00000修改到0x50000000,这样方便下载到DRAM后,可以直接运行uboot,方便前期调试
<1> uboot根目录Makefile修改链接地址

tiny6410_config	:	unconfig
	@mkdir -p $(obj)include $(obj)board/samsung/tiny6410
	@mkdir -p $(obj)nand_spl/board/samsung/tiny6410
	@echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
	@if [ -z "$(findstring tiny6410_noUSB_config,$@)" ]; then			\
		echo "RAM_TEXT = 0x50000000" >> $(obj)board/samsung/tiny6410/config.tmp;\
	else										\
		echo "RAM_TEXT = 0xc0000000" >> $(obj)board/samsung/tiny6410/config.tmp;\
	fi
	@$(MKCONFIG) tiny6410 arm arm1176 tiny6410 samsung s3c64xx
	@echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk

<2> 配置文件tiny6410.h修改宏定义

#define CONFIG_SYS_PHY_UBOOT_BASE	(CONFIG_SYS_SDRAM_BASE + 0)
#define CONFIG_SYS_UBOOT_BASE		(CONFIG_SYS_MAPPED_RAM_BASE + 0)

至此,将uboot工程编译,并下载DRAM,并go 50000000;然后uboot串口就会输出一些调试信息,说明uboot已经开始运行起来了。虽然还有一些问题,但后续会一步一步解决。

uboot启动日志
## Starting application at 0x50000000 ...                                         
                                                                                  
                                                                                  
U-Boot 2013.01-00008-ga1e7b04d3d (Mar 18 2020 - 19:54:29) for TINY6410            
                                                                                  
                                                                                  
CPU:     S3C6400@532MHz                                                           
         Fclk = 532MHz, Hclk = 133MHz, Pclk = 66MHz (ASYNC Mode)                  
Board:   TINY6400                                                                 
DRAM:  128 MiB                                                                    
WARNING: Caches not enabled                                                       
Flash: *** failed ***                                                             
### ERROR ### Please RESET the board ###

6.2 第二步,将UBOOT正常运行

6.2.1 Flash驱动代码关闭

在上一节中,uboot启动日志中报告FLASH错误。查看代码,错误原因是在flash_init()调用中返回flash_size=0,导致后续的代码判断进行系统报错与挂起。由于tiny6410中并未用到norflash,因此可以将Flash驱动代码关闭。

<1> tiny6410.h文件中修改

/* 添加以下宏定义,配置系统无NOR FLASH */
#define CONFIG_SYS_NO_FLASH			/* 该宏需要定义在 #include <config_cmd_default.h> 这条语句前即可 */

/* 注释或删掉以下定义 */
#define CONFIG_SYS_MAX_FLASH_BANKS	1	/* max number of memory banks	*/
#define CONFIG_SYS_MAX_FLASH_SECT	40
#define CONFIG_AMD_LV800
#define CONFIG_SYS_FLASH_CFI		1	/* Use CFI parameters (needed?) */
#define CONFIG_FLASH_CFI_DRIVER	1
#define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_16BIT
#define CONFIG_FLASH_CFI_LEGACY
#define CONFIG_SYS_FLASH_LEGACY_512Kx16

<2> tiny6410.c文件中修改
以下代码删除或注释

ulong board_flash_get_legacy (ulong base, int banknum, flash_info_t *info)
{
	if (banknum == 0) {	/* non-CFI boot flash */
		info->portwidth = FLASH_CFI_16BIT;
		info->chipwidth = FLASH_CFI_BY16;
		info->interface = FLASH_CFI_X16;
		return 1;
	} else
		return 0;
}

编译,下载,运行

## Starting application at 0x50000000 ...                                         
                                                                                
U-Boot 2013.01-00008-ga1e7b04d3d-dirty (Mar 18 2020 - 20:21:41) for TINY6410      
                                                                                  
CPU:     S3C6400@532MHz                                                           
         Fclk = 532MHz, Hclk = 133MHz, Pclk = 66MHz (ASYNC Mode)                  
Board:   TINY6400                                                                 
DRAM:  128 MiB                                                                    
WARNING: Caches not enabled                                                       
NAND:  raise: Signal # 8 caught                                                   
raise: Signal # 8 caught                                                          
raise: Signal # 8 caught                                                          
raise: Signal # 8 caught                                                          
raise: Signal # 8 caught                                                          
raise: Signal # 8 caught                                                          
raise: Signal # 8 caught                                                          
raise: Signal # 8 caught                                                          
256 MiB                                                                           
*** Warning - bad CRC, using default environment                                  
                                                                                  
In:    serial                                                                     
Out:   serial                                                                     
Err:   serial                                                                     
Net:   CS8900-0                                                                   
Hit any key to stop autoboot:  0

6.2.2 修复raise: Signal # 8 caught问题

该问题解决参考了这里,同时对比了本工程文件(arch/arm/cpu/arm920t/s3c24x0/timer.c)

本次主要在arch/arm/cpu/arm176/s3c64xx/timer.c进行了一些变量替换,如下:

  • 添加全局数据变量定义DECLARE_GLOBAL_DATA_PTR
  • timer_load_val替换为gd-tbu
  • lastdec替换为gd->lastinc
  • timestamp替换为gd->tbl

修改内容查看


至此,uboot运行就不会出现有异常问题了。

6.3 第三步,网络功能移植

工程中目前所使用的网卡是cs8900,而tiny6410中使用的是dm9000网卡。因此后续需要修改一些内容以支持dm9000网卡功能。
<1> tiny6410.h文件修改

#define CONFIG_CS8900			/* we have a CS8900 on-board	*/
#define CONFIG_CS8900_BASE	  	0x18800300
#define CONFIG_CS8900_BUS16		/* follow the Linux driver	*/

/* 将上面的定义替换为下面这些内容 */

#define CONFIG_DM9000
#define CONFIG_DRIVER_DM9000
#define CONFIG_DM9000_BASE				0x18000300
#define DM9000_IO 						CONFIG_DM9000_BASE
#define DM9000_DATA						(CONFIG_DM9000_BASE+4)

/*
 * U-Boot 网络环境变量定义
 */
#define CONFIG_ETHADDR		08:90:90:90:90:90
#define CONFIG_IPADDR		192.168.1.100
#define CONFIG_SERVERIP		192.168.1.10
#define CONFIG_GATEWAYIP	192.168.1.10
#define CONFIG_NETMASK		255.255.255.0

<2> tiny6410.c文件修改
将cs8900初始化代码修改为dm9000的初始化代码
点击查看修改内容
可尝试使用ping、tftp命令来测试网络功能是否正常,注意ip地址设置需在同一网段。


至此,uboot已经可以实现大部分常用的已经实现了。

7. nand_spl代码修改

SPL(Secondary Program Loader)是指开发板启动后的第二阶段阶段运行程序,它会被三星公司固化的启动代码BL0拷贝到stepping stone中运行,它的功能是将主体的uboot拷贝到DRAM中,并跳转到目标地址运行。

<1> arch/arm/lib/crt0.S文件修改
之前的编译已经编译出了这部分代码,位于nand_spl文件夹下,u-boot-spl.bin
但目前这部分代码无法正常运行,需要进行一些小的修改,打开arch/arm/lib/crt0.S,进行如下修改

#if defined(CONFIG_NAND_SPL)
	/* deprecated, use instead CONFIG_SPL_BUILD */
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
	b	here				/* 添加这行,跳过后面的代码重定向,直接配置c运行环境,然后运行nand_boot */
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	sp, =(CONFIG_SPL_STACK)
#else
	ldr	sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif

-------------

#if defined(CONFIG_NAND_SPL)
	/* call _nand_boot() */
	b	nand_boot		/* 使用b命令相对跳转,防止由于链接地址问题导致无法正确跳转 */
#else

<2> tiny6410.h文件修改uboot镜像大小
并修改tiny6410.h中的以下宏定义,根据u-boot.bin的大小修改,不能小于u-boot.bin的实际大小。我这里设置大小为254k

#define CONFIG_SYS_NAND_U_BOOT_SIZE	(254 * 1024)	/* Size of RAM U-Boot image   */

8. 更新nand flash中的uboot镜像

nand flash中的区域分布如下

u-boot-spl.binu-boot.binenvkernelrootfs
固定4k254k默认16k--

<1> 下载镜像
注意u-boot.bin的地址偏移为4k

tftp 50000000 u-boot-spl.bin
tftp 50001000 u-boot.bin

<2> 将镜像保存到nand flash
擦除大小需要根据u-boot.bin的大小,我这假设u-boot.bin大小为254k

# nand flash擦除
nand erase 0 40800

# nand flash 写入
nand write 50000000 0 40800

至此,就实现了对友善之臂uboot的替代,重新上电看看是否能够正常运行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值