DRM系列十一:Drm之config->funcs->atomic_commit

本系列文章基于linux 5.15

上一篇介绍了atomic commit之前的check工作,接着就会调用drm_mode_config的config->funcs->atomic_commit回调,这一回调是通过厂商自己实现,以rockchip为例,会直接调用drm_atomic_helper_commit函数。

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

一、drm_atomic_helper_commit

用于提交原子模式设置(Atomic Mode Setting)状态的核心函数。它负责将经过验证的原子状态对象应用到硬件中,完成显示配置的更新

int drm_atomic_helper_commit(struct drm_device *dev,
			     struct drm_atomic_state *state,
			     bool nonblock)
{
	int ret;
/*如果 state->async_update 为 true,表示这是一个异步更新,异步更新后续补充*/
	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;
	}
	/*为原子更新操作创建和初始化提交结构体(drm_crtc_commit),
	并确保在非阻塞模式下不会因为之前的提交操作未完成而导致新的提交操作被阻塞。*/
	ret = drm_atomic_helper_setup_commit(state, nonblock);
	if (ret)
		return ret;
	/*初始化工作队列*/
	INIT_WORK(&state->commit_work, commit_work);
	/*用于在原子更新过程中准备平面(plane)的状态*/
	ret = drm_atomic_helper_prepare_planes(dev, state);
	if (ret)
		return ret;
/*如果 nonblock 为 false(同步模式),调用 drm_atomic_helper_wait_for_fences 等待所有fence完成。fence机制之后再介绍*/
	if (!nonblock) {
		ret = drm_atomic_helper_wait_for_fences(dev, state, true);
		if (ret)
			goto err;
	}
	/*将新的状态(new_state)替换到当前状态(old_state),确保后续操作可以基于新的状态进行。*/
	ret = drm_atomic_helper_swap_state(state, true);
	if (ret)
		goto err;
	/*增加原子状态的引用计数,确保状态在提交过程中不会被释放*/
	drm_atomic_state_get(state);
		/*a.如果 nonblock 为 true(异步模式),将 state->commit_work 加入 system_unbound_wq 工作队列,异步执行提交。异步模式以后讲解。
	b.如果 nonblock 为 false(同步模式),直接调用 commit_tail 执行提交。*/

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

1.drm_atomic_helper_setup_commit

主要作用是为原子更新操作创建和初始化提交结构体(drm_crtc_commit),并确保在非阻塞模式下不会因为之前的提交操作未完成而导致新的提交操作被阻塞。

