赞
踩
一、DRM
Linux下的DRM框架内容众多,结构复杂。本文将简单介绍下开发过程中用到的几个结构体。这几个结构体都在之前文章里面开发DRM驱动时用到的,未用到的暂不介绍。
DRM中的KMS包含Framebuffer、CRTC,ENCODER,CONNECTOR,PLANE,VBLANK,property。因此,开发DMR驱动也是围绕这几个部分展开。驱动的逻辑部分需要包含这些。开发DRM驱动可以简化为如下操作。
1、初始化结构体
2、注册
3、 给 driver_features 添加上 DRIVER_MODESET,告诉 DRM Core 当前驱动支持 modesetting 操作,创建plane、crtc、encoder、connector 这4个 drm_mode_object。
4、给 driver_features 添加上 DRIVER_GEM 标志位,告诉 DRM Core 该驱动支持 GEM 操作。添加 FB 和 GEM 支持:dumb_create 回调接口用于创建 gem object,并分配物理 buffer。这里直接使用 CMA helper 函数来实现;fb_create 回调接口用于创建 framebuffer object,并绑定 gem objects。这里直接使用 CMA helper 函数实现。fops 中的 mmap 接口,用于将 dumb buffer 映射到 userspace,它依赖 drm driver 中的 gem_vm_ops 实现。这里也直接使用 CMA helper 函数来实现。
DRIVER_MODESET:表示支持modesetting 操作
DRIVER_GEM:表示支持GEM 操作,用于操作对内存的分配、释放
DRIVER_ATOMIC:支持 Atomic 操作,用于操作各种属性
.fops = &drv_driver_fops,驱动的fops结构体
.dumb_create = stm_gem_cma_dumb_create,创建gem object,分配屋里buffer,可以使用CMA helper函数实现
其中,
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() 接口必须实现
helper 函数的作用:drm_xxx_funcs 是 drm ioctl 操作的最终入口,但是对于大多数 SoC 厂商来说,它们的 drm_xxx_funcs 操作流程基本相同(你抄我,我抄你),只是在寄存器配置上存在差异,因此开发者们将那些 common 的操作流程做成了 helper 函数,而将那些厂商差异化的代码放到了 drm_xxx_helper_funcs 中去,由 SoC 厂商自己实现。
开发一个DRM驱动大致流程如上所述。总之,就是实现KMS中的各个部分。GEM中的部分可以使用CAM中的接口完成。
二、几个结构体
1、struct drm_plane_funcs结构体
plane是图层相关部分。结构体部分成员如下:
- struct drm_plane_funcs 结构体成员:
- 1、 update_plane:为给定的CRTC和framebuffer启用并配置平面
- 2、 disable_plane:关闭plane
- 3、 destroy:清除plane所有的资源
- 4、 reset:复位软硬件状态为关闭
- 5、 set_property:更新plane的property
- 6、 atomic_duplicate_state:复制当前的plane状态并返回
- 7、 atomic_destroy_state:销毁当前的plane状态
- 8、 atomic_set/get_property:原子操作设置/获得property
- 9、 format_mod_supported:该可选挂钩用于DRM,以确定给定的格式/修饰符组合是否对平面有效
struct drm_plane_helper_funcs部分成员如下:
- struct drm_plane_helper_funcs结构体成员:
- 1、 prepare_fb:该钩子通过固定其后备存储器或将其重新定位到连续的VRAM块,为扫描准备帧缓冲区。其他可能的准备工作包括冲洗缓存。
- 2、 cleanup_fb:清除在prepare_fb分配的给framebuffer和plane的资源
- 3、 atomic_check:检查该挂钩中的plane特定约束
- 4、 atomic_update:更新plane状态
- 5、 atomic_disable:关闭
- 6、 atomic_async_check:异步检查
- 7、 atomic_async_update:异步更新状态
使用示例:
- 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, //更新plane状态
- .atomic_disable = ltdc_plane_atomic_disable, //关闭
- };
2、struct drm_crtc_funcs结构体
部分结构体成员如下:
- struct drm_crtc_funcs结构体成员:
- 1、 reset;复位,设置为关闭状态
- 2、 destroy:清除CRTC资源
- 3、 cursor_set:更新鼠标图像
- 4、 cursor_move:更新光标位置
- 5、 gamma_set:gamma设置
- 6、 set_config:修改配置
- 7、 page_flip:修改帧缓冲页,避免垂直消影期间用新的缓冲区替代时产生撕裂
- 8、 set_property:设置property
- 9、 atomic_duplicate_state:复制当前的状态
- 10、 atomic_destroy_state:销毁复制的状态
- 11、 atomic_get_property:获取atomic_get_property
- 12、 set_crc_source:更改CRC的来源
- 13、 get_vblank_counter 获取CRTC的vblank计数器
- 14、 disable_vblank:关闭消影
-
- struct drm_crtc_helper_funcs结构体成员
- 1、 dpms:控制CRTC电源功率
- 2、 commit:提交新的模式
- 3、 mode_valid:用于检查特定模式在此crtc中是否有效
- 4、 mode_fixup:用于验证模式
- 5、 mode_set:设置模式
- 6、 mode_set_nofb:用于更新CRTC的显示模式,而不更改主平面配置的任何内容
- 7、 mode_set_base:设置新的帧缓冲区和扫描位置
- 8、 atomic_flush:完成CRTC上多个平面的更新
- 9、 atomic_enable/disable:打开/关闭
使用示例如下:
- static const struct drm_crtc_funcs ltdc_crtc_funcs = {
- .destroy = drm_crtc_cleanup, //清除CRTC资源
- .set_config = drm_atomic_helper_set_config, //设置配置
- .page_flip = drm_atomic_helper_page_flip, //修改帧缓冲页,避免垂直消影期间用新的缓冲区替代时产生撕裂
- .reset = drm_atomic_helper_crtc_reset, // 复位,设置为关闭状态
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, // 复制当前状态
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, // 销毁当前状态
- .enable_vblank = ltdc_crtc_enable_vblank, // 使能消影
- .disable_vblank = ltdc_crtc_disable_vblank, // 关闭消影
- .gamma_set = drm_atomic_helper_legacy_gamma_set, //gamma设置
- };
-
-
- struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
- .mode_valid = ltdc_crtc_mode_valid, //用于检查特定模式红CRTC是否有效
- .mode_fixup = ltdc_crtc_mode_fixup, //用于验证模式
- .mode_set_nofb = ltdc_crtc_mode_set_nofb, //用于更新CRTC的显示模式,而不更改主平面配置的任何内容
- .atomic_flush = ltdc_crtc_atomic_flush, //完成CRTC上多个平面的更新
- .atomic_enable = ltdc_crtc_atomic_enable, // 打开
- .atomic_disable = ltdc_crtc_atomic_disable, //关闭
- };
3、struct drm_encoder_helper_funcs结构体:
- static const struct drm_encoder_funcs ltdc_encoder_funcs = {
- .destroy = drm_encoder_cleanup,
- };
-
- static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = {
- .disable = ltdc_encoder_disable,
- .enable = ltdc_encoder_enable,
- .mode_set = ltdc_encoder_mode_set,
- };
4、drm_panel相关
drm_panel这部分是在drivers\gpu\drm\panel\panel-simple.c添加。具体则是:
static const struct of_device_id platform_of_match[]下面添加一个自己的of_device_id。
- {
- .compatible = "alientek,lcd-rgb",
- .data = &HTQ_alientek_desc,
- },
HTQ_alientek_desc结构体描述的是所用屏幕的信息,包括显示模式、像素格式等。
- static const struct panel_desc HTQ_alientek_desc = {
- .modes = &HTQ_ATK7016_mode,
- .num_modes = 1,
- .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
- };
显示模式在HTQ_ATK7016_mode这个结构体里面具体描述,如时钟、分辨率、刷新率等等。
- static const struct drm_display_mode HTQ_ATK7016_mode = {
- .clock = 51200, /* LCD像素时钟,单位KHz */
- .hdisplay = 1024, /* LCD X轴像素个数 */
- .hsync_start = 1024 + 140, /* LCD X轴+hbp的像素个数 */
- .hsync_end = 1024 + 140 + 20, /* LCD X轴+hbp+hspw的像素个数 */
- .htotal = 1024 + 140 + 20 + 160,/* LCD X轴+hbp+hspw+hfp */
- .vdisplay = 600, /* LCD Y轴像素个数 */
- .vsync_start = 600 + 20, /* LCD Y轴+vbp的像素个数 */
- .vsync_end = 600 + 20 + 3, /* LCD Y轴+vbp+vspw的像素个数 */
- .vtotal = 600 + 20 + 3 + 12,/* LCD Y轴+vbp+vspw+vfp */
- .vrefresh = 60, /* LCD的刷新频率为60HZ */ 12
- };
添加上这些,就能将设备树上的屏幕信息和驱动对应上。DRM框架就能驱动屏幕。
以上几个结构体分别对应KMS里面的crtc、plane、encoder、panel几个部分。对应着写好代码即可。都比较简单。最后一个是drm_panel相关的,屏幕这部分可以使用已经定义好的struct panel_desc结构体去描述,struct panel_desc结构体里面有drm_panel,struct panel_desc可以看作是drm_panel的继承。
panel-simple.c里面实际上使用的是struct mipi_dsi_driver panel_simple_dsi_driver结构体作为驱动描述结构体。
- static struct mipi_dsi_driver panel_simple_dsi_driver = {
- .driver = {
- .name = "panel-simple-dsi",
- .of_match_table = dsi_of_match,
- },
- .probe = panel_simple_dsi_probe,
- .remove = panel_simple_dsi_remove,
- .shutdown = panel_simple_dsi_shutdown,
- };
本质上依然是个platform驱动。在panel_simple_init函数里面可以看到
- static int __init panel_simple_init(void)
- {
- int err;
-
- err = platform_driver_register(&panel_simple_platform_driver);
- if (err < 0)
- return err;
-
- if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
- err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
- if (err < 0)
- return err;
- }
-
- return 0;
- }
- module_init(panel_simple_init);
注册一个platform驱动,在panel_simple_dsi_probe函数中进行匹配,根据上面static const struct of_device_id platform_of_match[]中已经定义的数组数据。
三、总结
DRM驱动是目前Linux内核主流的显示框架,支持现代的显示技术,社区参与度、活跃度都很高,传统的framebuffer基本上已经处于半废弃状态。DRM驱动开发离不开KMS中的几个模块,按照定义好的结构体填充代码,完成开发,还算比较方面。
相关链接:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。