当前位置: 首页 > news >正文

Linux内核4.14版本——drm框架分析(4)——crtc分析

目录

1. struct drm_crtc结构体

2. crtc相关的API

2.1 drm_crtc_init_with_planes

2.5 drm_mode_setcrtc

3. func的一些介绍

3.1 struct drm_crtc_helper_funcs

3.2 struct drm_crtc_funcs

4. 应用层的调用

4.1 drmModeSetCrtc (drmlib库里)---> drm_mode_setcrtc


       本文主要分析一下crtc相关的内容。

1. struct drm_crtc结构体


/*** struct drm_crtc - central CRTC control structure* @dev: parent DRM device* @port: OF node used by drm_of_find_possible_crtcs()* @head: list management* @name: human readable name, can be overwritten by the driver* @mutex: per-CRTC locking* @base: base KMS object for ID tracking etc.* @primary: primary plane for this CRTC* @cursor: cursor plane for this CRTC* @cursor_x: current x position of the cursor, used for universal cursor planes* @cursor_y: current y position of the cursor, used for universal cursor planes* @enabled: is this CRTC enabled?* @mode: current mode timings* @hwmode: mode timings as programmed to hw regs* @x: x position on screen* @y: y position on screen* @funcs: CRTC control functions* @gamma_size: size of gamma ramp* @gamma_store: gamma ramp values* @helper_private: mid-layer private data* @properties: property tracking for this CRTC** Each CRTC may have one or more connectors associated with it.  This structure* allows the CRTC to be controlled.*/
struct drm_crtc {struct drm_device *dev;struct device_node *port;struct list_head head;char *name;/*** @mutex:** This provides a read lock for the overall CRTC state (mode, dpms* state, ...) and a write lock for everything which can be update* without a full modeset (fb, cursor data, CRTC properties ...). A full* modeset also need to grab &drm_mode_config.connection_mutex.** For atomic drivers specifically this protects @state.*/struct drm_modeset_lock mutex;struct drm_mode_object base;/* primary and cursor planes for CRTC */struct drm_plane *primary;struct drm_plane *cursor;/*** @index: Position inside the mode_config.list, can be used as an array* index. It is invariant over the lifetime of the CRTC.*/unsigned index;/* position of cursor plane on crtc */int cursor_x;int cursor_y;bool enabled;/* Requested mode from modesetting. */struct drm_display_mode mode;/* Programmed mode in hw, after adjustments for encoders,* crtc, panel scaling etc. Needed for timestamping etc.*/struct drm_display_mode hwmode;int x, y;const struct drm_crtc_funcs *funcs;/* Legacy FB CRTC gamma size for reporting to userspace */uint32_t gamma_size;uint16_t *gamma_store;/* if you are using the helper */const struct drm_crtc_helper_funcs *helper_private;struct drm_object_properties properties;/*** @state:** Current atomic state for this CRTC.** This is protected by @mutex. Note that nonblocking atomic commits* access the current CRTC state without taking locks. Either by going* through the &struct drm_atomic_state pointers, see* for_each_crtc_in_state(), for_each_oldnew_crtc_in_state(),* for_each_old_crtc_in_state() and for_each_new_crtc_in_state(). Or* through careful ordering of atomic commit operations as implemented* in the atomic helpers, see &struct drm_crtc_commit.*/struct drm_crtc_state *state;/*** @commit_list:** List of &drm_crtc_commit structures tracking pending commits.* Protected by @commit_lock. This list doesn't hold its own full* reference, but burrows it from the ongoing commit. Commit entries* must be removed from this list once the commit is fully completed,* but before it's correspoding &drm_atomic_state gets destroyed.*/struct list_head commit_list;/*** @commit_lock:** Spinlock to protect @commit_list.*/spinlock_t commit_lock;#ifdef CONFIG_DEBUG_FS/*** @debugfs_entry:** Debugfs directory for this CRTC.*/struct dentry *debugfs_entry;
#endif/*** @crc:** Configuration settings of CRC capture.*/struct drm_crtc_crc crc;/*** @fence_context:** timeline context used for fence operations.*/unsigned int fence_context;/*** @fence_lock:** spinlock to protect the fences in the fence_context.*/spinlock_t fence_lock;/*** @fence_seqno:** Seqno variable used as monotonic counter for the fences* created on the CRTC's timeline.*/unsigned long fence_seqno;/*** @timeline_name:** The name of the CRTC's fence timeline.*/char timeline_name[32];
};

