DRM框架(vkms)分析(4)----encoder初始化

本文

主要分析encoder的初始化和配置,drm_encoder结构体如下:

/**
 * struct drm_encoder - central DRM encoder structure
 * @dev: parent DRM device
 * @head: list management
 * @base: base KMS object
 * @name: human readable name, can be overwritten by the driver
 * @funcs: control functions, can be NULL for simple managed encoders
 * @helper_private: mid-layer private data
 *
 * CRTCs drive pixels to encoders, which convert them into signals
 * appropriate for a given connector or set of connectors.
 */
struct drm_encoder {
	struct drm_device *dev;
	struct list_head head;

	struct drm_mode_object base;
	char *name;
	/**
	 * @encoder_type:
	 *
	 * One of the DRM_MODE_ENCODER_ types in drm_mode.h. The following
	 * encoder types are defined thus far:
	 *
	 * - DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A.
	 *
	 * - DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort.
	 *
	 * - DRM_MODE_ENCODER_LVDS for display panels, or in general any panel
	 *   with a proprietary parallel connector.
	 *
	 * - DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video,
	 *   Component, SCART).
	 *
	 * - DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
	 *
	 * - DRM_MODE_ENCODER_DSI for panels connected using the DSI serial bus.
	 *
	 * - DRM_MODE_ENCODER_DPI for panels connected using the DPI parallel
	 *   bus.
	 *
	 * - DRM_MODE_ENCODER_DPMST for special fake encoders used to allow
	 *   mutliple DP MST streams to share one physical encoder.
	 */
	int encoder_type;

	/**
	 * @index: Position inside the mode_config.list, can be used as an array
	 * index. It is invariant over the lifetime of the encoder.
	 */
	unsigned index;

	/**
	 * @possible_crtcs: Bitmask of potential CRTC bindings, using
	 * drm_crtc_index() as the index into the bitfield. The driver must set
	 * the bits for all &drm_crtc objects this encoder can be connected to
	 * before calling drm_dev_register().
	 *
	 * You will get a WARN if you get this wrong in the driver.
	 *
	 * Note that since CRTC objects can't be hotplugged the assigned indices
	 * are stable and hence known before registering all objects.
	 */
	uint32_t possible_crtcs;

	uint32_t possible_clones;

	/**
	 * @crtc: Currently bound CRTC, only really meaningful for non-atomic
	 * drivers.  Atomic drivers should instead check
	 * &drm_connector_state.crtc.
	 */
	struct drm_crtc *crtc;

	/**
	 * @bridge_chain: Bridges attached to this encoder. Drivers shall not
	 * access this field directly.
	 */
	struct list_head bridge_chain;

	const struct drm_encoder_funcs *funcs;
	const struct drm_encoder_helper_funcs *helper_private;
};

一 drm_encoder初始化

drm_encoder实例一般通过drm_simple_encoder_init简化接口进行初始化,通过drm_encoder_helper_add增加helper回调,并在connector初始化后,通过drm_connector_attach_encoder绑定到crtc上。


//zynqmp dp
zynqmp_dp_drm_init
    //设置encoder支持的crtc
    encoder->possible_crtcs != zynpmq_disp_get_crtc(dpsub->disp);
    //初始化drm_encoder实例
    drm_simple_encoder_init(dp->drm, encoder, DRM_MODE_ENCODER_TMDS);
        //初始化drm_encoder实例, 
        drm_encoder_init(dev, encoder, 
                &drm_simple_encoder_funcs_cleanup, encoder_type, NULL);
             __drm_encoder_init()
                    //记录encoder_type
                    encoder->encoder_type = encoder_type
                    //初始化encoder->funcs
                    encoder->funcs = funcs //drm_simple_encoder_funcs_cleanup
                    //将drm_encoder实例添加到mode_config.encoder_list链表
                    list_add_tail(&encoder->head, &dev->mode_config.encoder_list)
                   //初始化encoder序号
                    encoder->index = dev->mode_config.num_encoder++;

//初始化encoder->helper_private
drm_encoder_helper_add(encoder, &zynqmp_dp_encoder_helper_funcs)
        encoder->helper_private = funcs ;//zynqmp_dp_encoder_helper_funcs

二 drm_encoder.funcs

drm_encoder_funcs结构体比较简单,如下:


