Ver Fonte

disp: msm: add support for seamless dsc switch

This change adds logic to determine dsc switch based on
the connector property "CONNECTOR_PROP_DSC_MODE" and
performs seamless DSC switch if there is any change in
DSC configuration. The connector property is populated
in msm_sub_mode based on which suitable mode is selected.

Change-Id: Ifc4931f16dfb814781bc1d72b103e09103e6bfee
Signed-off-by: Yashwanth <[email protected]>
Yashwanth há 4 anos atrás
pai
commit
7e03fb61fd

+ 1 - 0
msm/dp/dp_drm.c

@@ -377,6 +377,7 @@ end:
 
 int dp_connector_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res)
 {

+ 4 - 1
msm/dp/dp_drm.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DP_DRM_H_
@@ -103,12 +103,14 @@ enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
  * @connector: Pointer to drm connector structure
  * @drm_mode: Display mode set for the display
  * @mode_info: Out parameter. Information of the mode
+ * @sub_mode: Additional mode info to drm display mode
  * @display: Pointer to private display structure
  * @avail_res: Pointer with curr available resources
  * Returns: zero on success
  */
 int dp_connector_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res);
 
@@ -216,6 +218,7 @@ static inline enum drm_mode_status dp_connector_mode_valid(
 
 static inline int dp_connector_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res)
 {

+ 2 - 1
msm/dp/dp_mst_drm.c

@@ -1116,6 +1116,7 @@ int dp_mst_connector_get_info(struct drm_connector *connector,
 
 int dp_mst_connector_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display,
 		const struct msm_resource_caps_info *avail_res)
@@ -1125,7 +1126,7 @@ int dp_mst_connector_get_mode_info(struct drm_connector *connector,
 	DP_MST_DEBUG("enter:\n");
 	SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, connector->base.id);
 
-	rc = dp_connector_get_mode_info(connector, drm_mode, mode_info,
+	rc = dp_connector_get_mode_info(connector, drm_mode, NULL, mode_info,
 			display, avail_res);
 
 	DP_MST_DEBUG("mst connector:%d get mode info. rc:%d\n",

+ 28 - 8
msm/dsi/dsi_display.c

@@ -36,10 +36,6 @@
 
 #define SEC_PANEL_NAME_MAX_LEN  256
 
-#define DSI_MODE_MATCH_ACTIVE_TIMINGS (1 << 0)
-#define DSI_MODE_MATCH_PORCH_TIMINGS (1 << 1)
-#define DSI_MODE_MATCH_FULL_TIMINGS (DSI_MODE_MATCH_ACTIVE_TIMINGS | DSI_MODE_MATCH_PORCH_TIMINGS)
-
 u8 dbgfs_tx_cmd_buf[SZ_4K];
 static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
 static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN];
@@ -6235,7 +6231,7 @@ static int dsi_display_ext_get_info(struct drm_connector *connector,
 }
 
 static int dsi_display_ext_get_mode_info(struct drm_connector *connector,
-	const struct drm_display_mode *drm_mode,
+	const struct drm_display_mode *drm_mode, struct msm_sub_mode *sub_mode,
 	struct msm_mode_info *mode_info,
 	void *display, const struct msm_resource_caps_info *avail_res)
 {
@@ -7167,11 +7163,16 @@ static bool dsi_display_mode_match(const struct dsi_display_mode *mode1,
 			!dsi_display_match_timings(mode1, mode2, match_flags))
 		return false;
 
+	if ((match_flags & DSI_MODE_MATCH_DSC_CONFIG) &&
+			mode1->priv_info->dsc_enabled != mode2->priv_info->dsc_enabled)
+		return false;
+
 	return true;
 }
 
 int dsi_display_find_mode(struct dsi_display *display,
-		const struct dsi_display_mode *cmp,
+		struct dsi_display_mode *cmp,
+		struct msm_sub_mode *sub_mode,
 		struct dsi_display_mode **out_mode)
 {
 	u32 count, i;
@@ -7179,6 +7180,7 @@ int dsi_display_find_mode(struct dsi_display *display,
 	struct dsi_display_mode *m;
 	struct dsi_dyn_clk_caps *dyn_clk_caps;
 	unsigned int match_flags = DSI_MODE_MATCH_FULL_TIMINGS;
+	struct dsi_display_mode_priv_info priv_info;
 
 	if (!display || !out_mode)
 		return -EINVAL;
@@ -7209,6 +7211,15 @@ int dsi_display_find_mode(struct dsi_display *display,
 		if (dyn_clk_caps->maintain_const_fps)
 			match_flags = DSI_MODE_MATCH_ACTIVE_TIMINGS;
 
+		if (sub_mode && sub_mode->dsc_mode) {
+			match_flags |= DSI_MODE_MATCH_DSC_CONFIG;
+			cmp->priv_info = &priv_info;
+			memset(cmp->priv_info, 0,
+				sizeof(struct dsi_display_mode_priv_info));
+			cmp->priv_info->dsc_enabled = (sub_mode->dsc_mode ==
+				MSM_DISPLAY_DSC_MODE_ENABLED) ? true : false;
+		}
+
 		if (dsi_display_mode_match(cmp, m, match_flags)) {
 			*out_mode = m;
 			rc = 0;
@@ -7286,11 +7297,20 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
 	if (sde_conn->expected_panel_mode == MSM_DISPLAY_VIDEO_MODE &&
 		display->config.panel_mode == DSI_OP_CMD_MODE) {
 		adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS_TO_VID;
+		SDE_EVT32(SDE_EVTLOG_FUNC_CASE1, sde_conn->expected_panel_mode,
+			display->config.panel_mode);
 		DSI_DEBUG("Panel operating mode change to video detected\n");
 	} else if (sde_conn->expected_panel_mode == MSM_DISPLAY_CMD_MODE &&
 		display->config.panel_mode == DSI_OP_VIDEO_MODE) {
 		adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS_TO_CMD;
+		SDE_EVT32(SDE_EVTLOG_FUNC_CASE2, sde_conn->expected_panel_mode,
+			display->config.panel_mode);
 		DSI_DEBUG("Panel operating mode change to command detected\n");
+	} else if (cur_mode->timing.dsc_enabled != adj_mode->timing.dsc_enabled) {
+		adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
+		SDE_EVT32(SDE_EVTLOG_FUNC_CASE3, cur_mode->timing.dsc_enabled,
+				adj_mode->timing.dsc_enabled);
+		DSI_DEBUG("DSC mode change detected\n");
 	} else {
 		dyn_clk_caps = &(display->panel->dyn_clk_caps);
 		/* dfps and dynamic clock with const fps use case */
@@ -7300,7 +7320,7 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
 				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(SDE_EVTLOG_FUNC_CASE1,
+				SDE_EVT32(SDE_EVTLOG_FUNC_CASE4,
 					cur_mode->timing.refresh_rate,
 					adj_mode->timing.refresh_rate,
 					cur_mode->timing.h_front_porch,
@@ -7333,7 +7353,7 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
 
 				adj_mode->dsi_mode_flags |=
 						DSI_MODE_FLAG_DYN_CLK;
-				SDE_EVT32(SDE_EVTLOG_FUNC_CASE2,
+				SDE_EVT32(SDE_EVTLOG_FUNC_CASE5,
 					cur_mode->pixel_clk_khz,
 					adj_mode->pixel_clk_khz);
 			}

+ 9 - 1
msm/dsi/dsi_display.h

@@ -24,6 +24,12 @@
 #define DSI_CLIENT_NAME_SIZE		20
 #define MAX_CMDLINE_PARAM_LEN	 512
 #define MAX_CMD_PAYLOAD_SIZE	256
+
+#define DSI_MODE_MATCH_ACTIVE_TIMINGS (1 << 0)
+#define DSI_MODE_MATCH_PORCH_TIMINGS (1 << 1)
+#define DSI_MODE_MATCH_FULL_TIMINGS (DSI_MODE_MATCH_ACTIVE_TIMINGS | DSI_MODE_MATCH_PORCH_TIMINGS)
+#define DSI_MODE_MATCH_DSC_CONFIG (1 << 2)
+
 /*
  * DSI Validate Mode modifiers
  * @DSI_VALIDATE_FLAG_ALLOW_ADJUST:	Allow mode validation to also do fixup
@@ -436,12 +442,14 @@ int dsi_display_get_avr_step_req_fps(void *dsi_display, u32 mode_fps);
  * dsi_display_find_mode() - retrieve cached DSI mode given relevant params
  * @display:            Handle to display.
  * @cmp:                Mode to use as comparison to find original
+ * @sub_mode:           Additional mode info to drm display mode
  * @out_mode:           Output parameter, pointer to retrieved mode
  *
  * Return: error code.
  */
 int dsi_display_find_mode(struct dsi_display *display,
-		const struct dsi_display_mode *cmp,
+		struct dsi_display_mode *cmp,
+		struct msm_sub_mode *sub_mode,
 		struct dsi_display_mode **out_mode);
 /**
  * dsi_display_validate_mode() - validates if mode is supported by display

+ 21 - 19
msm/dsi/dsi_drm.c

@@ -398,7 +398,8 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode;
 	struct drm_crtc_state *crtc_state;
 	struct drm_connector_state *drm_conn_state;
-	struct sde_connector_state *conn_state;
+	struct sde_connector_state *conn_state, *old_conn_state;
+	struct msm_sub_mode new_sub_mode;
 
 	crtc_state = container_of(mode, struct drm_crtc_state, mode);
 
@@ -435,12 +436,15 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 
 	convert_to_dsi_mode(mode, &dsi_mode);
 	msm_parse_mode_priv_info(&conn_state->msm_mode, &dsi_mode);
+	new_sub_mode.dsc_mode = sde_connector_get_property(drm_conn_state,
+				CONNECTOR_PROP_DSC_MODE);
 
 	/*
 	 * retrieve dsi mode from dsi driver's cache since not safe to take
 	 * the drm mode config mutex in all paths
 	 */
-	rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
+	rc = dsi_display_find_mode(display, &dsi_mode, &new_sub_mode,
+						&panel_dsi_mode);
 	if (rc)
 		return rc;
 
@@ -474,10 +478,11 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 			crtc_state->crtc) {
 		const struct drm_display_mode *cur_mode =
 				&crtc_state->crtc->state->mode;
+		old_conn_state = to_sde_connector_state(display->drm_conn->state);
+
 		convert_to_dsi_mode(cur_mode, &cur_dsi_mode);
-		cur_dsi_mode.timing.dsc_enabled =
-				dsi_mode.priv_info->dsc_enabled;
-		cur_dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
+		msm_parse_mode_priv_info(&old_conn_state->msm_mode, &cur_dsi_mode);
+
 		rc = dsi_display_validate_mode_change(c_bridge->display,
 					&cur_dsi_mode, &dsi_mode);
 		if (rc) {
@@ -546,6 +551,7 @@ u32 dsi_drm_get_dfps_maxfps(void *display)
 
 int dsi_conn_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res)
 {
@@ -557,7 +563,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 		return -EINVAL;
 
 	convert_to_dsi_mode(drm_mode, &partial_dsi_mode);
-	rc = dsi_display_find_mode(display, &partial_dsi_mode, &dsi_mode);
+	rc = dsi_display_find_mode(display, &partial_dsi_mode, sub_mode, &dsi_mode);
 	if (rc || !dsi_mode->priv_info)
 		return -EINVAL;
 
@@ -831,25 +837,21 @@ enum drm_connector_status dsi_conn_detect(struct drm_connector *conn,
 void dsi_connector_put_modes(struct drm_connector *connector,
 	void *display)
 {
-	struct drm_display_mode *drm_mode;
-	struct dsi_display_mode dsi_mode, *full_dsi_mode = NULL;
 	struct dsi_display *dsi_display;
-	int rc = 0;
+	int count, i;
 
 	if (!connector || !display)
 		return;
 
-	list_for_each_entry(drm_mode, &connector->modes, head) {
-		convert_to_dsi_mode(drm_mode, &dsi_mode);
-		rc = dsi_display_find_mode(display, &dsi_mode, &full_dsi_mode);
-		if (rc)
-			continue;
+	dsi_display = display;
+	count = dsi_display->panel->num_display_modes;
+	for (i = 0; i < count; i++) {
+		struct dsi_display_mode *dsi_mode = &dsi_display->modes[i];
 
-		dsi_display_put_mode(display, full_dsi_mode);
+		dsi_display_put_mode(dsi_display, dsi_mode);
 	}
 
 	/* free the display structure modes also */
-	dsi_display = display;
 	kfree(dsi_display->modes);
 	dsi_display->modes = NULL;
 }
@@ -1050,7 +1052,7 @@ enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector,
 	if (conn_state)
 		msm_parse_mode_priv_info(&conn_state->msm_mode, &dsi_mode);
 
-	rc = dsi_display_find_mode(display, &dsi_mode, &full_dsi_mode);
+	rc = dsi_display_find_mode(display, &dsi_mode, NULL, &full_dsi_mode);
 	if (rc) {
 		DSI_ERR("could not find mode %s\n", mode->name);
 		return MODE_ERROR;
@@ -1273,7 +1275,7 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
 
 		convert_to_dsi_mode(drm_mode, &dsi_mode);
 
-		rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode);
+		rc = dsi_display_find_mode(display, &dsi_mode, NULL, &panel_dsi_mode);
 		if (rc)
 			return;
 
@@ -1290,7 +1292,7 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
 			convert_to_dsi_mode(cmp_drm_mode, &dsi_mode);
 
 			rc = dsi_display_find_mode(display, &dsi_mode,
-					&cmp_panel_dsi_mode);
+					NULL, &cmp_panel_dsi_mode);
 			if (rc)
 				return;
 

+ 2 - 0
msm/dsi/dsi_drm.h

@@ -68,6 +68,7 @@ void dsi_connector_put_modes(struct drm_connector *connector,
 /**
  * dsi_conn_get_mode_info - retrieve information on the mode selected
  * @drm_mode: Display mode set for the display
+ * @sub_mode: Additional mode info to drm display mode
  * @mode_info: Out parameter. information of the mode.
  * @display: Pointer to private display structure
  * @avail_res: Pointer with curr available resources
@@ -75,6 +76,7 @@ void dsi_connector_put_modes(struct drm_connector *connector,
  */
 int dsi_conn_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res);
 

+ 21 - 0
msm/msm_drv.h

@@ -226,6 +226,7 @@ enum msm_mdp_conn_property {
 	CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE,
 	CONNECTOR_PROP_SET_PANEL_MODE,
 	CONNECTOR_PROP_AVR_STEP,
+	CONNECTOR_PROP_DSC_MODE,
 
 	/* total # of properties */
 	CONNECTOR_PROP_COUNT
@@ -307,6 +308,18 @@ enum panel_op_mode {
 	MSM_DISPLAY_MODE_MAX = BIT(2)
 };
 
+/**
+ * enum msm_display_dsc_mode - panel dsc mode
+ * @MSM_DISPLAY_DSC_MODE_NONE: No operation
+ * @MSM_DISPLAY_DSC_MODE_ENABLED: DSC is enabled
+ * @MSM_DISPLAY_DSC_MODE_DISABLED: DSC is disabled
+ */
+enum msm_display_dsc_mode {
+	MSM_DISPLAY_DSC_MODE_NONE,
+	MSM_DISPLAY_DSC_MODE_ENABLED,
+	MSM_DISPLAY_DSC_MODE_DISABLED,
+};
+
 /**
  * struct msm_display_mode - wrapper for drm_display_mode
  * @base: drm_display_mode attached to this msm_mode
@@ -319,6 +332,14 @@ struct msm_display_mode {
 	u32 *private;
 };
 
+/**
+ * struct msm_sub_mode - msm display sub mode
+ * @dsc_enabled: boolean used to indicate if dsc should be enabled
+ */
+struct msm_sub_mode {
+	enum msm_display_dsc_mode dsc_mode;
+};
+
 /**
  * struct msm_ratio - integer ratio
  * @numer: numerator

+ 3 - 0
msm/msm_kms.h

@@ -295,6 +295,9 @@ static inline bool msm_is_private_mode_changed(
 	if (msm_is_mode_seamless_dyn_clk(msm_mode))
 		return true;
 
+	if (msm_is_mode_seamless_dms(msm_mode))
+		return true;
+
 	return false;
 }
 

+ 11 - 2
msm/sde/sde_connector.c

@@ -66,6 +66,11 @@ static const struct drm_prop_enum_list e_qsync_mode[] = {
 	{SDE_RM_QSYNC_CONTINUOUS_MODE,	"continuous"},
 	{SDE_RM_QSYNC_ONE_SHOT_MODE,	"one_shot"},
 };
+static const struct drm_prop_enum_list e_dsc_mode[] = {
+	{MSM_DISPLAY_DSC_MODE_NONE, "none"},
+	{MSM_DISPLAY_DSC_MODE_ENABLED, "dsc_enabled"},
+	{MSM_DISPLAY_DSC_MODE_DISABLED, "dsc_disabled"},
+};
 static const struct drm_prop_enum_list e_frame_trigger_mode[] = {
 	{FRAME_DONE_WAIT_DEFAULT, "default"},
 	{FRAME_DONE_WAIT_SERIALIZE, "serialize_frame_trigger"},
@@ -441,6 +446,7 @@ int sde_connector_set_msm_mode(struct drm_connector_state *conn_state,
 
 int sde_connector_get_mode_info(struct drm_connector *conn,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info)
 {
 	struct sde_connector *sde_conn;
@@ -455,7 +461,7 @@ int sde_connector_get_mode_info(struct drm_connector *conn,
 
 	sde_connector_get_avail_res_info(conn, &avail_res);
 
-	return sde_conn->ops.get_mode_info(conn, drm_mode,
+	return sde_conn->ops.get_mode_info(conn, drm_mode, sub_mode,
 			mode_info, sde_conn->display, &avail_res);
 }
 
@@ -2631,7 +2637,7 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn,
 
 		memset(&mode_info, 0, sizeof(mode_info));
 
-		rc = sde_connector_get_mode_info(&c_conn->base, mode,
+		rc = sde_connector_get_mode_info(&c_conn->base, mode, NULL,
 				&mode_info);
 		if (rc) {
 			SDE_ERROR_CONN(c_conn,
@@ -2892,6 +2898,9 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 						CONNECTOR_PROP_AVR_STEP);
 		}
 
+		msm_property_install_enum(&c_conn->property_info, "dsc_mode", 0,
+			0, e_dsc_mode, ARRAY_SIZE(e_dsc_mode), 0, CONNECTOR_PROP_DSC_MODE);
+
 		if (display_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
 			msm_property_install_enum(&c_conn->property_info,
 				"frame_trigger_mode", 0, 0,

+ 4 - 0
msm/sde/sde_connector.h

@@ -138,6 +138,7 @@ struct sde_connector_ops {
 	 * get_mode_info - retrieve mode information
 	 * @connector: Pointer to drm connector structure
 	 * @drm_mode: Display mode set for the display
+	 * @sub_mode: Additional mode info to drm display mode
 	 * @mode_info: Out parameter. information of the display mode
 	 * @display: Pointer to private display structure
 	 * @avail_res: Pointer with curr available resources
@@ -145,6 +146,7 @@ struct sde_connector_ops {
 	 */
 	int (*get_mode_info)(struct drm_connector *connector,
 			const struct drm_display_mode *drm_mode,
+			struct msm_sub_mode *sub_mode,
 			struct msm_mode_info *mode_info,
 			void *display,
 			const struct msm_resource_caps_info *avail_res);
@@ -1080,11 +1082,13 @@ int sde_connector_set_msm_mode(struct drm_connector_state *conn_state,
 * sde_connector_get_mode_info - retrieve mode info for given mode
 * @connector: Pointer to drm connector structure
 * @drm_mode: Display mode set for the display
+* @sub_mode: Additional mode info to drm display mode
 * @mode_info: Out parameter. information of the display mode
 * Returns: Zero on success
 */
 int sde_connector_get_mode_info(struct drm_connector *conn,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info);
 
 /**

+ 29 - 2
msm/sde/sde_encoder.c

@@ -933,12 +933,15 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc,
 {
 	int ret = 0;
 	struct drm_display_mode *adj_mode = &crtc_state->adjusted_mode;
+	struct msm_sub_mode sub_mode;
 
 	if (sde_conn && msm_atomic_needs_modeset(crtc_state, conn_state)) {
 		struct msm_display_topology *topology = NULL;
 
+		sub_mode.dsc_mode = sde_connector_get_property(conn_state,
+				CONNECTOR_PROP_DSC_MODE);
 		ret = sde_connector_get_mode_info(&sde_conn->base,
-				adj_mode, &sde_conn_state->mode_info);
+				adj_mode, &sub_mode, &sde_conn_state->mode_info);
 		if (ret) {
 			SDE_ERROR_ENC(sde_enc,
 				"failed to get mode info, rc = %d\n", ret);
@@ -5432,6 +5435,7 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder,
 	struct sde_encoder_phys *phys_enc;
 	struct drm_bridge *bridge;
 	int ret = 0, i;
+	struct msm_sub_mode sub_mode;
 
 	if (!encoder) {
 		SDE_ERROR("invalid drm enc\n");
@@ -5497,9 +5501,11 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder,
 		return -EINVAL;
 	}
 
+	sub_mode.dsc_mode = splash_display->dsc_cnt ? MSM_DISPLAY_DSC_MODE_ENABLED :
+			MSM_DISPLAY_DSC_MODE_DISABLED;
 	drm_mode = &encoder->crtc->state->adjusted_mode;
 	ret = sde_connector_get_mode_info(&sde_conn->base,
-		drm_mode, &sde_conn_state->mode_info);
+		drm_mode, &sub_mode, &sde_conn_state->mode_info);
 	if (ret) {
 		SDE_ERROR_ENC(sde_enc,
 			"conn: ->get_mode_info failed. ret=%d\n", ret);
@@ -5647,3 +5653,24 @@ void sde_encoder_enable_recovery_event(struct drm_encoder *encoder)
 	sde_enc = to_sde_encoder_virt(encoder);
 	sde_enc->recovery_events_enabled = true;
 }
+
+bool sde_encoder_needs_dsc_disable(struct drm_encoder *drm_enc)
+{
+	struct sde_kms *sde_kms;
+	struct drm_connector *conn;
+	struct sde_connector_state *conn_state;
+
+	if (!drm_enc)
+		return false;
+
+	sde_kms = sde_encoder_get_kms(drm_enc);
+	if (!sde_kms)
+		return false;
+
+	conn = sde_encoder_get_connector(sde_kms->dev, drm_enc);
+	if (!conn || !conn->state)
+		return false;
+
+	conn_state = to_sde_connector_state(conn->state);
+	return TOPOLOGY_DSC_MODE(conn_state->old_topology_name);
+}

+ 6 - 0
msm/sde/sde_encoder.h

@@ -559,6 +559,12 @@ void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable);
 struct drm_connector *sde_encoder_get_connector(struct drm_device *dev,
 			struct drm_encoder *drm_enc);
 
+/**sde_encoder_needs_dsc_disable - indicates if dsc should be disabled
+ *			based on previous topology
+ * @drm_enc:	Pointer to drm encoder structure
+ */
+bool sde_encoder_needs_dsc_disable(struct drm_encoder *drm_enc);
+
 /**
  * sde_encoder_get_transfer_time - get the mdp transfer time in usecs
  * @drm_enc: Pointer to drm encoder structure

+ 2 - 1
msm/sde/sde_encoder_dce.c

@@ -936,7 +936,8 @@ void sde_encoder_dce_disable(struct sde_encoder_virt *sde_enc)
 
 	comp_type = sde_enc->mode_info.comp_info.comp_type;
 
-	if (comp_type == MSM_DISPLAY_COMPRESSION_DSC)
+	if (comp_type == MSM_DISPLAY_COMPRESSION_DSC ||
+		sde_encoder_needs_dsc_disable(&sde_enc->base))
 		_dce_dsc_disable(sde_enc);
 	else if (comp_type == MSM_DISPLAY_COMPRESSION_VDC)
 		_dce_vdc_disable(sde_enc);

+ 8 - 0
msm/sde/sde_rm.h

@@ -33,6 +33,14 @@
 		x == SDE_RM_TOPOLOGY_QUADPIPE_DSCMERGE ||\
 		x == SDE_RM_TOPOLOGY_QUADPIPE_DSC4HSMERGE)
 
+#define TOPOLOGY_DSC_MODE(x) \
+	(x == SDE_RM_TOPOLOGY_SINGLEPIPE_DSC ||\
+		x == SDE_RM_TOPOLOGY_DUALPIPE_DSC ||\
+		x == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC ||\
+		x == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE ||\
+		x == SDE_RM_TOPOLOGY_QUADPIPE_3DMERGE_DSC ||\
+		x == SDE_RM_TOPOLOGY_QUADPIPE_DSCMERGE ||\
+		x == SDE_RM_TOPOLOGY_QUADPIPE_DSC4HSMERGE)
 /**
  * enum sde_rm_topology_name - HW resource use case in use by connector
  * @SDE_RM_TOPOLOGY_NONE:                 No topology in use currently

+ 1 - 0
msm/sde/sde_wb.c

@@ -373,6 +373,7 @@ int sde_wb_get_info(struct drm_connector *connector,
 
 int sde_wb_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res)
 {

+ 4 - 1
msm/sde/sde_wb.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __SDE_WB_H__
@@ -196,6 +196,7 @@ int sde_wb_get_info(struct drm_connector *connector,
  * sde_wb_get_mode_info - retrieve information of the mode selected
  * @connector: Pointer to drm connector structure
  * @drm_mode: Display mode set for the display
+ * @sub_mode: Additional mode info to drm display mode
  * @mode_info: Out parameter. information of the mode.
  * @display: Pointer to private display structure
  * @avail_res: Pointer with curr available resources
@@ -203,6 +204,7 @@ int sde_wb_get_info(struct drm_connector *connector,
  */
 int sde_wb_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res);
 
@@ -352,6 +354,7 @@ int sde_wb_connector_set_info_blob(struct drm_connector *connector,
 static inline
 int sde_wb_get_mode_info(struct drm_connector *connector,
 		const struct drm_display_mode *drm_mode,
+		struct msm_sub_mode *sub_mode,
 		struct msm_mode_info *mode_info,
 		void *display, const struct msm_resource_caps_info *avail_res)
 {