首页
商城
  • English
  • 简体中文
首页
商城
  • English
  • 简体中文
  • 产品系列

    • FPGA+ARM

      • GM-3568JHF

        • 一、简介

          • GM-3568JHF 简介
        • 二、快速开始

          • 00 前言
          • 01 环境搭建
          • 02 编译说明
          • 03 烧录指南
          • 04 调试工具
          • 05 软件更新
          • 06 查看信息
          • 07 测试命令
          • 08 应用编译
          • 09 源码获取
        • 三、外设与接口

          • 01 USB
          • 02 显示与触摸
          • 03 以太网
          • 04 WIFI
          • 05 蓝牙
          • 06 TF-Card
          • 07 音频
          • 08 串口
          • 09 CAN
          • 10 RTC
        • 四、应用开发

          • 01 UART读写案例
          • 02 按键检测案例
          • 03 LED灯闪烁案例
          • 04 MIPI屏幕检测案例
          • 05 读取 USB 设备信息案例
          • 06 FAN 检测案例
          • 07 FPGA FSPI 通信案例
          • 08 FPGA DMA 读写案例
          • 09 GPS调试案例
          • 10 以太网测试案例
          • 11 RS485读写案例
          • 12 FPGA IIC 读写案例
          • 13 PN532 NFC读卡案例
          • 14 TF卡读写案例
        • 五、QT开发

          • 01 ARM64交叉编译器环境搭建
          • 02 QT 程序加入开机自启服务
        • 六、RKNN_NPU开发

          • 01 RK3568 NPU 概述
          • 02 开发环境搭建
          • 运行官方 YOLOv5 示例
        • 七、FPGA开发

          • ARM与FPGA通讯
          • FPGA开发手册
        • 八、其他

          • 01 根目录文件系统的修改
          • 02 系统自启服务
        • 九、资料下载

          • 资料下载
    • ShimetaPi

      • M4-R1

        • 一、简介

          • M4-R1简介
        • 二、快速上手

          • 01 OpenHarmony概述
          • 02 镜像烧录
          • 03 应用开发快速上手
          • 04 设备开发快速上手
        • 三、应用开发

          • 01 ArkUI

            • 1 ArkTS语言简介
            • 2 UI 组件-Row 容器介绍
            • 3 UI 组件-Column 容器介绍
            • 4 UI 组件-Text 组件
            • 5 UI 组件-Toggle 组件
            • 6 UI 组件-Slider 组件
            • 7 UI 组件-Animation 组件&Transition 组件
          • 02 资料获取

            • 1 OpenHarmony 官方资料
          • 03 开发须知

            • 1 Full-SDK替换教程
            • 2 引入和使用三方库
            • 3 HDC调试
            • 4 命令行恢复出厂模式
            • 5 升级App为system权限
          • 04 构建第一个应用

            • 1 构建第一个ArkTs应用-HelloWorld
          • 05 案例

            • 01 串口调试助手应用案例
            • 02 手写板应用案例
            • 03 数字时钟应用案例
            • 04 WIFI 信息获取应用案例
        • 四、设备开发

          • 1 Ubuntu环境开发

            • 01 环境搭建
            • 02 下载源码
            • 03 编译源码
          • 2 使用DevEco Device Tool 工具

            • 01 工具简介
            • 02 开发环境的搭建
            • 03 导入SDK
            • 04 HUAWEI DevEco Tool 功能介绍
        • 五、内核外设与接口

          • 01 指南
          • 02 设备树介绍
          • 03 NAPI 入门
          • 04 ArkTS入门
          • 05 NAPI开发实战演示
          • 06 GPIO介绍
          • 07 I2C通讯
          • 08 SPI通信
          • 09 PWM 控制
          • 10 串口通讯
          • 11 TF卡
          • 12 屏幕
          • 13 触摸
          • 14 Ethernet(以太网)
          • 15 M.2 硬盘
          • 16 音频
          • 17 WIFI & BT
          • 18 摄像头
        • 六、资料下载

          • 资料下载
      • M4-R2

        • 一、产品简介

          • M4-R2 产品简介
        • 二、快速上手

          • 快速上手
        • 三、Android 系统

          • 1 快速上手

            • Android系统烧录与启动
            • 开发环境搭建
            • ADB调试与日志分析
            • SDK下载与编译环境搭建
            • Android系统基础操作
          • 2 SDK 编译

            • Android_SDK编译
            • Android构建系统与增量编译
          • 3 系统开发

            • Android系统定制
          • 4 应用开发

            • Android应用开发入门
            • Android JNI开发
          • 5 驱动与 HAL

            • Android HAL开发
          • 6 AI 与 NPU

            • Android NPU使用指南
        • 四、硬件参考

          • 核心板参数
          • 底板接口定义
          • 40PIN引脚定义
          • 电源管理
        • 五、常见问题与故障排除

          • 系统启动问题
          • 外设驱动问题
          • 网络连接问题
          • 显示问题
          • 常见编译错误
        • 六、应用方案参考

          • 智能显示终端方案
          • 边缘AI计算方案
          • 工业控制方案
          • NVR安防监控方案
          • 智能家居网关方案
        • 七、资料下载

          • 资料下载
      • M5-R2A

        • 一、产品简介

          • M5-R2A 产品简介
        • 二、快速上手

          • 系统烧录指南
          • 开发环境搭建
          • 快速上手
          • SDK下载与编译环境搭建
        • 四、Debian/Ubuntu 系统

          • 1 快速上手

            • 系统启动与基础操作
            • 网络配置与SSH
            • 软件包管理与更新
            • Debian 与 Ubuntu 镜像差异
          • 2 系统开发

            • Linux SDK编译
            • 内核配置与裁剪
            • 设备树详解与实践
            • 根文件系统构建
          • 3 外设驱动开发

            • GPIO驱动与控制
            • I2C驱动开发
            • SPI驱动开发
            • UART串口驱动
            • PWM驱动
            • ADC驱动
            • CAN/CAN-FD驱动
            • USB主机与设备驱动
            • SDMMC/eMMC驱动
            • 以太网GMAC驱动
            • 音频驱动
            • 摄像头Camera驱动
            • 触摸屏驱动
            • 显示DRM驱动
            • HDMI显示驱动
            • PCIe驱动
            • WiFi/蓝牙驱动
            • 看门狗WDT驱动
            • 热敏传感器THERMAL驱动
          • 4 应用开发

            • C/C++应用开发入门
            • Python应用开发
            • Qt嵌入式开发实战
            • GStreamer多媒体开发
            • 网络编程与应用
            • 文件系统与存储
          • 5 AI 与 NPU

            • NPU架构与性能概览
            • RKNN Toolkit2安装与使用
            • 模型转换与量化
            • 分类模型部署(LeNet/ResNet)
            • 目标检测部署(YOLOv5/v7/v8)
            • 语义分割部署
            • 人脸检测与识别
            • OCR文字识别
            • NPU性能调优与调试
          • 6 多媒体

            • 显示框架
            • 摄像头应用
            • 视频编解码(MPP)
            • 音频开发与ALSA
            • RGA图像处理
          • 7 性能优化与调试

            • 系统启动时间优化
            • CPU/GPU/NPU调优
            • 内存与存储优化
            • 功耗分析与优化
            • 调试工具使用指南
          • 8 高级主题

            • 安全启动与加密
            • OTA远程升级
            • Docker容器部署
            • ROS/ROS2机器人开发
            • RTOS与Linux协同
        • 五、Android 系统

          • 1 快速上手

            • Android系统烧录与启动
            • Android系统基础操作
            • ADB调试与日志分析
          • 2 SDK 编译

            • Android SDK编译
            • Android构建系统与增量编译
          • 3 系统开发

            • Android系统定制
          • 4 应用开发

            • Android应用开发入门
            • Android JNI开发
          • 5 驱动与 HAL

            • Android HAL开发
          • 6 AI 与 NPU

            • Android NPU使用指南
        • 六、硬件参考

          • 核心板参数
          • 底板接口定义
          • 40PIN引脚定义
          • 电源管理
        • 七、资料下载

          • 资料下载
      • Pico-G1

        • 一、产品概述

          • 01 产品介绍
          • 02 SDK版本基本信息
        • 二、快速入门

          • 01 开发环境搭建
          • 02 镜像编译
          • 03 镜像烧录
          • 04 系统登录
          • 05 网络配置
          • 06 文件传输
          • 07 SDK目录结构
          • 08 部署第一个应用程序
          • 09 部署第一个驱动程序
          • 10 SD卡挂载
        • 三、外设与接口

          • 01 GPIO控制
          • 02 UART串口通信
          • 03 I2C 通信
          • 04 SPI 通信
        • 四、MPP媒体开发

          • 01 MPP媒体处理软件
          • 02 图像处理链路
          • 03 视频输入
          • 04 图像编码
        • 五、NPU与AI

          • 01 NPU驱动与运行库架构
          • 02 .xmm 模型加载
          • 03 SVP视频处理
          • 04 AI降噪 (AI_NR)
        • 六、应用程序示例

          • 01 加解密接口应用
          • 02 ADC 采集应用
          • 03 低功耗应用
          • 04 音频处理应用
          • 05 视频编码应用
          • 06 视频输入应用
          • 07 视频图形子系统应用
          • 08 区域叠加应用
          • 09 智能视频引擎应用
          • 10 UVC 网络摄像头应用
          • 11 综合快速演示应用
          • 12 FPN 校正应用
          • 13 区域运动检测应用
          • 14 MTCNN 人脸检测应用
        • 七、扩展板外设功能例程

          • 00 - Pico 扩展板外设功能例程总览
          • 01 - OLED 显示应用
          • 02 - TFT 显示应用
          • 03 - MPU6050 陀螺仪应用
          • 04 - ADC 采集应用
          • 05 - 无源蜂鸣器应用
          • 06 - MQ 气体传感器应用
          • 07 - GPS 定位应用
          • 08 - SHT20 温湿度应用
          • 09 - 超声波测距应用
          • 10 - SPO2 血氧传感器应用
          • 11 - 电机控制应用
          • 12 - 舵机控制应用
    • 开源鸿蒙

      • SC-3568HA

        • 一、简介

          • SC-3568HA简介
        • 二、快速上手

          • OpenHarmony概述
          • 镜像烧录
          • 开发环境准备
          • Hello World应用以及部署
        • 三、应用开发

          • ArkUI

            • 第一章 ArkTS语言简介
            • 第二章 UI组件介绍和实际应用(上)
            • 第三章 UI组件介绍和实际应用(中)
            • 第四章 UI组件介绍和实际应用(下)
          • 拓展

            • 第一章 入门指引
            • 第二章 三方库的引用和使用
            • 第三章 应用编译以及部署
            • 第四章 命令行恢复出厂设置
            • 第五章 系统调试--HDC调试
            • 第六章 APP 稳定性测试
            • 第七章 应用测试
        • 四、设备开发

          • 第一章 环境搭建
          • 第二章 下载源码
          • 第三章 编译源码
        • 五、内核的外设与接口

          • 树莓派接口
          • GPIO 接口
          • I2C 接口
          • SPI通信
          • PWM控制
          • 串口通讯
          • TF Card
          • 屏幕
          • 触摸
          • 音频
          • RTC
          • Ethernet
          • M.2
          • MINI-PCIE
          • Camera
          • WIFI&BT
          • 树莓派拓展板
        • 六、资料下载

          • 资料下载
      • M-K1HSE

        • 一、简介

          • M-K1HSE 简介
        • 二、快速开始

          • 开发环境搭建
          • 源码获取
          • 编译说明
          • 烧录指南
        • 三、应用开发

          • 00 应用开发环境搭建
          • 01 第一个应用-Hello World
        • 四、外设与接口

          • 01 Audio
          • 02 RS485
          • 03 Display
        • 五、系统定制开发

          • 系统移植
          • 系统定制
          • 驱动开发
          • 系统调试
          • OTA升级
        • 六、资料下载

          • 资料下载
    • HVS视觉融合相机

      • 快速开始

        • 01 SDK 介绍
        • 02 资料下载
        • 03 设备固件烧录
        • 04 第一个 C++ 程序
        • 05 第一个 Python 程序
        • 06 Python 数据分析
        • 07 MultiVision Studio
        • 08 版本介绍
      • 二次开发

        • 01 编程指引

          • 01 打开相机
          • 02 读取事件
          • 03 录制与回放
          • 04 事件处理
          • 05 显示与可视化
          • 06 调参
          • 07 采集 APS 图像
          • 08 帧率切换
          • 09 时间戳同步
        • 02 Toolkit SDK

          • 01 Hybrid Vision Toolkit
          • 02 快速上手
          • 03 C++ API
          • 04 Python API
        • 03 Algo SDK

          • 01 Hybrid Vision Algo
          • 02 Algo API
          • 03 Windows Algo SDK
        • 04 USB数据协议
        • 05 示例程序总览
        • 06 应用场景
      • 基础知识

        • 01 事件相机基础原理
        • 02 HVS 融合视觉
        • 03 事件可视化
        • 04 数据格式参考
        • 05 术语表
        • 06 偏置与调参
        • 07 视频教程
      • HVS 相机

        • 01 HVS 相机快速上手
        • 02 网络化能力

          • 01 HVS 相机系统架构
          • 2 EVS Network Server
          • 3 EVS Time Sync
          • 4 Web Window
        • 03 HVS 相机兼容性矩阵
        • 04 常见问题解决指南
        • 05 产品

          • CF-NRS1(灵光一号视觉融合相机)
      • HVS 模块

        • 01 MIPI 模块快速上手
        • 02 载板适配

          • RDK X5 载板适配
          • RDK S100 载板适配
          • 树莓派载板适配
          • shimetapi 板载板适配
        • 03 MIPI 模块兼容性矩阵
        • 04 产品

          • EVS_003 传感器模块
    • AI硬件

      • 1684XB-32T

        • 一、简介

          • AIBOX-1684XB-32简介
        • 二、快速上手

          • 初次使用
          • 网络配置
          • 磁盘使用
          • 内存分配
          • 风扇策略
          • 固件升级
          • 交叉编译
          • 模型量化
        • 三、应用开发

          • 开发简介

            • Sophgo SDK开发
            • SOPHON-DEMO简介
          • 大语言模型

            • 部署Llama3示例
            • Sophon LLM_api_server开发
            • 部署MiniCPM-V-2_6
            • Qwen-2-5-VL图片视频识别DEMO
            • Qwen3-chat-DEMO
            • Qwen3-Qwen Agent-MCP开发
            • Qwen3-langchain-AI Agent
          • 深度学习

            • ResNet(图像分类)
            • LPRNet(车牌识别)
            • SAM(通用图像分割基础模型)
            • YOLOv5(目标检测)
            • OpenPose(人体关键点检测)
            • PP-OCR(光学字符识别)
        • 四、资料下载

          • 资料下载
      • 1684X-416T

        • 简介

          • AIBOX-1684X-416简介
        • Demo简单操作指引

          • shimeta智慧监控demo的简单使用说明
      • RDK-X5

        • 简介

          • RDK-X5 硬件简介
        • 快速开始

          • RDK-X5 快速开始
        • 应用开发

          • AI在线模型开发

            • 实验01-接入火山引擎豆包 AI
            • 实验02-图片分析
            • 实验03-多模态视觉分析定位
            • 实验04-多模态图文比较分析
            • 实验05-多模态文档表格分析
            • 实验06-摄像头运用-AI视觉分析
          • 大语言模型

            • 实验01-语音识别
            • 实验02-语音对话
            • 实验03-多模态图片分析-语音对话
            • 实验04-多模态图片比较-语音对话
            • 实验05-多模态文档分析-语音对话
            • 实验06-多模态视觉运用-语音对话
          • ROS2基础开发

            • 实验01-搭建环境
            • 实验02-工作包的创建及编译
            • 实验03-运行 ROS2 话题通信节点
            • 实验04-ROS2 相机应用
          • 40pin-IO开发

            • 实验01-GPIO 输出(LED闪烁)
            • 实验02-GPIO 输入
            • 实验03-按键控制 LED
            • 实验04-PWM 输出
            • 实验05-串口输出
            • 实验06-IIC 实验
            • 实验07-SPI 实验
          • USB模块开发使用

            • 实验01-USB 语音模块使用
            • 实验02-声源定位模块使用
          • 机器视觉技术实战

            • 实验01-打开 USB 摄像头
            • 实验02-颜色识别检测
            • 实验03-手势识别体验
            • 实验04-YOLOv5物体检测
      • RDK-S100

        • 简介

          • RDK-S100 硬件简介
        • 快速开始

          • RDK-S100 硬件简介
        • 应用开发

          • AI在线模型开发

            • 实验01-接入火山引擎豆包 AI
            • 实验02-图片分析
            • 实验03-多模态视觉分析定位
            • 实验04-多模态图文比较分析
            • 实验05-多模态文档表格分析
            • 实验06-摄像头运用-AI视觉分析
          • 大语言模型

            • 实验01-语音识别
            • 实验02-语音对话
            • 实验03-多模态图片分析-语音对话
            • 实验04-多模态图片比较-语音对话
            • 实验05-多模态文档分析-语音对话
            • 实验06-多模态视觉运用-语音对话
          • ROS2基础开发

            • 实验01-搭建环境
            • 实验02-工作包的创建及编译
            • 实验03-运行 ROS2 话题通信节点
            • 实验04-ROS2 相机应用
          • 40pin-IO开发

            • 实验01-GPIO 输出(LED闪烁)
            • 实验02-GPIO 输入
            • 实验03-按键控制 LED
            • 实验04-PWM 输出
            • 实验05-串口输出
            • 实验06-IIC 实验
            • 实验07-SPI 实验
          • USB模块开发使用

            • 实验01-USB 语音模块使用
            • 实验02-声源定位模块使用
          • 机器视觉技术实战

            • 实验01-打开 USB 摄像头
            • 实验02-图像处理基础
            • 实验03-目标检测
            • 实验04-图像分割
      • AIBOX-M88(RK1828)

        • 一、简介

          • AIBOX-M88(RK1828) - 产品介绍
          • AIBOX-M88(RK1828) 硬件规格
          • AIBOX-M88(RK1828) 使用与安全
        • 二、快速开始

          • AIBOX-M88(RK1828) 镜像烧录
          • RK182X 硬件安装与验证
          • RK182X 开发环境快速搭建
          • RK182X SDK 总览
          • RK182X 环境搭建详解
          • RK182X 快速开始
          • 原厂 SDK 资料抽取记录
        • 三、开发指南

          • ClawChips 架构与原理
          • SKILL 使用手册
          • RK182X系列LLM推理(RK1828型号)
          • RK182X系列CNN推理(RK1828型号)
          • 模型转换
          • RK182X AI Agent 应用开发指南
          • RK182X 工业异常检测应用
        • 四、SDK 参考

          • RKNN3-SDK 概述

            • RKNN3 SDK 概述
          • RKNN3-Toolkit

            • RKNN3 Toolkit 安装与使用
          • RKLLM

            • RKLLM 设备端 LLM 推理
          • RK182X系列 NPU 概述与架构(RK1828型号)
          • RK182X INT8 量化推理部署
          • RK182X MPP 多媒体处理框架
          • MPP 详解

            • RK182X 视频解码
            • RK182X 视频编码
          • NPU 详解

            • RKNN 模型转换
            • RK182X NPU INT8 量化推理
            • RK182X 多模型并行推理
          • RGA 详解

            • RK182X RGA 2D 图形加速
          • VPU 详解

            • RK182X VPU 编解码
        • 五、硬件参考

          • RK182X系列 硬件架构概述(RK1828型号)
          • RK182X 引脚定义与复用配置
          • RK182X 引脚定义
          • RK182X 电源管理
          • RK182X 时钟与 PLL 配置
          • RK182X 时钟与频率配置
        • 六、实战教程

          • Hello World
          • Hello RK1828 - 第一个程序
          • RTSP 推流
          • RTSP 推流 + AI 分析
          • 视美泰AI龙虾一键部署
          • PaddleOCR-VL 文字识别
          • Qwen3-1.7B LLM 文本对话
          • AI 巡检多视角(Qwen3-VL 包装)
          • YOLOv5 目标检测
        • 七、资料下载

          • 资料下载
        • 八、常见问题

          • 常见问题
    • 核心板

      • C-3568BQ

        • 简介

          • C-3568BQ 简介
      • C-3588LQ

        • 简介

          • C-3588LQ 简介
      • GC-3568JBAF

        • 简介

          • GC-3568JBAF 简介
      • C-K1BA

        • 简介

          • C-K1BA 简介
    • 软件平台

      • ShiMetaPi Workbench

        • 一、产品简介

          • 产品概述
          • 核心架构
          • 功能入口
          • 支持的硬件
          • 版本说明
        • 二、快速入门

          • 安装与登录
          • 连接设备
          • 配置环境
          • 接入 AIHub
          • 首次调用模型
        • 三、用户指南

          • 工作区总览
          • 设备管理
          • 模型广场
          • 一键部署
          • 视觉 - SVP
          • 视觉 - 自定义模型
          • shimeta-py IDE
          • 终端
          • Agent 调试助手
          • 设置与资源
        • 四、常见问题

          • 安装与登录
          • 设备连接
          • 模型与部署
          • 视觉与运行时
          • 设置与其他
      • ShimetaPi软件源

        • 简介

          • ShimetaPi 软件源
        • Pico G1 (GK7206)

          • 快速开始

            • 安装与首次推理
            • shimeta_infer — 图片推理
            • shimeta_camera — 摄像头实时推理
            • SVP 场景检测
            • 文件传输与内置模型参考
            • 常见问题
          • HTTP API & Python SDK

            • HTTP API 参考
      • 模型微调训练平台

        • 一、平台介绍

          • 模型训练平台
        • 二、快速上手

          • 注册与登录
          • 创建第一个模型(30 分钟快速体验)
        • 三、训练指南

          • 数据准备与标注
          • 训练参数配置
          • 启动与监控训练
          • 模型评估与测试
        • 四、模型部署

          • 导出模型
          • 部署到边缘设备

