Преглед на файлове

disp: msm: support 8bit and 10bit bpp switch

Support 8bit and 10bit bpp switch for display.

Change-Id: Ia5fcb330df95618596377773d0598be2b5609de1
Signed-off-by: Yahui Wang <[email protected]>
Yahui Wang преди 2 години
родител
ревизия
e280657f7f
променени са 10 файла, в които са добавени 169 реда и са изтрити 29 реда
  1. 8 1
      include/uapi/display/drm/sde_drm.h
  2. 9 1
      msm/dsi/dsi_defs.h
  3. 27 2
      msm/dsi/dsi_display.c
  4. 1 0
      msm/dsi/dsi_display.h
  5. 24 1
      msm/dsi/dsi_drm.c
  6. 49 2
      msm/dsi/dsi_panel.c
  7. 19 0
      msm/msm_drv.h
  8. 20 20
      msm/msm_kms.h
  9. 8 0
      msm/sde/sde_connector.c
  10. 4 2
      msm/sde/sde_encoder.c

+ 8 - 1
include/uapi/display/drm/sde_drm.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
 /*
- * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
@@ -932,6 +932,13 @@ struct sde_drm_dnsc_blur_cfg {
 #define DRM_MODE_FLAG_CMD_MODE_PANEL        0x02
 #endif
 
+#ifndef DRM_MODE_FLAG_DSI_24BPP
+#define DRM_MODE_FLAG_DSI_24BPP             0x01
+#endif
+#ifndef DRM_MODE_FLAG_DSI_30BPP
+#define DRM_MODE_FLAG_DSI_30BPP             0x02
+#endif
+
 /* display hint flags*/
 #define DRM_MSM_DISPLAY_EARLY_WAKEUP_HINT         0x01
 #define DRM_MSM_DISPLAY_POWER_COLLAPSE_HINT       0x02

+ 9 - 1
msm/dsi/dsi_defs.h

