【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第四篇 嵌入式Linux系统移植篇-第六十七章 Uboot编译及移植

描述

        i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用。

 

第四篇 嵌入式Linux系统移植篇

第六十七章 Uboot编译及移植

在之前学习开发板烧写的章节中,我们用到uboot和内核的镜像是怎么做出来的呢,我们在学习移植uboot之前先使用迅为电子移植好的uboot镜像来学习一下uboot的相关知识,本章节我们来学习下基础的知识“什么是uboot”和“uboot中的常用命令”,并且我们下载NXP官方的源码。

 

67.1 U-Boot介绍

67.1.1 什么是u-boot

uboot是一段裸机代码,它的实现非常复杂,主要是初始化一些硬件,部署整个计算机系统,然后将Linux内核从flash(NAND,NOR FLASH,SD,MMC 等)拷贝到 DDR 中,根据环境变量去启动内核,并向内核传递参数。它的目标就是启动内核,内核启动后它的生命也随之结束。

 

u-boot是SourceForge上的开源项目,由一个人发起,然后由整个世界所有感兴趣的人共同维护发展而来的一个bootloader,bootloader是用来引导和加载内核,向内核传递参数的,是内核引导程序的统称,bootloader除了u-boot还有bios,LilO,redboot,vivi等。

 

uboot 的全称是 Universal Boot Loader,uboot 是一个遵循 GPL 协议的开源软件,uboot 是一个裸机代码,可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB 等高级功能。uboot 官网为 http://www.denx.de/wiki/U-Boot/,

 

 

 

 可以在 uboot 官网下载 uboot 源码,点击图中左侧 Topics 中的“Source Code”,

 

 

进入其 FTP 服务器即可看到 uboot 源码

 

UbootUboot

 

 

我们可以在uboot官网下载最原始的uboot源码,也就是没有经过修改的,原汁原味的uboot的,但是在实际工作中,我们并不会直接在uboot官网下载uboot源码来移植uboot。为什么呢?因为我们要在对应的平台上来运行uboot,那么这个uboot是不是就要对这个平台支持的非常全面呢,因为uboot本身就是裸机代码,所以想要对某一个平台支持的非常全面,就要对这个平台非常熟悉,比如i.MX 8M Mini,那就要对i.MX 8M Mini这个芯片非常熟悉,那谁对这个芯片非常熟悉呢,当然是半导体厂家呀,所以,uboot官网里面的原汁原味的uboot是给半导体厂家准备的,比如RK,NXP等等。NXP官方的 uboot 基本支持了 NXP 当前所有可以跑 Linux 的芯片,而且支持各种启动方式,比如 EMMC、NAND、NOR FLASH 等等,这些都是 uboot 官方所不支持的。我们如果要移植对芯片支持最全面,最好的uboot的,我们一般是在半导体厂家维护uboot版本的基础上来二次开发自己的uboot,而不是直接在uboot官网下载源码来移植。

 

在迅为提供的资料里面有两个Linux的BSP源码包,一个是半导体厂商提供的源码包,里面的uboot是未经修改的,一个是迅为提供的BSP源码包,里面的uboot是经过迅为修改后的uboot,可以直接编译在开发板上来运行。当然了,你也可以在购买了第三方开发板以后使用半导体厂商提供的 uboot,只不过有些外设驱动可能不支持,需要自己移植,这个就是我们常说的 uboot 移植。

 

67.1.2 常用命令

我们先烧迅为做好的uboot(flash.bin)到开发板上,我们先了解与uboot相关的命令。

 

uboot启动如下图所示:

 

UbootUboot

 

 

 

上电以后,出现 Hit any key to stop autoboot: 0就按下任意键,进入uboot命令行,输入?查看帮助信息,会弹出很多命令和介绍,

 

 

 

上面的那些命令并不是 uboot 所支持的所有命令,前面说过 uboot 是可配置的,需要什么命令就使能什么命令。这些命令后面都跟有命令说明,用于描述此命令的作用,但是命令具体怎么用呢?我们输入“help(或?) 命令名”既可以查看命令的详细用法,以“bootz”这个命令为例,我们输入如下命令即可查看“bootz”这个命令的用法:

 

=> ? bootz

bootz - boot Linux zImage image from memory

 

Usage:

bootz [addr [initrd[:size]] [fdt]]

    - boot Linux zImage stored in memory

        The argument 'initrd' is optional and specifies the address

        of the initrd in memory. The optional argument ':size' allows

        specifying the size of RAW initrd.

        When booting a Linux kernel which requires a flat device-tree

        a third argument is required which is the address of the

        device-tree blob. To boot that kernel without an initrd image,

        use a '-' for the second argument. If you do not pass a third

        a bd_info struct will be passed instead

常用的和信息查询有关的命令有 3 个:

 

bdinfo

printenv

version

先来看一下 bdinfo 命令,此命令用于查看板子信息,直接输入“bdinfo”即可,

 

 

从上面中可以得出 DRAM 的起始地址和大小、启动参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息。

 

命令“printenv”用于输出环境变量信息,uboot 也支持 TAB 键自动补全功能,输入“print”然后按下 TAB 键就会自动补全命令,直接输入“print”也可以。输入“print”,然后按下回车键,环境变量如下面所示:

 

 

UbootUboot

 

 

u-boot=> pri

baudrate=115200

boot_fdt=try

bootcmd=mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot; else run netboot; fi; fi; else booti ${loadaddr} - ${fdt_addr}; fi

bootcmd_mfg=run mfgtool_args;if iminfo ${initrd_addr}; then if test ${tee} = yes; then bootm ${tee_addr} ${initrd_addr} ${fdt_addr}; else booti ${loadaddr} ${initrd_addr} ${fdt_addr}; fi; else echo "Run fastboot ..."; fastboot 0; fi;

bootdelay=2

bootscript=echo Running bootscript from mmc ...; source

console=ttymxc1,115200 earlycon=ec_imx6q,0x30890000,115200

emmc_dev=1

ethprime=FEC

fastboot_dev=mmc1

fdt_addr=0x43000000

fdt_file=itop8mm-evk-7.0.dtb

fdt_high=0xffffffffffffffff

fdtcontroladdr=be8f5860

image=Image

initrd_addr=0x43800000

initrd_high=0xffffffffffffffff

jh_clk=

jh_mmcboot=setenv fdt_file fsl-imx8mm-evk-root.dtb;setenv jh_clk clk_ignore_unused; if run loadimage; then run mmcboot; else run jh_netboot; fi;

jh_netboot=setenv fdt_file fsl-imx8mm-evk-root.dtb; setenv jh_clk clk_ignore_unused; run netboot;

kboot=booti

loadaddr=0x40480000

loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};

loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}

loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}

mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc clk_ignore_unused

mmcargs=setenv bootargs ${jh_clk} console=${console} root=${mmcroot}

mmcautodetect=yes

mmcboot=echo Booting from mmc ...; run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; else echo wait for boot; fi;

mmcdev=1

mmcpart=1

mmcroot=/dev/mmcblk2p2 rootwait rw

netargs=setenv bootargs ${jh_clk} console=${console} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp

netboot=echo Booting from net ...; run netargs;  if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; ${get_cmd} ${loadaddr} ${image}; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if ${get_cmd} ${fdt_addr} ${fdt_file}; then booti ${loadaddr} - ${fdt_addr}; else echo WARN: Cannot load the DT; fi; else booti; fi;

script=boot.scr

sd_dev=0

soc_type=imx8mm

 

Environment size: 2333/4092 bytes

 

 有很多的环境变量,比如 baudrate、board_name、board_rec、boot_fdt、bootcmd等等。uboot 中的环境变量都是字符串,既然叫做环境变量,那么它的作用就和“变量”一样。

 

比如 bootdelay 这个环境变量就表示 uboot 启动延时时间,默认bootdelay=3,也就默认延时 3秒。前面说的 3 秒倒计时就是由 bootdelay 定义的,如果将 bootdelay 改为 5 的话就会倒计时 5s了。uboot 中的环境变量是可以修改的,有专门的命令来修改环境变量的值。

 

setenv:修改环境变量:setenv 环境变量名 环境变量值

 

删除环境变量:setenv 环境变量名

 

例如设置自启动倒计时环境变量bootdelay,设置为5秒,默认是2秒,

 

 

输入命令setenv bootdelay 10,然后输入printenv查看环境变量,发现环境变量已经改变。

 

 

 

删除环境变量也是使用命令 setenv,要删除一个环境变量只要给这个环境变量赋空值即可,比如我们删除掉上面新建的bootdelay 环境变量,使用命令 setenv bootdelay删除环境变量,

 

 

 

实验完成后,重新启动开发板恢复环境变量使设置的环境失效,因为环境变量没有保存到flash。

 