int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
				   bool nonblock)
{
	struct drm_crtc *crtc;
	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
	struct drm_connector *conn;
	struct drm_connector_state *old_conn_state, *new_conn_state;
	struct drm_plane *plane;
	struct drm_plane_state *old_plane_state, *new_plane_state;
	struct drm_crtc_commit *commit;
	const struct drm_mode_config_helper_funcs *funcs;
	int i, ret;

	funcs = state->dev->mode_config.helper_private;
	/*遍历crtc,一方面为每个crtc初始化 drm_crtc_commit 结构体,另一方面new_crtc_state 没有事件,为其分配个事件,这两种情况都增加提交结构体的引用计数*/
	for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
		commit = kzalloc(sizeof(*commit), GFP_KERNEL);
		if (!commit)
			return -ENOMEM;
	/*初始化一个 drm_crtc_commit 结构体*/
		init_commit(commit, crtc);

		new_crtc_state->commit = commit;
	/*目的是确保提交操作不会因为队列中的未完成操作而过度阻塞,从而提高系统的响应性和稳定性*/
		ret = stall_checks(crtc, nonblock);
		if (ret)
			return ret;

		/*
	如果旧状态和新状态的 CRTC 都是不活动的(active 为 false),则直接完成 flip_done 信号,并跳过当前 CRTC。
	这是因为在这种情况下,不需要进行任何实际的显示更新。
		 */
		if (!old_crtc_state->active && !new_crtc_state->active) {
			complete_all(&commit->flip_done);
			continue;
		}

		/* 如果当前原子更新是遗留的光标更新(legacy_cursor_update 为 true),则直接完成 flip_done 信号,并跳过当前 CRTC。
		光标更新通常不需要同步,因此可以直接完成。 */
		if (state->legacy_cursor_update) {
			complete_all(&commit->flip_done);
			continue;
		}
	/*如果 new_crtc_state 没有事件,则分配一个事件结构体并初始化它,设置事件的完成信号为 commit->flip_done, 
	设置事件的释放函数为 release_crtc_commit,增加提交结构体的引用计数。*/
		if (!new_crtc_state->event) {
			commit->event = kzalloc(sizeof(*commit->event),
						GFP_KERNEL);
			if (!commit->event)
				return -ENOMEM;

			new_crtc_state->event = commit->event;
		}

		new_crtc_state->event->base.completion = &commit->flip_done;
		new_crtc_state->event->base.completion_release = release_crtc_commit;
		drm_crtc_commit_get(commit);
	/*设置提交结构体的 abort_completion 标志为 true,表示在必要时可以中止提交*/
		commit->abort_completion = true;
	/*将提交结构体赋值给 state->crtcs[i].commit。
	增加提交结构体的引用计数。*/
		state->crtcs[i].commit = commit;
		drm_crtc_commit_get(commit);
	}

	for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
		/*如果是非阻塞模式且旧状态的提交操作未完成,则返回 -EBUSY*/
		if (nonblock && old_conn_state->commit &&
		    !try_wait_for_completion(&old_conn_state->commit->flip_done)) {
			DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] busy with a previous commit\n",
				conn->base.id, conn->name);

			return -EBUSY;
		}

		/* 确保在原子更新操作中,即使没有实际的 CRTC,也能有一个有效的提交结构体用于后续的处理。*/
		commit = crtc_or_fake_commit(state, new_conn_state->crtc ?: old_conn_state->crtc);
		if (!commit)
			return -ENOMEM;

		new_conn_state->commit = drm_crtc_commit_get(commit);
	}
	/*和connector相似,不做解释*/
	for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
		if (nonblock && old_plane_state->commit &&
		    !try_wait_for_completion(&old_plane_state->commit->flip_done)) {
			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] busy with a previous commit\n",
				plane->base.id, plane->name);

			return -EBUSY;
		}

		/* Always track planes explicitly for async pageflip support. */
		commit = crtc_or_fake_commit(state, new_plane_state->crtc ?: old_plane_state->crtc);
		if (!commit)
			return -ENOMEM;

		new_plane_state->commit = drm_crtc_commit_get(commit);
	}
	/*调用drm_mode_config_helper_funcs的funcs->atomic_commit_setup回调*/
	if (funcs && funcs->atomic_commit_setup)
		return funcs->atomic_commit_setup(state);

	return 0;
}

1.1init_commit

用于初始化一个 drm_crtc_commit 结构体。

static void init_commit(struct drm_crtc_commit *commit, struct drm_crtc *crtc)
{
	/*
		这三行代码调用了 init_completion 函数,
    分别初始化了 commit 结构体中的三个 completion 对象:
      flip_done、hw_done 和   cleanup_done。
	a.completion 是 Linux 内核中用于同步操作的机制,表示某个操作完成的信号。
	b.init_completion 用于初始化 completion 对象,将其状态设置为未完成(未触发)。
	c.这些 completion 对象的作用:
	flip_done:用于表示页面翻转操作完成。
	hw_done:用于表示硬件操作完成。
	cleanup_done:用于表示清理操作完成。
	*/
	init_completion(&commit->flip_done);
	init_completion(&commit->hw_done);
	init_completion(&commit->cleanup_done);
	INIT_LIST_HEAD(&commit->commit_entry);
		/*kref_init 是 Linux 内核中用于初始化引用计数的函数。
	commit->ref 是一个引用计数器,用于跟踪 commit 结构体的引用次数。
	初始化引用计数为 1,表示该结构体已经被引用了一次。*/
	kref_init(&commit->ref);
	commit->crtc = crtc;
}

1.2stall_checks

目的是确保提交操作不会因为队列中的未完成操作而过度阻塞,从而提高系统的响应性和稳定性。