@@ -81,6 +81,7 @@ enum dsi_op_mode {
  *         Seamless transition is dynamic panel operating mode switch to video
  * @DSI_MODE_FLAG_POMS_TO_CMD:
  *         Seamless transition is dynamic panel operating mode switch to cmd
+ * @DSI_MODE_FLAG_NONDSC_BPP_SWITCH:  Transition is bpp mode switch without DSC.
  */
 enum dsi_mode_flags {
 	DSI_MODE_FLAG_SEAMLESS			= BIT(0),
@@ -91,7 +92,8 @@ enum dsi_mode_flags {
 	DSI_MODE_FLAG_DYN_CLK			= BIT(5),
 	DSI_MODE_FLAG_DMS_FPS                   = BIT(6),
 	DSI_MODE_FLAG_POMS_TO_VID		= BIT(7),
-	DSI_MODE_FLAG_POMS_TO_CMD		= BIT(8)
+	DSI_MODE_FLAG_POMS_TO_CMD		= BIT(8),
+	DSI_MODE_FLAG_NONDSC_BPP_SWITCH		= BIT(9)
 };
 
 /**
@@ -474,6 +476,7 @@ struct dsi_split_link_config {
  * @data_lanes:          Physical data lanes to be enabled.
  * @num_data_lanes:      Number of physical data lanes.
  * @bpp:                 Number of bits per pixel.
+ * @bpp_switch_enabled:  Check if bpp switch is enabled without DSC.
  * @en_crc_check:        Enable CRC checks.
  * @en_ecc_check:        Enable ECC checks.
  * @te_mode:             Source for TE signalling.
@@ -511,6 +514,7 @@ struct dsi_host_common_cfg {
 	enum dsi_data_lanes data_lanes;
 	u8 num_data_lanes;
 	u8 bpp;
+	bool bpp_switch_enabled;
 	bool en_crc_check;
 	bool en_ecc_check;
 	enum dsi_te_mode te_mode;
@@ -681,6 +685,8 @@ struct dsi_display_mode_priv_info {
  * @pixel_clk_khz:  Pixel clock in Khz.
  * @dsi_mode_flags: Flags to signal other drm components via private flags
  * @panel_mode_caps: panel mode capabilities.
+ * @pixel_format_caps: pixel format capabilities.
+ * @bpp:               bits per pixel.
  * @is_preferred:   Is mode preferred
  * @mode_idx:       Mode index as defined by devicetree.
  * @priv_info:      Mode private info
@@ -690,6 +696,8 @@ struct dsi_display_mode {
 	u32 pixel_clk_khz;
 	u32 dsi_mode_flags;
 	u32 panel_mode_caps;
+	u32 pixel_format_caps;
+	u32 bpp;
 	bool is_preferred;
 	u32 mode_idx;
 	struct dsi_display_mode_priv_info *priv_info;

+ 27 - 2
msm/dsi/dsi_display.c

@@ -7517,6 +7517,10 @@ bool dsi_display_mode_match(const struct dsi_display_mode *mode1,
 			mode1->priv_info->dsc_enabled != mode2->priv_info->dsc_enabled)
 		return false;
 
+	if ((match_flags & DSI_MODE_MATCH_NONDSC_BPP_CONFIG) &&
+			mode1->pixel_format_caps != mode2->pixel_format_caps)
+		return false;
+
 	return true;
 }
 
@@ -7573,6 +7577,21 @@ int dsi_display_find_mode(struct dsi_display *display,
 				MSM_DISPLAY_DSC_MODE_ENABLED) ? true : false;
 		}
 
+		if (sub_mode) {
+			switch (sub_mode->pixel_format_mode) {
+			case MSM_DISPLAY_PIXEL_FORMAT_RGB888:
+				cmp->pixel_format_caps = DSI_PIXEL_FORMAT_RGB888;
+				match_flags |= DSI_MODE_MATCH_NONDSC_BPP_CONFIG;
+				break;
+			case MSM_DISPLAY_PIXEL_FORMAT_RGB101010:
+				cmp->pixel_format_caps = DSI_PIXEL_FORMAT_RGB101010;
+				match_flags |= DSI_MODE_MATCH_NONDSC_BPP_CONFIG;
+				break;
+			default:
+				break;
+			}
+		}
+
 		if (dsi_display_mode_match(cmp, m, match_flags)) {
 			*out_mode = m;
 			rc = 0;
@@ -7668,6 +7687,12 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
 		SDE_EVT32(SDE_EVTLOG_FUNC_CASE3, cur_mode->timing.dsc_enabled,
 				adj_mode->timing.dsc_enabled);
 		DSI_DEBUG("DSC mode change detected\n");
+	} else if (cur_mode->pixel_format_caps !=  adj_mode->pixel_format_caps) {
+		adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_NONDSC_BPP_SWITCH;
+		display->panel->host_config.dst_format = adj_mode->pixel_format_caps;
+		SDE_EVT32(SDE_EVTLOG_FUNC_CASE4, cur_mode->pixel_format_caps,
+				adj_mode->pixel_format_caps);
+		DSI_DEBUG("BPP mode change detected\n");
 	} else {
 		dyn_clk_caps = &(display->panel->dyn_clk_caps);
 		/* dfps and dynamic clock with const fps use case */
@@ -7677,7 +7702,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_CASE4,
+				SDE_EVT32(SDE_EVTLOG_FUNC_CASE5,
 					cur_mode->timing.refresh_rate,
 					adj_mode->timing.refresh_rate,
 					cur_mode->timing.h_front_porch,
@@ -7710,7 +7735,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_CASE5,
+				SDE_EVT32(SDE_EVTLOG_FUNC_CASE6,
 					cur_mode->pixel_clk_khz,
 					adj_mode->pixel_clk_khz);
 			}

+ 1 - 0
msm/dsi/dsi_display.h

@@ -31,6 +31,7 @@
 #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)
+#define DSI_MODE_MATCH_NONDSC_BPP_CONFIG (1 << 3)
 
 /*
  * DSI Validate Mode modifiers

+ 24 - 1
msm/dsi/dsi_drm.c

@@ -92,6 +92,8 @@ static void msm_parse_mode_priv_info(const struct msm_display_mode *msm_mode,
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS_TO_CMD;
 	if (msm_is_mode_seamless_dyn_clk(msm_mode))
 		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK;
+	if (msm_is_mode_bpp_switch(msm_mode))
+		dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_NONDSC_BPP_SWITCH;
 }
 
 void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
@@ -160,6 +162,8 @@ static void dsi_convert_to_msm_mode(const struct dsi_display_mode *dsi_mode,
 		msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS_CMD;
 	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)
 		msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK;
+	if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_NONDSC_BPP_SWITCH)
+		msm_mode->private_flags |= MSM_MODE_FLAG_NONDSC_BPP_SWITCH;
 }
 
 static int dsi_bridge_attach(struct drm_bridge *bridge,
@@ -416,6 +420,7 @@ static bool _dsi_bridge_mode_validate_and_fixup(struct drm_bridge *bridge,
 
 	convert_to_dsi_mode(cur_mode, &cur_dsi_mode);
 	msm_parse_mode_priv_info(&old_conn_state->msm_mode, &cur_dsi_mode);
+	cur_dsi_mode.pixel_format_caps = display->panel->host_config.dst_format;
 
 	rc = dsi_display_validate_mode_change(c_bridge->display, &cur_dsi_mode, adj_mode);
 	if (rc) {
@@ -503,7 +508,8 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	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);
-
+	new_sub_mode.pixel_format_mode = sde_connector_get_property(drm_conn_state,
+				CONNECTOR_PROP_BPP_MODE);
 	/*
 	 * retrieve dsi mode from dsi driver's cache since not safe to take
 	 * the drm mode config mutex in all paths
@@ -517,6 +523,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	dsi_mode.priv_info = panel_dsi_mode->priv_info;
 	dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags;
 	dsi_mode.panel_mode_caps = panel_dsi_mode->panel_mode_caps;
+	dsi_mode.pixel_format_caps = panel_dsi_mode->pixel_format_caps;
 	dsi_mode.timing.dsc_enabled = dsi_mode.priv_info->dsc_enabled;
 	dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
 
@@ -636,6 +643,8 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
 	mode_info->jitter_denom = dsi_mode->priv_info->panel_jitter_denom;
 	mode_info->dfps_maxfps = dsi_drm_get_dfps_maxfps(display);
 	mode_info->panel_mode_caps = dsi_mode->panel_mode_caps;
+	mode_info->bpp = dsi_mode->bpp;
+	mode_info->pixel_format_caps = dsi_mode->pixel_format_caps;
 	mode_info->mdp_transfer_time_us = dsi_mode->priv_info->mdp_transfer_time_us;
 	mode_info->mdp_transfer_time_us_min = dsi_mode->priv_info->mdp_transfer_time_us_min;
 	mode_info->mdp_transfer_time_us_max = dsi_mode->priv_info->mdp_transfer_time_us_max;
@@ -923,6 +932,7 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn,
 		struct dsi_display_mode *dsi_mode = &dsi_display->modes[i];
 
 		u32 panel_mode_caps = 0;
+		u32 pixel_format_caps = 0;
 		const char *topo_name = NULL;
 
 		if (!dsi_display_mode_match(&partial_dsi_mode, dsi_mode,
@@ -942,6 +952,19 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn,
 		sde_kms_info_add_keyint(info, "panel_mode_capabilities",
 			panel_mode_caps);
 
+		switch (dsi_mode->pixel_format_caps) {
+		case DSI_PIXEL_FORMAT_RGB888:
+			pixel_format_caps = DRM_MODE_FLAG_DSI_24BPP;
+			break;
+		case DSI_PIXEL_FORMAT_RGB101010:
+			pixel_format_caps = DRM_MODE_FLAG_DSI_30BPP;
+			break;
+		default:
+			break;
+		}
+
+		sde_kms_info_add_keyint(info, "bpp_mode", pixel_format_caps);
+
 		sde_kms_info_add_keyint(info, "dsc_mode",
 			dsi_mode->priv_info->dsc_enabled ? MSM_DISPLAY_DSC_MODE_ENABLED :
 				MSM_DISPLAY_DSC_MODE_DISABLED);

+ 49 - 2
msm/dsi/dsi_panel.c

@@ -947,6 +947,7 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host,
 	u32 bpp = 0;
 	enum dsi_pixel_format fmt;
 	const char *packing;
+	bool bpp_switch_enabled;
 
 	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bpp", &bpp);
 	if (rc) {
@@ -991,6 +992,10 @@ static int dsi_panel_parse_pixel_format(struct dsi_host_common_cfg *host,
 	}
 
 	host->dst_format = fmt;
+
+	bpp_switch_enabled = utils->read_bool(utils->data, "qcom,mdss-dsi-bpp-switch");
+	host->bpp_switch_enabled = bpp_switch_enabled;
+
 	return rc;
 }
 
@@ -3294,6 +3299,37 @@ static bool dsi_panel_parse_panel_mode_caps(struct dsi_display_mode *mode,
 	return true;
 };
 
+static int dsi_panel_parse_bpp_mode_caps(struct dsi_display_mode *mode,
+				struct dsi_parser_utils *utils)
+{
+	int rc = 0;
+	u32 bpp = 0;
+
+	if (!mode || !mode->priv_info) {
+		DSI_ERR("invalid arguments\n");
+		return -EINVAL;
+	}
+
+	rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bpp-mode", &bpp);
+	if (rc) {
+		DSI_DEBUG("bpp mode not defined in timing node, setting default 24bpp\n");
+		mode->pixel_format_caps = DSI_PIXEL_FORMAT_RGB888;
+		return 0;
+	}
+
+	switch(bpp) {
+	case 30:
+		mode->pixel_format_caps = DSI_PIXEL_FORMAT_RGB101010;
+		break;
+	case 24:
+	default:
+		mode->pixel_format_caps = DSI_PIXEL_FORMAT_RGB888;
+		break;
+	}
+
+	return rc;
+};
+
 static int dsi_panel_parse_dms_info(struct dsi_panel *panel)
 {
 	int dms_enabled;
@@ -4084,7 +4120,7 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config,
 					* timing->v_active));
 		/* calculate the actual bitclk needed to transfer the frame */
 		min_bitclk_hz = (total_active_pixels * (timing->refresh_rate) *
-				(config->bpp));
+				(mode->bpp));
 		do_div(min_bitclk_hz, config->num_data_lanes);
 	}
 