显示框架(DRM/KMS)

文档版本: V1.0 适用系统: Linux 6.1(Debian 12 / Ubuntu 22.04) 适用硬件: RK3588(C-3588LQ V1.0 核心板 + SHIMETAPI-M5-R2A V1.0 底板) 更新日期: 2026-08-19

1. 概述

1.1 功能简介

RK3588 的显示框架建立在 Linux 内核的 DRM/KMS 子系统(Direct Rendering Manager / Kernel Mode Setting)之上。DRM/KMS 是内核里统一管理 GPU 和显示控制器的标准框架,负责帧缓冲分配、显示时序控制、图层合成和多屏管理。芯片内部的显示控制器是 VOP2(Video Output Processor v2),最多支持 4 路独立显示输出,配合 Mali-G610 MP4 GPU 完成高性能图形渲染。

和老的 Framebuffer 设备(/dev/fb*)相比,DRM/KMS 的硬件抽象能力强得多:支持 Atomic Mode Setting(原子模式设置,把所有显示参数打包成一次提交,要么全部生效、要么全部不变)、硬件 Plane 图层合成、DMA-BUF 缓冲区共享(DMA-BUF 是让多个设备共用同一块内存的机制,可以省去数据拷贝)和 DRM GEM(Graphics Execution Manager,DRM 自己的显存管理器)。现代 Linux 发行版已经全面转向 DRM/KMS,Framebuffer 只作为兼容层保留。

