U-BOOT的本地控制台输出

U-BOOT是伴随Linux成长起来的引导程序(Boot Loader),以代码短小精悍,功能灵活强大著称。虽然它支持包括比如Power PC和X86在内的很多种CPU,但是在ARM上使用的最广泛。比如幽兰代码本最初使用的就是U-BOOT。2023年年初,幽兰本增加了UEFI支持,但使用了一段时间后,又改为默认预装U-BOOT了。

曾经改用UEFI的主要原因有两个:一个是支持Windows,另一个是本地的交互界面,包括GUI和UEFI Shell。

改回U-BOOT的原因也主要有两个:一是U-BOOT速度快,二是硬件适配得比较好。U-BOOT对ARM的支持超过20年,而UEFI在ARM上的时间虽然算起来也有将近10年,但是实际使用不多,还属于磨合阶段。

换回U-BOOT后,少了UEFI的本地GUI和UEFI Shell。如何弥补这个缺失呢?

其实,U-BOOT也是有命令接口(Command Shell)的,而且命令的数量和功能与UEFI不相上下,只是使用起来不如UEFI那么方便。

幽兰使用的U-BOOT是基于瑞芯微定制过的版本修改的(以下简称RK版本)。以这个版本为例,只能通过串口终端才能激活和使用命令接口。

具体来说,需要使用一根串口线和两台电脑,在U-BOOT阶段在串口终端中按热键1打断自动启动,让其进入命令行。

Autoboot in 2 seconds
ulan# version
U-Boot 2017.09-YourLand_YouXi (Jan 27 2025 - 14:39:17 +0800)


gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
GNU ld (GNU Binutils for Ubuntu) 2.42
ulan#

本地对话

串口终端需要两台电脑,肯定不如本地交互方便。为此,我一直在思考如何解决这个问题。

在谷歌公司工作的Simon Glass是U-BOOT的一位重要开发者,他在2023年6月的Embedded Open Source Summit上演讲,题目为《U-Boot中的近期进步》(Recent Advances in U-Boot)。

9fb3e18881e0c4d6b70aa2bc1d1030db.jpeg

(Simon Glass,U-Boot重要开发者,照片来自Github)

在这个演讲中,Simon介绍了U-Boot的expo子系统,用于显示图形和文字,开发图形界面,比如菜单等。

fb129bbf5671932dea66da212b6ecb07.png

Simon提到expo子系统已经在U-Boot的主线代码里,但是并不在RK代码里。因为expo子系统是在2022年开发的,而RK代码是基于主线的2017年9月版本。

看到曙光

上周在准备U-BOOT课程的讲义时,我仔细梳理了U-BOOT的所有命令,注意到了一条以前没有注意到的命令,名叫lcdputs。

ulan# lcdputs
lcdputs - print string on video framebuffer


Usage:
lcdputs     <string>

读这条命令的帮助信息,“在视频帧缓冲区上打印字符串”,正是我想要的。

于是,马上试了一下,lcdputs hi

但是屏幕上没有任何变化。

上挥码枪

接上挥码枪调试,设置断点,跟踪do_lcd_puts函数,发现内部执行console_normal_putc_xy函数时出错了。

ba4cd7a2445585ac213f13f9d98e3806.png

具体来说,是上面的第85处返回错误了。

观察设备对象的私有数据,代表屏幕宽度的xsize_frac居然为0。

a91e94770a1098df6a110e488982dedc.png

追查代码,找这个字段的赋值过程,发现它源于xsize字段。而xsize和它的兄弟ysize是通过如下两个宏来赋值的。

uc_priv->xsize = DRM_ROCKCHIP_FB_WIDTH;
  uc_priv->ysize = DRM_ROCKCHIP_FB_HEIGHT;
  uc_priv->bpix = VIDEO_BPP32;

查这两个宏的定义:

#ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER
 #define DRM_ROCKCHIP_FB_WIDTH    800
 #define DRM_ROCKCHIP_FB_HEIGHT    600
 #define DRM_ROCKCHIP_FB_BPP    VIDEO_BPP32
#else
 #define DRM_ROCKCHIP_FB_WIDTH    0
 #define DRM_ROCKCHIP_FB_HEIGHT    0
 #define DRM_ROCKCHIP_FB_BPP    VIDEO_BPP32
#endif

是根据CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER条件编译的。而CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER的确没有定义。

