Bootloader移植

​ —本文所有所需资源都可以到电子资源页中去找到下载。

开发环境

开发机:Ubuntu 20.04(虚拟机)

开发板:三星exynos-4412 fs4412核心板+华清远见外设板(armv7)

u-boot是Bootloader的一种,u-boot是一个开源的软件。

概述

对于Bootloader移植,一般步骤如下:

  • 对照
    1. 找到官方发布的源码,这里我们使用的是u-boot引导程序,所以就找官方发布的引导程序。
    2. 找到和该开发板类似的型号的u-boot,使用对比工具来对比,可以更快的了解那些地方需要修改。
  • 更改ARCH
    1. 因为该开发板是armv7,所以先去官方的u-boot是否支持该架构,查找路径arch/arm/cpu/armv7
  • 修改Board
    1. 确认开发板信息,我们这里是fs4412
    2. board中查找是否有我们这款型号,有最好。若没有,则找一款类似的。
    3. fs4412和三星的origen板子类似,所以我们就参考这个origen文件加来进行修改board的信息。

移植

准备工作

下载u-boot :u-boot-2013.01.tar.bz2

拷贝u-boot到某个开发目录下 cp u-boot-2013.01.tar.bz2 ~/workspace/fs4412

进入该目录并解压

cd ~/workspace/fs4412
tar xf u-boot-2013.01.tar.bz2
cd u-boot-2013.01

借鉴

借鉴origen板子的信息:  find . -name origen*

拷贝板子头文件信息:
cp include/configs/origen.h include/configs/fs4412.h

拷贝并且修改板级文件:
cp board/samsung/origen/ board/samsung/fs4412 -afr
mv board/samsung/fs4412/origen.c board/samsung/fs4412/fs4412.c

修改board/samsung/fs4412/Makefile的目标文件:
vim board/samsung/fs4412/Makefile	
将31行的 origen.o 修改为 fs4412.o


修改u-boot目录下板级配置文件 boards.cfg
在origen后面添加新行
40 # Target                     ARCH        CPU         Board name          Vendor         SoC         Options
41 ###########################################################################################################

284 origen                       arm         armv7       origen              samsung        exynos
285 fs4412                       arm         armv7       fs4412              samsung        exynos
修改这个cfg文件,然我们的makefile知道有这个板子的存在

重新编译

烧写到emmc启动开发板,
make distclean						//清除原有的配置文件和生产的文件
make fs4412_config					//添加现有板子的配置文件
make 								//编译uboot
-->生产u-boot.bin
cp u-boot.bin /tftpboot		//将生成的u-boot.bin拷贝到tftp共享文件中;

将拨码开关拨到100x SD启动
#tftp 41000000 u-boot.bin			//在目标机上下载u-boot到41000000
#movi write u-boot 41000000			//将41000000地址空间的数据写入到uboot对应的位置

将拨码开关拨到011x emmc启动
观察现象:串口没有数据输出,板子没有任何反应;

解决问题

通过上面的步骤发现有问题,板子没有任何反应,该怎么办?

这里我们就要引入排错方法。

在C语言中,我们排错办法有:调试工具GDB输出打印信息等方法。但是现在是裸机,u-boot还是裸机阶段,没有操作系统已经部分硬件的支持,那我们怎么进行排错呢。最简单的方法,我们使用电灯法。在ARM阶段,我们以及使用过汇编去进行点亮开发板上的灯(点灯代码如下)

         /* led on */
         ldr r0, =0x11000c40 @GPK2_7 led2
         ldr r1, [r0]
         bic r1, r1, #0xf0000000
         orr r1, r1, #0x10000000
         str r1, [r0]
 
        ldr r0, =0x11000c44
        mov r1,#0xff
        str r1, [r0]

我们在u-boot的开头放入上面的代码,可以看到我们的u-boot程序是否正确的启动。

u-boot的启动流程,以及如何找到u-boot程序的入口

如何找到程序入口,以及流程可以看上面的文章。

再加入点灯代码后,重新编译make生成u-boot.bin,然后cp u-boot.bin /tftpboot重新断点,再上点看板子的反应。

发现灯还没有亮,说明一个问题,那就是我们程序没有正确进入u-boot程序中,说明再进入前以及被,某个东西打断了,倒是无法进入系统。那该怎么板。现在以及缩小范围了!