static int stall_checks(struct drm_crtc *crtc, bool nonblock)
{
	struct drm_crtc_commit *commit, *stall_commit = NULL;
	bool completed = true;
	int i;
	long ret = 0;

	spin_lock(&crtc->commit_lock);
	i = 0;
	list_for_each_entry(commit, &crtc->commit_list, commit_entry) {
			/*
			try_wait_for_completion(&commit->flip_done):尝试等待第一个提交操作的 flip_done 信号完成。
			a.如果 flip_done 已经完成,返回 true;否则返回 false。
	        b.如果 nonblock 为 true 且 flip_done 未完成,
	        说明当前操作不能在未完成的提交操作之前执行,因此释放锁并返回 -EBUSY。*/
		if (i == 0) {
			completed = try_wait_for_completion(&commit->flip_done);
			/*
			 * Userspace is not allowed to get ahead of the previous
			 * commit with nonblocking ones.
			 */
			if (!completed && nonblock) {
				spin_unlock(&crtc->commit_lock);
				DRM_DEBUG_ATOMIC("[CRTC:%d:%s] busy with a previous commit\n",
					crtc->base.id, crtc->name);

				return -EBUSY;
			}
		} else if (i == 1) {
			/*如果当前遍历到的是第二个提交操作(i == 1),则调用 drm_crtc_commit_get 增加该提交操作的引用计数,
			并将其存储到 stall_commit 中。然后退出循环。*/
			stall_commit = drm_crtc_commit_get(commit);
			break;
		}

		i++;
	}
	spin_unlock(&crtc->commit_lock);
/*如果没有找到第二个提交操作(stall_commit 为空),说明队列中没有需要等待的提交操作,直接返回 0*/
	if (!stall_commit)
		return 0;

	/* 等待第二个提交操作的清理完成:
	调用 wait_for_completion_interruptible_timeout 等待第二个提交操作的 cleanup_done 信号完成,超时时间为 10*HZ(HZ 是内核的时钟频率,通常为1000)。
	如果在超时时间内完成,返回值为剩余时间;如果超时,返回值为 0。
	 */
	ret = wait_for_completion_interruptible_timeout(&stall_commit->cleanup_done,
							10*HZ);
	if (ret == 0)
		DRM_ERROR("[CRTC:%d:%s] cleanup_done timed out\n",
			  crtc->base.id, crtc->name);

	drm_crtc_commit_put(stall_commit);

	return ret < 0 ? ret : 0;
}

1.3crtc_or_fake_commit

作用是确保在原子更新操作中,即使没有实际的 CRTC,也能有一个有效的提交结构体用于后续的处理。这对于一些特殊情况(例如光标更新或平面更新)非常有用,这些操作可能不需要实际的 CRTC,但仍然需要一个提交结构体来管理状态。

static struct drm_crtc_commit *crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
{
	/*如果指定了有效的 CRTC,返回与该 CRTC 相关联的提交结构体。*/
	if (crtc) {
		struct drm_crtc_state *new_crtc_state;

		new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);

		return new_crtc_state->commit;
	}
/*如果没有指定 CRTC(即 CRTC 为 NULL),则创建一个虚拟的提交结构体,并初始化它,最终返回虚拟提交结构体*/
	if (!state->fake_commit) {
		state->fake_commit = kzalloc(sizeof(*state->fake_commit), GFP_KERNEL);
		if (!state->fake_commit)
			return NULL;

		init_commit(state->fake_commit, NULL);
	}

	return state->fake_commit;
}

2.drm_atomic_helper_prepare_planes

用于在原子更新过程中准备平面(plane)的状态。它的主要作用是确保所有平面的帧缓冲区(framebuffer)都准备好,以便后续的显示操作能够顺利进行。

int drm_atomic_helper_prepare_planes(struct drm_device *dev,
				     struct drm_atomic_state *state)
{
	struct drm_connector *connector;
	struct drm_connector_state *new_conn_state;
	struct drm_plane *plane;
	struct drm_plane_state *new_plane_state;
	int ret, i, j;