struct drm_encoder_funcs {
    //通过drm_mode_config_reset调用
	void (*reset)(struct drm_encoder *encoder);
    //通过drm_mode_config_cleanup调用
	void (*destroy)(struct drm_encoder *encoder);
    //如下两个接口很少有encoder实现
    //drm_dev_register阶段调用,用于注册额外的用户空间接口,如debugfs等
	int (*late_register)(struct drm_encoder *encoder);
    //drm_dev_unregister阶段调用
	void (*early_unregister)(struct drm_encoder *encoder);
};

drm_simple_encoder_init初始化接口,drm_encoder.funcs = drm_simple_encoder_funcs_cleanup,该实例仅仅初始化了destroy成员

drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
        .destroy = drm_encoder_cleanup,
    }

三 drm_encoder.helper_private

helper回调接口,通过drm_encoder_helper_add赋值

/**
 * struct drm_encoder_helper_funcs - helper operations for encoders
 *
 * These hooks are used by the legacy CRTC helpers, the transitional plane
 * helpers and the new atomic modesetting helpers.
 */
struct drm_encoder_helper_funcs {
	/**
	 * @dpms:
        drm_helper_connector_dpms会调用其绑定的drm_encoder实例,进一步通过
        drm_helper_encoder_dmps调用该dpms接口
	 */
	void (*dpms)(struct drm_encoder *encoder, int mode);

	/**
	 * @mode_valid:
      验证output mode的有效性, 通过drm_helper_probe_single_connector_modes()或者
        drm_atomic_helper_check_modeset调用
	 */
	enum drm_mode_status (*mode_valid)(struct drm_encoder *crtc,
					   const struct drm_display_mode *mode);

	/**
	 * @mode_fixup:
	     修正output mode, drm_atomic_helper_check_modeset会调用
	 */
	bool (*mode_fixup)(struct drm_encoder *encoder,
			   const struct drm_display_mode *mode,
			   struct drm_display_mode *adjusted_mode);

	/**
	 * @prepare:
	 * 如果encoder正在运行,此时进行modeset需要通过该接口关掉,
        一般情况下通过调用dpms接口(DRM_MODE_DPMS_OFF)实现
        Atomic helpers接口使用@disable替代
	 */
	void (*prepare)(struct drm_encoder *encoder);

	/**
	 * @commit:
	 * 该接口是在完成modeset之后,调用该接口打开encoder, 大部分驱动的该接口实现是
        进一步调用其dmps(参数DRM_MODE_DPMS_ON), Atomic helpers接口使用@enable替代
	 */
	void (*commit)(struct drm_encoder *encoder);

	/**
	 * @mode_set:
	 *
	 * 设置encoder的 display mode, crtc_set_mode接口中会调用
	 */
	void (*mode_set)(struct drm_encoder *encoder,
			 struct drm_display_mode *mode,
			 struct drm_display_mode *adjusted_mode);

	/**
	 * @atomic_mode_set:
	    atomic modeset helpers 使用该接口替代mode_set, crtc_set_mode接口中会调用
	void (*atomic_mode_set)(struct drm_encoder *encoder,
				struct drm_crtc_state *crtc_state,
				struct drm_connector_state *conn_state);

	/**
	 * @detect:
	 * 使用比较少,不做分析
	 */
	enum drm_connector_status (*detect)(struct drm_encoder *encoder,
					    struct drm_connector *connector);

	/**
	 * @atomic_disable:
        关闭encoder, 优先级比disable接口高, crtc_needs_disable接口中调用
        
	 */
	void (*atomic_disable)(struct drm_encoder *encoder,
			       struct drm_atomic_state *state);

	/**
	 * @atomic_enable:
	    使用encoder,优先级比enable高, drm_atomic_helper_commit_modeset_enables中调用
	 */
	void (*atomic_enable)(struct drm_encoder *encoder,
			      struct drm_atomic_state *state);

	/**
	 * @disable:
	 *
	 关闭encoder, 优先级比atomic_disable接口低, crtc_needs_disable接口中调用
	 */
	void (*disable)(struct drm_encoder *encoder);

	/**
	 * @enable:
	 使用encoder,优先级比atomic_enable低, drm_atomic_helper_commit_modeset_enables中调用
	 */
	void (*enable)(struct drm_encoder *encoder);

	/**
	 * @atomic_check:
           检查encoder state
	 */
	int (*atomic_check)(struct drm_encoder *encoder,
			    struct drm_crtc_state *crtc_state,
			    struct drm_connector_state *conn_state);
};