2. crtc相关的API

2.1 drm_crtc_init_with_planes


/*** drm_crtc_init_with_planes - Initialise a new CRTC object with*    specified primary and cursor planes.* @dev: DRM device* @crtc: CRTC object to init* @primary: Primary plane for CRTC* @cursor: Cursor plane for CRTC* @funcs: callbacks for the new CRTC* @name: printf style format string for the CRTC name, or NULL for default name** Inits a new object created as base part of a driver crtc object. Drivers* should use this function instead of drm_crtc_init(), which is only provided* for backwards compatibility with drivers which do not yet support universal* planes). For really simple hardware which has only 1 plane look at* drm_simple_display_pipe_init() instead.** Returns:* Zero on success, error code on failure.*/
int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,struct drm_plane *primary,struct drm_plane *cursor,const struct drm_crtc_funcs *funcs,const char *name, ...)
{struct drm_mode_config *config = &dev->mode_config;int ret;WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);crtc->dev = dev;crtc->funcs = funcs;INIT_LIST_HEAD(&crtc->commit_list);spin_lock_init(&crtc->commit_lock);drm_modeset_lock_init(&crtc->mutex);ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);   // (1)if (ret)return ret;if (name) {                                          // (2)va_list ap;va_start(ap, name);crtc->name = kvasprintf(GFP_KERNEL, name, ap);va_end(ap);} else {crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",drm_num_crtcs(dev));}if (!crtc->name) {drm_mode_object_unregister(dev, &crtc->base);return -ENOMEM;}crtc->fence_context = dma_fence_context_alloc(1);     // (3)spin_lock_init(&crtc->fence_lock);snprintf(crtc->timeline_name, sizeof(crtc->timeline_name),"CRTC:%d-%s", crtc->base.id, crtc->name);crtc->base.properties = &crtc->properties;           // (4)list_add_tail(&crtc->head, &config->crtc_list);crtc->index = config->num_crtc++;crtc->primary = primary;                             // (5) crtc->cursor = cursor;if (primary && !primary->possible_crtcs)primary->possible_crtcs = 1 << drm_crtc_index(crtc);if (cursor && !cursor->possible_crtcs)cursor->possible_crtcs = 1 << drm_crtc_index(crtc);ret = drm_crtc_crc_init(crtc);                      // (6)if (ret) {drm_mode_object_unregister(dev, &crtc->base);return ret;}if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {     // (7)drm_object_attach_property(&crtc->base, config->prop_active, 0);drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);drm_object_attach_property(&crtc->base,config->prop_out_fence_ptr, 0);}return 0;
}

        (1)创建一个类型为DRM_MODE_OBJECT_CRTC的struct drm_mode_object结构体。

        (2)为创建的crtc赋名字。

        (3)暂不知道。

        (4)初始化properties

        (5)初始化primary plane、cursor plane。

        (6)drm_crtc_crc_init是一些调试方面的。

        (7)attach一些properties变量。

2.5 drm_mode_setcrtc

int drm_mode_setcrtc(struct drm_device *dev, void *data,struct drm_file *file_priv)
{struct drm_mode_config *config = &dev->mode_config;struct drm_mode_crtc *crtc_req = data;struct drm_crtc *crtc;struct drm_connector **connector_set = NULL, *connector;struct drm_framebuffer *fb = NULL;struct drm_display_mode *mode = NULL;struct drm_mode_set set;uint32_t __user *set_connectors_ptr;struct drm_modeset_acquire_ctx ctx;int ret;int i;if (!drm_core_check_feature(dev, DRIVER_MODESET))return -EINVAL;/** Universal plane src offsets are only 16.16, prevent havoc for* drivers using universal plane code internally.*/if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)return -ERANGE;crtc = drm_crtc_find(dev, crtc_req->crtc_id);             // (1)if (!crtc) {DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);return -ENOENT;}DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);mutex_lock(&crtc->dev->mode_config.mutex);drm_modeset_acquire_init(&ctx, 0);                       // (2)
retry:ret = drm_modeset_lock_all_ctx(crtc->dev, &ctx);         // (3)if (ret)goto out;if (crtc_req->mode_valid) {                              /* If we have a mode we need a framebuffer. *//* If we pass -1, set the mode with the currently bound fb */if (crtc_req->fb_id == -1) {                         // (4)           if (!crtc->primary->fb) {DRM_DEBUG_KMS("CRTC doesn't have current FB\n");ret = -EINVAL;goto out;}fb = crtc->primary->fb;/* Make refcounting symmetric with the lookup path. */drm_framebuffer_get(fb);} else {fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);if (!fb) {DRM_DEBUG_KMS("Unknown FB ID%d\n",crtc_req->fb_id);ret = -ENOENT;goto out;}}mode = drm_mode_create(dev);                       // (5)if (!mode) {ret = -ENOMEM;goto out;}ret = drm_mode_convert_umode(mode, &crtc_req->mode);   // (6)if (ret) {DRM_DEBUG_KMS("Invalid mode\n");goto out;}/** Check whether the primary plane supports the fb pixel format.* Drivers not implementing the universal planes API use a* default formats list provided by the DRM core which doesn't* match real hardware capabilities. Skip the check in that* case.*/if (!crtc->primary->format_default) {                  // (7)ret = drm_plane_check_pixel_format(crtc->primary,fb->format->format);if (ret) {struct drm_format_name_buf format_name;DRM_DEBUG_KMS("Invalid pixel format %s\n",drm_get_format_name(fb->format->format,&format_name));goto out;}}ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,mode, fb);                           // (8)if (ret)goto out;}if (crtc_req->count_connectors == 0 && mode) {DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");ret = -EINVAL;goto out;}if (crtc_req->count_connectors > 0 && (!mode || !fb)) {DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",crtc_req->count_connectors);ret = -EINVAL;goto out;}if (crtc_req->count_connectors > 0) {               u32 out_id;/* Avoid unbounded kernel memory allocation */if (crtc_req->count_connectors > config->num_connector) {ret = -EINVAL;goto out;}connector_set = kmalloc_array(crtc_req->count_connectors,sizeof(struct drm_connector *),GFP_KERNEL);if (!connector_set) {ret = -ENOMEM;goto out;}for (i = 0; i < crtc_req->count_connectors; i++) {        // (9)connector_set[i] = NULL;set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;if (get_user(out_id, &set_connectors_ptr[i])) {ret = -EFAULT;goto out;}connector = drm_connector_lookup(dev, out_id);         // (10)if (!connector) {DRM_DEBUG_KMS("Connector id %d unknown\n",out_id);ret = -ENOENT;goto out;}DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",connector->base.id,connector->name);connector_set[i] = connector;}}set.crtc = crtc;set.x = crtc_req->x;set.y = crtc_req->y;set.mode = mode;set.connectors = connector_set;set.num_connectors = crtc_req->count_connectors;set.fb = fb;ret = __drm_mode_set_config_internal(&set, &ctx);            // (11)out:if (fb)drm_framebuffer_put(fb);                                 // (12)if (connector_set) {for (i = 0; i < crtc_req->count_connectors; i++) {if (connector_set[i])drm_connector_put(connector_set[i]);             // (13)}}kfree(connector_set);drm_mode_destroy(dev, mode);if (ret == -EDEADLK) {drm_modeset_backoff(&ctx);goto retry;}drm_modeset_drop_locks(&ctx);drm_modeset_acquire_fini(&ctx);mutex_unlock(&crtc->dev->mode_config.mutex);return ret;
}

        (1)找到需要的crtc实体。

        (2)初始化一个ctrc的需求内容结构体。

        (3)connection、crtc、plane等锁上锁。 

        (4)得到或者生成primary plane的framebuffer。

        (5~6)创建一个struct drm_display_mode结构体,并把应用层传递下来的参数赋值给给结构体。

        (7)检查primary plane支持的pixel format。

        (8)检查一下framebuffer是否足够大,能否满足crtc viewport.

        (9~10)找到crtc绑定链接的connetcor。

        (11)设置struct drm_mode_set结构体。

3. func的一些介绍

