一、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));  //设置DMAddev = drm_dev_alloc(&drv_driver, dev);  //分配一个drm_device结构体if (IS_ERR(ddev))return PTR_ERR(ddev);ret = my_modeset_init(ddev);  //初始化KMSif (ret)goto err_put;ret = drm_dev_register(ddev, 0);  //注册drmif (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;}

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      0x00000000Connectors:
id      encoder status          name            size (mm)       modes   encoders
32      31      connected       DPI-1           0x0             1       31modes: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, driverprops:1 EDID:flags: immutable blobblobs:value:2 DPMS:flags: enumenums: On=0 Standby=1 Suspend=2 Off=3value: 05 link-status:flags: enumenums: Good=0 Bad=1value: 06 non-desktop:flags: immutable rangevalues: 0 1value: 04 TILE:flags: immutable blobblobs:value:20 CRTC_ID:flags: objectvalue: 35CRTCs:
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, driverprops:22 ACTIVE:flags: rangevalues: 0 1value: 123 MODE_ID:flags: blobblobs:value:00c8000000048c04a0044005000058026c026f027b0200003c0000000500000048000000313032347836303000000000000000000000000000000000000000000000000019 OUT_FENCE_PTR:flags: rangevalues: 0 18446744073709551615value: 024 VRR_ENABLED:flags: rangevalues: 0 1value: 028 GAMMA_LUT:flags: blobblobs:value:29 GAMMA_LUT_SIZE:flags: immutable rangevalues: 0 4294967295value: 256Planes:
id      crtc    fb      CRTC x,y        x,y     gamma size      possible crtcs
33      35      38      0,0             0,0     0               0x00000001formats: AR24 XR24 RG24 RG16 AR15 XR15 AR12 XR12 C8props:8 type:flags: immutable enumenums: Overlay=0 Primary=1 Cursor=2value: 117 FB_ID:flags: objectvalue: 3818 IN_FENCE_FD:flags: signed rangevalues: -1 2147483647value: -120 CRTC_ID:flags: objectvalue: 3513 CRTC_X:flags: signed rangevalues: -2147483648 2147483647value: 014 CRTC_Y:flags: signed rangevalues: -2147483648 2147483647value: 015 CRTC_W:flags: rangevalues: 0 2147483647value: 102416 CRTC_H:flags: rangevalues: 0 2147483647value: 6009 SRC_X:flags: rangevalues: 0 4294967295value: 010 SRC_Y:flags: rangevalues: 0 4294967295value: 011 SRC_W:flags: rangevalues: 0 4294967295value: 6710886412 SRC_H:flags: rangevalues: 0 4294967295value: 3932160030 IN_FORMATS:flags: immutable blobblobs:value:01000000000000000900000018000000010000004000000041523234585232345247323452473136415231355852313541523132585231324338202000000000ff0100000000000000000000000000000000000000000000in_formats blob decoded:AR24:  LINEARXR24:  LINEARRG24:  LINEARRG16:  LINEARAR15:  LINEARXR15:  LINEARAR12:  LINEARXR12:  LINEARC8  :  LINEAR
36      0       0       0,0             0,0     0               0x00000001formats: AR24 RG24 RG16 AR15 AR12 C8props:8 type:flags: immutable enumenums: Overlay=0 Primary=1 Cursor=2value: 017 FB_ID:flags: objectvalue: 018 IN_FENCE_FD:flags: signed rangevalues: -1 2147483647value: -120 CRTC_ID:flags: objectvalue: 013 CRTC_X:flags: signed rangevalues: -2147483648 2147483647value: 014 CRTC_Y:flags: signed rangevalues: -2147483648 2147483647value: 015 CRTC_W:flags: rangevalues: 0 2147483647value: 016 CRTC_H:flags: rangevalues: 0 2147483647value: 09 SRC_X:flags: rangevalues: 0 4294967295value: 010 SRC_Y:flags: rangevalues: 0 4294967295value: 011 SRC_W:flags: rangevalues: 0 4294967295value: 012 SRC_H:flags: rangevalues: 0 4294967295value: 030 IN_FORMATS:flags: immutable blobblobs:value:0100000000000000060000001800000001000000300000004152323452473234524731364152313541523132433820203f0000000000000000000000000000000000000000000000in_formats blob decoded:AR24:  LINEARRG24:  LINEARRG16:  LINEARAR15:  LINEARAR12:  LINEARC8  :  LINEARFrame 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

