STM32MP157 Linux系統(tǒng)移植開發(fā)篇4: BootLoader(Uboot)移植
本文章為《STM32MP157 Linux系統(tǒng)移植開發(fā)篇》系列中的一篇,筆者使用的開發(fā)平臺(tái)為華清遠(yuǎn)見FS-MP1A開發(fā)板(STM32MP157開發(fā)板)。stm32mp157是ARM雙核,2個(gè)A7核,1個(gè)M4核,A7核上可以跑Linux操作系統(tǒng),M4核上可以跑FreeRTOS、RT-Thread等實(shí)時(shí)操作系統(tǒng),STM32MP157開發(fā)板所以既可以學(xué)嵌入式linux,也可以學(xué)stm32單片機(jī)。
針對(duì)FS-MP1A開發(fā)板,除了Linux系統(tǒng)移植篇外,還包括其他多系列教程,包括Cortex-A7開發(fā)篇、Cortex-M4開發(fā)篇、擴(kuò)展板驅(qū)動(dòng)移植篇、Linux應(yīng)用開發(fā)篇、FreeRTOS系統(tǒng)移植篇、Linux驅(qū)動(dòng)開發(fā)篇、硬件設(shè)計(jì)篇、人工智能機(jī)器視覺篇、Qt應(yīng)用編程篇、Qt綜合項(xiàng)目實(shí)戰(zhàn)篇等。歡迎關(guān)注,更多stm32mp157開發(fā)教程及視頻,可加技術(shù)交流Q群459754978,感謝關(guān)注。
關(guān)于FS-MP1A開發(fā)板:
手機(jī)淘寶分享碼:復(fù)制本行文字打開手淘?T4FPXn3YYJ2?
鏈接:https://item.taobao.com/item.htm?id=622457259672
1 ?BootLoader(Uboot)移植
1.1?實(shí)驗(yàn)原理
1.1.1?概念
簡(jiǎn)單地說(shuō),Bootloader就是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行的一段程序,它類似于PC機(jī)中的BIOS程序。通過(guò)這段程序,可以完成硬件設(shè)備的初始化,并建立內(nèi)存空間的映射圖的功能,從而將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)合適的狀態(tài),為最終調(diào)用系統(tǒng)內(nèi)核做好準(zhǔn)備。
通常,Bootloader是嚴(yán)重地依賴于硬件實(shí)現(xiàn)的,特別是在嵌入式中。因此,在嵌入式世界里建立一個(gè)通用的Bootloader幾乎是不可能的。盡管如此,仍然可以對(duì)Bootloader歸納出一些通用的概念來(lái)指導(dǎo)用戶特定的Bootloader設(shè)計(jì)與實(shí)現(xiàn)。
(1)Bootloader所支持的CPU和嵌入式開發(fā)板
每種不同的CPU體系結(jié)構(gòu)都有不同的Bootloader。有些Bootloader也支持多種體系結(jié)構(gòu)的CPU,如后面要介紹的U-Boot就同時(shí)支持ARM體系結(jié)構(gòu)和MIPS體系結(jié)構(gòu)。除了依賴于CPU的體系結(jié)構(gòu)外,Bootloader實(shí)際上也依賴于具體的嵌入式板級(jí)設(shè)備的配置。
(2)Bootloader的安裝媒介
系統(tǒng)加電或復(fù)位后,所有的CPU通常都從某個(gè)由CPU制造商預(yù)先安排的地址上取指令。而基于CPU構(gòu)建的嵌入式系統(tǒng)通常都有某種類型的固態(tài)存儲(chǔ)設(shè)備(比如ROM、EEPROM或FLASH等)被映射到這個(gè)預(yù)先安排的地址上。因此在系統(tǒng)加電后,CPU將首先執(zhí)行Bootloader程序。
(3)Bootloader的啟動(dòng)過(guò)程分為單階段和多階段兩種。通常多階段的Bootloader能提供更為復(fù)雜的功能,以及更好的可移植性。
(4)Bootloader的操作模式。大多數(shù)Bootloader都包含兩種不同的操作模式:“啟動(dòng)加載”模式和“下載”模式,這種區(qū)別僅對(duì)于開發(fā)人員才有意義。
? ?啟動(dòng)加載模式:這種模式也稱為“自主”模式。也就是Bootloader從目標(biāo)機(jī)上的某個(gè)固態(tài)存儲(chǔ)設(shè)備上將操作系統(tǒng)加載到RAM中運(yùn)行,整個(gè)過(guò)程并沒有用戶的介入。這種模式是嵌入式產(chǎn)品發(fā)布時(shí)的通用模式。
? ?下載模式:在這種模式下,目標(biāo)機(jī)上的Bootloader將通過(guò)串口連接或網(wǎng)絡(luò)連接等通信手段從主機(jī)(Host)下載文件,比如:下載內(nèi)核映像和根文件系統(tǒng)映像等。從主機(jī)下載的文件通常首先被Bootloader保存到目標(biāo)機(jī)的RAM中,然后再被Bootloader寫到目標(biāo)機(jī)上的FLASH類固態(tài)存儲(chǔ)設(shè)備中。Bootloader的這種模系統(tǒng)是在更新時(shí)使用。工作于這種模式下的Bootloader通常都會(huì)向它的終端用戶提供一個(gè)簡(jiǎn)單的命令行接口。
(5)Bootloader與主機(jī)之間進(jìn)行文件傳輸所用的通信設(shè)備及協(xié)議,最常見的情況就是,目標(biāo)機(jī)上的Bootloader通過(guò)串口與主機(jī)之間進(jìn)行文件傳輸,傳輸協(xié)議通常是xmodem/ ymodem/zmodem協(xié)議中的一種。但是,串口傳輸?shù)乃俣仁怯邢薜?,因此通過(guò)以太網(wǎng)連接并借助TFTP協(xié)議來(lái)下載文件是個(gè)更好的選擇。
1.1.2?Bootloader啟動(dòng)流程
Bootloader的啟動(dòng)流程一般分為兩個(gè)階段:stage1和stage2,下面分別對(duì)這兩個(gè)階段進(jìn)行講解:
(1)Bootloader的stage1
在stage1中Bootloader主要完成以下工作。
? ?基本的硬件初始化,包括屏蔽所有的中斷、設(shè)置CPU的速度和時(shí)鐘頻率、RAM初始化、初始化LED、關(guān)閉CPU內(nèi)部指令和數(shù)據(jù)cache燈。
? ?為加載stage2準(zhǔn)備RAM空間,通常為了獲得更快的執(zhí)行速度,通常把stage2加載到RAM空間中來(lái)執(zhí)行,因此必須為加載Bootloader的stage2準(zhǔn)備好一段可用的RAM空間范圍。
? ?拷貝stage2到RAM中,在這里要確定兩點(diǎn):①stage2的可執(zhí)行映像在固態(tài)存儲(chǔ)設(shè)備的存放起始地址和終止地址;②RAM空間的起始地址。
? ?設(shè)置堆棧指針sp,這是為執(zhí)行stage2的C語(yǔ)言代碼做好準(zhǔn)備。
(2)Bootloader的stage2
在stage2中Bootloader主要完成以下工作。
? ?用匯編語(yǔ)言跳轉(zhuǎn)到main入口函數(shù)
由于stage2的代碼通常用C語(yǔ)言來(lái)實(shí)現(xiàn),目的是實(shí)現(xiàn)更復(fù)雜的功能和取得更好的代碼可讀性和可移植性。但是與普通C語(yǔ)言應(yīng)用程序不同的是,在編譯和鏈接Bootloader這樣的程序時(shí),不能使用glibc庫(kù)中的任何支持函數(shù)。
? ?初始化本階段要使用到的硬件設(shè)備,包括初始化串口、初始化計(jì)時(shí)器等。在初始化這些設(shè)備之前、可以輸出一些打印信息。
? ?檢測(cè)系統(tǒng)的內(nèi)存映射,所謂內(nèi)存映射就是指在整個(gè)4GB物理地址空間中有指出哪些地址范圍被分配用來(lái)尋址系統(tǒng)的RAM單元。
? ?加載內(nèi)核映像和根文件系統(tǒng)映像,這里包括規(guī)劃內(nèi)存占用的布局和從Flash上拷貝數(shù)據(jù)。
? ?設(shè)置內(nèi)核的啟動(dòng)參數(shù)。
1.1.3?Bootloader的種類
嵌入式系統(tǒng)世界已經(jīng)有各種各樣的Bootloader,種類劃分也有多種方式。除了按照處理器體系結(jié)構(gòu)不同劃分以外,還有功能復(fù)雜程度的不同。
首先區(qū)分一下“Bootloader”和“Monitor”的概念。嚴(yán)格來(lái)說(shuō),“Bootloader”只是引導(dǎo)設(shè)備并且執(zhí)行主程序的固件;而“Monitor”還提供了更多的命令行接口,可以進(jìn)行調(diào)試、讀寫內(nèi)存、燒寫Flash、配置環(huán)境變量等?!癕onitor”在嵌入式系統(tǒng)開發(fā)過(guò)程中可以提供很好的調(diào)試功能,開發(fā)完成以后,就完全設(shè)置成了一個(gè)“Bootloader”。所以,習(xí)慣上大家把它們統(tǒng)稱為Bootloader。
下表列出了Linux的開放源碼引導(dǎo)程序及其支持的體系結(jié)構(gòu)。表中給出了X86、ARM、PowerPC體系結(jié)構(gòu)的常用引導(dǎo)程序,并且注明了每一種引導(dǎo)程序是不是“Monitor”。