(1)mode_valid && mode_fixup

调用逻辑如下:

其中注意到mode_fixup和atomic_check其实做了相同的事情,只是atomic_check优先级更高

drm_atomic_helper_check   //一般被赋值给drm_mode_config_funcs.atomic_check
    drm_atomic_helper_check_modeset
           ret = mode_valid(state)
                    mode_valid_path
                        drm_encoder_mode_valid
                                //encoder侧验证mode的有效性
                                encoder_funcs = encoder->helper_private
                                encoder_funcs->mode_valid(encoder, mode);
            mode_fixup(state)
                //encoder侧修正mode
                funcs = encoder->helper_private
                //优先调用atomic_check
                if ( funcs && funcs->atomic_check )
                    ret = funcs->atomic_check()
                //其次调用mode_fixup
                else if ( funcs & funcs->mode_fixup )
                    ret = funcs->mode_fixup()
            
                funcs->mode_fixup(...)

(2)atomic_mode_set && mode_set

用来设置encoder的display mode, 这两个接口会在crtc_set_mode接口中调用, 优先使用atomic_mode_set, 如果其未被实现,才会使用mode_set

drm_mode_config_helper_funcs vkms_mode_config_helper = {

    .atomic_commit_tail = vkms_atomic_commit_tail;
}

//vkms_atomic_commit_tail
        drm_atomic_helper_commit_modeset_disables
            crtc_set_mode
                funcs = encoder->helper_private
                //优先使用atomic_mode_set
                if (funcs && funcs->atomic_mode_set)
                        funcs->atomic_mode_set()
                else if (funcs && funcs->mode_set)
                        funcs->mode_set
//由上述调用流程也可以看出这个是在commit阶段调用的

(3)atomic_disable && disable

从下面的代码逻辑中,我们可以看出atomic_disable/disable/prepare/dpms其实都可以实现关闭encoder的作用,其优先级依次是atomic_disable > prepare > disable  > dpms

drm_mode_config_helper_funcs vkms_mode_config_helper = {

    .atomic_commit_tail = vkms_atomic_commit_tail;
}

//vkms_atomic_commit_tail
        drm_atomic_helper_commit_modeset_disables
            //关掉输出
            disable_outputs
                funcs = encoder->helper_private
                //优先调用atomic_disable
                if ( funcs->atomic_disable )
                    funcs->atomic_disable(encode, old_state)
                //其次调用preparedisable
                else if (new_conn_state->crtc && funcs->prepare)
                    funcs->prepare(encoder)
                //其次调用disable
                else if (funcs->disable)
                    funcs->disable(encoder)
                //其次调用dpms
                else if (funcs->dpms)
                    funcs->dpms(encoder, DRM_MODE_DPMS_OFF)    

(4)atomic_enable && enable

使能encoder,调用逻辑如下:

从下面的逻辑可以看出使用encoder有三种接口,其优先级依次为:

atomic_enable > enable > commit

drm_mode_config_helper_funcs vkms_mode_config_helper = {

    .atomic_commit_tail = vkms_atomic_commit_tail;
}

//vkms_atomic_commit_tail
        drm_atomic_helper_commit_modeset_enables
           funcs = encoder->helper_private
                //优先调用atomic_enable
                if ( funcs->atomic_enable )
                    funcs->atomic_enable(encode, old_state)
                //其次调用enable
                else if (funcs->enable)
                    funcs->enable(encoder)
                //其次调用commit
                else if (funcs->commit)
                    funcs->commit(encoder)

(5)atomic_check

检查encoder的state, 注意到与mode_fixup功能相同,优先级更高

drm_atomic_helper_check   //一般被赋值给drm_mode_config_funcs.atomic_check
    drm_atomic_helper_check_modeset
           ret = mode_valid(state)
                    mode_valid_path
                        drm_encoder_mode_valid
                                //encoder侧验证mode的有效性
                                encoder_funcs = encoder->helper_private
                                encoder_funcs->mode_valid(encoder, mode);
            mode_fixup(state)
                //encoder侧修正mode
                funcs = encoder->helper_private
                //优先调用atomic_check
                if ( funcs && funcs->atomic_check )
                    ret = funcs->atomic_check()
                //其次调用mode_fixup
                else if ( funcs & funcs->mode_fixup )
                    ret = funcs->mode_fixup()
            
                funcs->mode_fixup(...)

你可能感兴趣的:(DRM子系统,drm)