	for_each_new_connector_in_state(state, connector, new_conn_state, i) {
		if (!new_conn_state->writeback_job)
			continue;

		ret = drm_writeback_prepare_job(new_conn_state->writeback_job);
		if (ret < 0)
			return ret;
	}
	/*遍历所有新的plane状态,如果有funcs->prepare_fb回调,调用drm_plane_helper_funcs的 funcs->prepare_fb回调 函数准备帧缓冲区;如果没有funcs->prepare_fb回调且支持GEM,则调用drm_gem_plane_helper_prepare_fb准备帧缓冲区*/
	for_each_new_plane_in_state(state, plane, new_plane_state, i) {
		const struct drm_plane_helper_funcs *funcs;

		funcs = plane->helper_private;

		if (funcs->prepare_fb) {
			ret = funcs->prepare_fb(plane, new_plane_state);
			if (ret)
				goto fail;
		} else {
			WARN_ON_ONCE(funcs->cleanup_fb);

			if (!drm_core_check_feature(dev, DRIVER_GEM))
				continue;

			ret = drm_gem_plane_helper_prepare_fb(plane, new_plane_state);
			if (ret)
				goto fail;
		}
	}

	return 0;

fail:
	for_each_new_plane_in_state(state, plane, new_plane_state, j) {
		const struct drm_plane_helper_funcs *funcs;

		if (j >= i)
			continue;

		funcs = plane->helper_private;

		if (funcs->cleanup_fb)
			funcs->cleanup_fb(plane, new_plane_state);
	}

	return ret;
}

2.1drm_writeback_prepare_job

调用drm_connector_helper_funcs的funcs->prepare_writeback_job回调,进行准备工作。

int drm_writeback_prepare_job(struct drm_writeback_job *job)
{
	struct drm_writeback_connector *connector = job->connector;
	const struct drm_connector_helper_funcs *funcs =
		connector->base.helper_private;
	int ret;

	if (funcs->prepare_writeback_job) {
		ret = funcs->prepare_writeback_job(connector, job);
		if (ret < 0)
			return ret;
	}

	job->prepared = true;
	return 0;
}

3.drm_atomic_helper_swap_state

a.阻塞等待硬件操作完成(可选):如果 stall 参数为 true,则等待所有相关的硬件操作完成。
b.交换状态:将新的状态(new_state)替换到当前状态(old_state),确保后续操作可以基于新的状态进行。
c.更新提交队列:将新的提交结构体(drm_crtc_commit)添加到 CRTC 的提交队列中。

int drm_atomic_helper_swap_state(struct drm_atomic_state *state,
				  bool stall)
{
	int i, ret;
	struct drm_connector *connector;
	struct drm_connector_state *old_conn_state, *new_conn_state;
	struct drm_crtc *crtc;
	struct drm_crtc_state *old_crtc_state, *new_crtc_state;
	struct drm_plane *plane;
	struct drm_plane_state *old_plane_state, *new_plane_state;
	struct drm_crtc_commit *commit;
	struct drm_private_obj *obj;
	struct drm_private_state *old_obj_state, *new_obj_state;
/*在 stall 参数为 true 时,函数会遍历所有旧的 CRTC、连接器和状态,等待它们的硬件操作(hw_done)完成*/
	if (stall) {
		for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
			commit = old_crtc_state->commit;

			if (!commit)
				continue;

			ret = wait_for_completion_interruptible(&commit->hw_done);
			if (ret)
				return ret;
		}

		for_each_old_connector_in_state(state, connector, old_conn_state, i) {
			commit = old_conn_state->commit;

			if (!commit)
				continue;

			ret = wait_for_completion_interruptible(&commit->hw_done);
			if (ret)
				return ret;
		}

		for_each_old_plane_in_state(state, plane, old_plane_state, i) {
			commit = old_plane_state->commit;

			if (!commit)
				continue;

			ret = wait_for_completion_interruptible(&commit->hw_done);
			if (ret)
				return ret;
		}
	}
/*遍历所有connector、crtc、plane和私有对象的状态,将新的状态替换到当前状态中。*/
	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;
	/*如果新状态有提交结构体(commit),则将提交结构体添加到 CRTC 的提交队列中,并清除事件指针。*/
		if (new_crtc_state->commit) {
			spin_lock(&crtc->commit_lock);
			list_add(&new_crtc_state->commit->commit_entry,
				 &crtc->commit_list);
			spin_unlock(&crtc->commit_lock);

			new_crtc_state->commit->event = NULL;
		}
	}

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

