1. R-Car平台概述:从芯片选型到第一个Hello World

各位好,我是老赵。做嵌入式图形驱动有些年头了,瑞萨R-Car平台也折腾了好几个项目。今天咱们聊聊R-Car系列,特别是它的图形显示子系统。嗯,这部分内容,说白了就是整个移植工作的地基——地基没打好,后面全是坑。

1.1 R-Car系列芯片:你该选哪一颗?

R-Car是瑞萨面向汽车电子推出的SoC家族。覆盖从入门仪表到高端座舱的全场景。我个人习惯把R-Car分成三代:

系列 典型型号 图形能力 典型场景
R-Car Gen2 H2, M2, E2 SGX544MP2 (PowerVR) 入门仪表、AVM
R-Car Gen3 H3, M3, E3, D3 GX6650 / GX6250 (PowerVR) 中高端座舱、全景环视
R-Car Gen4 S4, V4H, V3U AXR8G (Imagination) + 专用NPU 自动驾驶、超高清仪表

关键点: 如果你做的是图形显示驱动移植,Gen3是目前最成熟的平台。H3/M3的文档和社区支持最全。Gen4虽然性能强,但很多驱动接口还在迭代,我建议新手从Gen3入手。

为什么会这样?因为Gen3的图形显示子系统架构已经非常稳定。我在2018年做过一个H3的项目,当时被它的显示通道数量吓了一跳——最多支持8路独立显示输出。你想想看,一个芯片同时驱动仪表、中控、HUD、后排娱乐,这得有多强的显示控制器。

1.2 图形显示子系统架构:别被框图吓到

第一次看R-Car的显示子系统框图,你可能会觉得眼花缭乱。其实核心就三个模块:

  • DU (Display Unit) —— 显示控制器,负责合成图层、生成时序
  • VSP (Video Signal Processor) —— 视频处理管线,做缩放、旋转、色彩转换
  • LIF (LVDS/eDP/HDMI Interface) —— 物理输出接口

它们的关系是这样的:

R-Car Gen3 图形显示子系统架构 GPU (GX6650) 摄像头 (CSI-2) 视频解码器 VSP 缩放 / 旋转 色彩转换 Alpha混合 裁剪 / 拼接 最多 8 个 独立管线 DU 图层合成 时序生成 Gamma校正 抖动处理 最多 3 个 显示通道 LVDS / eDP / HDMI VSP + DU 构成完整 显示流水线

我的经验: 移植驱动时,90%的问题出在VSP和DU的时钟配置上。我曾经花了两天时间调试一个显示偏移问题,最后发现是VSP的时钟分频设错了。所以,拿到开发板第一件事——确认时钟树。

1.3 开发环境搭建:别在第一步就卡住

搭建开发环境这件事,说简单也简单,说复杂也复杂。我见过太多人在这一步浪费一整天。咱们按步骤来:

  1. 获取SDK —— 从瑞萨官网下载R-Car SDK (Yocto BSP)。注意选对芯片型号和版本。我个人习惯用LTS版本,稳定。
  2. 安装依赖 —— Ubuntu 20.04/22.04 都行。需要安装的工具链:gcc-arm-linux-gnueabihf、cmake、python3、device-tree-compiler。
  3. 配置Yocto环境 —— 运行 source poky/oe-init-build-env。然后修改 local.conf,指定MACHINE为你的板子型号。
  4. 编译最小系统 —— bitbake core-image-minimal。第一次编译会下载大量源码,建议用代理或提前准备好本地sstate缓存。
  5. 烧录与启动 —— 生成SD卡镜像,用 dd 命令写入。上电后通过串口观察启动日志。

注意: 瑞萨的BSP对网络要求很高。如果你在公司内网,记得配置好代理。我曾经因为代理没配好,编译到一半卡在git clone上,白白浪费了3个小时。

1.4 SDK安装:图形显示相关的组件

SDK装好之后,你还需要确认图形显示相关的组件是否齐全。我建议你检查以下几个关键包:

  • kernel-module-du —— DU显示控制器驱动
  • kernel-module-vsp —— VSP视频处理驱动
  • libdrm-rcar —— DRM/KMS用户态库
  • mesa-pvr —— PowerVR GPU的用户态驱动
  • wayland/weston —— 显示合成器(如果你用Wayland)

你可以用 bitbake -s | grep rcar 来列出所有R-Car相关的包。嗯,这里要注意:有些包名可能带版本号后缀,比如 libdrm-rcar-2.4.100,别搞混了。

快速验证: 系统启动后,执行 ls /dev/dri/。如果看到 card0 和 controlD64,说明DRM驱动加载成功。再执行 modetest,如果能显示输出信息,恭喜你,图形显示子系统已经跑起来了。

1.5 第一个测试:点亮屏幕

环境搭好了,咱们来点个灯。写一个最简单的DRM程序,在屏幕上显示纯色:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <drm/drm.h>
#include <drm/drm_mode.h>

int main() {
    int fd = open("/dev/dri/card0", O_RDWR);
    if (fd < 0) {
        perror("open card0 failed");
        return -1;
    }

    // 获取资源
    drmModeRes *res = drmModeGetResources(fd);
    if (!res) {
        perror("get resources failed");
        close(fd);
        return -1;
    }

    printf("Connectors: %d, Encoders: %d, CRTCs: %d\n",
           res->count_connectors, res->count_encoders, res->count_crtcs);

    drmModeFreeResources(res);
    close(fd);
    return 0;
}

编译命令:

arm-linux-gnueabihf-gcc -o drm_test drm_test.c -ldrm

把这个程序放到开发板上运行。如果输出类似 Connectors: 2, Encoders: 2, CRTCs: 3,说明你的DRM接口已经打通了。

小技巧: 如果 modetest 没有输出,先检查 dmesg | grep du 和 dmesg | grep vsp。我遇到过好几次,驱动加载成功了但显示没输出,最后发现是设备树里DU的时钟频率写错了。