一、U-Boot简介
Linux 系统要启动就必须需要一个 bootloader 程序,比如 U-Boot、 vivi、 RedBoot 等 等,其中以 U-Boot 使用最为广泛,为了方便书写,本文会将 U-Boot 写为 uboot。这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND, NOR FLASH, SD, MMC 等)拷贝到 DDR 中,最后启动 Linux 内核。
二、uboot源码的下载
(1) 官方原汁原味uboot
ftp://ftp.denx.de/pub/u-boot/ 主要被半导体产商使用,移植到自家芯片。
(2) 半导体产商uboot
在半导体产商官网下载如NXP等,适配NXP官方开发板。
(3) 开发板厂商uboot
由开发板厂商提供,在半导体产商提供的uboot基础上修改,适配自家的开发板。
三、uboot的编译
(1) 安装ncurses库
sudo apt-get install libncurses5-dev
(2) 编译脚本
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean #清理
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xxx_defconfig #配置
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12 #编译
(3)uboot烧写
(1) 构建.imx可烧写文件
.imx文件是在.bin文件前添加一些头信息构成的。主要有:
IVT(Image Vector table): IVT里面包含了一系列的地址信息,比较重要的如链接地址。
Boot data: 启动数据,包含了镜像要拷贝到哪个地址,拷贝的大小是多少等等
DCD(Device configuration data): 设备配置信息,重点是 DDR3 的初始化配置
.bin: 用户代码可执行文件
具体见:正点原子手册V3 P324
(2) 烧写文件、测试驱动
可以通过SD卡启动或烧写金EMMC启动。主要测试SD卡驱动、EMMC驱动、LCD驱动、网络驱动。
三、Uboot移植
(1) 添加开发板对应的板级文件夹
-
copy板级文件目录
cd board/freescale/ cp mx6ullevk/ -r mx6ull_ht -
修改目录下.c文件命名
cd mx6ull_ht mv mx6ullevk.c mx6ull_ht.c -
修改目录下的Makefile
obj-y :=mx6ull_ht.o #将修改命名的.c文件编译进去 -
修改目录下的imximag.cfg
PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000 修改为 PLUGIN board/freescale/mx6ull_ht /plugin.bin 0x00907000 -
修改目录下的Kconfig
if TARGET_MX6ULL_HT config SYS_BOARD default "mx6ull_ht" config SYS_VENDOR default "freescale" config SYS_SOC default "mx6" config SYS_CONFIG_NAME default "mx6ull_ht" endif -
修改U-Boot图形界面配置文件
#在 arch/arm/cpu/armv7/mx6/Kconfig 中添加 config TARGET_MX6ULL_HT bool "Support mx6ull_ht" select MX6ULL elect DM select DM_THERMAL #在endif前添加Kconfig源 source "board/freescale/mx6ull_ht/Kconfig"
(2) 移植配置文件
cd configs
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_ht_defconfig
#修改xmx6ull_ht_defconfig
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_ht/imximage.cfg,MX6ULL_EVK_EMMC_REWORK" #路径改成自己的板级文件夹
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_HT=y #这一项主要控制Kconfig文件,要与Kconfig中的宏一致
CONFIG_CMD_GPIO=y
(3) 移植开发板对应头文件(配置裁剪文件)
cp include/configs/mx6ullevk.h mx6ull_ht.h
#修改.h的重复检测宏
#ifndef __MX6ULL_HT_CONFIG_H
#define __MX6ULL_HT_CONFIG_H
#剩下的就是uboot功能的配置和裁剪
L14 添加头文件mx6_common.h也包含部分配置项
L29-L39 根据板子类型设置DRAM的大小
L50 定义宏CONFIG_DISPLAY_CPUINFO,uboot启动可以输出CPU信息。
L51 定义宏 CONFIG_DISPLAY_BOARDINFO,uboot启动可以输出板子信息.
L54 CONFIG_SYS_MALLOC_LEN,配置内存池大小。
L56 定义宏CONFIG_BOARD_EARLY_INIT_F,board_init_f可以调用board_early_init_f。
L57 定义宏CONFIG_BOARD_LATE_INIT,board_init_r可以调用board_early_init_r。
L59 定义宏CONFIG_MXC_UART,使能串口功能。
L60 CONFIG_MXC_UART_BASE,配置串口寄存器基地址。
L63 CONFIG_FSL_USDHC,EMMC使能,EMMC接在I.MX6ULL的USDHC2上。
L64 CONFIG_SYS_FSL_ESDHC_ADDR,配置EMMC使用接口寄存器的基地址。
L67-L2 NAND与USDHC2的引脚冲突,如果使用NAND则只能有一个USDHC设备(SD卡),否则两个。
L75-81 控制I2C使能与速度
L92-96 NAND分区设置
L98-111 CONFIG_MFG_ENV_SETTINGS定义了使用Mfgtool烧录时使用的一系列环境变量。
L113-202 COFIG_EXTRA_ENV_SETTING后面需要使用的设置一些环境变量。
L204-217 CONFIG_BOOTCOMMAND设置bootcmd的值。
L220-222 使能memtest并设置memtest的内存起始地址和内存大小。
L224 CONFIG_SYS_LOAD_ADDR,设置linux内核再DRAM中的加载地址。
L225 CONFIG_SYS_HZ,配置系统的时钟频率。单位HZ
L227 CONFIG_STACKSIZE,配置栈大小。
L230 CONFIG_NR_DRAM_BANKS,配置DRAM BANK的数量。
L231 PHYS_SDRAM,配置DRAM控制器MMDC0所管辖的DRAM起始地址。
L233 CONFIG_SYS_SDRAM_BASE,配置DRAM的起始地址。
L234 CONFIG_SYS_INIT_RAM_ADDR,配置IMX6ULL内部的IRAM的起始地址。
L235 CONFIG_SYS_INIT_RAM_SIZE,配置IRAM的大小。
L256 CONFIG_SYS_MMC_ENV_DEV,配置默认的MMC设备。
L257 CONFIG_SYS_MMC_ENV_PART,配置默认分区。
L258 CONFIG_MMCROOT,配置进入linux系统的根文件系统所在的分区,"/dev/mmcblk1p2"代表EMMC设备分区2,第0个分区保存uboot,第一个分区保存linux镜像和设备树,第二个分区为linux系统的根文件系统。
L325~342 与网络有关的宏。使能dhcp,ping等命令。CONFIG_FEC_ENET_DEV制度uboot使用的网口。IMX_FEC_BASE,配置网口基地址。CONFIG_FEC_MXC_PHYADDR,配置PHY芯片地址。CONFIG_FEC_XCV_TYPE,配置接口类型。
L344~END 配置宏。CONFIG_VIDEO开启LCD功能。CONFIG_VIDEO_LOGO使能LOGO显示。CONFIG_CMD_BMP 使能 BMP
图片显示指令。其中L345 CONFIG_PHY_MICREL表示使能Micrel公司的PHY驱动,对标的还有CONFIG_PHY_SMSC,SMSC公司的网络驱动如LAN8720A。
四、驱动修改
一般 uboot 中修改驱动基本都是在上文修改的 imx6ull_ht.h 和 imx6ull_ht.c 这两个文件中进行的。
- 网络驱动一般要再imx6ull_ht.h文件中修改PHY地址和对应的PHY公司宏。再imx6ull_ht.c中修改引脚配置,board_init函数(板子初始化)等。
五、Uboot中的环境变量
(1) bootcmd
-
bootcmd保存着uboot默认命令,主要是调用一些环境变量,环境变量默认值定义再include/env_default.h
-
bootcmd默认值:文件imx6ull_ht.h中
#define CONFIG_BOOTCOMMAND \ "run findfdt;" \ #findfdt是NXP自定义的环境变量,用来查找开发板对应的设备树文件,并设为环境变量fdt_file "mmc dev ${mmcdev};" \ #切换mmc设备,这里mmcdev是1,就是EMMC. "mmc dev ${mmcdev}; if mmc rescan; then " \ #判断能否检测到sd卡或者emmc "if run loadbootscript; then " \ #如果检测到mmc,再判断能否运行loadbootscript(script文件是否存在) "run bootscript; " \ #存在则运行boot脚本 "else " \ #否则 "if run loadimage; then " \ #判断能否运行loadimage(是否存在{zImage}) "run mmcboot; " \ #存在zImage运行mmcboot(从emmc启动) "else run netboot; " \ #否则运行netboot "fi; " \ "fi; " \ "else run netboot; fi" #检测不到mmcdev则从网络启动,运行netboot环境变量 #进一步解析:将环境变量都拆开,成功从emmc启动的命令如下: mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-evk.dtb; bootz 0x80800000 - 0x83000000
(2) bootargs
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
#拆开后
mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw
六、uboot启动Linux测试
(1) 从EMMC启动,uboot界面命令。
- ls mmc 1:1 #查看emmc分区1中的文件。
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull_ht.dtb; bootz 80800000 - 83000000;'
saveenv
(2) 从网络启动,uboot界面命令。
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-ht.dtb; bootz 80800000 - 83000000'
saveenv
(3)uboot命令总结
(1)环境变量相关
printenv
setenv
saveenv
(2)内存操作相关
md[.b, .w, .l] address [# of objects]
nm [.b, .w, .l] address
mm [.b, .w, .l] address
mw [.b, .w, .l] address value [count]
cp [.b, .w, .l] source target count
cmp [.b, .w, .l] addr1 addr2 count
(3)网络操作命令
setenv ipaddr 192.168.1.50 #开发板ip
setenv ethaddr 00:04:9f:04:d2:35
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.250
saveenv
ping 192.168.1.250
dhcp
nfs [loadAddress] [[hostIPaddr:]bootfilename]
nfs 80800000 192.168.1.250:/home/ht/imx6ull/nfs/zImage
tftpboot [loadAddress] [[hostIPaddr:]bootfilename]
tftp 80800000 zImage
(4)内存操作相关
md[.b, .w, .l] address [# of objects]
nm [.b, .w, .l] address
mm [.b, .w, .l] address
mw [.b, .w, .l] address value [count]
cp [.b, .w, .l] source target count
cmp [.b, .w, .l] addr1 addr2 count
(5)EMMC 和 SD 卡操作命令
mmc info #当前选中的mmc信息
mmc rescan #扫描所有mmc
mmc list #查看当前开发板一共有几个 MMC 设备
mmc dev [dev] [part] #[dev]用来设置要切换的 MMC 设备号, [part]是分区号(默认0)。
mmc part #查看其分区
saveenv
ping 192.168.1.250
dhcp
nfs [loadAddress] [[hostIPaddr:]bootfilename]
nfs 80800000 192.168.1.250:/home/ht/imx6ull/nfs/zImage
tftpboot [loadAddress] [[hostIPaddr:]bootfilename]
tftp 80800000 zImage
mmc read addr blk# cnt
mmc write addr blk# cnt
mmc erase blk# cnt
七、uboot移植总结
- 不管是购买的开发板还是自己做的开发板,基本都是参考半导体厂商的 dmeo 板,而 半导体厂商会在他们自己的开发板上移植好 uboot、 linux kernel 和 rootfs 等,最终制作好 BSP 包提供给用户。我们可以在官方提供的 BSP 包的基础上添加我们的板子,也就是俗称的移植。
- 我们购买的开发板或者自己做的板子一般都不会原封不动的照抄半导体厂商的 demo 板,都会根据实际的情况来做修改,既然有修改就必然涉及到 uboot 下驱动的移植。
- 一般 uboot 中需要解决串口、 NAND、 EMMC 或 SD 卡、网络和 LCD 驱动,因为 uboot 的主要目的就是启动 Linux 内核,所以不需要考虑太多的外设驱动。
- 在 uboot 中添加自己的板子信息,根据自己板子的实际情况来修改 uboot 中的驱动。
八、uboot图形化配置
(1) 安装必备库
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev
(2) 关键文件描述
.config文件保存着uboot的配置项;Kconfig文件是图形界面的描述文件,也就是描述图形界面应该有什么内容
(3) 操作图形界面
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_ht_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
#谨慎使用make clean,因为会清理掉.config文件,而menuconfig文件是读取.config文件的。
(4)Kconfig语法介绍
(1)顶层Kconfig
mainmenu "U-Boot $UBOOTVERSION Configuration" #主菜单名字
(2)调用其他目录下的Kconfig文件
source "xxx/Kconfig" #xxx为具体目录名,相对路径
(3)生成菜单
menu General setup
....
endmenu
(4)config条目
#顶层Kconfig
config LOCALVERSION
string "Local version - append to U-Boot release"
help
...
config LOCALVERSION_AUTO
bool "Automatically append version information to the version string"
default y
help
...
# 变量类型:bool、tristate、string、hex、int
bool:有y和n两个值,y表示配置该项。
tristate:有y、n、m三个值,m表示编译成模块。
string:表示字符串类型。此处显示标题
help:按h出来的提示
default y:默认为y
(5)depends on 和 select
#arch/Kconfig
config SYS_GENERIC_BOARD
bool
depends on HAVE_GENERIC_BOARD
config ARC
bool "ARC architecture"
select HAVE_PRIVATE_LIBGCC
select HAVE_GENERIC_BOARD
select SYS_GENERIC_BOARD
select SUPPORT_OF_CONTROL
depends on:说明SYS_GENERIC_BOARD依赖于HAVE_GENERIC_BOARD,只有后者被选中才能被选中。
select:方向依赖,当ARC被选择,则下面4个也被选中。
(6)choice/endchoice
#arch/Kconfig
choice
config
...
config
...
...
endchoice
#提供一组可选择项,供用户单选或多选,如架构。
(7)menuconfig
menuconfig MODULES
bool "菜单"
if MODULES
...
endif # MODULES
#产生一个带选项的菜单,被选择后才会产生
(7)comment
在选项下产生注释