这块板卡上与显示相关的核心组件如下:

组件说明
VOP2 显示控制器寄存器基地址 vop@fe040000,4 路独立 Video Port
HDMI 2.1 控制器寄存器基地址 hdmi@fe0a0000,最高 8K@60fps / 4K@120fps
MIPI DSI 控制器寄存器基地址 dsi@fe060000,双通道 4-Lane MIPI DSI 2.0
Display Port 控制器寄存器基地址 dp@fe960000,DP 1.4
eDP 控制器寄存器基地址 edp@fe070000,eDP 1.4
Mali-G610 MP4GPU,支持 OpenGL ES 3.2、Vulkan 1.1
DRM/KMS 内核框架管理 CRTC、Plane、Encoder、Connector 等抽象对象

各显示接口的能力对比:

接口寄存器基地址最大分辨率协议版本物理接口
HDMIhdmi@fe0a00008K@60fps / 4K@120fpsHDMI 2.1Type-A
DPdp@fe9600008K@30fps / 4K@60fpsDP 1.4USB Type-C
MIPI DSIdsi@fe0600002.5K@60fpsMIPI DSI 2.0FPC 连接器(4-Lane)
eDPedp@fe0700004K@60fpseDP 1.4eDP 接口

1.2 应用场景

常见的几种用法,以及各自适合的显示接口:

应用场景显示接口说明
多屏异显HDMI + DP / HDMI + MIPI DSI同时输出不同内容
桌面系统HDMI + WestonLinux 桌面图形界面
数字标牌多路 HDMI广告机、信息发布系统
工业 HMIMIPI DSI / eDP工业控制触摸屏界面
视频播放HDMI + DRM Direct Show硬件解码 + DRM 直接显示
8K 大屏HDMI 2.18K@60fps 或 4K@120fps
嵌入式 GUIeDP / LVDS嵌入式设备人机交互

1.3 工作原理

先看整体架构,了解一帧画面从应用走到屏幕要经过哪些环节:

+--------------------------------------------------------------+
|                      Application Layer                        |
|       libdrm / GBM / EGL / Mali GPU / Weston / X11           |
+--------------------------------------------------------------+
|                  Kernel DRM/KMS Driver Layer                   |
|    +----------------------------------------------------+     |
|    |              VOP2 Display Controller                |     |
|    |           vop@fe040000                              |     |
|    |  +------+ +------+ +------+ +------+              |     |
|    |  | VP0  | | VP1  | | VP2  | | VP3  |              |     |
|    |  | (4K) | | (4K) | |(2K)  | |(2K)  |              |     |
|    |  +--+---+ +--+---+ +--+---+ +--+---+              |     |
|    +-----|--------|--------|--------|---------+          |
|          |        |        |        |                    |
|    +-----|--------|--------|--------|---------+          |
|    |        Encoder / Connector Layer           |        |
|    |  HDMI    DP    MIPI DSI0   MIPI DSI1  eDP |        |
|    +---------------------|---------------------+        |
+--------------------------|-----------------------------+
             +-------------+-----------+
             |       Display Device    |
             +-------------------------+

再看 DRM 设备内部的抽象对象关系。后面排查问题时,经常要对着这张图找某个 connector 或 CRTC 对应哪个硬件:

+--------------------------------------------------------------+
|                      DRM Device Node                          |
|                    /dev/dri/card0                             |
+--------------------------------------------------------------+
|                                                              |
|  Connector ------> Encoder ------> CRTC                     |
|  (Physical I/F)    (Protocol)      (Display Controller)      |
|  HDMI-A-1          dw_hdmi         VP0                       |
|  DP-1              dw_dp           VP1                       |
|  DSI-1             dw_mipi_dsi2    VP2                       |
|  DSI-2             analogix_dp     VP3                       |
|                                                              |
|  CRTC <--------- Plane (Layer)                                |
|  (VP0)           Cluster  (AFBC decode)                      |
|                  Esmart   (Hardware scaling)                  |
|                  Smart    (Basic layer)                       |
|                                                              |
|  Plane <--------- Framebuffer (Framebuffer Object)            |
|                  GEM / DMA-BUF                                |
+--------------------------------------------------------------+

图里出现的名词对照如下:

概念说明RK3588 对应
CRTC显示控制器抽象,管理显示时序和 Plane 合成VOP2 中的 Video Port
Plane硬件图层,支持多种像素格式和缩放Cluster、Esmart、Smart 三种类型
Encoder将像素数据编码为特定接口协议信号dw_hdmi、dw_dp 等
Connector物理显示接口,支持热插拔检测HDMI-A、DP、DSI 等
BridgeEncoder 与 Panel 之间的桥接设备HDMI bridge、DP bridge
Framebuffer帧缓冲对象,存储像素数据GEM 对象,支持 DMA-BUF 共享
GEMDRM 缓冲区管理与分配类似 ION / DMA-BUF heap

VOP2 提供三种硬件图层,能力各不相同,选图层时先对照下表:

Plane 类型说明AFBC 解码硬件缩放最大分辨率
Cluster高性能图层,支持 AFBC 解码支持不支持4096x2160
Esmart智能缩放图层不支持支持4096x2160
Smart基础图层不支持不支持4096x2160

Framebuffer 和 DRM 两种设备节点的差异:

对比项Framebuffer (/dev/fb*)DRM (/dev/dri/card0)
硬件抽象简单的像素缓冲区CRTC + Plane + Encoder + Connector
模式设置内核固定分辨率Atomic Mode Setting(用户态控制)
多图层不支持(单层)支持多硬件 Plane 合成
缓冲区管理mmap 直接访问GEM / DMA-BUF / GBM
热插拔不支持原生支持
GPU 合成不支持支持 EGL/Vulkan 渲染输出
用途嵌入式简单显示现代图形系统

注意:RK3588 同时支持两种模式:DRM 设备节点 /dev/dri/card0 用于 DRM/KMS 框架,Framebuffer 设备节点 /dev/fb0 用于传统兼容模式。


2. 硬件准备

2.1 硬件清单

序号组件型号/规格数量备注
1核心板C-3588LQ V1.0(660-pin LGA)1含 RK3588 SoC、4GB/8GB LPDDR4x
2底板SHIMETAPI-M5-R2A V1.01含 HDMI、DP、MIPI DSI、eDP 接口 (S-03)
3电源适配器12V/3A DC1底板 DC 输入,至少 36W
4HDMI 显示器支持 HDMI 2.0+1用于 HDMI 输出测试
5HDMI 线缆HDMI 2.0 / 2.11建议使用认证线缆
6DP 显示器(可选)支持 DP 1.41用于 DP 输出测试
7MIPI DSI 屏(可选)支持 MIPI DSI 2.0, 4-Lane1用于 DSI 输出测试
8调试串口线USB 转 TTL(3.3V)1波特率 1500000
9TF 卡或 eMMC16GB+1系统存储

2.2 显示接口引出

底板引出了下面这些显示接口(参考 S-03 底板原理图):

