注:文章都是通过阅读 Android && Linux 平台源码、各位前辈总结的资料、加上自己的思考分析总结出来的,其中难免有理不对的地方,欢迎大家批评指正。文章为个人学习、研究、欣赏之用。图文内容、源码整理自互联网,如有侵权,请联系删除(◕‿◕) ,转载请注明出处( ©Android @Linux @Rockchip版权所有),谢谢(๑乛◡乛๑) 、( ͡° ͜ʖ ͡°)、(ಡωಡ)!!!。 (==文章基于 Kernel-4.4 ==)&&(==文章基于 Android-8.1 ==)【开发板 - Firefly-RK3399 7.85寸1024x768显示屏模组(MIPI接口)】
正是由于前人的分析和总结,帮助我节约了大量的时间和精力,特别感谢!!!
(1)【DRM(Direct Rendering Manager)学习简介】
(2)【The DRM/KMS subsystem from a newbie’s point of view】
(3)【Anatomy of an Atomic KMS Driver】
(4)【Why and How to use KMS】
==源码(部分)==
DRM
I:\RK3399_Android8.1_MIPI\kernel\drivers\gpu\drm\rockchip*
I:\RK3399_Android8.1_MIPI\kernel\drivers\gpu\drm*
I:\RK3399_Android8.1_MIPI\kernel\drivers\phy\rockchip*
(一)、DRM/KMS简介 (1)、DRM(Direct Rendering Manager)简介 DRM 是 Linux 目前主流的图形显示框架,相比 FB 架构,DRM 更能适应当前日益更新的显示硬件。比如 FB 原生不支持多层合成,不支持 VSYNC,不支持 DMA-BUF,不支持异步更新,不支持 fence 机制等等,而这些功能 DRM 原生都支持。同时 DRM 可以统一管理 GPU 和 Display 驱动,使得软件架构更为统一,方便管理和维护。
DRM 从模块上划分,可以简单分为 3 部分:**libdrm
、 KMS
、 GEM
**
1.1、libdrm 对底层接口进行封装,向上层提供通用的 API 接口,主要是对各种 IOCTL 接口进行封装。
1.2、GEM Graphic Execution Manager,主要负责显示 buffer 的分配和释放,也是 GPU 唯一用到 DRM 的地方。
1.3、基本元素
DRM 框架涉及到的元素很多,大致如下: KMS:**CRTC
, ENCODER
, CONNECTOR
, PLANE
, FB
, VBLANK
, property
** GEM:**DUMB
、 PRIME
、 fence
**
元素
说明
CRTC
对显示 buffer 进行扫描,并产生时序信号的硬件模块,通常指 Display Controller
ENCODER
负责将 CRTC 输出的 timing 时序转换成外部设备所需要的信号的模块,如 HDMI 转换器或 DSI Controller
CONNECTOR
连接物理显示设备的连接器,如 HDMI、DisplayPort、DSI 总线,通常和 Encoder 驱动绑定在一起
PLANE
硬件图层,有的 Display 硬件支持多层合成显示,但所有的 Display Controller 至少要有 1 个 plane
FB
Framebuffer,单个图层的显示内容,唯一一个和硬件无关的基本元素
VBLANK
软件和硬件的同步机制,RGB 时序中的垂直消影区,软件通常使用硬件 VSYNC 来实现
property
任何你想设置的参数,都可以做成 property,是 DRM 驱动中最灵活、最方便的 Mode setting 机制
DUMB
只支持连续物理内存,基于 kernel 中通用 CMA API 实现,多用于小分辨率简单场景
PRIME
连续、非连续物理内存都支持,基于 DMA-BUF 机制,可以实现 buffer 共享,多用于大内存复杂场景
fence
buffer 同步机制,基于内核 dma_fence 机制实现,用于防止显示内容出现异步问题
(2)、KMS Kernel Mode Setting,所谓 Mode setting,其实说白了就两件事:更新画面
和设置显示参数
。更新画面 :显示 buffer 的切换,多图层的合成方式,以及每个图层的显示位置。设置显示参数 :包括分辨率、刷新率、电源状态(休眠唤醒)等。
(二)、DRM/KMS驱动分析 首先看看RK3399 DRM Kernel启动框图: 首先看看RK3399DRM Kernel启动UML流程图:
(1)、Drm device创建注册 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static int rockchip_drm_bind (struct device *dev) { struct drm_device *drm_dev ; struct rockchip_drm_private *private ; int ret; struct device_node *np = dev ->of_node ; struct device_node *parent_np ; struct drm_crtc *crtc ; printk("zjj.sye.display rockchip_drm_drv.c rockchip_drm_bind \n" ); drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev); ret = drm_dev_set_unique(drm_dev, "%s" , dev_name(dev)); dev_set_drvdata(dev, drm_dev); private = devm_kzalloc(drm_dev->dev, sizeof (*private ), GFP_KERNEL); mutex_init(&private ->commit_lock); INIT_WORK(&private ->commit_work, rockchip_drm_atomic_work); drm_dev->dev_private = private ; private ->dmc_support = false ; private ->devfreq = devfreq_get_devfreq_by_phandle(dev, 0 ); private ->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll" ); private ->default_pll.pll = devm_clk_get(dev, "default-vop-pll" ); #ifdef CONFIG_DRM_DMA_SYNC private ->cpu_fence_context = fence_context_alloc(1 ); atomic_set(&private ->cpu_fence_seqno, 0 ); #endif ret = rockchip_drm_init_iommu(drm_dev); drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); rockchip_drm_create_properties(drm_dev); ret = component_bind_all(dev, drm_dev); rockchip_attach_connector_property(drm_dev); ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); drm_mode_config_reset(drm_dev); rockchip_drm_set_property_default(drm_dev); drm_dev->irq_enabled = true ; drm_kms_helper_poll_init(drm_dev); drm_dev->vblank_disable_allowed = true ; rockchip_gem_pool_init(drm_dev); #ifndef MODULE show_loader_logo(drm_dev); #endif ret = of_reserved_mem_device_init(drm_dev->dev); ret = rockchip_drm_fbdev_init(drm_dev); drm_for_each_crtc(crtc, drm_dev) { struct drm_fb_helper *helper = private ->fbdev_helper ; struct rockchip_crtc_state *s = NULL ; s = to_rockchip_crtc_state(crtc->state); if (is_support_hotplug(s->output_type)) { s->crtc_primary_fb = crtc->primary->fb; crtc->primary->fb = helper->fb; drm_framebuffer_reference(helper->fb); } } drm_dev->mode_config.allow_fb_modifiers = true ; ret = drm_dev_register(drm_dev, 0 ); }
(2)、Drm driver信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static struct drm_driver rockchip_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC | DRIVER_RENDER, .preclose = rockchip_drm_preclose, .lastclose = rockchip_drm_lastclose, .get_vblank_counter = drm_vblank_no_hw_counter, .open = rockchip_drm_open, .postclose = rockchip_drm_postclose, .enable_vblank = rockchip_drm_crtc_enable_vblank, .disable_vblank = rockchip_drm_crtc_disable_vblank, .gem_vm_ops = &rockchip_drm_vm_ops, .gem_free_object = rockchip_gem_free_object, .dumb_create = rockchip_gem_dumb_create, .dumb_map_offset = rockchip_gem_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = drm_gem_prime_import, .gem_prime_export = drm_gem_prime_export, .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, .gem_prime_vmap = rockchip_gem_prime_vmap, .gem_prime_vunmap = rockchip_gem_prime_vunmap, .gem_prime_mmap = rockchip_gem_mmap_buf, .gem_prime_begin_cpu_access = rockchip_gem_prime_begin_cpu_access, .gem_prime_end_cpu_access = rockchip_gem_prime_end_cpu_access, #ifdef CONFIG_DEBUG_FS .debugfs_init = rockchip_drm_debugfs_init, .debugfs_cleanup = rockchip_drm_debugfs_cleanup, #endif .ioctls = rockchip_ioctls, .num_ioctls = ARRAY_SIZE(rockchip_ioctls), .fops = &rockchip_drm_driver_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, .major = DRIVER_MAJOR, .minor = DRIVER_MINOR, };
(3)、Drm driver file operations 1 2 3 4 5 6 7 8 9 10 11 12 13 14 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static const struct file_operations rockchip_drm_driver_fops = { .owner = THIS_MODULE, .open = drm_open, .mmap = rockchip_gem_mmap, .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = drm_compat_ioctl, #endif .release = drm_release, };
(4)、Mode Config 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static int rockchip_drm_bind (struct device *dev) {drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); } I:\RK3399_Android8.1 _MIPI\kernel\arch\arm64\boot\dts\rockchip\rk3399-firefly-mipi.dts void rockchip_drm_mode_config_init (struct drm_device *dev) { dev->mode_config.min_width = 0 ; dev->mode_config.min_height = 0 ; dev->mode_config.max_width = 8192 ; dev->mode_config.max_height = 8192 ; dev->mode_config.funcs = &rockchip_drm_mode_config_funcs; } static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { .fb_create = rockchip_user_fb_create, .output_poll_changed = rockchip_drm_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = rockchip_drm_atomic_commit, };
(5)、GEM 1 2 3 4 5 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c const struct vm_operations_struct rockchip_drm_vm_ops = { .open = drm_gem_vm_open, .close = drm_gem_vm_close, };
(6)、GEM – Dumb 1 2 3 4 5 6 7 8 9 10 11 12 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static struct drm_driver rockchip_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC | DRIVER_RENDER, ...... .dumb_create = rockchip_gem_dumb_create, .dumb_map_offset = rockchip_gem_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, ...... };
(7)、GEM – PRIME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static struct drm_driver rockchip_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC | DRIVER_RENDER, ...... .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_import = drm_gem_prime_import, .gem_prime_export = drm_gem_prime_export, .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table, .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, .gem_prime_vmap = rockchip_gem_prime_vmap, .gem_prime_vunmap = rockchip_gem_prime_vunmap, .gem_prime_mmap = rockchip_gem_mmap_buf, .gem_prime_begin_cpu_access = rockchip_gem_prime_begin_cpu_access, .gem_prime_end_cpu_access = rockchip_gem_prime_end_cpu_access, ...... };
(8)、Frame Buffer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_fb.c static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { .fb_create = rockchip_user_fb_create, .output_poll_changed = rockchip_drm_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = rockchip_drm_atomic_commit, }; static struct drm_framebuffer *rockchip_user_fb_create (struct drm_device *dev , struct drm_file *file_priv , struct drm_mode_fb_cmd2 *mode_cmd ) { struct drm_framebuffer *fb ; struct drm_gem_object *objs [ROCKCHIP_MAX_FB_BUFFER ]; struct drm_gem_object *obj ; unsigned int hsub; unsigned int vsub; int num_planes; int ret; int i; hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format); vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format); num_planes = min(drm_format_num_planes(mode_cmd->pixel_format), ROCKCHIP_MAX_FB_BUFFER); for (i = 0 ; i < num_planes; i++) { unsigned int width = mode_cmd->width / (i ? hsub : 1 ); unsigned int height = mode_cmd->height / (i ? vsub : 1 ); unsigned int min_size; unsigned int bpp = drm_format_plane_bpp(mode_cmd->pixel_format, i); obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[i]); if (!obj) { dev_err(dev->dev, "Failed to lookup GEM object\n" ); ret = -ENXIO; goto err_gem_object_unreference; } min_size = (height - 1 ) * mode_cmd->pitches[i] + mode_cmd->offsets[i] + roundup(width * bpp, 8 ) / 8 ; if (obj->size < min_size) { DRM_ERROR("Invalid Gem size on plane[%d]: %zd < %d\n" , i, obj->size, min_size); drm_gem_object_unreference_unlocked(obj); ret = -EINVAL; goto err_gem_object_unreference; } objs[i] = obj; } fb = rockchip_fb_alloc(dev, mode_cmd, objs, NULL , i); ...... return fb; }
(9)、Initialization – CRTC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 static int vop_bind (struct device *dev, struct device *master, void *data) { struct platform_device *pdev = to_platform_device (dev ); const struct vop_data *vop_data ; struct drm_device *drm_dev = data ; struct vop *vop ; struct resource *res ; ...... ret = vop_create_crtc(vop); ...... of_rockchip_drm_sub_backlight_register(dev, &vop->crtc, &rockchip_sub_backlight_ops); return 0 ; } static int vop_create_crtc (struct vop *vop) { struct device *dev = vop ->dev ; const struct vop_data *vop_data = vop ->data ; struct drm_device *drm_dev = vop ->drm_dev ; struct rockchip_drm_private *private = drm_dev ->dev_private ; struct drm_plane *primary = NULL , *cursor = NULL , *plane , *tmp ; struct drm_crtc *crtc = &vop ->crtc ; struct device_node *port ; for (i = 0 ; i < vop->num_wins; i++) { struct vop_win *win = &vop ->win [i ]; ...... ret = vop_plane_init(vop, win, 0 ); ...... } ret = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &vop_crtc_funcs, NULL ); ....... drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); ...... init_completion(&vop->dsp_hold_completion); init_completion(&vop->line_flag_completion); crtc->port = port; rockchip_register_crtc_funcs(crtc, &private_crtc_funcs); ....... }
(10)、Initialization – Encoder 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c static int dw_mipi_dsi_register (struct drm_device *drm, struct dw_mipi_dsi *dsi) { struct drm_encoder *encoder = &dsi ->encoder ; struct drm_connector *connector = &dsi ->connector ; struct device *dev = dsi ->dev ; int ret; printk("zjj.sye.display dw_mipi_dsi.c dw_mipi_dsi_register\n" ); encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); if (encoder->possible_crtcs == 0 ) return -EPROBE_DEFER; drm_encoder_helper_add(&dsi->encoder, &dw_mipi_dsi_encoder_helper_funcs); ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI, NULL ); ...... return 0 ; }
(11)、Initialization – Connector 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c static int dw_mipi_dsi_register (struct drm_device *drm, struct dw_mipi_dsi *dsi) { struct drm_encoder *encoder = &dsi ->encoder ; struct drm_connector *connector = &dsi ->connector ; struct device *dev = dsi ->dev ; int ret; ...... if (dsi->bridge) { ...... } else { dsi->connector.port = dev->of_node; ret = drm_connector_init(drm, &dsi->connector, &dw_mipi_dsi_atomic_connector_funcs, DRM_MODE_CONNECTOR_DSI); ...... drm_connector_helper_add(connector, &dw_mipi_dsi_connector_helper_funcs); drm_mode_connector_attach_encoder(connector, encoder); ret = drm_panel_attach(dsi->panel, &dsi->connector); ...... } return 0 ; }
(12)、Initialization – Plane 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\panel\panel-simple.c static int panel_simple_probe (struct device *dev, const struct panel_desc *desc) { struct device_node *backlight , *ddc ; struct panel_simple *panel ; struct panel_desc *of_desc ; const char *cmd_type; u32 val; ...... panel = devm_kzalloc(dev, sizeof (*panel), GFP_KERNEL); ...... drm_panel_init(&panel->base); panel->base.dev = dev; panel->base.funcs = &panel_simple_funcs; err = drm_panel_add(&panel->base); if (err < 0 ) goto free_ddc; dev_set_drvdata(dev, panel); return 0 ; }
(13)、Modes Discovery 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = dw_mipi_dsi_detect, .destroy = dw_mipi_dsi_drm_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, }; static const struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = { .loader_protect = dw_mipi_loader_protect, .get_modes = dw_mipi_dsi_connector_get_modes, .best_encoder = dw_mipi_dsi_connector_best_encoder, };
(14)、State – CRTC 1 2 3 4 5 6 7 8 9 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_vop.c static const struct drm_crtc_funcs vop_crtc_funcs = { ...... .atomic_duplicate_state = vop_crtc_duplicate_state, .atomic_destroy_state = vop_crtc_destroy_state, };
(15)、State – Connector 1 2 3 4 5 6 7 8 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = { ...... .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, };
(16)、Atomic Update – KMS 1 2 3 4 5 6 7 8 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { ....... .atomic_check = drm_atomic_helper_check, .atomic_commit = rockchip_drm_atomic_commit, };
(17)、Atomic Update – CRTC 1 2 3 4 5 6 7 8 9 10 11 12 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_vop.c static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { .load_lut = vop_crtc_load_lut, .enable = vop_crtc_enable, .disable = vop_crtc_disable, .mode_fixup = vop_crtc_mode_fixup, .atomic_check = vop_crtc_atomic_check, .atomic_flush = vop_crtc_atomic_flush, .atomic_begin = vop_crtc_atomic_begin, };
(18)、Atomic Update – Encoder 1 2 3 4 5 6 7 8 9 10 11 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\dw-mipi-dsi.c static const struct drm_encoder_helper_funcs dw_mipi_dsi_encoder_helper_funcs = { .mode_fixup = dw_mipi_dsi_encoder_mode_fixup, .mode_set = dw_mipi_dsi_encoder_mode_set, .enable = dw_mipi_dsi_encoder_enable, .disable = dw_mipi_dsi_encoder_disable, .atomic_check = dw_mipi_dsi_encoder_atomic_check, };
(19)、Atomic Update – CRTC+Plane 1 2 3 4 5 6 7 8 9 10 11 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_vop.c static const struct drm_plane_helper_funcs plane_helper_funcs = { .prepare_fb = vop_plane_prepare_fb, .cleanup_fb = vop_plane_cleanup_fb, .atomic_check = vop_plane_atomic_check, .atomic_update = vop_plane_atomic_update, .atomic_disable = vop_plane_atomic_disable, };
(20)、Vertical Blanking 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_drv.c static struct drm_driver rockchip_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC | DRIVER_RENDER, ...... .enable_vblank = rockchip_drm_crtc_enable_vblank, .disable_vblank = rockchip_drm_crtc_disable_vblank, } I:\RK3399_Android8.1 _MIPI\kernel\drivers\gpu\drm\rockchip\rockchip_drm_vop.c static int vop_crtc_enable_vblank(struct drm_crtc *crtc) { struct vop *vop = to_vop(crtc); unsigned long flags; ...... spin_lock_irqsave(&vop->irq_lock, flags); if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) >= 7 ) { VOP_INTR_SET_TYPE(vop, clear, FS_FIELD_INTR, 1 ); VOP_INTR_SET_TYPE(vop, enable, FS_FIELD_INTR, 1 ); } else { VOP_INTR_SET_TYPE(vop, clear, FS_INTR, 1 ); VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1 ); } spin_unlock_irqrestore(&vop->irq_lock, flags); return 0 ; }
(三)、参考资料(特别感谢): (1)【DRM(Direct Rendering Manager)学习简介】
(2)【The DRM/KMS subsystem from a newbie’s point of view】
(3)【Anatomy of an Atomic KMS Driver】
(4)【Why and How to use KMS】