RK3399 开机画面启动过程中的显示问题
2021-02-24 18:12:39
ThanksView
  • 访问次数: 222
  • 注册日期: 2019-03-19
  • 最后登录: 2024-04-22


问题现象:

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 10
                          0x80
                           [ 
                          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#######################\r\n",__func__);
	
	root = of_get_child_by_name(np, "route");
	if (!root) {
		dev_warn(drm_dev->dev, "failed to parse display resources\n");
		return;
	}
	if (init_loader_memory(drm_dev)) {
		dev_warn(drm_dev->dev, "failed to parse loader memory\n");
		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\n");
		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###########\r\n");
				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###########\r\n");
				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\n");
		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\n");
		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\n");
		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\n");
	rockchip_free_loader_memory(drm_dev);
}

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

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

rockchip_drm_bind 函数屏蔽如下内容:


	ret = rockchip_drm_fbdev_init(drm_dev);
	if (ret)
		goto err_kms_helper_poll_fini;
	drm_for_each_crtc(crtc, drm_dev) {
		struct drm_fb_helper *helper = private->fbdev_helper;
		struct rockchip_crtc_state *s = NULL;
		if (!helper)
			break;
		s = to_rockchip_crtc_state(crtc->state);
//#ifndef MODULE	
		if (is_support_hotplug(s->output_type)) {
			s->crtc_primary_fb = crtc->primary->fb;
			crtc->primary->fb = helper->fb;
			drm_framebuffer_reference(helper->fb);
		}
//#endif
	}
	drm_dev->mode_config.allow_fb_modifiers = true;


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

三维半岛官网: http://www.thanksview.com

进入首页