接口说明
HDMI TXHDMI Type-A,HDMI2.1,最高 8K@60fps
MIPI DSI0FPC 连接器,4-Lane DSI,用于连接 LCD 模组
MIPI DSI1FPC 连接器,4-Lane DSI,副屏
eDP嵌入式 DisplayPort
DisplayPortDP 1.4

注意:具体连接器编号请查阅 S-03 底板原理图,不同批次底板布局可能略有差异。

2.3 硬件确认

接好硬件、上电进入系统后,用下面的命令逐项确认显示子系统是否被内核正常接管。每条命令的预期输出写在注释里,都能对上就说明硬件这一关过了:

# 查看 DRM 设备节点
ls /sys/class/drm/
# 输出示例:card0  card0-HDMI-A-1  card0-DP-1  card0-DSI-1  version

# 查看 HDMI 连接状态
cat /sys/class/drm/card0-HDMI-A-1/status
# 输出:connected 或 disconnected

# 查看所有显示接口状态
for f in /sys/class/drm/card0-*/status; do
    echo "$(basename $(dirname $f)): $(cat $f)"
done

# 查看 VOP2 设备树状态
cat /proc/device-tree/soc/vop@fe040000/status
# 预期输出:okay

# 查看 HDMI 控制器设备树状态
cat /proc/device-tree/soc/hdmi@fe0a0000/status
# 预期输出:okay

# 查看 DSI 控制器设备树状态
cat /proc/device-tree/soc/dsi@fe060000/status

# 查看 DP 控制器设备树状态
cat /proc/device-tree/soc/dp@fe960000/status

# 查看 framebuffer 信息
ls /dev/fb*
cat /sys/class/graphics/fb0/virtual_size

# 查看 DRM 设备版本
cat /sys/class/drm/version

# 检查 Mali-G610 GPU 设备
ls /dev/dri/renderD128
cat /sys/class/misc/mali0/device/uevent

3. 软件准备

3.1 依赖安装

本章用到的测试工具和库都来自软件源,直接用 apt 安装:

# 安装 DRM 测试工具
apt-get update
apt-get install -y libdrm-tests libdrm-dev

# 安装显示相关库
apt-get install -y \
    libegl-dev libgles-dev \
    libgbm-dev \
    libwayland-dev libwayland-bin \
    weston wayland-protocols \
    xwayland

# 安装 Mesa(用户态 GPU 驱动)
apt-get install -y \
    mesa-utils libgl1-mesa-dev \
    mesa-vulkan-drivers

# 安装 edid-decode(EDID 解析工具)
apt-get install -y edid-decode

# 安装 Westo n 配置工具
apt-get install -y weston-init

# 确认 Mali-G610 GPU 驱动
# RK3588 使用 panfrost(开源)或 mali-g610(闭源)驱动
apt-get install -y libmali   # 闭源驱动(如有提供)

3.2 内核配置

自己编译内核时,需要打开以下 DRM/KMS 相关驱动配置(出厂镜像一般已经配好):

# DRM 核心框架
CONFIG_DRM=y
CONFIG_DRM_ROCKCHIP=y

# VOP2 显示控制器
CONFIG_ROCKCHIP_VOP2=y

# HDMI 2.1 输出
CONFIG_ROCKCHIP_ANALOGIX_DIGITAL=y
CONFIG_ROCKCHIP_HDMI=y
CONFIG_DRM_ROCKCHIP_ANALOGIX_HDMI=y

# MIPI DSI 输出
CONFIG_ROCKCHIP_DW_MIPI_DSI=y

# eDP 输出
CONFIG_ROCKCHIP_ANALOGIX_DP=y

# Display Port 输出
CONFIG_ROCKCHIP_DW_DP=y

# 通用 Panel 驱动
CONFIG_DRM_PANEL_SIMPLE=y

# DRM GEM / CMA 缓冲区管理
CONFIG_DRM_GEM_CMA_HELPER=y
CONFIG_DRM_CMA_HELPER=y

# Framebuffer 兼容层
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_FB=y
CONFIG_FB_ROCKCHIP=y

RK3588 使用 CONFIG_ROCKCHIP_VOP2 驱动 VOP2 显示控制器,支持 4 路独立 Video Port。

在正在运行的系统上,可以这样查看当前内核配置:

# 查看 VOP2 配置
grep -i "VOP2\|ROCKCHIP_VOP" /boot/config-$(uname -r)

# 查看 DRM 配置
grep -i "DRM_ROCKCHIP" /boot/config-$(uname -r)

# 查看 HDMI 配置
grep -i "HDMI\|ROCKCHIP_HDMI" /boot/config-$(uname -r)

# 检查已加载的 DRM 模块
lsmod | grep -i "drm\|rockchip"
# 预期看到:drm rockchip vop2 dw_hdmi 等模块

3.3 设备树配置

RK3588 VOP2 显示控制器的设备树定义:

vop2: vop@fe040000 {
    compatible = "rockchip,rk3588-vop2";
    reg = <0x0 0xfe040000 0x0 0x2000>,
          <0x0 0xfe044000 0x0 0x1000>;
    reg-names = "regs", "gamma_luts";
    interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>,
             <&cru DCLK_VOP0>, <&cru DCLK_VOP1>,
             <&cru DCLK_VOP2>, <&cru DCLK_VOP3>;
    clock-names = "aclk", "hclk",
                  "dclk_vp0", "dclk_vp1",
                  "dclk_vp2", "dclk_vp3";
    resets = <&cru SRST_A_VOP>, <&cru SRST_H_VOP>;
    reset-names = "aclk", "hclk";
    power-domains = <&power RK3588_PD_VOP>;
    iommu = <&vop2_mmu>;
    status = "disabled";
};

HDMI 控制器的设备树定义:

hdmi0: hdmi@fe0a0000 {
    compatible = "rockchip,rk3588-dp-hdmi";
    reg = <0x0 0xfe0a0000 0x0 0x20000>;
    interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cru PCLK_HDMI_TX>, <&cru CLK_HDMI_REF>,
             <&cru CLK_HDMI_TX>;
    clock-names = "pclk", "ref", "phy";
    resets = <&cru SRST_HDMI_TX>;
    reset-names = "hdmi";
    rockchip,phy = <&hdmi_phy>;
    pinctrl-names = "default";
    pinctrl-0 = <&hdmi0_tx_cec &hdmim0_tx_hpd>;
    status = "disabled";
};

MIPI DSI 控制器的设备树定义:

dsi0: dsi@fe060000 {
    compatible = "rockchip,rk3588-mipi-dsi";
    reg = <0x0 0xfe060000 0x0 0x10000>;
    interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&cru PCLK_DSI0>, <&cru CLK_DSI0_TXCLK>,
             <&cru CLK_DSI0_RXCLK>, <&cru CLK_DSI0_24M>;
    clock-names = "pclk", "txclk", "rxclk", "clk24m";
    resets = <&cru SRST_DSI0_P>,
             <&cru SRST_DSI0_TX>,
             <&cru SRST_DSI0_RX>,
             <&cru SRST_DSI0>;
    reset-names = "pclk", "tx", "rx", "dsi";
    power-domains = <&power RK3588_PD_VO1>;
    rockchip,grf = <&sysgrf>;
    status = "disabled";
};

Display Port 控制器的设备树定义:

dp: dp@fe960000 {
    compatible = "rockchip,rk3588-dp";
    reg = <0x0 0xfe960000 0x0 0x10000>;
    clocks = <&cru PCLK_DP>, <&cru CLK_DP_Ref>,
             <&cru CLK_DP_TXPHY>;
    clock-names = "pclk", "ref", "txphy";
    resets = <&cru SRST_DP_TXPHY>,
             <&cru SRST_DP>;
    reset-names = "txphy", "dp";
    rockchip,usbdpcom = <&usbdpcom>;
    status = "disabled";
};

3.4 display_subsystem 路由配置

display_subsystem 下的 route 节点决定哪个显示接口接哪个 VP。下面是启用 HDMI + MIPI DSI 双屏的路由配置:

display_subsystem: display-subsystem {
    compatible = "rockchip,display-subsystem";
    memory-region = <&drm_logo>, <&drm_cubic_lut>;
    ports = <&vop2_out>;

    route {
        route_hdmi: route-hdmi {
            status = "okay";
            logo,uboot = "logo.bmp";
            logo,kernel = "logo_kernel.bmp";
            logo,mode = "center";
            connect = <&vp0_out_hdmi>;
        };

        route_dsi0: route-dsi0 {
            status = "okay";
            logo,uboot = "logo.bmp";
            logo,kernel = "logo_kernel.bmp";
            logo,mode = "center";
            connect = <&vp1_out_dsi0>;
        };

        route_dp1: route-dp1 {
            status = "disabled";
            connect = <&vp0_out_dp>;
        };
    };
};

对应的 VP 与显示接口连接关系配置:

&hdmi0 {
    status = "okay";
};

&hdmi0_in_vp0 {
    status = "okay";
};

&hdmi0_in_vp1 {
    status = "disabled";
};

&route_hdmi {
    status = "okay";
    connect = <&vp0_out_hdmi>;
};

&dsi0 {
    status = "okay";
    rockchip,lane-rate = <1500>;
};

&route_dsi0 {
    status = "okay";
    connect = <&vp1_out_dsi0>;
};

注意:一个显示接口在同一时刻只能连接一个 VP。改板级配置时,记得把不使用的通路设为 disabled。

3.5 Weston 合成器配置

Weston 是 Wayland 的参考合成器,也就是把各个应用的画面拼成最终屏幕内容的程序。先安装:

apt-get install -y weston libwayland-dev wayland-protocols

weston.ini 基本配置:

[core]
backend=drm-backend.so
shell=desktop-shell.so

[output]
name=HDMI-A-1
mode=1920x1080-60

3.5.1 Weston 动态配置

Weston 支持通过环境变量和配置文件动态调整显示输出,不必改主配置文件:

# 环境变量
export WESTON_DRM_PRIMARY=HDMI-A-1
export WESTON_OUTPUT_FLOW=output1,eDP-1:clone,output1

# 动态配置文件
echo "[output]
name=HDMI-A-1
mode=3840x2160-60" > /tmp/.weston_drm.conf

