DRM系列十:Drm之drm_atomic_check_only

本系列文章基于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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值