启动
U-Boot和OpenSBI开发调试指南。
uboot 功能与配置
功能介绍
uboot 的主要功能有以下几点:
- 加载启动内核
uboot 从存储介质(emmc/sd/nand/nor/ssd 等),加载内核镜像到内存指定位置,并启动内核 。
- fastboot 刷机功能
通过 fastboot 工具,烧写镜像到指定的分区位置。
- 开机 logo
uboot 启动阶段显示启动 logo 以及 boot menu。
- 驱动调试
基于 uboot 调试设备驱动,如 mmc/spi/nand/nor/nvme 等驱动。uboot 提供 shell 命令行对各个驱动进行功能调试。
uboot 驱动在 drivers/目录下。
编译
本章节介绍基于 uboot 代码环境,编译生成 uboot 的镜像文件。
- 编译配置
首次编译,或者需要重新选择其他方案,则需要先选择编译配置,这里以 k1 为例:
cd ~/uboot-2022.10
make ARCH=riscv k1_defconfig -C ~/uboot-2022.10/
可视 化更改编译配置:
make ARCH=riscv menuconfig
通过键盘"Y"/"N"以开启/关闭相关的功能配置。保存后会更新到 uboot 根目录的.config 文件。
- 编译 uboot
cd ~/uboot-2022.10
GCC_PREFIX=riscv64-unknown-linux-gnu-
make ARCH=riscv CROSS_COMPILE=${GCC_PREFIX} -C ~/uboot-2022.10 -j4
- 编译产物
~/uboot-2022.10$ ls u-boot* -l
u-boot
u-boot.bin # uboot镜像
u-boot.dtb # dtb文件
u-boot-dtb.bin # 带dtb的uboot镜像
u-boot.itb # 将u-boot-nodtb.bin和dtb打包成fit格式
u-boot-nodtb.bin
bootinfo_emmc.bin # 用于emmc启动时记录spl位置的信息
bootinfo_sd.bin
bootinfo_spinand.bin
bootinfo_spinor.bin
FSBL.bin # u-boot-spl.bin加上头信息。由brom加载启动
k1-x_deb1.dtb # 方案deb1的dtb文件
k1-x_spl.dtb # spl的dtb文件
dts 配置
uboot dts 配置在目录 uboot-2022.10/arch/riscv/dts/,根据不同的方案修改该方案的 dts,如 deb1 方案。
~/uboot-2022.10$ ls arch/riscv/dts/k1*.dts -l
arch/riscv/dts/k1-x_deb1.dts
arch/riscv/dts/k1-x_deb2.dts
arch/riscv/dts/k1-x_evb.dts
arch/riscv/dts/k1-x_fpga_1x4.dts
arch/riscv/dts/k1-x_fpga_2x2.dts
arch/riscv/dts/k1-x_fpga.dts
arch/riscv/dts/k1-x_spl.dts
uboot 驱动开发调试
本章节主要介绍 uboot 的驱动使用和调试方法,默认情况下所有的驱动都已经做好配置。
boot kernel
本小节介绍 uboot 启动 kernel,以及分区的自定义配置和启动。
- 开发板上电启动后,立即按下键盘上的"s"键,进入 uboot shell
- 可通过执行 fastboot 0 进入 fastboot mode,通过电脑端的 fastboot stage Image 发送镜像到开发板。(或者其他下载镜像的方式,如 fatload 等命令)
- 执行 booti 启动 kernel(或者 bootm 启动 fit 格式镜像)
#下载kernel镜像
=> fastboot -l 0x40000000 0
Starting download of 50687488 bytes
...
downloading/uploading of 50687488 bytes finished
#电脑端执行命令
C:\Users>fastboot stage Z:\k1\output\Image
Sending 'Z:\k1\output\Image' (49499 KB) OKAY [ 1.934s]
Finished. Total time: 3.358s
#下载完成后,在uboot shell中,通过键盘输入CTRL+C退出fastboot mode。
#下载dtb
=> fastboot -l 0x50000000 0
Starting download of 33261 bytes
downloading/uploading of 33261 bytes finished
#电脑端执行命令
C:\Users>fastboot stage Z:\k1\output\k1-x_deb1.dtb
Sending 'Z:\k1\output\k1-x_deb1.dtb' (32 KB) OKAY [ 0.004s]
Finished. Total time: 0.054s
执行启动命令
=> booti 0x40000000 - 0x50000000
Moving Image from 0x40000000 to 0x200000, end=3d4f000
## Flattened Device Tree blob at 50000000
Booting using the fdt blob at 0x50000000
Using Device Tree in place at 0000000050000000, end 0000000050014896
Starting kernel ...
[ 0.000000] Linux version 6.1.15+ ... ...
[ 0.000000] OF: fdt: Ignoring memory range 0x0 - 0x200000
[ 0.000000] Machine model: spacemit k1-x deb1 board
[ 0.000000] earlycon: sbi0 at I/O port 0x0 (options '')
[ 0.000000] printk: bootconsole [sbi0] enabled
- 通过 bootm 命令启动 fit 格式镜像
假设 emmc 中分区 5 为 fat32 文件系统。且里面保存 uImage.itb 文件,通过以下命令加载启动 kernel。
=> fatls mmc 2:5
sdh@d4281000: 74 clk wait timeout(100)
50896911 uImage.itb
4671 env_k1-x.txt
2 file(s), 0 dir(s)
=> fatload mmc 2:5 0x40000000 uImage.itb
50896911 bytes read in 339 ms (143.2 MiB/s)
=> bootm 0x40000000
## Loading kernel from FIT Image at 40000000 ...
Boot from fit configuration k1_deb1
Using 'conf_2' configuration
Trying 'kernel' kernel subimage
Description: Vanilla Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x400000e8
Data Size: 50687488 Bytes = 48.3 MiB
Architecture: RISC-V
OS: Linux
Load Address: 0x01400000
Entry Point: 0x01400000
Verifying Hash Integrity ... OK
## Loading fdt from FIT Image at 40000000 ...
Using 'conf_2' configuration
Trying 'fdt_2' fdt subimage
Description: Flattened Device Tree blob for k1_deb1
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x43067c90
Data Size: 68940 Bytes = 67.3 KiB
Architecture: RISC-V
Load Address: 0x28000000
Verifying Hash Integrity ... OK
Loading fdt from 0x43067c90 to 0x28000000
Booting using the fdt blob at 0x28000000
Loading Kernel Image
Using Device Tree in place at 0000000028000000, end 0000000028013d4b
Starting kernel ...
[ 0.000000] Linux version 6.1.15+ ... ...
[ 0.000000] OF: fdt: Ignoring memory range 0x0 - 0x1400000
[ 0.000000] Machine model: spacemit k1-x deb1 board
[ 0.000000] earlycon: sbi0 at I/O port 0x0 (options '')
[ 0.000000] printk: bootconsole [sbi0] enabled
env
本章节介绍如何配置在 uboot 启动阶段,从指定存储介质加载 env。
- 执行 make menuconfig,进入 Environment,
目前支持可选的介质为 mmc,mtd 设备(其中 mtd 设备包括 spinor,spinand)。
env 的偏移地址需要根据分区表的配置来确定,具体可以参考刷机启动设置章节的分区表配置,默认是 0x80000。
(0x80000) Environment address #spinor的env偏移地址
(0x80000) Environment offset #mmc设备的env偏移地址
mmc
emmc 和 sd 卡都是使用到 mmc 驱动,dev number 分别为 2、0。
- config 配置
执行 make menuconfig,进入 Device Drivers--->MMC Host controller Support,开启以下配置
- dts 配置
//uboot-2022.10/arch/riscv/dts/k1-x.dtsi
sdhci0: sdh@d4280000 {
compatible = "spacemit,k1-x-sdhci";
reg = <0x0 0xd4280000 0x0 0x200>;
interrupt-parent = <&intc>;
interrupts = <99>;
resets = <&reset RESET_SDH_AXI>,
<&reset RESET_SDH0>;
reset-names = "sdh_axi", "sdh0";
clocks = <&ccu CLK_SDH0>,
<&ccu CLK_SDH_AXI>;
clock-names = "sdh-io", "sdh-core";
status = "disabled";
};
sdhci2: sdh@d4281000 {
compatible = "spacemit,k1-x-sdhci";
reg = <0x0 0xd4281000 0x0 0x200>;
interrupt-parent = <&intc>;
interrupts = <101>;
resets = <&reset RESET_SDH_AXI>,
<&reset RESET_SDH2>;
reset-names = "sdh_axi", "sdh2";
clocks = <&ccu CLK_SDH2>,
<&ccu CLK_SDH_AXI>;
clock-names = "sdh-io", "sdh-core";
status = "disabled";
};
//uboot-2022.10/arch/riscv/dts/k1-x_deb1.dts
&sdhci0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_mmc1 &gpio80_pmx_func0>;
bus-width = <4>;
cd-gpios = <&gpio 80 0>;
cd-inverted;
cap-sd-highspeed;
sdh-phy-module = <0>;
status = "okay";
};
/* eMMC */
&sdhci2 {
bus-width = <8>;
non-removable;
mmc-hs400-1_8v;
mmc-hs400-enhanced-strobe;
sdh-phy-module = <1>;
status = "okay";
};
- 调试验证
uboot shell 提供命令行调试 mmc 驱动,需要开启编译配置项 CONFIG_CMD_MMC
=> mmc list
sdh@d4280000: 0 (SD)
sdh@d4281000: 2 (eMMC)
=> mmc dev 2 #切换到emmc
switch to partitions #0, OK
mmc2(part 0) is current device
#read 0偏移的0x1000个blk_cnt到内存0x40000000
=> mmc read 0x40000000 0 0x1000
MMC read: dev # 2, block # 0, count 4096 ... 4096 blocks read: OK
#从内存地址0x40000000 写到0x1000个blk_cnt到0偏移
=> mmc write 0x40000000 0 0x1000
MMC write: dev # 2, block # 0, count 4096 ... 4096 blocks written: OK
#其他用法可参考mmc -h
- 常用接口
参考 cmd/mmc.c 中的接口
nvme
nvme 驱动主要用于调试 ssd 硬盘。
- config 配置
执行 make menuconfig,进入 Device Driver,开启以下配置,
- dts 配置
//uboot-2022.10/arch/riscv/dts/k1-x.dtsi
pcie1_rc: pcie@ca400000 {
compatible = "k1x,dwc-pcie";
reg = <0x0 0xca400000 0x0 0x00001000>, /* dbi */
<0x0 0xca700000 0x0 0x0001ff24>, /* atu registers */
<0x0 0x90000000 0x0 0x00100000>, /* config space */
<0x0 0xd4282bd4 0x0 0x00000008>, /*k1x soc config addr*/
<0x0 0xc0c20000 0x0 0x00001000>, /* phy ahb */
<0x0 0xc0c10000 0x0 0x00001000>, /* phy addr */
<0x0 0xd4282bcc 0x0 0x00000008>, /* conf0 addr */
<0x0 0xc0b10000 0x0 0x00001000>; /* phy0 addr */
reg-names = "dbi", "atu", "config",
"k1x_conf", "phy_ahb",
"phy_addr", "conf0_addr",
"phy0_addr";
k1x,pcie-port = <1>;
clocks = <&ccu CLK_PCIE1>;
clock-names = "pcie-clk";
resets = <&reset RESET_PCIE1>;
reset-names = "pcie-reset";
bus-range = <0x00 0xff>;
max-link-speed = <2>;
num-lanes = <2>;
num-viewport = <8>;
device_type = "pci";
#address-cells = <3>;
#size-cells = <2>;
ranges = <0x01000000 0x0 0x90100000
0 0x90100000 0x0 0x100000>,
<0x02000000 0x0 0x90200000
0 0x90200000 0x0 0x0fe00000>;
interrupts = <142>, <146>;
interrupt-parent = <&intc>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0000 0 0 1 &pcie1_intc 1>, /* int_a */
<0000 0 0 2 &pcie1_intc 2>, /* int_b */
<0000 0 0 3 &pcie1_intc 3>, /* int_c */
<0000 0 0 4 &pcie1_intc 4>; /* int_d */
linux,pci-domain = <1>;
status = "disabled";
pcie1_intc: interrupt-controller@0 {
interrupt-controller;
reg = <0 0 0 0 0>;
#address-cells = <0>;
#interrupt-cells = <1>;
};
};
//uboot-2022.10/arch/riscv/dts/k1-x_deb1.dts
&pcie1_rc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pcie1_3>;
status = "okay";
};
- 调试验证
需要开启编译配置 CONFIG_CMD_NVME,调试方法如下:
=> nvme scan
=> nvme detail
Blk device 0: Optional Admin Command Support:
Namespace Management/Attachment: no
Firmware Commit/Image download: yes
Format NVM: yes
Security Send/Receive: yes
Blk device 0: Optional NVM Command Support:
Reservation: yes
Save/Select field in the Set/Get features: yes
Write Zeroes: yes
Dataset Management: yes
Write Uncorrectable: yes
Blk device 0: Format NVM Attributes:
Support Cryptographic Erase: No
Support erase a particular namespace: Yes
Support format a particular namespace: Yes
Blk device 0: LBA Format Support:
LBA Foramt 0 Support: (current)
Metadata Size: 0
LBA Data Size: 512
Relative Performance: Good
Blk device 0: End-to-End DataProtect Capabilities:
As last eight bytes: No
As first eight bytes: No
Support Type3: No
Support Type2: No
Support Type1: No
Blk device 0: Metadata capabilities:
As part of a separate buffer: No
As part of an extended data LBA: No
=> nvme read/write addr blk_off blk_cnt
- 常用接口
参考 cmd/nvme.c 中的代码接口
net
- config 配置
执行 make menuconfig,开启以下配置,
- dts 配置
//uboot-2022.10/arch/riscv/dts/k1-x.dtsi
eth0: ethernet@cac80000 {
compatible = "spacemit,k1x-emac";
reg = <0x00000000 0xCAC80000 0x00000000 0x00000420>;
ctrl-reg = <0x3e4>;
dline-reg = <0x3e8>;
clocks = <&ccu CLK_EMAC0_BUS>;
clock-names = "emac-clk";
resets = <&reset RESET_EMAC0>;
reset-names = "emac-reset";
status = "disabled";
};
//uboot-2022.10/arch/riscv/dts/k1-x_deb1.dts
ð0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gmac0>;
phy-reset-pin = <110>;
clk_tuning_enable;
clk-tuning-by-delayline;
tx-phase = <90>;
rx-phase = <73>;
phy-mode = "rgmii";
phy-addr = <1>;
phy-handle = <&rgmii>;
ref-clock-from-phy;
mdio {
#address-cells = <0x1>;
#size-cells = <0x0>;
rgmii: phy@0 {
compatible = "ethernet-phy-id001c.c916";
device_type = "ethernet-phy";
reg = <0x1>;
};
};
};
- 调试验证
需要先开启编译配置 CONFIG_CMD_NET, 网线接上开发板的网口,且已经准备好 tftp 服务器(tftp 服务器的搭建方法可搜索网上资料,这里不做介绍)
=> dhcp #执行dhcp后,如果返回地址,表示与网络服务器联通。其他情况为连接失败
ethernet@cac80000 Waiting for PHY auto negotiation to complete...... done
emac_adjust_link link:1 speed:1000 duplex:full
BOOTP broadcast 1
BOOTP broadcast 2
BOOTP broadcast 3
BOOTP broadcast 4
BOOTP broadcast 5
BOOTP broadcast 6
BOOTP broadcast 7
DHCP client bound to address 10.0.92.130 (7982 ms)
=> tftpboot 0x40000000 site11/uImage.itb
ethernet@cac80000 Waiting for PHY auto negotiation to complete...... done
emac_adjust_link link:1 speed:1000 duplex:full
Using ethernet@cac80000 device
TFTP from server 10.0.92.134; our IP address is 10.0.92.130
Filename 'site11/uImage.itb'.
Load address: 0x40000000
Loading: ##############################################################
########
1.1 MiB/s
done
Bytes transferred = 66900963 (3fcd3e3 hex)
=>
#启动kernel
=>bootm 0x40000000