定义CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER宏后,先是更新新版本遇到了点麻烦(pre-loader升级rkbin后魔码错误),解决了之后,也还是不能显示。

沙箱模式

为了方便调试,U-Boot支持以App方式运行,称为沙箱模式(Sandbox)。

昨天,我花了大约2小时的时间,亲自试验了这种方法。

8d0198a9d6c8027404fe411336d79f2f.png

在沙箱模式下,我测试了lcdputs功能,是可以工作的。顺便也跟踪了它的执行过程。

锲而不舍

临近春节假期,小伙伴们陆续休假回老家了。今天是春节前的最后一个工作日,早晨6点半左右,我就到了办公室。

试验室里很安静,我一边准备U-Boot课程的讲义,一边看U-Boot的代码和文档,也时不时的在幽兰上做各种试验。

为了准备驱动模型一讲的讲义,我逐行阅读了U-Boot文档中的Develop U-Boot/Driver Model / Design Details部分。并且做了很多试验,包括用挥码枪调试器看幽兰上的设备树和具体实现。

使用dm tree命令观察,可以看到上百个驱动。考虑到萦绕心头许久的本地界面问题,我再次选择了视频实现有关的驱动,上调试器,看活代码。

关于U-Boot,瑞芯微也有一篇很不错的文档,也是很多同行积累了多年的成果。

把多方面收集的信息汇总到一起,眼前的代码逐渐从陌生变得熟悉。脑海中有了一幅比较清晰的蓝图。总体来说,关于RK硬件的显示驱动有两套代码,一套出自RK官方,在video/dm目录下,另一套出自开源社区,在video目录下。前者代码量较大,支持幽兰使用的RK3588芯片,后者只支持比较老的芯片。功能方面RK驱动实现了显示图片和启动徽标,没有很好的实现字符显示。

充分理解代码后,我开始尝试做一些修改,特别是仔细核对分辨率后,纠正前面设置分辨率的两个宏定义。

edp@fded0000:  detailed mode clock 148500 kHz, flags[a]
    H: 1920 1968 2000 2200
    V: 1080 1083 1089 1126
bus_format: 100e

这样调整代码和更新后,重启时,我看到一些白色的字符在屏幕上方划过,虽然很快就被后来显示徽标所替代,但是我还是确认那就是代码里打印出的字符,我的修改有效果了。

仔细跟踪前面提到的console_normal_putc_xy函数,很容易看出它的工作原理就是把字符的点阵信息“镶嵌”到帧缓冲区(fb)里。

Sandbox下,这个帧缓冲区被通过video_sync函数刷新到窗口里,就显示出来了。

但是目前使用的代码中,video_sync函数并没有把fb发送给dm下的video驱动。

仔细跟踪可以工作的位图显示代码,我发现显示位图时调用的函数叫display_logo,display_logo的代码是把位图的内存区传给底层的。

display_set_plane(state);
  display_enable(state);

display_logo接受的参数是一个display_state 结构体。

static int display_logo(struct display_state *state)

接下来的目标便是如何给帧缓冲区fb封装一个display_state 结构体,浏览代码,发现有一个rockchip_show_fbbase函数实现了这个逻辑。

有了这些基础后,我大胆地在video_sync函数末尾加入如下三行代码:

#ifdef CONFIG_DRM_ROCKCHIP_VIDEO_FRAMEBUFFER
  rockchip_show_fbbase(priv->fb);
  video_set_flush_dcache(vid, true);
#endif

然后构建更新,再进入U-Boot命令,执行lcdputs hi,这一次出现在屏幕上了。再试: ulan# lcdputs "Happy 2025 Sping Festival!\n"

也显示出来了。

05cc7cfa915e5cadfa0b32bd13485779.jpeg

期待多日的本地显示功能终于在龙年的最后一个工作日工作了。高兴之余,我站起身顺手向窗外拍了一张照片,这棵香樟树看见了我调试的全过程。

183d7720fd6debaf69198d77aa1e49a3.jpeg

龙年即将过去,在此感谢一直支持格蠹的各位格友,祝大家新一年里大吉大利!

(写文章很辛苦,恳请各位读者点击“在看”,欢迎转发)

*************************************************

正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生

扫描下方二维码或者在微信中搜索“盛格塾”小程序,可以阅读更多文章和有声读物

3e51d21b8d88b3100aa55e5d9fad3c2a.png

也欢迎关注格友公众号

315d25be3d546137061d22652e86fbcd.jpeg

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值