Linux内核4.14版本——drm框架分析(16)——drm_atomic_commit之atomic_commit

目录

1. drm_atomic_helper_commit

1.1 drm_atomic_helper_swap_state

1.2 commit_tail

2. drm_atomic_helper_commit_tail

2.1 drm_atomic_helper_commit_modeset_disables

 2.2 drm_atomic_helper_commit_planes

 2.3 drm_atomic_helper_commit_modeset_enables

2.4 drm_atomic_helper_commit_hw_done

2.5 drm_atomic_helper_wait_for_vblanks

3. 流程图

4. 参考文章


        前文分析了drm_atomic_check_only,本文分析一下config->funcs->atomic_commit(state->dev, state, false);

int drm_atomic_commit(struct drm_atomic_state *state)
{
	struct drm_mode_config *config = &state->dev->mode_config;
	int ret;
 
	ret = drm_atomic_check_only(state);
	if (ret)
		return ret;
 
	DRM_DEBUG_ATOMIC("committing %p\n", state);
 
	return config->funcs->atomic_commit(state->dev, state, false);
}

static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
	.fb_create = drm_fb_cma_create,
	.output_poll_changed = malidp_output_poll_changed,
	.atomic_check = drm_atomic_helper_check,
	.atomic_commit = drm_atomic_helper_commit,
};

1. drm_atomic_helper_commit

int drm_atomic_helper_commit(struct drm_device *dev,
			     struct drm_atomic_state *state,
			     bool nonblock)
{
	int ret;

	if (state->async_update) {
		ret = drm_atomic_helper_prepare_planes(dev, state);
		if (ret)
			return ret;

		drm_atomic_helper_async_commit(dev, state);
		drm_atomic_helper_cleanup_planes(dev, state);

		return 0;
	}

	ret = drm_atomic_helper_setup_commit(state, nonblock);
	if (ret)
		return ret;

	INIT_WORK(&state->commit_work, commit_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;
	}

	/*
	 * This is the point of no return - everything below never fails except
	 * when the hw goes bonghits. Which means we can commit the new state on
	 * the software side now.
	 */

	ret = drm_atomic_helper_swap_state(state, true);
	if (ret)
		goto err;

	/*
	 * Everything below can be run asynchronously without the need to grab
	 * any modeset locks at all under one condition: It must be guaranteed
	 * that the asynchronous work has either been cancelled (if the driver
	 * supports it, which at least requires that the framebuffers get
	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
	 * before the new state gets committed on the software side with
	 * drm_atomic_helper_swap_state().
	 *
	 * This scheme allows new atomic state updates to be prepared and
	 * checked in parallel to the asynchronous completion of the previous
	 * update. Which is important since compositors need to figure out the
	 * composition of the next frame right after having submitted the
	 * current layout.
	 *
	 * NOTE: Commit work has multiple phases, first hardware commit, then
	 * cleanup. We want them to overlap, hence need system_unbound_wq to
	 * make sure work items don't artifically stall on each another.
	 */

	drm_atomic_state_get(state);
	if (nonblock)
		queue_work(system_unbound_wq, &state->commit_work);
	else
		commit_tail(state);

	return 0;

err:
	drm_atomic_helper_cleanup_planes(dev, state);
	return ret;
}

我们重点分析下drm_atomic_helper_commit的主要内容:

        (1)初始化一个工作队列,应用如果使用noblock的方式刷图,就使用此工作队列,这样驱动可以直接返回给应用,让应用做其他事情。
        (2)交换state,将要刷新的state赋给各组件的state,将上次刷新的state保存到state结构体中。
        (3)根据是否采用noblock方式刷图来决定如何调用commit_tail。

1.1 drm_atomic_helper_swap_state

