目录
一、uboot源码结构
1.1 uboot源码获取
1.2 uboot的特点
1.3 uboot源码结构
二、uboot配置与编译
2.1uboot配置
2.2 uboot编译
三、uboot移植
3.1添加board信息
3.2再次配置和编译
3.3添加三星加密引导程序
3.4添加调制代码(点灯法)
3.5添加编译脚本
3.6测试uboot
3.7修改UART源码
3.8修改网络初始代码
3.9修改网络配置代码
3.10修改emmc初始代码
3.11添加emmc命令
3.12修改emmc配置代码
3.13修改电源管理相关代码
百度百科-验证
一、uboot源码结构
1.1 uboot源码获取
uboot是一个开源的软件。开源有两层含义。一是可以免费用、二是开放源代码
http://www.denx.de/wiki/U-Boot/
直接百度搜uboot这个就能下载。
或者进入上面那个链接我们进入它的官网下载,uboot是德国一个小组做的。
现在貌似被GitHub管理起来了,反正直接搜索还是去官网他的下载路径都是GitHub的具体什么原因不清楚,这个历史问题和学习无关我们能用就行。
对于不会英语的人很不友好,下载都找不到怎么下建议使用下面链接
uboot官方下载地址,无需密码
Index of /pub/u-boot/
或者:
ftp://ftp.denx.de/pub/u-boot/
前期:uboot-1.2.3
现在:uboot-2008.01
08年以前uboot是1.2.几1.3.几这样命名08年开始以年份和月份命名。
它的更新是非常频繁的上次更新是两天前。
支持对应的硬件平台
相对成熟的版本(资料多)
每当发布新的芯片后uboot就会增加对应芯片的版本。一般和处理器同一时期发布的uboot版本对处理器的支持较好。
1.2 uboot的特点
VxWorks 操作系统是美国WindRiver公司于1983年设计开发的一种嵌入式 实时操作系统(RTOS),是嵌入式开发环境的关键组成部分。良好的持续发展能力、高性能的内核以及友好的用户开发环境,在嵌入式实时操作系统领域占据一席之地。它以其良好的可靠性和卓越的实时性被广泛地应用在通信、军事、航空、 航天等高精尖技术及实时性要求极高的领域中,如卫星通讯、 军事演习、弹道制导、飞机导航等。在美国的 F-16、FA-18战斗机、 B-2 隐形轰炸机和 爱国者导弹上,甚至连1997年4月在火星表面登陆的 火星探测器、2008年5月登陆的凤凰号,和2012年8月登陆的好奇号也都使用到了VxWorks。
1.3 uboot源码结构
即与CPU架构或开发板硬件相关的源码,硬件的改动对应的代码也需要进行修改
arch:与CPU架构相关的源代码
board:与开发板相关的源代码,包含各种官方评估板对应的源码
api: 这个目录下有很多的用户接口
arch: 目录下存储的是架构
这里有很多的架构如果我们使用的arm那么剩下的就可以都删了
在cpu这个文件夹下他又细分了很多的架构。我们使用的A9是V7架构的。
在使用时我们可以把arch目录除了V7外的其它文件夹内容都删掉。不过其实不删也行,编译的时候不编译它就行了。这里还有makefile文件官方给我们写好了。
board:这个目录下都是一些公司的名字比如三星、诺基亚、ST剩下的也不认识了哈哈。
在samsung的目录下我们看到还有很多的文件夹,这些就是三星出的一些机器。
但是这里不能把所有的公司出的开发板都包括,这里都是官方的评估版,评估版就是这些公司在新出一款芯片时为这款芯片做的测试的板子。这个origen就是exynos4412的评估板。不过我使用的板子是华清远见的所以在这里找不到。但是我们可以找和官方用一样芯片的评估板我们自己修改一下。
boards.cfg:这个文件是配置信息
common:这下面全是uboot命令的.c文件
config.mk:也是一个配置文件
COPYING:这是版权文件虽然是开源软件但是也不能乱用
CREDITS:这里是代码贡献者名单包括他们的邮箱,出了问题可以给他们发邮件问,但是也许不会回你,之前都是外国人我今天进GitHub发现贡献者前几名还有几个中国人。
disk:磁盘操作的命令文件夹
readme:一个说明书或者说帮助文档,这个说明书有5000多行都是一些介绍性的的东西。
dos:这里是详细的说明书
drivers:这里面全是驱动文件
dts:设备树文件夹,后面学习驱动时在详细学习。
examples:里面是例程,在不会写的时候可以参考一下
fs:文件系统,这里面每个文件夹内都是文件系统的源代码和makefile文件这里面ext4是嵌入式领域常用的文件系统。
include:这里是头文件
lib:这里是库
makefile:方便我们编译uboot镜像。它这个makefile是层层调用的每个文件夹下都有,使用make命令后总的makefile文件会调用每层的马克file文件来共同编译出uboot镜像。这个makefile文件非常的复杂。
post:上电自检程序
tools:工具
net:网络文件夹,这里面是uboot支持的一些网络。
剩下的都是无关紧要的,想要了解就看readme来学习。uboot的源码是非常复杂的想要修改要学习很长的时间。
二、uboot配置与编译
为了保证uboot适用所有的开发板,uboot把所有的开发板都写出来了,需要哪个编译哪个
2.1uboot配置
make <board_name>_config
注1:<board_name>为当前使用的开发板的名字
注2:执行该命令的前提是uboot源码支持该开发板
注3:该命令必须在uboot源码的顶层目录下执行
出现下面这种提示就是配置成功了。
在uboot源码顶层目录下的Makefile中指定(CROSS_COMPILE变量)
因为编译过程很复杂所有我们不可能自己去gcc编译。我们用官方写好的makefile就行。
但是我们要先指定编译器
打开顶层目录的makefile文件,搜索CROSS_COMPILE
我们加上arm的编译工具,不要加那个gcc因为在编译过程中不止需要gcc
因为它放在了if语句中,但是我们不知道那俩条件是什么所以改一下。
2.2 uboot编译
make
注1:该命令必须在uboot源码的顶层目录下执行
注2:该命令执行后在uboot源码顶层目录下生成u-boot.bin
编译需要大概一分钟。编译完多了几个文件
多了一个system.map文件和那些u-boot开头的。
make在编译的过程中先将.c和.s编译成.o文件。最后把他们链接(ld)成一个可执行文件绿色的那个u-boot。他是elf格式的。我们肯定不能把他刷到板子上。不过在这之后它还会用objcopy把利用elf文件生成bin文件。这里还有一个srec文件这是符合摩托罗拉的二进制文件。
make clean
make distclean
注1:该命令必须在uboot源码的顶层目录下执行
这些中间文件就是.o文件。执行make clean只是清除这些.o文件。执行下面那个会把生成的可执行文件和二进制文件也删除。恢复刚下载的源码状态。
三、uboot移植
因为uboot支持的只是官方的评估板,所以我们没法直接用。
因为咱们和origen的SOC一样都是exynos4412所以不需要修改arch目录的内容。
uboot就先不深入学习了,芯片厂家的开放程度不够,很少需要自己去配置,一般用三星或者全志的芯片都会给我们提供相关的uboot。而且uboot代码量太大了,我们要改就得把他的代码结构,实现过程,具体的代码都研究透。所以又来了一个可以研究一辈子的东西。
3.1添加board信息
拷贝出来一份不要破坏本来的程序
修改C文件名
因为vi编译器不好操作所以使用图形化的编译器
同样这个也换了
然后再把这个路径下的h文件复制一份
把这个也改成fs4412
这句话是编译的时候的提示信息其实该不该不影响用,改了只是让提示信息变过来
打开顶层目录的boards.cfg在origen后加一个我们的信息
这个文件就是一个支持的开发板列表包括一些信息,所以我们要添加一下
3.2再次配置和编译
试了一下在底层目录运行不好使哈哈。回到顶层配置成功
然后再make,但是现在还是用不了因为我们只是换了名,其它的都没改
3.3添加三星加密引导程序
三星公司为了安全性或者一些“其他原因”它没有全部使用uboot的开源程序,有一部三星自己写好了,我们可以用但是不能看里面是什么
把这俩目录放到顶层
这之后不要执行make clean或make distclean,这会将加密文件清除
然后修改一些makefile让原来的代码和三星的引导文件链接到一起
再这段话后面加上一些东西:
@#./mkuboot
@split -b 14336 u-boot.bin bl2
@+make -C sdfuse_q/
@#cp u-boot.bin u-boot-4212.bin
@#cp u-boot.bin u-boot-4412.bin
@#./sdfuse_q/add_sign
@./sdfuse_q/chksum
@./sdfuse_q/add_padding
@rm bl2a*
@echo
这些前面都要加一个tab件不然会报错
3.4添加调制代码(点灯法)
vi arch/arm/cpu/armv7/start.S
打开这个文件
在这个位置加上点亮LED2的操作这样可以保证终端无现象第一时间找到是串口坏了还是uboot没启动导致的问题。干别的也行就是确认用的,不理解这段程序可以看我前面的文章。
GPIO实验_gpio控制实验_宇努力学习的博客-CSDN博客
3.5添加编译脚本
使用make命令编译时只链接uboot源码中的相关代码,而我们添加的初始引导加密的 代码不会被连接到u-boot.bin中,所以这里我们自己编写编译脚本build.sh,这个脚本 中除了对uboot源码进行配置和编译外还将初始引导加密代码链接到了u-boot.bin上, 最终生成一个完成的uboot镜像u-boot-fs4412.bin
先配置后编译 -j是使用多线程编译加快编译速度
然后直接执行就行了
这个u-boot-fs4412就是开发板可执行的文件
3.6测试uboot
把这个bin文件拖出来刷到SD卡上
改成SD卡启动模式
这时候LED2应该是亮的,但是串口没有信息还是需要修改硬件设备的代码。
3.7修改UART源码
$ vi board/samsung/fs4412/lowlevel_init.S
打开这个文件
添加下面变色的代码:
初始化栈
关闭看门狗
把这句话注释,上面的操作是为了初始化串口
然后再试试,先创造一个512字节的空镜像
把他们组合一下
做一个1M的空镜像用来擦除
先擦除再烧写
欧克没有问题。我们运行help命令发现不全。
3.8修改网络初始代码
虽然可以通过终端输入命令,但此时的uboot还不能使用ping、tftp等命令,原因在于 命令都是操作网络的,而uboot源码中网卡的相关配置与我们当前的板子不匹配,所以 我们还要对网卡进行移植。我们的开发板用的网卡是dm9000
打开这个文件 board/samsung/fs4412/fs4412.c
#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];
};
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
文件末尾加上‘
#ifdef CONFIG_CMD_NET
int board_eth_init(bd_t *bis)
{
int rc = 0;
#ifdef CONFIG_DRIVER_DM9000
rc = dm9000_initialize(bis);
#endif
return rc;
}
#endif
3.9修改网络配置代码
uboot默认不编译这部分的代码,所以要使用需要配置一下
打开这个文件 include/configs/fs4412.h
这两个undef改成define
文件末尾这个前面加上:
#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.9.200
#define CONFIG_SERVERIP 192.168.9.120
#define CONFIG_GATEWAYIP 192.168.9.1
#define CONFIG_NETMASK 255.255.255.0
#endif
然后再编译
cat zero.bin u-boot-fs4412.bin > win-u-boot-fs4412.bin
sudo dd if=/dev/zero of=clear.bin count=2048
sudo dd if=/dev/zero of=zero.bin count=1
上面这三个命令总用我就单独粘了一份。
没啥问题,上面最后加的那段就是网卡一些初始的信息,根据自己需要改就行,当然不改也行后面可以自己设置。
3.10修改emmc初始代码
将资料中“移植相关文件”下的movi.c拷贝到uboot源码的arch/arm/cpu/armv7/exynos/ 目录下
这里都是emmc的相关代码,一般也是emmc厂家提供的
然后再当前目录下的makefile加上我们新加入的文件的.o
board/samsung/fs4412/fs4412.c
再打开这个文件
加上这俩头文件
u32 sclk_mmc4; /*clock source for emmc controller*/
#define __REGMY(x) (*((volatile u32 *)(x)))
#define CLK_SRC_FSYS __REGMY(EXYNOS4_CLOCK_BASE + CLK_SRC_FSYS_OFFSET)
#define CLK_DIV_FSYS3 __REGMY(EXYNOS4_CLOCK_BASE + CLK_DIV_FSYS3_OFFSET)
int emmc_init()
{
u32 tmp;
u32 clock;
u32 i;
/* setup_hsmmc_clock */
/* MMC4 clock src = SCLKMPLL */
tmp = CLK_SRC_FSYS & ~(0x000f0000);
CLK_SRC_FSYS = tmp | 0x00060000;
/* MMC4 clock div */
tmp = CLK_DIV_FSYS3 & ~(0x0000ff0f);
clock = get_pll_clk(MPLL)/1000000;
for(i=0 ; i<=0xf; i++) {
sclk_mmc4=(clock/(i+1));
if(sclk_mmc4 <= 160) //200
{
CLK_DIV_FSYS3 = tmp | (i<<0);
break;
}
}
emmcdbg("[mjdbg] sclk_mmc4:%d MHZ; mmc_ratio: %d\n",sclk_mmc4,i);
sclk_mmc4 *= 1000000;
/*
* MMC4 EMMC GPIO CONFIG
*
* GPK0[0] SD_4_CLK
* GPK0[1] SD_4_CMD
* GPK0[2] SD_4_CDn
* GPK0[3:6] SD_4_DATA[0:3]
*/
writel(readl(0x11000048)&~(0xf),0x11000048); //SD_4_CLK/SD_4_CMD pull-down enable
writel(readl(0x11000040)&~(0xff),0x11000040);//cdn set to be output
writel(readl(0x11000048)&~(3<<4),0x11000048); //cdn pull-down disable
writel(readl(0x11000044)&~(1<<2),0x11000044); //cdn output 0 to shutdown the emmc power
writel(readl(0x11000040)&~(0xf<<8)|(1<<8),0x11000040);//cdn set to be output
udelay(100*1000);
writel(readl(0x11000044)|(1<<2),0x11000044); //cdn output 1
writel(0x03333133, 0x11000040);
writel(0x00003FF0, 0x11000048);
writel(0x00002AAA, 0x1100004C);
#ifdef CONFIG_EMMC_8Bit
writel(0x04444000, 0x11000060);
writel(0x00003FC0, 0x11000068);
writel(0x00002AAA, 0x1100006C);
#endif
#ifdef USE_MMC4
smdk_s5p_mshc_init();
#endif
}
把上面代码加到那个宏的后面
把原来的文件换掉
int board_mmc_init(bd_t *bis)
{
int i, err;
#ifdef CONFIG_EMMC
err = emmc_init();
#endif
return err;
}
文件最末尾加上
#ifdef CONFIG_BOARD_LATE_INIT
#include <movi.h>
int chk_bootdev(void)//mj for boot device check
{
char run_cmd[100];
struct mmc *mmc;
int boot_dev = 0;
int cmp_off = 0x10;
ulong start_blk, blkcnt;
mmc = find_mmc_device(0);
if (mmc == NULL)
{
printf("There is no eMMC card, Booting device is SD card\n");
boot_dev = 1;
return boot_dev;
}
start_blk = (24*1024/MOVI_BLKSIZE);
blkcnt = 0x10;
sprintf(run_cmd,"emmc open 0");
run_command(run_cmd, 0);
sprintf(run_cmd,"mmc read 0 %lx %lx %lx",CFG_PHY_KERNEL_BASE,start_blk,blkcnt);
run_command(run_cmd, 0);
/* switch mmc to normal paritition */
sprintf(run_cmd,"emmc close 0");
run_command(run_cmd, 0);
return 0;
}
int board_late_init (void)
{
int boot_dev =0 ;
char boot_cmd[100];
boot_dev = chk_bootdev();
if(!boot_dev)
{
printf("\n\nChecking Boot Mode ... EMMC4.41\n");
}
return 0;
}
#endif
3.11添加emmc命令
将资料中“移植相关文件”下的cmd_movi.c、cmd_mmc.c、cmd_mmc_fdisk.c拷贝到uboot 源码的common/目录下
然后修改当前目录的makefile
COBJS-$(CONFIG_CMD_MMC) += cmd_mmc_fdisk.o
COBJS-$(CONFIG_CMD_MOVINAND) += cmd_movi.o
在这句话后面加上这两个
将资料中“移植相关文件”下的mmc.c、s5p_mshc.c拷贝到uboot源码的drivers/mmc/ 目录下
将资料中“移植相关文件”下的mmc.h、movi.h、s5p_mshc.h拷贝到uboot源码的include/ 目录下
还要配置makefile
在蓝色框后面加上红色框的内容
3.12修改emmc配置代码
include/configs/fs4412.h
#define CONFIG_EVT1 1 /* EVT1 */
#ifdef CONFIG_EVT1
#define CONFIG_EMMC44_CH4 //eMMC44_CH4 (OMPIN[5:1] = 4)
#ifdef CONFIG_SDMMC_CH2
#define CONFIG_S3C_HSMMC
#undef DEBUG_S3C_HSMMC
#define USE_MMC2
#endif
#ifdef CONFIG_EMMC44_CH4
#define CONFIG_S5P_MSHC
#define CONFIG_EMMC 1
#define USE_MMC4
/* #define CONFIG_EMMC_8Bit */
#define CONFIG_EMMC_EMERGENCY
/*#define emmcdbg(fmt,args...) printf(fmt ,##args) */
#define emmcdbg(fmt,args...)
#endif
#endif /*end CONFIG_EVT1*/
#define CONFIG_CMD_MOVINAND
#define CONFIG_CLK_1000_400_200
#define CFG_PHY_UBOOT_BASE CONFIG_SYS_SDRAM_BASE + 0x3e00000
#define CFG_PHY_KERNEL_BASE CONFIG_SYS_SDRAM_BASE + 0x8000
#define BOOT_MMCSD 0x3
#define BOOT_EMMC43 0x6
#define BOOT_EMMC441 0x7
#define CONFIG_BOARD_LATE_INIT
再这个文件的最后加上上面的代码,这些都是emmc的配置这个最后是指文件名宏那句话的前面。
接着测试
麻了
第一个错误是有个函数重定义了
终于修好了,有俩函数有个叫board_init 一个叫board_emc_init我把这俩整混了。
太感人终于搞出来了。
3.13修改电源管理相关代码
因为uboot源码中对电源管理芯片的配置与我们的板子不匹配,后续有可能会导致内核 启动卡死,这里还需要对电源管理芯片相关的代码进行修改和配置。
再makefile里加这句话
include/power/pmic.h
再上面这个文件里添加声明
include/configs/fs4412.h
board/samsung/fs4412/fs4412.c
drivers/power/Makefile
注释掉这句话
arch/arm/cpu/armv7/s5p-common/cpu_info.c
加上头文件
编译然后做镜像
最后clearSD卡,再把镜像写进去