动态配置文件 /tmp/.weston_drm.conf 在运行时被 Weston 监控,修改后自动生效,无需重启 Weston 进程。


4. 操作步骤

4.1 DRM 基础测试

先做最基础的检查:列出 DRM 资源,再用 modetest 直接点亮一块 plane。modetest 是 3.1 节安装的 libdrm-tests 自带的测试程序。命令里出现的 connector ID 和 plane ID 每台机器不一样,以自己机器上 modetest 的输出为准:

# 查看 DRM 设备信息
modetest -M rockchip -c

# 查看所有 connector 信息(包含分辨率列表)
modetest -M rockchip -c | grep -A 30 "Connectors:"

# 测试 HDMI 1080p 输出(connector ID 需根据实际 modetest 输出确定)
# 本机 connector ID = 226,plane ID = 58/83(Esmart0/1-win0)
modetest -M rockchip -s 226:1920x1080 -P 83:1920x1080

# 注意:Xorg 桌面在跑时 -s 会抢占显示(X 自动恢复),无人值守测试建议先停 lightdm

# 使用 solid color 测试平面
modetest -M rockchip -r -s 226:1920x1080 -P 83:1920x1080 -F solid

# 查看 VOP2 当前状态信息(需 root)
sudo cat /sys/kernel/debug/dri/0/state

下面的输出取自本机(modetest -M rockchip -c 摘要 + VOP state):

#0 1920x1080 60.00 1920 2008 2052 2200 1080 1084 1089 1125 148500 flags: phsync, pvsync; type: preferred, driver
#1 1920x1080 100.00 ...
#2 1920x1080 75.00 ...
...(共 32 个 mode,1080p 及以下——本机所接显示器不支持 4K)

plane[58]: Esmart0-win0
	crtc=(null)          ← 未使用
plane[83]: Esmart1-win0
	crtc=video_port1
	fb=256  allocated by = Xorg  format=XR24  size=1920x1080

结论:Xorg 正以 XR24 格式占用 Esmart1-win0 图层输出 1080p;4K 输出本机无法验证,因为所接显示器的 EDID 只报 1080p 模式。

4.2 DRM 设备节点检查

这一节检查设备节点、VOP2 时钟和 debugfs 信息。本机有两处和常见资料不一样的地方,都写在命令注释里了:出厂内核没有 fbdev 兼容层(/dev/fb* 不存在),以及 debugfs 时钟树里查不到 VOP 的时钟名,要改走 devfreq 接口:

# 查看 DRM 设备信息
ls -la /dev/dri/
# card0      - DRM 主设备节点
# renderD128 - GPU 渲染节点

# 查看 framebuffer 设备节点
ls -la /dev/fb*
#  不存在!本内核未启用 fbdev 兼容层(无 /sys/class/graphics/),
#        传统 fb 应用不可用,一律走 DRM(见 4.7)

# 查看 VOP2 时钟频率
#  debugfs 时钟树里没有 clk_dclk_vp0~3 / clk_aclk_vop 这些名字!
#       可用替代(sysfs devfreq,fdd90000.vop 即 VOP):
cat /sys/class/devfreq/fdd90000.vop/cur_freq
cat /sys/class/devfreq/fdd90000.vop/available_frequencies

# 查看 DRM debug 信息(需 root)
sudo cat /sys/kernel/debug/dri/0/name
# 输出: rockchip dev=display-subsystem unique=display-subsystem
sudo cat /sys/kernel/debug/dri/0/state
# 输出: 4 个 crtc(video_port0~3)+ plane 列表(见 4.1)

# debugfs dri/0 下的全部节点
sudo ls /sys/kernel/debug/dri/0/
# active_regs  clients  crtc-0  crtc-1  crtc-2  crtc-3
# framebuffer  gem_names  HDMI-A-1  internal_clients ...

4.3 验证 HDMI2.1 输出

验证 HDMI 输出的顺序是:先确认连接状态,再列出支持的分辨率,需要细节时读 EDID(EDID 是显示器里存的一小段数据,向主机报告自己支持的分辨率和参数):

# 查看 HDMI 连接状态
cat /sys/class/drm/card0-HDMI-A-1/status
# 应输出: connected

# 查看 HDMI 支持的分辨率
cat /sys/class/drm/card0-HDMI-A-1/modes

# 查看 EDID 信息( 需先安装 edid-decode;EDID 共 256 字节)
sudo apt install -y edid-decode
cat /sys/class/drm/card0-HDMI-A-1/edid | edid-decode

# 查询当前分辨率(X11 会话内,可用)
DISPLAY=:0 xrandr
# 输出:
# Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 16384 x 16384
# HDMI-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis)
#    1920x1080     60.00*+ 100.00    75.00    60.00    50.00    59.94
#    1920x1080i    60.00    50.00    59.94
#    1680x1050     59.88 ...
#    1280x720      60.00 ...

# 强制设置 HDMI 分辨率(显示器支持时)
DISPLAY=:0 xrandr --output HDMI-1 --mode 1920x1080 --rate 60

# 4K 输出:本机显示器 EDID 仅报 1080p 模式,4K 未验证;
# 接 4K 屏后用 xrandr --output HDMI-1 --mode 3840x2160 --rate 60

4.4 配置 MIPI DSI 输出

DSI 屏和 HDMI 显示器不一样:内核要等设备树里配置了 panel 节点之后,才会出现对应的 connector。先看连接状态:

# 查看 DSI 连接状态
#  本机出厂镜像没有 card0-DSI* connector(仅 HDMI-A-1 和 Writeback-1),
#       DSI 输出需在 DTS 挂 panel 节点后才会出现
cat /sys/class/drm/card0-DSI*/status 2>&1
# cat: '/sys/class/drm/card0-DSI*/status': 没有那个文件或目录

# 本机全部 connector:
for f in /sys/class/drm/card0-*/status; do echo -n "$f: "; cat $f; done
# /sys/class/drm/card0-HDMI-A-1/status: connected
# /sys/class/drm/card0-Writeback-1/status: unknown

# DSI 屏幕需要在设备树中配置 panel-timing
# 常见方式:在 DTS 中添加 panel 节点,如 panel-simple 或厂家自定义驱动
dmesg | grep -i panel

4.5 多屏同时显示配置

RK3588 VOP2 支持最多 4 路独立显示输出。先查所有连接器状态,再用 modetest 同时点亮两块屏(connector 和 plane ID 同样以 modetest 实际输出为准):

# 查看当前所有连接器状态
for f in /sys/class/drm/card0-*/status; do
    echo "$(dirname $f | xargs basename): $(cat $f)"
done

# 示例输出:
#   card0-HDMI-A-1: connected
#   card0-DP-1: disconnected
#   card0-DSIA: connected

# 同时启用 HDMI 和 DSI 显示(connector/plane ID 需根据 modetest 输出确定)
modetest -M rockchip \
    -s 39:1920x1080-60 \
    -s 46:1080x1920-60 \
    -P 31:1920x1080 \
    -P 49:1080x1920

4.6 Framebuffer 设备操作

先说明:本机出厂内核没有启用 fbdev 兼容层,本节命令在这块板子上跑不通,仅作传统系统参考;新开发一律走 DRM(见 4.7、4.8)。情况见命令注释:

# 查看 framebuffer 信息
#  本机无 fbdev 兼容层——/sys/class/graphics/fb0 不存在、/dev/fb* 不存在!
#       本节命令在出厂内核上全部不可用,仅作传统系统参考;新开发一律走 DRM(4.7/4.8)
cat /sys/class/graphics/fb0/virtual_size   #  No such file or directory
cat /sys/class/graphics/fb0/bits_per_pixel
cat /sys/class/graphics/fb0/stride

# 使用 fbset 修改 framebuffer 参数
fbset -fb /dev/fb0 -info
fbset -fb /dev/fb0 -g 1920 1080 1920 2160 32

如果系统里有 /dev/fb0(比如启用了兼容层的内核),可以用下面的 Python 脚本往屏幕写一张渐变测试图案:

#!/usr/bin/env python3
"""
fb_test.py - Framebuffer 测试图案写入工具
适用平台: RK3588, Linux 6.1, Debian 12/Ubuntu 22.04
"""

import struct
import os

FB_DEV = "/dev/fb0"

def get_fb_info():
    """获取 framebuffer 基本信息"""
    info = {}

    with open("/sys/class/graphics/fb0/virtual_size", "r") as f:
        size = f.read().strip()
        width, height = [int(x) for x in size.split(",")]
        info["width"] = width
        info["height"] = height

    with open("/sys/class/graphics/fb0/bits_per_pixel", "r") as f:
        info["bpp"] = int(f.read().strip())

    with open("/sys/class/graphics/fb0/stride", "r") as f:
        info["stride"] = int(f.read().strip())

    return info

def create_gradient(width, height, bpp=32):
    """创建 RGB 渐变测试图案"""
    stride = ((width * bpp + 255) >> 8) << 8
    line_size = stride // 8

    framebuffer = bytearray(line_size * height)
    for y in range(height):
        for x in range(width):
            offset = y * line_size + (x * bpp) // 8
            r = int(255 * x / width)    # X 轴红色渐变
            g = 0
            b = int(255 * y / height)   # Y 轴蓝色渐变
            a = 255
            # BGRA8888 格式(Rockchip 默认)
            struct.pack_into("<BBBB", framebuffer, offset, b, g, r, a)

    return framebuffer

def main():
    print("=" * 50)
    print("RK3588 Framebuffer 测试")
    print("=" * 50)

    # 获取 framebuffer 信息
    info = get_fb_info()
    print(f"  分辨率: {info['width']}x{info['height']}")
    print(f"  位深: {info['bpp']} bpp")
    print(f"  步长: {info['stride']} bytes")

    # 生成测试图案
    buffer = create_gradient(info["width"], info["height"], info["bpp"])

    # 写入 framebuffer
    fb = open(FB_DEV, "wb")
    fb.write(buffer)
    fb.close()

    print("  测试图案已写入")
    print("  显示器应显示红蓝渐变图案")

if __name__ == "__main__":
    main()

4.7 DRM Framebuffer 操作(C 语言)