3.1 struct drm_crtc_helper_funcs

 
//struct drm_crtc_helper_funcs - helper operations for CRTCs
struct drm_crtc_helper_funcs {//电源管理接口,一般由drm_helper_connector_dpms调用void (*dpms)(struct drm_crtc *crtc, int mode);/*为modeset做准备,一般就是调用dpms接口关闭crtc(DRM_MODE_DPMS_OFF),    *drm_crtc_heler_set_mode接口会调用*atomic接口使用atomic_disable替代*/void (*prepare)(struct drm_crtc *crtc);/* 和prepare接口对应,是在modeset完成后,调用该接口来enable crtc* 一般就是调用dmps接口( DRM_MODE_DPMS_ON)* atomic 操作是用atomic_enable替代*/void (*commit)(struct drm_crtc *crtc);/*检查显示mode的有效性,  drm_helper_probe_single_connector_modes()和* drm_atomic_helper_check_modeset()会调用到, 该接口仅作初步检查* 更详细的检查有@mode_fixup or @atomic_check*/enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc,const struct drm_display_mode *mode);/*验证并修正mode, 由drm_atomic_helper_check_modeset()调用*/bool (*mode_fixup)(struct drm_crtc *crtc,const struct drm_display_mode *mode,struct drm_display_mode *adjusted_mode);//设置display mode ,crtc_set_mode会调用该接口int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,struct drm_display_mode *adjusted_mode, int x, int y,struct drm_framebuffer *old_fb);/*更新crtc的display mode, 但不会修改其primary plane配置,* 注意调用该接口的时候, display pipe应该是完全off的*/void (*mode_set_nofb)(struct drm_crtc *crtc);//设置fb 和 显示位置, drm_crtc_helper_set_config()会调用该接口int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,struct drm_framebuffer *old_fb);int (*mode_set_base_atomic)(struct drm_crtc *crtc,struct drm_framebuffer *fb, int x, int y,enum mode_set_atomic);//关闭crtcvoid (*disable)(struct drm_crtc *crtc);/*检查待更新的drm_crtc_state, * drm_atomic_helper_check() -->  drm_atomic_helper_check_planes()会调用*/int (*atomic_check)(struct drm_crtc *crtc,struct drm_atomic_state *state);//多plane的atomic update之前需要调用该接口(drm_atomic_helper_commit_planes中调用)void (*atomic_begin)(struct drm_crtc *crtc,struct drm_atomic_state *state);/*多plane的atomic update之后需要调用该接口(drm_atomic_helper_commit_planes中调用)* atomic_begin/atomic_flush具体的作用好像也不是太清晰,应该就是为driver提供在更新* planes的前后能做一些额外操作吧?*/void (*atomic_flush)(struct drm_crtc *crtc,struct drm_atomic_state *state);//atomic encable crtcvoid (*atomic_enable)(struct drm_crtc *crtc,struct drm_atomic_state *state);atomic disable crtcvoid (*atomic_disable)(struct drm_crtc *crtc,struct drm_atomic_state *state);//获取扫描信息,由drm_crtc_vblank_helper_get_vblank_timestamp()调用bool (*get_scanout_position)(struct drm_crtc *crtc,bool in_vblank_irq, int *vpos, int *hpos,ktime_t *stime, ktime_t *etime,const struct drm_display_mode *mode);
};