對(duì)于每種體系結(jié)構(gòu),都有一系列開放源碼Bootloader可以選用。
(1)X86
X86的工作站和服務(wù)器上一般使用LILO和GRUB。LILO是Linux發(fā)行版主流的Bootloader。不過(guò)Redhat Linux發(fā)行版已經(jīng)使用了GRUB,GRUB比LILO有更友好的顯示接口,使用配置也更加靈活方便。
在某些X86嵌入式單板機(jī)或者特殊設(shè)備上,會(huì)采用其他的Bootloader,如ROLO。這些Bootloader可以取代BIOS的功能,能夠從Flash中直接引導(dǎo)Linux啟動(dòng)?,F(xiàn)在ROLO支持的開發(fā)板已經(jīng)并入U(xiǎn)-Boot,所以U-Boot也可以支持X86平臺(tái)。
(2)ARM
ARM處理器的芯片商很多,所以每種芯片的開發(fā)板都有自己的Bootloader。結(jié)果ARM Bootloader也變得多種多樣。最早有為ARM720處理器的開發(fā)板的固件,又有了armboot,StrongARM平臺(tái)的BLOB,還有S3C2410處理器開發(fā)板上的vivi等?,F(xiàn)在armboot已經(jīng)并入了U-Boot,所以U-Boot也支持ARM/XSCALE平臺(tái)。U-Boot已經(jīng)成為ARM平臺(tái)事實(shí)上的標(biāo)準(zhǔn)Bootloader。
(3)PowerPC
PowerPC平臺(tái)的處理器有標(biāo)準(zhǔn)的Bootloader,就是PPCBOOT。PPCBOOT在合并armboot等之后,創(chuàng)建了U-Boot,成為各種體系結(jié)構(gòu)開發(fā)板的通用引導(dǎo)程序。U-Boot仍然是PowerPC平臺(tái)的主要Bootloader。
(4)MIPS
MIPS公司開發(fā)的YAMON是標(biāo)準(zhǔn)的Bootloader,也有許多MIPS芯片商為自己的開發(fā)板寫了Bootloader?,F(xiàn)在,U-Boot也已經(jīng)支持MIPS平臺(tái)。
(5)SH
SH平臺(tái)的標(biāo)準(zhǔn)Bootloader是sh-boot。RedBoot在這種平臺(tái)上也很好用。
(6)M68K
M68K平臺(tái)沒有標(biāo)準(zhǔn)的Bootloader。RedBoot能夠支持M68K系列的系統(tǒng)。
值得說(shuō)明的是RedBoot,它幾乎能夠支持所有的體系結(jié)構(gòu),包括MIPS、SH、M68K等。RedBoot是以eCos為基礎(chǔ),采用GPL許可的開源軟件工程?,F(xiàn)在由core eCos的開發(fā)人員維護(hù),源碼下載網(wǎng)站是http://www.ecoscentric.com/snapshots。RedBoot的文檔也相當(dāng)完善,有詳細(xì)的使用手冊(cè)《RedBoot User’s Guide》。
1.1.1?U-Boot概述
U-Boot(UniversalBootloader),是遵循GPL條款的開放源碼項(xiàng)目。它是從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來(lái)。其源碼目錄、編譯形式與Linux內(nèi)核很相似,事實(shí)上,不少U-Boot源碼就是相應(yīng)的Linux內(nèi)核源程序的簡(jiǎn)化,尤其是一些設(shè)備的驅(qū)動(dòng)程序,這從U-Boot源碼的注釋中能體現(xiàn)這一點(diǎn)。但是U-Boot不僅僅支持嵌入式Linux系統(tǒng)的引導(dǎo),而且還支持NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS嵌入式操作系統(tǒng)。其目前要支持的目標(biāo)操作系統(tǒng)是OpenBSD、NetBSD、FreeBSD、4.4BSD、Linux、SVR4、Esix、Solaris、Irix、SCO、Dell、NCR、VxWorks,LynxOS、pSOS、QNX、RTEMS、ARTOS。這是U-Boot中Universal的一層含義,另外一層含義則是U-Boot除了支持PowerPC系列的處理器外,還能支持MIPS、x86、ARM、NIOS、XScale等諸多常用系列的處理器。這兩個(gè)特點(diǎn)正是U-Boot項(xiàng)目的開發(fā)目標(biāo),即支持盡可能多的嵌入式處理器和嵌入式操作系統(tǒng)。就目前為止,U-Boot對(duì)PowerPC系列處理器支持最為豐富,對(duì)Linux的支持最完善。
U-Boot的特點(diǎn)如下。
? ?開放源碼;
? ?支持多種嵌入式操作系統(tǒng)內(nèi)核,如Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS;
? ?支持多個(gè)處理器系列,如PowerPC、ARM、x86、MIPS、XScale;
? ?較高的可靠性和穩(wěn)定性;
? ?高度靈活的功能設(shè)置,適合U-Boot調(diào)試,操作系統(tǒng)不同引導(dǎo)要求,產(chǎn)品發(fā)布等;
? ?豐富的設(shè)備驅(qū)動(dòng)源碼,如串口、以太網(wǎng)、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、鍵盤等;
? ?較為豐富的開發(fā)調(diào)試文檔與強(qiáng)大的網(wǎng)絡(luò)技術(shù)支持。
U-Boot可支持的主要功能列表。
? ?系統(tǒng)引導(dǎo):支持NFS掛載、RAMDISK(壓縮或非壓縮)形式的根文件系統(tǒng)。支持NFS掛載,并從FLASH中引導(dǎo)壓縮或非壓縮系統(tǒng)內(nèi)核。
? ?基本輔助功能:強(qiáng)大的操作系統(tǒng)接口功能;可靈活設(shè)置、傳遞多個(gè)關(guān)鍵參數(shù)給操作系統(tǒng),適合系統(tǒng)在不同開發(fā)階段的調(diào)試要求與產(chǎn)品發(fā)布,尤其對(duì)Linux支持最為強(qiáng)勁;支持目標(biāo)板環(huán)境參數(shù)多種存儲(chǔ)方式,如FLASH、NVRAM、EEPROM;CRC32校驗(yàn),可校驗(yàn)FLASH中內(nèi)核、RAMDISK鏡像文件是否完好。
? ?設(shè)備驅(qū)動(dòng):串口、SDRAM、FLASH、以太網(wǎng)、LCD、NVRAM、EEPROM、鍵盤、USB、PCMCIA、PCI、RTC等驅(qū)動(dòng)支持。
? ?上電自檢功能:SDRAM、FLASH大小自動(dòng)檢測(cè);SDRAM故障檢測(cè);CPU型號(hào)。
? ?特殊功能:XIP內(nèi)核引導(dǎo)。
1.1.2?U-Boot的常用命令
U-Boot上電啟動(dòng)后,按任意鍵可以退出自動(dòng)啟動(dòng)狀態(tài),進(jìn)入命令行。

在命令行提示符下,可以輸入U(xiǎn)-Boot的命令并執(zhí)行。U-Boot可以支持幾十個(gè)常用命令,通過(guò)這些命令,可以對(duì)開發(fā)板進(jìn)行調(diào)試,可以引導(dǎo)Linux內(nèi)核,還可以擦寫Flash完成系統(tǒng)部署等功能。掌握這些命令的使用,才能夠順利地進(jìn)行嵌入式系統(tǒng)的開發(fā)。
輸入help命令,可以得到當(dāng)前U-Boot的所有命令列表。每一條命令后面是簡(jiǎn)單的命令說(shuō)明。




U-Boot還提供了更加詳細(xì)的命令幫助,通過(guò)help命令還可以查看每個(gè)命令的參數(shù)說(shuō)明。由于開發(fā)過(guò)程的需要,有必要先把U-Boot命令的用法弄清楚。
實(shí)驗(yàn)?zāi)康?/h1>
熟悉交叉工具鏈的使用、u-boot常用命令、u-boot的代碼結(jié)構(gòu)和移植方法。
實(shí)驗(yàn)平臺(tái)
華清遠(yuǎn)見開發(fā)環(huán)境,F(xiàn)S-MP1A平臺(tái)
實(shí)驗(yàn)步驟
本實(shí)驗(yàn)基于u-boot 2020.01版本,然后添加意法半導(dǎo)體提供的補(bǔ)丁文件。在意法半導(dǎo)體官方的u-boot中移植我們自己的u-boot。
導(dǎo)入源碼
建立源碼目錄
linux@ubuntu:$ cd ~
linux@ubuntu:$ mkdir FS-MP1A
將【華清遠(yuǎn)見-FS-MP1A開發(fā)資料\02-程序源碼\04-Linux系統(tǒng)移植\01-官方源碼】下的
en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz壓縮包,導(dǎo)入到ubuntu下的${HOME}/FS-MP1A目錄下。

