2024年物联网嵌入式最新Linux驱动开发系列:DRM(第十部分)_drm bolb,2024年最新物联网嵌入式开发基础控件

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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-&gt;caps.pix_fmt_hw[i]);
if (!drm_fmt)
	continue;
formats[nb_fmt++] = drm_fmt;

/* Add the no-alpha related format if any &amp; supported */
drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt);
if (!drm_fmt_no_alpha)
	continue;

/* Manage hw-specific capabilities */
if (ldev-&gt;caps.non_alpha_only_l1 &amp;&amp;
    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框架产生的节点。![](https://i3.wp.com/img-blog.csdnimg.cn/32313b5bd17d4a30834dc4430ae8e593.png)


#### 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  


![img](https://img-blog.csdnimg.cn/img_convert/abd70c7e36f15fa025ccf5deb7463a8d.png)
![img](https://img-blog.csdnimg.cn/img_convert/46d89b2b8a8fd0537983a105c2a33cf5.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

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  


[外链图片转存中...(img-CTv13oCC-1715658668249)]
[外链图片转存中...(img-Nzi42cLT-1715658668250)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值