disp: msm: dsi: enable dfps trigger at mdp intf flush

This change allows dynamic refresh trigger to sw trigger
and mdp intf flush. With this we can make sure that DSI
timing/clock update and mdp intf timings are updated in
one vsync.

Change-Id: Ic807f498e2e47be6dd0f1e11ff1fc0896a8ec758
Signed-off-by: Vara Reddy <varar@codeaurora.org>
This commit is contained in:
Vara Reddy
2020-08-18 08:45:42 -07:00
parent c75b0eb0a0
commit c9cb9f51f3
8 changed files with 117 additions and 2 deletions

View File

@@ -201,6 +201,7 @@ static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy)
dsi_phy_hw_v2_0_dyn_refresh_pipe_delay; dsi_phy_hw_v2_0_dyn_refresh_pipe_delay;
phy->ops.dyn_refresh_ops.dyn_refresh_helper = phy->ops.dyn_refresh_ops.dyn_refresh_helper =
dsi_phy_hw_v2_0_dyn_refresh_helper; dsi_phy_hw_v2_0_dyn_refresh_helper;
phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel = NULL;
phy->ops.dyn_refresh_ops.cache_phy_timings = phy->ops.dyn_refresh_ops.cache_phy_timings =
dsi_phy_hw_v2_0_cache_phy_timings; dsi_phy_hw_v2_0_cache_phy_timings;
} }
@@ -236,6 +237,7 @@ static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy)
dsi_phy_hw_v3_0_dyn_refresh_pipe_delay; dsi_phy_hw_v3_0_dyn_refresh_pipe_delay;
phy->ops.dyn_refresh_ops.dyn_refresh_helper = phy->ops.dyn_refresh_ops.dyn_refresh_helper =
dsi_phy_hw_v3_0_dyn_refresh_helper; dsi_phy_hw_v3_0_dyn_refresh_helper;
phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel = NULL;
phy->ops.dyn_refresh_ops.cache_phy_timings = phy->ops.dyn_refresh_ops.cache_phy_timings =
dsi_phy_hw_v3_0_cache_phy_timings; dsi_phy_hw_v3_0_cache_phy_timings;
} }
@@ -272,6 +274,8 @@ static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy)
dsi_phy_hw_v4_0_dyn_refresh_pipe_delay; dsi_phy_hw_v4_0_dyn_refresh_pipe_delay;
phy->ops.dyn_refresh_ops.dyn_refresh_helper = phy->ops.dyn_refresh_ops.dyn_refresh_helper =
dsi_phy_hw_v4_0_dyn_refresh_helper; dsi_phy_hw_v4_0_dyn_refresh_helper;
phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel =
dsi_phy_hw_v4_0_dyn_refresh_trigger_sel;
phy->ops.dyn_refresh_ops.cache_phy_timings = phy->ops.dyn_refresh_ops.cache_phy_timings =
dsi_phy_hw_v4_0_cache_phy_timings; dsi_phy_hw_v4_0_cache_phy_timings;
phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk; phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk;

View File

@@ -260,6 +260,8 @@ int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl);
int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings, int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
u32 *dst, u32 size); u32 *dst, u32 size);
void dsi_phy_hw_v4_0_dyn_refresh_trigger_sel(struct dsi_phy_hw *phy,
bool is_master);
void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset); void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy, void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg, bool is_master); struct dsi_phy_cfg *cfg, bool is_master);

View File