解壓縮源碼包
linux@ubuntu:$ tar xvf en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz
解壓完成后得到“
stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24”目錄

進(jìn)入uboot目錄下
linux@ubuntu:$ cd ~/FS-MP1A/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0

該目錄下以patch結(jié)尾的文件為ST官方提供的補(bǔ)丁文件;
u-boot-stm32mp-2020.01-r0.tar.gz為標(biāo)準(zhǔn)u-boot源碼包。
解壓標(biāo)準(zhǔn)u-boot源碼包
linux@ubuntu:$ tar -xvf u-boot-stm32mp-2020.01-r0.tar.gz
解壓完成后得到u-boot-stm32mp-2020.01目錄

進(jìn)入u-boot源碼目錄下:
linux@ubuntu:$ cd u-boot-stm32mp-2020.01

將ST官方補(bǔ)丁文件打到u-boot源碼中:
linux@ubuntu:$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done

TF卡分區(qū)
要對(duì)TF卡進(jìn)行燒錄,需要先將TF接入到ubuntu系統(tǒng)中。
查看TF卡分區(qū)
linux@ubuntu:$ ls /dev/sd*

由上圖所示只有“/dev/sdb1”一個(gè)分區(qū)則需要重新進(jìn)行分區(qū)。
首先刪除原有分區(qū)
linux@ubuntu:$ sudo parted -s /dev/sdb mklabel msdos
如果顯示如下內(nèi)容,則表示設(shè)備已經(jīng)被掛載,需要卸載掉設(shè)備再刪除分區(qū)。

卸載設(shè)備
linux@ubuntu:$ umount /dev/sdb1
卸載完成后重新執(zhí)行刪除分區(qū)命令
linux@ubuntu:$ sudo parted -s /dev/sdb mklabel msdos
對(duì)tf進(jìn)行重新分區(qū)
linux@ubuntu:$ sudo sgdisk --resize-table=128 -a 1 -n 1:34:545 -c 1:fsbl1 -n 2:546:1057 -c 2:fsbl2 -n 3:1058:5153 -c 3:ssbl -n 4:5154:136225 -c 4:bootfs -n 5:136226 -c 5:rootfs -A 4:set:2 -p /dev/sdb -g

注意:最后-p /dev/sdb參數(shù)中的/dev/sdb需要按照實(shí)際ubuntu中的tf節(jié)點(diǎn)為準(zhǔn),否則可能發(fā)生不可預(yù)料的后果。
建立自己的平臺(tái)
配置工具鏈
導(dǎo)入交叉編譯工具鏈(如果還未安裝SDK可參考《SDK工具鏈安裝》章節(jié)進(jìn)行安裝)
linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
驗(yàn)證開發(fā)工具是否安裝正確,顯示版本信息如下圖所示。
linux@ubuntu:$ $CC --version

