From 39bc44163c03ed1215c196c051ada74c09bbea1d Mon Sep 17 00:00:00 2001 From: Yujun Zhang Date: Mon, 21 Jan 2019 11:19:46 +0530 Subject: [PATCH] disp: msm: dsi: unify dynamic clk support for command mode Currently the dynamic bit clock switch trigger for command mode is supported via sysfs node. This might lead to unnecessary race conditions, when dsi driver is enabling the dsi bit clock as part of commit and at the same time if bit rate change via sysfs happens. So make the trigger happens via kernel mode set call as done for video mode. Change-Id: I17acb408d2b6dbd6fa41994e56262e31e43d088b Signed-off-by: Ritesh Kumar Signed-off-by: Yujun Zhang --- msm/dsi/dsi_display.c | 70 +++++++++++++++++++++++++++++++++++-------- msm/dsi/dsi_drm.c | 3 +- msm/dsi/dsi_panel.c | 16 +++++----- msm/sde/sde_crtc.c | 4 ++- msm/sde/sde_encoder.c | 15 ++++++---- 5 files changed, 82 insertions(+), 26 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index b2007450ea..4dc51b6773 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -2987,7 +2987,10 @@ static int dsi_display_clocks_init(struct dsi_display *display) goto error; } - if (dyn_clk_caps->dyn_clk_support) { + if (dyn_clk_caps->dyn_clk_support && + (display->panel->panel_mode == + DSI_OP_VIDEO_MODE)) { + if (dsi_display_check_prefix(src_byte, clk_name)) src->byte_clk = NULL; @@ -4016,7 +4019,7 @@ exit: return rc; } -static int dsi_display_dynamic_clk_switch(struct dsi_display *display, +static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display, struct dsi_display_mode *mode) { int rc = 0, mask, i; @@ -4085,6 +4088,39 @@ exit: return rc; } +static int dsi_display_dynamic_clk_configure_cmd(struct dsi_display *display, + int clk_rate) +{ + int rc = 0; + + if (clk_rate <= 0) { + pr_err("%s: bitrate should be greater than 0\n", __func__); + return -EINVAL; + } + + if (clk_rate == display->cached_clk_rate) { + pr_info("%s: ignore duplicated DSI clk setting\n", __func__); + return rc; + } + + display->cached_clk_rate = clk_rate; + + rc = dsi_display_update_dsi_bitrate(display, clk_rate); + if (!rc) { + pr_info("%s: bit clk is ready to be configured to '%d'\n", + __func__, clk_rate); + atomic_set(&display->clkrate_change_pending, 1); + } else { + pr_err("%s: Failed to prepare to configure '%d'. rc = %d\n", + __func__, clk_rate, rc); + /* Caching clock failed, so don't go on doing so. */ + atomic_set(&display->clkrate_change_pending, 0); + display->cached_clk_rate = 0; + } + + return rc; +} + static int dsi_display_dfps_update(struct dsi_display *display, struct dsi_display_mode *dsi_mode) { @@ -4318,7 +4354,7 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, struct dsi_display_mode *mode, u32 flags) { - int rc = 0; + int rc = 0, clk_rate = 0; int i; struct dsi_display_ctrl *ctrl; struct dsi_display_mode_priv_info *priv_info; @@ -4355,15 +4391,25 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, goto error; } } else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { - rc = dsi_display_dynamic_clk_switch(display, mode); - if (rc) - pr_err("dynamic clk change failed %d\n", rc); - /* - * skip rest of the opearations since - * dsi_display_dynamic_clk_switch() already takes - * care of them. - */ - return rc; + if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { + rc = dsi_display_dynamic_clk_switch_vid(display, mode); + if (rc) + pr_err("dynamic clk change failed %d\n", rc); + /* + * skip rest of the opearations since + * dsi_display_dynamic_clk_switch_vid() already takes + * care of them. + */ + return rc; + } else if (display->panel->panel_mode == DSI_OP_CMD_MODE) { + clk_rate = mode->timing.clk_rate_hz; + rc = dsi_display_dynamic_clk_configure_cmd(display, + clk_rate); + if (rc) { + pr_err("Failed to configure dynamic clk\n"); + return rc; + } + } } display_for_each_ctrl(i, display) { diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index decf9aa658..3dafde7603 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -231,7 +231,8 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) } if (c_bridge->dsi_mode.dsi_mode_flags & - (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) { + (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR | + DSI_MODE_FLAG_DYN_CLK)) { pr_debug("[%d] seamless enable\n", c_bridge->id); return; } diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 77ede1015d..7051b5932d 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -3093,12 +3093,9 @@ struct dsi_panel *dsi_panel_get(struct device *parent, pr_err("failed to parse qsync features, rc=%d\n", rc); } - if (panel->panel_mode == DSI_OP_VIDEO_MODE) { - rc = dsi_panel_parse_dyn_clk_caps(panel); - if (rc) - pr_err("failed to parse dynamic clk config, rc=%d\n", - rc); - } + rc = dsi_panel_parse_dyn_clk_caps(panel); + if (rc) + pr_err("failed to parse dynamic clk config, rc=%d\n", rc); rc = dsi_panel_parse_phy_props(panel); if (rc) { @@ -3522,6 +3519,7 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel, struct dsi_host_config *config) { int rc = 0; + struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps; if (!panel || !mode || !config) { pr_err("invalid params\n"); @@ -3549,7 +3547,11 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel, config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled; config->video_timing.dsc = &mode->priv_info->dsc; - config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz; + if (dyn_clk_caps->dyn_clk_support) + config->bit_clk_rate_hz_override = mode->timing.clk_rate_hz; + else + config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz; + config->esc_clk_rate_hz = 19200000; mutex_unlock(&panel->panel_lock); return rc; diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index aacf11293a..0a93c5aa9e 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -4057,7 +4057,9 @@ static void sde_crtc_enable(struct drm_crtc *crtc, /* return early if crtc is already enabled, do this after UIDLE check */ if (sde_crtc->enabled) { - if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode)) + if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode) || + msm_is_mode_seamless_dyn_clk(&crtc->state->adjusted_mode)) + SDE_DEBUG("%s extra crtc enable expected during DMS\n", sde_crtc->name); else diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index ec85900706..2db4a6ddd1 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2792,7 +2792,8 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, sde_encoder_virt_mode_switch(intf_mode, sde_enc, adj_mode); /* release resources before seamless mode change */ - if (msm_is_mode_seamless_dms(adj_mode)) { + if (msm_is_mode_seamless_dms(adj_mode) || + msm_is_mode_seamless_dyn_clk(adj_mode)) { /* restore resource state before releasing them */ ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_PRE_MODESET); @@ -2866,7 +2867,8 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, } /* update resources after seamless mode change */ - if (msm_is_mode_seamless_dms(adj_mode)) + if (msm_is_mode_seamless_dms(adj_mode) || + msm_is_mode_seamless_dyn_clk(adj_mode)) sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_POST_MODESET); } @@ -3147,7 +3149,8 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) } /* register input handler if not already registered */ - if (sde_enc->input_handler && !msm_is_mode_seamless_dms(cur_mode)) { + if (sde_enc->input_handler && !msm_is_mode_seamless_dms(cur_mode) && + !msm_is_mode_seamless_dyn_clk(cur_mode)) { ret = _sde_encoder_input_handler_register( sde_enc->input_handler); if (ret) @@ -3193,7 +3196,8 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) * already. Invoke restore to reconfigure the * new mode. */ - if (msm_is_mode_seamless_dms(cur_mode) && + if ((msm_is_mode_seamless_dms(cur_mode) || + msm_is_mode_seamless_dyn_clk(cur_mode)) && phys->ops.restore) phys->ops.restore(phys); else if (phys->ops.enable) @@ -3206,7 +3210,8 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) sde_enc->misr_frame_count); } - if (msm_is_mode_seamless_dms(cur_mode) && + if ((msm_is_mode_seamless_dms(cur_mode) || + msm_is_mode_seamless_dyn_clk(cur_mode)) && sde_enc->cur_master->ops.restore) sde_enc->cur_master->ops.restore(sde_enc->cur_master); else if (sde_enc->cur_master->ops.enable)