linux驱动系列学习之DRM(十)相关推荐

  1. linux驱动系列学习之input子系统(二)

    一.input子系统简介 linux系统支持的输入设备众多,例如键盘.鼠标.按键.触摸屏等,linux系统通过抽象出一个input子系统去支持众多的输入设备.input子系统分为三层:上层:输入事件处 ...

  2. 嵌入式Linux驱动大全问世,十年磨一剑,视频!服务!新老客户都有大折扣!

    对于学习嵌入式Linux,韦东山老师整理了三条学习路线,适合与不同阶段的学员. 三条嵌入式学习路线 路线一:单片机路线 使用KEL.HAL库来快速的掌握单片机开发 路线二:深入学习单片机/RTOS/U ...

  3. linux驱动系列学习之OLED(i2c接口)(八)

    一.OLED简介 本次使用的开发板正点原子Linux阿波罗.屏幕是i2c接口的四针.分辨率为128×64的oled液晶屏.通信接口为i2c.具体的i2c框架使用请参考前面的文章.oled的详细简介请参 ...

  4. linux驱动系列学习之Framebuffer子系统(三)

    一.Framebuffer子系统简介         Framebuffer(帧缓冲)时Linux系统位显示设备提供的一个接口.属于偏底层的显示接口.它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上 ...

  5. Linux驱动开发之DRM驱动

    作者 QQ群:852283276 微信:arm80x86 微信公众号:青儿创客基地 B站:主页 https://space.bilibili.com/208826118 参考 Linux DRM Gr ...

  6. Linux驱动编程 step-by-step (十) Linux 内核链表

    终于可以清闲下来打理一下我的blog了,台资企业真的事情很多很烦-- 前几篇文章对字符设备有个简单介绍,并以简单的一个字符设备驱动作结尾,其实linux上大部分驱动程序都是字符设备程序,Linux源码 ...

  7. 嵌入式Linux驱动学习之路(十五)按键驱动-定时器防抖

    在之前的定时器驱动程序中,我们发现在连续按下按键的时候,正常情况下应该是一次按下对应一次松开.而程序有时候会显示是两次按下,一次松开.这个问题是因为在按下的时候,因为是机械按键,所以电压信号会产生一定 ...

  8. linux驱动系列学习之i2c子系统(四)

    一.i2c子系统简介 1. i2c总线 i2c总线因为只用SCL.SDA两根线就实现了设备之间的数据互传,极大的简化PCB布线,因此,2c总线在EEPROM.小型LCD等设备中应用极光.i2c的相关时 ...

  9. linux驱动系列学习之阻塞与非阻塞IO(六)

    一. 阻塞与非阻塞IO概念     阻塞操作是指在执行设备操作时,若不能获取资源,则挂起进程进入休眠状态,等待可满足条件后进行操作.被挂起的进程从调度器队列移动到挂起队列(睡眠状态).当操作驱动程序r ...

最新文章

  1. iOS实录15:浅谈iOS Crash
  2. IE中同一个url第二次AJAX调用无法触发onreadystatechange事件
  3. 一个对象的内存图及运行流程和3个对象的内存图的运行流程
  4. java中Class.getResource用法(用于配置文件的读取)
  5. Linux命令之hexdump
  6. 安卓linux开机画面,Android系统的开机画面显示过程分析(1)
  7. 【POJ - 1523】SPF(Tarjan求割点,求分割成的连通块数,模板题,tricks)
  8. 运维linux脚本实例,Shell脚本使用示例
  9. 国内的Android SDK镜像
  10. oracle数据库服务器c盘满,Oracle数据库服务器磁盘满导致数据库无法登陆,通过清理归档文件解决...
  11. matlab中符号函数sgn,matlab 饱和函数 sat
  12. java 获取视频编码_Java如何获取文件编码格式
  13. 什么是敏捷管理及scrum方法
  14. 读书笔记(平凡的世界)
  15. filter-grok,dissect匹配数据
  16. robotstudio试用期延长总结
  17. 微前端应用及基于qiankun的微前端实践
  18. 车载、行车记录仪产品知识汇集
  19. 记录: 之前发的 Unity 2018.x工具已经不能用了,我在这里说明一下,不是破解不是破解不是破解,我就说明一下情况!!!0.0
  20. 数据库的基本概念-基础(课堂笔记)

热门文章

  1. tipask二次开发总结_tipask二次开发总结
  2. 【Windows系统】产品ID、设备ID等系统参数
  3. ArrayList的三种遍历方法
  4. 海康摄像机被锁了 怎么办
  5. 计算机辅助项目管理课程方案,计算机辅助项目管理课程设计_大学论文.docx
  6. c语言中使用的字符常量其起止标记符是,2021国家开放大学电大本科《C语言程序设计》期末试题及答案(试卷号:1253)...
  7. python 正则表达式整理
  8. 2022-2028全球与中国健康资讯交换(HIE)市场现状及未来发展趋势
  9. java判断访问设备类型
  10. QCharts随时间流逝