下面是一个完整的 DRM framebuffer 示例程序:打开 /dev/dri/card0,找到一块已连接的显示器,创建纯色 dumb buffer(dumb buffer 是由内核代为分配、可以直接 mmap 写像素的简单缓冲区),再设置 CRTC 把它显示出来。编译命令在代码开头的注释里,注意必须加 -I/usr/include/libdrm,否则头文件找不到:

/*
 * drm_fb_test.c
 * RK3588 DRM/KMS framebuffer 操作示例
 *
 * 编译(必须加 -I/usr/include/libdrm,否则 xf86drm.h 内部的
 *      #include <drm.h> 找不到):
 *   gcc -o drm_fb_test drm_fb_test.c -I/usr/include/libdrm -ldrm
 * 运行: sudo ./drm_fb_test
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libdrm/drm.h>
#include <libdrm/drm_mode.h>

#define DRM_DEVICE "/dev/dri/card0"

/* DRM 设备资源结构体 */
struct drm_res {
    int fd;
    uint32_t conn_id, enc_id, crtc_id, fb_id;
    drmModeModeInfo mode;
    uint32_t width, height, pitch, handle, size;
    uint8_t *map;
};

/* 获取 DRM 设备资源 */
static int get_drm_res(struct drm_res *res)
{
    drmModeRes *resources;
    drmModeConnector *conn;
    drmModeEncoder *encoder;
    int i;

    res->fd = open(DRM_DEVICE, O_RDWR);
    if (res->fd < 0) {
        perror("open DRM device");
        return -1;
    }

    resources = drmModeGetResources(res->fd);
    if (!resources) {
        perror("get DRM resources");
        close(res->fd);
        return -1;
    }

    printf("DRM: %d connectors, %d encoders, %d CRTCs\n",
           resources->count_connectors, resources->count_encoders,
           resources->count_crtcs);

    /* 遍历 connector,找到第一个已连接的 */
    res->conn_id = 0;
    for (i = 0; i < resources->count_connectors; i++) {
        conn = drmModeGetConnector(res->fd, resources->connectors[i]);
        if (!conn)
            continue;

        if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0) {
            const char *type_name = "Unknown";
            if (conn->connector_type == DRM_MODE_CONNECTOR_HDMIA)
                type_name = "HDMI";
            else if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort)
                type_name = "DP";
            else if (conn->connector_type == DRM_MODE_CONNECTOR_DSI)
                type_name = "DSI";

            printf("Connector %d: %s, %d modes\n",
                   conn->connector_id, type_name, conn->count_modes);
            res->conn_id = conn->connector_id;
            memcpy(&res->mode, &conn->modes[0], sizeof(drmModeModeInfo));
            res->width = conn->modes[0].hdisplay;
            res->height = conn->modes[0].vdisplay;
            printf("Mode: %dx%d@%dHz\n",
                   res->width, res->height, res->mode.vrefresh);

            if (conn->encoder_id) {
                encoder = drmModeGetEncoder(res->fd, conn->encoder_id);
                if (encoder) {
                    res->enc_id = encoder->encoder_id;
                    res->crtc_id = encoder->crtc_id;
                    drmModeFreeEncoder(encoder);
                }
            }
            drmModeFreeConnector(conn);
            break;
        }
        drmModeFreeConnector(conn);
    }

    drmModeFreeResources(resources);

    if (!res->conn_id) {
        fprintf(stderr, "No connected display found\n");
        return -1;
    }
    return 0;
}

/* 创建 DRM framebuffer 并填充纯色 */
static int create_fb(struct drm_res *res, uint32_t color)
{
    struct drm_mode_create_dumb creq = {0};
    struct drm_mode_map_dumb mreq = {0};
    uint32_t i;
    uint32_t bpp = 32;

    /* 创建 dumb buffer(pitch 必须用内核返回的 creq.pitch,
       手动按 ((w*bpp+255)>>8)<<8 计算是把 bpp 当字节用,1920 宽会算出
       61696 ≠ 内核的 7680,导致 drmModeAddFB 返回 EINVAL) */
    creq.width = res->width;
    creq.height = res->height;
    creq.bpp = bpp;
    if (drmIoctl(res->fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq)) {
        perror("create dumb buffer");
        return -1;
    }
    res->pitch = creq.pitch;   /* 1920x32bpp 内核返回 7680 */
    res->handle = creq.handle;
    res->size = creq.size;

    /* 创建 framebuffer */
    if (drmModeAddFB(res->fd, res->width, res->height, 24,
                     bpp, res->pitch, res->handle, &res->fb_id)) {
        perror("add framebuffer");
        return -1;
    }
    printf("Framebuffer created: fb_id=%u, %ux%u\n",
           res->fb_id, res->width, res->height);

    /* 映射到用户空间 */
    mreq.handle = res->handle;
    if (drmIoctl(res->fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq)) {
        perror("map dumb buffer");
        return -1;
    }

    res->map = mmap(0, res->size, PROT_READ | PROT_WRITE,
                    MAP_SHARED, res->fd, mreq.offset);
    if (res->map == MAP_FAILED) {
        perror("mmap");
        return -1;
    }

    /* 填充纯色 */
    uint32_t *pixels = (uint32_t *)res->map;
    uint32_t pixel_count = (res->pitch / 4) * res->height;
    for (i = 0; i < pixel_count; i++)
        pixels[i] = color;

    return 0;
}

/* 设置 CRTC 显示模式 */
static int set_crtc(struct drm_res *res)
{
    if (!res->crtc_id) {
        /* 如果 encoder 没有绑定 CRTC,获取第一个可用的 */
        drmModeRes *r = drmModeGetResources(res->fd);
        if (r && r->count_crtcs > 0)
            res->crtc_id = r->crtcs[0];
        if (r)
            drmModeFreeResources(r);
    }

    if (drmModeSetCrtc(res->fd, res->crtc_id, res->fb_id,
                        0, 0, &res->conn_id, 1, &res->mode)) {
        perror("set crtc mode");
        return -1;
    }

    printf("CRTC %u: %ux%u@%uHz\n",
           res->crtc_id, res->width, res->height, res->mode.vrefresh);
    return 0;
}

/* 清理资源 */
static void cleanup(struct drm_res *res)
{
    if (res->map && res->map != MAP_FAILED)
        munmap(res->map, res->size);

    if (res->fb_id)
        drmModeRmFB(res->fd, res->fb_id);

    if (res->handle) {
        struct drm_mode_destroy_dumb d = {0};
        d.handle = res->handle;
        drmIoctl(res->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &d);
    }

    if (res->fd >= 0)
        close(res->fd);
}

int main(void)
{
    struct drm_res res = {0};

    printf("RK3588 DRM/KMS Framebuffer Test\n");
    printf("==============================\n\n");

    /* 获取 DRM 设备资源 */
    if (get_drm_res(&res) < 0) {
        fprintf(stderr, "Failed to get DRM resources\n");
        return 1;
    }

    /* 创建红色 framebuffer */
    printf("\nCreating framebuffer with red color (0xFF0000FF)...\n");
    if (create_fb(&res, 0xFF0000FF) < 0) {
        cleanup(&res);
        return 1;
    }

    /* 设置 CRTC 显示模式 */
    if (set_crtc(&res) < 0) {
        cleanup(&res);
        return 1;
    }

    printf("\nPress Enter to exit...\n");
    getchar();

    /* 清理资源 */
    cleanup(&res);
    printf("Done.\n");
    return 0;
}

输出(普通用户,Xorg 会话下运行):

RK3588 DRM/KMS Framebuffer Test
==============================

DRM: 1 connectors, 2 encoders, 4 CRTCs
Connector 226: HDMI, 32 modes
Mode: 1920x1080@60Hz

Creating framebuffer with red color (0xFF0000FF)...
Framebuffer created: fb_id=266, 1920x1080
CRTC 99: 1920x1080@60Hz

(普通用户与 sudo 运行均成功,本机 CRTC=99、每次运行 fb_id 递增;屏幕红色闪现后程序退出,Xorg 自动恢复)

要点:

  1. connector 226 / CRTC 99 / 2 encoders / 4 CRTCs 为本机真实 ID。
  2. 修复 pitch 前 add framebuffer: Invalid argument(原因见 create_fb 内注释)。
  3. Xorg 会话下 drmModeSetCrtc 需 DRM master:普通用户会被 Xorg 挡(-EACCES)或抢屏后 X 自动恢复;无人值守建议先 sudo systemctl stop lightdm。

4.8 Atomic Mode Setting 示例

Atomic 模式设置把所有显示参数打包成一次提交,是现代 DRM 推荐的用法。示例代码如下,编译同样需要 -I/usr/include/libdrm:

/*
 * drm_atomic_test.c
 * RK3588 DRM Atomic Mode Setting 示例
 * 展示如何使用 atomic commit 进行模式设置
 *
 * 编译(需 -I/usr/include/libdrm):
 *   gcc -o drm_atomic_test drm_atomic_test.c -I/usr/include/libdrm -ldrm
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>

#define DRM_DEVICE "/dev/dri/card0"

/*
 * Atomic commit 流程:
 * 1. 获取 DRM 资源(CRTC, Plane, Connector)
 * 2. 创建 dumb buffer -> framebuffer
 * 3. 创建 atomic request
 * 4. 设置 CRTC 属性(mode, active)
 * 5. 设置 Plane 属性(fb_id, src, dest)
 * 6. 提交 atomic commit
 */

