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);
};