Linux驱动开发系列:DRM(第十部分)

2023-05-16

https://www.iotword.com/7227.html

一、DRM简介

        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。

二、KMS

        如图1,可以看到KMS主要负责显示相关功能。在DRM中,将其进行抽象,包括:

Framebuffer、CRTC,ENCODER,CONNECTOR,PLANE,VBLANK,property。他们之间的关系如图2

 图2 KMS之间模块之间的功能关系

 1、Framebuffer:

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

2、CRTC:

        从framebuffer中读取待显示的图像,并按照响应的格式输出给encoder。其承担的主要作用为:
          1).配置适合显示器的分辨率,并输出响应的时序。
          2).扫描framebuffer送到一个或多个显示器
          3).更新framebuffer

概括下就是,对显示器进行扫描,产生时序信号的模块、负责帧切换、电源控制、色彩调整等等。

3、Plane:

        图层,实际输出的图像是多个图层叠加而成的,比如主图层、光标图层。其中有些图层由硬件加速模块生成,每个crtc至少一个plane。plane一共有三种,分别是:DRM_PLANE_TYPE_PRIMARY、DRM_PLANE_TYPE_OVERLAY、DRM_PLANE_TYPE_CURSOR。这是配置plane的三个枚举,标注主图层、覆盖图层、光标图层(自己翻译的,跟标准翻译可能有出入)。

4、Encoder:

        将一定格式的图像信号(如RGB、YUV等)编码成connector需要的输出信号。以HDMI为例,数据都是通过TMDS data的串行总线输出,编码的任务就是encoder的任务。

5、Connector:

        连接显示器的物理接口,负责硬件设备的接入、屏参获取等,如DP、HDMI等。

6、Vblank:

        软、硬件同步机制,RGB时序中垂直消影区,软件通常使用硬件VSYNC实现。

7、Property:

        任何想设置的参数都可以做成property,是DRM驱动中最灵活的部分

        以HDMI接口为例说明:Soc内部一般包含一个Display模块,通过总线连接到HDMI接口上。则Display模块对应CRTC、HDMI接口对应Connector,Framebuffer对应的是显存部分。Plane是对Framebuffer进行描述的部分。Encoder是将像素转化为HDMI接口所需要的信号。一般Encoder和Connector放到一块初始化。

三、GEM

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

1、Dumb:

        只支持连续物理内存,基于kernel中通用CMA API实现,多用于小分辨率简单场景。主要负责一些简单的buffer显示,可以直接使用CPU渲染,GPU不会使用dumb。

2、Prime:

        连续、非连续物理内存都支持,基于DMA-BUF机制,可以实现buffer共享,多用于大内存复杂场景。

3、Fence:

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

四、部分代码介绍

        st公司已经写好了DRM框架代码,位于路径:drivers\gpu\drm\stm。本次进行测试的时候,将该目录下的代码删除,参考厂家的代码重新写。设备树部分,修改compatible等代码,适合本次测试代码,仅作为学习使用。

 1、struct drm_driver结构体

        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。

2、probe函数

        在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()添加。

  1. xxx_funcs 必须有,xxx_helper_funcs 可以没有。
  2. drm_xxx_init() 必须有,drm_xxx_helper_add() 可以没有。
  3. 只有当 xxx_funcs 采用 DRM 标准的 helper 函数实现时,才有可能 需要定义 xxx_helper_funcs 接口。
  4. xxx_funcs.destroy() 接口必须实现

例如:


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;
}</code></pre>

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能正常使用。

1、查看/dev/dri

 /dev/dri下是DRM生成的节点,也可以看到/dev/fb0,这个节点是DRM框架兼容FB框架产生的节点。

2、modetest

        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:1024×600进行测试,可以看到输出为