static int atomic_set_mode(int fd, uint32_t crtc_id, uint32_t conn_id,
                           drmModeModeInfo *mode, uint32_t fb_id)
{
    drmModeAtomicReq *req;
    int ret;

    req = drmModeAtomicAlloc();
    if (!req) {
        perror("atomic alloc");
        return -1;
    }

    /* 获取 connector 和 CRTC 的 property ID
       (勘误:libdrm 2.4.114 里类型是 drmModeObjectProperties、
         函数名是 drmModeObjectGetProperties,原文的 drmModeObjectRes /
         drmModeGetObjectProperties 均不存在,编译报 unknown type name) */
    drmModeObjectProperties *obj = drmModeObjectGetProperties(fd, crtc_id,
                            DRM_MODE_OBJECT_CRTC);
    if (!obj) {
        perror("get crtc properties");
        drmModeAtomicFree(req);
        return -1;
    }

    /* 设置 CRTC active 属性 */
    for (uint32_t i = 0; i < obj->count_props; i++) {
        drmModePropertyRes *prop = drmModeGetProperty(fd, obj->props[i]);
        if (!prop) continue;

        if (strcmp(prop->name, "ACTIVE") == 0) {
            drmModeAtomicAddProperty(req, crtc_id, prop->prop_id, 1);
            printf("Set CRTC %u ACTIVE = 1\n", crtc_id);
        }

        if (strcmp(prop->name, "MODE_ID") == 0) {
            /* 创建 mode blob */
            uint32_t blob_id;
            ret = drmModeCreatePropertyBlob(fd, mode, sizeof(*mode), &blob_id);
            if (ret < 0) {
                perror("create mode blob");
                drmModeFreeProperty(prop);
                drmModeFreeObjectProperties(obj);
                drmModeAtomicFree(req);
                return -1;
            }
            drmModeAtomicAddProperty(req, crtc_id, prop->prop_id, blob_id);
            printf("Set CRTC %u MODE_ID = %u (%dx%d@%d)\n",
                   crtc_id, blob_id, mode->hdisplay,
                   mode->vdisplay, mode->vrefresh);
        }

        drmModeFreeProperty(prop);
    }
    drmModeFreeObjectProperties(obj);

    /* 提交 atomic commit */
    ret = drmModeAtomicCommit(fd, req,
                              DRM_MODE_ATOMIC_ALLOW_MODESET |
                              DRM_MODE_ATOMIC_TEST_ONLY, NULL);
    if (ret < 0) {
        fprintf(stderr, "Atomic commit test failed: %s\n", strerror(-ret));
        drmModeAtomicFree(req);
        return -1;
    }

    /* 正式提交 */
    ret = drmModeAtomicCommit(fd, req,
                              DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
    if (ret < 0) {
        fprintf(stderr, "Atomic commit failed: %s\n", strerror(-ret));
    } else {
        printf("Atomic commit succeeded\n");
    }

    drmModeAtomicFree(req);
    return ret;
}

int main(void)
{
    int fd;
    drmModeRes *resources;
    drmModeConnector *conn = NULL;
    drmModeEncoder *encoder = NULL;
    drmModeModeInfo mode;
    uint32_t crtc_id = 0;

    printf("RK3588 DRM Atomic Mode Setting Test\n\n");

    fd = open(DRM_DEVICE, O_RDWR);
    if (fd < 0) {
        perror("open DRM");
        return 1;
    }

    resources = drmModeGetResources(fd);
    if (!resources) {
        perror("get resources");
        close(fd);
        return 1;
    }

    /* 找到已连接的 connector */
    for (int i = 0; i < resources->count_connectors; i++) {
        conn = drmModeGetConnector(fd, resources->connectors[i]);
        if (conn && conn->connection == DRM_MODE_CONNECTED &&
            conn->count_modes > 0) {
            printf("Found connected display: connector %u\n", conn->connector_id);
            memcpy(&mode, &conn->modes[0], sizeof(drmModeModeInfo));
            crtc_id = resources->crtcs[0];
            break;
        }
        if (conn) drmModeFreeConnector(conn);
        conn = NULL;
    }

    if (!conn) {
        fprintf(stderr, "No connected display found\n");
        drmModeFreeResources(resources);
        close(fd);
        return 1;
    }

    printf("Using mode: %dx%d@%dHz\n",
           mode.hdisplay, mode.vdisplay, mode.vrefresh);

    /* 执行 atomic mode setting */
    atomic_set_mode(fd, crtc_id, conn->connector_id, &mode, 0);

    /* 释放资源 */
    drmModeFreeConnector(conn);
    drmModeFreeResources(resources);
    close(fd);

    printf("Done.\n");
    return 0;
}

修正类型/函数名后,普通用户与 sudo 都能运行,输出:

RK3588 DRM Atomic Mode Setting Test

Found connected display: connector 226
Using mode: 1920x1080@60Hz
Atomic commit succeeded
Done.

注意:本例的 atomic request 只设置了 CRTC 的 ACTIVE 和 MODEID,没有挂 plane(fb_id 传 0),本质是"空提交",能验证调用链但不产生可见输出;要真正上屏还需给 plane 加 FB_ID/CRTC_ID/SRC_/CRTC__ 属性。TEST_ONLY 标志先试提交再真提交的写法本身正确。

4.9 Weston/Wayland 合成器启动

Weston 装好后,既可以从命令行手动启动,也可以交给 systemd 服务管理:

# 基础启动(DRM 后端)
weston --backend=drm-backend.so &

# 或使用 weston-init 服务
systemctl start weston

# 多屏 Weston 配置文件
cat > /etc/wayland/weston.ini << 'EOF'
[core]
backend=drm-backend.so

[output]
name=HDMI-A-1
mode=3840x2160@60

[output]
name=DSIA
mode=1080x1920@60
transform=90
EOF

# 启动 Weston
weston

4.9.1 测试 Weston 显示输出

Weston 起来之后,运行下面任意一个小程序验证显示输出,屏幕上出现动画或窗口就说明 Wayland 链路通了:

# OpenGL ES 渲染测试
weston-simple-egl

# CPU 渲染测试
weston-simple-shm

# 花朵窗口演示
weston-flower

# 启动终端窗口(Wayland 协议客户端)
weston-terminal

4.10 屏幕旋转配置

旋转有三种做法,按自己使用的显示协议选一种:

# === 方式一:Weston transform 配置(推荐) ===
# 在 /etc/wayland/weston.ini 中添加:
#
# [output]
# name=DSIA
# mode=1080x1920@60
# transform=90
#
# transform 取值:
#   0 = 正常 (0°)
#   1 = 顺时针 90°
#   2 = 180°
#   3 = 逆时针 90° (即 270° 顺时针)
#   4 = 水平翻转
#   5 = 水平翻转 + 90°
#   6 = 垂直翻转
#   7 = 垂直翻转 + 90°

# === 方式二:X11 xrandr 旋转 ===
xrandr --output DSIA --rotate left

# === 方式三:DRM Plane rotation 属性 ===
# 通过 modetest 查看 plane 的 rotation 属性
modetest -M rockchip -c | grep -A 20 "Planes:"
# 然后设置 rotation 属性值

注意:旋转 90/270° 后,宽高需要交换。例如 1920x1080 旋转后变为 1080x1920。

4.11 冻屏(Freeze Display)

冻结当前显示内容,防止开机 logo 到 UI 之间的黑屏过渡:

# 冻结当前显示
cat /sys/kernel/debug/dri/0/state | grep "ACTIVE"

# 设置 Framebuffer 固定显示
echo 1 > /sys/class/graphics/fb0/blank

5. 代码详解

5.1 内核驱动结构

RK3588 DRM 显示驱动源码目录:

drivers/gpu/drm/rockchip/          # Rockchip DRM 核心驱动
drivers/gpu/drm/bridge/analogix/   # eDP 桥接驱动
drivers/gpu/drm/bridge/synopsys/   # HDMI/DP 桥接驱动
drivers/phy/rockchip/              # 物理层驱动
drivers/video/rockchip/            # Framebuffer 驱动

核心驱动文件:

模块驱动文件说明
Corerockchip_drm_drv.cDRM 驱动核心,注册 DRM 设备
Corerockchip_drm_fb.c帧缓冲管理
Corerockchip_drm_gem.cGEM 缓冲区管理
Corerockchip_drm_logo.cLogo 显示
VOP2rockchip_drm_vop2.cVOP2 显示控制器驱动
VOP2rockchip_vop2_reg.cVOP2 寄存器定义
HDMIdw_hdmi.cDesignWare HDMI 驱动
HDMIrockchip_dw_hdmi.cRockchip HDMI 封装
HDMIphy-rockchip-samsung-hdptx-hdmi.cHDMI PHY
DPdw-dp.cDesignWare DP 驱动
DPphy-rockchip-usbdp.cUSB DP PHY
MIPI DSIdw-mipi-dsi2.cDesignWare MIPI DSI 驱动
eDPanalogix_dp_core.cAnalogix eDP 驱动
Panelpanel-simple.c通用 Panel 驱动
FBfb_rockchip.c传统 Framebuffer 驱动

5.2 驱动加载流程

Kernel boot up
    |
    +-- reserved-memory: drm_logo (保留 logo 显示缓冲区)
    |
    +-- 各显示设备 probe(顺序无关,使用 deferred probe)
    |   +-- edp_probe                :component_add
    |   +-- dw_hdmi_rockchip_probe   :component_add
    |   +-- cdn_dp_probe             :component_add
    |   +-- dw_mipi_dsi2_probe       :component_add
    |   +-- vop_probe                :component_add
    |
    +-- rockchip_drm_platform_probe
    |   +-- 解析 display 节点,将显示设备加入 component
    |
    +-- rockchip_drm_bind
    |   +-- component_bind_all: 执行各子设备 bind 程序
    |       +-- vop_bind
    |       +-- rockchip_dp_bind
    |       +-- dw_hdmi_rockchip_bind
    |       +-- cdn_dp_bind
    |       +-- dw_mipi_dsi_bind
    |
    +-- show_loader_logo()
    |   +-- 解析 dts 中 logo 显示链路,将 logo 显示到对应设备
    |
    +-- rockchip_drm_fbdev_init
    |   +-- 加入 framebuffer 兼容支持(创建 /dev/fb0)
    |
    +-- DRM kernel 阶段加载完成

DRM 驱动利用了 Linux 内核的 deferred probe 机制:当某个依赖资源未就绪时,驱动返回 -EPROBE_DEFER(-517),内核稍后会重新尝试加载,直到所有依赖资源就绪。这样各显示设备的 probe 顺序就无关紧要了。

启动日志示例(正常时应能看到各显示设备陆续 bound):

[1.747198] rockchip-drm display-subsystem: bound fe040000.vop (ops vop2_component_ops)
[1.748822] rockchip-drm display-subsystem: bound fe0a0000.hdmi (ops dw_hdmi_rockchip_ops)
[1.748676] dw-hdmi-rockchip fe0a0000.hdmi: registered ddc I2C bus driver
[1.755174] dw-mipi-dsi2 : [drm:dw_mipi_dsi2_bind] *ERROR* Failed to find panel or bridge: -517
...
[2.472319] rockchip-drm display-subsystem: bound fe960000.dp (ops dw_dp_component_ops)
[2.531892] rockchip-drm display-subsystem: [drm] fb0: rockchipdrmfb frame buffer device
[2.532850] [drm] Initialized rockchip 3.0.0 20140818 for display-subsystem on minor 0

5.3 用户空间调用链

一个典型的 DRM 应用,从打开设备到画面上屏的调用链:

User Space Application (modetest / program)
  |
  +-- open("/dev/dri/card0")
  |
  +-- drmIoctl(DRM_IOCTL_GET_MAGIC)           // 获取 DRM 魔数
  |
  +-- drmIoctl(DRM_IOCTL_MODE_GETRESOURCES)   // 获取 CRTC/Connector/Encoder 资源
  |
  +-- drmIoctl(DRM_IOCTL_MODE_GETCONNECTOR)   // 获取 Connector 支持的显示模式
  |
  +-- drmIoctl(DRM_IOCTL_MODE_SETCRTC)        // 设置 CRTC 显示模式
  |   +-- vop2_crtc_enable()
  |       +-- 启动 VOP2 显示控制器
  |
  +-- drmIoctl(DRM_IOCTL_MODE_GETPlane)       // 获取可用 Plane
  |
  +-- drmIoctl(DRM_IOCTL_MODE_SETPLANE)       // 设置 Plane 显示内容
  |   +-- vop2_plane_atomic_update()
  |       +-- 向 CRTC 写入帧缓冲数据
  |
  +-- drmIoctl(DRM_IOCTL_MODE_PAGE_FLIP)      // 页面翻转
      +-- vop2_crtc_atomic_flush()
          +-- 提交显示帧

5.4 DRM/KMS 与 Framebuffer 关系

+-----------------------------------------------------------+
|                    User Space Application                   |
+-----------------+-----------------------------------------+
|  DRM Application|    Framebuffer Compatibility Layer        |
|  (modetest)     |    (/dev/fb0)                            |
+-----------------+-----------------------------------------+
|  libdrm         |    fb_rockchip.c                         |
|  GBM            |    (auto-creates fb0 device node)        |
+-----------------+-----------------------------------------+
|              DRM/KMS Kernel Framework                       |
|         /dev/dri/card0                                      |
+-----------------------------------------------------------+
|              VOP2 Display Controller                        |
|         vop@fe040000                                       |
+-----------------------------------------------------------+
|              Display Interfaces                              |
|         HDMI  DP  MIPI DSI  eDP  LVDS                     |
+-----------------------------------------------------------+

Rockchip 的 DRM 驱动在初始化时会自动创建 Framebuffer 设备节点(/dev/fb0),该节点作为 DRM 框架的兼容层存在。传统 Framebuffer 应用可以通过 /dev/fb0 直接操作,但功能受限于单图层、无硬件合成。


6. 常见问题

6.1 显示无输出

现象:连接显示器后无信号显示。

排查步骤:

# 1. 检查设备树中 VOP2 节点状态
cat /proc/device-tree/soc/vop@fe040000/status
# 应输出:okay

# 2. 检查 HDMI 节点状态
cat /proc/device-tree/soc/hdmi@fe0a0000/status
# 应输出:okay

# 3. 检查连接状态
cat /sys/class/drm/card0-HDMI-A-1/status
# 应输出:connected

# 4. 检查 VOP2 时钟
cat /sys/kernel/debug/clk/clk_dclk_vp0/clk_rate

# 5. 查看 DRM 驱动加载日志
dmesg | grep -i "rockchip-drm"

# 6. 检查设备树 route 节点
cat /proc/device-tree/soc/display-subsystem/route/route_hdmi/status
# 应输出:okay

解决方案:确认设备树中 VOP2 和对应显示接口节点 status = "okay",检查 route 节点中 connect 属性是否正确连接到对应 VP。

6.2 HDMI 未检测到

现象:连接 HDMI 线缆后,status 始终显示 disconnected。

排查步骤:

# 1. 检查 HPD(Hot Plug Detect)引脚状态
cat /sys/kernel/debug/gpio | grep HDMI

# 2. 检查 HDMI PHY 状态
cat /sys/kernel/debug/clk/clk_hdmi_ref/clk_rate

# 3. 查看 HDMI 驱动日志
dmesg | grep -i "hdmi"

# 4. 检查 EDID 读取
cat /sys/class/drm/card0-HDMI-A-1/edid | edid-decode

解决方案:检查 HPD 引脚的 pinctrl 配置是否正确,确认 HDMI PHY 时钟配置。对于不支持热插拔的显示器,可在设备树中将 HDMI connector 的 status 设置为 fixed。

6.3 分辨率不正确或显示异常

现象:显示分辨率与预期不符,或画面拉伸/压缩。

# 查看显示器支持的分辨率
cat /sys/class/drm/card0-HDMI-A-1/modes

# 使用 modetest 设置分辨率
modetest -M rockchip -s 32:1920x1080-60

# 查看当前 EDID 信息
cat /sys/class/drm/card0-HDMI-A-1/edid | edid-decode

# 查看 VOP2 当前显示时序
cat /sys/kernel/debug/dri/0/state

解决方案:检查 EDID 读取是否正常,确认 HDMI 线缆支持所需带宽。对于不支持自动协商的显示器,可在设备树中手动配置显示时序(display-timings 节点)。

6.4 Framebuffer 设备节点不存在

现象:/dev/fb0 不存在,但 /dev/dri/card0 存在。

# 检查 DRM 设备
ls -la /dev/dri/
# 应看到 card0 和 renderD128

# 检查 Framebuffer 相关配置
grep "FB_ROCKCHIP\|DRM_FBDEV_EMULATION" /boot/config-$(uname -r)

# 手动创建 framebuffer 设备节点(临时方案)
mknod /dev/fb0 c 29 0

解决方案:确认内核配置中启用了 CONFIG_DRM_FBDEV_EMULATION=y 和 CONFIG_FB_ROCKCHIP=y。DRM 驱动加载成功后会自动创建 /dev/fb0 设备节点。

6.5 DRM 设备权限不足

现象:非 root 用户无法打开 /dev/dri/card0。

# 检查设备权限
ls -la /dev/dri/card0
# 预期输出:crw-rw---- 1 root video ...

# 检查用户组
groups
# 当前用户应在 video 组中

# 添加用户到 video 组
sudo usermod -a -G video $USER

# 重新登录后生效

解决方案:确认当前用户在 video 组中,或修改 /dev/dri/card0 的设备权限。

6.6 VOP2 驱动加载失败

现象:DRM 设备节点不存在,dmesg 中有 VOP2 相关错误。

# 查看 VOP2 驱动加载日志
dmesg | grep -i "vop2\|vop"

# 检查设备树节点状态
cat /proc/device-tree/soc/vop@fe040000/status

# 检查 VOP2 时钟
cat /sys/kernel/debug/clk/clk_aclk_vop/clk_rate

# 检查 power domain
cat /sys/kernel/debug/pm_genpd/pm_genpd_summary | grep vop

解决方案:确认设备树中 vop2 节点 status = "okay",检查时钟和 power domain 配置是否正确。VOP2 驱动加载失败通常是设备树配置问题。

6.7 DRM Framebuffer 创建失败

现象:drmModeAddFB 或 drmModeAddFB2 返回 -ENOMEM 或 -EINVAL。

# 1. 检查像素格式是否支持
# RK3588 支持: DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888 等

# 2. 检查可用内存
cat /proc/meminfo | grep MemAvail

# 3. 检查 GEM handle 是否有效
# 确保 create_dumb 成功后再创建 FB

解决方案:确认使用 Rockchip 支持的像素格式(优先使用 DRM_FORMAT_XRGB8888),检查 dumb buffer 创建是否成功,确认 GEM handle 有效。

6.8 Mali-G610 GPU 驱动问题

现象:GPU 渲染节点不存在或 EGL 初始化失败。

# 检查 GPU 驱动是否加载
lsmod | grep panfrost    # 开源驱动(Linux 6.1 默认)
# 或
lsmod | grep mali        # 闭源驱动

# 检查 GPU 渲染节点
ls -la /dev/dri/renderD12*
# renderD128 -> GPU 0

# 使用 eglinfo 查看 GPU 能力
eglinfo | head -30

# 检查 Mesa 版本
glxinfo | grep "OpenGL version"

解决方案:Linux 6.1 内核默认使用 panfrost 开源驱动支持 Mali-G610 MP4。如需使用闭源驱动以获得更好性能,需安装 Arm 提供的 libmali 驱动包。

6.9 Weston 无法启动

现象:执行 weston 命令后无窗口显示或报错退出。

# 检查 DRM 设备
ls -la /dev/dri/card0

# 查看 Weston 日志
WESTON_DEBUG=1 weston 2>&1 | head -50

# 检查用户权限
groups  # 确认在 video 组中

解决方案:确认当前用户在 video 组中,DRM 设备权限正确(crw-rw---- root video)。

6.10 冻屏后画面不显示

现象:执行 echo 1 > /sys/class/graphics/fb0/blank 后画面不恢复。

# 恢复显示
echo 0 > /sys/class/graphics/fb0/blank

# 检查 fb0 状态
cat /sys/class/graphics/fb0/blank

解决方案:使用 echo 0 恢复显示,或重启 Weston 合成器重新初始化显示输出。


7. 相关文档

文档说明
Rockchip Linux 显示开发指南 (S-01)DRM/KMS 驱动开发参考
C-3588LQ 核心板规格书 (S-02)核心板硬件规格
SHIMETAPI-M5-R2A 底板原理图 (S-03)底板显示接口定义
DRM/KMS 官方文档https://docs.kernel.org/gpu/drm-internals.html
libdrm API 参考https://gitlab.freedesktop.org/mesa/drm/
Weston 合成器文档https://wayland.freedesktop.org/
03_视频编解码(MPP).mdMPP 视频编解码框架
04_音频开发与ALSA.mdALSA 音频框架
ch05-rga-image-processing.mdRGA 2D 图形加速
03_设备树详解与实践设备树配置方法
02_内核配置与裁剪内核配置方法
在 GitHub 上编辑此页
Next
摄像头应用