drm通过DRM_IOCTL_MODE_SETCRTC实现最原始的模式设置和送显操作。
setCrtc的整个流程是围绕的各种state结构,如下图:
注:本图及后述内容没特别说明都是以linux5.4.162的源码版本为准。
drm_mode_setcrtc是DRM_IOCTL_MODE_SETCRTC的处理函数。其源码如下:
int drm_mode_setcrtc(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
# 略略略... ...
mutex_lock(&crtc->dev->mode_config.mutex);
//构建struct drm_mode_set set
# 略略略... ...
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;
//执行set_config操作
if (drm_drv_uses_atomic_modeset(dev))
ret = crtc->funcs->set_config(&set, &ctx);
else
ret = __drm_mode_set_config_internal(&set, &ctx);
out:
# 略略略... ...
mutex_unlock(&crtc->dev->mode_config.mutex);
# 略略略... ...
}
整个函数流程概况:
drm_atomic_helper_set_config函数是drm_crtc_funcs的set_config回调默认实现函数。关键源码如下:
int drm_atomic_helper_set_config(struct drm_mode_set *set,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_atomic_state *state;
struct drm_crtc *crtc = set->crtc;
int ret = 0;
state = drm_atomic_state_alloc(crtc->dev);
if (!state)
return -ENOMEM;
state->acquire_ctx = ctx;
ret = __drm_atomic_helper_set_config(set, state);
if (ret != 0)
goto fail;
ret = handle_conflicting_encoders(state, true);
if (ret)
goto fail;
ret = drm_atomic_commit(state);
fail:
drm_atomic_state_put(state);
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_set_config);
整个函数流程概况:
drm_atomic_helper_commit是drm_mode_config_funcs的atomic_commit回调的默认实现函数。关键源码如下:
int drm_atomic_helper_commit(struct drm_device *dev,
struct drm_atomic_state *state,
bool nonblock) //noblock = false
{
# 略去代码块if (state->async_update)... ...
ret = drm_atomic_helper_setup_commit(state, nonblock);
if (ret)
return ret;
# 略去INIT_WORK代码... ...
ret = drm_atomic_helper_prepare_planes(dev, state);
if (ret)
return ret;
if (!nonblock) {
ret = drm_atomic_helper_wait_for_fences(dev, state, true);
if (ret)
goto err;
}
ret = drm_atomic_helper_swap_state(state, true);
if (ret)
goto err;
drm_atomic_state_get(state);
if (nonblock)
# 略去queue_work代码... ...
else
commit_tail(state);
return 0;
err:
drm_atomic_helper_cleanup_planes(dev, state);
return ret;
}
整个函数流程概况:
在该函数中,完成最后的提交动作。关键源码如下:
static void commit_tail(struct drm_atomic_state *old_state)
{
# 略略略... ...
drm_atomic_helper_wait_for_fences(dev, old_state, false);
drm_atomic_helper_wait_for_dependencies(old_state);
# 略略略... ...
if (funcs && funcs->atomic_commit_tail)
funcs->atomic_commit_tail(old_state);
else
drm_atomic_helper_commit_tail(old_state);
# 略略略... ...
drm_atomic_helper_commit_cleanup_done(old_state);
drm_atomic_state_put(old_state);
}
整个函数流程概况:
drm_atomic_helper_commit_tail是drm_mode_config_helper_funcs的atomic_commit_tail回调的默认实现函数。关键源码如下:
void drm_atomic_helper_commit_tail(struct drm_atomic_state *old_state)
{
struct drm_device *dev = old_state->dev;
drm_atomic_helper_commit_modeset_disables(dev, old_state);
drm_atomic_helper_commit_planes(dev, old_state, 0);
drm_atomic_helper_commit_modeset_enables(dev, old_state);
drm_atomic_helper_fake_vblank(old_state);
drm_atomic_helper_commit_hw_done(old_state);
drm_atomic_helper_wait_for_vblanks(dev, old_state);
drm_atomic_helper_cleanup_planes(dev, old_state);
}
整个函数流程概况:
drm_atomic_helper_commit_modeset_disables函数用于对上一次的状态设置做disable和复位,同时对当前的state使能。源码如下:
void drm_atomic_helper_commit_modeset_disables(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
disable_outputs(dev, old_state);
drm_atomic_helper_update_legacy_modeset_state(dev, old_state);
crtc_set_mode(dev, old_state);
}
整个函数流程概况:
该函数是硬件提交的核心函数,其源码如下:
void drm_atomic_helper_commit_planes(struct drm_device *dev,
struct drm_atomic_state *old_state,
uint32_t flags)
{
# 略略略... ...
for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
funcs = crtc->helper_private;
if (!funcs || !funcs->atomic_begin)
continue;
if (active_only && !new_crtc_state->active)
continue;
funcs->atomic_begin(crtc, old_crtc_state);
}
for_each_oldnew_plane_in_state(old_state, plane, old_plane_state, new_plane_state, i) {
const struct drm_plane_helper_funcs *funcs;
bool disabling;
funcs = plane->helper_private;
if (!funcs)
continue;
disabling = drm_atomic_plane_disabling(old_plane_state,
new_plane_state);
# 略去代码块if (active_only) ... ...
if (disabling && funcs->atomic_disable) {
# 略略略... ...
funcs->atomic_disable(plane, old_plane_state);
} else if (new_plane_state->crtc || disabling) {
funcs->atomic_update(plane, old_plane_state);
}
}
for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
funcs = crtc->helper_private;
if (!funcs || !funcs->atomic_flush)
continue;
if (active_only && !new_crtc_state->active)
continue;
funcs->atomic_flush(crtc, old_crtc_state);
}
}
整个函数流程概况:
该函数做硬件的真正使能动作。其核心源码如下:
void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
struct drm_atomic_state *old_state)
{
# 略略略... ...
for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
/* Need to filter out CRTCs where only planes change. */
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
continue;
if (!new_crtc_state->active)
continue;
funcs = crtc->helper_private;
if (new_crtc_state->enable) {
DRM_DEBUG_ATOMIC("enabling [CRTC:%d:%s]\n",
crtc->base.id, crtc->name);
if (funcs->atomic_enable)
funcs->atomic_enable(crtc, old_crtc_state);
else if (funcs->commit)
funcs->commit(crtc);
}
}
for_each_new_connector_in_state(old_state, connector, new_conn_state, i) {
const struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
if (!new_conn_state->best_encoder)
continue;
if (!new_conn_state->crtc->state->active ||
!drm_atomic_crtc_needs_modeset(new_conn_state->crtc->state))
continue;
# 略略略... ...
if (funcs) {
if (funcs->atomic_enable)
funcs->atomic_enable(encoder, old_state);
else if (funcs->enable)
funcs->enable(encoder);
else if (funcs->commit)
funcs->commit(encoder);
}
# 略略略... ...
}
# 略略略... ...
}
整个函数流程概况:
以drm_crtc_state为例(其他的类似),整个过程的状态变化如下: