disp: msm: dsi: add support for dsi dynamic clock switch

This change adds support for dynamic switching of dsi clocks
to avoid RF interference issues. Also with dynamic dsi clock
switch feature coming into picture, now populate the supported
refresh rate as list instead of providing a range. Modify the
logic to enumerate all the modes in dsi driver, taking dynamic
bit clocks, resolutions and refresh rates into account.

Change-Id: I5b6e62bc935cf2234bdd96fcb3c7537b4e735fff
Signed-off-by: Sandeep Panda <spanda@codeaurora.org>
Signed-off-by: Ritesh Kumar <riteshk@codeaurora.org>
Signed-off-by: Yujun Zhang <yujunzhang@codeaurora.org>
This commit is contained in:
Yujun Zhang
2018-10-25 15:49:16 +05:30
parent 6ec69969e2
commit b0f2e2222e
27 changed files with 1331 additions and 446 deletions

View File

@@ -73,6 +73,8 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
if (msm_is_mode_seamless_poms(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS;
if (msm_is_mode_seamless_dyn_clk(drm_mode))
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK;
dsi_mode->timing.h_sync_polarity =
!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
@@ -88,6 +90,8 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
struct drm_display_mode *drm_mode)
{
bool video_mode = (dsi_mode->panel_mode == DSI_OP_VIDEO_MODE);
memset(drm_mode, 0, sizeof(*drm_mode));
drm_mode->hdisplay = dsi_mode->timing.h_active;
@@ -122,6 +126,8 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS)
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS;
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK;
if (dsi_mode->timing.h_sync_polarity)
drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
@@ -133,7 +139,11 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
if (dsi_mode->panel_mode == DSI_OP_CMD_MODE)
drm_mode->flags |= DRM_MODE_FLAG_CMD_MODE_PANEL;
drm_mode_set_name(drm_mode);
/* set mode name */
snprintf(drm_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%dx%dx%d%s",
drm_mode->hdisplay, drm_mode->vdisplay,
drm_mode->vrefresh, drm_mode->clock,
video_mode ? "vid" : "cmd");
}
static int dsi_bridge_attach(struct drm_bridge *bridge)
@@ -178,7 +188,8 @@ static void dsi_bridge_pre_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 pre-enable\n", c_bridge->id);
return;
}
@@ -311,6 +322,12 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
/* restore bit_clk_rate also for dynamic clk use cases */
c_bridge->dsi_mode.timing.clk_rate_hz =
dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode);
pr_debug("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz);
}
static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
@@ -379,11 +396,13 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
cur_dsi_mode.timing.dsc_enabled =
dsi_mode.priv_info->dsc_enabled;
cur_dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
rc = dsi_display_validate_mode_vrr(c_bridge->display,
rc = dsi_display_validate_mode_change(c_bridge->display,
&cur_dsi_mode, &dsi_mode);
if (rc)
pr_debug("[%s] vrr mode mismatch failure rc=%d\n",
if (rc) {
pr_err("[%s] seamless mode mismatch failure rc=%d\n",
c_bridge->display->name, rc);
return false;
}
cur_mode = crtc_state->crtc->mode;
@@ -397,6 +416,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
if (!drm_mode_equal(&cur_mode, adjusted_mode) &&
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS)) &&
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) &&
(!crtc_state->active_changed ||
display->is_cont_splash_enabled))
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
@@ -408,6 +428,33 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
return true;
}
u64 dsi_drm_find_bit_clk_rate(void *display,
const struct drm_display_mode *drm_mode)
{
int i = 0, count = 0;
struct dsi_display *dsi_display = display;
struct dsi_display_mode *dsi_mode;
u64 bit_clk_rate = 0;
if (!dsi_display || !drm_mode)
return 0;
dsi_display_get_mode_count(dsi_display, &count);
for (i = 0; i < count; i++) {
dsi_mode = &dsi_display->modes[i];
if ((dsi_mode->timing.v_active == drm_mode->vdisplay) &&
(dsi_mode->timing.h_active == drm_mode->hdisplay) &&
(dsi_mode->pixel_clk_khz == drm_mode->clock) &&
(dsi_mode->timing.refresh_rate == drm_mode->vrefresh)) {
bit_clk_rate = dsi_mode->timing.clk_rate_hz;
break;
}
}
return bit_clk_rate;
}
int dsi_conn_get_mode_info(struct drm_connector *connector,
const struct drm_display_mode *drm_mode,
struct msm_mode_info *mode_info,
@@ -432,7 +479,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines;
mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer;
mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom;
mode_info->clk_rate = dsi_mode.priv_info->clk_rate_hz;
mode_info->clk_rate = dsi_drm_find_bit_clk_rate(display, drm_mode);
mode_info->mdp_transfer_time_us =
dsi_mode.priv_info->mdp_transfer_time_us;
@@ -538,6 +585,9 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
panel->dfps_caps.max_refresh_rate);
}
sde_kms_info_add_keystr(info, "dyn bitclk support",
panel->dyn_clk_caps.dyn_clk_support ? "true" : "false");
switch (panel->phy_props.rotation) {
case DSI_PANEL_ROTATE_NONE:
sde_kms_info_add_keystr(info, "panel orientation", "none");
@@ -796,6 +846,9 @@ int dsi_connector_get_modes(struct drm_connector *connector, void *data)
}
m->width_mm = connector->display_info.width_mm;
m->height_mm = connector->display_info.height_mm;
/* set the first mode in list as preferred */
if (i == 0)
m->type |= DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, m);
}
@@ -915,6 +968,9 @@ int dsi_conn_post_kickoff(struct drm_connector *connector)
c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR;
}
/* ensure dynamic clk switch flag is reset */
c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_DYN_CLK;
return 0;
}