本文主要目的是如何从0编译和移植uboot,增加串口、网络、emmc等功能,让他支持exynos4412开发板。
一、移植步骤
1. Uboot配置
- 指定交叉编译工具链 进入uboot代码根目录
nbsp;cdu-boot-2013.01
修改 Makefile 在
ifeq($(HOSTARCH),$(ARCH))
CROSS_COMPILE?=
endif
下添加
ifeq(arm,$(ARCH))
CROSS_COMPILE?=arm-none-linux-gnueabi-
endif

交叉编译工具

- 指定产品CPU 我们产品用的CPU是 exynos 4412;
查看u-boot源码:
arch/arm/cpu/armv7/exynos/
可见U-boot已支持该CPU。
- 指定产品BOARD 三星公司已经为exynos 4412发布了初始化的程序:

origen
- cpu硬件信息 对应的该CPU硬件信息头文件位于以下位置:
include/configs/origen.h
该文件定义了uboot启动必须关于exynos 4412必须的一些资源信息。
- boards.cfg 在uboot-2013-01中,顶层目录下的boards.cfs文件中查看它支持的开发板和相应的信息,后续的编译过程需要根据配置名检索到相应的信息。文件格式如下:

和以前的老版本比,配置更加规范化了,其实这些就是相关文件分类的一个文件夹的描述。依照这个层次关系,我们可以很方便地对我们开发板进行配置。
- 编译u-boot
不同版本的uboot的配置命令可能是不同的,源码包的文件README通常会有相应的配置命令【其他版本的uboot会不一样】:

配置和编译命令如下:
nbsp;makedistclean
nbsp;makeorigen_config
改配置命令会生成以下文件:
include/config.h

