linux drm,linux内核编译

老铁们,大家好,相信还有很多朋友对于linux drm和linux内核编译的相关问题不太懂,没关系,今天就由我来为大家分享分享linux drm以及linux内核编译的问题,文章篇幅可能偏长,希望可以帮助到大家,下面一起来看看吧!

【科普】linux驱动系列学习之DRM

DRM简介

DRM,即Direct Rendering Manager,是当前Linux系统中主流的图形显示框架。相较于传统的Framebuffer,DRM更适应现代硬件需求。它支持GPU、3D渲染显示等功能,能够统一管理GPU和Display驱动,使软件架构更统一且便于开发与维护。本文仅介绍Display相关部分,因对GPU相关知识了解有限,无法详细解释,待未来学习到相关知识后再进行补充。

DRM框架的模块划分

DRM框架主要分为三个部分:libdrm、KMS、GEM。

图1展示了DRM框架结构。其中,libdrm位于用户空间,用于操作DRM。应用程序通过调用内核中的KMS和GEM,访问显示相关的资源。

KMS(Kernel Mode Setting)模块是DRM框架的重要组成部分,主要功能包括显示参数的设置与控制。

GEM(Graphics Execution Manager)负责DRM下的内存管理和释放工作。

本文主要关注KMS和GEM相关部分,所使用的测试设备为stm32mp157(正点原子),系统为ubuntu18.04。

KMS模块概览

如图1所示,KMS模块主要负责显示相关功能。在DRM中,KMS被抽象为以下模块:

Framebuffer:单个图层的显示内容,是与硬件无关的基本元素。

CRTC:从framebuffer中读取待显示图像,并按照指定格式输出给encoder。主要功能包括:配置适合显示器的分辨率、输出响应时序、扫描framebuffer并显示在显示器上、更新framebuffer。

Plane:图层,实际输出图像为多个图层叠加,包括主图层、光标图层等。其中,主图层、覆盖图层、光标图层分别由硬件加速模块生成,每个多至少一个plane。

Encoder:将特定格式的图像信号(如RGB、YUV等)编码为connector所需的输出信号。以HDMI为例,数据通过TMDS总线输出,编码任务由encoder完成。

Connector:连接显示器的物理接口,负责设备接入、屏参获取等,包括DP、HDMI等。

Vblank:软硬件同步机制,RGB时序中的垂直消影区,软件通常通过硬件VSYNC实现。

Property:任何可设置的参数均可做成property,是DRM驱动中最灵活的部分。

以HDMI接口为例,Soc内部通常包含Display模块,通过总线连接到HDMI接口上。则Display模块对应CRTC,HDMI接口对应Connector,Framebuffer对应显存部分,Plane用于描述Framebuffer,Encoder将像素转化为HDMI接口所需的信号。通常,Encoder和Connector会在初始化时一起处理。

GEM概览

GEM主要负责显示buffer的分配和释放,包括dumb、prime、fence。

Dumb:仅支持连续物理内存,基于内核中的通用CMA API实现,适用于小分辨率和简单场景。主要用于简单的buffer显示,不涉及GPU处理。

Prime:支持连续和非连续物理内存,基于DMA-BUF机制,实现buffer共享,适用于复杂的大内存场景。

Fence:buffer同步机制,基于内核dma_fence机制实现,防止显示内容出现异步问题。

总结

实现一个DRM KMS驱动,通常需要实现以下代码和功能:

fops、drm_driver

dumb_create、fb_create、atomic_commit

drm_xxx_funcs、drm_xxx_helper_funcs

drm_xxx_init()、drm_xxx_helper_add()

drm_dev_init()、drm_dev_register()

核心围绕七个objects展开,实现这些objects的创建与操作是关键。

DRM框架在Linux内核中相对复杂,本文仅介绍部分功能,并未涵盖所有内容,如DMA-Buf等部分未涉及,将视情况在后续更新。

Linux DRM原理及应用

Linux DRM(Direct Rendering Manager)起源于一个为视频数据从camera传递到display提供数据传输管理的框架。它通过libdrm这个用户空间与内核的中间层,简化了应用程序对驱动的操作。