3.2 struct drm_crtc_funcs

 
//crtc控制接口,一般填写helper函数
struct drm_crtc_funcs {/*重置软硬件state, 由drm_mode_config_reset()调用,一般赋值为        drm_atomic_helper_crtc_reset()接口*/void (*reset)(struct drm_crtc *crtc);/*设置鼠标图片, width/height应该是鼠标图片的宽高, handle是鼠标图片buf(drm_gem_obj)对        应的handle, 该接口最新版本已经被废弃,使用鼠标层代替*/int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv,uint32_t handle, uint32_t width, uint32_t height);/*同上,设置鼠标图片,不过这个接口多了hot_x, hot_y坐标*/int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv,uint32_t handle, uint32_t width, uint32_t height,int32_t hot_x, int32_t hot_y);/*鼠标移动操作*/int (*cursor_move)(struct drm_crtc *crtc, int x, int y);//gamma设置int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,uint32_t size,struct drm_modeset_acquire_ctx *ctx);//drm_mode_config_cleanup 调用到该接口void (*destroy)(struct drm_crtc *crtc);/* 设置crtc的fb/ connector/ mode的属性,对应用户态drmModeSetCrtc接口* atomic modeset操作,使用drm_atomic_helper_set_config接口赋值*/int (*set_config)(struct drm_mode_set *set,struct drm_modeset_acquire_ctx *ctx);//page翻转接口,vsync同步的int (*page_flip)(struct drm_crtc *crtc,struct drm_framebuffer *fb,struct drm_pending_vblank_event *event,uint32_t flags,struct drm_modeset_acquire_ctx *ctx);//和page_flip类似,但该接口会等待特定的vbankint (*page_flip_target)(struct drm_crtc *crtc,struct drm_framebuffer *fb,struct drm_pending_vblank_event *event,uint32_t flags, uint32_t target,struct drm_modeset_acquire_ctx *ctx);//设置属性int (*set_property)(struct drm_crtc *crtc,struct drm_property *property, uint64_t val);//拷贝crtc的drm_crtc_state对象, 一般赋值为drm_atomic_helper_crtc_duplicate_state()struct drm_crtc_state *(*atomic_duplicate_state)(struct drm_crtc *crtc);void (*atomic_destroy_state)(struct drm_crtc *crtc,struct drm_crtc_state *state);//atomic 操作中设置特定属性值到state中,该接口一般可由drm_atomic_set_property调用int (*atomic_set_property)(struct drm_crtc *crtc,struct drm_crtc_state *state,struct drm_property *property,uint64_t val);//获取atomic属性int (*atomic_get_property)(struct drm_crtc *crtc,const struct drm_crtc_state *state,struct drm_property *property,uint64_t *val);//drm_dev_register之后,调用该接口进行额外的crtc操作int (*late_register)(struct drm_crtc *crtc);//与late_register接口相反, 在drm_dev_unregister之前调用void (*early_unregister)(struct drm_crtc *crtc);//以下接口与crc相关int (*set_crc_source)(struct drm_crtc *crtc, const char *source);int (*verify_crc_source)(struct drm_crtc *crtc, const char *source,size_t *values_cnt);const char *const *(*get_crc_sources)(struct drm_crtc *crtc,size_t *count);//打印crtc的atomic state属性值, 一般由drm_atomic_print_state调用void (*atomic_print_state)(struct drm_printer *p,const struct drm_crtc_state *state);//获取硬件vblank counter计数u32 (*get_vblank_counter)(struct drm_crtc *crtc);//使能vblank中断int (*enable_vblank)(struct drm_crtc *crtc);//关闭vbank中断void (*disable_vblank)(struct drm_crtc *crtc);//获取vblank时间戳bool (*get_vblank_timestamp)(struct drm_crtc *crtc,int *max_error,ktime_t *vblank_time,bool in_vblank_irq);
};

4. 应用层的调用

         crtc的设置主要有ACTIVE/MODE_ID属性, 其中MODE_ID属性,是设置其显示时序,常用的设置接口如下:

4.1 drmModeSetCrtc (drmlib库里)---> drm_mode_setcrtc

        该接口设置crtc的显示buf, 连接的connector_id, 显示时序mode, 从代码中可以看出来,该接口绑定fb到crtc时,实际上是绑定该crtc的primary plane上。前面已经介绍了。

http://www.lryc.cn/news/28881.html

相关文章:

  • 用原生js手写分页功能
  • CornerNet介绍
  • 【SpringBoot】日志使用
  • 关于slice扩容性能损耗的探究
  • Java实现单向链表
  • 3月4日,30秒知全网,精选7个热点
  • EXCEL-职业版本(2)
  • java中延时队列的实现
  • 基于java的circle buffer的实现
  • 通用方法——为什么重写equals还要重写hashcode
  • JavaSE学习进阶day2_01 包和权限修饰符
  • Android性能调优 - 省电优化
  • ElasticSearch - SpringBoot整合ES之全文搜索匹配查询 match
  • 句子的改写和扩写
  • DockerFile创建及案例
  • 第十四届蓝桥杯三月真题刷题训练——第 1 天
  • 基于容器云提交spark job任务
  • Linux系统调用之目录操作函数
  • 设计模式-策略模式
  • 面试+算法:罗马数字及Excel列名与数字互相转换
  • Connext DDS路由服务Routing Service(1)
  • 如何使用SaleSmartly进行Facebook Messenger 营销、销售和支持
  • 教资教育知识与能力中学教学
  • IDEA中使用Tomcat的两种方式:集成本地Tomcat使用Tomcat Maven插件
  • IP 地址的简介
  • 3D动作/动画特效
  • python 多线程编程之_thread模块
  • vue:vue2与vue3的区别
  • SQL数据库语法
  • 人机界面艺术设计