int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
  bool stall)
{
	for_each_oldnew_connector_in_state(state, connector, old_conn_state, new_conn_state, i) {
		WARN_ON(connector->state != old_conn_state);
 
		old_conn_state->state = state;
		new_conn_state->state = NULL;
 
		state->connectors[i].state = old_conn_state;
		connector->state = new_conn_state;
	}
 
	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
		WARN_ON(crtc->state != old_crtc_state);
 
		old_crtc_state->state = state;
		new_crtc_state->state = NULL;
 
		state->crtcs[i].state = old_crtc_state;
		crtc->state = new_crtc_state;
	}
 
	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
		WARN_ON(plane->state != old_plane_state);
 
		old_plane_state->state = state;
		new_plane_state->state = NULL;
 
		state->planes[i].state = old_plane_state;
		plane->state = new_plane_state;
	}
 
	for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
		WARN_ON(obj->state != old_obj_state);
 
		old_obj_state->state = state;
		new_obj_state->state = NULL;
 
		state->private_objs[i].state = old_obj_state;
		obj->state = new_obj_state;
	}
 
	return 0;
}

         从代码可以看到如果noblock被置位,将启动commit_work,否则调用commit_tail。

1.2 commit_tail

static void commit_tail(struct drm_atomic_state *old_state)
{
	struct drm_device *dev = old_state->dev;
	const struct drm_mode_config_helper_funcs *funcs;

	funcs = dev->mode_config.helper_private;

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

        commit_tail最终调用了drm_atomic_helper_commit_tail函数。

2. drm_atomic_helper_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_commit_hw_done(old_state);

	drm_atomic_helper_wait_for_vblanks(dev, old_state);

	drm_atomic_helper_cleanup_planes(dev, old_state);
}

2.1 drm_atomic_helper_commit_modeset_disables

        (1)如果mode发生改变其实就是state->mode_changed state->active_changed state->connectors_changed,状态被置位(上节atomic_check中有聊到在哪里置位的)就会关掉crtc,和encoder
        (2)在crtc_set_mode中,如果active被置位,并且上面mode_changed等状态被置位则调用crtc->helper_private->mode_set_nofb和encoder的modeset函数,来将对应mode设置到配置到硬件,同样这些回调需要soc厂商来实现。

 2.2 drm_atomic_helper_commit_planes

        plane->helper_private->atomic_update(plane, old_plane_state):根据plane_state中图像大小和位置等和fb的显存地址配置layer的信息到硬件。

        crtc->helper_private->atomic_flush(crtc, old_crtc_state):更新除了layer的其他相关的内容,比如trigger位。

 2.3 drm_atomic_helper_commit_modeset_enables

        (1)将之前关闭的crtc和encoder打开;配置硬件打开显示和tcon,一并打开encoder。

2.4 drm_atomic_helper_commit_hw_done

        报hw_done事件,通知硬件配置已经完成。

2.5 drm_atomic_helper_wait_for_vblanks

        等待vblank事件,硬件更新完成之后,会等到下一个vsync中断到来后才会生效,vblank事件会在vsync中断处理函数中上报;drm中默认等待50ms,如果显示硬件出现异常超过50ms未上报vblank事件,会打印警告和堆栈

W kernel: [CRTC:35:crtc-0] vblank wait timed out
W kernel: ------------[ cut here ]------------
W kernel: WARNING: CPU: 0 PID: 24879 at gpu/drm/drm_atomic_helper.c:1240 drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: CPU: 0 PID: 24879 Comm: kworker/u12:5 Tainted: P        W  O L  4.14.61+ #1
W kernel: Workqueue: events_unbound commit_work
W kernel: task: ffff8000c4904880 task.stack: ffff00000d6d8000
W kernel: PC is at drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: LR is at drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: [<ffff0000086fb094>] drm_atomic_helper_wait_for_vblanks.part.7+0x2ac/0x2b8
W kernel: [<ffff0000086fb140>] drm_atomic_helper_commit_tail+0x60/0x78
W kernel: [<ffff0000086fb1e4>] commit_tail+0x8c/0x90
W kernel: [<ffff0000086fb208>] commit_work+0x20/0x30
W kernel: [<ffff0000081017e4>] process_one_work+0x1dc/0x4a8
W kernel: [<ffff000008101b00>] worker_thread+0x50/0x478
W kernel: [<ffff000008108eb8>] kthread+0x138/0x140
W kernel: [<ffff00000808518c>] ret_from_fork+0x10/0x1c

        vsync中断处理函数中也会上报filpdone事件,代表新的一帧已经在硬件生效,新的一帧图像已经出现在屏幕上。

3. 流程图

4. 参考文章

DRM驱动(七)之atomic_commit_一瓶布满的博客-CSDN博客

LCD DRM驱动框架分析二_沉沦者的博客-CSDN博客

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值