赞
踩
DRM,全称Direct Rending Manger。是目前Linux主流的图形显示框架。相比较传统的Framebuffer,DRM更能适应现代硬件。支持GPU、3D渲染显示等。DRM可以统一管理GPU、Display驱动,使得软件架构更统一、方便开发和维护。本文只介绍Display相关内容,GPU相关的,博主也不懂,无能为力,等以后学到相关的再来更新。
从模块上划分,DRM可以分为三个部分:libdrm、KMS、GEM。l
图1 DRM框架
1. lbdrm是DRM框架提供的、位于用户空间、操作DRM的库。应用程序调用内核里面的KMS和GEM,访问显示相关的资源。
2. KMS(Kernel Mode Setting)
KMS是DRM框架的一个大模块,主要功能是:显示参数及显示控制。
3. GEM(Graphics Execution Manager)
GEM负责DRM下的内存管理和释放。
本文只涉及KMS和GEM相关部分。使用的开发板是stm32mp157(正点原子)进行测试。系统是ubuntu18.04。
如图1,可以看到KMS主要负责显示相关功能。在DRM中,将其进行抽象,包括:
Framebuffer、CRTC,ENCODER,CONNECTOR,PLANE,VBLANK,property。他们之间的关系如图2
图2 KMS之间模块之间的功能关系
单个图层的显示内容,唯一一个与硬件无关的基本元素。
从framebuffer中读取待显示的图像,并按照响应的格式输出给encoder。其承担的主要作用为:
1).配置适合显示器的分辨率,并输出响应的时序。
2).扫描framebuffer送到一个或多个显示器
3).更新framebuffer
概括下就是,对显示器进行扫描,产生时序信号的模块、负责帧切换、电源控制、色彩调整等等。
图层,实际输出的图像是多个图层叠加而成的,比如主图层、光标图层。其中有些图层由硬件加速模块生成,每个crtc至少一个plane。plane一共有三种,分别是:DRM_PLANE_TYPE_PRIMARY、DRM_PLANE_TYPE_OVERLAY、DRM_PLANE_TYPE_CURSOR。这是配置plane的三个枚举,标注主图层、覆盖图层、光标图层(自己翻译的,跟标准翻译可能有出入)。
将一定格式的图像信号(如RGB、YUV等)编码成connector需要的输出信号。以HDMI为例,数据都是通过TMDS data的串行总线输出,编码的任务就是encoder的任务。
连接显示器的物理接口,负责硬件设备的接入、屏参获取等,如DP、HDMI等。
软、硬件同步机制,RGB时序中垂直消影区,软件通常使用硬件VSYNC实现。
任何想设置的参数都可以做成property,是DRM驱动中最灵活的部分
以HDMI接口为例说明:Soc内部一般包含一个Display模块,通过总线连接到HDMI接口上。则Display模块对应CRTC、HDMI接口对应Connector,Framebuffer对应的是显存部分。Plane是对Framebuffer进行描述的部分。Encoder是将像素转化为HDMI接口所需要的信号。一般Encoder和Connector放到一块初始化。
主要负责显示buffer的分配和释放,包括dumb、prime、fence
只支持连续物理内存,基于kernel中通用CMA API实现,多用于小分辨率简单场景。主要负责一些简单的buffer显示,可以直接使用CPU渲染,GPU不会使用dumb。
连续、非连续物理内存都支持,基于DMA-BUF机制,可以实现buffer共享,多用于大内存复杂场景。
buffer同步机制,基于内核dma_fence机制实现,用于防止显示内容出现异步问题。
st公司已经写好了DRM框架代码,位于路径:drivers\gpu\drm\stm。本次进行测试的时候,将该目录下的代码删除,参考厂家的代码重新写。设备树部分,修改compatible等代码,适合本次测试代码,仅作为学习使用。
struct drm_driver是DRM框架的核心结构体。
图3 struct drm_driver结构体
如图3,driver_features描述的是DRM支持的相关操作。
1)、DRIVER_MODESET:表示支持modesetting 操作
2)、DRIVER_GEM:表示支持GEM 操作,用于操作对内存的分配、释放
3)、DRIVER_ATOMIC:支持 Atomic 操作,用于操作各种属性
dumb_create成员是创建dumb内存。本例中对其进行重写,其他的回调函数,使用cma api。
在probe函数中,申请struct drm_device *ddev=drm_dev_alloc(&drv_driver, dev)结构体,在里面传入struct drm_driver结构体、配置KMS、注册DRM。部分代码如下:
- //配置KMS信息,
- static int my_modeset_init(struct drm_device *ddev)
- {
- struct platform_device *pdev = to_platform_device(ddev->dev);
- struct ltdc_device *ldev;
- int ret;
-
- DRM_DEBUG("%s\n", __func__);
-
- ldev = devm_kzalloc(ddev->dev, sizeof(*ldev), GFP_KERNEL);
- if (!ldev)
- return -ENOMEM;
-
- ddev->dev_private = (void *)ldev;
-
- drm_mode_config_init(ddev); //初始化drm_device
-
- /*
- * 设置最大/小宽、高值
- * 绑定framebuffer结构体,drm可以模拟fb
- */
- ddev->mode_config.min_width = 0;
- ddev->mode_config.min_height = 0;
- ddev->mode_config.max_width = MY_MAX_FB_WIDTH;
- ddev->mode_config.max_height = MY_MAX_FB_HEIGHT;
- ddev->mode_config.funcs = &drv_mode_config_funcs; //设置framebuffer的回调函数结构体
-
- ret = ltdc_load(ddev); //初始化ltdc接口,包括初始化connector和encoder一起初始化。
- //connector初始化的时候会调用drm_panel结构体离的获取屏幕参数函数
-
-
- if (ret)
- goto err;
-
- drm_mode_config_reset(ddev);
- drm_kms_helper_poll_init(ddev);
-
- platform_set_drvdata(pdev, ddev);
-
- return 0;
- err:
- drm_mode_config_cleanup(ddev);
- return ret;
- }
- //驱动的probe函数
- static int my_drm_platform_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct drm_device *ddev;
- int ret;
-
- DRM_DEBUG("%s\n", __func__);
-
- dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); //设置DMA
-
- ddev = drm_dev_alloc(&drv_driver, dev); //分配一个drm_device结构体
- if (IS_ERR(ddev))
- return PTR_ERR(ddev);
-
- ret = my_modeset_init(ddev); //初始化KMS
- if (ret)
- goto err_put;
-
- ret = drm_dev_register(ddev, 0); //注册drm
- if (ret)
- goto err_put;
-
- drm_fbdev_generic_setup(ddev, 16);
-
- return 0;
-
- err_put:
- drm_dev_put(ddev);
-
- return ret;
- }
ddev->mode_config.funcs = &drv_mode_config_funcs; //设置framebuffer的回调函数结构体
这个部分,是DRM用于模拟Framebuffer框架的代码,结构体如下:
- static const struct drm_mode_config_funcs drv_mode_config_funcs = {
- .fb_create = drm_gem_fb_create,
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = drm_atomic_helper_commit,
- };
ret = ltdc_load(ddev);代码中,对KMS中的相关功能进行完善,包括connector、encoder、plane、crtc等。代码太多了,具体的可以看后面连接放的代码。这里简单的说下大致内容。
KMS中的基本元素(CRTC,ENCODER,CONNECTOR,PLANE,Framebuffer已经在GEM中实现)均需要在DRM驱动中实现,没有硬件对应时,需要模拟出来。在DRM中,每一个部分都是使用一个结构体进行描述,需要使用对应的函数进行初始化。
注:各个Soc厂家的DRM部分设计的很多都比(互)较(相)相(抄)似(袭)。DRM框架将它们共同的代码使用xxx_funcs描述、xxx_init进行初始化,不同的部分使用xxx_helper_funcs描述、
drm_xxx_helper_add()添加。
例如:
-
- static int ltdc_plane_atomic_check(struct drm_plane *plane,
- struct drm_plane_state *state)
- {
- struct drm_framebuffer *fb = state->fb;
- struct drm_crtc_state *crtc_state;
- struct drm_rect *src = &state->src;
- struct drm_rect *dst = &state->dst;
-
- DRM_DEBUG_DRIVER("\n");
-
- if (!fb)
- return 0;
-
- /* convert src from 16:16 format */
- src->x1 = state->src_x >> 16;
- src->y1 = state->src_y >> 16;
- src->x2 = (state->src_w >> 16) + src->x1 - 1;
- src->y2 = (state->src_h >> 16) + src->y1 - 1;
- dst->x1 = state->crtc_x;
- dst->y1 = state->crtc_y;
- dst->x2 = state->crtc_w + dst->x1 - 1;
- dst->y2 = state->crtc_h + dst->y1 - 1;
-
- DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n",
- plane->base.id, fb->base.id,
- src->x2 - src->x1 + 1, src->y2 - src->y1 + 1,
- src->x1, src->y1,
- dst->x2 - dst->x1 + 1, dst->y2 - dst->y1 + 1,
- dst->x1, dst->y1);
-
- crtc_state = drm_atomic_get_existing_crtc_state(state->state,
- state->crtc);
- /* destination coordinates do not have to exceed display sizes */
- if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 ||
- crtc_state->mode.vdisplay <= dst->y2))
- return -EINVAL;
-
- /* source sizes do not have to exceed destination sizes */
- if (dst->x2 - dst->x1 < src->x2 - src->x1 ||
- dst->y2 - dst->y1 < src->y2 - src->y1)
- return -EINVAL;
-
- return 0;
- }
-
- static void ltdc_plane_atomic_update(struct drm_plane *plane,
- struct drm_plane_state *oldstate)
- {
- struct ltdc_device *ldev = plane_to_ltdc(plane);
- struct drm_plane_state *state = plane->state;
- struct drm_rect *src = &state->src;
- struct drm_rect *dst = &state->dst;
- struct drm_framebuffer *fb = state->fb;
- u32 lofs = plane->index * LAY_OFS;
- u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr;
- enum ltdc_pix_fmt pf;
- struct drm_rect dr;
-
- if (!state->crtc || !fb) {
- DRM_DEBUG_DRIVER("fb or crtc NULL");
- return;
- }
-
- /* compute final coordinates of frame buffer */
- dr.x1 = src->x1 + dst->x1;
- dr.y1 = src->y1 + dst->y1;
- dr.x2 = src->x2 + dst->x1;
- dr.y2 = src->y2 + dst->y1;
-
- bpcr = my_reg_read(ldev->regs, LTDC_BPCR);
- ahbp = (bpcr & BPCR_AHBP) >> 16;
- avbp = bpcr & BPCR_AVBP;
-
- /* Configures the horizontal start and stop position */
- val = ((dr.x2 + 1 + ahbp) << 16) + (dr.x1 + 1 + ahbp);
- my_reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs,
- LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val);
-
- /* Configures the vertical start and stop position */
- val = ((dr.y2 + 1 + avbp) << 16) + (dr.y1 + 1 + avbp);
- my_reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs,
- LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val);
-
- /* Specifies the pixel format */
- pf = to_ltdc_pixelformat(fb->format->format);
- for (val = 0; val < NB_PF; val++)
- if (ldev->caps.pix_fmt_hw[val] == pf)
- break;
-
- if (val == NB_PF) {
- DRM_ERROR("Pixel format %.4s not supported\n",
- (char *)&fb->format->format);
- val = 0; /* set by default ARGB 32 bits */
- }
- my_reg_update_bits(ldev->regs, LTDC_L1PFCR + lofs, LXPFCR_PF, val);
-
- /* Configures the color frame buffer pitch in bytes & line length */
- pitch_in_bytes = fb->pitches[0];
- line_length = fb->format->cpp[0] * (dr.x2 - dr.x1 + 1) +
- (ldev->caps.bus_width >> 3) - 1;
- val = ((pitch_in_bytes << 16) | line_length);
- my_reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs,
- LXCFBLR_CFBLL | LXCFBLR_CFBP, val);
-
- /* Specifies the constant alpha value */
- val = CONSTA_MAX;
- my_reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val);
-
- /* Specifies the blending factors */
- val = BF1_PAXCA | BF2_1PAXCA;
- if (!fb->format->has_alpha)
- val = BF1_CA | BF2_1CA;
-
- /* Manage hw-specific capabilities */
- if (ldev->caps.non_alpha_only_l1 &&
- plane->type != DRM_PLANE_TYPE_PRIMARY)
- val = BF1_PAXCA | BF2_1PAXCA;
-
- my_reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs,
- LXBFCR_BF2 | LXBFCR_BF1, val);
-
- /* Configures the frame buffer line number */
- val = dr.y2 - dr.y1 + 1;
- my_reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val);
-
- /* Sets the FB address */
- paddr = (u32)drm_fb_cma_get_gem_addr(fb, state, 0);
-
- DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr);
- my_reg_write(ldev->regs, LTDC_L1CFBAR + lofs, paddr);
-
- /* Enable layer and CLUT if needed */
- val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0;
- val |= LXCR_LEN;
- my_reg_update_bits(ldev->regs, LTDC_L1CR + lofs,
- LXCR_LEN | LXCR_CLUTEN, val);
-
- ldev->plane_fpsi[plane->index].counter++;
-
- mutex_lock(&ldev->err_lock);
- if (ldev->error_status & ISR_FUIF) {
- DRM_WARN("ltdc fifo underrun: please verify display mode\n");
- ldev->error_status &= ~ISR_FUIF;
- }
- if (ldev->error_status & ISR_TERRIF) {
- DRM_WARN("ltdc transfer error\n");
- ldev->error_status &= ~ISR_TERRIF;
- }
- mutex_unlock(&ldev->err_lock);
- }
-
- static void ltdc_plane_atomic_disable(struct drm_plane *plane,
- struct drm_plane_state *oldstate)
- {
- struct ltdc_device *ldev = plane_to_ltdc(plane);
- u32 lofs = plane->index * LAY_OFS;
-
- /* disable layer */
- my_reg_clear(ldev->regs, LTDC_L1CR + lofs, LXCR_LEN);
-
- DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n",
- oldstate->crtc->base.id, plane->base.id);
- }
-
- static void ltdc_plane_atomic_print_state(struct drm_printer *p,
- const struct drm_plane_state *state)
- {
- struct drm_plane *plane = state->plane;
- struct ltdc_device *ldev = plane_to_ltdc(plane);
- struct fps_info *fpsi = &ldev->plane_fpsi[plane->index];
- int ms_since_last;
- ktime_t now;
-
- now = ktime_get();
- ms_since_last = ktime_to_ms(ktime_sub(now, fpsi->last_timestamp));
-
- drm_printf(p, "\tuser_updates=%dfps\n",
- DIV_ROUND_CLOSEST(fpsi->counter * 1000, ms_since_last));
-
- fpsi->last_timestamp = now;
- fpsi->counter = 0;
- }
-
- static bool ltdc_plane_format_mod_supported(struct drm_plane *plane,
- u32 format,
- u64 modifier)
- {
- if (modifier == DRM_FORMAT_MOD_LINEAR)
- return true;
-
- return false;
- }
-
- static const struct drm_plane_funcs ltdc_plane_funcs = {
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane,
- .destroy = drm_plane_cleanup,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
- .atomic_print_state = ltdc_plane_atomic_print_state,
- .format_mod_supported = ltdc_plane_format_mod_supported,
- };
-
- static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = {
- .prepare_fb = drm_gem_fb_prepare_fb,
- .atomic_check = ltdc_plane_atomic_check,
- .atomic_update = ltdc_plane_atomic_update,
- .atomic_disable = ltdc_plane_atomic_disable,
- };
- //创建图层
- static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
- enum drm_plane_type type)
- {
- unsigned long possible_crtcs = CRTC_MASK;
- struct ltdc_device *ldev = ddev->dev_private;
- struct device *dev = ddev->dev;
- struct drm_plane *plane;
- unsigned int i, nb_fmt = 0;
- u32 formats[NB_PF * 2];
- u32 drm_fmt, drm_fmt_no_alpha;
- const u64 *modifiers = ltdc_format_modifiers;
- int ret;
-
- /* Get supported pixel formats NB_PF个*/
- for (i = 0; i < NB_PF; i++) { //添加支持的图层格式
-
- drm_fmt = to_drm_pixelformat(ldev->caps.pix_fmt_hw[i]);
- if (!drm_fmt)
- continue;
- formats[nb_fmt++] = drm_fmt;
-
- /* Add the no-alpha related format if any & supported */
- drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt);
- if (!drm_fmt_no_alpha)
- continue;
-
- /* Manage hw-specific capabilities */
- if (ldev->caps.non_alpha_only_l1 &&
- type != DRM_PLANE_TYPE_PRIMARY)
- continue;
-
- formats[nb_fmt++] = drm_fmt_no_alpha;
- }
ltdc_plane_create函数用于创建plane相关部分,
drm_universal_plane_init:初始化plane结构体
drm_plane_helper_add:添加helper函数
将代码放到drivers\gpu\drm\stm目录下进行覆盖(省心),重新编译内核(经过测试,修改设备树和stm目录下的代码之后,屏幕在uboot启动阶段能正常使用,在Image启动阶段无法使用,说明修改之后,内核中的DRM框架已经无法正常工作),下载Image和设备树。重新启动之后,可以在内核启动中看到这种输出字样。
[ 1.358037] panel-simple panel-rgb: panel-rgb supply power not found, using dummy regulator
有这个部分说明DRM能正常使用。
/dev/dri下是DRM生成的节点,也可以看到/dev/fb0,这个节点是DRM框架兼容FB框架产生的节点。
modetest是libdrm库编译出来产生的一个DRM测试程序,输出结果如图,可以看到KSM相关的输出。libdrm使用版本为libdrm-2.4.109。
- root@ATK-MP157:~# modetest
- trying to open device 'i915'...failed
- trying to open device 'amdgpu'...failed
- trying to open device 'radeon'...failed
- trying to open device 'nouveau'...failed
- trying to open device 'vmwgfx'...failed
- trying to open device 'omapdrm'...failed
- trying to open device 'exynos'...failed
- trying to open device 'tilcdc'...failed
- trying to open device 'msm'...failed
- trying to open device 'sti'...failed
- trying to open device 'tegra'...failed
- trying to open device 'imx-drm'...failed
- trying to open device 'rockchip'...failed
- trying to open device 'atmel-hlcdc'...failed
- trying to open device 'fsl-dcu-drm'...failed
- trying to open device 'vc4'...failed
- trying to open device 'virtio_gpu'...failed
- trying to open device 'mediatek'...failed
- trying to open device 'meson'...failed
- trying to open device 'pl111'...failed
- trying to open device 'stm'...done
- Encoders:
- id crtc type possible crtcs possible clones
- 31 35 DPI 0x00000001 0x00000000
-
- Connectors:
- id encoder status name size (mm) modes encoders
- 32 31 connected DPI-1 0x0 1 31
- modes:
- index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
- #0 1024x600 59.99 1024 1164 1184 1344 600 620 623 635 51200 flags: phsync, pvsync; type: preferred, driver
- props:
- 1 EDID:
- flags: immutable blob
- blobs:
-
- value:
- 2 DPMS:
- flags: enum
- enums: On=0 Standby=1 Suspend=2 Off=3
- value: 0
- 5 link-status:
- flags: enum
- enums: Good=0 Bad=1
- value: 0
- 6 non-desktop:
- flags: immutable range
- values: 0 1
- value: 0
- 4 TILE:
- flags: immutable blob
- blobs:
-
- value:
- 20 CRTC_ID:
- flags: object
- value: 35
-
- CRTCs:
- id fb pos size
- 35 38 (0,0) (1024x600)
- #0 1024x600 59.99 1024 1164 1184 1344 600 620 623 635 51200 flags: phsync, pvsync; type: preferred, driver
- props:
- 22 ACTIVE:
- flags: range
- values: 0 1
- value: 1
- 23 MODE_ID:
- flags: blob
- blobs:
-
- value:
- 00c8000000048c04a004400500005802
- 6c026f027b0200003c00000005000000
- 48000000313032347836303000000000
- 00000000000000000000000000000000
- 00000000
- 19 OUT_FENCE_PTR:
- flags: range
- values: 0 18446744073709551615
- value: 0
- 24 VRR_ENABLED:
- flags: range
- values: 0 1
- value: 0
- 28 GAMMA_LUT:
- flags: blob
- blobs:
-
- value:
- 29 GAMMA_LUT_SIZE:
- flags: immutable range
- values: 0 4294967295
- value: 256
-
- Planes:
- id crtc fb CRTC x,y x,y gamma size possible crtcs
- 33 35 38 0,0 0,0 0 0x00000001
- formats: AR24 XR24 RG24 RG16 AR15 XR15 AR12 XR12 C8
- props:
- 8 type:
- flags: immutable enum
- enums: Overlay=0 Primary=1 Cursor=2
- value: 1
- 17 FB_ID:
- flags: object
- value: 38
- 18 IN_FENCE_FD:
- flags: signed range
- values: -1 2147483647
- value: -1
- 20 CRTC_ID:
- flags: object
- value: 35
- 13 CRTC_X:
- flags: signed range
- values: -2147483648 2147483647
- value: 0
- 14 CRTC_Y:
- flags: signed range
- values: -2147483648 2147483647
- value: 0
- 15 CRTC_W:
- flags: range
- values: 0 2147483647
- value: 1024
- 16 CRTC_H:
- flags: range
- values: 0 2147483647
- value: 600
- 9 SRC_X:
- flags: range
- values: 0 4294967295
- value: 0
- 10 SRC_Y:
- flags: range
- values: 0 4294967295
- value: 0
- 11 SRC_W:
- flags: range
- values: 0 4294967295
- value: 67108864
- 12 SRC_H:
- flags: range
- values: 0 4294967295
- value: 39321600
- 30 IN_FORMATS:
- flags: immutable blob
- blobs:
-
- value:
- 01000000000000000900000018000000
- 01000000400000004152323458523234
- 52473234524731364152313558523135
- 41523132585231324338202000000000
- ff010000000000000000000000000000
- 0000000000000000
- in_formats blob decoded:
- AR24: LINEAR
- XR24: LINEAR
- RG24: LINEAR
- RG16: LINEAR
- AR15: LINEAR
- XR15: LINEAR
- AR12: LINEAR
- XR12: LINEAR
- C8 : LINEAR
- 36 0 0 0,0 0,0 0 0x00000001
- formats: AR24 RG24 RG16 AR15 AR12 C8
- props:
- 8 type:
- flags: immutable enum
- enums: Overlay=0 Primary=1 Cursor=2
- value: 0
- 17 FB_ID:
- flags: object
- value: 0
- 18 IN_FENCE_FD:
- flags: signed range
- values: -1 2147483647
- value: -1
- 20 CRTC_ID:
- flags: object
- value: 0
- 13 CRTC_X:
- flags: signed range
- values: -2147483648 2147483647
- value: 0
- 14 CRTC_Y:
- flags: signed range
- values: -2147483648 2147483647
- value: 0
- 15 CRTC_W:
- flags: range
- values: 0 2147483647
- value: 0
- 16 CRTC_H:
- flags: range
- values: 0 2147483647
- value: 0
- 9 SRC_X:
- flags: range
- values: 0 4294967295
- value: 0
- 10 SRC_Y:
- flags: range
- values: 0 4294967295
- value: 0
- 11 SRC_W:
- flags: range
- values: 0 4294967295
- value: 0
- 12 SRC_H:
- flags: range
- values: 0 4294967295
- value: 0
- 30 IN_FORMATS:
- flags: immutable blob
- blobs:
-
- value:
- 01000000000000000600000018000000
- 01000000300000004152323452473234
- 52473136415231354152313243382020
- 3f000000000000000000000000000000
- 0000000000000000
- in_formats blob decoded:
- AR24: LINEAR
- RG24: LINEAR
- RG16: LINEAR
- AR15: LINEAR
- AR12: LINEAR
- C8 : LINEAR
-
- Frame buffers:
- id size pitch
输入modetest -M stm -s 32@35:1024x600进行测试,可以看到输出为
其中 32为 Connectors ID、35为CRTCs ID,分辨率为1024×600。屏幕显示如图
博主自己参考libdrm库里面的例程写了一个简单的测试代码,编译之后显示如图。测试代码和DRM驱动一起放到百度云上面供学习参考。
声明:代码仅供学习参考,使用中出现的任何情况均与本人无关。
要实现一个 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()
核心是7个 objects,一切都围绕着这几个 objects 展开:
为了创建 crtc/plane/encoder/connector objects,需要调用 drm_xxx_init()。
为了创建 framebuffer object,需要实现 fb_create() callback。
为了创建 gem object,需要实现 dumb_create() callback。
为了创建 property objects,需要调用 drm_mode_config_init()。
为了让这些 objects 动起来,需要实现各种 funcs 和 helper funcs。
为了支持 atomic 操作,需要实现 atomic_commit() callback。
DRM框架是Linux内核中一个比较复杂的框架,本文只是介绍其中的一部分,并未完全介绍完,如DMA-Buf部分并未介绍,以后有时间再来更新。
百度云链接:
链接:https://pan.baidu.com/s/1zuqqy_nryNTD6YqLjazJ1w 提取码:6hgv
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。