本系列文章基于linux 5.15
接着上篇,在提交之前,需要进行check检查,此时会调用drm_atomic_check_only这一函数。
一、drm_atomic_check_only
主要作用是验证原子提交的状态是否合法。它通过检查plane、crtc 和connector的状态,确保这些状态不会导致硬件或软件冲突。如果检查通过,状态可以安全地提交到硬件;否则,返回错误并阻止提交。
int drm_atomic_check_only(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct drm_mode_config *config = &dev->mode_config;
struct drm_plane *plane;
struct drm_plane_state *old_plane_state;
struct drm_plane_state *new_plane_state;
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state;
struct drm_crtc_state *new_crtc_state;
struct drm_connector *conn;
struct drm_connector_state *conn_state;
unsigned int requested_crtc = 0;
unsigned int affected_crtc = 0;
int i, ret = 0;
DRM_DEBUG_ATOMIC("checking %p\n", state);
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
requested_crtc |= drm_crtc_mask(crtc);
for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
/*检查plane的state里面的参数值是否合法*/
ret = drm_atomic_plane_check(old_plane_state, new_plane_state);
if (ret) {
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] atomic core check failed\n",
plane->base.id, plane->name);
return ret;
}
}
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
/*检查crtc的state里面的参数值是否合法*/
ret = drm_atomic_crtc_check(old_crtc_state, new_crtc_state);
if (ret) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] atomic core check failed\n",
crtc->base.id, crtc->name);
return ret;
}
}
for_each_new_connector_in_state(state, conn, conn_state, i) {
/*检查connector的state里面的参数值是否合法*/
ret = drm_atomic_connector_check(conn, conn_state);
if (ret) {
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] atomic core check failed\n",
conn->base.id, conn->name);
return ret;
}
}
/*调用 atomic_check 回调函数,调用该函数进行额外的check。(厂商自己实现)*/
if (config->funcs->atomic_check) {
ret = config->funcs->atomic_check(state->dev, state);
if (ret) {
DRM_DEBUG_ATOMIC("atomic driver check for %p failed: %d\n",
state, ret);
return ret;
}
}
/*如果当前提交不允许模式设置(state->allow_modeset 为 false),
但某个 CRTC 需要完整模式设置(drm_atomic_crtc_needs_modeset 返回 true),则返回错误。*/
if (!state->allow_modeset) {
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (drm_atomic_crtc_needs_modeset(new_crtc_state)) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] requires full modeset\n",
crtc->base.id, crtc->name);
return -EINVAL;
}
}
}
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i)
affected_crtc |= drm_crtc_mask(crtc);
/*判断受影响的 CRTC 与请求的 CRTC 是否一致*/
if (affected_crtc != requested_crtc) {
DRM_DEBUG_ATOMIC("driver added CRTC to commit: requested 0x%x, affected 0x%0x\n",
requested_crtc, affected_crtc);
WARN(!state->allow_modeset, "adding CRTC not allowed without modesets: requested 0x%x, affected 0x%0x\n",
requested_crtc, affected_crtc);
}
return 0;
}
drm_atomic_xxx_check函数是检查plane、crtc、connector相关state内容是否合法,比较简单,报错可以轻松找到问题点,这里不做详述。
1.config->funcs->atomic_check
调用 atomic_check 回调函数,调用该函数进行额外的check,这里都是各大厂商根据自己的驱动进行实现,以rockchip为例,atomic_check回调直接调用了drm_atomic_helper_check函数。
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
.fb_create = rockchip_fb_create,
.output_poll_changed = drm_fb_helper_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
1.1drm_atomic_helper_check
用于在提交原子状态之前对其进行验证和准备。
int drm_atomic_helper_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
int ret;
/*检查并验证原子状态中的 modeset(显示模式设置)部分。
它确保提出的显示配置(例如分辨率、刷新率)是有效的.*/
ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
return ret;
/*如果设备的 mode_config 中启用了 normalize_zpos 标志,该函数会规范化平面的 z-pos(z 轴位置)。
z-pos 决定了平面的堆叠顺序(例如哪个平面显示在另一个平面的上方)。*/
if (dev->mode_config.normalize_zpos) {
ret = drm_atomic_normalize_zpos(dev, state);
if (ret)
return ret;
}
/*检查并验证原子状态中的 平面(plane)部分。
它确保所有平面的配置(例如大小、格式、位置)是有效的。*/
ret = drm_atomic_helper_check_planes(dev, state);
if (ret)
return ret;
/*如果 state->legacy_cursor_update 为真,表示这是一个传统的游标更新。
通过调用 drm_atomic_helper_async_check(dev, state) 检查是否可以异步更新。
如果可以异步更新,state->async_update 被设置为 true,否则为 false。
目前异步还未设计,之后在研究*/
if (state->legacy_cursor_update)
state->async_update = !drm_atomic_helper_async_check(dev, state);
/*与 自刷新(self-refresh)功能相关,用于调整状态以支持自刷新模式。
自刷新是一种节能技术,允许显示器在内容未变化时降低刷新率*/
drm_self_refresh_helper_alter_state(state);
return ret;
}
1.1.1drm_atomic_helper_check_modeset
int drm_atomic_helper_check_modeset(struct drm_device *dev,
struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
struct drm_connector *connector;
struct drm_connector_state *old_connector_state, *new_connector_state;
int i, ret;
unsigned int connectors_mask = 0;
/*检查 CRTC 的状态变化:
a.遍历所有的 CRTC(显示控制器),检查它们的模式、启用状态、激活状态等是否发生了变化。
b.如果 CRTC 的模式发生了变化,标记 mode_changed 为 true。
c.如果 CRTC 的启用状态发生了变化,标记 mode_changed 和 connectors_changed 为 true。
d.如果 CRTC 的激活状态发生了变化,标记 active_changed 为 true。
e.如果 CRTC 的启用状态与连接的连接器(connector)不匹配,返回错误。*/
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
bool has_connectors =
!!new_crtc_state->connector_mask;
WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
if (!drm_mode_equal(&old_crtc_state->mode, &new_crtc_state->mode)) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode changed\n",
crtc->base.id, crtc->name);
new_crtc_state->mode_changed = true;
}
if (old_crtc_state->enable != new_crtc_state->enable) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enable changed\n",
crtc->base.id, crtc->name);
new_crtc_state->mode_changed = true;
new_crtc_state->connectors_changed = true;
}
if (old_crtc_state->active != new_crtc_state->active) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] active changed\n",
crtc->base.id, crtc->name);
new_crtc_state->active_changed = true;
}
if (new_crtc_state->enable != has_connectors) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] enabled/connectors mismatch\n",
crtc->base.id, crtc->name);
return -EINVAL;
}
if (drm_dev_has_vblank(dev))
new_crtc_state->no_vblank = false;
else
new_crtc_state->no_vblank = true;
}
/*确保没有多个连接器试图使用同一个编码器*/
ret = handle_conflicting_encoders(state, false);
if (ret)
return ret;
for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
/*更新connector的路由信息 */
ret = update_connector_routing(state, connector,
old_connector_state,
new_connector_state);
if (ret)
return ret;
if (old_connector_state->crtc) {
new_crtc_state = drm_atomic_get_new_crtc_state(state,
old_connector_state->crtc);
/*如果connector的链路状态或max_requested_bpc(每像素位数)发生了变化,
标记相关的 CRTC 的 connectors_changed 为 true。*/
if (old_connector_state->link_status !=
new_connector_state->link_status)
new_crtc_state->connectors_changed = true;
if (old_connector_state->max_requested_bpc !=
new_connector_state->max_requested_bpc)
new_crtc_state->connectors_changed = true;
}
/*调用drm_connector_helper_funcs的funcs->atomic_check回调,厂商自己实现*/
if (funcs->atomic_check)
ret = funcs->atomic_check(connector, state);
if (ret)
return ret;
connectors_mask |= BIT(i);
}
/*对于需要模式变更的 CRTC,添加所有受影响的coonector和plane到原子状态中 */
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
continue;
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] needs all connectors, enable: %c, active: %c\n",
crtc->base.id, crtc->name,
new_crtc_state->enable ? 'y' : 'n',
new_crtc_state->active ? 'y' : 'n');
/*用于将一个 CRTC(显示控制器)所影响的所有连接器(connector)添加到原子状态(drm_atomic_state)中。
它的主要作用是在原子提交(atomic commit)过程中,确保所有与 CRTC 相关的connector都被正确地包含在状态更新中。*/
ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret != 0)
return ret;
/*用于将一个 CRTC(显示控制器)所影响的所有plane添加到原子状态(drm_atomic_state)中。
它的主要作用是在原子提交(atomic commit)过程中,确保所有与 CRTC 相关的plane都被正确地包含在状态更新中。*/
ret = drm_atomic_add_affected_planes(state, crtc);
if (ret != 0)
return ret;
}
/*调用未受影响的connector的drm_connector_helper_funcs的funcs->atomic_check回调 */
for_each_oldnew_connector_in_state(state, connector, old_connector_state, new_connector_state, i) {
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
if (connectors_mask & BIT(i))
continue;
if (funcs->atomic_check)
ret = funcs->atomic_check(connector, state);
if (ret)
return ret;
}
/*为给定的 drm_encoder 添加所有相关的桥接(bridge)到原子状态(drm_atomic_state)中,bridge的作用是啥,后续研究*/
for_each_oldnew_connector_in_state(state, connector,
old_connector_state,
new_connector_state, i) {
struct drm_encoder *encoder;
encoder = old_connector_state->best_encoder;
ret = drm_atomic_add_encoder_bridges(state, encoder);
if (ret)
return ret;
encoder = new_connector_state->best_encoder;
ret = drm_atomic_add_encoder_bridges(state, encoder);
if (ret)
return ret;
}
/*用于验证显示模式(drm_display_mode)是否适用于给定的 DRM(Direct Rendering Manager)connector、encoder和 crtc*/
ret = mode_valid(state);
if (ret)
return ret;
/*用于处理显示模式调整和验证的关键函数*/
return mode_fixup(state);
}
1.1.1.1handle_conflicting_encoders
用于处理encoder冲突的关键函数。它通过两个循环来检测并解决encoder的冲突,确保显示配置的正确性和有效性。避免多个连接器(Connector)使用同一个编码器(encoder)。
static int handle_conflicting_encoders(struct drm_atomic_state *state,
bool disable_conflicting_encoders)
{
struct drm_connector_state *new_conn_state;
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct drm_encoder *encoder;
unsigned int encoder_mask = 0;
int i, ret = 0;
/*遍历新的connector,对于每个连接器(connector),检查是否有有效的 crtc。
a.如果没有有效的 CRTC,则跳过该连接器。
b.如果有有效的 CRTC,则调用连接器的 atomic_best_encoder 或 best_encoder 回调函数,获取最佳的编码器。
c.如果没有找到编码器,则尝试获取连接器的单一编码器。
d.如果找到编码器,则检查该编码器是否已经被其他连接器使用。如果已经被使用,则返回错误。
e.如果没有冲突,则将该编码器添加到 encoder_mask 中。*/
for_each_new_connector_in_state(state, connector, new_conn_state, i) {
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_encoder *new_encoder;
if (!new_conn_state->crtc)
continue;
if (funcs->atomic_best_encoder)
new_encoder = funcs->atomic_best_encoder(connector,
state);
else if (funcs->best_encoder)
new_encoder = funcs->best_encoder(connector);
else
new_encoder = drm_connector_get_single_encoder(connector);
if (new_encoder) {
if (encoder_mask & drm_encoder_mask(new_encoder)) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] on [CONNECTOR:%d:%s] already assigned\n",
new_encoder->base.id, new_encoder->name,
connector->base.id, connector->name);
return -EINVAL;
}
encoder_mask |= drm_encoder_mask(new_encoder);
}
}
if (!encoder_mask)
return 0;
/*遍历所有不在当前状态中的连接器,对于每个连接器,检查是否有有效的编码器,并且该编码器是否在 encoder_mask 中。
a.如果没有有效的编码器或编码器不在 encoder_mask 中,则跳过该连接器。
b.如果有冲突的编码器,并且 disable_conflicting_encoders 参数为 false,则返回错误。
c.如果 disable_conflicting_encoders 参数为 true,则获取连接器的新状态,并将其从当前的 CRTC 中移除。
d.如果移除连接器后,CRTC 没有其他连接器,则禁用该 CRTC。 */
drm_connector_list_iter_begin(state->dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct drm_crtc_state *crtc_state;
if (drm_atomic_get_new_connector_state(state, connector))
continue;
encoder = connector->state->best_encoder;
if (!encoder || !(encoder_mask & drm_encoder_mask(encoder)))
continue;
if (!disable_conflicting_encoders) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s] by [CONNECTOR:%d:%s]\n",
encoder->base.id, encoder->name,
connector->state->crtc->base.id,
connector->state->crtc->name,
connector->base.id, connector->name);
ret = -EINVAL;
goto out;
}
new_conn_state = drm_atomic_get_connector_state(state, connector);
if (IS_ERR(new_conn_state)) {
ret = PTR_ERR(new_conn_state);
goto out;
}
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] in use on [CRTC:%d:%s], disabling [CONNECTOR:%d:%s]\n",
encoder->base.id, encoder->name,
new_conn_state->crtc->base.id, new_conn_state->crtc->name,
connector->base.id, connector->name);
crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
ret = drm_atomic_set_crtc_for_connector(new_conn_state, NULL);
if (ret)
goto out;
if (!crtc_state->connector_mask) {
ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
NULL);
if (ret < 0)
goto out;
crtc_state->active = false;
}
}
out:
drm_connector_list_iter_end(&conn_iter);
return ret;
}
1.1.1.2update_connector_routing
用于更新连接器路由信息的关键函数。它通过处理 CRTC 的变化、选择最佳编码器、检查兼容性等步骤,确保连接器的路由信息能够正确更新。
static int update_connector_routing(struct drm_atomic_state *state,
struct drm_connector *connector,
struct drm_connector_state *old_connector_state,
struct drm_connector_state *new_connector_state)
{
const struct drm_connector_helper_funcs *funcs;
struct drm_encoder *new_encoder;
struct drm_crtc_state *crtc_state;
DRM_DEBUG_ATOMIC("Updating routing for [CONNECTOR:%d:%s]\n",
connector->base.id,
connector->name);
if (old_connector_state->crtc != new_connector_state->crtc) {
if (old_connector_state->crtc) {
crtc_state = drm_atomic_get_new_crtc_state(state, old_connector_state->crtc);
crtc_state->connectors_changed = true;
}
if (new_connector_state->crtc) {
crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc);
crtc_state->connectors_changed = true;
}
}
if (!new_connector_state->crtc) {
DRM_DEBUG_ATOMIC("Disabling [CONNECTOR:%d:%s]\n",
connector->base.id,
connector->name);
set_best_encoder(state, new_connector_state, NULL);
return 0;
}
crtc_state = drm_atomic_get_new_crtc_state(state,
new_connector_state->crtc);
if (!state->duplicated && drm_connector_is_unregistered(connector) &&
crtc_state->active) {
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n",
connector->base.id, connector->name);
return -EINVAL;
}
funcs = connector->helper_private;
/*调用连接器的 atomic_best_encoder 或 best_encoder 回调函数,选择最佳的编码器。
如果没有找到合适的编码器,则返回错误。*/
if (funcs->atomic_best_encoder)
new_encoder = funcs->atomic_best_encoder(connector, state);
else if (funcs->best_encoder)
new_encoder = funcs->best_encoder(connector);
else
new_encoder = drm_connector_get_single_encoder(connector);
if (!new_encoder) {
DRM_DEBUG_ATOMIC("No suitable encoder found for [CONNECTOR:%d:%s]\n",
connector->base.id,
connector->name);
return -EINVAL;
}
if (!drm_encoder_crtc_ok(new_encoder, new_connector_state->crtc)) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] incompatible with [CRTC:%d:%s]\n",
new_encoder->base.id,
new_encoder->name,
new_connector_state->crtc->base.id,
new_connector_state->crtc->name);
return -EINVAL;
}
/*如果选择的编码器与当前的最佳编码器相同,则直接返回。
如果选择的编码器与当前的最佳编码器不同,则调用 steal_encoder 函数,将该编码器从其他连接器中“偷”过来。
更新连接器的最佳编码器,并标记 CRTC 状态为 connectors_changed*/
if (new_encoder == new_connector_state->best_encoder) {
set_best_encoder(state, new_connector_state, new_encoder);
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d:%s]\n",
connector->base.id,
connector->name,
new_encoder->base.id,
new_encoder->name,
new_connector_state->crtc->base.id,
new_connector_state->crtc->name);
return 0;
}
steal_encoder(state, new_encoder);
set_best_encoder(state, new_connector_state, new_encoder);
crtc_state->connectors_changed = true;
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n",
connector->base.id,
connector->name,
new_encoder->base.id,
new_encoder->name,
new_connector_state->crtc->base.id,
new_connector_state->crtc->name);
return 0;
}
1.1.1.3funcs->atomic_check
调用drm_connector_helper_funcs的funcs->atomic_check回调,厂商自己实现。
1.1.1.4mode_valid
判断encoder、bridge和crtc是否支持给定的显示模式
static enum drm_mode_status mode_valid_path(struct drm_connector *connector,
struct drm_encoder *encoder,
struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
struct drm_bridge *bridge;
enum drm_mode_status ret;
/*检查encoder是否支持给定的显示模式*/
ret = drm_encoder_mode_valid(encoder, mode);
if (ret != MODE_OK) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] mode_valid() failed\n",
encoder->base.id, encoder->name);
return ret;
}
/*检查bridge是否支持给定的显示模式*/
bridge = drm_bridge_chain_get_first_bridge(encoder);
ret = drm_bridge_chain_mode_valid(bridge, &connector->display_info,
mode);
if (ret != MODE_OK) {
DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n");
return ret;
}
/*检查crtc是否支持给定的显示模式*/
ret = drm_crtc_mode_valid(crtc, mode);
if (ret != MODE_OK) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] mode_valid() failed\n",
crtc->base.id, crtc->name);
return ret;
}
return ret;
}
对于drm_xxx_mode_valid,都是调用drm_xxx_helper_funcs的回调xxx_funcs->mode_valid实现,该回调xxx_funcs->mode_valid是由厂商自己实现。
enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
if (!crtc_funcs || !crtc_funcs->mode_valid)
return MODE_OK;
return crtc_funcs->mode_valid(crtc, mode);
}
1.1.1.5mode_fixup
用于处理显示模式调整和验证的关键函数。它通过遍历 crtc 和connector的状态,调用硬件驱动的回调函数来确保显示模式的正确性和有效性。
static int mode_fixup(struct drm_atomic_state *state)
{
struct drm_crtc *crtc;
struct drm_crtc_state *new_crtc_state;
struct drm_connector *connector;
struct drm_connector_state *new_conn_state;
int i;
int ret;
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (!new_crtc_state->mode_changed &&
!new_crtc_state->connectors_changed)
continue;
drm_mode_copy(&new_crtc_state->adjusted_mode, &new_crtc_state->mode);
}
for_each_new_connector_in_state(state, connector, new_conn_state, i) {
const struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc);
if (!new_conn_state->crtc || !new_conn_state->best_encoder)
continue;
new_crtc_state =
drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
encoder = new_conn_state->best_encoder;
funcs = encoder->helper_private;
bridge = drm_bridge_chain_get_first_bridge(encoder);
ret = drm_atomic_bridge_chain_check(bridge,
new_crtc_state,
new_conn_state);
if (ret) {
DRM_DEBUG_ATOMIC("Bridge atomic check failed\n");
return ret;
}
/*检查编码器的drm_encoder_helper_funcs的 atomic_check 或 mode_fixup 回调函数是否存在,
并调用它们来验证或调整显示模式。*/
if (funcs && funcs->atomic_check) {
ret = funcs->atomic_check(encoder, new_crtc_state,
new_conn_state);
if (ret) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] check failed\n",
encoder->base.id, encoder->name);
return ret;
}
} else if (funcs && funcs->mode_fixup) {
ret = funcs->mode_fixup(encoder, &new_crtc_state->mode,
&new_crtc_state->adjusted_mode);
if (!ret) {
DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] fixup failed\n",
encoder->base.id, encoder->name);
return -EINVAL;
}
}
}
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
const struct drm_crtc_helper_funcs *funcs;
if (!new_crtc_state->enable)
continue;
if (!new_crtc_state->mode_changed &&
!new_crtc_state->connectors_changed)
continue;
funcs = crtc->helper_private;
if (!funcs || !funcs->mode_fixup)
continue;
/*检查crtc的drm_crtc_helper_funcs的mode_fixup 回调函数是否存在,
并调用它们来验证或调整显示模式。*/
ret = funcs->mode_fixup(crtc, &new_crtc_state->mode,
&new_crtc_state->adjusted_mode);
if (!ret) {
DRM_DEBUG_ATOMIC("[CRTC:%d:%s] fixup failed\n",
crtc->base.id, crtc->name);
return -EINVAL;
}
}
return 0;
}
以rockchip的drm_crtc_helper_funcs为例,这里vop_crtc_mode_fixup的作用是调整显示模式的时钟频率,以确保硬件能够正确支持该模式。
static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
.mode_fixup = vop_crtc_mode_fixup,
.atomic_check = vop_crtc_atomic_check,
.atomic_begin = vop_crtc_atomic_begin,
.atomic_flush = vop_crtc_atomic_flush,
.atomic_enable = vop_crtc_atomic_enable,
.atomic_disable = vop_crtc_atomic_disable,
};
static bool vop_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct vop *vop = to_vop(crtc);
unsigned long rate;
rate = clk_round_rate(vop->dclk, adjusted_mode->clock * 1000 + 999);
adjusted_mode->clock = DIV_ROUND_UP(rate, 1000);
return true;
}