disp: msm: dsi: Add support for clk switch with constant FPS

There is lag or lead in the FPS during dynamic clock change,
along with the increment or decrement in clock. So, HFP or
VFP are adjusted to ensure a constant FPS.

Change-Id: I87ba7a185104a0f5f1d13734a7e487e728d6b2c0
Signed-off-by: Lipsa Rout <lrout@codeaurora.org>
Signed-off-by: Satya Rama Aditya Pinapala <psraditya30@codeaurora.org>
此提交包含在:
Lipsa Rout
2019-12-11 17:40:50 +05:30
提交者 Satya Rama Aditya Pinapala
父節點 5644d01f7a
當前提交 5e09ea2aed
共有 4 個檔案被更改,包括 143 行新增11 行删除

查看文件

@@ -4222,6 +4222,7 @@ static int dsi_display_dfps_update(struct dsi_display *display,
struct dsi_dfps_capabilities dfps_caps;
int rc = 0;
int i = 0;
struct dsi_dyn_clk_caps *dyn_clk_caps;
if (!display || !dsi_mode || !display->panel) {
DSI_ERR("Invalid params\n");
@@ -4230,8 +4231,9 @@ static int dsi_display_dfps_update(struct dsi_display *display,
timing = &dsi_mode->timing;
dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
if (!dfps_caps.dfps_support) {
DSI_ERR("dfps not supported\n");
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) {
DSI_ERR("dfps or constant fps not supported\n");
return -ENOTSUPP;
}
@@ -4508,7 +4510,32 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
display->name, rc);
goto error;
}
} else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_ctrl_update_host_config(ctrl->ctrl,
&display->config, mode, mode->dsi_mode_flags,
display->dsi_clk_handle);
if (rc) {
DSI_ERR("failed to update ctrl config\n");
goto error;
}
}
if (priv_info->phy_timing_len) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_phy_set_timing_params(ctrl->phy,
priv_info->phy_timing_val,
priv_info->phy_timing_len,
commit_phy_timing);
if (rc)
DSI_ERR("Fail to add timing params\n");
}
}
if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))
return rc;
}
if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) {
rc = dsi_display_dynamic_clk_switch_vid(display, mode);
if (rc)
@@ -5899,6 +5926,51 @@ int dsi_display_get_mode_count(struct dsi_display *display,
return 0;
}
void dsi_display_adjust_mode_timing(
struct dsi_dyn_clk_caps *dyn_clk_caps,
struct dsi_display_mode *dsi_mode,
int lanes, int bpp)
{
u32 new_htotal, new_vtotal, htotal, vtotal, old_htotal;
if (!dyn_clk_caps->maintain_const_fps)
return;
/*
* When there is a dynamic clock switch, there is small change
* in FPS. To compensate for this difference in FPS, hfp or vfp
* is adjusted. It has been assumed that the refined porch values
* are supported by the panel. This logic can be enhanced further
* in future by taking min/max porches supported by the panel.
*/
switch (dyn_clk_caps->type) {
case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP:
vtotal = DSI_V_TOTAL(&dsi_mode->timing);
old_htotal = dsi_h_total_dce(&dsi_mode->timing);
new_htotal = (dsi_mode->timing.clk_rate_hz * lanes);
new_htotal /= (bpp * vtotal * dsi_mode->timing.refresh_rate);
if (old_htotal > new_htotal)
dsi_mode->timing.h_front_porch -=
(old_htotal - new_htotal);
else
dsi_mode->timing.h_front_porch +=
(new_htotal - old_htotal);
break;
case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP:
htotal = dsi_h_total_dce(&dsi_mode->timing);
new_vtotal = (dsi_mode->timing.clk_rate_hz * lanes);
new_vtotal /= (bpp * htotal * dsi_mode->timing.refresh_rate);
dsi_mode->timing.v_front_porch = new_vtotal -
dsi_mode->timing.v_back_porch -
dsi_mode->timing.v_sync_width -
dsi_mode->timing.v_active;
break;
default:
break;
}
}
static void _dsi_display_populate_bit_clks(struct dsi_display *display,
int start, int end, u32 *mode_idx)
{
@@ -5938,6 +6010,9 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
* be based on user or device tree preferrence.
*/
src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
dsi_display_adjust_mode_timing(dyn_clk_caps, src, lanes, bpp);
src->pixel_clk_khz =
div_u64(src->timing.clk_rate_hz * lanes, bpp);
src->pixel_clk_khz /= 1000;
@@ -5957,6 +6032,10 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
}
memcpy(dst, src, sizeof(struct dsi_display_mode));
dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i];
dsi_display_adjust_mode_timing(dyn_clk_caps, dst, lanes,
bpp);
dst->pixel_clk_khz =
div_u64(dst->timing.clk_rate_hz * lanes, bpp);
dst->pixel_clk_khz /= 1000;
@@ -6251,13 +6330,28 @@ int dsi_display_find_mode(struct dsi_display *display,
return rc;
}
static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur,
struct dsi_display_mode *adj)
{
/*
* If there is a change in the hfp or vfp of the current and adjoining
* mode,then either it is a dfps mode switch or dynamic clk change with
* constant fps.
*/
if ((cur->timing.h_front_porch != adj->timing.h_front_porch) ||
(cur->timing.v_front_porch != adj->timing.v_front_porch))
return true;
else
return false;
}
/**
* dsi_display_validate_mode_change() - Validate mode change case.
* @display: DSI display handle.
* @cur_mode: Current mode.
* @adj_mode: Mode to be set.
* MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there
* is change in fps but vactive and hactive are same.
* is change in hfp or vfp but vactive and hactive are same.
* DSI_MODE_FLAG_DYN_CLK flag is set if there
* is change in clk but vactive and hactive are same.
* Return: error code.
@@ -6281,14 +6375,14 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
}
mutex_lock(&display->display_lock);
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if ((cur_mode->timing.v_active == adj_mode->timing.v_active) &&
(cur_mode->timing.h_active == adj_mode->timing.h_active)) {
/* dfps change use case */
if (cur_mode->timing.refresh_rate !=
adj_mode->timing.refresh_rate) {
/* dfps and dynamic clock with const fps use case */
if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) {
dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
if (dfps_caps.dfps_support) {
if (dfps_caps.dfps_support ||
dyn_clk_caps->maintain_const_fps) {
DSI_DEBUG("Mode switch is seamless variable refresh\n");
adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
SDE_EVT32(cur_mode->timing.refresh_rate,
@@ -6300,10 +6394,11 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
/* dynamic clk change use case */
if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) {
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if (dyn_clk_caps->dyn_clk_support) {
DSI_DEBUG("dynamic clk change detected\n");
if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) {
if ((adj_mode->dsi_mode_flags &
DSI_MODE_FLAG_VRR) &&
(!dyn_clk_caps->maintain_const_fps)) {
DSI_ERR("dfps and dyn clk not supported in same commit\n");
rc = -ENOTSUPP;
goto error;