Linux U-Boot 開發指南
1 前言
1.1 編寫目的
介紹 U-Boot 的編譯打包、基本配置、常用命令的使用、基本調試方法等, 為 U-BOOT 的移植及應用開發提供了基礎。
1.2 適用范圍
本文檔適用于 brandy2.0, 即 U-Boot-2018 平臺。
1.3 相關人員
U-Boot 開發/維護人員,內核開發人員。
2 LICHEE 類宏關鍵字解釋
請到 longan 目錄下的.buildconfig 查看目前使用了以下 LICHEE 類宏。
LICHEE_IC ——> IC名
LICHEE_CHIP ——> 平臺名
LICHEE_BOARD ——> 板級名
LICHEE_ARCH ——> 所屬架構
LICHEE_BOARD_CONFIG_DIR ——> 板級目錄
LICHEE_BRANDY_OUT_DIR ——> bin文件所在目錄
LICHEE_PLAT_OUT ——> 平臺臨時bin所在目錄
LICHEE_CHIP_CONFIG_DIR ——> IC目錄
3 編譯方法介紹
3.1 準備編譯工具鏈
準備編譯工具鏈接執行步驟如下:
1)cd longan/brandy/brandy-2.0/
2)./build.sh -t
3.2 快速編譯 boot0 及 U-Boot
在longan/brandy/brandy-2.0/目錄下,執行 ./build.sh -p 平臺名稱,可以快速完成整個 boot 編譯動作。這個平臺名稱是指,LICHEE_CHIP。
./build.sh -p {LICHEE_CHIP} //快速編譯spl/U-Boot
./build.sh -o spl-pub -p {LICHEE_CHIP} //快速編譯spl-pub
./build.sh -o uboot -p {LICHEE_CHIP} //快速編譯U-Boot
3.3 編譯 U-Boot
cd longan/brandy/brandy-2.0/u-boot-2018/進入 u-boot-2018 目錄。以{LICHEE_CHIP}為例,依次執行如下操作即可。
1)make {LICHEE_CHIP}_defconfig
2)make -j
3.4 編譯 boot0/fes/sboot
cd longan/brandy/brandy-2.0/spl-pub進入spl-pub目錄,需設置平臺和要編譯的模塊參數。以{LICHEE_CHIP}為例,編譯 nand/emmc 的方法如下:
編譯boot0
make distclean
make p={LICHEE_CHIP} m=nand
make boot0
?
make distclean
make p={LICHEE_CHIP} m=emmc
make boot0
編譯fes
make distclean
make p={LICHEE_CHIP} m=fes
make fes
編譯sboot
make distclean
make p={LICHEE_CHIP} m=sboot
make sboot
4 U-Boot 功能及其配置方法/文件介紹
4.1 U-Boot 功能介紹
在嵌入式操作系統中,BootLoader/U-Boot 是在操作系統內核運行之前運行??梢猿跏蓟布O備、建立內存空間映射圖,從而將系統的軟硬件環境帶到一個合適狀態,以便為最終調用操作系統內核準備好正確的環境。在 sunxi 平臺中,除了必須的引導系統啟動功能外,BOOT 系統還提供燒寫、升級等其它功能。
U-Boot 主要功能可以分為以下幾類
引導內核
能從存儲介質(nand/mmc/spinor)上加載內核鏡像到 DRAM 指定位置并運行。
量產 & 升級
包括卡量產,USB 量產,私有數據燒錄,固件升級
開機提示信息
開機能顯示啟動 logo 圖片(BMP 格式)
Fastboot 功能
實現 fastboot 的標準命令,能使用 fastboot 刷機
4.2 U-Boot 功能配置方法介紹
U-Boot 中的各項功能可以通過 defconfig 或配置菜單 menuconfig 進行開啟或關閉, 具體配置
方法如下:
4.2.1 通過 defconfig 方式配置
vim /longan/brandy/brandy-2.0/u-boot-2018/configs/{LICHEE_CHIP}_defconfig
開{LICHEE_CHIP}defconfig或{LICHEE_CHIP}nor_defconfig后,在相應的宏定義前去掉或添加"#"即可將相應功能開啟或關閉。如下圖,只要將CONFIG_SUNXI_NAND前的#去掉即可支持 NAND 相關功能,其他宏定義的開啟關閉也類似。修改后需要運行make xxx_defconfig使修改后的配置生效。

圖 4-1: defconfig 配置圖
4.2.2 通過 menuconfig 方式配置
通過 menuconfig 方式配置的方法步驟如下:
cd brandy/brandy-2.0/u-boot-2018/
執行make menuconfig命令,會彈出 menuconfig 配置菜單窗口,如下圖所示。此時即可對各模塊功能進行配置,配置方法 menuconfig 配置菜單窗口中有說明。
修改后配置已經生效,直接 make 即可生成對應 bin。如果重新運行make xxx_defconfig,通過menuconfig 方式修改的配置會在運行make xxx_defconfig后被xxx_defconfig中的配置覆蓋。