config.h
编译:
nbsp;makeall
编译完成后生成的u-boot.bin就是可执行的镜像文件。
但是并不会生成真正适配我们板子的uboot,只是适配参考板,该文件还不能在我们板子上运行,我们需要对u-boot源代码进行相应的修改。
2. 确认第一条指令有运行到 (点灯法)
在arch/arm/cpu/armv7/start.S 134 行后添加点灯程序
#if1
ldrr0,=0x11000c40@GPX2_7led2
ldrr1,[r0]
bicr1,r1,#0xf0000000
orrr1,r1,#0x10000000
strr1,[r0]
ldrr0,=0x11000c44
movr1,#0xff
strr1,[r0]
#endif
因为uboot刚启动的时候,串口没有来得及初始化,我们可以通过点亮LED的方法来判断程序是否执行到此处。
代码详解参考《十、LED汇编、C语言驱动编写》
3. 添加三星加密方式
exynos 需要三星提供的初始引导加密后,我们的u-boot,才能被引导运行,这其中要用到下面的几个命令或三星提供的工具软件,这些操作的目的就是根据三星的芯片的启动要求对uboot.bin 进行一些处理,包括在特定长度的位置加上和校验信息以及插入一些文件段。
$cpsdfuse_qu-boot-2013.01-rf
nbsp;chmod777u-boot-2013.01/sdfuse_q-R
$cpCodeSign4SecureBootu-boot-2013.01-rf
注:CodeSign4SecureBoot 三星提供的安全启动方式 ,对应的程序由三星提供。sdfuse_q目录下的文件是针对三星堆uboot.bin文件格式要求进行加密编写的文件。
修改根目录Makefile,实现sdfuse_q的编译 在
$(obj)u-boot.bin:$(obj)u-boot
$(OBJCOPY)${OBJCFLAGS}-Obinarylt;$@
$(BOARD_SIZE_CHECK)
下添加
@#./mkuboot
@split-b14336u-boot.binbl2
@make-Csdfuse_q/
@#cpu-boot.binu-boot-4212.bin
@#cpu-boot.binu-boot-4412.bin
@#./sdfuse_q/add_sign
@./sdfuse_q/chksum
@./sdfuse_q/add_padding
@rmbl2a*
@echo
注意是tab键缩进的,否则makefile编译报错 注意如果执行了make distclean 需重新拷贝CodeSign4SecureBoot
为方便起见,在根目录下创建编译脚本build.sh,该脚本将自动完成添加加密方式。
1#!/bin/sh
2
3sec_path="CodeSign4SecureBoot/"
4CPU_JOB_NUM=$(grepprocessor/proc/cpuinfo|awk'{field=$NF};END{printfield+1}')
5ROOT_DIR=$(pwd)
6CUR_DIR=${ROOT_DIR##*/}
7
8case"$1"in
9clean)
10echomakeclean
11makemrproper
12;;
13*)
14
15if[!-d$sec_path]
16then
17echo"**********************************************"
18echo"[ERR]pleasegettheCodeSign4SecureBootfirst"
19echo"**********************************************"
20return
21fi
22
23makeorigen_config
24
25make-j$CPU_JOB_NUM
26
27if[!-fchecksum_bl2_14k.bin]
28then
29echo"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
30echo"Therearesomeerror(s)whilebuildinguboot,pleaseusecommandmaketocheck."
31echo"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
32exit0
33fi
34
35cp-rfchecksum_bl2_14k.bin$sec_path
36cp-rfu-boot.bin$sec_path
37rmchecksum_bl2_14k.bin
38
39cd$sec_path
40catE4412_N.bl1.SCP2G.binbl2.binall00_padding.binu-boot.bintzsw_SMDK4412_SCP_2GB.bin>u-boot-origen.bin
41mvu-boot-origen.bin$ROOT_DIR
42
43rmchecksum_bl2_14k.bin
44rmu-boot.bin
45
46echo
47echo
48;;
49
50esac
编译脚本
nbsp;chmod777u-boot-2013.01/build.sh
nbsp;./buildsh
注:build.sh 脚本方式完成自动添加加密方式, 编译生成所需文件u-boot_origen.bin
root@ubuntu:/home/peng/uboot/u-boot-2013.01#ls
apiconfig.mkexamplesMakefilesdfuse_qu-boot.bin
archCOPYINGfsmkconfigsnapshot.commitu-boot.map
boardCREDITShelper.mknand_splsplu-boot-origen.bin
boards.cfgdiskincludenetSystem.mapu-boot.srec
build.shdoclibposttest
CodeSign4SecureBootdriversMAINTAINERSREADMEtools
commondtsMAKEALLrules.mku-boot