@@ -4161,7 +4197,7 @@ void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config,
 	do_div(pclk_rate_hz, timing->dsi_transfer_time_us);
 
 	pixel_clk_khz = pclk_rate_hz * config->num_data_lanes;
-	do_div(pixel_clk_khz, config->bpp);
+	do_div(pixel_clk_khz, mode->bpp);
 	display_mode->pixel_clk_khz = pixel_clk_khz;
 
 	display_mode->pixel_clk_khz =  display_mode->pixel_clk_khz / 1000;
@@ -4230,6 +4266,17 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
 			mode->panel_mode_caps = panel->panel_mode;
 		}
 
+		if (panel->host_config.bpp_switch_enabled) {
+			rc = dsi_panel_parse_bpp_mode_caps(mode, utils);
+			if (rc) {
+				DSI_ERR("failed to parse bpp mode caps, rc=%d\n", rc);
+				goto parse_fail;
+			}
+		} else {
+			mode->pixel_format_caps = panel->host_config.dst_format;
+		}
+		mode->bpp = dsi_pixel_format_to_bpp(mode->pixel_format_caps);
+
 		rc = utils->read_u32(utils->data, "cell-index", &mode->mode_idx);
 		if (rc)
 			mode->mode_idx = index;

+ 19 - 0
msm/msm_drv.h

