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 源碼
我們可以在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啟動如下圖所示:
上電以后,出現 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”,然后按下回車鍵,環境變量如下面所示:
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
切換成功如下圖所示:
使用命令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工具燒寫,接下來進一步優化源碼,請查看第二章。
-
嵌入式
+關注
關注
5086文章
19144瀏覽量
306096 -
Linux
+關注
關注
87文章
11320瀏覽量
209833 -
Uboot
+關注
關注
4文章
125瀏覽量
28256 -
RK3568
+關注
關注
4文章
519瀏覽量
5100
發布評論請先 登錄
相關推薦
評論