RK3568 Linux驱动学习——U-Boot使用
前言
U-Boot 用于引导 Linux 系统,所以要先使用一下 U-Boot,体验一下 U-Boot 是什么。
正点原子 ATK-DLRK3568 开发板出厂系统已经烧写了 U-Boot,所以可以直接拿开发板体验 U-Boot。当然,提供的 SDK 包里面也有 U-Boot 源码,可以自行编译 U-Boot 源码烧写测试。本章主要学习使用 U-Boot 的相关命令。
U-Boot简介
Linux 系统要启动需要通过 bootloader 程序引导,即芯片上电以后先运行一段 bootloader 程序。这段 bootloader 程序会先初始化 DDR 等外设,然后将 Linux 内核从 flash(NAND,NOR FLASH,SD,EMMC 等)拷贝到 DDR 中,最后启动 Linux 内核。当然了,bootloader 的实际工作要复杂的多,但是它最主要的工作就是启动 Linux 内核。
所以要先搞定 bootloader,有很多现成的 bootloader 软件可以使用,比如 U-Boot、vivi、RedBoot 等等,其中以 U-Boot 使用最为广泛,为了方便书写,本教程会将 U-Boot 写为 uboot。
uboot 的全称是 Universal Boot Loader,uboot 是一个遵循 GPL 协议的开源软件,是一个裸机代码,可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB 等高级功能。uboot 官网为 uboot官网。如下所示:
可以在 uboot 官方 FTP 下载服务器地址为 uboot下载服务器,进入此 FTP 服务器即可看到 uboot 源码,如下图所示:
一般不会直接用 uboot 官方的 U-Boot 源码。uboot 官方的 uboot 源码是给半导体厂商准备的,半导体厂商会下载 uboot 官方的 uboot 源码,然后将自家相应的芯片移植进去。也就是说半导体厂商会自己维护一个版本的 uboot,这个版本的 uboot 相当于是他们定制的。瑞芯微的 SDK 包提供了 2017.09 版本的 uboot。Linux SDK 包中 uboot 源码如下图所示:
上图中的 “u-boot” 就是 RK3568 官方 uboot 源码包,它支持 RK3568 芯片,而且支持各种启动方式,比如 EMMC、NAND 等等,这些都是 uboot 官方所不支持的。但是该 uboot 是针对正点原子根据自家 ATK-DLRK3568 开发板移植好的。如果直接使用的瑞芯微原厂的 SDK 包,那么可能需要根据自己所使用的平台进行移植,使其支持自己做的板子。
U-Boot编译
编译烧写
这个之前 SDK 烧录的时候已经试过了,不再赘述。
U-Boot 启动过程
烧写完成以后用 USB Type-C 线将开发板上的 UART 接口与电脑连接起来,要在串口终端里面输入命令来操作 uboot。
打开 MobaXterm,设置好串口参数,最后复位开发板。在 MobaXterm 上出现“Hit key to stop autoboot(‘CTRL+C’):”倒计时的时候按下键盘上“CTRL+C”按键。
进入 uboot 的命令行模式以后如下图所示:
简单介绍一下 uboot 启动过程中都打印出了哪些信息:
- uboot 版本号,比如上图当前 uboot 版本号是 2017.09,编译时间为 2025 年 7 月 20 号 15:19:41。
- 板子信息,当前板子是瑞芯微的 RK3568 Evaluation 开发板,这个信息是可以改的。
- DDR 大小为 3.7GB
- EMMC 启动设备信息。
- PMIC 芯片(RK809)信息。
- DRM 信息,也就是屏幕信息。
- RK3568 芯片时钟信息。
- ……
最后是“Hit key to stop autoboot(‘CTRL+C’):”倒计时提示,倒计时结束之前按下“CTRL+C”组合键就会进入 Uboot 命令行模式。如果在倒计时结束以后没有按下“CTRL+C”组合键,那么 Linux 内核就会启动。
U-Boot 命令使用
进入 uboot 的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前 uboot 所支持的命令,如下图:
这些命令是正点原子提供的 uboot 中使能的命令,uboot 支持的命令还有很多,而且也可以在 uboot 中自定义命令。命令具体用法可以输入“help(或?) 命令名”就可以查看。
查询命令
常用的和信息查询有关的命令有 3 个:bdinfo、printenv 和 version。
直接输入“bdinfo”,如下:
从上图可以看出 DRAM 的起始地址和大小、BOOT 参数保存起始地址、波特率、
sp(堆栈指针)起始地址等信息。
“printenv” 用于输出环境变量信息,而且 uboot 也支持 TAB 键自动补全功能。直接输入“print” 也可以,如下图:
命令 version 用于查看 uboot 的版本号,输入“version”,uboot 版本号如下图所示:
环境变量操作命令
- 修改环境变量
环境变量的操作涉及到两个命令:setenv 和 saveenv,setenv 命令用于设置或者修改环境变量的值。命令 saveenv 用于保存修改后的环境变量,一般环境变量存放在外部 flash 中,uboot 启动的时候会将环境变量从 flash 读取到 DRAM 中。所以使用命令 setenv 修改的是 DRAM中的环境变量值,修改以后要使用 saveenv 命令将修改后的环境变量保存到 flash 中,否则 uboot 下一次重启会继续使用以前的环境变量值。
瑞芯微官方 SDK 中的 uboot 默认没有使能 saveenv 命令,但是正点原子出厂 SDK 里面已经使能了。
比如要将环境变量 bootdelay 改为 3,就可以使用如下所示命令:
setenv bootdelay 3
saveenv
上述命令执行结果如下:
可以看到保存到了 MMC(0) 中,也就是 EMMC。修改后重启,如下:
- 新建环境变量
命令 setenv 也可以用于新建命令,用法和修改环境变量一样,比如我们新建一个环境变量 author,author 的值为‘alientek’,那么就可以使用如下命令:
setenv author 'alientek'
saveenv
创建完之后重启 uboot,然后 printenv 查看当前环境变量,如下:
- 删除环境变量
删除环境变量也是使用命令 setenv,要删除一个环境变量只要给这个环境变量赋空值即可:
setenv author
saveenv
内存操作命令
内存操作命令就是用于直接对 DRAM 进行读写操作的,常用的内存操作命令有 md、nm、mm、mw、cp 和 cmp。
- md 命令
md 命令用于显示内存值,格式如下:
md[.b, .w, .l] address [# of objects]
命令中的[.b .w .l]对应 byte、word 和 long,也就是分别以 1 个字节、2 个字节、4 个字节来显示内存值。address 就是要查看的内存起始地址,[# of objects]表示要查看的数据长度,这个数据长度单位不是字节,而是跟你所选择的显示格式有关。比如你设置要查看的内存长度为20(十六进制为 0x14),如果显示格式为.b 的话那就表示 20 个字节;如果显示格式为.w 的话就表示 20 个 word,也就是 20 * 2=40 个字节;如果显示格式为.l 的话就表示 20 个 long,也就是 20 * 4=80 个字节。
注意:
uboot 命令中的数字都是十六进制的!不是十进制的!
可以执行如下三个命令:
md.b 8300000 10
md.w 8300000 10
md.l 8300000 10
分别是显示了 16、32、64 个字节:
- nm 命令
nm 命令用于修改指定地址的内存值,命令格式如下:
nm [.b, .w, .l] address
nm 命令同样可以以 .b、.w 和.l 来指定操作格式。输入命令:
nm.l 8300000
输入上述命令以后如下图所示:
上图中,08300000 表示现在要修改的内存地址,40000002 表示地址 0X08300000 现在的数据,‘?’后面就可以输入要修改后的数据 0x12345678,输入完成以后按下回车,然后再输入‘q’即可退出(大小写不敏感),如下图:
- mm 命令
mm 命令也是修改指定地址内存值的,使用 mm 修改内存值的时候地址会自增,而使用 nm 不会。如以.l 格式修改从地址 0X08300000 开始的连续 3 个内存块(3*4=12个字节)的数据为 0X05050505,操作如下图:
- mw 命令
命令 mw 用于使用一个指定的数据填充一段内存,命令格式如下:
mw [.b, .w, .l] address value [count]
mw 命令同样以.b、.w 和.l 来指定操作格式,address 表示要填充的内存起始地址,value 为要填充的数据,count 是填充的长度。比如使用.l 格式将以 0X08300000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0X0A0A0A0A,命令如下:
mw.l 8300000 0A0A0A0A 10
结果如下:
- cp 命令
cp 是数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 NorFlash 中的数据拷贝到 DRAM 中。命令格式如下:
cp [.b, .w, .l] source target count
cp 命令同样以.b、.w 和.l 来指定操作格式,source 为源地址,target 为目的地址,count 为拷贝的长度。使用.l 格式将 0x08300000 处的地址拷贝到 0x08300100 处,长度为 0x10 个内存块(0x10 * 4=64 个字节),命令如下所示:
cp.l 8300000 8300100 10
结果如下:
- cmp 命令
cmp 是比较命令,用于比较两段内存的数据是否相等,命令格式如下:
cmp [.b, .w, .l] addr1 addr2 count
cmp 命令同样以.b、.w 和.l 来指定操作格式,addr1 为第一段内存首地址,addr2 为第二段内存首地址,count 为要比较的长度。使用.l 格式来比较 0x08300000 和 0x08300100 这两个地址数据是否相等,比较长度为 0x10 个内存块(16 * 4=64 个字节),命令如下所示:
cmp.l 8300000 8300100 10
结果如下:
如果比较不一样的段,比如 0x08300000 和 0x08300200,长度为 0x10,结果如下:
网络操作命令
网络配置
需要先配置虚拟机和开发板,为之后的有线互联搭建环境。
我的配置是,PC 上虚拟机,直接 WiFi 将电脑连接上网,然后通过以太网口将开发板和 PC 直接连接。
- VMware 设置
根据下图序列来完成操作:
打开虚拟机设置:
在虚拟机设置中,将网络适配器 修改为桥接模式 ,如下图。
因为电脑是 WiFi 上网,所以需要添加一个网络适配器并设置成 NAT 模式,供虚拟机上网。具体操作如下图所示。
默认添加的网络适配器是 NAT 模式的,如果不是 NAT 模式则要手动设置成 NAT 模式。
之后打开虚拟机的网络编辑器:
更改设置:
这个需要管理员权限,点击是就可以了。
开发板是直连到电脑的网口的,所以需要虚拟网络编辑器里的 VMnet0 桥接到有线网卡上,如下图所示。本次桥接到主机机箱后面的网卡(网口)上,所添加的所有网络适配器,如果配置了桥接模式,那么都会从 VMnet0 桥接到真实的网络,从真实的网络中分配得到 ip。另外 VMnet8 是虚拟机自动运行的虚拟网卡,如果设置了一个网络适配器是 Net 模式的,那么虚拟网络就会从这个 VMnet8 分配得到一个 ip。
- Ubuntu 设置静态 IP
可以用 ifconfig 命令查看当前 IP 信息。ens36 网络节点中 192.168.129.xxx 就是从 VMnet8 中获取的 ip,还有一个 ens33 是桥接的网卡。
现在要做的就是设置桥接模式的网络适配器 1(ens33)的 IP 信息。网络适配器 1 用于和 Windows 和开发板通信,所以要先看下 Windows 主机的用于桥接网络的 IP。查看 Windows 主机的 IP:在 Windows 端按下 win + R 快捷键打开运行栏,输入 cmd 指令后按下回车。之后通过 ipconfig 命令来查看电脑 IP。
上图中就是本次实验要用到的以太网适配器,与开发板直连,所以需要手动来完成地址分配,后面会写怎么分配的。
现在要先在 Ubuntu 内设置桥接网络的 IP。
打开 ens33 的设置:
给 Ubuntu 设置一个静态 ip。设置 IPv4 地址,地址可以随意设置,但是要
符合网络协议的要求。
设置完成后执行 ifconfig 来查看:
- Windows 设置 IP
打开控制面板,找到网络和共享中心,然后进入以太网:
需要设置这个 IP 与 ens33 在同一网段内:
以上就完成了基础配置。
uboot 内操作
uboot 是支持网络的,在移植 uboot 的时候一般都要调通网络功能,因为在移植 linux kernel 的时候需要使用到 uboot 的网络功能做调试。uboot 支持大量的网络相关命令,比如 dhcp、ping、nfs 和 tftpboot。
开发板和主机PC都连接到同一个路由器上!最后设置下图的环境变量:
在我的开发板内可以如下设置:
setenv ipaddr 192.168.5.4
setenv ethaddr b8:ae:1d:01:01:00 //有的 uboot 会默认设置 ethaddr,然后禁止修改,RK3568
是禁止修改的,所以这个可以不用设置
setenv gatewayip 192.168.5.1
setenv netmask 255.255.255.0
setenv serverip 192.168.5.2
saveenv
设置好网络相关的环境变量以后就可以使用网络相关命令了。
- ping 命令
可以尝试 ping 自己的服务器 IP,命令如下:
ping 192.168.5.2
注意!
只能在 uboot 中 ping 其他的机器,其他机器不能 ping uboot,因为 uboot 没有对 ping 命令做处理,如果用其他的机器 ping uboot 的话会失败!
- dhcp 命令
dhcp 用于从路由器获取 IP 地址,前提是开发板得连接到路由器上的,如果开发板是和电脑直连的,那么 dhcp 命令就会失效。
- nfs 命令
nfs(Network File System)网络文件系统,通过 nfs 可以在计算机之间通过网络来分享资源,比如将 linux 镜像和设备树文件放到 Ubuntu 中,然后在 uboot 中使用 nfs 命令将 Ubuntu 中的 linux 镜像和设备树下载到开发板的 DRAM 中。这样做的目的是为了方便调试 linux 镜像和设备树,也就是网络调试,网络调试是 Linux 开发中最常用的调试方法。虽然半导体厂商一般都会提供一个烧写固件的软件,但是这个软件使用起来比较复杂,这个烧写软件一般用于量产的。
一般使用 uboot 中的 nfs 命令将 Ubuntu 中的文件下载到开发板的 DRAM 中,在使用之前需要开启 Ubuntu 主机的 NFS 服务,并且要新建一个 NFS 使用的目录,以后所有要通过 NFS 访问的文件都需要放到这个 NFS 目录中。
在 Ubuntu 中搭建 NFS 目录,要先安装并开启 Ubuntu 中的 NFS 服务,使用如下命令安装 NFS 服务:
sudo apt-get install nfs-kernel-server rpcbind
等待安装完成,安装完成以后在用户根目录下创建一个名为 “linux” 的文件夹,以后所有的东西都放到这个 “linux” 文件夹里面,在 “linux” 文件夹里面新建一个名为 “nfs” 的文件夹,如下图:
可以在开发板上通过网络文件系统来访问 nfs 文件夹,要先配置 nfs,使用如下命令打开 nfs 配置文件/etc/exports:
sudo gedit /etc/exports
打开后添加如下一行:
/home/xhj/linux/nfs *(rw,sync,no_root_squash)
Ubuntu20.04 中默认关闭了 NFS V2 版本,uboot 里面使用 nfs 命令下载可能失败,所以需要打开 NFS V2 版本。打开/etc/default/nfs-kernel-server,加入下面这行:
RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog"
最后重启 NFS 服务,使用命令如下:
sudo /etc/init.d/nfs-kernel-server restart
至此,Ubuntu 下的 NFS 服务搭建完毕。
uboot 中的 nfs 命令格式如下所示:
nfs [loadAddress] [[hostIPaddr:]bootfilename]
loadAddress 是要保存的 DRAM 地址,[[hostIPaddr:]bootfilename]是要下载的文件地址。这里将正点原子官方编译出来的 Linux 内核镜像文件 boot.img 下载到开发板 DRAM 的 0X30000000 这个地址处(这个地址是笔者随便定义的)。将 boot.img 拷贝到 NFS 目录下:~/linux/nfs。准备好以后就可以使用 nfs 命令来将 boot.img 下载到开发板 DRAM 的 0X30000000 地址处,命令如下:
nfs 30000000 192.168.5.2:/home/xhj/linux/nfs/boot.img
命令中的 “30000000” 表示 boot.img 在 DDR 中的首地址, “192.168.5.2:/home/xhj/linux/nfs/boot.img” 表示 boot.img 在 192.168.5.2 这个主机中,路径为 /home/xhj/linux/nfs/boot.img。下载过程如下图所示:
下载完成以后查看 0x30000000 地址处的数据,使用命令 md.b 来查看前 0x100(256) 个字节的数据,如下图所示:
可以通过 winhex 软件来查看刚才下载的 boot.img,查看一下数据是否相同,相同则证明下载成功:
- tftp 命令
tftp 命令的作用和 nfs 命令一样,都是用于通过网络下载东西到 DRAM 中,只是 tftp 命令使用的是 TFTP 协议,Ubuntu 主机作为 TFTP 服务器。因此需要在 Ubuntu 上搭建 TFTP 服务器,需要安装 tftp-hpa 和 tftpd-hpa,命令如下:
sudo apt-get install tftp-hpa tftpd-hpa
sudo apt-get install xinetd
和 NFS 一样,TFTP 也需要一个文件夹来存放文件,在用户目录下新建一个目录,命令如下:
mkdir /home/xhj/linux/tftpboot
chmod 777 /home/xhj/linux/tftpboot
要给 tftpboot 文件夹权限,否则的话 uboot 不能从 tftpboot 文件夹里面下载文件。
最后配置 tftp,新建文件/etc/xinetd.d/tftp,如果没有 /etc/xinetd.d 目录的话自行创建,然后在里面输入如下内容:
server tftp
{socket_type = dgramprotocol = udpwait = yesuser = rootserver = /usr/sbin/in.tftpdserver_args = -s /home/alientek/linux/tftpboot/disable = noper_source = 11cps = 100 2flags = IPv4
}
完成后启动 tftp 服务,命令如下:
sudo service tftpd-hpa start
打开 /etc/default/tftpd-hpa 文件,将其修改为如下所示内容:
# /etc/default/tftpd-hpaTFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/xhj/linux/tftpboot"
TFTP_ADDRESS=":69"
TFTP_OPTIONS="-1 -c -s"
最后输入如下命令, 重启 tftp 服务器:
sudo service tftpd-hpa restart
tftp 服务器已经搭建好了,接下来就是使用了。将 boot.img 镜像文件拷贝到 tftpboot 文件夹中,并且给予 boot.img 相应的权限,命令如下:
cp boot.img /home/alientek/linux/tftpboot/
cd /home/alientek/linux/tftpboot/
chmod 777 boot.img
uboot 中的 tftp 命令格式如下:
tftpboot [loadAddress] [[hostIPaddr:]bootfilename]
loadAddress 是文件在 DRAM 中 的存放地址,[[hostIPaddr:]bootfilename] 是要从 Ubuntu 中下载的文件。但是和 nfs 命令的区别在于,tftp 命令不需要输入文件在 Ubuntu 中的完整路径,只需要输入文件名即可。如将 tftpboot 文件夹里面的 boot.img 文件下载到开发板 DRAM 的 0X30000000 地址处,命令如下:
tftp 30000000 boot.img
下载过程如下:
EMMC 和 SD 卡操作命令
uboot 支持 EMMC 和 SD 卡,因此也要提供 EMMC 和 SD 卡的操作命令。uboot 中常用于操作 MMC 设备的命令为 “mmc”。
mmc 是一系列的命令,其后可以跟不同的参数,输入“?mmc”即可查看 mmc 有关的命令,如下图:
可以看出,mmc 有不同功能:
- mmc info 命令
mmc info 命令用于输出当前选中的 mmc info 设备的信息,输入命令“mmc info”即可,如下图所示:
- mmc rescan 命令
mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备,包括 EMMC 和 SD 卡,输入 “mmc rescan” 即可。
- mmc list 命令
mmc list 命令用于来查看当前开发板一共有几个 MMC 设备,输入“mmc list”,结果如下所示:
可以看出当前开发板有三个 MMC 设备:sdhci@fec310000:0 (eMMC)、dwmmc@fe2c0000:2 和 dwmmc@fe2b0000:1,一共有三个 MMC 设备,sdhci@fec310000:0 (eMMC)是 EMMC,dwmmc@fe2b0000:1 (SD)是 SD 卡,另一个应是 SDIO WIFI 设备(若没有接 MMC 设备,这里就代表 SDIO 总线)。默认会将 EMMC 设置为当前 MMC 设备,这就是为什么输入 “mmc info” 查询到的是 EMMC 设备信息,而不是 SD 卡。要想查看 SD 卡信息,就要使用命令“mmc dev” 来将 SD 卡设置为当前的 MMC 设备。
- mmc dev 命令
mmc dev 命令用于切换当前 MMC 设备,命令格式如下:
mmc dev [dev] [part]
[dev]用来设置要切换的 MMC 设备号,[part] 是分区号,如果不写分区号的话默认为分区 0。使用如下命令切换到 SD 卡:
mmc dev 1 //切换到 SD 卡,0 为 EMMC,1 为 SD 卡
- mmc part 命令
有时候 SD 卡或者 EMMC 会有多个分区,可以使用命令“mmc part”来查看其分区,比如查看 EMMC 的分区情况,输入如下命令:
mmc dev 0 //切换到 EMMC
mmc part //查看 EMMC 分区
结果如下图所示:
此时 EMMC 是 EFI 类型并且有 8 个分区,这个是烧写了正点原
子出厂系统以后才会有的分区。
如果要将上图中 EMMC 的分区 6 设置为当前 MMC 设置分区,可以使用如下命令:
mmc dev 0 6
- mmc read 命令
mmc read 命令用于读取 mmc 设备的数据,命令格式如下:
mmc read addr blk# cnt
addr 是数据读取到 DRAM 中的地址,blk 是要读取的块起始地址(十六进制),一个块是 512 字节,这里的块和扇区是一个意思,在 MMC 设备中通常说扇区,cnt 是要读取的块数量(十六进制)。比如从 EMMC 的第 1024(0x400)个块开始,读取 16(0x10)个块的数据到 DRAM 的 0XC0000000 地址处,命令如下:
mmc dev 0 //切换到 EMMC
mmc read 8300000 400 10 //读取数据
EXT 格式文件系统操作命令
uboot 有 ext2 和 ext4 这两种格式的文件系统的操作命令,RK3568 的系统镜像都是 ext4 格式的,所以重点讲解一下和 ext4 有关的三个命令:ext4ls、ext4load 和 ext4write。注意,由于只有 linux 内核、设备树和根文件系统是以 ext4 格式存放在 EMMC 中的,因此在测试 ext4 相关命令的时候要先确保 EMMC 里面烧写了完整的出厂系统!
- ext4ls
ext4ls 命令用于查询 EXT4 格式设备的目录和文件信息,命令格式如下:
ext4ls <interface> [<dev[:part]>] [directory]
interface 是要查询的接口,比如 mmc,dev 是要查询的设备号,part 是要查询的分区,directory 是要查询的目录。比如查询 EMMC 分区 6 中的所有的目录和文件,输入命令:
ext4ls mmc 0:6
可以看出 emmc 分区 6 存放了根文件系统。
- ext4load 命令
extload 命令用于将指定的文件读取到 DRAM 中,命令格式如下:
ext4load<interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]
interface 为接口,比如 mmc,dev 是设备号,part 是分区,addr 是保存在 DRAM 中的起始地址,filename 是要读取的文件名字。bytes 表示读取多少字节的数据,如果 bytes 为 0 或者省略的话表示读取整个文件。pos 是要读的文件相对于文件首地址的偏移,如果为 0 或者省略的话表示从文件首地址开始读取。将上图中 EMMC 分区 6 中的 linuxrc 文件读取到 DRAM 中的 0X08300000 地址处,命令如下:
ext4load mmc 0:6 8300000 linuxrc
BOOT 操作命令
uboot 的本质工作是引导 Linux,所以 uboot 肯定有相关的 boot(引导)命令来启动 Linux。常用的跟 boot 有关的命令有:boot_fit 和 boot。
- boot_fit 命令
之前学 STM32MP1 的话, uboot 使用 bootm 或者 bootz 这两个命令启动内核,需要提供 Linux 编译出来的 zImage 或 uImage 以及设备树文件,然后使用 bootm 或 bootz 启动。但是 RK3568 最终的系统烧写文件只有一个 boot.img,Image 和设备树文件全部打包进 boot.img 这一个文件里面,所以就不能用 bootm 或 bootz,要用到 boot_fit 命令。
boot_fit 命令格式如下:
boot_fit [addr]
addr 是可选的,也就是 boot.img 在 DRAM 中的位置。可以不需要,boot_fit 默认会从相应的 boot 分区里面读取 boot.img 然后解析启动 Linux 内核,比如把系统烧写到 EMMC 里面后,只需要一个 boot_fit 命令就可以完成 Linux 内核和设备树的提取、启动。
如果想要从网络启动系统,那么先把 boot.img 放到 Ubuntu 的 tftpboot 文件夹中,然后用 tftp 命令将 boot.img 下载到开发板的 DRAM 中,然后使用 boot_fit 命令启动。首先是要先将 boot.img 通过 tftp 下载到合适的 DRAM 地址处,这里需要用到 sysmem_search 命令找到一个合适的存储起始地址,sysmem_search 命令格式如下:
sysmem_search size
size 就是要获取的内存大小,为十六进制的。一般来说就是 boot.img 大小,但是每次重新编译 Linux 内核以后 boot.img 大小都会变,每次都要获取内存起始地址太麻烦了。就直接获取一个 25MB 的空间就行了,所以 25MB=0X1900000,输入如下命令:
sysmem_serach 1900000
从上图可以看出,当前得到的地址为 0XE9EF7000,大家以自己实际得到的地址为准!接下来就是通过 tftp 将 boot.img 下载到 0XE9EF7000 地址处,然后通过 boot_fit 命令启动,整个的命令如下:
tftp E9EF7000 boot.img
boot_fit E9EF7000
- boot 和 bootd 命令
boot 和 bootd 其实是一个命令,它们最终执行的是同一个函数。此命令也是用来启动 Linux 系统的,只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统,bootcmd 是一个很重要的环境变量!
RK3568 开发板 bootcmd 默认值如下图所示:
可以看出 bootcmd 默认值为“boot_fit;boot_android ${devtype} ${devnum};bootrkp;run distro_bootcmd”,其中 devtype 为 mmc,devnum 为 0,所以简化一下就是“boot_fit;boot_android mmc 0;”。也就是有两种启动内核的方式:boot_fit 和 boot_android,其中 boot_android 在 RK3568 里面无效,因此实际有效的只有一个 boot_fit。后面的 bootrkp;run distro_bootcmd 未定义,所以无效。
因此在 RK3568 中,bootcmd 就是直接调用 boot_fit 命令来启动 Linux 系统的。uboot 倒计时结束以后会默认运行 bootcmd 环境变量里面的命令,所以 boot_fit 也就会默认执行。
其他常用命令
uboot 中还有其他一些常用的命令,比如 reset、go、run 和 mtest 等。
- reset 命令
reset 命令就是复位的,输入“reset”即可复位重启,如下图所示:
- go 命令
go 命令用于跳到指定的地址处执行应用,命令格式如下:
go addr [arg ...]
addr 是应用在 DRAM 中的首地址。
- run 命令
run 命令用于运行环境变量中定义的命令,比如可以通过“run bootcmd”来运行 bootcmd 中的启动命令,但是 run 命令最大的作用在于运行自定义的环境变量。
至此,uboot 常用命令基本学习完毕,剩余的可以直接查看 uboot 自己的帮助信息。
MII 命令使用说明
MII 命令是网络相关命令,主要用于读取网络 PHY 芯片寄存器,在 uboot 中调试网络 PHY芯片的时候非常有用!MII 是一系列命令,如下图所示:
使用“mii info”命令,“mii info”命令格式如下:
mii info <addr>
其中 addr 就是 PHY 芯片地址,RK3568 开发板上网络 PHY 地址为 0X01,输入如下命令:
mii info 0x1
也可以使用 “mii dump” 直接打印出 PHY 的 0~5 寄存器值,输入如下命令:
mii dump 1 0-5
其中 1 表示 PHY 地址为 1,0-5 表示读取 0-5 这 6 个寄存器,结果如下图所示:
也可以使用 “mii read” 命令读取 PHY 芯片的其他寄存器。或者使用 “mii write” 命令向指定的寄存器写入一个数据。