DRM框架(vkms)分析(5)----crtc初始化

drm_crtc结构体类型如下:

/**
 * struct drm_crtc - central CRTC control structure
 *
 * Each CRTC may have one or more connectors associated with it.  This structure
 * allows the CRTC to be controlled.
 */
struct drm_crtc {
	/*挂载到&drm_mode_config.crtc_list*/
	struct list_head head;
	/** crtc名称 */
	char *name;
	/** kms mode对象 */
	struct drm_mode_object base;
	/*primary层*/
	struct drm_plane *primary;
	/*鼠标层*/
	struct drm_plane *cursor;
	/*序号*/
	unsigned index;

	int cursor_x;
	int cursor_y;

	/*使用drm_atomic_helper_update_legacy_modeset_state更新*/
	bool enabled;
	/*显示时序,通过drm_atomic_helper_update_legacy_modeset_state()更新*/
	struct drm_display_mode mode;
	struct drm_display_mode hwmode;
	int x;
	int y;

	/*crtc 的funcs*/
	const struct drm_crtc_funcs *funcs;

    //gamma相关参数
	uint32_t gamma_size;
	uint16_t *gamma_store;

	/*驱动自定义的helper函数*/
	const struct drm_crtc_helper_funcs *helper_private;

	/*crtc的属性 */
	struct drm_object_properties properties;
	struct drm_property *scaling_filter_property;

	/*crtc的state*/
	struct drm_crtc_state *state;

	/*记录commit链表*/
	struct list_head commit_list;

};

一 drm_crtc初始化

drm_crtc_init_with_planes
    __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs, ...)
        crtc->funcs = funcs //初始化funcs (如赋值struct drm_crtc_funcs vkms_crtc_funs)
        //创建DRM_MODE_OBJECT_CRTC类型的drm_mode_object对象实例
        ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC)
        //将crtc->head添加到config->crtc_list中、
        list_add_tail(&crtc->head, &config->crtc_list)
        crtc->primary = primary //初始化primary plane
        crtc->cursor = cursor //初始化 cursor plane
        //将config中创建的prop_active等属性绑定到crtc->base(drm_mode_object对象);
        drm_object_attach_property(&crtc->base, config->prop_active, 0);
//赋值crtc->helper_private
drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs);
        crtc->helper_private = funcs; //vkms_crtc_helper_funcs

二 常用属性设置

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

(1)drmModeSetCrtc

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

//用户态
drmModeSetCrtc
    DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
//内核态
drm_mode_setcrtc
    //将用户态传过来的mode, fb, connector等组装为drm_mode_set;
    struct drm_mode_set set;
    set.crtc = crtc;
    set.mode =mode;
    set.connectors = connector_set;
    set.fb = fb;
    if ( drm_drv_uses_atomic_modeset(dev))
        //支持atomic操作
        ret = crtc->funcs->set_config(&set, &ctx);//drm_atomic_helper_set_config
        //drm_atomic_helper_set_config
        state = drm_atomic_state_alloc();//创建drm_atomic_state实例
        //将mode, fb connector等参数转换为drm_atomic_state的各参数
        ret = __drm_atomic_helper_set_config(set, state);
        //处理冲突的encoders
        handle_conficting_encoders(state, true);
        //提交state, 具体逻辑后续分析
        ret = drm_atomic_commit(state);
    else
        //legacy操作
        ret = drm_mode_set_config_internal(&set, &ctx);
                fb = set->fb
                //调用crtc的set_config回调
                ret = crtc->funcs->set_config(set,ctx);
                struct drm_plane *plane = crtc->primary;
                plane->fb =fb;  //从这里可看出,crtc的fb默认是设置到绑定的primary plane上

(2)atomic modeseting

atomic操作方式,设置crtc的ative mode等属性

//用户态
drmModeAtomicReq *req = drmModeAtomicAlloc();
//设置crtc_id的active属性为1
drmModeAtomicAddProperty(req, crtc_id, property_active, 1);
//根据modes创建一个blob属性对象,目的是为了给crtc_id的mode属性赋值
drmModeCreatePropertyBlob(fd, &conn->modes[0], sizeof(conn->modes[0]), &blob_id);
//将blob_id赋值给crtc_id的mode属性
drmModeAtomicAddProperty(req, crtc_id, property_mode_id, blob_id);
//提交设置的属性
drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOC_MODESET, NULL);
    DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic)
//内核态
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER)
        //遍历设置各crtc/plane/connector等的属性值
        for ( i = 0; i < arg->count_objs; i++ )
            //根据obj_id找到crtc/p;ane/connector等drm_mode_object实例
            obj = drm_mode_object_find(obj_id)
            for (j=0; j< count_props; j++)
                //根据prop_id在对应的drm_mode_object实例中找到其drm_property属性实例
                prop = drm_mode_object_find_prop_id(obj, prop_id)
                //设置各obj的prop值到state中,注意这里只是统一设置到state中,并没有写到硬件
                ret = drm_atomic_set_property(state, obj, prop, prop_value)
        //提交state
        drm_atomic_commit(state);

三 drm_crtc.func


//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类似,但该接口会等待特定的vbank
	int (*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);
};

四 drm_crtc.helper_private


//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);
    //关闭crtc
	void (*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 crtc
	void (*atomic_enable)(struct drm_crtc *crtc,
			      struct drm_atomic_state *state);

    atomic disable crtc
	void (*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);
};
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值