u-boot_origen.bin
4. 实现串口输出
修改lowlevel_init.S文件
$vimboard/samsung/origen/lowlevel_init.S
a) 添加临时栈,在
41lowlevel_init:
后添加
ldrsp,=0x02060000@useiRomstackinbl2
b) 添加关闭看门狗代码: 在
67beqwakeup_reset
后添加
#if1/*forclosewatchdog*/
/*PS-Holdhigh*/
ldrr0,=0x1002330c
ldrr1,[r0]
orrr1,r1,#0x300
strr1,[r0]
ldrr0,=0x11000c08
ldrr1,=0x0
strr1,[r0]
/*ClearMASK_WDT_RESET_REQUEST*/
ldrr0,=0x1002040c
ldrr1,=0x00
strr1,[r0]
#endif
c) 添加串口初始化代码: 在uart_asm_init: 的
351strr1,[r0,#EXYNOS4_GPIO_A1_CON_OFFSET]
后添加
ldrr0,=0x10030000
ldrr1,=0x666666
ldrr2,=CLK_SRC_PERIL0_OFFSET
strr1,[r0,r2]
ldrr1,=0x777777
ldrr2,=CLK_DIV_PERIL0_OFFSET
strr1,[r0,r2]
d) 注释掉trustzone初始化 注释掉
104bluart_asm_init
下的代码:
#if0
bltzpc_init
#endif
5. 网卡移植
因为各个厂家使用的网卡不尽相同,所以三星公司提供的驱动程序只预留了网卡初始化的函数入口,针对不同的板子,我们需要针对电路自己移植网卡的驱动。网卡的驱动详解,我们会在后一章节详细讲解。
1、 添加网络初始化代码
nbsp;vimboard/samsung/origen/origen.c
在
31structexynos4_gpio_part2*gpio2;
后添加:
#ifdefCONFIG_DRIVER_DM9000
#defineEXYNOS4412_SROMC_BASE0X12570000
#defineDM9000_Tacs(0x1)
#defineDM9000_Tcos(0x1)
#defineDM9000_Tacc(0x5)
#defineDM9000_Tcoh(0x1)
#defineDM9000_Tah(0xC)
#defineDM9000_Tacp(0x9)
#defineDM9000_PMC(0x1)
structexynos_sromc{
unsignedintbw;
unsignedintbc[6];
};
/*
*s5p_config_sromc()-selecttheproperSROMCBankandconfigurethe
*bandwidthcontrolandbankcontrolregisters
*srom_bank-SROM
*srom_bw_conf-SMCBandwitdhregconfigurationvalue
*srom_bc_conf-SMCBankControlregconfigurationvalue
*/
voidexynos_config_sromc(u32srom_bank,u32srom_bw_conf,u32srom_bc_conf)
{
unsignedinttmp;
structexynos_sromc*srom=(structexynos_sromc*)(EXYNOS4412_SROMC_BASE);
/*ConfigureSMC_BWregistertohandleproperSROMCbank*/
tmp=srom->bw;
tmp&=~(0xF<<(srom_bank*4));
tmp|=srom_bw_conf;
srom->bw=tmp;
/*ConfigureSMC_BCregister*/
srom->bc[srom_bank]=srom_bc_conf;
}
staticvoiddm9000aep_pre_init(void)
{
unsignedinttmp;
unsignedcharsmc_bank_num=1;
unsignedintsmc_bw_conf=0;
unsignedintsmc_bc_conf=0;
/*gpioconfiguration*/
writel(0x00220020,0x11000000+0x120);
writel(0x00002222,0x11000000+0x140);
/*16Bitbuswidth*/
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);
后添加
#ifdefCONFIG_DRIVER_DM9000
dm9000aep_pre_init();
#endif
在文件末尾添加
#ifdefCONFIG_CMD_NET
intboard_eth_init(bd_t*bis)
{
intrc=0;
#ifdefCONFIG_DRIVER_DM9000
rc=dm9000_initialize(bis);
#endif
returnrc;
}
#endif
2、 修改配置文件添加网络相关配置 $ vim include/configs/origen.h 修改
85#undefCONFIG_CMD_PING
为
#defineCONFIG_CMD_PING
修改
90#undefCONFIG_CMD_NET
为
#defineCONFIG_CMD_NET
在文件末尾
#endif/*__CONFIG_H*/
前面添加
#ifdefCONFIG_CMD_NET
#defineCONFIG_NET_MULTI
#defineCONFIG_DRIVER_DM90001
#defineCONFIG_DM9000_BASE0x05000000//内存基地址
#defineDM9000_IOCONFIG_DM9000_BASE
#defineDM9000_DATA(CONFIG_DM9000_BASE+4)
#defineCONFIG_DM9000_USE_16BIT
#defineCONFIG_DM9000_NO_SROM1
#defineCONFIG_ETHADDR11:22:33:44:55:66
#defineCONFIG_IPADDR192.168.6.187
#defineCONFIG_SERVERIP192.168.6.186
#defineCONFIG_GATEWAYIP192.168.1.1
#defineCONFIG_NETMASK255.255.255.0
#endif
其中CONFIG_DM9000_BASE 地址为何是0x05000000,后续章节会详细分析。
6. FLASH移植 (EMMC)
- 移植EMMC需要添加一些源文件:
cmd_mmc.c
cmd_mmc_fdisk.c
cmd_movi.c
mmc.c
mmc.h
movi.c
movi.h
s5p_mshc.c
s5p_mshc.h
这些文件,由三星提供。
- 添加相关驱动
cpmovi.carch/arm/cpu/armv7/exynos/
修改文件arch/arm/cpu/armv7/exynos/Makefile在pinmux.o 后添加movi.o
修改板级文件 board/samsung/origen/origen.c,在
#include<asm/arch/mmc.h>
后面添加
#include<asm/arch/clk.h>
#include"origen_setup.h"
在
#ifdefCONFIG_GENERIC_MMC
后面添加
u32sclk_mmc4;/*clocksourceforemmccontroller*/
#define__REGMY(x)(*((volatileu32*)(x)))
#defineCLK_SRC_FSYS__REGMY(EXYNOS4_CLOCK_BASE+CLK_SRC_FSYS_OFFSET)
#defineCLK_DIV_FSYS3__REGMY(EXYNOS4_CLOCK_BASE+CLK_DIV_FSYS3_OFFSET)
intemmc_init()
{
u32tmp;
u32clock;
u32i;
/*setup_hsmmc_clock*/
/*MMC4clocksrc=SCLKMPLL*/
tmp=CLK_SRC_FSYS&~(0x000f0000);
CLK_SRC_FSYS=tmp|0x00060000;
/*MMC4clockdiv*/
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:%dMHZ;mmc_ratio:%d\n",sclk_mmc4,i);
sclk_mmc4*=1000000;
/*
*MMC4EMMCGPIOCONFIG
*
*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_CMDpull-downenable
writel(readl(0x11000040)&~(0xff),0x11000040);//cdnsettobeoutput
writel(readl(0x11000048)&~(3<<4),0x11000048);//cdnpull-downdisable
writel(readl(0x11000044)&~(1<<2),0x11000044);//cdnoutput0toshutdowntheemmcpower
writel(readl(0x11000040)&~(0xf<<8)|(1<<8),0x11000040);//cdnsettobeoutput
udelay(100*1000);
writel(readl(0x11000044)|(1<<2),0x11000044);//cdnoutput1
writel(0x03333133,0x11000040);
writel(0x00003FF0,0x11000048);
writel(0x00002AAA,0x1100004C);
#ifdefCONFIG_EMMC_8Bit
writel(0x04444000,0x11000060);
writel(0x00003FC0,0x11000068);
writel(0x00002AAA,0x1100006C);
#endif
#ifdefUSE_MMC4
smdk_s5p_mshc_init();
#endif
}
将 int board_mmc_init(bd_t *bis)函数内容改写为
intboard_mmc_init(bd_t*bis)
{
inti,err;
#ifdefCONFIG_EMMC
err=emmc_init();
#endif
returnerr;
}
在末尾添加
#ifdefCONFIG_BOARD_LATE_INIT
#include<movi.h>
intchk_bootdev(void)//mjforbootdevicecheck
{
charrun_cmd[100];
structmmc*mmc;
intboot_dev=0;
intcmp_off=0x10;
ulongstart_blk,blkcnt;
mmc=find_mmc_device(0);
if(mmc==NULL)
{
printf("ThereisnoeMMCcard,BootingdeviceisSDcard\n");
boot_dev=1;
returnboot_dev;
}
start_blk=(24*1024/MOVI_BLKSIZE);
blkcnt=0x10;
sprintf(run_cmd,"emmcopen0");
run_command(run_cmd,0);
sprintf(run_cmd,"mmcread0%lx%lx%lx",CFG_PHY_KERNEL_BASE,start_blk,blkcnt);
run_command(run_cmd,0);
/*switchmmctonormalparitition*/
sprintf(run_cmd,"emmcclose0");
run_command(run_cmd,0);
return0;
}
intboard_late_init(void)
{
intboot_dev=0;
charboot_cmd[100];
boot_dev=chk_bootdev();
if(!boot_dev)
{
printf("\n\nCheckingBootMode...EMMC4.41\n");
}
return0;
}
#endif
- 添加相关命令
nbsp;cpcmd_movi.ccommon/
nbsp;cpcmd_mmc.ccommon/
nbsp;cpcmd_mmc_fdisk.ccommon/
修改common/Makefile 在
COBJS-$(CONFIG_CMD_MMC)+=cmd_mmc.o
后添加
COBJS-$(CONFIG_CMD_MMC)+=cmd_mmc_fdisk.o
COBJS-$(CONFIG_CMD_MOVINAND)+=cmd_movi.o
添加驱动
nbsp;cpmmc.cdrivers/mmc/
nbsp;cps5p_mshc.cdrivers/mmc/
nbsp;cpmmc.hinclude/
nbsp;cpmovi.hinclude/
nbsp;cps5p_mshc.hinclude/
修改Makefile
$vimdrivers/mmc/Makefile
添加
COBJS-$(CONFIG_S5P_MSHC)+=s5p_mshc.o
- 添加EMMC相关配置
$viminclude/configs/origen.h
添加
#defineCONFIG_EVT11/*EVT1*/
#ifdefCONFIG_EVT1
#defineCONFIG_EMMC44_CH4//eMMC44_CH4(OMPIN[5:1]=4)
#ifdefCONFIG_SDMMC_CH2
#defineCONFIG_S3C_HSMMC
#undefDEBUG_S3C_HSMMC
#defineUSE_MMC2
#endif
#ifdefCONFIG_EMMC44_CH4
#defineCONFIG_S5P_MSHC
#defineCONFIG_EMMC1
#defineUSE_MMC4
/*#defineCONFIG_EMMC_8Bit*/
#defineCONFIG_EMMC_EMERGENCY
/*#defineemmcdbg(fmt,args...)printf(fmt,##args)*///foremmcdebug
#defineemmcdbg(fmt,args...)
#endif
#endif/*endCONFIG_EVT1*/
#defineCONFIG_CMD_MOVINAND
#defineCONFIG_CLK_1000_400_200
#defineCFG_PHY_UBOOT_BASECONFIG_SYS_SDRAM_BASE+0x3e00000
#defineCFG_PHY_KERNEL_BASECONFIG_SYS_SDRAM_BASE+0x8000
#defineBOOT_MMCSD0x3
#defineBOOT_EMMC430x6
#defineBOOT_EMMC4410x7
#defineCONFIG_BOARD_LATE_INIT
7. 重新编译u-boot
修改顶层Makefile,注释掉spl的编译:
623#$(obj)spl/u-boot-spl.bin:$(SUBDIR_TOOLS)depend
624#$(MAKE)-Csplall
重新编译uboot:
nbsp;./build.sh
在根目录下会生成bin文件u-boot-origen.bin。
二、SD卡制作
1. 烧写脚本
三星公司已经给我们提供了制作SD卡启动的烧写的脚本:mkuboot.sh
#!/bin/bash
#
#Thisscriptwillcreateau-bootbinaryformovinand/mmcboot
#
echo"FuseFS4412trustzoneubootfileintoSDcard"
if[-z$1]#判断参数1的字符串是否为空,如果为空,则打印出帮助信息
then
./sd_fusing_exynos4x12.sh/dev/sdbu-boot-origen.bin
else
./sd_fusing_exynos4x12.sh$1u-boot-origen.bin
fi
sd_fusing_exynos4x12.sh
1#!/bin/sh
2#
3#Copyright(C)2010SamsungElectronicsCo.,Ltd.
4#http://www.samsung.com/
5#
6#Thisprogramisfreesoftware;youcanredistributeitand/ormodify
7#itunderthetermsoftheGNUGeneralPublicLicenseversion2as
8#publishedbytheFreeSoftwareFoundation.
9#
10####################################
11reader_type1="/dev/sd"
12reader_type2="/dev/mmcblk0"
13
14if[-z$2]#判断参数2的字符串是否为空,如果为空,则打印出帮助信息
15then
16echo"usage:./sd_fusing.sh<SDReader'sdevicefile><filename>"
17exit0
18fi
19
20param1=`echo"$1"|awk'{printsubstr($1,1,7)}'`
21
22if["$param1"="$reader_type1"]
23then
24partition1=$1"1"
25partition2=$1"2"
26partition3=$1"3"
27partition4=$1"4"
28
29elif["$1"="$reader_type2"]
30then
31partition1=$1"p1"
32partition2=$1"p2"
33partition3=$1"p3"
34partition4=$1"p4"
35
36else
37echo"UnsupportedSDreader"
38exit0
39fi
40
41if[-b$1]#判断参数1所指向的设备节点是否存在
42then
43echo"$1readerisidentified."
44else
45echo"$1isNOTidentified."
46exit0
47fi
48
49####################################
50#format
51umount$partition12>/dev/null
52umount$partition22>/dev/null
53umount$partition32>/dev/null
54umount$partition42>/dev/null
55
56echo"$2fusing..."
#烧写u-boot-origen.bin到SD卡(512+8K)字节处,512+8K=17x512,即第17个block
57ddiflag=dsyncoflag=dsyncif=$2of=$1seek=1&&\
58echo"$2imagehasbeenfusedsuccessfully."
59
60#echo"zImagefusing..."
61#ddiflag=dsyncoflag=dsyncif=../../TC4_Kernel_3.0/arch/arm/boot/zImageof=$1seek=1024&&\
62#echo"zImagehasbeenfusedsuccessfully."
63
64#echo"ramdisk-uboot.imgfusing..."
65#ddiflag=dsyncoflag=dsyncif=../../TC4_GB_2.3.4/out/target/product/smdk4212/ramdisk-uboot.imgof=$1seek=9216&&\
66#echo"ramdisk-uboot.imghasbeenfusedsuccessfully."
67
68####################################
69#<MessageDisplay>
70echo"EjectSDcard"
71
2. 制作步骤
a) 创建文件mkuboot.sh、sd_fusing_exynos4x12.sh b) 将SD卡插入电脑并被ubuntu识别 c) 拷贝编译好u-boot-origen.bin拷贝到当前目录下
root@ubuntu:/home/peng/uboot/sdfuse_q#ls
mkuboot.shsd_fusing_exynos4x12.shu-boot-origen.bin
d) 进入sdfuse_q执行如下操作
root@ubuntu:/home/peng/uboot/sdfuse_q#./mkuboot.sh/dev/sdb