reset:重新启动

在uboot命令行输入reset即可重启开发板,

 

 

 

实验完成后,重新启动开发板恢复环境变量使设置的环境失效,因为环境变量没有保存到flash。

 

reset:重新启动

在uboot命令行输入reset即可重启开发板,

 

 

 

1.mmc: 在uboot命令行,输入mmc可以查看跟mmc相关的命令

由上图我们可以发现,mmc后面的参数不同,mmc的功能就不一样,例如:

 

mmc info:打印mmc的信息

 

mmc list :查看mmc设备

 

mmc read addr blk# cnt:从eMMC读cnt个块数据到内存addr处;

 

mmc write addr blk# cnt:把内存addr处的cnt个块数据写到eMMC。

 

mmc erase blk# cnt:擦除blk#开始的cnt个数据块

 

其中,addr为内存地址,blk#是mmc的块号,cnt是设备块的个数,块的单位是512字节。

 

(1)mmc info命令

 

mmc info命令可以查看设备信息,

 

 

 

通过上图我们可以看出,当前的设备是emmc设备,也就是图中MMC version所表示的信息为emmc的版本为5.1,Capacity所表示的信息为容量大小为14.6 Gib,Bus Width表示带宽为8-bit,Bus Speed表示速度为52000000Hz。

 

(2)mmc list命令

 

mmc list查看mmc设备,直接输入mmc list即可,

 

 

 

(3)mmc rescan命令

 

mmc rescan可以扫描开发板上的emmc设备,直接输入mmc rescan命令即可

 

 

 

(4)mmc dev命令

 

mmc dev命令可以切换mmc设备,命令格式:mmc dev mmc dev [dev] [part],其中dev是我们要切换到的mmc设备号,part可以不写,不写的话默认分区为0。

 

我们找一张FAT32的TF卡,查到开发板上的TF卡座子上,一般我们把TF卡也认为是mmc设备。所以也可以用mmc命令来操作。连接好TF卡以后,使用以下命令切换到TF卡

 

mmc dev 0

 

其中0为sd卡,1为emmc。

 

然后我们使用mmc info命令查看是否切换成功,

 

 

 

从上图我们可以看到,sd卡的版本信息为3.0,容量为14.6 GiB,位宽为4-bit。

 

(5)mmc part命令

 

mmc part可以用来查看mmc设备的分区,比如我们要查看emmc的分区,我们先切换到emmc设备(如果当前已经是emmc设备则不用切换),命令如下:

 

mmc dev 1

 

切换成功如下图所示:

 

 

UbootUboot

 

 

 使用命令mmc part查看emmc的分区,

 

 

 

从上图我们可以看出,emmc一共有2个分区,类型为DOS,其中第一个分区用来存放uboot镜像和内核镜像,第二个分区用来存放文件系统

 

(6)mmc read命令

 

使用mmc read命令可以读取mmc设备的数据信息,格式为mmc read addr blk# cnt,其中addr是读取到内存中的地址,blk为起始的块地址,一般为十六进制,一块是512字节,cnt是要读取的块的数量。

 

例如:mmc read 0xa0000000 10 10 ,表示mmc设备的第10块开始,读取10块到内存的0xa0000000地址当中去。结果如下:

 

 

 

5  go命令

 

go命令可以指定跳到地址处运行,命令格式为 go addr ,其中addr是应用在内存中的首地址。

 

6  run命令

 

可以执行环境变量中的命令,这个命令一般用于用户运行自定义的环境变量。

 

7  ls命令,默认uboot没有这个命令,可以配置上使用。

 

ls命令可以列出文件的目录,命令格式ls [ [directory]]:

 

例如,查看emmc分区5的信息。分区5为文件系统分区

 

ls mmc 1:5

 

其中,1为emmc,5为emmc里面的分区5

 

查看emmc分区5里面的etc信息,也就是文件系统里面的etc信息,命令如下

 

ls mmc 1:5 etc

 

67.2设置交叉编译器

输入以下命令设置交叉编译器,只有设置了交叉编译器,才可以编译源码,否则会报错。

 

 . /opt/fsl-imx-xwayland/4.14-sumo/environment-setup-aarch64-poky-linux

export ARCH=arm64

export CROSS_COMPILE=aarch64-poky-linux-

67.3 获取u-boot-imx 源码并编译

输入以下命令下载u-boot-imx 源码。

 

git clone https://source.codeaurora.org/external/imx/uboot-imx

 

 

 

进入uboot-imx目录,

cd uboot-imx

 

 

 

查看git分支,

git branch -a

 

 

 

切换分支,输入以下命令:

 

git checkout imx_v2018.03_4.14.78_1.0.0_ga

 

 

 

同步到当前仓库,输入以下命令:

 

git pull origin

 

 

 

输入以下命令,开始编译。

 

make distclean    

 

make imx8mm_ddr4_evk_defconfig

 

 

 

输入以下命令,开始编译。

 

 . /opt/fsl-imx-xwayland/4.14-sumo/environment-setup-aarch64-poky-linux

 

make -j 8

 

 

 

编译成功后会产生所需的文件:

 

u-boot-nodtb.bin

 

spl/u-boot-spl.bin

 

arch/arm/dts/fsl-imx8mm-ddr4-evk.dtb

 

 

 

67.4 获取 imx-mkimage源码并编译

下载 imx-mkimage源码,输入以下命令:

 

git clone https://source.codeaurora.org/external/imx/imx-mkimage/ && cd imx-mkimage

 

 查看远程分支,输入以下命令:

 

git branch -a

 

 

 

切换到与imx_4.14.78_1.0.0_ga版本对应的分支上,输入以下命令:

 

git checkout imx_4.14.78_1.0.0_ga

 

 

 

同步到当前仓库,输入以下命令:

 

git pull origin

 

 

 

67.5获取imx-atf源码并编译

退回上一级目录,下载 imx-atf,并同样切换分支

 

cd ..    

 

git clone https://source.codeaurora.org/external/imx/imx-atf/ && cd imx-atf    

 

 

 

切换到与imx_4.14.78_1.0.0_ga版本对应的分支上,输入以下命令:

 

git checkout imx_4.14.78_1.0.0_ga   

 

同步到当前仓库,输入以下命令:

 

git pull origin

 

 

 

编译 imx-atf,输入以下命令:

 

make clean PLAT=imx8mm

 

LDFLAGS="" make PLAT=imx8mm

 

 编译完成会生成build/imx8mm/release/bl31.bin文件,

 

 

67.6 获得firmware-imx源码

返回上一级目录,输入以下命令获得firmware-imx源码

 

cd .. && mkdir firmware-imx-8.10

 

cd firmware-imx-8.10

 

wget http://www.freescale.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.1.bin

 

 解压输入以下命令:

 

./firmware-imx-8.1.bin --auto-accept

 

 

 

67.7生成flash.bin

使用 imx-mkimage 链接合成所有文件生成最后二进制文件

 

输入以下命令拷贝uboot-imx中的文件到imx-mkimage目录。

 

cp uboot-imx/tools/mkimage ./imx-mkimage/iMX8M/mkimage_uboot    

 

cp uboot-imx/arch/arm/dts/fsl-imx8mm-ddr4-evk.dtb ./imx-mkimage/iMX8M/fsl-imx8mm-ddr4-evk.dtb    

 

cp uboot-imx/spl/u-boot-spl.bin ./imx-mkimage/iMX8M/    

 

cp uboot-imx/u-boot-nodtb.bin ./imx-mkimage/iMX8M/

 

 

 

 

 

cpfirmware-imx-8.10/firmware-imx-8.1/firmware/ddr/synopsys/ddr4_dmem_1d.bin ./imx-mkimage/iMX8M/    

cpfirmware-imx-8.10/firmware-imx-8.1/firmware/ddr/synopsys/ddr4_dmem_2d.bin ./imx-mkimage/iMX8M/    

cp firmware-imx-8.10/firmware-imx-8.1/firmware/ddr/synopsys/ddr4_imem_1d.bin ./imx-mkimage/iMX8M/    

cp firmware-imx-8.10/firmware-imx-8.1/firmware/ddr/synopsys/ddr4_imem_2d.bin ./imx-mkimage/iMX8M/

 

 

cp imx-atf/build/imx8mm/release/bl31.bin ./imx-mkimage/iMX8M/

 

 

 

cd imx-mkimage    

 

make SOC=iMX8MM clean    

 

make SOC=iMX8MM flash_ddr4_evk

 

 

 

编译完会生成flash.bin镜像,

 

 

 

然后我们可以使用TF卡启动uboot,但是不能使用UUU工具烧写,接下来进一步优化源码,请查看第二章。 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分