linux驱动系列学习之DRM(十)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一、DRM简介

        DRM全称Direct Rending Manger。是目前Linux主流的图形显示框架。相比较传统的FramebufferDRM更能适应现代硬件。支持GPU、3D渲染显示等。DRM可以统一管理GPU、Display驱动使得软件架构更统一、方便开发和维护。本文只介绍Display相关内容GPU相关的博主也不懂无能为力等以后学到相关的再来更新。

        从模块上划分DRM可以分为三个部分libdrm、KMS、GEM。l

图1 DRM框架

1. lbdrm是DRM框架提供的、位于用户空间、操作DRM的库。应用程序调用内核里面的KMS和GEM访问显示相关的资源。

2. KMSKernel Mode Setting

        KMS是DRM框架的一个大模块主要功能是显示参数及显示控制。

3. GEMGraphics Execution Manager

        GEM负责DRM下的内存管理和释放。

        本文只涉及KMS和GEM相关部分。使用的开发板是stm32mp157正点原子进行测试。系统是ubuntu18.04。

二、KMS

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

Framebuffer、CRTCENCODERCONNECTORPLANEVBLANKproperty。他们之间的关系如图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接口对应ConnectorFramebuffer对应的是显存部分。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结构体

如图3driver_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中的基本元素CRTCENCODERCONNECTORPLANEFramebuffer已经在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;
	}

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

其中 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 
 

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux