U-Boot v2020.01 和 Linux 5.4 在 RK3399 上部署
mainline 的 u-boot 和 linux kernel
可能很多玩 Linux 的同学都听过 mainline 或者 upstream 这两个词,但是又搞不清他们到底指的是什么。
一般大家拿到一块开发板,上面搭载的都是芯片原厂开发的 u-boot 和 linux kernel,我们称之为vendor 的 u-boot 和 kernel,这些内核一般是基于 linux 官方的某个分支修改的,比如 i.MX6 目前用的内核很多是 Linux 4.1,rk3288/rk3399 目前用的内核大部分是 Linux 4.4,芯片原厂为了系统的稳定和易于维护,一般会在这个特定的版本上做长期开发,轻易不会升级内核版本,而 Linux 官方内核却会以固定的节奏向前不停的演进,比如目前最新的稳定版本为 Linux 5.4.2,我们称这种 Linux kernel 开源社区官方发布的内核为 mainline 内核或者 upstream 内核。
u-boot 也是同样的概念。
过去两个月利用空闲时间在 RK3399 Leez P710 开发板上移植了最新的 U-Boot 和 Linux kernel,然后把对应的补丁提交到了 mainline 上,Linux Kernel 的补丁被合并到 Linux 5.4 中,对 U-Boot 的支持补丁也在 V2020.01 中被合并了。
随着最近 U-Boot v2020.1 和 Linux 5.4 的相继发布,这块开发板已经可以直接用 mainline 的 U-Boot 和 Linux kernel 来启动了。
这篇文章以 Leez P710 为例,描述了把 mainline u-boot 和 linux kernel 部署到开发板上的步骤,如果想在其他开发板上做测试,方法类似,只要选择对应的 u-boot defconfig 文件和 Linux kernel dtb 文件即可。
这里顺便说下当前 Linux 和 U-Boot 开源社区的开发节奏。
Linux 一般是两个月发布一个大版本,像 Linux 5.2、Linux 5.3、Linux 5.4这样的,在这两个月的开发周期中,一般会按照一周一个的节奏发布 7~8个候选版本(rc1~rc8), rc1 里面会包含各种新功能新特性,rc2~rc8 一般只接受对当前版本中存在的 bug 修改,不允许增加新功能,直到整个系统趋于稳定,没有明显的 bug,然后发布正式版本,比如 Linux 5.4 就是经过了 8 个候选版本才发布的。正式版本发布后同时也会打开下一个大版本的合并窗口,这个合并窗口大概是两个星期的时间,开源社区的各路大佬(Linus 信任的 maintainer)会在这两个星期中把自己收到的补丁以 Pull Request 的形式发送给 Linus,由 Linus 来决定是否最终合并。
U-Boot 开源社区目前是 3 个月发布一个大版本,而且版本号按照正式发布的时候对应的时间命名,比如 v2019.07,v2019.10,v2020.01,一般是两到三个星期发布一个候选版本,而且也是只在 rc1 版本中接受新增功能和特性,其他的候选版本只允许修改 bug。
所以如果你要向 Linux 和 U-Boot 社区提交代码,一定要赶在 rc1 版本发布之前把补丁发给对应的 maintainer,错过这个窗口期就要等几个月到下一个版本才会被接受了。
Armbian
Armbian 是国外开发者维护的一个针对各种 Arm 开发板的开源项目,支持了大量基于Rockchip、Allwinner、Amlogic 主控的开发板,还有少量几款基于 i.MX 的开发板。从这个项目里面可以编译出在 Arm 上运行的 Debian 和 Ubuntu 系统。
我以 mainline 的 u-boot 和 Linux kernel 为基础,利用 Armbian 做了一个 Debian 10 的镜像,分享在百度网盘上:链接: https://pan.baidu.com/s/1avuzcmSMvGREv4Cioh1_UA 提取码: af5i
。
这个镜像可以用 Etcher
软件烧写到 TF卡中,然后把卡插到开发板上,让系统从开发板启动。
如果你的板子上有eMMC,最好先把eMMC 上的固件擦除,至少把eMMC 从第64个扇区开始的一小段擦除,因为RK3399 默认是优先从eMMC 启动的,擦除方法很多,比如进入 u-boot 命令行,通过 mmc erase
命令擦除:
把 TF 卡插到板子后上电,系统会从 TF 卡上启动,接上串口或者 HDMI 就能看到系统启动后的登录信息,默认登录账号和密码分别为 root
和 1234
,输入密码后系统会要求重新修改密码,按照要求操作即可。
进入命令行后,可以通过 nmtui-connect
命令扫描 WiFi,联网。
在 HDMI 屏幕上可以通过 lightdm
命令启动桌面。不过这个桌面是不带 GPU 加速的,我后面会专门写一篇文章来讲怎么启动 GPU 加速。
还可以通过 nand-sata-install
命令把整个系统从 TF 卡上迁移到 eMMC 上,不过整个操作你最好通过 ssh 登录后操作,我发现在串口下面界面显示的有问题。
安装完毕后会提示 All done. Power off
, 选择 Power off
后,拔掉卡,再上电,系统就会从eMMC 启动了。
更新 U-Boot
我们可以自己编译 mainline 的 U-Boot 然后更新到板子上。
因为 RK3399 是 Arm64,所以我们还需要编译 ATF (Arm trust firmware), ATF 主要负责在启动 U-Boot 之前把 CPU 从安全的 EL3 切换到 EL2,然后跳转到 U-Boot,并且在内核启动后负责启动其他的 CPU。
- 下载 ATF
git clone https://github.com/ARM-software/arm-trusted-firmware.git
- 编译 ATF
make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3399
最终编译出来的目标文件为:build/rk3399/release/bl31/bl31.elf, 这个文件需要和编译出来的 u-boot 一起打包成 fit 格式的镜像才能被 SPL 加载。
- 下载 U-Boot
git clone https://gitlab.denx.de/u-boot/u-boot.git
- 编译 U-Boot
export BL31=../../arm-trusted-firmware/build/rk3399/release/bl31/bl31.elf
make leez-rk3399_defconfig
make CROSS_COMPILE=aarch64-linux-gnu-
第一步设置 BL31 环境变量,即指定前面编译的 bl31.elf 的位置,u-boot 编译到最后会把它打包到 fit 镜像中。
第二步执行 Leez-RK3399 这块开发板对应的配置文件。
第三步开始编译。
最终编译成功后会生成两个供烧写的文件:
- idbloader.img :是 TPL 和 SPL 的合成文件,前者负责 DDR 初始化,后者负责加载 ATF 和 u-boot。
- u-boot.itb : 是由 u-boot 和 前面的 ATF 合成的 FIT 格式的镜像文件。
- 更新 U-Boot 到开发板上
可以通过 scp
命令把编译的 idbloader.img 和 u-boot.itb 拷贝到开发板上,然后通过 dd
命令把这两个文件写入 eMMC 中。其中 idbloader.img 写到 64 扇区处,u-boot.itb 写到 16384 扇区处:
写完后执行 reboot
命令重启,可以从时间戳上判断 u-boot 已经更新成功了。
更新 Linux Kernel
- 下载 mainline linux kernel
git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
如果下载速度比较慢,可以参考这篇文章:一个 Git Clone 加速小技巧 来提速。
- 切到最新的稳定版 Linux 5.4 分支
git checkout -b linux-5.4.y origin/linux-5.4.y
- 编译
make ARCH=arm64 defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8
编译成功后会生成 Image 和 dtb 文件:
- 更新 Linux Kernel 到开发板上
编译生成的 Image 和 dtb 文件还是通过 scp
命令拷贝到开发板上。
Armbian 采用和 PC Ubuntu 发行版同样的启动机制,把 Kernel Image 放在 /boot 目录下,用户只要把 Kernel Image 和 dtb 拷贝进来,重启开发板,新内核就替换成功,而不需要专门让开发板进烧写模式。
所以我们只要用编译好的 Image 和 dtb 来分别替换 vmlinuz-5.4.1-rockchip64
和rk3399-leez-p710.dtb
即可。
为了安全起见,最好先把系统中原生的 vmlinuz-5.4.1-rockchip64
和 rk3399-leez-p710.dtb
拷贝出来备份起来,万一更新的固件破坏了某个功能,还可以用备份的来恢复。
更新完重启,可以看到最新的内核已经生效。
如果在编译 Linux Kernel 或者 U-Boot 的过程中遇到问题,可以参考这篇文章:Linux Kernel 和 U-Boot 编译的那些事。
更多原创文章,请扫码关注公众号:HackforFun。