d) 在SD卡中创建目录sdupdate,并把编译好的uboot镜像文件u-boot-origen.bin拷贝到这个目录。
3. 通过sd卡启动烧写uboot
a) 连接串口和板子,运行串口通信程序putty

选择右上角的”Serial”,然后点击左下角的”Serial”

按照自己的主机的情况选择COM口其他必须一直,然后点击open打开串口
b) 关闭开发板电源,将拨码开关SW1调至(1000)(SD启动模式)后打开电源 c) 将刚才做好的SD启动盘插入SD卡插槽 d) 重新打开开发板能够看到如下界面

在这里插入图片描述
在读秒倒计时时按任意键。由上图所示,已经支持EMMC和dm9000网卡。
e) 烧写 在终端上执行
sdfuseflashall
注意:上面的命令把SD卡 sdupdate目录下的u-boot-origen.bin烧写到emmc起始位置 等待终端无输出是表示烧写结束
f) 关闭开发板电源,将拨码开关SW1调至0110(EMMC启动模式)后打开电源即可以从emmc启动
4. 网络烧写uboot
如果板子已经可以启动uboot,我们也可以通过网络烧写uboot。
步骤如下:
- 把编译好的u-boot-origen.bin拷贝到/tftpboot下
- 启动开发板,在u-boot下先*载下**u-boot-origen.bin到41000000;再运行
moviwriteu-boot41000000
若编译后的u-boot-origen.bin 无法运行,可参考上一节,重新从SD卡引导烧写。
文中资料后台回复:uboot