当前位置:   article > 正文

DRM几个重要的结构体及panel开发_drm panel

drm panel

一、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 接口。

4xxx_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是图层相关部分。结构体部分成员如下:

  1. struct drm_plane_funcs 结构体成员:
  2. 1、 update_plane:为给定的CRTC和framebuffer启用并配置平面
  3. 2、 disable_plane:关闭plane
  4. 3、 destroy:清除plane所有的资源
  5. 4、 reset:复位软硬件状态为关闭
  6. 5、 set_property:更新plane的property
  7. 6、 atomic_duplicate_state:复制当前的plane状态并返回
  8. 7、 atomic_destroy_state:销毁当前的plane状态
  9. 8、 atomic_set/get_property:原子操作设置/获得property
  10. 9、 format_mod_supported:该可选挂钩用于DRM,以确定给定的格式/修饰符组合是否对平面有效

struct drm_plane_helper_funcs部分成员如下:

  1. struct drm_plane_helper_funcs结构体成员:
  2. 1、 prepare_fb:该钩子通过固定其后备存储器或将其重新定位到连续的VRAM块,为扫描准备帧缓冲区。其他可能的准备工作包括冲洗缓存。
  3. 2、 cleanup_fb:清除在prepare_fb分配的给framebuffer和plane的资源
  4. 3、 atomic_check:检查该挂钩中的plane特定约束
  5. 4、 atomic_update:更新plane状态
  6. 5、 atomic_disable:关闭
  7. 6、 atomic_async_check:异步检查
  8. 7、 atomic_async_update:异步更新状态

使用示例:

  1. static const struct drm_plane_funcs ltdc_plane_funcs = {
  2. .update_plane = drm_atomic_helper_update_plane,
  3. .disable_plane = drm_atomic_helper_disable_plane,
  4. .destroy = drm_plane_cleanup,
  5. .reset = drm_atomic_helper_plane_reset,
  6. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  7. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  8. .atomic_print_state = ltdc_plane_atomic_print_state,
  9. .format_mod_supported = ltdc_plane_format_mod_supported,
  10. };
  11. static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = {
  12. .prepare_fb = drm_gem_fb_prepare_fb, //准备分配资源
  13. .atomic_check = ltdc_plane_atomic_check, //检查驱动
  14. .atomic_update = ltdc_plane_atomic_update, //更新plane状态
  15. .atomic_disable = ltdc_plane_atomic_disable, //关闭
  16. };

     2、struct drm_crtc_funcs结构体

        部分结构体成员如下:

  1. struct drm_crtc_funcs结构体成员:
  2. 1、 reset;复位,设置为关闭状态
  3. 2、 destroy:清除CRTC资源
  4. 3、 cursor_set:更新鼠标图像
  5. 4、 cursor_move:更新光标位置
  6. 5、 gamma_set:gamma设置
  7. 6、 set_config:修改配置
  8. 7、 page_flip:修改帧缓冲页,避免垂直消影期间用新的缓冲区替代时产生撕裂
  9. 8、 set_property:设置property
  10. 9、 atomic_duplicate_state:复制当前的状态
  11. 10、 atomic_destroy_state:销毁复制的状态
  12. 11、 atomic_get_property:获取atomic_get_property
  13. 12、 set_crc_source:更改CRC的来源
  14. 13、 get_vblank_counter 获取CRTC的vblank计数器
  15. 14、 disable_vblank:关闭消影
  16. struct drm_crtc_helper_funcs结构体成员
  17. 1、 dpms:控制CRTC电源功率
  18. 2、 commit:提交新的模式
  19. 3、 mode_valid:用于检查特定模式在此crtc中是否有效
  20. 4、 mode_fixup:用于验证模式
  21. 5、 mode_set:设置模式
  22. 6、 mode_set_nofb:用于更新CRTC的显示模式,而不更改主平面配置的任何内容
  23. 7、 mode_set_base:设置新的帧缓冲区和扫描位置
  24. 8、 atomic_flush:完成CRTC上多个平面的更新
  25. 9、 atomic_enable/disable:打开/关闭