@@ -4123,9 +4123,13 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
struct link_clk_freq *bkp_freq) struct link_clk_freq *bkp_freq)
{ {
int rc = 0, i; int rc = 0, i;
u8 ctrl_version;
struct dsi_display_ctrl *m_ctrl, *ctrl; struct dsi_display_ctrl *m_ctrl, *ctrl;
struct dsi_dyn_clk_caps *dyn_clk_caps;
m_ctrl = &display->ctrl[display->clk_master_idx]; m_ctrl = &display->ctrl[display->clk_master_idx];
dyn_clk_caps = &(display->panel->dyn_clk_caps);
ctrl_version = m_ctrl->ctrl->version;
dsi_clk_prepare_enable(&display->clock_info.src_clks); dsi_clk_prepare_enable(&display->clock_info.src_clks);
@@ -4163,6 +4167,15 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
} }
dsi_phy_dynamic_refresh_trigger(m_ctrl->phy, true); dsi_phy_dynamic_refresh_trigger(m_ctrl->phy, true);
/*
* Don't wait for dynamic refresh done for dsi ctrl greater than 2.5
* and with constant fps, as dynamic refresh will applied with
* next mdp intf ctrl flush.
*/
if ((ctrl_version >= DSI_CTRL_VERSION_2_5) &&
(dyn_clk_caps->maintain_const_fps))
goto defer_dfps_wait;
/* wait for dynamic refresh done */ /* wait for dynamic refresh done */
display_for_each_ctrl(i, display) { display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i]; ctrl = &display->ctrl[i];
@@ -4181,6 +4194,7 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
dsi_phy_dynamic_refresh_clear(ctrl->phy); dsi_phy_dynamic_refresh_clear(ctrl->phy);
} }
defer_dfps_wait:
rc = dsi_clk_update_parent(&display->clock_info.src_clks, rc = dsi_clk_update_parent(&display->clock_info.src_clks,
&display->clock_info.mux_clks); &display->clock_info.mux_clks);
if (rc) if (rc)
@@ -4580,8 +4594,10 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
int rc = 0, clk_rate = 0; int rc = 0, clk_rate = 0;
int i; int i;
struct dsi_display_ctrl *ctrl; struct dsi_display_ctrl *ctrl;
struct dsi_display_ctrl *mctrl;
struct dsi_display_mode_priv_info *priv_info; struct dsi_display_mode_priv_info *priv_info;
bool commit_phy_timing = false; bool commit_phy_timing = false;
struct dsi_dyn_clk_caps *dyn_clk_caps;
priv_info = mode->priv_info; priv_info = mode->priv_info;
if (!priv_info) { if (!priv_info) {
@@ -4607,8 +4623,26 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
memcpy(&display->config.lane_map, &display->lane_map, memcpy(&display->config.lane_map, &display->lane_map,
sizeof(display->lane_map)); sizeof(display->lane_map));
mctrl = &display->ctrl[display->clk_master_idx];
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if (mode->dsi_mode_flags & if (mode->dsi_mode_flags &
(DSI_MODE_FLAG_DFPS | DSI_MODE_FLAG_VRR)) { (DSI_MODE_FLAG_DFPS | DSI_MODE_FLAG_VRR)) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
ctrl->ctrl->hw.ops.set_timing_db(&ctrl->ctrl->hw,
true);
dsi_phy_dynamic_refresh_clear(ctrl->phy);
if (!ctrl->ctrl || (ctrl != mctrl))
continue;
if ((ctrl->ctrl->version >= DSI_CTRL_VERSION_2_5) &&
(dyn_clk_caps->maintain_const_fps)) {
dsi_phy_dynamic_refresh_trigger_sel(ctrl->phy,
true);
}
}
rc = dsi_display_dfps_update(display, mode); rc = dsi_display_dfps_update(display, mode);
if (rc) { if (rc) {
DSI_ERR("[%s]DSI dfps update failed, rc=%d\n", DSI_ERR("[%s]DSI dfps update failed, rc=%d\n",

View File

@@ -990,8 +990,9 @@ int dsi_conn_post_kickoff(struct drm_connector *connector,
struct dsi_display_mode adj_mode; struct dsi_display_mode adj_mode;
struct dsi_display *display; struct dsi_display *display;
struct dsi_display_ctrl *m_ctrl, *ctrl; struct dsi_display_ctrl *m_ctrl, *ctrl;
int i, rc = 0; int i, rc = 0, ctrl_version;
bool enable; bool enable;
struct dsi_dyn_clk_caps *dyn_clk_caps;
if (!connector || !connector->state) { if (!connector || !connector->state) {
DSI_ERR("invalid connector or connector state\n"); DSI_ERR("invalid connector or connector state\n");
@@ -1007,9 +1008,11 @@ int dsi_conn_post_kickoff(struct drm_connector *connector,
c_bridge = to_dsi_bridge(encoder->bridge); c_bridge = to_dsi_bridge(encoder->bridge);
adj_mode = c_bridge->dsi_mode; adj_mode = c_bridge->dsi_mode;
display = c_bridge->display; display = c_bridge->display;
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) { if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) {
m_ctrl = &display->ctrl[display->clk_master_idx]; m_ctrl = &display->ctrl[display->clk_master_idx];
ctrl_version = m_ctrl->ctrl->version;
rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false); rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false);
if (rc) { if (rc) {
DSI_ERR("[%s] failed to dfps update rc=%d\n", DSI_ERR("[%s] failed to dfps update rc=%d\n",
@@ -1017,6 +1020,17 @@ int dsi_conn_post_kickoff(struct drm_connector *connector,
return -EINVAL; return -EINVAL;
} }
if ((ctrl_version >= DSI_CTRL_VERSION_2_5) &&
(dyn_clk_caps->maintain_const_fps)) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_ctrl_wait4dynamic_refresh_done(
ctrl->ctrl);
if (rc)
DSI_ERR("wait4dfps refresh failed\n");
}
}
/* Update the rest of the controllers */ /* Update the rest of the controllers */
display_for_each_ctrl(i, display) { display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i]; ctrl = &display->ctrl[i];

View File

@@ -1196,6 +1196,32 @@ void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
mutex_unlock(&phy->phy_lock); mutex_unlock(&phy->phy_lock);
} }
/**
* dsi_phy_dynamic_refresh_trigger_sel() - trigger dynamic refresh and
* update the video timings at next frame flush call.
* @phy: DSI PHY handle
* @is_master: Boolean to indicate if for master or slave.
*/
void dsi_phy_dynamic_refresh_trigger_sel(struct msm_dsi_phy *phy,
bool is_master)
{
if (!phy)
return;
mutex_lock(&phy->phy_lock);
/*
* program DYNAMIC_REFRESH_CTRL.TRIGGER_SEL for master.
*/
if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_trigger_sel)
phy->hw.ops.dyn_refresh_ops.dyn_refresh_trigger_sel
(&phy->hw, is_master);
phy->dfps_trigger_mdpintf_flush = true;
SDE_EVT32(is_master, phy->index);
mutex_unlock(&phy->phy_lock);
}
/** /**
* dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
* @phy: DSI PHY handle * @phy: DSI PHY handle

View File

@@ -75,6 +75,7 @@ enum phy_ulps_return_type {
* @allow_phy_power_off: True if PHY is allowed to power off when idle * @allow_phy_power_off: True if PHY is allowed to power off when idle
* @regulator_min_datarate_bps: Minimum per lane data rate to turn on regulator * @regulator_min_datarate_bps: Minimum per lane data rate to turn on regulator
* @regulator_required: True if phy regulator is required * @regulator_required: True if phy regulator is required
* @dfps_trigger_mdpintf_flush: mdp intf flush controls dfps trigger.
*/ */
struct msm_dsi_phy { struct msm_dsi_phy {
struct platform_device *pdev; struct platform_device *pdev;
@@ -102,6 +103,7 @@ struct msm_dsi_phy {
bool allow_phy_power_off; bool allow_phy_power_off;
u32 regulator_min_datarate_bps; u32 regulator_min_datarate_bps;
bool regulator_required; bool regulator_required;
bool dfps_trigger_mdpintf_flush;
}; };
/** /**
@@ -323,6 +325,14 @@ int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy, void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
struct dsi_dyn_clk_delay *delay, struct dsi_dyn_clk_delay *delay,
bool is_master); bool is_master);
/**
* dsi_phy_dynamic_refresh_trigger_sel() - dynamic refresh trigger select.
* @phy: DSI PHY handle
* @is_master: Boolean to indicate if for master or slave.
*/
void dsi_phy_dynamic_refresh_trigger_sel(struct msm_dsi_phy *phy,
bool is_master);
/** /**
* dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh * dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
* @phy: DSI PHY handle * @phy: DSI PHY handle

View File

@@ -184,6 +184,14 @@ struct phy_dyn_refresh_ops {
*/ */
void (*dyn_refresh_helper)(struct dsi_phy_hw *phy, u32 offset); void (*dyn_refresh_helper)(struct dsi_phy_hw *phy, u32 offset);
/**
* dyn_refresh_trigger_sel - configure trigger_sel to frame flush
* @phy: Pointer to DSI PHY hardware instance.
* @is_master: Boolean to indicate whether master or slave.
*/
void (*dyn_refresh_trigger_sel)(struct dsi_phy_hw *phy,
bool is_master);
/** /**
* dyn_refresh_config - configure dynamic refresh ctrl registers * dyn_refresh_config - configure dynamic refresh ctrl registers
* @phy: Pointer to DSI PHY hardware instance. * @phy: Pointer to DSI PHY hardware instance.

View File

@@ -755,6 +755,23 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
delay->pll_delay); delay->pll_delay);
} }
void dsi_phy_hw_v4_0_dyn_refresh_trigger_sel(struct dsi_phy_hw *phy,
bool is_master)
{
u32 reg;
/*
* Dynamic refresh will take effect at next mdp flush event.
* This makes sure that any update to frame timings together
* with dfps will take effect in one vsync at next mdp flush.
*/
if (is_master) {
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
reg |= BIT(17);
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
}
}
void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset) void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
{ {
u32 reg; u32 reg;
@@ -766,7 +783,7 @@ void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
*/ */
if (!offset) { if (!offset) {
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL); reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
reg &= ~(BIT(0) | BIT(8)); reg &= ~(BIT(0) | BIT(8) | BIT(13) | BIT(16) | BIT(17));
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg); DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
wmb(); /* ensure dynamic fps is cleared */ wmb(); /* ensure dynamic fps is cleared */
return; return;