ソースを参照

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 <[email protected]>
Vara Reddy 4 年 前
コミット
c9cb9f51f3

+ 4 - 0
msm/dsi/dsi_catalog.c

@@ -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;
 	phy->ops.dyn_refresh_ops.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 =
 		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;
 	phy->ops.dyn_refresh_ops.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 =
 		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;
 	phy->ops.dyn_refresh_ops.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 =
 		dsi_phy_hw_v4_0_cache_phy_timings;
 	phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk;

+ 2 - 0
msm/dsi/dsi_catalog.h

@@ -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,
 				      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_config(struct dsi_phy_hw *phy,
 				struct dsi_phy_cfg *cfg, bool is_master);

+ 34 - 0
msm/dsi/dsi_display.c

@@ -4123,9 +4123,13 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
 					struct link_clk_freq *bkp_freq)
 {
 	int rc = 0, i;
+	u8 ctrl_version;
 	struct dsi_display_ctrl *m_ctrl, *ctrl;
+	struct dsi_dyn_clk_caps *dyn_clk_caps;
 
 	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);
 
@@ -4163,6 +4167,15 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
 	}
 	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 */
 	display_for_each_ctrl(i, display) {
 		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);
 	}
 
+defer_dfps_wait:
 	rc = dsi_clk_update_parent(&display->clock_info.src_clks,
 			      &display->clock_info.mux_clks);
 	if (rc)
@@ -4580,8 +4594,10 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
 	int rc = 0, clk_rate = 0;
 	int i;
 	struct dsi_display_ctrl *ctrl;
+	struct dsi_display_ctrl *mctrl;
 	struct dsi_display_mode_priv_info *priv_info;
 	bool commit_phy_timing = false;
+	struct dsi_dyn_clk_caps *dyn_clk_caps;
 
 	priv_info = mode->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,
 	       sizeof(display->lane_map));
 
+	mctrl = &display->ctrl[display->clk_master_idx];
+	dyn_clk_caps = &(display->panel->dyn_clk_caps);
+
 	if (mode->dsi_mode_flags &
 			(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);
 		if (rc) {
 			DSI_ERR("[%s]DSI dfps update failed, rc=%d\n",

+ 15 - 1
msm/dsi/dsi_drm.c

@@ -990,8 +990,9 @@ int dsi_conn_post_kickoff(struct drm_connector *connector,
 	struct dsi_display_mode adj_mode;
 	struct dsi_display *display;
 	struct dsi_display_ctrl *m_ctrl, *ctrl;
-	int i, rc = 0;
+	int i, rc = 0, ctrl_version;
 	bool enable;
+	struct dsi_dyn_clk_caps *dyn_clk_caps;
 
 	if (!connector || !connector->state) {
 		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);
 	adj_mode = c_bridge->dsi_mode;
 	display = c_bridge->display;
+	dyn_clk_caps = &(display->panel->dyn_clk_caps);
 
 	if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) {
 		m_ctrl = &display->ctrl[display->clk_master_idx];
+		ctrl_version = m_ctrl->ctrl->version;
 		rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false);
 		if (rc) {
 			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;
 		}
 
+		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 */
 		display_for_each_ctrl(i, display) {
 			ctrl = &display->ctrl[i];

+ 26 - 0
msm/dsi/dsi_phy.c

@@ -1196,6 +1196,32 @@ void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
 	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
  * @phy:	DSI PHY handle

+ 10 - 0
msm/dsi/dsi_phy.h

@@ -75,6 +75,7 @@ enum phy_ulps_return_type {
  * @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_required: True if phy regulator is required
+ * @dfps_trigger_mdpintf_flush: mdp intf flush controls dfps trigger.
  */
 struct msm_dsi_phy {
 	struct platform_device *pdev;
@@ -102,6 +103,7 @@ struct msm_dsi_phy {
 	bool allow_phy_power_off;
 	u32 regulator_min_datarate_bps;
 	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,
 				    struct dsi_dyn_clk_delay *delay,
 				    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
  * @phy:	DSI PHY handle

+ 8 - 0
msm/dsi/dsi_phy_hw.h

@@ -184,6 +184,14 @@ struct phy_dyn_refresh_ops {
 	 */
 	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
 	 * @phy:           Pointer to DSI PHY hardware instance.

+ 18 - 1
msm/dsi/dsi_phy_hw_v4_0.c

@@ -755,6 +755,23 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
 		    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)
 {
 	u32 reg;
@@ -766,7 +783,7 @@ void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
 	 */
 	if (!offset) {
 		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);
 		wmb(); /* ensure dynamic fps is cleared */
 		return;