rk3399启动过程log_kernel一闪而过问题

Posted weishengzhong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rk3399启动过程log_kernel一闪而过问题相关的知识,希望对你有一定的参考价值。

环境:rk3399 linux SDK  linux kernel版本为4.4.179   uboot版本为201709

问题现象:

  uboot阶段 logo.bmp 可以正常显示,并且持续到 logo_kernel.bmp开始显示那一刻, 但是logo_kernel.bmp 虽然能显示,但是一闪而过,之后屏幕就持续黑屏直到显示桌面内容……

 

  问题排查:

  查看启动log:

  

[    4.212505] ##################show_loader_logo#######################
[    4.262751] ############fb_find_logo  depth = 24#############
[    4.262751] Freeing drm_logo memory: 3348K
[    4.325082] Console: switching to colour frame buffer device 100x80
[    4.375269] rockchip-drm display-subsystem: fb0:  frame buffer device

  发现drm memory被free,查看 show_loader_logo 函数

  

struct drm_atomic_state *state, *old_state;
	struct device_node *np = drm_dev->dev->of_node;
	struct drm_mode_config *mode_config = &drm_dev->mode_config;
	struct device_node *root, *route;
	struct rockchip_drm_mode_set *set, *tmp, *unset;
	struct list_head mode_set_list;
	struct list_head mode_unset_list;
	unsigned plane_mask = 0;
	int ret;

	printk("##################%s#######################
",__func__);
	
	root = of_get_child_by_name(np, "route");
	if (!root) {
		dev_warn(drm_dev->dev, "failed to parse display resources
");
		return;
	}

	if (init_loader_memory(drm_dev)) {
		dev_warn(drm_dev->dev, "failed to parse loader memory
");
		return;
	}

	INIT_LIST_HEAD(&mode_set_list);
	INIT_LIST_HEAD(&mode_unset_list);
	drm_modeset_lock_all(drm_dev);
	state = drm_atomic_state_alloc(drm_dev);
	if (!state) {
		dev_err(drm_dev->dev, "failed to alloc atomic state
");
		ret = -ENOMEM;
		goto err_unlock;
	}

	state->acquire_ctx = mode_config->acquire_ctx;

	for_each_child_of_node(root, route) {
		if (!of_device_is_available(route))
			continue;

		set = of_parse_display_resource(drm_dev, route);
		if (!set)
			continue;

		if (setup_initial_state(drm_dev, state, set)) {
			drm_framebuffer_unreference(set->fb);
			INIT_LIST_HEAD(&set->head);
			list_add_tail(&set->head, &mode_unset_list);
			continue;
		}
		INIT_LIST_HEAD(&set->head);
		list_add_tail(&set->head, &mode_set_list);
	}

	/*
	 * the mode_unset_list store the unconnected route, if route‘s crtc
	 * isn‘t used, we should close it.
	 */
	list_for_each_entry_safe(unset, tmp, &mode_unset_list, head) {
		struct rockchip_drm_mode_set *tmp_set;
		int found_used_crtc = 0;

		list_for_each_entry_safe(set, tmp_set, &mode_set_list, head) {
			if (set->crtc == unset->crtc) {
				printk("############found 1 used crtc###########
");
				found_used_crtc = 1;
				continue;
			}
		}
		if (!found_used_crtc) {
			struct drm_crtc *crtc = unset->crtc;
			int pipe = drm_crtc_index(crtc);
			struct rockchip_drm_private *priv =
							drm_dev->dev_private;

			if (unset->hdisplay && unset->vdisplay){
				printk("############close the unused crtc###########
");
				priv->crtc_funcs[pipe]->crtc_close(crtc);
				}
		}
		list_del(&unset->head);
		kfree(unset);
	}

	if (list_empty(&mode_set_list)) {
		dev_warn(drm_dev->dev, "can‘t not find any loader display
");
		ret = -ENXIO;
		goto err_free_state;
	}

	/*
	 * The state save initial devices status, swap the state into
	 * drm deivces as old state, so if new state come, can compare
	 * with this state to judge which status need to update.
	 */
	drm_atomic_helper_swap_state(drm_dev, state);
	drm_atomic_state_free(state);
	old_state = drm_atomic_helper_duplicate_state(drm_dev,
						      mode_config->acquire_ctx);
	if (IS_ERR(old_state)) {
		dev_err(drm_dev->dev, "failed to duplicate atomic state
");
		ret = PTR_ERR_OR_ZERO(old_state);
		goto err_free_state;
	}

	state = drm_atomic_helper_duplicate_state(drm_dev,
						  mode_config->acquire_ctx);
	if (IS_ERR(state)) {
		dev_err(drm_dev->dev, "failed to duplicate atomic state
");
		ret = PTR_ERR_OR_ZERO(state);
		goto err_free_old_state;
	}
	state->acquire_ctx = mode_config->acquire_ctx;
	list_for_each_entry(set, &mode_set_list, head)
		/*
		 * We don‘t want to see any fail on update_state.
		 */
		WARN_ON(update_state(drm_dev, state, set, &plane_mask));

	ret = drm_atomic_commit(state);
	drm_atomic_clean_old_fb(drm_dev, plane_mask, ret);

	list_for_each_entry_safe(set, tmp, &mode_set_list, head) {
		list_del(&set->head);
		kfree(set);
	}

	/*
	 * Is possible get deadlock here?
	 */
	WARN_ON(ret == -EDEADLK);

	if (ret) {
		/*
		 * restore display status if atomic commit failed.
		 */
		drm_atomic_helper_swap_state(drm_dev, old_state);
		goto err_free_old_state;
	}
	
//	rockchip_free_loader_memory(drm_dev);
//	drm_atomic_state_free(old_state);

	drm_modeset_unlock_all(drm_dev);

	return;

err_free_old_state:
	drm_atomic_state_free(old_state);
err_free_state:
	drm_atomic_state_free(state);
err_unlock:
	drm_modeset_unlock_all(drm_dev);
	if (ret)
		dev_err(drm_dev->dev, "failed to show loader logo
");
	rockchip_free_loader_memory(drm_dev);

}


  大致的意思是有个备份区存储上个framebuffer内容,如果之后重新分配并且填充了frambuffer则更新备份区内容,也就是显示屏显示内容会更新……

  禁止启动阶段fb更新即可解决内核图片一闪而过问题:

  

RK官方也提供了不少解决方案,但对于我这个现象不适用;这个问题的根源应该是RK为了兼容老的framebuffer机制,如果配置linux内核里面  logo.c 文件里面指定的内核图片显示,但是这会影响到 kernel目录下 logo_kernel.bmp文件的显示,如果不按如上步骤操作, 在logo.c文件内把 fb_logo_late_init 函数里面的 logos_freed 设为false, 则会显示 logo.c 指定的图片,我的版本是几只企鹅…… 启动过程的现象就是:uboot阶段显示logo.bmp正常,接着logo_kernel.bmp一闪而过,接着显示企鹅画面直到进入桌面…… 

附官方指导文档:

 技术图片

 

 

技术图片

 

以上是关于rk3399启动过程log_kernel一闪而过问题的主要内容,如果未能解决你的问题,请参考以下文章

RK3399快速上手 | 03-RK3399启动流程分析

RK3399快速上手 | 03-RK3399启动流程分析

RK3399平台开发系列讲解(内存篇)18.14内存被覆盖导致启动死机问题

RK3399芯片启动需要像三星一样的bl1吗

RK3399平台开发系列讲解(内核调试篇)2.50嵌入式产品启动速度优化

RK3399平台开发系列讲解(内核调试篇)2.50嵌入式产品启动速度优化