使用示例如下:

  1. static const struct drm_crtc_funcs ltdc_crtc_funcs = {
  2. .destroy = drm_crtc_cleanup, //清除CRTC资源
  3. .set_config = drm_atomic_helper_set_config, //设置配置
  4. .page_flip = drm_atomic_helper_page_flip, //修改帧缓冲页,避免垂直消影期间用新的缓冲区替代时产生撕裂
  5. .reset = drm_atomic_helper_crtc_reset, // 复位,设置为关闭状态
  6. .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, // 复制当前状态
  7. .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, // 销毁当前状态
  8. .enable_vblank = ltdc_crtc_enable_vblank, // 使能消影
  9. .disable_vblank = ltdc_crtc_disable_vblank, // 关闭消影
  10. .gamma_set = drm_atomic_helper_legacy_gamma_set, //gamma设置
  11. };
  12. struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = {
  13. .mode_valid = ltdc_crtc_mode_valid, //用于检查特定模式红CRTC是否有效
  14. .mode_fixup = ltdc_crtc_mode_fixup, //用于验证模式
  15. .mode_set_nofb = ltdc_crtc_mode_set_nofb, //用于更新CRTC的显示模式,而不更改主平面配置的任何内容
  16. .atomic_flush = ltdc_crtc_atomic_flush, //完成CRTC上多个平面的更新
  17. .atomic_enable = ltdc_crtc_atomic_enable, // 打开
  18. .atomic_disable = ltdc_crtc_atomic_disable, //关闭
  19. };

3、struct drm_encoder_helper_funcs结构体:

  1. static const struct drm_encoder_funcs ltdc_encoder_funcs = {
  2. .destroy = drm_encoder_cleanup,
  3. };
  4. static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = {
  5. .disable = ltdc_encoder_disable,
  6. .enable = ltdc_encoder_enable,
  7. .mode_set = ltdc_encoder_mode_set,
  8. };

4、drm_panel相关

drm_panel这部分是在drivers\gpu\drm\panel\panel-simple.c添加。具体则是:

static const struct of_device_id platform_of_match[]下面添加一个自己的of_device_id。

  1. {
  2. .compatible = "alientek,lcd-rgb",
  3. .data = &HTQ_alientek_desc,
  4. },

HTQ_alientek_desc结构体描述的是所用屏幕的信息,包括显示模式、像素格式等。

  1. static const struct panel_desc HTQ_alientek_desc = {
  2. .modes = &HTQ_ATK7016_mode,
  3. .num_modes = 1,
  4. .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
  5. };

显示模式在HTQ_ATK7016_mode这个结构体里面具体描述,如时钟、分辨率、刷新率等等。

  1. static const struct drm_display_mode HTQ_ATK7016_mode = {
  2. .clock = 51200, /* LCD像素时钟,单位KHz */
  3. .hdisplay = 1024, /* LCD X轴像素个数 */
  4. .hsync_start = 1024 + 140, /* LCD X轴+hbp的像素个数 */
  5. .hsync_end = 1024 + 140 + 20, /* LCD X轴+hbp+hspw的像素个数 */
  6. .htotal = 1024 + 140 + 20 + 160,/* LCD X轴+hbp+hspw+hfp */
  7. .vdisplay = 600, /* LCD Y轴像素个数 */
  8. .vsync_start = 600 + 20, /* LCD Y轴+vbp的像素个数 */
  9. .vsync_end = 600 + 20 + 3, /* LCD Y轴+vbp+vspw的像素个数 */
  10. .vtotal = 600 + 20 + 3 + 12,/* LCD Y轴+vbp+vspw+vfp */
  11. .vrefresh = 60, /* LCD的刷新频率为60HZ */ 12
  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结构体作为驱动描述结构体。

  1. static struct mipi_dsi_driver panel_simple_dsi_driver = {
  2. .driver = {
  3. .name = "panel-simple-dsi",
  4. .of_match_table = dsi_of_match,
  5. },
  6. .probe = panel_simple_dsi_probe,
  7. .remove = panel_simple_dsi_remove,
  8. .shutdown = panel_simple_dsi_shutdown,
  9. };

本质上依然是个platform驱动。在panel_simple_init函数里面可以看到

  1. static int __init panel_simple_init(void)
  2. {
  3. int err;
  4. err = platform_driver_register(&panel_simple_platform_driver);
  5. if (err < 0)
  6. return err;
  7. if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
  8. err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
  9. if (err < 0)
  10. return err;
  11. }
  12. return 0;
  13. }
  14. module_init(panel_simple_init);

注册一个platform驱动,在panel_simple_dsi_probe函数中进行匹配,根据上面static const struct of_device_id platform_of_match[]中已经定义的数组数据。

三、总结

        DRM驱动是目前Linux内核主流的显示框架,支持现代的显示技术,社区参与度、活跃度都很高,传统的framebuffer基本上已经处于半废弃状态。DRM驱动开发离不开KMS中的几个模块,按照定义好的结构体填充代码,完成开发,还算比较方面。

相关链接:

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/330230
推荐阅读
相关标签
  

闽ICP备14008679号