圖 4-2: menuconfig 配置菜單圖
4.3 U-Boot 配置參數文件介紹
U-Boot 自 linux-5.4 以后不再使用 sysconfig 和內核 dts 作為配置文件,而是使用 U-Boot 自帶的 dts 來配置參數。kernel-dts 與 U-Boot-dts 完全獨立。
4.3.1 U-Boot-dts 路徑
U-Boot-dts 路徑為:vim longan/brandy/brandy-2.0/u-boot-2018/arch/arm/dts
4.3.2 U-Boot-dts,defconfig 配置
配置項 | 配置項含義 |
---|---|
CONFIG_OF_SEPARATE | 構建 U-Boot 設備樹成為 U-Boot 的一部分 |
CONFIG_OF_BOARD | 關閉使用外部 dts |
CONFIG_DEFAULT_DEVICE_TREE | 選擇構建的 dts 文件文件名 |
CONFIG_SUNXI_NECESSARY_REPLACE_FDT | 開啟選項, 實現內部 dts 換成外部 dts |
配置項 | 選項 |
---|---|
CONFIG_OF_SEPARATE | y |
CONFIG_OF_BOARD | n |
CONFIG_DEFAULT_DEVICE_TREE | “{LICHEE_CHIP}-soc-system” |
CONFIG_SUNXI_NECESSARY_REPLACE_FDT | y |
4.3.3 U-Boot-dts 注意事項
4.3.3.1 編譯注意事項
1.dts 分為板級 dts,和系統 dts。
?? 系統 dts 由 CONFIG_DEFAULT_DEVICE_TREE 決定,可以在 $(CONFIG_SYS_CONFIG_NAME)_defconfig找到該宏的定義。
?? 系統 dts 最終會 include 板級 dts,文件路徑 {LICHEE_BOARD_CONFIG_DIR},文件名:uboot-board.dts。
我們可以通過編譯時的打印判斷啟動的 dts
OBJCOPY examples/standalone/hello_world.srec
OBJCOPY examples/standalone/hello_world.bin
LD u-boot
OBJCOPY u-boot.srec
OBJCOPY u-boot-nodtb.bin
‘{LICHEE_BOARD_CONFIG_DIR}/uboot-board.dts’ -> ‘~/longan/brandy/brandy-2.0/u-boot-2018/
arch/{LICHEE_ARCH}/dts/.board-uboot.dts’
DTC arch/{LICHEE_ARCH}/dts/{LICHEE_CHIP}-soc-system.dtb
SYM u-boot.sym
SHIPPED dts/dt.dtb
FDTGREP dts/dt-spl.dtb
COPY u-boot.dtb
CAT u-boot-dtb.bin
COPY u-boot.bin
‘u-boot.bin’ -> ‘{LICHEE_CHIP}.bin’ ‘u-boot-g{LICHEE_CHIP}.bin’ -> ‘{LICHEE_BRANDY_OUT_DIR}/bin/u-boot-g{LICHEE_CHIP}.bin’ ‘u-boot-g{LICHEE_CHIP}.bin’ -> ‘{LICHEE_PLAT_OUT}/u-boot-g{LICHEE_CHIP}.bin’
CFGCHK u-boot.cfg
4.3.3.2 語法注意事項
當系統 dts 與板級 dts 存在同路徑下同名節點時,板級 dts 將會覆蓋系統 dts。
4.3.3.3 運行時注意事項
為了在啟動內核前更新參數到內核 dts 和可以在 U-Boot 控制臺查看修改 dts。按階段劃分可以分為使用內部 dts 階段和使用內核 dts 階段,如下圖所示。