其中 32为 Connectors ID、35为CRTCs ID,分辨率为1024×600。屏幕显示如图

 3、使用libdrm测试

        博主自己参考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 
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux驱动开发系列:DRM(第十部分) 的相关文章

  • C++中“.“,“->“,“:“和“::“的区别

    在 C 43 43 中 xff0c 34 34 xff0c 34 gt 34 xff0c 34 34 和 34 34 都是运算符 xff0c 它们的作用是明显不同的 xff0c 但是初学者很容易被其迷惑 1 34 34 是成员访问运算符 x
  • ubuntu系统中忘记root密码的解决办法

    1 启动ubuntu按shift进入grub菜单 xff1b 2 选择recovery mode进入Recovery Menu界面 xff0c 选择root Drop to root shell prompt 3 修改root密码操作 xf
  • C++语言实现哈希表中的线性探测法和平方探测法

    哈希表 xff08 Hash表 xff09 xff0c 也称为散列表 xff0c 是一种数据结构 xff0c 通过使用哈希函数将键映射到数组的特定位置来实现高效的查找 插入和删除操作 哈希函数将键转换为一个整数 xff0c 这个整数对应数组
  • C++实现的二叉树前序遍历函数

    include lt iostream gt using namespace std struct TreeNode int val TreeNode left TreeNode right TreeNode int x val x lef
  • c语言和c++实现层序遍历

    层序遍历是一种二叉树的遍历方式 xff0c 也称为广度优先遍历 xff0c 它的遍历顺序是 xff1a 从上到下 xff0c 从左到右 xff0c 一层一层地遍历整棵树 在 C 语言中 xff0c 我们可以使用队列来实现层序遍历 具体实现步
  • C语言获取wifi状态

    mark https blog csdn net dongyoubin article details 122134198 int getWirelessStatus char ath char ssid char ipAddr
  • 最全Visual Studio版本号对应表VisualStudioVersion

    名字 版本号 简称 全称 msvc70 VC7 0 VS2002 Microsoft Visual Studio 2002 msvc71 VC7 1 VS2003 Microsoft Visual Studio 2003 msvc80 VC
  • 二叉树静态实现的示例代码

    使用指针对于初学者容易出现很多困惑 下面是一个完整的二叉树静态实现的示例代码 xff0c 包括初始化 插入节点 各种遍历方法以及一些辅助函数 include lt stdio h gt include lt stdlib h gt defi
  • 广度优先搜索(BFS)算法实现二叉树层序遍历的 C++ 代码

    include lt iostream gt 输入输出流 include lt vector gt 向量容器 include lt queue gt 队列容器 using namespace std 命名空间 定义二叉树节点结构体 stru
  • PAT 1005 Spell It Right

    Given a non negative integer N your task is to compute the sum of all the digits of N and output every digit of the sum
  • 在PC的Ubuntu虚拟机上完成一个TCP 服务器,在设备上实现一个TCP客户端

    要求 在虚拟机上实现一个服务器 xff0c 设备终端上实现一个客户端设备客户端每隔 1 秒 检测一次网卡eth2 1 xff08 WAN口网卡 xff09 的信息 xff08 使用popen调用ifconfig xff09 然后将RX和TX
  • TCP发送数据、接受数据及TCP通信程序练习

    目录 一 TCP发送数据 二 TCP接收数据 三 TCP通信程序练习 一 TCP发送数据 Java中的TCP通信 xff1a Java对于基于TCP协议的网络提供了良好的封装 xff0c 使用Socket对象来代表两端的通信端口 xff0c
  • slam学习笔记

    ubuntu20 04 使用vs code编写 现放cmake文件 xff08 记得链接库文件和配置C 43 43 版本 xff09 cmake minimum required VERSION 2 8 project learingMat
  • SLAM学习笔记

    编译环境ubuntu20 04 vs code xff08 李群 李代数 xff09 先是CMakeLists txt cmake minimum required VERSION 3 0 project learning sophus s
  • SLAM学习笔记

    编译环境ubuntu20 04 xff0c vs code 先cmake文件 cmake minimum required VERSION 2 8 project image set CMAKE BUILD TYPE 34 Release
  • SLAM学习笔记

    编译环境ubuntu20 04 vscode ceres库2 0 0 g2o库同gaoxiang12 slambook2中的版本号一致 cmake文件 cmake minimum required VERSION 2 8 project c
  • 数据结构之C语言单链表操作

    实验目的 xff1a 1 xff0e 创建一个带头结点的单链表 2 xff0e 插入元素操作 xff1a 将新元素x插入到单链表head的头部 将新元素x插入到单链表head的尾部 将新元素x插入到单链表head中第i个元素之后 3 xff
  • DBUS入门与C编程

    https blog csdn net weixin 45566765 article details 125028296 一 D Bus简介 1 D Bus是什么 D Bus最主要的用途是在 Linux 桌面环境为进程提供通信 xff0c
  • 模拟IIC——关于模拟IIC的IO口的配置选取推挽输出还是开漏输出,以及是否需要更改IO口输入输出模式和是否需要对IO配置上拉

    在使用模拟IIC的时候 xff0c 观看别人的程序的时候发现了程序之间的一些不一样的地方 代码1 IO方向设置 define SDA IN GPIOB gt MODER amp 61 3 lt lt 9 2 GPIOB gt MODER 6
  • C语言——链表

    C语言 链表 链表是一种基础的数据结构类型 xff0c 一种能够动态维护数据的线性数据表 链表的数据以结点形式存储信息 xff0c 并通过结点之间的指针实现结点之间的衔接 为什么要用链表 xff1f 链表和数组类似 xff0c 但是功能比数