DRM系统主要包含三个关键模块:libdrm、GEM(Graphic Execution Manager)和KMS(Kernel Mode Setting)。libdrm作为用户空间与内核的桥梁,处理应用程序与内核之间的交互,通过ioctl调用传递数据结构给内核,再将处理后的结果返回给应用程序。GEM主要负责图形缓冲区的操作,而KMS负责设置显示参数,如分辨率、刷新率,以及控制画面切换等。

以HDMI Monitor显示为例,流程包括:HDMI驱动检测到电视信号,读取EDID获取分辨率信息(DRM Connector)。应用程序填充显示数据到framebuffer,通过libdrm通知VOP设备进行显示。VOP驱动将数据转换为LCDC Timing,而HDMI驱动调整硬件以匹配VOP输出。Encoder负责将LCDC Timing转换为TMDS信号,以适应电视。

应用程序调用libdrm的顺序通常为:先找到Connector,再找到与之相连的Encoder,接着是CRTC,最后是Plane。在循环中,可能需要在2步中释放资源,但1步的初始化资源不能释放。然而,如果在某些情况下错误地释放了正在使用的framebuffer(fb),可能导致显示问题,甚至需要在内核启用CONFIG_DRM_FBDEV_EMULATION时,通过drmModeSetCrtc()函数手动重置CRTC,否则可能需要重启程序。

libdrm与内核的交互涉及参数填充,如alloc_arg.handle, alloc_arg.pitch和alloc_arg.size,以及mmap_arg.offset。这些信息会被传递给v4l2插件,用于相机数据输入。值得注意的是,crtc_id和fb_id不是指针,意味着每个plane只能对应单一的fb_id和crtc_id。

最后,DMA-buf机制在DRM中也扮演重要角色,如exporter申请的DMA buffer与文件描述符fd关联,确保相机数据的顺利输入。

Linux内核中断之中断调用流程

本文基于 RockPI 4A单板Linux4.4内核介绍中断调用流程。

ARMv8包括两种运行状态:AArch64和AArch32。

AArch64中不再使用AArch32中的7种特权模式,而是提出了Exception Levels的概念,包括:

1)EL0:用于用户态程序,权限最低

2)EL1:给内核使用,权限稍高

3)EL2:虚拟化相关,权限更高

4)EL3:安全相关,权限最高

Linux内核中一般只使用EL0和EL1。

AArch64异常向量表中的异常包括:

1)Synchronous exception(同步异常)

2)SError

3)IRQ

4)FIQ

注:SError、IRQ和FIQ属于异步异常。

在Linux内核中,在 arch/arm64/kernel/entry.S文件中定义了异常向量表,内容如下:

选取 el1_irq()函数介绍Linux内核中断的调用流程。

文件: arch/arm64/kernel/entry.S,调用流程如下:

1、handle_irq()初始化

在 DTS解析阶段完成 handle_irq()函数的初始化,流程如下:

gic_irq_domain_map()函数中完成了 handle_irq()函数的赋值,具体执行如下:

2、handle_irq()实现

以共享外设中断 SPI的中断处理函数 handle_fasteoi_irq()为例,继续跟踪中断的执行过程。

handle_irq_event_percpu()函数会调用已经注册的中断处理函数,同时唤醒 irq_thread线程。

3、中断处理线程

在使用 request_threaded_irq()函数申请中断时,会创建一个 irq_thread线程,调用流程如下:

irq_thread线程平时在睡眠状态,等待 handle_irq_event_percpu()函数唤醒,进一步执行已注册的中断处理线程函数。

使用 DRM框架中 HDMI中断验证中断调用流程。

文件: drivers\gpu\drm\bridge\synopsys\dw-hdmi.c

在中断处理函数 dw_hdmi_hardirq()和中断处理线程函数 dw_hdmi_irq中增加 dump_stack()调用(注:仅限于调试验证)。

插入 HDMI线,系统启动后,显示中断调用流程的日志如下:

阅读剩余
THE END