第三章:Linux内核编译——内核配置、设备树基础与镜像生成

好,咱们进入第三章。这一章可以说是整个双屏异显方案的基石——你得先把内核跑起来,才能谈上层应用。我见过不少新手,一上来就改驱动、调屏幕,结果内核都编不过,白白浪费好几天。所以,咱们先把内核编译这件事儿捋清楚。

3.1 内核配置:别被那些选项吓到

全志T113-S3这颗芯片,官方SDK里带了一份默认配置。我个人习惯,第一步不是直接改,而是先看看这份配置到底开了什么。

核心思路:内核配置的本质,就是告诉编译器“哪些功能要编进去,哪些不要”。对于双屏异显,你至少得保证DRM框架、两个显示控制器(DE、TCON)以及对应的LCD/HDMI驱动是打开的。

怎么操作?进入内核源码目录,执行:

make ARCH=arm menuconfig

嗯,这里要注意。T113-S3是ARM Cortex-A7内核,所以ARCH必须指定为arm。我刚开始做的时候,忘了加这个参数,结果编译出来一堆x86的玩意儿,哭笑不得。

在menuconfig界面里,你需要关注几个关键路径:

  • Device Drivers → Graphics support:这里要确保DRM、Sunxi DRM驱动是选中的。双屏异显依赖DRM的多个CRTC和Encoder。
  • Device Drivers → Graphics support → Display Panels:如果你用的是RGB/LVDS屏幕,这里要选对应的panel驱动。
  • Device Drivers → Graphics support → HDMI:HDMI输出需要打开sunxi_hdmi驱动。

我的小技巧:别手动一个个翻菜单,太累了。你可以用menuconfig的搜索功能(按/键),输入“SUNXI”或者“DRM”,直接定位到相关选项。我在项目中经常这么干,省时省力。

配置完成后,保存退出。配置会写入.config文件。我个人习惯把这个文件备份一份,命名为config_t113_dual_display,方便以后复用。

3.2 设备树基础:硬件描述的艺术

设备树(Device Tree)是什么?说白了,就是告诉内核“你的硬件长什么样”。T113-S3的引脚复用、时钟频率、显示接口参数,全写在这里。

全志的SDK里,设备树文件一般在arch/arm/boot/dts/目录下。T113-S3对应的文件通常是sun8i-t113-s3.dtsi(芯片级)和sun8i-t113-s3-xxx.dts(板级)。

对于双屏异显,设备树里最关键的是显示管道的描述。举个例子:

&de {
    status = "okay";
};

&tcon0 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = &lcd_rgb666_pins;
};

&tcon1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = &hdmi_pins;
};

你看,这里有两个TCON(Timing Controller)。TCON0通常接RGB/LVDS屏幕,TCON1接HDMI。每个TCON都有自己的引脚配置和时序参数。

我曾经踩过的坑:有一次我忘了给TCON1配置pinctrl,结果HDMI死活没信号。查了两天才发现,引脚复用没设对。所以,写设备树时,一定要确认每个外设的pinctrl节点都配好了。

设备树编译也很简单:

make ARCH=arm dtbs

编译后会生成.dtb文件。这个文件会跟内核镜像打包在一起,或者单独烧录到分区里。

3.3 编译生成boot.img与内核镜像

好,配置和设备树都搞定了,接下来就是编译。全志平台通常用mkbootimg工具来打包boot.img。boot.img里包含了内核镜像(zImage)和设备树(dtb)。

编译内核镜像:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 zImage

这里CROSS_COMPILE指定交叉编译工具链前缀。我建议用全志官方提供的工具链,版本太新或太旧都可能出问题。

生成zImage后,再打包boot.img:

mkbootimg --kernel arch/arm/boot/zImage \
          --ramdisk /path/to/ramdisk.img \
          --dtb arch/arm/boot/dts/sun8i-t113-s3-xxx.dtb \
          --base 0x40000000 \
          --output boot.img

注意--base参数,这是内核的加载地址。T113-S3的DDR起始地址是0x40000000,所以base设成这个值。我见过有人设成0x80000000,结果内核直接崩溃。

我的习惯:每次编译前,先执行make ARCH=arm clean,把之前的编译产物清掉。虽然会多花几分钟,但能避免很多莫名其妙的链接错误。

编译完成后,你会得到以下文件:

文件 说明
arch/arm/boot/zImage 压缩后的内核镜像
arch/arm/boot/dts/xxx.dtb 编译好的设备树
boot.img 可烧录的启动镜像(含内核+dtb+ramdisk)

3.4 验证与调试

镜像生成后,怎么验证对不对?我一般用fastboot把boot.img刷到板子上,看串口日志。

fastboot flash boot boot.img
fastboot reboot

如果内核启动时打印了DRM、TCON的初始化信息,并且两个显示接口都检测到了,那基本就稳了。如果某个接口没起来,先检查设备树里的status是不是"okay",再查pinctrl配置。

避坑指南:我曾经遇到一个情况,内核编译通过了,但刷进去后屏幕不亮。查了半天,发现是mkbootimg打包时--base参数写错了。所以,每次打包前,务必确认加载地址跟芯片手册一致。

嗯,这一章的内容就到这里。内核编译是嵌入式开发的基本功,看似简单,但细节很多。你只要把配置、设备树、打包这三步走顺了,后面的驱动开发就会轻松很多。