diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
index 0949b55a6d87..ab8e7a0ed6a5 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c
@@ -2394,6 +2394,40 @@ bool sde_hdmi_mode_needs_full_range(void *display)
 	return true;
 }
 
+enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn,
+	void *display)
+{
+	struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
+	struct sde_connector_state *c_state;
+	struct drm_msm_ext_panel_hdr_ctrl *hdr_ctrl;
+	struct drm_msm_ext_panel_hdr_metadata *hdr_meta;
+
+	if (!hdmi_display || !conn) {
+		SDE_ERROR("invalid input\n");
+		goto error;
+	}
+
+	c_state = to_sde_connector_state(conn->state);
+
+	if (!c_state) {
+		SDE_ERROR("invalid input\n");
+		goto error;
+	}
+
+	hdr_ctrl = &c_state->hdr_ctrl;
+	hdr_meta = &hdr_ctrl->hdr_meta;
+
+	if ((hdr_ctrl->hdr_state == HDR_ENABLE)
+		&& (hdr_meta->eotf != 0))
+		return SDE_CSC_RGB2YUV_2020L;
+	else if (sde_hdmi_mode_needs_full_range(hdmi_display)
+		|| conn->yuv_qs)
+		return SDE_CSC_RGB2YUV_601FR;
+
+error:
+	return SDE_CSC_RGB2YUV_601L;
+}
+
 int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
 {
 	struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
index 441bb3a6dfe8..e80fc66a6244 100644
--- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.h
@@ -490,6 +490,15 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector,
  */
 bool sde_hdmi_mode_needs_full_range(void *display);
 
+/*
+ * sde_hdmi_get_csc_type - returns the CSC type to be
+ * used based on state of HDR playback
+ * @conn: Pointer to DRM connector
+ * @display: Pointer to private display structure
+ * Returns: true or false based on mode
+ */
+enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn,
+	void *display);
 #else /*#ifdef CONFIG_DRM_SDE_HDMI*/
 
 static inline u32 sde_hdmi_get_num_of_displays(void)
@@ -609,5 +618,11 @@ static inline bool sde_hdmi_mode_needs_full_range(void *display)
 	return false;
 }
 
+enum sde_csc_type sde_hdmi_get_csc_type(struct drm_connector *conn,
+	void *display)
+{
+	return 0;
+}
+
 #endif /*#else of CONFIG_DRM_SDE_HDMI*/
 #endif /* _SDE_HDMI_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index d79361bbe265..5fa4c21060f9 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -90,6 +90,28 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
 	return rc;
 }
 
+enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn)
+{
+	struct sde_connector *c_conn;
+
+	if (!conn) {
+		SDE_ERROR("invalid argument\n");
+		return -EINVAL;
+	}
+
+	c_conn = to_sde_connector(conn);
+
+	if (!c_conn->display) {
+		SDE_ERROR("invalid argument\n");
+		return -EINVAL;
+	}
+
+	if (!c_conn->ops.get_csc_type)
+		return SDE_CSC_RGB2YUV_601L;
+
+	return c_conn->ops.get_csc_type(conn, c_conn->display);
+}
+
 bool sde_connector_mode_needs_full_range(struct drm_connector *connector)
 {
 	struct sde_connector *c_conn;
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 73a20133a944..b76ce0aaf577 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -143,6 +143,16 @@ struct sde_connector_ops {
 	 * Returns: true or false based on whether full range is needed
 	 */
 	bool (*mode_needs_full_range)(void *display);
+
+	/**
+	 * get_csc_type - returns the CSC type to be used
+	 * by the CDM block based on HDR state
+	 * @connector: Pointer to drm connector structure
+	 * @display: Pointer to private display structure
+	 * Returns: type of CSC matrix to be used
+	 */
+	enum sde_csc_type (*get_csc_type)(struct drm_connector *connector,
+		void *display);
 };
 
 /**
@@ -342,5 +352,14 @@ int sde_connector_pre_kickoff(struct drm_connector *connector);
  * Returns: true OR false based on connector mode
  */
 bool sde_connector_mode_needs_full_range(struct drm_connector *connector);
+
+/**
+ * sde_connector_get_csc_type - query csc type
+ * to be used for the connector
+ * @connector: Pointer to drm connector object
+ * Returns: csc type based on connector HDR state
+ */
+enum sde_csc_type sde_connector_get_csc_type(struct drm_connector *conn);
+
 #endif /* _SDE_CONNECTOR_H_ */
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 44b680d8ddc5..23fb79241d84 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -862,7 +862,12 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
 {
 	struct sde_encoder_virt *sde_enc;
 	struct sde_encoder_phys *phys;
+	struct drm_connector *conn_mas = NULL;
 	unsigned int i;
+	enum sde_csc_type conn_csc;
+	struct drm_display_mode *mode;
+	struct sde_hw_cdm *hw_cdm;
+	int mode_is_yuv = 0;
 	int rc;
 
 	if (!drm_enc) {
@@ -882,11 +887,46 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
 	}
 
 	if (sde_enc->cur_master && sde_enc->cur_master->connector) {
-		rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
+		conn_mas = sde_enc->cur_master->connector;
+		rc = sde_connector_pre_kickoff(conn_mas);
 		if (rc)
-			SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n",
-					sde_enc->cur_master->connector->base.id,
-					rc);
+			SDE_ERROR_ENC(sde_enc,
+				"kickoff conn%d failed rc %d\n",
+				conn_mas->base.id,
+				rc);
+
+		for (i = 0; i < sde_enc->num_phys_encs; i++) {
+			phys = sde_enc->phys_encs[i];
+			if (phys) {
+				mode = &phys->cached_mode;
+				mode_is_yuv = (mode->private_flags &
+					MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420);
+			}
+			/**
+			 * Check the CSC matrix type to which the
+			 * CDM CSC matrix should be updated to based
+			 * on the connector HDR state
+			 */
+			conn_csc = sde_connector_get_csc_type(conn_mas);
+			if (phys && mode_is_yuv) {
+				if (phys->enc_cdm_csc != conn_csc) {
+					hw_cdm = phys->hw_cdm;
+					rc = hw_cdm->ops.setup_csc_data(hw_cdm,
+					&sde_csc_10bit_convert[conn_csc]);
+
+					if (rc)
+						SDE_ERROR_ENC(sde_enc,
+							"CSC setup failed rc %d\n",
+							rc);
+					SDE_DEBUG_ENC(sde_enc,
+						"updating CSC %d to %d\n",
+						phys->enc_cdm_csc,
+						conn_csc);
+					phys->enc_cdm_csc = conn_csc;
+
+				}
+			}
+		}
 	}
 }
 
@@ -1543,6 +1583,9 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
 		}
 	}
 
+	/* Cache the CSC default matrix type */
+	phys_enc->enc_cdm_csc = csc_type;
+
 	if (hw_cdm && hw_cdm->ops.setup_cdwn) {
 		ret = hw_cdm->ops.setup_cdwn(hw_cdm, cdm_cfg);
 		if (ret < 0) {
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 20f125155de3..aec844d640bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -174,6 +174,7 @@ enum sde_intr_idx {
  * @split_role:		Role to play in a split-panel configuration
  * @intf_mode:		Interface mode
  * @intf_idx:		Interface index on sde hardware
+ * @enc_cdm_csc:	Cached CSC type of CDM block
  * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
  * @enable_state:	Enable state tracking
  * @vblank_refcount:	Reference count of vblank request
@@ -201,6 +202,7 @@ struct sde_encoder_phys {
 	enum sde_enc_split_role split_role;
 	enum sde_intf_mode intf_mode;
 	enum sde_intf intf_idx;
+	enum sde_csc_type enc_cdm_csc;
 	spinlock_t *enc_spinlock;
 	enum sde_enc_enable_state enable_state;
 	atomic_t vblank_refcount;
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index eaa1eca8fc8e..cdf67c0aa864 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -594,7 +594,8 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
 		.set_property = sde_hdmi_set_property,
 		.get_property = sde_hdmi_get_property,
 		.pre_kickoff = sde_hdmi_pre_kickoff,
-		.mode_needs_full_range = sde_hdmi_mode_needs_full_range
+		.mode_needs_full_range = sde_hdmi_mode_needs_full_range,
+		.get_csc_type = sde_hdmi_get_csc_type
 	};
 	struct msm_display_info info = {0};
 	struct drm_encoder *encoder;