收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事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->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框架产生的节点。![](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)**