对于嵌入式开发,特别是硬件,我们一定要多看芯片手册,里面会写的非常详细。RTFM!

所以我们去看FS4412的芯片手册

查看芯片手册,看启动流程,需要添加启动代码:BL1、BL2

1) 将CodeSign4SecureBoot 三星提供的安全启动方式拷贝uboot的目录中;

2)	进入到CodeSign4SecureBoot目录中修改build.sh文件中cp对应行
cp u.bin /tftpboot 

3) 重新编译 执行build.sh
因为需要三星提供的BL1,BL2方法,所以我们就是用一个编译好的脚本去添加所需方法,以及make操作
将产生的u.bin拷贝到tftp共享文件中;

4) 通过sd启动方式将uboot烧写到emmc
将拨码开关拨到100x SD启动
#tftp 41000000 u.bin				//在目标机上下载u-boot到41000000
#movi write u-boot 41000000			//将41000000地址空间的数据写入到uboot对应的位置

5) 通过emmc启动开发板
将拨码开关拨到011x emmc启动
观察现象:串口没有数据输出,led亮了,等一会灭了,又亮了,在等会led亮了,等一会灭了

由于我们的电灯代码是放在_reset:中的,所以系统一定是受到了某些中断从而不断复位。还记得u-boot的启动流程,他首先会关闭非必硬件对吧,那我们的代码是不是没有关闭呢。我觉得应该是没有的,所以我们进行如下操作,来解决启动时的问题。(这里网上搜索到说的好像是因为没有关闭这些非必要外设会导致电路温度过高,从而导致温度过高导致重启)

解决办法如下

@添加电源管理相关代码,关闭看门狗

1) 代码修改
vim arch/arm/cpu/armv7/start.S中添加	
/*for close watchdog */    
/* PS-Hold high */
ldr r0, =0x1002330c    /*PS_HOLD_CONTROL*/
ldr r1, [r0]
orr r1, r1, #0x300
str r1, [r0]         
ldr     r0, =0x11000c08
ldr r1, =0x0             /*Disables Pull-up/Pull-down*/
str r1, [r0]
/* Clear  MASK_WDT_RESET_REQUEST  */
ldr r0, =0x1002040c
ldr r1, =0x00
str r1, [r0]

2) 重新编译:
cd CodeSign4SecureBoot
./build.sh
--> 生成的u.bin文件存储在tftp共享文件中

3) 通过sd启动方式将uboot烧写到emmc
将拨码开关拨到100x SD启动
#tftp 41000000 u.bin				//在目标机上下载u-boot到41000000
#movi write u-boot 41000000			//将41000000地址空间的数据写入到uboot对应的位置

4) 通过emmc启动开发板
将拨码开关拨到011x emmc启动	

运行结果:led常亮(说明uboot正常执行),但是串口依然没有数据输出;

u-boot的启动流程一文中我提到过在串口通信前有一个步骤,那就是初始化时钟。

添加串口时钟初始化代码:board/samsung/fs4412/lowlevel_init.S
vim board/samsung/fs4412/lowlevel_init.S

在串口初始化代码中的
str     r1, [r0, #EXYNOS4_GPIO_A1_CON_OFFSET]
后面添加
         /* 添加串口相关的时钟初始化 */
         ldr     r0, =EXYNOS4_CLOCK_BASE      /*system_clock_init*/
 
         ldr     r1, =CLK_SRC_PERIL0_VAL		 /*uart[0:4]*/
         ldr     r2, =CLK_SRC_PERIL0_OFFSET
         str     r1, [r0, r2]
 
         ldr     r1, =CLK_DIV_PERIL0_VAL		 /*uart clock divisors*/
         ldr     r2, =CLK_DIV_PERIL0_OFFSET
         str     r1, [r0, r2]
并且把串口初始化后面的
#if 0
90		bl tzpc_init 
#endif
屏蔽掉

重新编译:
	cd CodeSign4SecureBoot
	./build.sh
	--> 生成的u.bin文件存储在tftp共享文件中
	
通过sd启动方式将uboot烧写到emmc
    将拨码开关拨到100x SD启动
    #tftp 41000000 u.bin				//在目标机上下载u-boot到41000000
    #movi write u-boot 41000000			//将41000000地址空间的数据写入到uboot对应的位置

通过emmc启动开发板
	将拨码开关拨到011x SD启动		

网卡移植

1、 添加网络初始化代码

$vim  board/samsung/fs4412/fs4412.c

在struct exynos4_gpio_part2 *gpio2; 后添加
    
#ifdef CONFIG_DRIVER_DM9000
#define EXYNOS4412_SROMC_BASE 0X12570000
#define DM9000_Tacs   (0x1) 
#define DM9000_Tcos   (0x1) 
#define DM9000_Tacc   (0x5) 
#define DM9000_Tcoh   (0x1) 
#define DM9000_Tah   (0xC) 
#define DM9000_Tacp   (0x9)  
#define DM9000_PMC   (0x1) 
struct exynos_sromc {
unsigned int bw;
unsigned int bc[6];
};
/*

 \* s5p_config_sromc() - select the proper SROMC Bank and configure the

 \* band width control and bank control registers

 \* srom_bank  - SROM

 \* srom_bw_conf - SMC Band witdh reg configuration value

 \* srom_bc_conf - SMC Bank Control reg configuration value

 */
void exynos_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf)
{
unsigned int tmp;
struct exynos_sromc *srom = (struct exynos_sromc *)(EXYNOS4412_SROMC_BASE);
/* Configure SMC_BW register to handle proper SROMC bank */
tmp = srom->bw;
tmp&= ~(0xF << (srom_bank * 4));
tmp |= srom_bw_conf;
srom->bw = tmp;
/* Configure SMC_BC register */
srom->bc[srom_bank] = srom_bc_conf;
}
static void dm9000aep_pre_init(void)
{
unsigned int tmp;
unsigned char smc_bank_num = 1;
unsigned int   smc_bw_conf=0;
unsigned int   smc_bc_conf=0;
/* gpio configuration */
writel(0x00220020, 0x11000000 + 0x120);
writel(0x00002222, 0x11000000 + 0x140);
/* 16 Bit bus width */
writel(0x22222222, 0x11000000 + 0x180);
writel(0x0000FFFF, 0x11000000 + 0x188);
writel(0x22222222, 0x11000000 + 0x1C0);
writel(0x0000FFFF, 0x11000000 + 0x1C8);
writel(0x22222222, 0x11000000 + 0x1E0);
writel(0x0000FFFF, 0x11000000 + 0x1E8);       
smc_bw_conf &= ~(0xf<<4);
smc_bw_conf |= (1<<7) | (1<<6) | (1<<5) | (1<<4);
smc_bc_conf = ((DM9000_Tacs << 28)
    | (DM9000_Tcos << 24)
    | (DM9000_Tacc << 16)
    | (DM9000_Tcoh << 12)
    | (DM9000_Tah << 8)
    | (DM9000_Tacp << 4)
    | (DM9000_PMC));
exynos_config_sromc(smc_bank_num,smc_bw_conf,smc_bc_conf);

}
#endif

在gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); 后添加
#ifdef CONFIG_DRIVER_DM9000
dm9000aep_pre_init();
#endif

// 在文件末尾添加
#ifdef CONFIG_DRIVER_DM9000
int board_eth_init(bd_t *bis)                         
{   
return dm9000_initialize(bis);                      
} 
#endif

2、 修改配置文件添加网络相关配置

$ vim  include/configs/fs4412.h
修改
#undef CONFIG_CMD_PING
为
#def ine CONFIG_CMD_PING
修改
#undef CONFIG_CMD_NET 
为
#def ine CONFIG_CMD_NET
在文件末尾
#ifdef CONFIG_CMD_NET
#define CONFIG_NET_MULTI
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE  0x05000000
#define DM9000_IO             CONFIG_DM9000_BASE
#define DM9000_DATA           (CONFIG_DM9000_BASE + 4)
#define CONFIG_DM9000_USE_16BIT
#define CONFIG_DM9000_NO_SROM 1
#define CONFIG_ETHADDR         11:22:33:44:55:66
#define CONFIG_IPADDR          192.168.12.25
#define CONFIG_SERVERIP     192.168.12.113
#define CONFIG_GATEWAYIP    192.168.12.1
#define CONFIG_NETMASK         255.255.255.0
#endif

3、 重新进入CodeSign4SecureBoot编译u-boot**

$ ./build.sh 

​    烧写新的u.bin

​    复位后

\# ping 192.168.9.120

img

EMMC移植

EMMC移植参考电子资源中的EMMC,里面有EMMC的操作手册