随机推荐

  • 学习记录 | ZigBee协议栈工作流程

    第一次来CSDN记录一下学习过程 xff0c 其实就是笔记啦 之前用Typora 的 但前几天电脑出问题重装系统后打开笔记文件发现照片都打不开了 xff0c 索性想换一种记笔记方式 好啦 以下是正文 xff01 xff01 xff01 对了
  • 学习记录 | ZigBee协议栈实践——串口收发数据

    上次的理论知识学的有点杂乱 今天来跟着例程实践看一看 目录 一 ZigBee协议栈的安装 编译和下载 二 协议栈工作流程 三 串口通信主要代码 1 串口打印 2 串口打印收到的数据 四 实现 五 总结 一 ZigBee协议栈的安装 编译和下
  • 第一次画异形板后的总结感悟

    目录 画原理图前的准备 画PCB的一些好方法 蜂鸣器电路 供电电路 其他电路 杂七杂八的随记要点 总结 像这样的异形板是通过solidworks扫描实物生成的 画原理图前的准备 当然是选购元器件 一般习惯在嘉立创进行选购 选择符合要求 有库
  • 自学物联网ESP第一天

    先简单的使用串口通信AT指令 刚开始不知道用什么开发好 在博客找了很久本来打算用 eclipse 不过突然发现可以用Arduino 不过下载真的好慢 于是开始看一下函数准备一下 一 基本函数 1 setup 函数 Arduino控制器通电或
  • stm32串口发送+接收

    本文章转自B站江科大自化协 一发送 接线图 目标结构 Serial c include 34 stm32f10x h 34 include lt stdio h gt 1移植printf函数 封装sprintf include lt std
  • vscode配置C/C++环境(超详细保姆级教学)

    大一上学期被学长安利了vscode xff0c 但是下载安装后不会配置 xff0c 自己连查带问搞了七八个小时终于配置好了 后面身边很多同学也不会配 xff0c 都来找我帮忙配 xff0c 加上之前自己摸索着配的时候感觉网上没有详细又靠谱的
  • 路由器接口解析

    ensp 接口解析 路由器的CON和AUX con是串口 xff0c 接口电脑串口可以进路由器的命令行查看和设置 一般为设备的控制端口 xff0c Console端口使用配置专用连线直接连接至计算机的串口 xff0c 利用终端仿真程序进行路
  • 解决VSCode写html文件时<!+Enter导入模板快捷键没办法使用的问题

    好久没有写前端了 xff0c 先是用模板快捷键 lt 43 Enter导入模板 xff0c 发现没有办法使用 找到网上一些资料 xff0c VSCode使用 html 5 取代了之前的生成模板快捷键 示例 xff1a 在空白html文本里逐
  • LVGL 之 windows 上 lvgl 模拟器 基于 Visual Studio 搭建方法的简单整理

    mark GUI Guider与lvgl联合仿真 xff08 结合stm32实验进行演示 xff0c 含触摸屏实验计数器与计算器 xff09 https blog csdn net gudao07 article details 12752
  • 初认识stm32 ————每日小总结(串口通信初始化基础操作)

    留下代码 xff0c 日后复习 c文件 include 34 my uart h 34 void my uart init NVIC PriorityGroupConfig NVIC PriorityGroup 2 设置中断优先级分组 RC
  • Sqoop全量导入mysql表数据到HDFS

    我是在三个节点运行的 xff0c 主节点只有namenode和mysql数据库 1 开启服务 具有NameNode和DataNode start all sh 2 进入sqoop的目录下并且输入代码 下面的命令用于从 MySQL 数据库服务
  • 在字符串中查找子字符串

    查找子串 include lt stdio h gt char Search char str1 char str2 char s1 61 str1 char s2 61 str2 char cur 61 str1 while cur s1
  • 基于相机云台周期运动的“远帧差”图像处理算法

    传统的帧差法针对前后两帧或者某几帧进行图像处理 xff0c 一旦相机视角转动 xff0c 就不能获得很好的检测效果 xff0c 我所参与的项目就是一个云台搭载一台红外相机进行取像 xff0c 这样可以大幅度的节约成本 xff0c 但是对图像
  • 深究C语言4.链表和结构体

    目录 一 xff0c 结构体 一 xff0c 结构体的定义 二 xff0c 结构体的概念 1 2 3 4 5 6 三 xff0c 结构变量的使用 1 结构变量的操作符 gt 和 2 结构变量的赋值 3 结构变量作为函数参数 4 结构指针 5
  • 使用c++解析http\https数据遇到的问题(附代码)

    开发环境 xff1a vs2019 系统 xff1a win10 openssl版本 xff1a Win32OpenSSL 3 0 7 访问网页 xff1a www baidu com 先说明以下问题 xff1a c 43 43 在发送ht
  • vector的使用

    vector的介绍 1 vector是表示可变大小数组的序列容器 2 vector就像数组一样 xff0c 也采用的连续空间来存储元素 xff0c 这也意味着可以采用下标对vector的元素进行访问 3 vector与普通数组不同的是 xf
  • Linux系统( Centos 7) 配置与管理Apache服务器实例详细步骤

    Linux系统 xff08 Centos 7 xff09 配置与管理Apache服务器实例详细步骤 服务器centos7 1 1 配置网络 root 64 centos7 vim etc sysconfig network scripts
  • 什么是Cmake和Makefile?

    目录 1 前言 2 什么是Makefile 3 什么是Cmake 4 Cmake的语法规则 1 前言 在学习视觉SLAM十四讲的时候 xff0c 对这个Cmake的概念不太清楚 xff08 笔者是机械方向转到SLAM这个方向的 xff09
  • 创建任务7.24

    创建任务 1 什么是任务 在裸机系统中 xff0c 系统的主体就是 main 函数里面顺序执行的无限循环 xff0c 这个无限循环里面 CPU 按照顺序完成各种事情 在多任务系统中 xff0c 我们根据功能的不同 xff0c 把整个系统分割
  • Linux驱动开发系列:DRM(第十部分)

    https www iotword com 7227 html 一 DRM简介 DRM xff0c 全称Direct Rending Manger 是目前Linux主流的图形显示框架 相比较传统的Framebuffer xff0c DRM更