@@ -255,6 +255,7 @@ enum msm_mdp_conn_property {
 	CONNECTOR_PROP_WB_USAGE_TYPE,
 	CONNECTOR_PROP_WB_ROT_TYPE,
 	CONNECTOR_PROP_WB_ROT_BYTES_PER_CLK,
+	CONNECTOR_PROP_BPP_MODE,
 
 	/* total # of properties */
 	CONNECTOR_PROP_COUNT
@@ -348,6 +349,18 @@ enum panel_op_mode {
 	MSM_DISPLAY_MODE_MAX = BIT(2)
 };
 
+/**
+ * enum msm_display_pixel_format - display dsi pixel format
+ * @MSM_DISPLAY_PIXEL_FORMAT_NONE: none
+ * @MSM_DISPLAY_PIXEL_FORMAT_RGB888: 24BPP
+ * @MSM_DISPLAY_PIXEL_FORMAT_RGB101010: 30BPP
+ */
+enum msm_display_pixel_format {
+	MSM_DISPLAY_PIXEL_FORMAT_NONE,
+	MSM_DISPLAY_PIXEL_FORMAT_RGB888,
+	MSM_DISPLAY_PIXEL_FORMAT_RGB101010,
+};
+
 /**
  * enum msm_display_dsc_mode - panel dsc mode
  * @MSM_DISPLAY_DSC_MODE_NONE: No operation
@@ -375,9 +388,11 @@ struct msm_display_mode {
 /**
  * struct msm_sub_mode - msm display sub mode
  * @dsc_enabled: boolean used to indicate if dsc should be enabled
+ * @pixel_format_mode: used to indicate pixel format mode
  */
 struct msm_sub_mode {
 	enum msm_display_dsc_mode dsc_mode;
+	enum msm_display_pixel_format pixel_format_mode;
 };
 
 /**
@@ -806,6 +821,8 @@ struct msm_display_wd_jitter_config {
  * @roi_caps:        panel roi capabilities
  * @wide_bus_en:	wide-bus mode cfg for interface module
  * @panel_mode_caps   panel mode capabilities
+ * @pixel_format_caps      pixel format capabilities.
+ * @bpp                    bits per pixel.
  * @mdp_transfer_time_us   Specifies the mdp transfer time for command mode
  *                         panels in microseconds.
  * @mdp_transfer_time_us_min   Specifies the minimum possible mdp transfer time
@@ -833,6 +850,8 @@ struct msm_mode_info {
 	struct msm_roi_caps roi_caps;
 	bool wide_bus_en;
 	u32 panel_mode_caps;
+	u32 pixel_format_caps;
+	u32 bpp;
 	u32 mdp_transfer_time_us;
 	u32 mdp_transfer_time_us_min;
 	u32 mdp_transfer_time_us_max;

+ 20 - 20
msm/msm_kms.h

@@ -47,6 +47,8 @@
 #define MSM_MODE_FLAG_SEAMLESS_POMS_VID			(1<<6)
 /* Request to switch the panel mode to command */
 #define MSM_MODE_FLAG_SEAMLESS_POMS_CMD			(1<<7)
+/* Request to switch bpp without DSC */
+#define MSM_MODE_FLAG_NONDSC_BPP_SWITCH			(1<<8)
 
 /* As there are different display controller blocks depending on the
  * snapdragon version, the kms support is split out and the appropriate
@@ -222,8 +224,7 @@ static inline bool msm_is_mode_seamless(const struct msm_display_mode *mode)
 
 static inline bool msm_is_mode_seamless_dms(const struct msm_display_mode *mode)
 {
-	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DMS)
-		: false;
+	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DMS) : false;
 }
 
 static inline bool msm_is_mode_dynamic_fps(const struct msm_display_mode *mode)
@@ -234,40 +235,36 @@ static inline bool msm_is_mode_dynamic_fps(const struct msm_display_mode *mode)
 
 static inline bool msm_is_mode_seamless_vrr(const struct msm_display_mode *mode)
 {
-	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_VRR)
-		: false;
+	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_VRR) : false;
 }
 
-static inline bool msm_is_mode_seamless_poms_to_vid(
-		const struct msm_display_mode *mode)
+static inline bool msm_is_mode_seamless_poms_to_vid(const struct msm_display_mode *mode)
 {
-	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS_VID)
-		: false;
+	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS_VID) : false;
 }
 
-static inline bool msm_is_mode_seamless_poms_to_cmd(
-		const struct msm_display_mode *mode)
+static inline bool msm_is_mode_seamless_poms_to_cmd(const struct msm_display_mode *mode)
 {
-	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS_CMD)
-		: false;
+	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS_CMD) : false;
 }
 
-static inline bool msm_is_mode_seamless_poms(
-			const struct msm_display_mode *mode)
+static inline bool msm_is_mode_seamless_poms(const struct msm_display_mode *mode)
 {
 	return (msm_is_mode_seamless_poms_to_vid(mode) ||
 		msm_is_mode_seamless_poms_to_cmd(mode));
 }
 
-static inline bool msm_is_mode_seamless_dyn_clk(
-					const struct msm_display_mode *mode)
+static inline bool msm_is_mode_seamless_dyn_clk(const struct msm_display_mode *mode)
 {
-	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYN_CLK)
-		: false;
+	return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYN_CLK) : false;
 }
 
-static inline bool msm_needs_vblank_pre_modeset(
-		const struct msm_display_mode *mode)
+static inline bool msm_is_mode_bpp_switch(const struct msm_display_mode *mode)
+{
+	return mode ? (mode->private_flags & MSM_MODE_FLAG_NONDSC_BPP_SWITCH) : false;
+}
+
+static inline bool msm_needs_vblank_pre_modeset(const struct msm_display_mode *mode)
 {
 	return (mode->private_flags & MSM_MODE_FLAG_VBLANK_PRE_MODESET);
 }
@@ -303,6 +300,9 @@ static inline bool msm_is_private_mode_changed(
 	if (msm_is_mode_seamless_dms(msm_mode))
 		return true;
 
+	if (msm_is_mode_bpp_switch(msm_mode))
+		return true;
+
 	return false;
 }
 

+ 8 - 0
msm/sde/sde_connector.c

@@ -86,6 +86,11 @@ static const struct drm_prop_enum_list e_panel_mode[] = {
 	{MSM_DISPLAY_CMD_MODE, "command_mode"},
 	{MSM_DISPLAY_MODE_MAX, "none"},
 };
+static const struct drm_prop_enum_list e_bpp_mode[] = {
+	{MSM_DISPLAY_PIXEL_FORMAT_NONE, "none"},
+	{MSM_DISPLAY_PIXEL_FORMAT_RGB888, "dsi_24bpp"},
+	{MSM_DISPLAY_PIXEL_FORMAT_RGB101010, "dsi_30bpp"},
+};
 
 static void sde_dimming_bl_notify(struct sde_connector *conn, struct dsi_backlight_config *config)
 {
@@ -3245,6 +3250,9 @@ static int _sde_connector_install_properties(struct drm_device *dev,
 			(dsi_display->panel->panel_mode == DSI_OP_VIDEO_MODE) ? 0 : 1,
 			CONNECTOR_PROP_SET_PANEL_MODE);
 
+		msm_property_install_enum(&c_conn->property_info, "bpp_mode", 0,
+			0, e_bpp_mode, ARRAY_SIZE(e_bpp_mode), 0, CONNECTOR_PROP_BPP_MODE);
+
 		if (test_bit(SDE_FEATURE_DEMURA, sde_kms->catalog->features)) {
 			msm_property_install_blob(&c_conn->property_info,
 				"DEMURA_PANEL_ID", DRM_MODE_PROP_IMMUTABLE,

+ 4 - 2
msm/sde/sde_encoder.c

@@ -1098,6 +1098,8 @@ static int _sde_encoder_atomic_check_reserve(struct drm_encoder *drm_enc,
 
 		sub_mode.dsc_mode = sde_connector_get_property(conn_state,
 				CONNECTOR_PROP_DSC_MODE);
+		sub_mode.pixel_format_mode = sde_connector_get_property(conn_state,
+				CONNECTOR_PROP_BPP_MODE);
 		ret = sde_connector_get_mode_info(&sde_conn->base,
 				adj_mode, &sub_mode, &sde_conn_state->mode_info);
 		if (ret) {
@@ -3348,8 +3350,8 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
 	bpc = dsc->config.bits_per_component;
 	bpp = dsc->config.bits_per_pixel;
 
-	/* disable dither for 10 bpp or 10bpc dsc config */
-	if (bpp == 10 || bpc == 10) {
+	/* disable dither for 10 bpp or 10bpc dsc config or 30bpp without dsc */
+	if (bpp == 10 || bpc == 10 || sde_enc->mode_info.bpp == 30) {
 		phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0);
 		return;
 	}