圖 4-3: dts 變化圖
可以通過命令set_working_fdt來切換當前生效的 fdt。
[04.562]update bootcmd [04.576]change working_fdt 0x7bebee58 to 0x7be8ee58 [04.587]update dts Hit any key to stop autoboot: 0 => set set_working_fdt setenv setexpr => set_working_fdt 0x7bebee58 change working_fdt 0x7be8ee58 to 0x7bebee58 =>
5 U-Boot 常用命令介紹
5.1 env 命令說明
通過env命令可以對{LICHEE_CHIP_CONFIG_DIR}/configs/default/env.cfg中的環境變量進行查看及更改。在小機啟動過程中按任意鍵進入 U-Boot shell 命令狀態,輸入命令"env"即可查看命令幫助信息。
具體示例如下:
輸入命令"env print",可查看當前所有的環境變量信息,如下:
=> pri ab_partition_list=bootloader,env,boot,vendor_boot,dtbo,vbmeta,vbmeta_system,vbmeta_vendor android_trust_chain=true boot_fastboot=fastboot boot_normal=sunxi_flash read 45000000 boot;bootm 45000000 boot_recovery=sunxi_flash read 45000000 recovery;bootm 45000000 bootcmd=run setargs_mmc boot_normal bootdelay=0 bootreason=charger bt_mac=20:A1:11:12:13:44 cma=8M console=ttyAS0,115200 earlyprintk=sunxi-uart,0x05000000 fdtcontroladdr=7bed0e60 fileaddr=40000000 filesize=15cf6 force_normal_boot=1 init=/init initcall_debug=0 keybox_list=widevine,ec_key,ec_cert1,ec_cert2,ec_cert3,rsa_key,rsa_cert1,rsa_cert2,rsa_cert3 loglevel=8 mac=10:14:15:15:9A:CA mmc_root=/dev/mmcblk0p4 nand_root=/dev/nand0p4 partitions=bootloader_a@mmcblk0p1:bootloader_b@mmcblk0p2:env_a@mmcblk0p3:env_b@mmcblk0p4: boot_a@mmcblk0p5:boot_b@mmcblk0p6:vendor_boot_a@mmcblk0p7:vendor_boot_b@mmcblk0p8: super@mmcblk0p9:misc@mmcblk0p10:vbmeta_a@mmcblk0p11:vbmeta_b@mmcblk0p12: vbmeta_system_a@mmcblk0p13:vbmeta_system_b@mmcblk0p14:vbmeta_vendor_a@mmcblk0p15: vbmeta_vendor_b@mmcblk0p16:frp@mmcblk0p17:empty@mmcblk0p18:metadata@mmcblk0p19: private@mmcblk0p20:dtbo_a@mmcblk0p21:dtbo_b@mmcblk0p22:media_data@mmcblk0p23: UDISK@mmcblk0p24 rotpk_status=0 setargs_mmc=setenv bootargs earlyprintk=${earlyprintk} clk_ignore_unused initcall_debug=${ initcall_debug} console=${console} loglevel=${loglevel} root=${mmc_root} init=${init} cma=${cma} snum=${snum} mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac} specialstr=${specialstr} gpt=1 androidboot.force_normal_boot=${force_normal_boot} androidboot.slot_suffix=${slot_suffix} setargs_nand=setenv bootargs earlyprintk=${earlyprintk} clk_ignore_unused initcall_debug=${ initcall_debug} console=${console} loglevel=${loglevel} root=${nand_root} init=${init} cma=${cma} snum=${snum} mac_addr=${mac} wifi_mac=${wifi_mac} bt_mac=${bt_mac} specialstr=${specialstr} gpt=1 androidboot.force_normal_boot=${force_normal_boot} androidboot.slot_suffix=${slot_suffix} slot_suffix=_a snum=A100B3N041 wifi_mac=10:A1:11:12:13:44 Environment size: 2078/131068 bytes =>
輸入命令"env set bootdelay 3",可更改環境變量bootdelay(即 boot 啟動時 log 中的倒計時延遲時間)值的大小。
輸入命令"env save",即可將上述更改進行保存,保存后重新上電,或輸入命令"reset",即可看到上述更改bootdelay的延時時間被更改生效。
其他env命令請查看env幫助信息。
5.2 sunxi_flash read 命令說明
5.2.1 使用方法
用以下命令將 flash 指定地址中數據讀到 DRAM 的指定地址處:
sunxi_flash read dram_addr flash_addr
5.2.2 使用示例
sunxi_flash read 0x45000000 env—將env分區數據讀到DRAM的0x45000000地址處 sunxi_flash read 45000000 boot;bootm 45000000—將flash中boot分區數據讀到DRAM的0x45000000地 址,并 從0x45000000處啟動。
5.3 fastboot 命令說明
fastboot 是 Android 平臺上一個通用的刷機工具,也是一個很好的開發調試工具,以下介紹 fastboot 的基本使用方法。
5.3.1 使用前提
fastboot PC 端工具可以從 Google Android SDK(Android-sdk-windows/tools) 中獲得,也可以在 Android 源代碼編譯過后的生成文件獲得 (out/host/linux-x86/bin)。
在 Linux 系統中,使用 fastboot 不需要安裝驅動。但在 Windows 系統中,使用 fastboot 前需安裝 fastboot 相關驅動。adb 的驅動在 fastboot 模式下也可以安裝成功,但是無法使用,請使用我們提供的驅動,并手動安裝。
5.3.2 使用步驟
小機上電啟動,按任意鍵進入 U-Boot 命令狀態;
串口端輸入"fastboot"命令;
打開 PC 端 fastboot 工具,并輸入"fastboot devices"命令,看是否有 fastboot 設備顯示;
在正確獲取 fastboot 設備的前提下,輸入命令"fastboot flash env /path/to/env.fex",將env.fex寫到env分區(/path/to/目錄下的env.fex中bootdelay值應該與 flash 中原有env中bootdelay值不同,這樣可根據bootdelay值不同來確定 fastboot 燒寫是否成功), 同下載env.fex分區一樣, 輸入命令“fastboot flash boot /path/to/boot.img”將內核下載到內存中;
輸入"fastboot reboot"命令重啟,查看啟動倒計時即bootdelay的值是否改變;
5.3.3 fastboot 基本命令使用示例
fastboot 幾個基本命令示例如下:
fastboot devices :顯示 fastboot 的設備。
fastboot erase :擦除分區,例如fastboot erase boot,擦除boot分區。
fastboot flash:舊分區(待寫分區),例如fastboot flash boot/path/to/boot.img,將boot.img寫到boot分區。
注意事項:
fastboot 中使用的分區和sys_partition.fex中分區一致,具體的分區信息可以從小機上電啟動進入 U-Boot shell 命令狀態,輸入命令"part list sunxi_flash 0"中獲取,分區信息如下:
=> part list sunxi_flash 0 Partition Map for UNKNOWN device 0 -- Partition Type: EFI Part Start LBA End LBA Name Attributes Type GUID Partition GUID 1 0x00008000 0x00017fff "bootloader" attrs: 0x8000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: a0085546-4166-744a-a353-fca9272b8e45 2 0x00018000 0x0001ffff "env" attrs: 0x8000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: a0085546-4166-744a-a353-fca9272b8e46 3 0x00020000 0x0002ffff "boot" attrs: 0x8000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: a0085546-4166-744a-a353-fca9272b8e47 4 0x00030000 0x0032ffff "super" attrs: 0x8000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: a0085546-4166-744a-a353-fca9272b8e48 5 0x00330000 0x00337fff "misc" attrs: 0x8000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: a0085546-4166-744a-a353-fca9272b8e49 6 0x00338000 0x00347fff "recovery" attrs: 0x8000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 guid: a0085546-4166-744a-a353-fca9272b8e4a
5.4 fat 命令說明
fat命令可以對 FAT 文件系統的相關存儲設備進行查詢及文件讀寫操作,在打包固件的時候, 我們會制作啟動資源分區鏡像, 把指定的目錄下的文件按照文件系統的格式排布,文件中包括了原來目錄中的所有文件,并完全按照目錄結構排列。當把這個鏡像文件燒寫到存儲設備上的某一個分區的時候,可以看到這個分區和原有目錄的內容一樣。使用fat可以方便地以文件和目錄的方式對小機 flash 進行數據訪問,如顯示 logo。這些指令基本上要和 U 盤或者 SD 卡同時使用,主要用于讀取這些移動存儲器上的 FAT 分區。其相關操作命令如下:
fatls : 列出相應設備目錄上的所有文件,示例如下圖:

圖 5-1: fatls 命令執行示例圖
說明
補充說明,fatls mmc 2:2 中的第一個 2 表示的是 emmc 設備,2 表示其分區號,其說明如下圖:

圖 5-2: fatls 命令參數說明圖
fatinfo: 打印出相應設備目錄的文件系統信息,示例如下圖:

圖 5-3: fatinfo 命令執行示例圖
fatload: 從 FAT 文件系統中讀取二進制文件到 RAM 存儲中,示例如下:
sunxi#usb start (Re)start USB... USB0: start sunxi ehci1... config usb pin success config usb clk ok sunxi ehci1 init ok... USB EHCI 1.00 scanning bus 0 for devices... 3 USB Device(s) found scanning usb for storage devices... 1 Storage Device(s) found sunxi#fatls usb 0:1 / 16024600 sandisksecureaccessv3_win.exe sandisk secureaccess/ lost.dir/ Android/ test/ video test/ amapauto/ 0 vid_20161017_160818.ts phoenixsuit/ system volume information/ 0 vid_20161017_160919.ts video/ 156672 wifi pro_com su.exe 495 sys.ini 1035 pr_80211g_all.ini config/ 158208 wifi pro_new.exe 158208 wifi pro.exe 0 vid_20161017_164822.ts 0 vid_20161017_164906.ts sunxi-tvd/ 71149 sys_config.fex vga/ 397836884 system.img 14180352 boot.img 13 file(s), 13 dir(s) sunxi#fatload usb 0:1 0x42000000 boot.img reading boot.img 14180352 bytes read in 1149 ms (11.8 MiB/s) sunxi#mmc dev 2 mmc2(part 0) is current device sunxi#mmc write 0x42000000 0x15000 5000 MMC write: dev # 2, block # 86016, count 20480 ... 20480 blocks written: OK
說明:以上操作即將 U 盤的boot.img寫到對應的 mmc 分區地址處。
fatwrite: 從內存中將對應的文件寫到設備文件系統中。
5.5 md 命令說明
md命令可以對指定內存的數據進行查看,方便了解內存的數據情況及調試工作。其使用方法如下:
md 0xF0000000: 即用md命令查看內存DRAM 0xF0000000處內容
5.6 FDT 命令說明
FDT:flattened device tree 的縮寫在 U-Boot 控制臺停下后,輸入fdt,可以查看fdt命令幫助。
sunxi#fdt fdt - flattened device tree utility commands Usage: fdt addr [-c] [] - Set the [control] fdt location to fdt move - Copy the fdt to and make it active fdt resize - Resize fdt to size + padding to 4k addr fdt print [] - Recursive print starting at fdt list [] - Print one level starting at fdt get value - Get and store in fdt get name - Get name of node and store in fdt get addr - Get start address of and store in fdt get size [] - Get size of [] or num nodes and store in fdt set [] - Set [to ] fdt mknode - Create a new node after fdt rm [] - Delete the node or fdt header fdt bootcpu - Set boot cpuid fdt memory - Add/Update memory node fdt rsvmem print - Show current mem reserves fdt rsvmem add - Add a mem reserve fdt rsvmem delete - Delete a mem reserves fdt chosen [] - Add/update the /chosen branch in the tree / - initrd start/end addr NOTE: Dereference aliases by omiting the leading '/', e.g. fdt print ethernet0。 sunxi#
說明
其中常用的命令就是fdt list 和 fdt set,fdt list 用來查詢節點配置,fdt set 用來修改節點配置。
5.6.1 查詢配置
首先確定要查詢的字段在 device tree 的路徑,如果不知道路徑,則需要用fdt命令按以下步驟進
行查詢。1. 在根目錄下查找。
sunxi#fdt list / / { model = "{LICHEE_CHIP}"; compatible = "arm,{LICHEE_CHIP}", "arm,{LICHEE_CHIP}"; interrupt-parent = <0x00000001>; #address-cells = <0x00000002>; #size-cells = <0x00000002>; ...................... cpuscfg { }; ion { }; dram { }; memory@40000000 { }; interrupt-controller@1c81000 { }; sunxi-chipid@1c14200 { }; timer { }; pmu { }; dvfs_table { }; dramfreq { }; gpu@0x01c40000 { }; wlan { }; bt { }; btlpm { }; };
如果找到需要的配置,比如wlan的配置,運行如下命令即可。
sunxi#fdt list /wlan //注意路徑中的 / wlan { compatible = "allwinner,sunxi-wlan"; clocks = <0x00000096>; wlan_power = "vcc-wifi"; wlan_io_regulator = "vcc-wifi-io"; wlan_busnum = <0x00000001>; status = "okay"; device_type = "wlan"; wlan_regon = <0x00000077 0x0000000b 0x00000002 0x00000001 0xffffffff 0xffffffff 0 ? ?x00000000>; wlan_hostwake = <0x00000077 0x0000000b 0x00000003 0x00000006 0xffffffff 0xffffffff ? ?0x00000000>; };
在 soc目錄下找。如果在第一步中沒有發現要找的配置,比如nand0的配置,則該配置可能在soc目錄下。
sunxi#fdt list /soc soc@01c00000 { compatible = "simple-bus"; #address-cells = <0x00000002>; #size-cells = <0x00000002>; ranges; device_type = "soc"; ...................... hdmi@01ee0000 { }; tr@01000000 { }; pwm@01c21400 { }; nand0@01c03000 { }; thermal_sensor { }; cpu_budget_cool { }; ....................... };
然后用如下命令顯示即可:
sunxi#fdt list /soc/nand0 nand0@01c03000 { compatible = "allwinner,sun50i-nand"; device_type = "nand0"; reg = <0x00000000 0x01c03000 0x00000000 0x00001000>; interrupts = <0x00000000 0x00000046 0x00000004>; clocks = <0x00000004 0x0000007e>; pinctrl-names = "default", "sleep"; pinctrl-1 = <0x00000081>; nand0_regulator1 = "vcc-nand"; nand0_regulator2 = "none"; nand0_cache_level = <0x55aaaa55>; nand0_flush_cache_num = <0x55aaaa55>; nand0_capacity_level = <0x55aaaa55>; nand0_id_number_ctl = <0x55aaaa55>; nand0_print_level = <0x55aaaa55>; nand0_p0 = <0x55aaaa55>; nand0_p1 = <0x55aaaa55>; nand0_p2 = <0x55aaaa55>; nand0_p3 = <0x55aaaa55>; status = "disabled"; nand0_support_2ch = <0x00000000>; pinctrl-0 = <0x000000a9 0x000000aa>; };
使用路徑別名查找。別名是 device tree 中完整路徑的一個簡寫,有一個專門的節點 ( /aliases) 來表示別名的相關信息,用如下命令可以查看系統中別名的配置情況:
sunxi#fdt list /aliases aliases { serial0 = "/soc@01c00000/uart@01c28000"; .............. mmc0 = "/soc@01c00000/sdmmc@01c0f000"; mmc2 = "/soc@01c00000/sdmmc@01C11000"; nand0 = "/soc@01c00000/nand0@01c03000"; disp = "/soc@01c00000/disp@01000000"; lcd0 = "/soc@01c00000/lcd0@01c0c000"; hdmi = "/soc@01c00000/hdmi@01ee0000"; pwm = "/soc@01c00000/pwm@01c21400"; boot_disp = "/soc@01c00000/boot_disp"; }; sunxi#
由于配置了nand0節點的路徑別名,因此可以用如下命令來顯示nand0的配置信息。
sunxi#fdt list nand0 nand0@01c03000 { compatible = "allwinner,sun50i-nand"; device_type = "nand0"; reg = <0x00000000 0x01c03000 0x00000000 0x00001000>; .................. pinctrl-names = "default", "sleep"; pinctrl-1 = <0x00000081>; };
注:在fdt的所有命令中,alias 可以用作path參數。
fdt list [] - Print one level starting at fdt set [] - Set [to ]
5.6.2 修改配置
5.6.2.1 修改整數配置
命令格式:fdt set path prop 示例:fdt set /wlan wlan_busnum <0x2>
sunxi#fdt list /wlan wlan { compatible = "allwinner,sunxi-wlan"; clocks = <0x00000096>; wlan_power = "vcc-wifi"; wlan_io_regulator = "vcc-wifi-io"; wlan_busnum = <0x00000001>; status = "disable"; device_type = "wlan"; }; sunxi#fdt set /wlan wlan_busnum <0x2> sunxi#fdt list /wlan wlan { compatible = "allwinner,sunxi-wlan"; clocks = <0x00000096>; wlan_power = "vcc-wifi"; wlan_io_regulator = "vcc-wifi-io"; wlan_busnum = <0x00000002>; //修改后 status = "disable"; device_type = "wlan"; };
注:修改整數時,根據需要也可配置為數組形式,需要用空格來分隔。命令格式:fdt set path prop <0x1 0x2 0x3>
5.6.2.2 修改字符串配置
命令格式:fdt set path prop "xxxxx" 示例:fdt set /wlan status "disable"
sunxi#fdt list /wlan wlan { compatible = "allwinner,sunxi-wlan"; clocks = <0x00000096>; wlan_power = "vcc-wifi"; wlan_io_regulator = "vcc-wifi-io"; wlan_busnum = <0x00000001>; status = "okay"; device_type = "wlan"; }; sunxi#fdt set /wlan status "disable" sunxi#fdt list /wlan wlan { compatible = "allwinner,sunxi-wlan"; clocks = <0x00000096>; wlan_power = "vcc-wifi"; wlan_io_regulator = "vcc-wifi-io"; wlan_busnum = <0x00000001>; status = "disable"; //修改后 device_type = "wlan"; }; sunxi#
注:修改字符串時,根據需要也可配置為數組形式,需要用空格來分隔。命令格式:fdt set path prop "string1" "string2"
5.6.3 GPIO 或者 PIN 配置特殊說明
接口對應的數字編號說明如下:
#define PA 0 #define PB 1 #define PC 2 #define PD 3 #define PE 4 #define PF 5 #define PG 6 #define PH 7 #define PI 8 #define PJ 9 #define PK 10 #define PL 11 #define PM 12 #define PN 13 #define PO 14 #define PP 15 #define default 0xffffffff
Sysconfig 中描述 gpio 的形式如下:Port:端口+組內序號<功能分配><內部電阻狀態><驅動能力><輸出電平狀態>
5.6.3.1 Pin 配置說明
Pinctrl 節點分為 cpux 和 cpus,對應的節點路徑如下:Cpux : /soc/pinctrl@01c20800 Cpus:/soc/pinctrl@01f02c00
5.6.3.2 查看 PIN 配置
PIN 配置屬性字段說明:
屬性字段 | 含義 |
---|---|
allwinner,function | 對應于 sysconfig 中的主鍵名 |
allwinner,pins | 對應于 sysconfig 中每個 gpio 配置中的端口名 |
allwinner,pname | 對應于 sysconfig 中主鍵下面子鍵名字 |
allwinner,muxsel | 功能分配 |
allwinner,pull | 內部電阻狀態 |
allwinner,drive | 驅動能力 |
allwinner,data | 輸出電平狀態 |
說明
其中0xffffffff表示使用默認值。
按以下方法查看cpux的 PIN 配置。
sunxi#fdt list /soc/pinctrl@01c20800/lcd0 lcd0@0 { linux,phandle = <0x000000ab>; phandle = <0x000000ab>; allwinner,pins = "PD12", "PD13", "PD14", "PD15", "PD16", "PD17", "PD18", "PD19", "PD20", "PD21"; allwinner,function = "lcd0"; allwinner,pname = "lcdd0", "lcdd1", "lcdd2", "lcdd3", "lcdd4", "lcdd5", "lcdd6", "lcdd7", "lcdd8", "lcdd9"; allwinner,muxsel = <0x00000003>; allwinner,pull = <0x00000000>; allwinner,drive = <0xffffffff>; allwinner,data = <0xffffffff>; }; sunxi#
按以下方法查看cpus的 PIN 配置。
sunxi# fdt list /soc/pinctrl@01f02c00/s_uart0 s_uart0@0 { linux,phandle = <0x000000b4>; phandle = <0x000000b4>; allwinner,pins = "PL2", "PL3"; allwinner,function = "s_uart0"; allwinner,pname = "s_uart0_tx", "s_uart0_rx"; allwinner,muxsel = <0x00000002>; allwinner,pull = <0xffffffff>; allwinner,drive = <0xffffffff>; allwinner,data = <0xffffffff>; }; sunxi#
5.6.3.3 修改 PIN 配置
使用fdt set命令可以修改 PIN 中相關屬性字段
sunxi#fdt set /soc/pinctrl@01c20800/lcd0 allwinner,drive <0x1> sunxi#fdt list /soc/pinctrl@01c20800/lcd0 lcd0@0 { linux,phandle = <0x000000ab>; phandle = <0x000000ab>; allwinner,pins = "PD12", "PD13", "PD14", "PD15", "PD16", "PD17", "PD18", "PD19", "PD20", "PD21"; allwinner,function = "lcd0"; allwinner,pname = "lcdd0", "lcdd1", "lcdd2", "lcdd3", "lcdd4", "lcdd5", "lcdd6", "lcdd7", "lcdd8", "lcdd9"; allwinner,muxsel = <0x00000003>; allwinner,pull = <0x00000000>; allwinner,drive = <0x00000001>; allwinner,data = <0xffffffff>; };
說明
示例中該處修改會影響allwinner,pins表示的所有端口的驅動能力配置,修改allwinner,muxsel, allwinner,pull,allwinner,data的值也會產生類似效果。
5.6.3.4 GPIO 配置說明
Device tree 中 GPIO 對應關系,以 usb 中usb_id_gpio為例
sunxi#fdt list /soc/usbc0 usbc0@0 { test = <0x00000002 0x00000003 0x12345678>; device_type = "usbc0"; compatible = "allwinner,sun50i-otg-manager"; ........ usb_serial_unique = <0x00000000>; usb_serial_number = "20080411"; rndis_wceis = <0x00000001>; status = "okay"; usb_id_gpio = <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0xffffffff 0xffffffff>; };
對應于 device tree 中 usb_id_gpio = <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0xffffffff 0xffffffff>,解釋如下:
屬性數值 | 含義 |
---|---|
0x00000030 | device tree 內部一個節點相關信息,這里可以略過 |
0x00000007 | 端口 PH, 即 #define PH 7 |
0x00000009 | 組內序號, 即 PH09 |
0x00000000 | 功能分配, 即將 PH09 配為輸入 |
0x00000001 | 內部電阻狀態, 即配為上拉 |
0xffffffff | 驅動能力, 默認值 |
0xffffffff | 輸出電平, 默認值 |
如果需要修改 usb_id_gpio的配置,可按如下方式(示例修改了驅動能力,輸出電平兩項):
sunxi#fdt set /soc/usbc0 usb_id_gpio <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0x2 0x1> sunxi#fdt list usbc0@0 { test = <0x00000002 0x00000003 0x12345678>; device_type = "usbc0"; compatible = "allwinner,sun50i-otg-manager"; ........ usb_serial_unique = <0x00000000>; usb_serial_number = "20080411"; rndis_wceis = <0x00000001>; status = "okay"; usb_id_gpio = <0x00000030 0x00000007 0x00000009 0x00000000 0x00000001 0x00000002 0x00000001>; //修改ok }; sunxi#
5.7 其他命令說明(boot, reset, efex)
boot : 啟動內核
reset: 復位重啟系統
efex: 進入燒錄狀態
說明
注:其他更多 U-Boot 命令介紹,請進入 U-Boot shell 命令狀態后輸入"help"進行了解。
6 基本調試方法介紹
debug 調試信息介紹如下:
debug_mode
debug_mode 可以控制 Boot0 的打印等級,打開文件{LICHEE_BOARD_CONFIG_DIR}/sys_config.fex,在主鍵 [platform] 下添加子鍵"debug_mode = 8"即表示開啟所有打印,debug_mode=0 表示關閉啟動時 Boot0 的打印 log,未顯式配置 debug_mode 時,按 debug_mode=8 處理。目前常用的打印等級有 0(關閉所有打?。?、1(只顯示關鍵節點打?。?(打印錯誤信息)、8(打印所有 log 信息)。
debug_mode 可以控制 U-Boot 的打印等級,打開文件{LICHEE_BOARD_CONFIG_DIR}/b3/uboot-board.dts,在 platform 節點下添加子鍵"debug_mode = 8"即表示開啟所有打印,debug_mode=0 表示關閉啟動時 U-Boot 的打印log, 未顯式配置 debug_mode 時,按 debug_mode=8 處理。目前常用的打印等級有 0(關閉所有打?。?、1(只顯示關鍵節點打?。?、4(打印錯誤信息)、8(打印所有 log 信息)。
usb_debug 在燒錄或啟動過程中,若遇到燒錄失敗或啟動失敗大致掛死在 usb 相關模塊,但又不確定具體位置,這時可以打開usb_debug進行調試,開啟usb_debug后有關 usb 相關的運行信息會被較詳細打印出來。打開usb_debug的方式:打開usb_base.h文件,將其中的#defineSUNXI_USB_DEBUG宏定義打開,打開后重新編譯 U-Boot 并打包燒錄即可。
7 進入燒寫的方法
開機時按住 fel 鍵
開機時打開串口按住鍵盤數字’2’
進入 U-Boot 控制臺輸入efex
進入 Android 控制臺輸入 reboot efex
8 常用接口函數
8.1 fdt 相關接口
const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp)
? 作用:檢索指定屬性的值
? 參數:
? fdt: 工作 flattened device tree
? nodeoffset: 待修改節點的偏移
? name: 待檢索的屬性名
? lenp: 檢索屬性值的長度(會被覆蓋)或者為 NULL
? 返回:
? 非空(屬性值的指針):成功
? NULL(lenp 為空):失敗
? 失敗代碼(lenp 非空):失敗
int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status, unsigned int error_code)
? 作用:設置節點狀態
? 參數:
? fdt: 工作 flattened device tree
? nodeoffset: 待修改節點的偏移
? status:FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL, FDT_STATUS_FAIL_ERROR_CODE
? error_code:optional, only used if status is FDT_STATUS_FAIL_ERROR_CODE
? 返回:
? 0: 成功
? 非 0: 失敗
int fdt_path_offset(const void *fdt, const char *path)
? 作用:通過全路徑查找節點的偏移量
? 參數:
? fdt: 工作 fdt
? path: 全路徑名稱
? 返回:
? >=0(節點的偏移量): 成功
? <0: 失敗代碼
static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val)
? 作用:將屬性值設置為一個 32 位整型數值,如果屬性值不存在,則新建該屬性
? 參數:
? fdt: 工作 flattened device tree
? nodeoffset: 待修改節點的偏移
? name: 待修改的屬性名
? val:32 位目標值
? 返回:
? 0: 成功
? <0: 失敗代碼
static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val)
? 作用:與fdt_setprop_u32類似,將屬性值設置為一個 64 位整型數值,如果屬性值不存在,則新建該屬性
? 參數:
? fdt: 工作 flattened device tree
? nodeoffset: 待修改節點的偏移
? name: 待修改的屬性名
? val:64 位目標值
? 返回:
? 0: 成功
? <0: 失敗代碼
#define fdt_setprop_string(fdt, nodeoffset, name, str) fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
? 作用:將屬性值設置為一個字符串,如果屬性值不存在,則新建該屬性
? 參數:
? fdt: 工作 flattened device tree
? nodeoffset: 待修改節點的偏移
? name: 待修改的屬性名
? str: 目標值
? 返回:
? 0: 成功
? <0: 失敗代碼
注意:在sys_config.fex的配置中,節點的啟用狀態為 0 或 1。轉換到 fdt 中對應的 status 屬性為disable或okay。
int save_fdt_to_flash(void *fdt_buf, size_t fdt_size)
? 作用:保存修改到 flash
? 參數:
? fdt_buf: 當前工作 flattened device tree
? fdt_size: 當前工作 flattened device tree 的大小,可以通過fdt_totalsize(fdt_buf )獲取
? 返回:
? 0: 成功
? <0: 失敗
應用參考
U-Boot 中 fdt 命令行的實現:cmd/fdt.c
8.2 env 相關接口函數
int env_set(const char *varname, const char *varvalue)
? 作用:將環境變量 varname 的值設置為 varvalue,重啟失效
? 參數:
? varname: 待設置環境變量的名稱
? varvalue: 將指定的環境變量修改為該值
? 返回:
? 0: 成功
? 非 0: 失敗
char *env_get(const char *name)
? 作用:獲取指定環境變量的值
? 參數:
? name: 變量名稱
? 返回:
? NULL: 失敗
? 非空(環境變量的值):成功
int env_save(void)
? 作用:保存環境變量,重啟仍保存
? 參數: 無
? 返回:
? 0: 成功
? 非 0: 失敗
應用參考
board/sunxi/sunxi_bootargs.c update_bootargs通過 cmdline 向 kernel 提供信息,主要是通過更新bootargs變量實現env_set("bootargs", cmdline)。
8.3 調用 U-Boot 命令行
int run_command_list(const char *cmd, int len, int flag)
? 作用:執行 U-Boot 命令行
? 參數:
? cmd: 命令字符指針
? len: 命令行長度,設置為-1 則自動獲取
? flag: 任意,因為 sunxi 中沒有用到
? 返回:
? 0: 成功
? 非 0: 失敗
應用參考:
common/autoboot.c autoboot_command實現了 U-Boot 的自動啟動命令
s = env_get("bootcmd");
run_command_list(s, -1, 0)。
8.4 Flash 的讀寫
int sunxi_flash_read(uint start_block, uint nblock, void *buffer)
? 作用:將指定起始位置start_block的nblock讀取到buffer
? 參數:
? start_block: 起始地址
? nblock:block 個數
? buffer: 內存地址
? 返回:
? 0: 成功
? 非 0: 失敗
int sunxi_flash_write(uint start_block, uint nblock, void *buffer)
? 作用:將buffer寫入指定起始位置start_block的nblock中
? 參數:
? start_block: 起始地址
? nblock:block 個數
? buffer: 內存地址
? 返回:
? 0: 成功
? 非 0: 失敗
int sunxi_sprite_read(uint start_block, uint nblock, void *buffer)
? 作用與sunxi_flash_read相似
int sunxi_sprite_write(uint start_block, uint nblock, void *buffer)
? 作用與sunxi_flash_write相似
應用參考
common/sunxi/board_helper.c sunxi_set_bootcmd_from_mis實現了對 misc 分區的讀寫操作
8.5 獲取分區信息
int sunxi_partition_get_partno_byname(const char *part_name)
? 作用:根據分區名稱獲取分區號
? 參數:
? part_name: 分區名稱
? 返回:
? <0: 失敗
? >0(分區號):成功
int sunxi_partition_get_info_byname(const char *part_name, uint *part_offset, uint *part_size)
? 作用:根據分區名稱獲取分區的偏移量和大小
? 參數:
? part_name: 分區名稱
? part_offset: 分區的偏移量
? part_size: 分區的大小
? 返回:
? 0: 成功
? -1: 失敗
uint sunxi_partition_get_offset_byname(const char *part_name)
? 作用:根據分區名稱獲取偏移量
? 參數:
? part_name: 分區名稱
? 返回:
? <=0 : 失敗
? >0 : 成功
int sunxi_partition_get_info(const char *part_name, disk_partition_t *info)
? 作用:根據part_name獲取分區信息
? 參數:
? part_name: 分區名稱
? info: 分區信息
? 返回:
? 非 0: 失敗
? 0: 成功
lbaint_t sunxi_partition_get_offset(int part_index)
? 作用:card sprite 模式下獲取分區的偏移量
? 參數:
? part_index: 分區號
? 返回:
? >=0(偏移量):成功
? -1: 失敗
應用參考
啟動時加載圖片:drivers/video/sunxi/logo_display/sunxi_load_bmp.c
8.6 GPIO 相關操作
int fdt_get_one_gpio(const char* node_path, const char* prop_name,user_gpio_set_t* gpio_list)
? 作用:根據路徑node_path和 gpio 名稱prop_name獲取 gpio 配置
? 參數:
? node_path:fdt 路徑
? prop_name:gpio 名稱
? gpio_list:待獲取的 gpio 信息
? 返回:
? 0:成功
? -1:失敗
ulong sunxi_gpio_request(user_gpio_set_t *gpio_list, __u32 group_count_max)
? 作用:根據 gpio 配置獲取 gpio 操作句柄
? 參數:
? gpio_list:gpio 配置列表,可以由fdt_get_one_gpio獲得
? group_count_max: gpio_list中最大的 gpio 配置個數
? 返回:
? 0:失敗
? >0(gpio 操作句柄):成功
__s32 gpio_write_one_pin_value(ulong p_handler, __u32 value_to_gpio, const char *gpio_name)
? 作用:根據 gpio 操作句柄寫數據
? 參數:
? p_handler:gpio 操作句柄,可由sunxi_gpio_request獲取
? value_to_gpio:待寫入數據,0 或 1
? gpio_name:gpio 名稱
? 返回:
? EGPIO_SUCCESS:成功
? EGPIO_FAIL:失敗
應用參考
操作 led 狀態:
ssprite/sprite_led.c user_gpio_set_t gpio_init; fdt_get_one_gpio("/soc/card_boot", "sprite_gpio0", &gpio_init); //獲取/soc/card_boot中sprite_gpio0的gpio配置 sprite_led_hd = sunxi_gpio_request(&gpio_init, 1); //獲取gpio操作句柄 gpio_write_one_pin_value(sprite_led_hd, sprite_led_status, "sprite_gpio0"); //操作led狀態
9 常用資源的初始化階段
? env :環境變量初始化后可以訪問
? fdt :在 U-Boot 運行開始即可訪問
? malloc :在重定位后才能訪問
-
Linux
+關注
關注
87文章
11402瀏覽量
212071 -
移植
+關注
關注
1文章
391瀏覽量
28467 -
u-boot
+關注
關注
0文章
122瀏覽量
38612 -
編譯
+關注
關注
0文章
672瀏覽量
33460 -
開發指南
+關注
關注
0文章
34瀏覽量
7696
發布評論請先 登錄
相關推薦
U-Boot介紹
U-boot的基本介紹

視壯rk3288/rk3399 Rockchip《U-Boot 開發指南 V3.7》
U-Boot的啟動及移植分析
u-boot的Makefile分析
u-boot學習指南
u-boot簡介
U-Boot架構淺析

評論