增加板級(jí)相關(guān)文件
進(jìn)入到u-boot源碼目錄
linux@ubuntu:$ cd ~/FS-MP1A/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0/u-boot-stm32mp-2020.01/
添加自己的默認(rèn)配置文件
linux@ubuntu:$ cp configs/stm32mp15_basic_defconfig configs/stm32mp15_fsmp1a_basic_defconfig
添加設(shè)備樹文件
linux@ubuntu:$ cp arch/arm/dts/stm32mp15xx-dkx.dtsi arch/arm/dts/stm32mp15xx-fsmp1x.dtsi
linux@ubuntu:$ cp arch/arm/dts/stm32mp157a-dk1.dts arch/arm/dts/stm32mp157a-fsmp1a.dts
linux@ubuntu:$ cp arch/arm/dts/stm32mp157a-dk1-u-boot.dtsi arch/arm/dts/stm32mp157a-fsmp1a-u-boot.dtsi
修改
arch/arm/dts/stm32mp157a-fsmp1a.dts將
#include "stm32mp15xx-dkx.dtsi"
修改為
#include "stm32mp15xx-fsmp1x.dtsi"
修改arch/arm/dts/Makefile,在stm32mp157a-dk1.dtb下添加stm32mp157a-fsmp1a的內(nèi)容:

配置u-boot
使用新添加的默認(rèn)配置:
linux@ubuntu:$ make stm32mp15_fsmp1a_basic_defconfig

可以使用make menuconfig進(jìn)行圖形化配置

編譯源碼
執(zhí)行如下指令編譯u-boot:
linux@ubuntu:$ make DEVICE_TREE=stm32mp157a-fsmp1a all
編譯成功后,最后顯示內(nèi)容(部分截圖)如下:

編譯完成后會(huì)得到如下文件:

固件燒寫
由于在移植過(guò)程中會(huì)多次燒寫固件并且會(huì)導(dǎo)致正常u-boot無(wú)法啟動(dòng),因此推薦使用TF卡啟動(dòng)的方式來(lái)驗(yàn)證。
將TF接入ubuntu系統(tǒng)后,查看TF卡分區(qū)
linux@ubuntu:$ ls /dev/sd*

/dev/sdb為TF卡設(shè)備。如果該設(shè)備下只有/dev/sdb1一個(gè)分區(qū)則重新分區(qū)。
執(zhí)行如下指令燒寫u-boot:
linux@ubuntu:$ sudo dd if=u-boot-spl.stm32 of=/dev/sdb1 conv=FDatasync
linux@ubuntu:$ sudo dd if=u-boot-spl.stm32 of=/dev/sdb2 conv=FDatasync
linux@ubuntu:$ sudo dd if=u-boot.img of=/dev/sdb3 conv=FDatasync
啟動(dòng)開發(fā)板
將撥碼開關(guān)設(shè)置為SD卡啟動(dòng)方式:

將制作好的TF卡插入開發(fā)板,上電后會(huì)出現(xiàn)如下錯(cuò)誤提示:

錯(cuò)誤提示電源初始化錯(cuò)誤,需重新調(diào)整電源相關(guān)配置
調(diào)整設(shè)備樹電源配置
由于官方參考板DK1采用電源管理芯片做電源管理,而FS-MP1A采用分離電路作為電源管理,本例需要將文件中原有電源管理芯片相關(guān)內(nèi)容去掉,增加上固定電源相關(guān)內(nèi)容
去掉原有電源管理內(nèi)容
DK1參考板電源管理芯片掛在I2C4上,而FS-MP1A并未使用I2C4總線,所以直接將I2C4相關(guān)內(nèi)容完全刪除即可。
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi文件
將文件中i2c4節(jié)點(diǎn)相關(guān)內(nèi)容整體刪除,刪除內(nèi)容如下:
&i2c4 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c4_pins_a>;
pinctrl-1 = <&i2c4_pins_sleep_a>;
i2c-scl-rising-time-ns = <185>;
i2c-scl-falling-time-ns = <20>;
clock-frequency = <400000>;
status = "disabled";
/*內(nèi)容太長(zhǎng)此處省略*/
watchdog {
compatible = "st,stpmic1-wdt";
status = "disabled";
};
};
};
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi文件,刪除如下內(nèi)容:
&cpu0{
cpu-supply = <&vddcore>;
};
&cpu1{
cpu-supply = <&vddcore>;
};
修改
arch/arm/dts/stm32mp157a-fsmp1a-u-boot.dtsi
文件
刪除如下內(nèi)容:
&pmic {
u-boot,dm-pre-reloc;
};
由于官方參考板DK1 I2C4總線上有個(gè)USB type C的控制器,上文刪除I2C4節(jié)點(diǎn)的同時(shí)將type C控制器的描述刪除,所以需要將引用type C控制器的內(nèi)容刪掉。
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi文件,刪除紅色部分內(nèi)容:
&usbotg_hs {
phys = <&usbphyc_port1 0>;
phy-names = "usb2-phy";
usb-role-switch;
status = "okay";
port {
usbotg_hs_ep: endpoint {
remote-endpoint = <&con_usbotg_hs_ep>;
};
};
};
添加固定電源配置
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi文件
固定電源配置通常添加在根節(jié)點(diǎn)下,在根節(jié)點(diǎn)末尾位置添加如下內(nèi)容(紅色字體為需要添加的內(nèi)容):
vin: vin {
compatible = "regulator-fixed";
regulator-name = "vin";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
v3v3: regulator-3p3v {
compatible = "regulator-fixed";
regulator-name = "v3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
v1v8_audio: regulator-v1v8-audio {
compatible = "regulator-fixed";
regulator-name = "v1v8_audio";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
};
v3v3_hdmi: regulator-v3v3-hdmi {
compatible = "regulator-fixed";
regulator-name = "v3v3_hdmi";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
v1v2_hdmi: regulator-v1v2-hdmi {
compatible = "regulator-fixed";
regulator-name = "v1v2_hdmi";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
};
vdd: regulator-vdd {
compatible = "regulator-fixed";
regulator-name = "vdd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
vdd_usb: regulator-vdd-usb {
compatible = "regulator-fixed";
regulator-name = "vdd_usb";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
};
};
配置uboot
linux@ubuntu:$ make menuconfig
去掉PMIC的配置選項(xiàng),按空格將方括號(hào)內(nèi)*號(hào)去掉:
Device Drivers --->
Power --->
[ ] Enable support for STMicroelectronics STPMIC1 PMIC
更新配置文件
linux@ubuntu:$ cp .config configs/stm32mp15_fsmp1a_basic_defconfig
重新編譯源碼
linux@ubuntu:$ make DEVICE_TREE=stm32mp157a-fsmp1a all
燒寫后啟動(dòng)
重新燒寫后啟動(dòng)現(xiàn)象如下:

提示顯示TF卡未被檢測(cè)到。
TF卡支持
系統(tǒng)檢測(cè)TF卡拔插是通過(guò)CD腳的狀態(tài)確認(rèn),通過(guò)原理圖可知,TF卡對(duì)應(yīng)MMC1的CD腳是與STM32MP1的PH3連接

對(duì)照設(shè)備樹中MMC1的描述,發(fā)現(xiàn)設(shè)備樹種原有CD腳的配置與FS-MP1A板子不一致,需調(diào)整為PH3。
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi文件,調(diào)整MMC1中CD的配置:
將如下內(nèi)容
&sdmmc1 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc1_b4_pins_a>;
pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
cd-gpios = <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
disable-wp;
st,neg-edge;
bus-width = <4>;
vmmc-supply = <&v3v3>;
status = "okay";
};
修改為
&sdmmc1 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc1_b4_pins_a>;
pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
cd-gpios = <&gpioh 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
disable-wp;
st,neg-edge;
bus-width = <4>;
vmmc-supply = <&v3v3>;
status = "okay";
};
重新編譯燒寫后現(xiàn)象如下:

去掉ADC功能
上一小節(jié)已經(jīng)成功啟動(dòng)到了u-boot的控制終端,但是可以看到還有一些錯(cuò)誤。本小節(jié)將解決如下錯(cuò)誤。

官方參考板DK1通過(guò)ADC檢測(cè)開機(jī)電流,如果供電電流不足3A則啟動(dòng)失敗,F(xiàn)S-MP1A沒有設(shè)計(jì)這個(gè)功能,所以需要去掉這部分功能,否則就會(huì)報(bào)上圖中顯示的錯(cuò)誤,由于u-boot期間ADC主要功能是檢測(cè)開機(jī)電流,這里直接去掉ADC功能即可。
配置uboot去掉ADC功能:按空格鍵去掉[ ]的星號(hào)
linux@ubuntu:$ make menuconfig
Command line interface --->
Device access commands --->
[ ] adc - Access ANALog to Digital Converters info and data
Device Drivers --->
[ ] Enable ADC drivers using Driver Model
更新配置文件
linux@ubuntu:$ cp .config configs/stm32mp15_fsmp1a_basic_defconfig
重新編譯燒寫后adc相關(guān)錯(cuò)誤已經(jīng)沒有了。

關(guān)閉ltdc
由于在u-boot階段我們不使用顯示設(shè)備,因此需要將ltdc相關(guān)配置關(guān)閉。
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi文件
<dc {
pinctrl-names = "default", "sleep";
pinctrl-0 = <<dc_pins_a>;
pinctrl-1 = <<dc_pins_sleep_a>;
status = "okay";
port {
#address-cells = <1>;
#size-cells = <0>;
ltdc_ep0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&sii9022_in>;
};
};
};
修改為
<dc {
pinctrl-names = "default", "sleep";
pinctrl-0 = <<dc_pins_a>;
pinctrl-1 = <<dc_pins_sleep_a>;
status = "disabled";
port {
#address-cells = <1>;
#size-cells = <0>;
ltdc_ep0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&sii9022_in>;
};
};
};
然后重新編譯燒寫
有線網(wǎng)卡配置
啟動(dòng)設(shè)備進(jìn)入u-boot控制臺(tái)之后,可以發(fā)現(xiàn)啟動(dòng)信息中有網(wǎng)卡未被發(fā)現(xiàn)的錯(cuò)誤信息,這個(gè)錯(cuò)誤是由于u-boot沒有設(shè)置正確的MAC地址,由啟動(dòng)信息可以看到,啟動(dòng)后網(wǎng)卡的MAC為00:00:00:00:00:00。這是由于在OTP中沒有固化默認(rèn)的MAC地址,解決這個(gè)問題可以通過(guò)燒寫OTP配置來(lái)進(jìn)行默認(rèn)MAC地址配置,但是由于操作OTP配置的風(fēng)險(xiǎn)較高,如果操作不當(dāng)可能會(huì)導(dǎo)致不可預(yù)料的結(jié)果。
如果u-boot期間不使用網(wǎng)卡這個(gè)錯(cuò)誤可以忽略。
如果需要使用網(wǎng)卡解決這個(gè)問題比較簡(jiǎn)單的方法有兩個(gè):
U-boot啟動(dòng)后通過(guò)命令設(shè)置一個(gè)MAC地址
STM32MP> env set -f ethaddr 1A:1F:DB:0E:69:FD
這種方式設(shè)置完成后即刻生效,重啟后網(wǎng)卡即可正常工作。
修改include/configs/stm32mp1.h,增加默認(rèn)環(huán)境變量
修改如下內(nèi)容:
#define CONFIG_EXTRA_ENV_SETTINGS \
"bootdelay=1\0" \
"kernel_addr_r=0xc2000000\0" \
"FDt_addr_r=0xc4000000\0" \
"scriptaddr=0xc4100000\0" \
為:
#define CONFIG_EXTRA_ENV_SETTINGS \
"bootdelay=1\0" \
"ethaddr=00:80:E1:42:60:17\0" \
"kernel_addr_r=0xc2000000\0" \
"FDt_addr_r=0xc4000000\0" \
"scriptaddr=0xc4100000\0" \
這種方式需重新編譯燒寫后才能生效。
重新編譯燒寫后網(wǎng)卡即可正常工作:

將網(wǎng)線插入開發(fā)板中可以進(jìn)行網(wǎng)絡(luò)測(cè)試。
使用dhcp命令獲取ip地址:
STM32MP> dhcp

可以看到這里獲取到的ip地址為192.168.11.81
Ping網(wǎng)關(guān)測(cè)試:
Board $> ping 192.168.11.1

Ping外網(wǎng)測(cè)試:
Board $> ping 8.8.8.8

eMMC移植
參考原理圖可知eMMC使用的是SDMMC2總線,當(dāng)前所使用的設(shè)備樹文件中沒有SDMMC2的支持,所以需要增加相關(guān)內(nèi)容才能正常驅(qū)動(dòng)eMMC。

由于在使STM32MP1芯片很多管腳為多功能復(fù)用管腳,且很多管腳具備同樣的功能,所以移植eMMC時(shí)需要確認(rèn)硬件設(shè)計(jì)是使用的是那些管腳,根據(jù)原理圖確認(rèn)后管腳對(duì)應(yīng)關(guān)系為:

管腳定義
在u-boot中STM32MP1默認(rèn)管腳定義在文件
arch/arm/dts/stm32mp15-pinctrl.dtsi中,查看文件中是否有需要的管腳定義:
查看后確認(rèn)有SDMMC2的管腳定義,且與FS-MP1A硬件使用情況一致,定義如下:
sdmmc2_b4_pins_a: sdmmc2-b4-0 {
pins1 {
pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
<STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
slew-rate = <1>;
drive-push-pull;
bias-pull-up;
};
pins2 {
pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
slew-rate = <2>;
drive-push-pull;
bias-pull-up;
};
};
sdmmc2_b4_od_pins_a: sdmmc2-b4-od-0 {
pins1 {
pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, AF9)>; /* SDMMC2_D3 */
slew-rate = <1>;
drive-push-pull;
bias-pull-up;
};
pins2 {
pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
slew-rate = <2>;
drive-push-pull;
bias-pull-up;
};
pins3 {
pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
slew-rate = <1>;
drive-open-drain;
bias-pull-up;
};
};
sdmmc2_b4_sleep_pins_a: sdmmc2-b4-sleep-0 {
pins {
pinmux = <STM32_PINMUX('B', 14, ANALOG)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, ANALOG)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, ANALOG)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, ANALOG)>, /* SDMMC2_D3 */
<STM32_PINMUX('E', 3, ANALOG)>, /* SDMMC2_CK */
<STM32_PINMUX('G', 6, ANALOG)>; /* SDMMC2_CMD */
};
};
sdmmc2_b4_pins_b: sdmmc2-b4-1 {
pins1 {
pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, AF9)>, /* SDMMC2_D3 */
<STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
slew-rate = <1>;
drive-push-pull;
bias-disable;
};
pins2 {
pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
slew-rate = <2>;
drive-push-pull;
bias-disable;
};
};
sdmmc2_b4_od_pins_b: sdmmc2-b4-od-1 {
pins1 {
pinmux = <STM32_PINMUX('B', 14, AF9)>, /* SDMMC2_D0 */
<STM32_PINMUX('B', 15, AF9)>, /* SDMMC2_D1 */
<STM32_PINMUX('B', 3, AF9)>, /* SDMMC2_D2 */
<STM32_PINMUX('B', 4, AF9)>; /* SDMMC2_D3 */
slew-rate = <1>;
drive-push-pull;
bias-disable;
};
pins2 {
pinmux = <STM32_PINMUX('E', 3, AF9)>; /* SDMMC2_CK */
slew-rate = <2>;
drive-push-pull;
bias-disable;
};
pins3 {
pinmux = <STM32_PINMUX('G', 6, AF10)>; /* SDMMC2_CMD */
slew-rate = <1>;
drive-open-drain;
bias-disable;
};
};
sdmmc2_d47_pins_a: sdmmc2-d47-0 {
pins {
pinmux = <STM32_PINMUX('A', 8, AF9)>, /* SDMMC2_D4 */
<STM32_PINMUX('A', 9, AF10)>, /* SDMMC2_D5 */
<STM32_PINMUX('E', 5, AF9)>, /* SDMMC2_D6 */
<STM32_PINMUX('D', 3, AF9)>; /* SDMMC2_D7 */
slew-rate = <1>;
drive-push-pull;
bias-pull-up;
};
};
sdmmc2_d47_sleep_pins_a: sdmmc2-d47-sleep-0 {
pins {
pinmux = <STM32_PINMUX('A', 8, ANALOG)>, /* SDMMC2_D4 */
<STM32_PINMUX('A', 9, ANALOG)>, /* SDMMC2_D5 */
<STM32_PINMUX('E', 5, ANALOG)>, /* SDMMC2_D6 */
<STM32_PINMUX('D', 3, ANALOG)>; /* SDMMC2_D7 */
};
};
增加SDMMC2節(jié)點(diǎn)信息
修改
arch/arm/dts/stm32mp15xx-fsmp1x.dtsi增加SDMMC2的信息
在原有sdmmc1節(jié)點(diǎn)下增加sdmmc2的內(nèi)容,添加內(nèi)容可參考
arch/arm/dts/stm32mp15xx-edx.dtsi中sdmmc2的寫法,內(nèi)容如下:
&sdmmc2 {
pinctrl-names = "default", "opendrain", "sleep";
pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>;
pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>;
non-removable;
no-sd;
no-sdio;
st,neg-edge;
bus-width = <8>;
vmmc-supply = <&v3v3>;
vqmmc-supply = <&vdd>;
mmc-ddr-3_3v;
status = "okay";
};
增加mmc映射
修改
arch/arm/dts/stm32mp157a-fsmp1a-u-boot.dtsi文件,調(diào)整啟動(dòng)通道。
修改如下內(nèi)容:
aliases {
i2c3 = &i2c4;
mmc0 = &sdmmc1;
usb0 = &usbotg_hs;
};
修改為(紅色字體為增加內(nèi)容):
aliases {
i2c3 = &i2c4;
mmc0 = &sdmmc1;
mmc1 = &sdmmc2;
usb0 = &usbotg_hs;
};
在sdmmc1節(jié)點(diǎn)后sdmmc2的內(nèi)容(紅色字體部分為添加內(nèi)容):
&sdmmc1 {
u-boot,dm-spl;
};
&sdmmc2 {
u-boot,dm-spl;
};
測(cè)試
重新編譯燒寫后啟動(dòng)信息對(duì)比前文多一個(gè)MMC:

eMMC的驗(yàn)證需要通過(guò)linux更新,相關(guān)操作可參考《通過(guò)linux更新eMMC中的u-boot》章節(jié)。
生成Trusted鏡像
前面我們做的相關(guān)配置都是基于basic的配置,而實(shí)際FS-MP1A使用的uboot是基于Trusted配置的鏡像,后邊的《Trusted Firmware-A移植》章節(jié)會(huì)使用到Trusted鏡像。
建立基礎(chǔ)的Trusted配置文件
linux@ubuntu:$ cp configs/stm32mp15_trusted_defconfig configs/stm32mp15_fsmp1a_trusted _defconfig
linux@ubuntu:$ make stm32mp15_fsmp1a_trusted_defconfig
去掉PMIC的配置選項(xiàng),按空格將方括號(hào)內(nèi)*號(hào)去掉:
linux@ubuntu:$ make menuconfig
Device Drivers --->
Power --->
[ ] Enable support for STMicroelectronics STPMIC1 PMIC
去掉ADC功能:按空格鍵去掉[ ]的星號(hào)
linux@ubuntu:$ make menuconfig
Command line interface --->
Device access commands --->
[ ] adc - Access ANALog to Digital Converters info and data
Device Drivers --->
[ ] Enable ADC drivers using Driver Model
修改配置文件
linux@ubuntu:$ cp .config configs/stm32mp15_fsmp1a_trusted_defconfig
修改上層目錄下的Makefile.sdk編譯腳本在UBOOT_CONFIGS配置項(xiàng)中添加“stm32mp15_fsmp1a_trusted_defconfig,trusted,u-boot.stm32”在DEVICE_TREE配置項(xiàng)中添加“stm32mp157a-fsmp1a”
UBOOT_CONFIGS ?= stm32mp15_fsmp1a_trusted_defconfig,trusted,u-boot.stm32 stm32mp15_trusted_defconfig,trusted,u-boot.stm32 stm32mp15_trusted_defconfig,optee,u-boot.stm32 stm32mp15_basic_defconfig,basic,u-boot.img
DEVICE_TREE ?= stm32mp157a-fsmp1a stm32mp157a-dk1 stm32mp157d-dk1 stm32mp157c-dk2 stm32mp157f-dk2 stm32mp157c-ed1 stm32mp157f-ed1 stm32mp157a-ev1 stm32mp157c-ev1 stm32mp157d-ev1 stm32mp157f-ev1
編譯trusted鏡像
linux@ubuntu:$ make distclean
linux@ubuntu:$ make -f $PWD/../Makefile.sdk all UBOOT_CONFIGS=stm32mp15_fsmp1a_trusted_defconfig,trusted,u-boot.stm32

編譯完成后生成的鏡像文件在上級(jí)目錄下的build-trusted文件夾中有一個(gè)“u-boot-stm32mp157a-fsmp1a-trusted.stm32”
linux@ubuntu:$ cd ../ build-trusted
linux@ubuntu:$ ls

u-boot-stm32mp157a-fsmp1a-trusted.stm32即為我們后續(xù)會(huì)使用的鏡像文件。