4.commit_tail

commit_tail实现比较复杂,可以参考下一篇文章。

<think>嗯,用户让我分析一个Linux内核驱动中的st7789v_probe函数。首先,我需要理解这个函数的作用和结构。根据之前的对话历史,用户可能是在开发或调试ST7789显示驱动,遇到了问题,需要了解这个probe函数的具体实现。 首先,这个函数是作为SPI设备驱动的探测函数,当设备与驱动匹配时会被调用。用户提供的代码中,函数内部进行了内存分配、设备树参数解析、GPIO和电源管理、背光处理,以及面板注册等操作。我需要逐一分析每个步骤的作用,确保解释清楚。 接下来,我需要考虑用户可能的疑问点。比如,为什么使用devm_kzalloc?regulator_get的作用是什么?of_parse_phandle在这里的作用?还有错误处理部分,比如EPROBE_DEFER的含义。这些都需要详细解释,帮助用户理解代码流程和可能的问题点。 另外,用户之前的问题是关于设备树参数解析的函数,现在转而分析probe函数,可能是在调试过程中发现设备未能正确初始化,想要检查probe函数的实现是否有问题。因此,我需要指出代码中的关键部分,比如资源获取、错误处理,以及可能的隐患,比如未解析设备树参数的问题。 还要注意代码中的潜在问题,比如是否有遗漏的设备树解析步骤,比如之前的回答中提到的st7789v_parse_dt函数,而当前代码中没有调用,这可能导致参数未被正确解析,进而引发初始化失败。这可能是一个关键点,需要提醒用户检查是否在代码中遗漏了这个函数,或者是否有其他地方的修改。 此外,用户可能在移植或修改驱动时遇到问题,比如背光无法开启,SPI通信失败等,因此需要解释相关部分,比如backlight的处理,GPIO的获取,以及错误返回的处理。比如,返回-EPROBE_DEFER表示背光设备可能尚未准备好,需要延迟探测。 最后,总结整个函数的工作流程,并指出潜在的问题点,帮助用户定位可能存在的bug或改进的地方。同时,提供调试建议,比如检查设备树节点,查看dmesg日志,确保所有必要的资源正确配置。</think>以下是对 `st7789v_probe` 函数的详细分析,按照代码执行流程分步解释: --- ### **一、函数功能概述** 这是 ST7789 显示驱动在 Linux 内核中的 **SPI 设备探测函数**,负责初始化显示控制器硬件、解析设备树(DTS)参数、配置电源/GPIO/背光,并注册 DRM 面板。 --- ### **二、逐行代码解析** #### **1. 内存分配与上下文初始化** ```c ctx = devm_kzalloc(&spi->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; ``` - **作用**:为驱动私有数据结构 `struct st7789v` 分配内存(自动内存管理 `devm_*` 确保无需手动释放)。 - **关键点**:`GFP_KERNEL` 表示在内核空间的常规内存分配。 #### **2. 关联 SPI 设备和驱动数据** ```c spi_set_drvdata(spi, ctx); ctx->spi = spi; ``` - **作用**:将私有数据 `ctx` 绑定到 SPI 设备,方便后续通过 `spi_get_drvdata()` 获取。 - **典型用途**:在中断处理或数据传输中快速访问设备上下文。 #### **3. DRM 面板初始化** ```c drm_panel_init(&ctx->panel); ctx->panel.dev = &spi->dev; ctx->panel.funcs = &st7789v_drm_funcs; ``` - **作用**: - `drm_panel_init`:初始化 DRM 面板的通用结构。 - `panel.dev`:关联父设备(用于设备模型和日志输出)。 - `panel.funcs`:绑定面板操作函数(如 `enable/disable` 等),定义在 `st7789v_drm_funcs` 中。 #### **4. 电源管理初始化** ```c ctx->power = devm_regulator_get(&spi->dev, "power"); if (IS_ERR(ctx->power)) return PTR_ERR(ctx->power); ``` - **作用**:通过设备树获取名为 `"power"` 的电压调节器(Regulator)。 - **设备树对应**:DTS 中应有 `power-supply = <&regulator_name>` 属性。 - **典型问题**:若未正确配置电源节点,会返回 `-EPROBE_DEFER` 或错误码。 #### **5. 复位信号(Reset GPIO)配置** ```c ctx->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset)) { dev_err(&spi->dev, "Couldn't get our reset line\n"); return PTR_ERR(ctx->reset); } ``` - **作用**:获取设备树中定义的 `reset` GPIO 引脚,初始化为低电平。 - **设备树对应**: ```dts reset-gpios = <&gpio 17 GPIO_ACTIVE_LOW>; // 示例 ``` - **关键点**:`GPIOD_OUT_LOW` 表示初始输出低电平(硬件复位通常需要拉高后拉低)。 #### **6. 背光(Backlight)处理** ```c backlight = of_parse_phandle(spi->dev.of_node, "backlight", 0); if (backlight) { ctx->backlight = of_find_backlight_by_node(backlight); of_node_put(backlight); if (!ctx->backlight) return -EPROBE_DEFER; } ``` - **作用**: 1. 解析设备树中 `backlight` 属性引用的背光控制器节点。 2. 通过 `of_find_backlight_by_node` 获取背光设备。 - **设备树对应**: ```dts backlight = <&backlight_device>; // 指向背光控制节点 ``` - **关键点**: - `-EPROBE_DEFER` 表示背光设备尚未初始化,需延迟探测。 - `of_node_put` 用于释放节点引用计数,避免内存泄漏。 #### **7. 注册 DRM 面板** ```c ret = drm_panel_add(&ctx->panel); if (ret < 0) goto err_free_backlight; ``` - **作用**:将面板注册到 DRM 框架,使其能被显示控制器(如 DRM/KMS 驱动)发现。 - **失败处理**:若注册失败,跳转到 `err_free_backlight` 清理背光资源。 #### **8. 错误处理** ```c err_free_backlight: if (ctx->backlight) put_device(&ctx->backlight->dev); return ret; ``` - **作用**:在注册面板失败时,释放已获取的背光设备引用。 - **关键点**:`put_device` 减少背光设备的引用计数,确保资源正确释放。 --- ### **三、潜在问题与改进建议** #### **1. 设备树参数解析缺失** - **现象**:当前代码未解析关键参数(如分辨率 `width/height`、SPI 模式等)。 - **对比**:根据前文分析,预期应有类似 `st7789v_parse_dt(ctx, dev)` 的解析函数。 - **改进建议**: ```c // 在注册面板前添加设备树解析 ret = st7789v_parse_dt(ctx, &spi->dev); if (ret) return ret; ``` #### **2. 硬件初始化不完整** - **现象**:未执行复位信号操作或 SPI 配置(如设置 `spi->mode` 和 `spi->max_speed_hz`)。 - **改进建议**: ```c // 在注册面板前添加硬件初始化 st7789v_hw_init(ctx); // 包含复位时序和SPI配置 ``` #### **3. 电源管理未启用** - **现象**:获取了 `regulator` 但未启用电源。 - **改进建议**: ```c ret = regulator_enable(ctx->power); if (ret) { dev_err(&spi->dev, "Failed to enable power regulator\n"); return ret; } ``` --- ### **四、调试方法** 1. **检查设备树配置**: ```bash # 确认SPI节点包含必要属性 cat /proc/device-tree/soc/spi@xxxxxx/st7789v@0/backlight ``` 2. **查看内核日志**: ```bash dmesg | grep st7789v # 典型错误:未找到背光设备或复位GPIO ``` 3. **动态调试**: ```bash echo -n 'file panel-sitronix-st7789v.c +p' > /sys/kernel/debug/dynamic_debug/control # 启用驱动级调试日志 ``` --- ### **五、总结** 此函数是 ST7789 驱动的核心初始化入口,但当前代码存在 **设备树参数解析缺失** 和 **硬件初始化不完整** 的问题。建议结合设备树绑定文档(`Documentation/devicetree/bindings/display/sitronix,st7789v.yaml`)补充必要逻辑,并增加复位时序和电源管理代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值