7. DRM图形显示框架¶
以往我们在Linux上为显示设备开发驱动时,通常使用的是FrameBuffer的驱动框架, 在FrameBuffer驱动框架下,我们能够快速开发出可供简单使用的显示驱动。 但是随着芯片显示外设的性能逐渐增强及GPU的引入,FrameBuffer框架看起来似乎就有些落伍了, 最直接的体现,就是在传统的框架下,对于许多芯片显示外设的新特性如: 显示覆盖(菜单层级)、GPU加速、硬件光标等功能并不能得到很好得支持, 并且FrameBuffer框架将底层的显存通过用户空间/dev/fb接口,暴露给了用户空间, 这很容易导致不同的应用程序在操作显存时,产生访问冲突,而且这种方式看起来似乎不是那么安全。
在这背景下,就需要一个现代的图形显示框架来解决这些问题,那么DRM(Direct Rendering Manager,直接图形管理器)诞生。
7.1. 框架简述¶
那么DRM图形显示框架是怎么解决FrameBuffer框架遇到的困境呢? DRM将现代显示领域中会涉及的一些操作进行分层并使这些模块独立, 如过上层应用想操作显存、显示效果抑或是GPU,都必须在一些框架的约束下进行,我们可以来了解一下。
我们可以从用户空间、内核空间的两个角度去了解DRM框架:
用户空间(libdrm driver):
Libdrm(DRM框架在用户空间的Lib)
内核空间(DRM driver):
KMS(Kernel Mode Setting,内核显示模式设置)
GEM(Graphic Execution Manager,图形执行管理器)
7.1.1. Libdrm¶
DRM框架在用户空间提供的Lib,用户或应用程序在用户空间调用libdrm提供的库函数, 即可访问到显示的资源,并对显示资源进行管理和使用。
这样通过libdrm对显示资源进行统一访问,libdrm将命令传递到内核最终由DRM驱动接管各应用的请求并处理, 可以有效避免访问冲突。
7.1.2. KMS(Kernel Mode Setting)¶
KMS属于DRM框架下的一个大模块,主要负责两个功能:显示参数及显示控制。 这两个基本功能可以说是显示驱动必须基本的能力,在DRM框架下, 为了将这两部分适配得符合现代显示设备逻辑,又分出了几部分子模块配合框架。
7.1.2.1. Planes¶
基本的显示控制单位,每个图像拥有一个Planes,Planes的属性控制着图像的显示区域、图像翻转、色彩混合方式等, 最终图像经过Planes并通过CRTC组件,得到多个图像的混合显示或单独显示的等等功能。
7.1.2.2. CRTC¶
CRTC的工作,就是负责把要显示图像,转化为底层硬件层面上的具体时序要求,还负责着帧切换、电源控制、色彩调整等等。
7.1.2.3. Encoder¶
Encoder的工作则是负责电源管理、视频输出格式封装(比如要将视频输出到HDMI接口、MIPI接口等)。
7.1.2.4. Connector¶
Connector连接器负责硬件设备的接入、屏参获取等。
上述的这些组件,最终完成了一个完整的DRM显示控制过程,如下图所示:
参考资料 Kernel Mode Setting (KMS) .
7.1.3. GEM(generic DRM memory-management)¶
顾名思义,GEM负责对DRM使用的内存(如显存)进行管理。
GEM框架提供的功能包括:
内存分配和释放
命令执行
执行命令时的管理
7.2. 驱动简述¶
我们通过简单讲解了DRM驱动的框架,简单地带领大家认识了DRM框架下对显示功能的实现方法。
实际的代码细节远比上述给大家介绍的内容复杂得多,给大家讲解框架组件功能只是起到一个抛砖引玉的作用,
如果对代码细节感兴趣的同学,可以在目录 drivers/gpu/drm
中,查看具体的驱动实现。
在实际的使用中,我这里将DRM的驱动实现分为了两个部分,主机驱动和设备驱动。主机驱动指的是片上的负责显示功能的外设驱动,如MP157上的LTDC外设、DSI外设的驱动,
这些一般由芯片厂商如ST、NXP等来负责实现,完成一个DRM-Host,主机驱动代码一般位于 drivers/gpu/drm/xxx/
目录下,这里xxx代指芯片厂商如ST、NXP。
一般我们要做的,就是现实一个设备驱动,比如针对某款LCD显示屏, 将其参数(LCD Timing、Size…)、显示方式(DSI、HDMI…)等通过设备驱动,和主机驱动关联起来。
在内核的DRM驱动目录中,给出了许多设备驱动的示例,详见目录: drivers/gpu/drm/panel
.
一个简单的DRM框架显示设备驱动例子可以参考 drivers/gpu/drm/panel/panel-simple.c
.
7.3. 设备树插件描述¶
MP157开发板支持两种接口的LCD显示屏:RGB(MIPI DPI)、MIPI DSI,由于显示原理不同,所以分别对应着两款设备树插件, 使用的也是不同的设备驱动,但是其驱动框架仍是DRM。
重要
两种接口RGB、DSI屏幕不可同时使用!
既然作为显示设备,那么设备树上描述的属性必然是和显示屏相关的内容,
比如:屏幕的display timing、ddc读取显示器EDID结构等,
详见及参考内核 Documentation/devicetree/bindings/display/panel
目录下的各种dt-bingdings,如:
通用的bingdings文档:
Documentation/devicetree/bindings/display/panel/panel-common.txt
Documentation/devicetree/bindings/display/panel/panel-dpi.txt
Documentation/devicetree/bindings/display/panel/panel-dsi-cm.txt
各种实例显示设备的bingdings文档。
各种的bingdings文档,可以帮助你快速了解一个设备树里描述的属性内容,及如何去写一个对应的设备树节点。
这里再补充一些知识,MIPI联盟提出了许多显示规范,有:DBI(Display Bus Interface带控制器及显存的并行接口显示模块)、 DPI(Display Pixel Interface不带控制器或显存的并行接口显示模块)、DSI(Display Serial Interface高速串行接口)、 DCS(Display Command Set用显示命令集操作的显示模块)。我们常说的RGB接口屏幕,也就是不带控制器及显存的并行接口屏幕,DBI的代表则有80接口MCU屏, 至于DSI则是串行接口屏幕了,手机中常用的就是DSI接口屏幕。
参考资料: MIPI Specifications .
7.3.1. RGB-LCD设备树插件¶
设备树插件的源码非常长,此处不便展示,源码位于如下目录:
arch/arm/boot/dts/overlays/stm-fire-lcd-overlay.dts
其驱动目录对应为:
drivers/gpu/drm/panel/panel-simple.c
7.3.2. DSI-LCD设备树插件¶
源码位于如下目录:
arch/arm/boot/dts/overlays/stm-fire-mipi-overlay.dts
其驱动目录对应为:
drivers/gpu/drm/panel/panel-himax-hx8394.c
7.4. 实验准备¶
下面我们就以野火的4.3寸RGB屏幕为例,为大家测试在DRM驱动框架下的驱动效果,我们进行屏幕的测试。
7.4.1. 添加设备树插件¶
方法参考如下:
重要
如果使用DSI屏幕,请将 stm-fire-lcd.dtbo
及 stm-fire-mipi.dtbo
设备树插件同时打开。
若使用RGB屏幕,则只将 stm-fire-lcd.dtbo
打开。
以野火的4.3寸RGB屏幕为例,操作如下:
如需调整屏幕参数,请使用fire-config工具调整,参考:
如若运行代码时出现“Device or resource busy”或者运行代码卡死等等现象, 请按上述情况检查并按上述步骤操作。
如出现 Permission denied
或类似字样,请注意用户权限,大部分操作硬件外设的功能,几乎都需要root用户权限,简单的解决方案是在执行语句前加入sudo或以root用户运行程序。
7.4.2. libdrm测试程序¶
野火MP157开发板中,DRM驱动默认被配置为编译进内核,驱动加载后,会在 /dev/dri/
目录下创建显示设备的节点,
我们的应用程序就是通过open这些节点,调用libdrm的API去进行LCD控制和显示的。
如下图,我们的RGB显示屏即为 /dev/dri/card0
节点.
编写一个libdrm的测试程序较为复杂,这里我们使用libdrm官方的测试工具来进行测试,我们可以在这里下载源码并进行交叉编译出测试工具,以供在开发板上使用: libdrm .
新版的libdrm使用meson+ninja的构建方式,而不是老版的autotools,没有基础的同学构建新版libdrm会比较痛苦。 建议直接使用我们给大家编译好的测试程序,测试程序位于\linux_driver\framework_drm\modetest。
对libdrm测试程序感兴趣的同学,可以下载libdrm源码解压,在其目录/libdrm-2.4.105/tests/下,查看modetest.c文件,此为测试程序源码。
7.5. 实验操作¶
将上述的modetest测试程序上传至开发板中,并使用chmod添加执行权限。
运行modetest程序,点击图片可放大:
待程序检测执行完毕,会列举出开发板上的DRM框架下的显示设备。
其中一些字样如Encoders、Connectors、CRTCs经过前面的介绍,大家都应该有了一点印象。
DRM框架下的显示过程如下图示:
我们要做的,就是找出前面终端中打印的RGB屏幕对应的connectors、CRTCs的ID:
图中状态为connected的connectorsID为31,并且从name中可以看出为DPI接口的屏幕,正是我们的RGB屏。 CRTCs对象中,唯一个id为34的CRTC,参数也为我们的RGB屏幕参数。
则我们可以执行如下命令进行测试:
./modetest -M stm -s 31@34:480x272
其中31、34分别为我们屏幕的Connectors ID、CRTCs ID,实验现象如图示:
在终端中按下回车键退出测试。
关于测试的更多相关内容,可以参考 linux DRM/KMS 测试工具 modetest .
文章末尾补充小知识,虽说DRM功能符合现代显示设备的需求,但是仍有众多的老设备及软件需要Framebuffer的支持。 所以在DRM框架下,有部分代码用于实现在DRM框架下,去模拟FB设备。
在ST提供的显示驱动代码中,也有模拟FB设备的相关代码,参见drivers/gpu/drm/stm/drv.c文件,
最终效果就是设备目录下,出现熟悉的身影 /dev/fb0
。
我们可以通过传统测试FrameBuffer设备的方式,使用如下命令来测试它:
# 会得到类似花屏的效果
cat /dev/random > /dev/fb0
相关新闻可以查看 Generic-FBDEV-Emulation .