From c96659a88a12f1363d2cebbc9bd73eb3cafda1ea Mon Sep 17 00:00:00 2001 From: Guchun Chen Date: Fri, 13 Apr 2018 17:29:40 +0800 Subject: [PATCH] drm: msm: improve early splash mechanism Early RVC will keep running even if all display's splash in bootloader are stopped. So kernel splash handoff mechanism needs to be modified to match the scenario. CRs-Fixed: 2225630 Change-Id: I0e00403f6cae0401ea23465f78cf092abfa2a611 Signed-off-by: Guchun Chen --- drivers/gpu/drm/msm/sde/sde_connector.c | 13 +-- drivers/gpu/drm/msm/sde/sde_kms.c | 5 +- drivers/gpu/drm/msm/sde/sde_splash.c | 200 ++++++++++++-------------------- drivers/gpu/drm/msm/sde/sde_splash.h | 19 ++- 4 files changed, 89 insertions(+), 148 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index e8dfd1f08236..f74a682c5f04 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -572,8 +572,6 @@ void sde_connector_complete_commit(struct drm_connector *connector) { struct drm_device *dev; struct msm_drm_private *priv; - struct sde_connector *c_conn; - struct sde_kms *sde_kms; if (!connector) { SDE_ERROR("invalid connector\n"); @@ -582,7 +580,6 @@ void sde_connector_complete_commit(struct drm_connector *connector) dev = connector->dev; priv = dev->dev_private; - sde_kms = to_sde_kms(priv->kms); /* signal connector's retire fence */ sde_fence_signal(&to_sde_connector(connector)->retire_fence, 0); @@ -590,14 +587,8 @@ void sde_connector_complete_commit(struct drm_connector *connector) /* after first vsync comes, * early splash resource should start to be released. */ - if (sde_splash_get_lk_complete_status(&sde_kms->splash_info)) { - c_conn = to_sde_connector(connector); - - sde_splash_clean_up_free_resource(priv->kms, - &priv->phandle, - c_conn->connector_type, - c_conn->display); - } + if (sde_splash_get_lk_complete_status(priv->kms)) + sde_splash_free_resource(priv->kms, &priv->phandle); } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index b95157b28855..1da8b5b4ff10 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -343,8 +343,9 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, struct drm_device *dev = sde_kms->dev; struct msm_drm_private *priv = dev->dev_private; - if (sde_kms->splash_info.handoff) - sde_splash_clean_up_exit_lk(kms); + if (sde_kms->splash_info.handoff && + sde_kms->splash_info.display_splash_enabled) + sde_splash_lk_stop_splash(kms); else sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); diff --git a/drivers/gpu/drm/msm/sde/sde_splash.c b/drivers/gpu/drm/msm/sde/sde_splash.c index 71ebb4b37d6b..f124bd7d5904 100644 --- a/drivers/gpu/drm/msm/sde/sde_splash.c +++ b/drivers/gpu/drm/msm/sde/sde_splash.c @@ -36,11 +36,9 @@ #define SCRATCH_REGISTER_2 0x01C #define SDE_LK_RUNNING_VALUE 0xC001CAFE -#define SDE_LK_SHUT_DOWN_VALUE 0xDEADDEAD +#define SDE_LK_STOP_SPLASH_VALUE 0xDEADDEAD #define SDE_LK_EXIT_VALUE 0xDEADBEEF -#define SDE_LK_EXIT_MAX_LOOP 20 - #define INTF_HDMI_SEL (BIT(25) | BIT(24)) #define INTF_DSI0_SEL BIT(8) #define INTF_DSI1_SEL BIT(16) @@ -190,26 +188,14 @@ static bool _sde_splash_lk_check(struct sde_hw_intr *intr) } /** - * _sde_splash_notify_lk_to_exit. + * _sde_splash_notify_lk_stop_splash. * - * Function to monitor LK's status and tell it to exit. + * Function to stop early splash in LK. */ -static void _sde_splash_notify_lk_exit(struct sde_hw_intr *intr) +static inline void _sde_splash_notify_lk_stop_splash(struct sde_hw_intr *intr) { - int i = 0; - - /* first is to write exit signal to scratch register*/ - SDE_REG_WRITE(&intr->hw, SCRATCH_REGISTER_1, SDE_LK_SHUT_DOWN_VALUE); - - while ((SDE_LK_EXIT_VALUE != - SDE_REG_READ(&intr->hw, SCRATCH_REGISTER_1)) && - (++i < SDE_LK_EXIT_MAX_LOOP)) { - DRM_INFO("wait for LK's exit"); - msleep(20); - } - - if (i == SDE_LK_EXIT_MAX_LOOP) - SDE_ERROR("Loop LK's exit failed\n"); + /* write splash stop signal to scratch register*/ + SDE_REG_WRITE(&intr->hw, SCRATCH_REGISTER_1, SDE_LK_STOP_SPLASH_VALUE); } static int _sde_splash_gem_new(struct drm_device *dev, @@ -327,31 +313,28 @@ static void _sde_splash_sent_pipe_update_uevent(struct sde_kms *sde_kms) kfree(event_string); } -static void _sde_splash_get_connector_ref_cnt(struct sde_splash_info *sinfo, - u32 *hdmi_cnt, u32 *dsi_cnt) +static int _sde_splash_free_module_resource(struct msm_mmu *mmu, + struct sde_splash_info *sinfo) { - mutex_lock(&sde_splash_lock); - *hdmi_cnt = sinfo->hdmi_connector_cnt; - *dsi_cnt = sinfo->dsi_connector_cnt; - mutex_unlock(&sde_splash_lock); -} + int i = 0; + struct msm_gem_object *msm_obj; -static int _sde_splash_free_resource(struct msm_mmu *mmu, - struct sde_splash_info *sinfo, enum splash_connector_type conn) -{ - struct msm_gem_object *msm_obj = to_msm_bo(sinfo->obj[conn]); + for (i = 0; i < sinfo->splash_mem_num; i++) { + msm_obj = to_msm_bo(sinfo->obj[i]); - if (!msm_obj) - return -EINVAL; + if (!msm_obj) + return -EINVAL; - if (mmu->funcs && mmu->funcs->unmap) - mmu->funcs->early_splash_unmap(mmu, - sinfo->splash_mem_paddr[conn], msm_obj->sgt); + if (mmu->funcs && mmu->funcs->unmap) + mmu->funcs->early_splash_unmap(mmu, + sinfo->splash_mem_paddr[i], msm_obj->sgt); - _sde_splash_free_bootup_memory_to_system(sinfo->splash_mem_paddr[conn], - sinfo->splash_mem_size[conn]); + _sde_splash_free_bootup_memory_to_system( + sinfo->splash_mem_paddr[i], + sinfo->splash_mem_size[i]); - _sde_splash_destroy_gem_object(msm_obj); + _sde_splash_destroy_gem_object(msm_obj); + } return 0; } @@ -374,6 +357,7 @@ __ref int sde_splash_init(struct sde_power_handle *phandle, struct msm_kms *kms) sinfo->dsi_connector_cnt = 0; sinfo->hdmi_connector_cnt = 0; + /* Vote data bus after splash is enabled in bootloader */ sde_power_data_bus_bandwidth_ctrl(phandle, sde_kms->core_client, true); @@ -578,12 +562,12 @@ int sde_splash_get_handoff_status(struct msm_kms *kms) if (num_of_display_on) { sinfo->handoff = true; - sinfo->program_scratch_regs = true; + sinfo->display_splash_enabled = true; sinfo->lk_is_exited = false; sinfo->intf_sel_status = intf_sel; } else { sinfo->handoff = false; - sinfo->program_scratch_regs = false; + sinfo->display_splash_enabled = false; sinfo->lk_is_exited = true; } @@ -709,29 +693,34 @@ void sde_splash_setup_connector_count(struct sde_splash_info *sinfo, } } -bool sde_splash_get_lk_complete_status(struct sde_splash_info *sinfo) +bool sde_splash_get_lk_complete_status(struct msm_kms *kms) { - bool ret = 0; + struct sde_kms *sde_kms = to_sde_kms(kms); + struct sde_hw_intr *intr; - mutex_lock(&sde_splash_lock); - ret = !sinfo->handoff && !sinfo->lk_is_exited; - mutex_unlock(&sde_splash_lock); + if (!sde_kms || !sde_kms->hw_intr) { + SDE_ERROR("invalid kms\n"); + return false; + } - return ret; + intr = sde_kms->hw_intr; + + if (sde_kms->splash_info.handoff && + SDE_LK_EXIT_VALUE == SDE_REG_READ(&intr->hw, + SCRATCH_REGISTER_1)) { + SDE_DEBUG("LK totoally exits\n"); + return true; + } + + return false; } -int sde_splash_clean_up_free_resource(struct msm_kms *kms, - struct sde_power_handle *phandle, - int connector_type, void *display) +int sde_splash_free_resource(struct msm_kms *kms, + struct sde_power_handle *phandle) { struct sde_kms *sde_kms; struct sde_splash_info *sinfo; struct msm_mmu *mmu; - struct dsi_display *dsi_display = display; - int ret = 0; - int hdmi_conn_count = 0; - int dsi_conn_count = 0; - static const char *last_commit_display_type = "unknown"; if (!phandle || !kms) { SDE_ERROR("invalid phandle/kms.\n"); @@ -745,88 +734,49 @@ int sde_splash_clean_up_free_resource(struct msm_kms *kms, return -EINVAL; } - _sde_splash_get_connector_ref_cnt(sinfo, &hdmi_conn_count, - &dsi_conn_count); - mutex_lock(&sde_splash_lock); - if (hdmi_conn_count == 0 && dsi_conn_count == 0 && - !sinfo->lk_is_exited) { - /* When both hdmi's and dsi's handoff are finished, - * 1. Destroy splash node objects. - * 2. Release the memory which LK's stack is running on. - * 3. Withdraw AHB data bus bandwidth voting. - */ - DRM_INFO("HDMI and DSI resource handoff is completed\n"); - - sinfo->lk_is_exited = true; - - _sde_splash_destroy_splash_node(sinfo); - - _sde_splash_free_bootup_memory_to_system(sinfo->lk_pool_paddr, - sinfo->lk_pool_size); - - sde_power_data_bus_bandwidth_ctrl(phandle, - sde_kms->core_client, false); - - _sde_splash_sent_pipe_update_uevent(sde_kms); - + if (!sinfo->handoff) { mutex_unlock(&sde_splash_lock); return 0; } mmu = sde_kms->aspace[0]->mmu; + if (!mmu) { + mutex_unlock(&sde_splash_lock); + return -EINVAL; + } - switch (connector_type) { - case DRM_MODE_CONNECTOR_HDMIA: - if (sinfo->hdmi_connector_cnt == 1) { - sinfo->hdmi_connector_cnt--; + /* free HDMI's, DSI's and early camera's reserved memory */ + _sde_splash_free_module_resource(mmu, sinfo); - ret = _sde_splash_free_resource(mmu, - sinfo, SPLASH_HDMI); - } - break; - case DRM_MODE_CONNECTOR_DSI: - /* - * Basically, we have commits coming on two DSI connectors. - * So when releasing DSI resource, it's ensured that the - * coming commits should happen on different DSIs, to promise - * the handoff has finished on the two DSIs, then it's safe - * to release DSI resource, otherwise, problem happens when - * freeing memory, while DSI0 or DSI1 is still visiting - * the memory. - */ - if (strcmp(dsi_display->display_type, "unknown") && - strcmp(last_commit_display_type, - dsi_display->display_type)) { - if (sinfo->dsi_connector_cnt > 1) - sinfo->dsi_connector_cnt--; - else if (sinfo->dsi_connector_cnt == 1) { - ret = _sde_splash_free_resource(mmu, - sinfo, SPLASH_DSI); - - sinfo->dsi_connector_cnt--; - } + _sde_splash_destroy_splash_node(sinfo); - last_commit_display_type = dsi_display->display_type; - } - break; - default: - ret = -EINVAL; - SDE_ERROR("%s: invalid connector_type %d\n", - __func__, connector_type); - } + /* free lk_pool heap memory */ + _sde_splash_free_bootup_memory_to_system(sinfo->lk_pool_paddr, + sinfo->lk_pool_size); - mutex_unlock(&sde_splash_lock); + /* withdraw data bus vote */ + sde_power_data_bus_bandwidth_ctrl(phandle, + sde_kms->core_client, false); - return ret; + /* send uevent to notify user to recycle resource */ + _sde_splash_sent_pipe_update_uevent(sde_kms); + + /* Finally mark handoff flag to false to say handoff is complete */ + sinfo->handoff = false; + + DRM_INFO("HDMI and DSI resource handoff is completed\n"); + + mutex_unlock(&sde_splash_lock); + return 0; } /* * In below function, it will - * 1. Notify LK to exit and wait for exiting is done. + * 1. Notify LK to stop display splash. * 2. Set DOMAIN_ATTR_EARLY_MAP to 1 to enable stage 1 translation in iommu. */ -int sde_splash_clean_up_exit_lk(struct msm_kms *kms) +int sde_splash_lk_stop_splash(struct msm_kms *kms) { struct sde_splash_info *sinfo; struct msm_mmu *mmu; @@ -842,12 +792,11 @@ int sde_splash_clean_up_exit_lk(struct msm_kms *kms) /* Monitor LK's status and tell it to exit. */ mutex_lock(&sde_splash_lock); - if (sinfo->program_scratch_regs) { + if (sinfo->display_splash_enabled) { if (_sde_splash_lk_check(sde_kms->hw_intr)) - _sde_splash_notify_lk_exit(sde_kms->hw_intr); + _sde_splash_notify_lk_stop_splash(sde_kms->hw_intr); - sinfo->handoff = false; - sinfo->program_scratch_regs = false; + sinfo->display_splash_enabled = false; } mutex_unlock(&sde_splash_lock); @@ -864,7 +813,8 @@ int sde_splash_clean_up_exit_lk(struct msm_kms *kms) */ if (mmu->funcs && mmu->funcs->set_property) { ret = mmu->funcs->set_property(mmu, - DOMAIN_ATTR_EARLY_MAP, &sinfo->handoff); + DOMAIN_ATTR_EARLY_MAP, + &sinfo->display_splash_enabled); if (ret) SDE_ERROR("set_property failed\n"); diff --git a/drivers/gpu/drm/msm/sde/sde_splash.h b/drivers/gpu/drm/msm/sde/sde_splash.h index 0608b2db878d..2fd8ba03112f 100644 --- a/drivers/gpu/drm/msm/sde/sde_splash.h +++ b/drivers/gpu/drm/msm/sde/sde_splash.h @@ -53,8 +53,8 @@ struct sde_splash_info { /* current hw configuration */ struct sde_res_data res; - /* flag of display scratch registers */ - bool program_scratch_regs; + /* flag of display splash status */ + bool display_splash_enabled; /* to indicate LK is totally exited */ bool lk_is_exited; @@ -119,21 +119,20 @@ void sde_splash_setup_connector_count(struct sde_splash_info *sinfo, int connector_type); /** - * sde_splash_clean_up_exit_lk. + * sde_splash_lk_stop_splash. * - * Tell LK to exit, and clean up the resource. + * Tell LK to stop display splash. */ -int sde_splash_clean_up_exit_lk(struct msm_kms *kms); +int sde_splash_lk_stop_splash(struct msm_kms *kms); /** - * sde_splash_clean_up_free_resource. + * sde_splash_free_resource. * * According to input connector_type, free * HDMI's and DSI's resource respectively. */ -int sde_splash_clean_up_free_resource(struct msm_kms *kms, - struct sde_power_handle *phandle, - int connector_type, void *display); +int sde_splash_free_resource(struct msm_kms *kms, + struct sde_power_handle *phandle); /** * sde_splash_parse_memory_dt. @@ -180,7 +179,7 @@ void sde_splash_destroy(struct sde_splash_info *sinfo, * * Get LK's status to check if it has been stopped. */ -bool sde_splash_get_lk_complete_status(struct sde_splash_info *sinfo); +bool sde_splash_get_lk_complete_status(struct msm_kms *kms); /** * sde_splash_setup_display_resource -- 2.11.0